All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.simplejavamail.internal.clisupport.CliCommandLineProducer Maven / Gradle / Ivy

There is a newer version: 8.12.4
Show newest version
/*
 * Copyright © 2009 Benny Bottema ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.simplejavamail.internal.clisupport;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simplejavamail.api.internal.clisupport.model.CliBuilderApiType;
import org.simplejavamail.api.internal.clisupport.model.CliDeclaredOptionSpec;
import org.simplejavamail.api.internal.clisupport.model.CliDeclaredOptionValue;
import org.simplejavamail.internal.clisupport.therapijavadoc.TherapiJavadocHelper;
import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Model.OptionSpec;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static java.lang.String.format;
import static org.simplejavamail.internal.clisupport.BuilderApiToPicocliCommandsMapper.colorizeOptionsInText;
import static org.simplejavamail.internal.clisupport.CliColorScheme.COMMAND_OPTION_STYLE;
import static org.simplejavamail.internal.clisupport.CliColorScheme.OPTION_VALUE_STYLE;
import static org.simplejavamail.internal.util.ListUtil.getFirst;

class CliCommandLineProducer {
    
    static final String OPTION_HELP_POSTFIX = "--help";
    static final String EMPTY_PARAM_LABEL = "";
    
    @SuppressWarnings("SameParameterValue")
    static CommandLine configurePicoCli(List declaredOptions, int maxTextWidth) {
        CommandSpec rootCommandsHolder = createDefaultCommandSpec("SimpleJavaMail",
                "Simple Java Mail Command Line Interface.%n" +
                        "%n" +
                        "All commands and their options are a direct translation of the Simple Java Mail builder API and translate back into builder calls " +
                        "(as such, the order of --options matter as well as combinations). Furthermore, all documentation is taken from the " +
                        "builder API Javadoc. Essentially you configure builders just like you would in Java, but with CLI commands.%n" +
                        "%n" +
                        "@|bold Note that each and every |@@|"+COMMAND_OPTION_STYLE+",bold --option|@ @|bold has an |@@|"+COMMAND_OPTION_STYLE+",bold --option--help|@ @|bold variation for full documentation.|@" +
                        "%n" +
                        "Note: All the regular functionality regarding properties and config files work with the CLI so you can provide defaults in a " +
                        "property file as long as it is visible (on class path) or as system environment variables.")
                .version("Simple Java Mail 8.12.3");
        
        rootCommandsHolder.usageMessage()
                .customSynopsis("",
                        colorizeOptionsInText("\tsend     [--help -h, --version -v] --email:options --mailer:options", COMMAND_OPTION_STYLE),
                        colorizeOptionsInText("\tconnect  [--help -h, --version -v] --mailer:options", COMMAND_OPTION_STYLE),
                        colorizeOptionsInText("\tvalidate [--help -h, --version -v] --email:options", COMMAND_OPTION_STYLE));
    
        createRootCommand(rootCommandsHolder, "send", "Send an email: starting blank, replying to or forwarding another email.",
                colorizeOptionsInText("\tsend [--help -h, --version -v] --email:options --mailer:options", COMMAND_OPTION_STYLE), declaredOptions, maxTextWidth);
        createRootCommand(rootCommandsHolder, "connect", "Test a server connection, including possible authentication and any proxy settings",
                colorizeOptionsInText("\tconnect [--help -h, --version -v] --mailer:options", COMMAND_OPTION_STYLE), declaredOptions, maxTextWidth);
        createRootCommand(rootCommandsHolder, "validate", "Validate an email for mandatory fields, injection detection and optional email address validation",
                colorizeOptionsInText("\tvalidate [--help -h, --version -v] --email:options --mailer:options", COMMAND_OPTION_STYLE), declaredOptions, maxTextWidth);
        
        return new CommandLine(rootCommandsHolder).setUsageHelpWidth(maxTextWidth).setSeparator(" ");
    }
    
    private static void createRootCommand(CommandSpec rootCommandsHolder, String name, String description, String synopsis,
                                                 List declaredOptions, int maxTextWidth) {
        final CommandSpec rootCommand = createDefaultCommandSpec(name, description);
		final Collection compatibleBuilderApiTypes = CliBuilderApiType.findForCliSynopsis(synopsis);
        rootCommand.usageMessage().customSynopsis(synopsis);
		populateRootCommands(rootCommand, declaredOptions, compatibleBuilderApiTypes, maxTextWidth);
        rootCommandsHolder.addSubcommand(rootCommand.name(), rootCommand);
    }
    
    private static void populateRootCommands(CommandSpec rootCommand, List declaredOptions, Collection compatibleBuilderApiTypes, int maxTextWidth) {
		for (CliDeclaredOptionSpec cliDeclaredOptionSpec : declaredOptions) {
            if (cliDeclaredOptionSpec.applicableToRootCommand(compatibleBuilderApiTypes)) {
                rootCommand.addOption(OptionSpec.builder(cliDeclaredOptionSpec.getName())
                        .type(List.class)
                        .auxiliaryTypes(String.class)
                        .arity(format("%s..%s",
                                cliDeclaredOptionSpec.getMandatoryOptionValues().size(),
                                cliDeclaredOptionSpec.getPossibleOptionValues().size()))
                        .paramLabel(determineParamLabel(cliDeclaredOptionSpec.getPossibleOptionValues()))
                        .hideParamSyntax(true)
                        .description(determineDescription(cliDeclaredOptionSpec, false, maxTextWidth))
                        .build());
                rootCommand.addOption(OptionSpec.builder(cliDeclaredOptionSpec.getName() + OPTION_HELP_POSTFIX)
                        .type(List.class) // cannot use .usageHelp(true), because this cannot be boolean, because description
                        .auxiliaryTypes(String.class)
                        .arity("*")
                        .hidden(true)
                        .help(true)
                        .paramLabel(determineParamLabel(cliDeclaredOptionSpec.getPossibleOptionValues()))
                        .hideParamSyntax(true)
                        .description(determineDescription(cliDeclaredOptionSpec, true, maxTextWidth))
                        .build());
            }
        }
    }
    
    // hide multi-line descriptions when usage is not focussed on the current option (ie. --current-option--help)
    private static String[] determineDescription(CliDeclaredOptionSpec cliCommand, boolean fullDescription, int maxTextWidth) {
        final List descriptions = formatOptionDescription(cliCommand, maxTextWidth);
        if (!fullDescription && descriptions.size() > 1) {
            return new String[] {getFirst(descriptions) + " (...more)"};
        } else {
            return descriptions.toArray(new String[]{});
        }
    }
    
    @NotNull
    private static List formatOptionDescription(CliDeclaredOptionSpec cliOption, int maxTextWidth) {
        final List fullDescription = new ArrayList<>(cliOption.getDescription());
        if (!cliOption.getPossibleOptionValues().isEmpty()) {
            fullDescription.add("%n@|bold,underline Parameters|@:");
            for (CliDeclaredOptionValue possibleValue : cliOption.getPossibleOptionValues()) {
				String optionalInfix = !possibleValue.isRequired() ? " (optional->null)" : "";
				fullDescription.add(format("@|%s %s%s|@: %s", OPTION_VALUE_STYLE, possibleValue.getName(), optionalInfix, possibleValue.formatDescription()));
            }
        }
	
		List seeAlsoReferences = TherapiJavadocHelper.getJavadocSeeAlsoReferences(cliOption.getSourceMethod(), true, maxTextWidth);
        if (!seeAlsoReferences.isEmpty()) {
            fullDescription.add("%n@|bold,underline See also|@:");
			fullDescription.addAll(seeAlsoReferences);
        }
        return fullDescription;
    }
    
    private static String determineParamLabel(List possibleParams) {
        final StringBuilder paramLabel = new StringBuilder();
        for (CliDeclaredOptionValue possibleParam : possibleParams) {
            paramLabel.append(possibleParam.isRequired() ? "" : "[");
            paramLabel.append(possibleParam.getName()).append("(=").append(possibleParam.getHelpLabel()).append(")");
            paramLabel.append(possibleParam.isRequired() ? " " : "] ");
        }
        String declaredParamLabel = paramLabel.toString().trim();
        return declaredParamLabel.isEmpty() ? EMPTY_PARAM_LABEL : declaredParamLabel;
    }
    
    private static CommandSpec createDefaultCommandSpec(@NotNull String name, @Nullable String... descriptions) {
        final CommandSpec command = CommandSpec.create()
                .name(name)
                .mixinStandardHelpOptions(true);
        command.usageMessage()
                .description(descriptions)
                .headerHeading("%n@|bold,underline Usage|@:")
                .commandListHeading("%n@|bold,underline Commands|@:%n")
                .synopsisHeading(" ")
                .descriptionHeading("%n@|bold,underline Description|@:%n")
                .optionListHeading("%n@|bold,underline Options|@:%n")
                .parameterListHeading("%n@|bold,underline Parameters|@:%n")
                .footerHeading("%n")
                .footer("@|faint,italic https://www.simplejavamail.org/#/cli|@");
        return command;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy