b8da9bc651
R=brianwilkerson@google.com BUG= Review URL: https://codereview.chromium.org//725143004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@41792 260f80e4-7a28-3924-810f-c04153c831b5
420 lines
12 KiB
Dart
420 lines
12 KiB
Dart
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
library options;
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:args/args.dart';
|
|
|
|
const _BINARY_NAME = 'dartanalyzer';
|
|
|
|
/**
|
|
* Analyzer commandline configuration options.
|
|
*/
|
|
class CommandLineOptions {
|
|
/** The path to the dart SDK */
|
|
final String dartSdkPath;
|
|
|
|
/** A table mapping the names of defined variables to their values. */
|
|
final Map<String, String> definedVariables;
|
|
|
|
/** Whether to report hints */
|
|
final bool disableHints;
|
|
|
|
/** Whether to display version information */
|
|
final bool displayVersion;
|
|
|
|
/** Whether to enable support for the proposed async feature. */
|
|
final bool enableAsync;
|
|
|
|
/** Whether to enable support for the proposed enum feature. */
|
|
final bool enableEnum;
|
|
|
|
/**
|
|
* Whether to treat type mismatches found during constant evaluation as
|
|
* errors.
|
|
*/
|
|
final bool enableTypeChecks;
|
|
|
|
/** Whether to ignore unrecognized flags */
|
|
final bool ignoreUnrecognizedFlags;
|
|
|
|
/** Whether to log additional analysis messages and exceptions */
|
|
final bool log;
|
|
|
|
/** Whether to use machine format for error display */
|
|
final bool machineFormat;
|
|
|
|
/** The path to the package root */
|
|
final String packageRootPath;
|
|
|
|
/** Whether to show performance statistics */
|
|
final bool perf;
|
|
|
|
/** Batch mode (for unit testing) */
|
|
final bool shouldBatch;
|
|
|
|
/** Whether to show package: warnings */
|
|
final bool showPackageWarnings;
|
|
|
|
/** Whether to show SDK warnings */
|
|
final bool showSdkWarnings;
|
|
|
|
/** The source files to analyze */
|
|
final List<String> sourceFiles;
|
|
|
|
/** Whether to show both cold and hot performance statistics */
|
|
final bool warmPerf;
|
|
|
|
/** Whether to treat warnings as fatal */
|
|
final bool warningsAreFatal;
|
|
|
|
/**
|
|
* Initialize options from the given parsed [args].
|
|
*/
|
|
CommandLineOptions._fromArgs(ArgResults args, Map<String,
|
|
String> definedVariables)
|
|
: dartSdkPath = args['dart-sdk'],
|
|
this.definedVariables = definedVariables,
|
|
disableHints = args['no-hints'],
|
|
displayVersion = args['version'],
|
|
enableAsync = args['enable-async'],
|
|
enableEnum = args['enable-enum'],
|
|
enableTypeChecks = args['enable_type_checks'],
|
|
ignoreUnrecognizedFlags = args['ignore-unrecognized-flags'],
|
|
log = args['log'],
|
|
machineFormat = args['machine'] || args['format'] == 'machine',
|
|
packageRootPath = args['package-root'],
|
|
perf = args['perf'],
|
|
shouldBatch = args['batch'],
|
|
showPackageWarnings = args['show-package-warnings'] ||
|
|
args['package-warnings'],
|
|
showSdkWarnings = args['show-sdk-warnings'] || args['warnings'],
|
|
sourceFiles = args.rest,
|
|
warmPerf = args['warm-perf'],
|
|
warningsAreFatal = args['fatal-warnings'];
|
|
|
|
/**
|
|
* Parse [args] into [CommandLineOptions] describing the specified
|
|
* analyzer options. In case of a format error, prints error and exists.
|
|
*/
|
|
static CommandLineOptions parse(List<String> args) {
|
|
CommandLineOptions options = _parse(args);
|
|
// check SDK
|
|
{
|
|
var sdkPath = options.dartSdkPath;
|
|
// check that SDK is specified
|
|
if (sdkPath == null) {
|
|
print('Usage: $_BINARY_NAME: no Dart SDK found.');
|
|
exit(15);
|
|
}
|
|
// check that SDK is existing directory
|
|
if (!(new Directory(sdkPath)).existsSync()) {
|
|
print('Usage: $_BINARY_NAME: invalid Dart SDK path: $sdkPath');
|
|
exit(15);
|
|
}
|
|
}
|
|
// OK
|
|
return options;
|
|
}
|
|
|
|
static String _getVersion() {
|
|
try {
|
|
// This is relative to bin/snapshot, so ../..
|
|
String versionPath =
|
|
Platform.script.resolve('../../version').toFilePath();
|
|
File versionFile = new File(versionPath);
|
|
return versionFile.readAsStringSync().trim();
|
|
} catch (_) {
|
|
// This happens when the script is not running in the context of an SDK.
|
|
return "<unknown>";
|
|
}
|
|
}
|
|
|
|
static CommandLineOptions _parse(List<String> args) {
|
|
args = args.expand((String arg) => arg.split('=')).toList();
|
|
var parser = new _CommandLineParser()
|
|
..addFlag(
|
|
'batch',
|
|
abbr: 'b',
|
|
help: 'Run in batch mode',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addOption('dart-sdk', help: 'The path to the Dart SDK')
|
|
..addOption(
|
|
'package-root',
|
|
abbr: 'p',
|
|
help:
|
|
'The path to the package root. The flag package-root is deprecated. Remove to use package information computed by pub.')
|
|
..addOption(
|
|
'format',
|
|
help: 'Specifies the format in which errors are displayed')
|
|
..addFlag(
|
|
'machine',
|
|
help: 'Print errors in a format suitable for parsing (deprecated)',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'version',
|
|
help: 'Print the analyzer version',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'no-hints',
|
|
help: 'Do not show hint results',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'ignore-unrecognized-flags',
|
|
help: 'Ignore unrecognized command line flags',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'fatal-warnings',
|
|
help: 'Treat non-type warnings as fatal',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'package-warnings',
|
|
help: 'Show warnings from package: imports',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'show-package-warnings',
|
|
help: 'Show warnings from package: imports (deprecated)',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'perf',
|
|
help: 'Show performance statistics',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'warnings',
|
|
help: 'Show warnings from SDK imports',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'show-sdk-warnings',
|
|
help: 'Show warnings from SDK imports (deprecated)',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
..addFlag(
|
|
'help',
|
|
abbr: 'h',
|
|
help: 'Display this help message',
|
|
defaultsTo: false,
|
|
negatable: false)
|
|
//
|
|
// Hidden flags.
|
|
//
|
|
..addFlag(
|
|
'enable-async',
|
|
help: 'Enable support for the proposed async feature',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: true)
|
|
..addFlag(
|
|
'enable-enum',
|
|
help: 'Enable support for the proposed enum feature',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: true)
|
|
..addFlag(
|
|
'log',
|
|
help: 'Log additional messages and exceptions',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: true)
|
|
..addFlag(
|
|
'warm-perf',
|
|
help: 'Show both cold and warm performance statistics',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: true)
|
|
..addFlag(
|
|
'enable_type_checks',
|
|
help: 'Check types in constant evaluation',
|
|
defaultsTo: false,
|
|
negatable: false,
|
|
hide: true);
|
|
|
|
try {
|
|
// TODO(scheglov) https://code.google.com/p/dart/issues/detail?id=11061
|
|
args =
|
|
args.map((String arg) => arg == '-batch' ? '--batch' : arg).toList();
|
|
Map<String, String> definedVariables = <String, String>{};
|
|
var results = parser.parse(args, definedVariables);
|
|
// help requests
|
|
if (results['help']) {
|
|
_showUsage(parser);
|
|
exit(0);
|
|
}
|
|
// batch mode and input files
|
|
if (results['batch']) {
|
|
if (results.rest.isNotEmpty) {
|
|
print('No source files expected in the batch mode.');
|
|
_showUsage(parser);
|
|
exit(15);
|
|
}
|
|
} else if (results['version']) {
|
|
print('$_BINARY_NAME version ${_getVersion()}');
|
|
exit(0);
|
|
} else {
|
|
if (results.rest.isEmpty) {
|
|
_showUsage(parser);
|
|
exit(15);
|
|
}
|
|
}
|
|
return new CommandLineOptions._fromArgs(results, definedVariables);
|
|
} on FormatException catch (e) {
|
|
print(e.message);
|
|
_showUsage(parser);
|
|
exit(15);
|
|
}
|
|
|
|
}
|
|
|
|
static _showUsage(parser) {
|
|
print('Usage: $_BINARY_NAME [options...] <libraries to analyze...>');
|
|
print(parser.getUsage());
|
|
print('');
|
|
print('For more information, see http://www.dartlang.org/tools/analyzer.');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Commandline argument parser.
|
|
*
|
|
* TODO(pquitslund): when the args package supports ignoring unrecognized
|
|
* options/flags, this class can be replaced with a simple [ArgParser] instance.
|
|
*/
|
|
class _CommandLineParser {
|
|
|
|
final List<String> _knownFlags;
|
|
final ArgParser _parser;
|
|
|
|
/** Creates a new command line parser */
|
|
_CommandLineParser()
|
|
: _knownFlags = <String>[],
|
|
_parser = new ArgParser(allowTrailingOptions: true);
|
|
|
|
|
|
/**
|
|
* Defines a flag.
|
|
*
|
|
* See [ArgParser.addFlag()].
|
|
*/
|
|
void addFlag(String name, {String abbr, String help, bool defaultsTo: false,
|
|
bool negatable: true, void callback(bool value), bool hide: false}) {
|
|
_knownFlags.add(name);
|
|
_parser.addFlag(
|
|
name,
|
|
abbr: abbr,
|
|
help: help,
|
|
defaultsTo: defaultsTo,
|
|
negatable: negatable,
|
|
callback: callback,
|
|
hide: hide);
|
|
}
|
|
|
|
/**
|
|
* Defines a value-taking option.
|
|
*
|
|
* See [ArgParser.addOption()].
|
|
*/
|
|
void addOption(String name, {String abbr, String help, List<String> allowed,
|
|
Map<String, String> allowedHelp, String defaultsTo, void callback(value),
|
|
bool allowMultiple: false}) {
|
|
_knownFlags.add(name);
|
|
_parser.addOption(
|
|
name,
|
|
abbr: abbr,
|
|
help: help,
|
|
allowed: allowed,
|
|
allowedHelp: allowedHelp,
|
|
defaultsTo: defaultsTo,
|
|
callback: callback,
|
|
allowMultiple: allowMultiple);
|
|
}
|
|
|
|
|
|
/**
|
|
* Generates a string displaying usage information for the defined options.
|
|
*
|
|
* See [ArgParser.usage].
|
|
*/
|
|
String getUsage() => _parser.usage;
|
|
|
|
/**
|
|
* Parses [args], a list of command-line arguments, matches them against the
|
|
* flags and options defined by this parser, and returns the result. The
|
|
* values of any defined variables are captured in the given map.
|
|
*
|
|
* See [ArgParser].
|
|
*/
|
|
ArgResults parse(List<String> args, Map<String, String> definedVariables) =>
|
|
_parser.parse(_filterUnknowns(parseDefinedVariables(args, definedVariables)));
|
|
|
|
List<String> parseDefinedVariables(List<String> args, Map<String,
|
|
String> definedVariables) {
|
|
int count = args.length;
|
|
List<String> remainingArgs = <String>[];
|
|
for (int i = 0; i < count; i++) {
|
|
String arg = args[i];
|
|
if (arg == '--') {
|
|
while (i < count) {
|
|
remainingArgs.add(args[i++]);
|
|
}
|
|
} else if (arg.startsWith("-D")) {
|
|
definedVariables[arg.substring(2)] = args[++i];
|
|
} else {
|
|
remainingArgs.add(arg);
|
|
}
|
|
}
|
|
return remainingArgs;
|
|
}
|
|
|
|
List<String> _filterUnknowns(args) {
|
|
|
|
// Only filter args if the ignore flag is specified.
|
|
if (!args.contains('--ignore-unrecognized-flags')) {
|
|
return args;
|
|
}
|
|
//TODO(pquitslund): replace w/ the following once library skew issues are
|
|
// sorted out
|
|
//return args.where((arg) => !arg.startsWith('--') ||
|
|
// _knownFlags.contains(arg.substring(2)));
|
|
|
|
// Filter all unrecognized flags and options.
|
|
var filtered = <String>[];
|
|
for (var i = 0; i < args.length; ++i) {
|
|
var arg = args[i];
|
|
if (arg.startsWith('--') && arg.length > 2) {
|
|
if (!_knownFlags.contains(arg.substring(2))) {
|
|
print('remove: $arg');
|
|
//"eat" params by advancing to the next flag/option
|
|
i = _getNextFlagIndex(args, i);
|
|
} else {
|
|
filtered.add(arg);
|
|
}
|
|
} else {
|
|
filtered.add(arg);
|
|
}
|
|
}
|
|
|
|
return filtered;
|
|
}
|
|
|
|
_getNextFlagIndex(args, i) {
|
|
for ( ; i < args.length; ++i) {
|
|
if (args[i].startsWith('--')) {
|
|
return i;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
}
|