Skip to content

Commit

Permalink
fixes #610, incorrect help output
Browse files Browse the repository at this point in the history
R=nweiz@google.com

Review URL: https://codereview.chromium.org/2244703003 .
  • Loading branch information
John Messerly committed Aug 12, 2016
1 parent 0aa5cbd commit 3627356
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 219 deletions.
65 changes: 2 additions & 63 deletions pkg/dev_compiler/bin/dartdevc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import 'dart:async';
import 'dart:io';
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:args/command_runner.dart';
import 'package:bazel_worker/bazel_worker.dart';
import 'package:dev_compiler/src/compiler/command.dart';

Expand All @@ -49,28 +48,10 @@ Future main(List<String> args) async {
if (args.contains('--persistent_worker')) {
new _CompilerWorker(args..remove('--persistent_worker')).run();
} else {
exitCode = await _runCommand(args);
exitCode = compile(args);
}
}

/// Runs a single compile command, and returns an exit code.
Future<int> _runCommand(List<String> args,
{MessageHandler messageHandler}) async {
try {
if (args.isEmpty || args.first != 'compile' && args.first != 'help') {
// TODO(jmesserly): we should deprecate the commands. For now they are
// still supported for backwards compatibility.
args.insert(0, 'compile');
}
var runner = new CommandRunner('dartdevc', 'Dart Development Compiler');
runner.addCommand(new CompileCommand(messageHandler: messageHandler));
await runner.run(args);
} catch (e, s) {
return _handleError(e, s, args, messageHandler: messageHandler);
}
return EXIT_CODE_OK;
}

/// Runs the compiler worker loop.
class _CompilerWorker extends AsyncWorkerLoop {
/// The original args supplied to the executable.
Expand All @@ -83,56 +64,14 @@ class _CompilerWorker extends AsyncWorkerLoop {
var args = _startupArgs.toList()..addAll(request.arguments);

var output = new StringBuffer();
var exitCode = await _runCommand(args, messageHandler: output.writeln);
var exitCode = compile(args, printFn: output.writeln);
AnalysisEngine.instance.clearCaches();
return new WorkResponse()
..exitCode = exitCode
..output = output.toString();
}
}

/// Handles [error] in a uniform fashion. Returns the proper exit code and calls
/// [messageHandler] with messages.
int _handleError(dynamic error, dynamic stackTrace, List<String> args,
{MessageHandler messageHandler}) {
messageHandler ??= print;

if (error is UsageException) {
// Incorrect usage, input file not found, etc.
messageHandler(error);
return 64;
} else if (error is CompileErrorException) {
// Code has error(s) and failed to compile.
messageHandler(error);
return 1;
} else {
// Anything else is likely a compiler bug.
//
// --unsafe-force-compile is a bit of a grey area, but it's nice not to
// crash while compiling
// (of course, output code may crash, if it had errors).
//
messageHandler("");
messageHandler("We're sorry, you've found a bug in our compiler.");
messageHandler("You can report this bug at:");
messageHandler(" https://github.com/dart-lang/dev_compiler/issues");
messageHandler("");
messageHandler(
"Please include the information below in your report, along with");
messageHandler(
"any other information that may help us track it down. Thanks!");
messageHandler("");
messageHandler(" dartdevc arguments: " + args.join(' '));
messageHandler(" dart --version: ${Platform.version}");
messageHandler("");
messageHandler("```");
messageHandler(error);
messageHandler(stackTrace);
messageHandler("```");
return 70;
}
}

