net.freifunk.autodeploy.ui.commandline.CommandLineParserImpl.java Source code

Java tutorial

Introduction

Here is the source code for net.freifunk.autodeploy.ui.commandline.CommandLineParserImpl.java

Source

/*
 * Freifunk Auto Deployer
 * Copyright (C) 2013, 2014 by Andreas Baldeau <andreas@baldeau.net>
 *
 *
 * For contributers see file CONTRIB.
 *
 *
 * 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.
 *
 *
 * Uses Logback (http://logback.qos.ch/) which is dual licensed under EPL v1.0 and LGPL v2.1.
 * See http://logback.qos.ch/license.html for details.
 */
package net.freifunk.autodeploy.ui.commandline;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintWriter;

import net.freifunk.autodeploy.AutoDeployOptions;
import net.freifunk.autodeploy.PhaseOptions;
import net.freifunk.autodeploy.device.Device;
import net.freifunk.autodeploy.device.DeviceService;
import net.freifunk.autodeploy.firmware.Firmware;
import net.freifunk.autodeploy.firmware.FirmwareService;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;

/**
 * Default implementation of {@link CommandLineParser}.
 *
 * @author Andreas Baldeau <andreas@baldeau.net>
 */
public class CommandLineParserImpl implements CommandLineParser {

    private static final String HELP_OPTION = "h";
    private static final String LIST_MODELS_OPTION = "M";
    private static final String LIST_FIRMWARES_OPTION = "F";
    private static final String DEPLOY_OPTION = "d";
    private static final String CONFIGURE_OPTION = "c";
    private static final String FIRMWARE_OPTION = "f";
    private static final String FIRMWARE_IMAGE_OPTION = "i";
    private static final String PASSWORD_OPTION = "p";
    private static final String GENERATE_PASSWORD_OPTION = "P";
    private static final String NODENAME_OPTION = "n";
    private static final String MODEL_OPTION = "m";
    private static final String AUTODETECT_MODEL_OPTION = "a";

    private final DeviceService _deviceService;
    private final FirmwareService _firmwareService;

    @Inject
    public CommandLineParserImpl(final DeviceService deviceService, final FirmwareService firmwareService) {
        _deviceService = deviceService;
        _firmwareService = firmwareService;
    }

    private Options createOptions() {
        final Options options = new Options();
        options.addOption(new Option(HELP_OPTION, "help", false, "Show this help."));
        options.addOption(new Option(LIST_MODELS_OPTION, "list-models", false, "List supported models."));
        options.addOption(new Option(LIST_FIRMWARES_OPTION, "list-firmwares", false, "List supported firmwares."));
        options.addOption(new Option(DEPLOY_OPTION, "deploy", false, "Deploy the firmware to the device."));
        options.addOption(
                new Option(CONFIGURE_OPTION, "configure", false, "Configure the firmware on the device."));
        options.addOption(new Option(FIRMWARE_OPTION, "firmware", true, "The firmware to configure."));
        options.addOption(new Option(FIRMWARE_IMAGE_OPTION, "image", true, "The firmware image."));
        options.addOption(new Option(PASSWORD_OPTION, "password", true, "The new root password for the device."));
        options.addOption(new Option(GENERATE_PASSWORD_OPTION, "gen-password", false,
                "The root password for the device will be generated."));
        options.addOption(
                new Option(NODENAME_OPTION, "nodename", true, "The name for the node. Will also be the hostname."));
        options.addOption(new Option(MODEL_OPTION, "model", true, "The model."));
        options.addOption(new Option(AUTODETECT_MODEL_OPTION, "autodetect-model", false, "Autodetect the model."));

        return options;
    }

    private String getLongOption(final Options options, final String shortOption) {
        return Preconditions.checkNotNull(options.getOption(shortOption).getLongOpt(),
                "No long option defined for: " + shortOption);
    }

    private static String getArgValue(final CommandLine commandLine, final String option, final String errorMessage)
            throws CommandLineParsingException {
        final String value = Strings.nullToEmpty(commandLine.getOptionValue(option)).trim();

        if (value.isEmpty()) {
            throw new CommandLineParsingException(errorMessage);
        }

        return value;
    }

