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

com.github.rvesse.airline.builder.CliBuilder Maven / Gradle / Ivy

Go to download

Java library provided an annotation-based framework for parsing Git like command line structures

The newest version!
/**
 * Copyright (C) 2010-16 the original author or authors.
 *
 * 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 com.github.rvesse.airline.builder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Queue;

import com.github.rvesse.airline.model.*;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.collections4.ListUtils;

import com.github.rvesse.airline.Cli;
import com.github.rvesse.airline.help.sections.HelpSection;
import com.github.rvesse.airline.restrictions.GlobalRestriction;
import com.github.rvesse.airline.restrictions.None;

/**
 * Builder for CLIs
 *
 * @param 
 *            Command type
 */
public class CliBuilder extends AbstractBuilder> {

    protected final String name;
    protected String description;
    protected String optionSeparators;
    protected Class defaultCommand;
    protected final List> defaultCommandGroupCommands = new ArrayList<>();
    protected final Map> groups = new HashMap<>();
    protected final List restrictions = new ArrayList<>();
    protected final ParserBuilder parserBuilder = new ParserBuilder(this);
    protected final Map baseHelpSections = new HashMap<>();

    public CliBuilder(String name) {
        checkNotBlank(name, "Program name");
        this.name = name;
    }

    public CliBuilder withDescription(String description) {
        checkNotEmpty(description, "Description");
        this.description = description;
        return this;
    }

    public CliBuilder withDefaultCommand(Class defaultCommand) {
        this.defaultCommand = defaultCommand;
        return this;
    }

    public CliBuilder withCommand(Class command) {
        this.defaultCommandGroupCommands.add(command);
        return this;
    }

    @SuppressWarnings("unchecked")
    public CliBuilder withCommands(Class command, Class... moreCommands) {
        this.defaultCommandGroupCommands.add(command);
        this.defaultCommandGroupCommands
                .addAll(ListUtils.unmodifiableList(IteratorUtils.toList(IteratorUtils.arrayIterator(moreCommands))));
        return this;
    }

    public CliBuilder withCommands(Iterable> commands) {
        this.defaultCommandGroupCommands.addAll(ListUtils.unmodifiableList(IteratorUtils.toList(commands.iterator())));
        return this;
    }

    public GroupBuilder withGroup(String name) {
        checkNotBlank(name, "Group name");

        if (groups.containsKey(name)) {
            return groups.get(name);
        }

        GroupBuilder group = new GroupBuilder(this, name);
        groups.put(name, group);
        return group;
    }

    public GroupBuilder getGroup(final String name) {
        checkNotBlank(name, "Group name");
        if (!groups.containsKey(name))
            throw new IllegalArgumentException(String.format("Group %s has not been declared", name));

        return groups.get(name);
    }

    public CliBuilder withRestriction(GlobalRestriction restriction) {
        if (restriction != null)
            restrictions.add(restriction);
        return this;
    }

    public CliBuilder withRestrictions(GlobalRestriction... restrictions) {
        for (GlobalRestriction restriction : restrictions) {
            if (restriction == null)
                continue;
            this.restrictions.add(restriction);
        }
        return this;
    }

    public CliBuilder withNoRestrictions() {
        restrictions.clear();
        restrictions.add(new None());
        return this;
    }

    public CliBuilder withDefaultRestrictions() {
        restrictions.addAll(Arrays.asList(GlobalRestriction.DEFAULTS));
        return this;
    }

    public CliBuilder withOnlyDefaultRestrictions() {
        restrictions.clear();
        return withDefaultRestrictions();
    }

    public ParserBuilder withParser() {
        return parserBuilder;
    }

    public CliBuilder withHelpSection(HelpSection section) {
        if (section == null)
            return this;
        baseHelpSections.put(section.getTitle().toLowerCase(Locale.ENGLISH), section);
        return this;
    }

    @Override
    public Cli build() {
        // Need Parser Configuration available up front
        ParserMetadata parserConfig = this.parserBuilder.build();

        CommandMetadata defaultCommandMetadata = null;
        List allCommands = new ArrayList();
        if (defaultCommand != null) {
            defaultCommandMetadata = MetadataLoader.loadCommand(defaultCommand, baseHelpSections, parserConfig);
        }

        List defaultCommandGroup = defaultCommandGroupCommands != null
                ? MetadataLoader.loadCommands(defaultCommandGroupCommands, baseHelpSections, parserConfig)
                : new ArrayList();

        allCommands.addAll(defaultCommandGroup);
        if (defaultCommandMetadata != null)
            allCommands.add(defaultCommandMetadata);

        // Build groups
        List commandGroups;
        if (groups != null) {
            commandGroups = new ArrayList();
            for (GroupBuilder groupBuilder : groups.values()) {
                commandGroups.add(groupBuilder.build());
            }
        } else {
            commandGroups = new ArrayList<>();
        }

        // Find all commands registered in groups and sub-groups, we use this to
        // check this is a valid CLI with at least 1 command
        for (CommandGroupMetadata group : commandGroups) {
            allCommands.addAll(group.getCommands());
            if (group.getDefaultCommand() != null)
                allCommands.add(group.getDefaultCommand());

            // Make sure to scan sub-groups
            Queue subGroups = new LinkedList();
            subGroups.addAll(group.getSubGroups());
            while (!subGroups.isEmpty()) {
                CommandGroupMetadata subGroup = subGroups.poll();
                allCommands.addAll(subGroup.getCommands());
                if (subGroup.getDefaultCommand() != null)
                    allCommands.add(subGroup.getDefaultCommand());
                subGroups.addAll(subGroup.getSubGroups());
            }
        }

        // add commands to groups based on the value of groups in the @Command
        // annotations
        // rather than change the entire way metadata is loaded, I figured just
        // post-processing was an easier, yet uglier, way to go
        MetadataLoader.loadCommandsIntoGroupsByAnnotation(allCommands, commandGroups, defaultCommandGroup,
                baseHelpSections, parserConfig);

        // Build restrictions
        // Use defaults if none specified
        if (restrictions.size() == 0)
            withDefaultRestrictions();

        if (allCommands.size() == 0)
            throw new IllegalArgumentException("Must specify at least one command to create a CLI");

        // Build metadata objects
        GlobalMetadata metadata = MetadataLoader. loadGlobal(name, description, defaultCommandMetadata,
                                                                   ListUtils.unmodifiableList(defaultCommandGroup), ListUtils.unmodifiableList(commandGroups),
                                                                   ListUtils.unmodifiableList(restrictions), Collections.unmodifiableCollection(baseHelpSections.values()),
                                                                   parserConfig);

        return new Cli(metadata);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy