| /******************************************************************************* |
| * Copyright (c) 2019 Ericsson, École Polytechnique de Montréal |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.internal.provisional.tmf.cli.core.parser; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| |
| import org.apache.commons.cli.CommandLine; |
| import org.apache.commons.cli.CommandLineParser; |
| import org.apache.commons.cli.HelpFormatter; |
| import org.apache.commons.cli.Options; |
| import org.apache.commons.cli.ParseException; |
| import org.apache.commons.cli.PosixParser; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubMonitor; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.internal.tmf.cli.core.Activator; |
| import org.eclipse.tracecompass.internal.tmf.cli.core.parser.CliParserConfigElement; |
| import org.eclipse.tracecompass.internal.tmf.cli.core.parser.Messages; |
| |
| /** |
| * Utility class to manage cli actions |
| * |
| * @author Matthew Khouzam |
| * @author Bernd Hufmann |
| * @author Geneviève Bastien |
| */ |
| public final class CliParserManager { |
| |
| private static final String CLI_ARGS_PREFIX = "--cli"; //$NON-NLS-1$ |
| |
| /** |
| * The CLI Parser instance |
| */ |
| private static @Nullable CliParserManager INSTANCE = null; |
| |
| private final Options fOptions; |
| |
| /** |
| * Constructor, not to be used |
| */ |
| private CliParserManager() { |
| Collection<@NonNull ICliParser> cliParsers = getCliParsers(); |
| Options options = new Options(); |
| for (ICliParser parser : cliParsers) { |
| for (CliOption option : parser.getCmdLineOptions()) { |
| options.addOption(option.toCliOption()); |
| } |
| } |
| fOptions = options; |
| } |
| |
| /** |
| * Get the instance of this class |
| * |
| * @return The instance |
| */ |
| public static synchronized CliParserManager getInstance() { |
| CliParserManager instance = INSTANCE; |
| if (instance == null) { |
| instance = new CliParserManager(); |
| INSTANCE = instance; |
| } |
| return instance; |
| } |
| |
| /** |
| * Get the CLI actions available |
| * |
| * @return A collection of CLI actions |
| */ |
| public static Collection<ICliParser> getCliParsers() { |
| return CliParserConfigElement.getInstance().getParsers(); |
| } |
| |
| /** |
| * Parse the command line arguments and return the result of the parsing |
| * |
| * @param args |
| * The arguments of the application |
| * @return The parsed command line, or <code>null</code> if there were no |
| * options given |
| * @throws CliParserException |
| * If there were exceptions parsing the arguments |
| */ |
| public @Nullable CliCommandLine parse(String[] args) throws CliParserException { |
| List<String> tcArgs = new ArrayList<>(); |
| boolean found = false; |
| boolean addNext = false; |
| for (String arg : args) { |
| if (arg.equals(CLI_ARGS_PREFIX)) { |
| found = true; |
| continue; |
| } |
| if (found) { |
| tcArgs.add(arg); |
| } else if (arg.equals("--open")) { //$NON-NLS-1$ |
| // Legacy parsing of the --open option, without preceding --cli |
| System.out.println(Messages.CliParser_WarningCliPrefix); |
| tcArgs.add(arg); |
| addNext = true; |
| } else if (addNext) { |
| tcArgs.add(arg); |
| addNext = false; |
| } |
| } |
| if (tcArgs.isEmpty()) { |
| return null; |
| } |
| CommandLineParser cmdLineParser = new PosixParser(); |
| try { |
| // There may not be one and only one command line, do not keep the |
| // command line as internal field of this class |
| CommandLine cmdLine = cmdLineParser.parse(fOptions, tcArgs.toArray(new String[tcArgs.size()]), false); |
| if (cmdLine != null) { |
| CliCommandLine cliCommandLine = new CliCommandLine(cmdLine); |
| return cliCommandLine; |
| } |
| } catch (ParseException e) { |
| // Print to screen the error and help text and re-throw the |
| // exception |
| System.out.println(Messages.CliParser_ErrorParsingArguments); |
| System.out.println(e); |
| System.out.println(); |
| printHelpText(); |
| throw new CliParserException(String.valueOf(e.getMessage())); |
| } |
| return null; |
| } |
| |
| /** |
| * Print the help text for the command line |
| */ |
| public void printHelpText() { |
| HelpFormatter helpFormatter = new HelpFormatter(); |
| helpFormatter.printHelp(Messages.CliParser_HelpTextIntro, fOptions); |
| } |
| |
| /** |
| * Handle early command line option, at a stage where the application is not |
| * fully loaded yet, but loading. This is the ideal place to handle help |
| * options or other options that should give instant feedback to the user, |
| * without having to fully open the interface. |
| * |
| * The return value of this method indicate whether to shutdown the |
| * application after executing the option or continue loading. |
| * |
| * @param commandLine |
| * The command line that was previously parsed using the |
| * {@link #parse(String[])} method |
| * |
| * @return <code>true</code> if an option was handled, or <code>false</code> |
| * otherwise. At this stage, a return value of <code>true</code> |
| * will cause the application not to continue loading and do a quick |
| * return. |
| */ |
| public static boolean applicationStartup(CliCommandLine commandLine) { |
| boolean optionsHandled = false; |
| for (ICliParser parser : getCliParsers()) { |
| optionsHandled |= parser.preStartup(commandLine); |
| } |
| return optionsHandled; |
| } |
| |
| private static class ExecuteCliParsersJob extends Job { |
| |
| private final CliCommandLine fCommandLine; |
| |
| /** |
| * Constructor |
| * |
| * @param commandLine |
| * the trace element |
| */ |
| public ExecuteCliParsersJob(CliCommandLine commandLine) { |
| super("Executing CLI parser"); //$NON-NLS-1$ |
| fCommandLine = commandLine; |
| } |
| |
| @Override |
| protected IStatus run(@Nullable IProgressMonitor monitor) { |
| SubMonitor subMonitor = SubMonitor.convert(monitor); |
| Collection<ICliParser> cliParsers = getCliParsers(); |
| subMonitor.beginTask("Executing CLI Parsers", cliParsers.size()); //$NON-NLS-1$ |
| for (ICliParser parser : cliParsers) { |
| if (subMonitor.isCanceled()) { |
| return Status.CANCEL_STATUS; |
| } |
| subMonitor.subTask("Executing parser :" + parser.getCmdLineOptions().toString()); //$NON-NLS-1$ |
| IStatus status = parser.workspaceLoading(fCommandLine, subMonitor); |
| if (!status.isOK()) { |
| Activator.getInstance().getLog().log(status); |
| } |
| } |
| return Status.OK_STATUS; |
| } |
| } |
| |
| /** |
| * Get a job that will handle the command line options. It is the caller's |
| * responsibility to schedule the job and do any appropriate actions for |
| * proper termination and cancellation from the user. |
| * |
| * This method will create a Job in which each CLI parser, ordered by |
| * priority, will execute its action sequentially. When the job is done, all |
| * CLI parsers will have been executed |
| * |
| * @param commandLine |
| * The command line that was previously parsed using the |
| * {@link #parse(String[])} method |
| * @return The workspace loading job, so it can be cancelled by caller |
| */ |
| public static Job getWorkspaceLoadingJob(CliCommandLine commandLine) { |
| return new ExecuteCliParsersJob(commandLine); |
| } |
| |
| } |