    @Override
    public AutoDeployOptions parse(final String[] args) throws CommandLineParsingException {
        final Options options = createOptions();
        final PosixParser parser = new PosixParser();

        final CommandLine commandLine;
        try {
            commandLine = parser.parse(options, args);
        } catch (final ParseException e) {
            throw new CommandLineParsingException(e.getMessage(), e);
        }

        if (commandLine.hasOption(HELP_OPTION)) {
            return AutoDeployOptions.forHelp();
        }

        final boolean listFirmwares = commandLine.hasOption(LIST_FIRMWARES_OPTION);
        final boolean listModels = commandLine.hasOption(LIST_MODELS_OPTION);

        if (listFirmwares || listModels) {
            return AutoDeployOptions.forListings(listFirmwares, listModels);
        }

        final ImmutableSet.Builder<PhaseOptions> phases = ImmutableSet.builder();

        final boolean deploy = commandLine.hasOption(DEPLOY_OPTION);
        if (deploy) {
            final boolean deviceGiven = commandLine.hasOption(MODEL_OPTION);
            final boolean autodetectDevice = commandLine.hasOption(AUTODETECT_MODEL_OPTION);

            if (deviceGiven && autodetectDevice) {
                throw new CommandLineParsingException("Specifying both --" + getLongOption(options, MODEL_OPTION)
                        + " and --" + getLongOption(options, AUTODETECT_MODEL_OPTION) + " is not supported.");
            }

            if (!deviceGiven && !autodetectDevice) {
                throw new CommandLineParsingException("Neither --" + getLongOption(options, MODEL_OPTION)
                        + " nor --" + getLongOption(options, AUTODETECT_MODEL_OPTION) + " is given.");
            }

            final String deviceString = autodetectDevice ? null
                    : getArgValue(commandLine, MODEL_OPTION, "Model not set.");

            final Device device;

            if (deviceGiven) {
                device = _deviceService.findSupportedDevice(deviceString);

                if (device == null) {
                    throw new CommandLineParsingException("Unknown device: " + deviceString);
                }
            } else {
                device = null;
            }

            final String firmwareFileString = getArgValue(commandLine, FIRMWARE_IMAGE_OPTION,
                    "No firmware image specified.");

            final File firmwareImage = new File(firmwareFileString);
            phases.add(PhaseOptions.forDeployPhase(device, autodetectDevice, firmwareImage));
        }

        final boolean configure = commandLine.hasOption(CONFIGURE_OPTION);
        if (configure) {
            final String firmwareString = getArgValue(commandLine, FIRMWARE_OPTION, "No firmware specified.");
            final Firmware firmware = _firmwareService.findSupportedFirmware(firmwareString);

            if (firmware == null) {
                throw new CommandLineParsingException("Unknown firmware: " + firmwareString);
            }

            final String nodename = getArgValue(commandLine, NODENAME_OPTION, "Node name not set.");

            final boolean passwordGiven = commandLine.hasOption(PASSWORD_OPTION);
            final boolean generatePassword = commandLine.hasOption(GENERATE_PASSWORD_OPTION);

            if (passwordGiven && generatePassword) {
                throw new CommandLineParsingException("Specifying both --" + getLongOption(options, PASSWORD_OPTION)
                        + " and --" + getLongOption(options, GENERATE_PASSWORD_OPTION) + " is not supported.");
            }

            if (!passwordGiven && !generatePassword) {
                throw new CommandLineParsingException("Neither --" + getLongOption(options, PASSWORD_OPTION)
                        + " nor --" + getLongOption(options, GENERATE_PASSWORD_OPTION) + " is given.");
            }

            if (passwordGiven) {
                final String password = getArgValue(commandLine, PASSWORD_OPTION, "Root password not set.");

                phases.add(PhaseOptions.forConfigurePhase(firmware, nodename, password));
            } else {
                phases.add(PhaseOptions.forConfigurePhase(firmware, nodename));
            }
        }

        return AutoDeployOptions.forPhases(phases.build());
    }

    @Override
    public String getHelpText() {
        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        final PrintWriter writer = new PrintWriter(outputStream);

        final HelpFormatter helpFormatter = new HelpFormatter();
        helpFormatter.printHelp(writer, helpFormatter.getWidth(), "ff-autodeploy", null, // no header
                createOptions(), helpFormatter.getLeftPadding(), helpFormatter.getDescPadding(), null, // no footer
                false // no auto usage
        );

        writer.flush();
        return new String(outputStream.toByteArray());
    }
}