org.syncany.cli.PluginCommand.java Source code

Java tutorial

Introduction

Here is the source code for org.syncany.cli.PluginCommand.java

Source

/*
 * Syncany, www.syncany.org
 * Copyright (C) 2011-2015 Philipp C. Heckel <philipp.heckel@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.syncany.cli;

import static java.util.Arrays.asList;

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

import org.syncany.cli.util.CliTableUtil;
import org.syncany.operations.OperationResult;
import org.syncany.operations.daemon.messages.ConnectToHostExternalEvent;
import org.syncany.operations.daemon.messages.PluginInstallExternalEvent;
import org.syncany.operations.plugin.ExtendedPluginInfo;
import org.syncany.operations.plugin.PluginInfo;
import org.syncany.operations.plugin.PluginOperation;
import org.syncany.operations.plugin.PluginOperationAction;
import org.syncany.operations.plugin.PluginOperationOptions;
import org.syncany.operations.plugin.PluginOperationOptions.PluginListMode;
import org.syncany.operations.plugin.PluginOperationResult;
import org.syncany.operations.plugin.PluginOperationResult.PluginResultCode;
import org.syncany.util.StringUtil;

import com.google.common.collect.Iterables;
import com.google.common.eventbus.Subscribe;

import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;

public class PluginCommand extends Command {
    private boolean minimalOutput = false;

    @Override
    public CommandScope getRequiredCommandScope() {
        return CommandScope.ANY;
    }

    @Override
    public boolean canExecuteInDaemonScope() {
        return false; // TODO [low] Doesn't have an impact if command scope is ANY
    }

    @Override
    public int execute(String[] operationArgs) throws Exception {
        PluginOperationOptions operationOptions = parseOptions(operationArgs);
        PluginOperationResult operationResult = new PluginOperation(config, operationOptions).execute();

        printResults(operationResult);

        return 0;
    }

    @Override
    public PluginOperationOptions parseOptions(String[] operationArgs) throws Exception {
        PluginOperationOptions operationOptions = new PluginOperationOptions();

        OptionParser parser = new OptionParser();
        OptionSpec<Void> optionLocal = parser.acceptsAll(asList("L", "local-only"));
        OptionSpec<Void> optionRemote = parser.acceptsAll(asList("R", "remote-only"));
        OptionSpec<Void> optionSnapshots = parser.acceptsAll(asList("s", "snapshot", "snapshots"));
        OptionSpec<Void> optionMinimalOutput = parser.acceptsAll(asList("m", "minimal-output"));
        OptionSpec<String> optionApiEndpoint = parser.acceptsAll(asList("a", "api-endpoint")).withRequiredArg();

        OptionSet options = parser.parse(operationArgs);

        // Files
        List<?> nonOptionArgs = options.nonOptionArguments();

        if (nonOptionArgs.size() == 0) {
            throw new Exception("Invalid syntax, please specify an action (list, install, remove, update).");
        }

        // <action>
        String actionStr = nonOptionArgs.get(0).toString();
        PluginOperationAction action = parsePluginAction(actionStr);

        operationOptions.setAction(action);

        // --minimal-output
        minimalOutput = options.has(optionMinimalOutput);

        // --snapshots
        operationOptions.setSnapshots(options.has(optionSnapshots));

        // --api-endpoint
        if (options.has(optionApiEndpoint)) {
            operationOptions.setApiEndpoint(options.valueOf(optionApiEndpoint));
        }

        // install|remove <plugin-id>
        if (action == PluginOperationAction.INSTALL || action == PluginOperationAction.REMOVE) {
            if (nonOptionArgs.size() != 2) {
                throw new Exception("Invalid syntax, please specify a plugin ID.");
            }

            // <plugin-id>
            String pluginId = nonOptionArgs.get(1).toString();
            operationOptions.setPluginId(pluginId);
        }

        // --local-only, --remote-only
        else if (action == PluginOperationAction.LIST) {
            if (options.has(optionLocal)) {
                operationOptions.setListMode(PluginListMode.LOCAL);
            } else if (options.has(optionRemote)) {
                operationOptions.setListMode(PluginListMode.REMOTE);
            } else {
                operationOptions.setListMode(PluginListMode.ALL);
            }

            // <plugin-id> (optional in 'list' or 'update')
            if (nonOptionArgs.size() == 2) {
                String pluginId = nonOptionArgs.get(1).toString();
                operationOptions.setPluginId(pluginId);
            }
        }

        else if (action == PluginOperationAction.UPDATE && nonOptionArgs.size() == 2) {
            String pluginId = nonOptionArgs.get(1).toString();
            operationOptions.setPluginId(pluginId);
        }

        return operationOptions;
    }

    private PluginOperationAction parsePluginAction(String actionStr) throws Exception {
        try {
            return PluginOperationAction.valueOf(actionStr.toUpperCase());
        } catch (Exception e) {
            throw new Exception("Invalid syntax, unknown action '" + actionStr + "'");
        }
    }

    @Override
    public void printResults(OperationResult operationResult) {
        PluginOperationResult concreteOperationResult = (PluginOperationResult) operationResult;

        switch (concreteOperationResult.getAction()) {
        case LIST:
            printResultList(concreteOperationResult);
            return;

        case INSTALL:
            printResultInstall(concreteOperationResult);
            return;

        case REMOVE:
            printResultRemove(concreteOperationResult);
            return;

        case UPDATE:
            printResultUpdate(concreteOperationResult);
            return;

        default:
            out.println("Unknown action: " + concreteOperationResult.getAction());
        }
    }

    private void printResultList(PluginOperationResult operationResult) {
        if (operationResult.getResultCode() == PluginResultCode.OK) {
            List<String[]> tableValues = new ArrayList<String[]>();

            tableValues.add(new String[] { "Id", "Name", "Local Version", "Type", "Remote Version", "Updatable",
                    "Provided By" });

            int outdatedCount = 0;
            int updatableCount = 0;
            int thirdPartyCount = 0;

            for (ExtendedPluginInfo extPluginInfo : operationResult.getPluginList()) {
                PluginInfo pluginInfo = (extPluginInfo.isInstalled()) ? extPluginInfo.getLocalPluginInfo()
                        : extPluginInfo.getRemotePluginInfo();

                String localVersionStr = (extPluginInfo.isInstalled())
                        ? extPluginInfo.getLocalPluginInfo().getPluginVersion()
                        : "";
                String installedStr = extPluginInfo.isInstalled()
                        ? (extPluginInfo.canUninstall() ? "User" : "Global")
                        : "";
                String remoteVersionStr = (extPluginInfo.isRemoteAvailable())
                        ? extPluginInfo.getRemotePluginInfo().getPluginVersion()
                        : "";
                String thirdPartyStr = (pluginInfo.isPluginThirdParty()) ? "Third Party" : "Syncany Team";
                String updatableStr = "";

                if (extPluginInfo.isInstalled() && extPluginInfo.isOutdated()) {
                    if (extPluginInfo.canUninstall()) {
                        updatableStr = "Auto";
                        updatableCount++;
                    } else {
                        updatableStr = "Manual";
                    }

                    outdatedCount++;
                }

                if (pluginInfo.isPluginThirdParty()) {
                    thirdPartyCount++;
                }

                tableValues.add(new String[] { pluginInfo.getPluginId(), pluginInfo.getPluginName(),
                        localVersionStr, installedStr, remoteVersionStr, updatableStr, thirdPartyStr });
            }

            CliTableUtil.printTable(out, tableValues, "No plugins found.");

            if (outdatedCount > 0) {
                String isAre = (outdatedCount == 1) ? "is" : "are";
                String pluginPlugins = (outdatedCount == 1) ? "plugin" : "plugins";

                out.printf("\nUpdates:\nThere %s %d outdated %s, %d of them %s automatically updatable.\n", isAre,
                        outdatedCount, pluginPlugins, updatableCount, isAre);
            }

            if (thirdPartyCount > 0) {
                String pluginPlugins = (thirdPartyCount == 1) ? "plugin" : "plugins";
                out.printf(
                        "\nThird party plugins:\nPlease note that the Syncany Team does not review or maintain the third-party %s\nlisted above. Please report issues to the corresponding plugin site.\n",
                        pluginPlugins);
            }
        } else {
            out.printf("Listing plugins failed. No connection? Try -d to get more details.\n");
            out.println();
        }
    }

    private void printResultInstall(PluginOperationResult operationResult) {
        // Print minimal result
        if (minimalOutput) {
            if (operationResult.getResultCode() == PluginResultCode.OK) {
                out.println("OK");
            } else {
                out.println("NOK");
            }
        }
        // Print regular result
        else {
            if (operationResult.getResultCode() == PluginResultCode.OK) {
                out.printf("Plugin successfully installed from %s\n", operationResult.getSourcePluginPath());
                out.printf("Install location: %s\n", operationResult.getTargetPluginPath());
                out.println();

                printPluginDetails(operationResult.getAffectedPluginInfo());
                printPluginConflictWarning(operationResult);
            } else {
                out.println("Plugin installation failed. Try -d to get more details.");
                out.println();
            }
        }
    }

    private void printResultUpdate(final PluginOperationResult operationResult) {
        // Print regular result
        if (operationResult.getResultCode() == PluginResultCode.OK) {
            if (operationResult.getUpdatedPluginIds().size() == 0) {
                out.println("All plugins are up to date.");
            } else {
                Iterables.removeAll(operationResult.getUpdatedPluginIds(), operationResult.getErroneousPluginIds());
                Iterables.removeAll(operationResult.getUpdatedPluginIds(), operationResult.getDelayedPluginIds());

                if (operationResult.getDelayedPluginIds().size() > 0) {
                    out.printf("Plugins to be updated: %s\n",
                            StringUtil.join(operationResult.getDelayedPluginIds(), ", "));
                }

                if (operationResult.getUpdatedPluginIds().size() > 0) {
                    out.printf("Plugins successfully updated: %s\n",
                            StringUtil.join(operationResult.getUpdatedPluginIds(), ", "));
                }

                if (operationResult.getErroneousPluginIds().size() > 0) {
                    out.printf("Failed to update %s. Try -d to get more details\n",
                            StringUtil.join(operationResult.getErroneousPluginIds(), ", "));
                }

                out.println();
            }
        } else {
            out.println("Plugin update failed. Try -d to get more details.");
            out.println();
        }
    }

    private void printPluginConflictWarning(PluginOperationResult operationResult) {
        List<String> conflictingPluginIds = operationResult.getConflictingPluginIds();

        if (conflictingPluginIds != null && conflictingPluginIds.size() > 0) {
            out.println("---------------------------------------------------------------------------");
            out.printf(" WARNING: The installed plugin '%s' conflicts with other installed:\n",
                    operationResult.getAffectedPluginInfo().getPluginId());
            out.printf("          plugin(s): %s\n", StringUtil.join(conflictingPluginIds, ", "));
            out.println();
            out.println(" If you'd like to use these plugins in the daemon, it is VERY likely");
            out.println(" that parts of the application WILL CRASH. Data corruption might occur!");
            out.println();
            out.println(" Using the plugins outside of the daemon (sy <command> ...) might also");
            out.println(" be an issue. Details about this in issue #154.");
            out.println("---------------------------------------------------------------------------");
            out.println();
        }
    }

    private void printResultRemove(PluginOperationResult operationResult) {
        // Print minimal result
        if (minimalOutput) {
            if (operationResult.getResultCode() == PluginResultCode.OK) {
                out.println("OK");
            } else {
                out.println("NOK");
            }
        }
        // Print regular result
        else {
            if (operationResult.getResultCode() == PluginResultCode.OK) {
                out.printf("Plugin successfully removed.\n");
                out.printf("Original local was %s\n", operationResult.getSourcePluginPath());
                out.println();
            } else {
                out.println("Plugin removal failed.");
                out.println();

                out.println("Note: Plugins shipped with the application or additional packages");
                out.println("      cannot be removed. These plugin are marked 'Global' in the list.");
                out.println();
            }
        }
    }

    private void printPluginDetails(PluginInfo pluginInfo) {
        out.println("Plugin details:");
        out.println("- ID: " + pluginInfo.getPluginId());
        out.println("- Name: " + pluginInfo.getPluginName());
        out.println("- Version: " + pluginInfo.getPluginVersion());
        out.println();
    }

    @Subscribe
    public void onConnectToHostEventReceived(ConnectToHostExternalEvent event) {
        if (!minimalOutput) {
            out.printr("Connecting to " + event.getHost() + " ...");
        }
    }

    @Subscribe
    public void onPluginInstallEventReceived(PluginInstallExternalEvent event) {
        if (!minimalOutput) {
            out.printr("Installing plugin from " + event.getSource() + " ...");
        }
    }
}