blob: 5a4d1e55696d674710ca40572ff029e33fd704d1 [file] [log] [blame]
/*******************************************************************************
* 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);
}
}