/// Always returns a new modifiable list.
///
/// If the final arg is `@file_path` then read in all the lines of that file
Expand Down
6 changes: 3 additions & 3 deletions pkg/dev_compiler/lib/src/analyzer/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ class AnalyzerOptions {
/// Whether to resolve 'package:' uris using the multi-package resolver.
bool get useMultiPackage => packagePaths.isNotEmpty;

static ArgParser addArguments(ArgParser parser) {
return parser
static void addArguments(ArgParser parser) {
parser
..addOption('summary',
abbr: 's', help: 'summary file(s) to include', allowMultiple: true)
..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null)
Expand All @@ -86,7 +86,7 @@ class AnalyzerOptions {
help: 'Package root to resolve "package:" imports',
defaultsTo: 'packages/')
..addOption('url-mapping',
help: '--url-mapping=libraryUri,/path/to/library.dart uses \n'
help: '--url-mapping=libraryUri,/path/to/library.dart uses\n'
'library.dart as the source for an import of of "libraryUri".',
allowMultiple: true,
splitCommas: false)
Expand Down
231 changes: 142 additions & 89 deletions pkg/dev_compiler/lib/src/compiler/command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,116 +4,169 @@

import 'dart:convert' show JSON;
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/summary/package_bundle_reader.dart'
show InSummarySource;
import 'package:args/args.dart' show ArgParser, ArgResults;
import 'package:args/command_runner.dart' show UsageException;
import 'package:path/path.dart' as path;

import 'compiler.dart'
show BuildUnit, CompilerOptions, JSModuleFile, ModuleCompiler;
import '../analyzer/context.dart' show AnalyzerOptions;
import 'package:path/path.dart' as path;

typedef void MessageHandler(Object message);

/// The command for invoking the modular compiler.
class CompileCommand extends Command {
final MessageHandler messageHandler;
CompilerOptions _compilerOptions;

CompileCommand({MessageHandler messageHandler})
: this.messageHandler = messageHandler ?? print {
argParser.addOption('out', abbr: 'o', help: 'Output file (required)');
argParser.addOption('module-root',
help: 'Root module directory. '
'Generated module paths are relative to this root.');
argParser.addOption('library-root',
help: 'Root of source files. '
'Generated library names are relative to this root.');
argParser.addOption('build-root',
help: 'Deprecated in favor of --library-root');
CompilerOptions.addArguments(argParser);
AnalyzerOptions.addArguments(argParser);
final ArgParser _argParser = () {
var argParser = new ArgParser()
..addFlag('help', abbr: 'h', help: 'Display this message.')
..addOption('out', abbr: 'o', help: 'Output file (required).')
..addOption('module-root',
help: 'Root module directory.\n'
'Generated module paths are relative to this root.')
..addOption('library-root',
help: 'Root of source files.\n'
'Generated library names are relative to this root.')
..addOption('build-root',
help: 'Deprecated in favor of --library-root', hide: true);
AnalyzerOptions.addArguments(argParser);
CompilerOptions.addArguments(argParser);
return argParser;
}();

/// Runs a single compile for dartdevc.
///
/// This handles argument parsing, usage, error handling.
/// See bin/dartdevc.dart for the actual entry point, which includes Bazel
/// worker support.
int compile(List<String> args, {void printFn(Object obj)}) {
printFn ??= print;
ArgResults argResults;
try {
argResults = _argParser.parse(args);
} on FormatException catch (error) {
printFn('$error\n\n$_usageMessage');
return 64;
}
try {
_compile(argResults, printFn);
return 0;
} on UsageException catch (error) {
// Incorrect usage, input file not found, etc.
printFn(error);
return 64;
} on CompileErrorException catch (error) {
// Code has error(s) and failed to compile.
printFn(error);
return 1;
} catch (error, stackTrace) {
// Anything else is likely a compiler bug.
//
// --unsafe-force-compile is a bit of a grey area, but it's nice not to
// crash while compiling
// (of course, output code may crash, if it had errors).
//
printFn('''
We're sorry, you've found a bug in our compiler.
You can report this bug at:
https://github.com/dart-lang/dev_compiler/issues
Please include the information below in your report, along with
any other information that may help us track it down. Thanks!
dartdevc arguments: ${args.join(' ')}
dart --version: ${Platform.version}
```
$error
$stackTrace
```''');
return 70;
}
}

get name => 'compile';
get description => 'Compile a set of Dart files into a JavaScript module.';

@override
void run() {
var compiler =
new ModuleCompiler(new AnalyzerOptions.fromArguments(argResults));
_compilerOptions = new CompilerOptions.fromArguments(argResults);
var outPath = argResults['out'];
void _compile(ArgResults argResults, void printFn(Object obj)) {
var compiler =
new ModuleCompiler(new AnalyzerOptions.fromArguments(argResults));
var compilerOpts = new CompilerOptions.fromArguments(argResults);
if (argResults['help']) {
printFn(_usageMessage);
return;
}
var outPath = argResults['out'];

if (outPath == null) {
usageException('Please include the output file location. For example:\n'
' -o PATH/TO/OUTPUT_FILE.js');
}
if (outPath == null) {
_usageException('Please include the output file location. For example:\n'
' -o PATH/TO/OUTPUT_FILE.js');
}

var libraryRoot = argResults['library-root'] as String;
libraryRoot ??= argResults['build-root'] as String;
if (libraryRoot != null) {
libraryRoot = path.absolute(libraryRoot);
} else {
libraryRoot = Directory.current.path;
}
var moduleRoot = argResults['module-root'] as String;
String modulePath;
if (moduleRoot != null) {
moduleRoot = path.absolute(moduleRoot);
if (!path.isWithin(moduleRoot, outPath)) {
usageException('Output file $outPath must be within the module root '
'directory $moduleRoot');
}
modulePath =
path.withoutExtension(path.relative(outPath, from: moduleRoot));
} else {
moduleRoot = path.dirname(outPath);
modulePath = path.basenameWithoutExtension(outPath);
var libraryRoot = argResults['library-root'] as String;
libraryRoot ??= argResults['build-root'] as String;
if (libraryRoot != null) {
libraryRoot = path.absolute(libraryRoot);
} else {
libraryRoot = Directory.current.path;
}
var moduleRoot = argResults['module-root'] as String;
String modulePath;
if (moduleRoot != null) {
moduleRoot = path.absolute(moduleRoot);
if (!path.isWithin(moduleRoot, outPath)) {
_usageException('Output file $outPath must be within the module root '
'directory $moduleRoot');
}
modulePath =
path.withoutExtension(path.relative(outPath, from: moduleRoot));
} else {
moduleRoot = path.dirname(outPath);
modulePath = path.basenameWithoutExtension(outPath);
}

var unit = new BuildUnit(modulePath, libraryRoot, argResults.rest,
(source) => _moduleForLibrary(moduleRoot, source));
var unit = new BuildUnit(modulePath, libraryRoot, argResults.rest,
(source) => _moduleForLibrary(moduleRoot, source, compilerOpts));

JSModuleFile module = compiler.compile(unit, _compilerOptions);
module.errors.forEach(messageHandler);
JSModuleFile module = compiler.compile(unit, compilerOpts);
module.errors.forEach(printFn);

if (!module.isValid) throw new CompileErrorException();
if (!module.isValid) throw new CompileErrorException();

// Write JS file, as well as source map and summary (if requested).
new File(outPath).writeAsStringSync(module.code);
if (module.sourceMap != null) {
var mapPath = outPath + '.map';
new File(mapPath)
.writeAsStringSync(JSON.encode(module.placeSourceMap(mapPath)));
}
if (module.summaryBytes != null) {
var summaryPath = path.withoutExtension(outPath) +
'.${_compilerOptions.summaryExtension}';
new File(summaryPath).writeAsBytesSync(module.summaryBytes);
}
// Write JS file, as well as source map and summary (if requested).
new File(outPath).writeAsStringSync(module.code);
if (module.sourceMap != null) {
var mapPath = outPath + '.map';
new File(mapPath)
.writeAsStringSync(JSON.encode(module.placeSourceMap(mapPath)));
}
if (module.summaryBytes != null) {
var summaryPath =
path.withoutExtension(outPath) + '.${compilerOpts.summaryExtension}';
new File(summaryPath).writeAsBytesSync(module.summaryBytes);
}
}

String _moduleForLibrary(String moduleRoot, Source source) {
if (source is InSummarySource) {
var summaryPath = source.summaryPath;
var ext = '.${_compilerOptions.summaryExtension}';
if (path.isWithin(moduleRoot, summaryPath) && summaryPath.endsWith(ext)) {
var buildUnitPath =
summaryPath.substring(0, summaryPath.length - ext.length);
return path.relative(buildUnitPath, from: moduleRoot);
}

throw usageException(
'Imported file ${source.uri} is not within the module root '
'directory $moduleRoot');
String _moduleForLibrary(
String moduleRoot, Source source, CompilerOptions compilerOpts) {
if (source is InSummarySource) {
var summaryPath = source.summaryPath;
var ext = '.${compilerOpts.summaryExtension}';
if (path.isWithin(moduleRoot, summaryPath) && summaryPath.endsWith(ext)) {
var buildUnitPath =
summaryPath.substring(0, summaryPath.length - ext.length);
return path.relative(buildUnitPath, from: moduleRoot);
}

throw usageException(
'Imported file "${source.uri}" was not found as a summary or source '
'file. Please pass in either the summary or the source file '
'for this import.');
_usageException('Imported file ${source.uri} is not within the module root '
'directory $moduleRoot');
}

_usageException(
'Imported file "${source.uri}" was not found as a summary or source '
'file. Please pass in either the summary or the source file '
'for this import.');
return null; // unreachable
}

final _usageMessage =
'Dart Development Compiler compiles Dart into a JavaScript module.'
'\n\n${_argParser.usage}';

void _usageException(String message) {
throw new UsageException(message, _usageMessage);
}

/// Thrown when the input source code has errors.
Expand Down
Loading

0 comments on commit 3627356

Please sign in to comment.