/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
*
* 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.google.dart.tools.core;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Instances of {@code CmdLineOptions} parse and cache options specified on the command line via the
* {@link #parseCmdLine(String[])} method. Command line arguments can include:
* <ul>
* <li>{@value #PERF} [start-time-in-milliseconds]</li>
* <li>{@value #AUTO_EXIT}</li>
* <li>/path/to/file.dart</li>
* </ul>
* Regardless of the other flags, the editor should open an editor tag for each *.dart file
* specified on the command line, and open a project for each directory specified on the command
* line.
*
* @coverage dart.tools.core
*/
public class CmdLineOptions {
public static final String PACKAGE_ROOT = "--package-root";
public static final String PACKAGE_OVERRIDE = "--package-override-directory";
private static final String AUTO_EXIT = "--auto-exit";
private static final String OPEN = "--open";
private static final String PERF = "--perf";
private static final String TEST = "--test";
private static final String EXPERIMENTAL = "--experimental";
private static final String NO_INSTRUMENTATION = "--no-instrumentation";
private static CmdLineOptions globalOptions;
/**
* Answer the options specified on the command line.
*
* @return the options or {@code null} if {@link #setOptions(CmdLineOptions)} has not been called
*/
public static CmdLineOptions getOptions() {
return globalOptions;
}
/**
* Parse the specified command line arguments and return an object representing the options
* specified on the command line.
*
* @param args the command line arguments (not {@code null}, contains no {@code null}s)
* @return the options (not {@code null})
*/
public static CmdLineOptions parseCmdLine(String[] args) {
CmdLineOptions options = new CmdLineOptions();
ArrayList<File> roots = new ArrayList<File>();
int index = 0;
while (index < args.length) {
String arg = args[index++];
if (arg.equals(AUTO_EXIT)) {
options.autoExit = true;
} else if (arg.equals(OPEN)) {
while (isOptionValue(args, index)) {
options.files.add(new File(args[index]));
index++;
}
} else if (arg.equals(EXPERIMENTAL)) {
options.experimental = true;
} else if (arg.equals(NO_INSTRUMENTATION)) {
options.allowInstrumentation = false;
} else if (arg.equals(PERF)) {
// --perf [<startTime-in-milliseconds>]
options.measurePerformance = true;
options.startTime = System.currentTimeMillis();
options.autoExit = true;
if (isOptionValue(args, index)) {
try {
options.startTime = Long.valueOf(args[index]);
index++;
} catch (NumberFormatException e) {
}
}
} else if (arg.equals(PACKAGE_ROOT)) {
while (isOptionValue(args, index)) {
roots.add(new File(args[index]).getAbsoluteFile());
index++;
}
if (roots.size() == 0) {
options.warning("Expected path after " + PACKAGE_ROOT);
}
} else if (arg.equals(PACKAGE_OVERRIDE)) {
if (isOptionValue(args, index)) {
options.packageOverrideDirectory = new File(args[index]).getAbsoluteFile();
index++;
} else {
options.warning("Expected path after " + PACKAGE_OVERRIDE);
}
} else if (arg.equals(TEST)) {
options.runTests = true;
if (isOptionValue(args, index)) {
options.runTestName = args[index];
index++;
}
} else if (arg.equals("-version") || arg.equals("-port") || arg.equals("-testLoaderClass")
|| arg.equals("-loaderpluginname") || arg.equals("-classNames")
|| arg.equals("-testApplication") || arg.equals("-testpluginname") || arg.equals("-test")) {
options.junitTestsAreRunning = true;
// Ignore jUnit arguments
if (isOptionValue(args, index)) {
index++;
}
} else if (arg.length() > 0) {
options.warning("Unknown option: " + arg);
}
}
options.packageRoots = roots.toArray(new File[roots.size()]);
return options;
}
/**
* Set the options specified on the command line.
*
* @param options the options (not {@code null})
*/
public static void setOptions(CmdLineOptions options) {
// Sanity check
if (CmdLineOptions.globalOptions != null) {
throw new RuntimeException("Options have already been set");
}
CmdLineOptions.globalOptions = options;
}
/**
* Answer {@code true} if the specified argument does not start with a "-"
*
* @param arg the command line argument being tested
* @return {@code true} if the argument is a value
*/
private static boolean isOptionValue(String value) {
return value.length() <= 0 || value.charAt(0) != '-';
}
/**
* Answer {@code true} if the specified argument exists and does not start with a "-"
*
* @param args the command line arguments
* @param index the index of the argument being tested
* @return {@code true} if the argument is a value
*/
private static boolean isOptionValue(String[] args, int index) {
if (index >= args.length) {
return false;
}
return isOptionValue(args[index]);
}
// options
private final ArrayList<File> files = new ArrayList<File>();
private boolean autoExit = false;
private boolean measurePerformance = false;
private boolean runTests = false;
private String runTestName = null;
private boolean junitTestsAreRunning = false;
private long startTime;
private File[] packageRoots = null;
private File packageOverrideDirectory = null;
private ArrayList<String> warnings = new ArrayList<String>();
private boolean experimental = false;
private boolean allowInstrumentation = true;
// use parseCmdLine(...) to construct new options
private CmdLineOptions() {
}
/**
* Determine if instrumentation should be allowed.
* Specifying the --no-instrumentation flag on the command line will prevent instrumentation
* from running regardless of whether instrumentation is installed.
*
* @return {@code true} if instrumentation should be allowed, else {@code false}
*/
public boolean allowInstrumentation() {
return allowInstrumentation;
}
/**
* Answer {@code true} if the {@value CmdLineOptions#AUTO_EXIT} (or the deprecated
* {@value #KILL_AFTER_PERF_OLD}) is specified on the command line indicating that the Editor
* should exit after all the performance numbers and test results have been echoed to standard
* out.
*/
public boolean getAutoExit() {
return autoExit;
}
/**
* Answer <code>true</code> if {@value #EXPERIMENTAL} is specified on the command line indicating
* that the Editor should use experimental code during execution.
*/
public boolean getExperimental() {
return experimental;
}
/**
* Answer the files specified on the command line.
*
* @return an array of files (not {@code null}, contains no {@code null}s)
*/
public ArrayList<File> getFiles() {
return files;
}
/**
* Answer {@code true} if the {@value CmdLineOptions#PERF} is specified on the command line
* indicating that performance should be measured and echoed to standard out.
*/
public boolean getMeasurePerformance() {
return measurePerformance;
}
/**
* Answer a string representing the package override directory specified on the command line.
*
* @return the package override directory or {@code null} if none specified
*/
public File getPackageOverrideDirectory() {
return packageOverrideDirectory;
}
/**
* Answer the package roots specified on the command line or an empty list if none.
*
* @return the package roots (not {@code null}, contains no {@code null}s)
*/
public File[] getPackageRoots() {
return packageRoots;
}
/**
* Answer name of the test to run if {@link #getRunTests()} is {@code true}.
*/
public String getRunTestName() {
return runTestName;
}
/**
* Answer {@code true} if {@value #TEST} is specified on the command line indicating that the
* Editor should automatically run the Editor's suite of tests.
*/
public boolean getRunTests() {
return runTests && !junitTestsAreRunning;
}
/**
* Answer the start time in milliseconds (see {@link System#currentTimeMillis()} of Dart Editor
* for use during performance measurements. This is the numeric value specified on the command
* line immediately after the {@value CmdLineOptions#PERF} flag, or the time at which the command
* line arguments are parsed if the {@value CmdLineOptions#PERF} flag is not present or is not
* followed by a number.
*/
public long getStartTime() {
return startTime;
}
/**
* Answer the warnings generated when parsing options.
*
* @return a list of warnings (not {@code null}, contains no {@code null}s)
*/
public List<String> getWarnings() {
return warnings;
}
/**
* Echo warnings to {@link System#err}.
*/
public void printWarnings() {
for (String message : warnings) {
System.err.println(message);
}
}
/**
* Report a warning about the options being parsed
*
* @param message the warning message
*/
private void warning(String message) {
warnings.add(message);
}
}