blob: e6ca6a7f64d0cd9b5378f49233df31f38121b916 [file] [log] [blame]
#!/usr/bin/env dart
// Copyright (c) 2016, 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.
/// Command line entry point for Dart Development Compiler (dartdevc).
///
/// Supported commands are
/// * compile: builds a collection of dart libraries into a single JS module
///
/// Additionally, these commands are being considered
/// * link: combines several JS modules into a single JS file
/// * build: compiles & links a set of code, automatically determining
/// appropriate groupings of libraries to combine into JS modules
/// * watch: watch a directory and recompile build units automatically
/// * serve: uses `watch` to recompile and exposes a simple static file server
/// for local development
///
/// These commands are combined so we have less names to expose on the PATH,
/// and for development simplicity while the precise UI has not been determined.
///
/// A more typical structure for web tools is simply to have the compiler with
/// "watch" as an option. The challenge for us is:
///
/// * Dart used to assume whole-program compiles, so we don't have a
/// user-declared unit of building, and neither "libraries" or "packages" will
/// work,
/// * We do not assume a `node` JS installation, so we cannot easily reuse
/// existing tools for the "link" step, or assume users have a local
/// file server,
/// * We didn't have a file watcher API at first,
/// * We had no conventions about where compiled output should go (or even
/// that we would be compiling at all, vs running on an in-browser Dart VM),
/// * We wanted a good first impression with our simple examples, so we used
/// local file servers, and users have an expectation of it now, even though
/// it doesn't scale to typical apps that need their own real servers.
import 'dart:async';
import 'dart:io';
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:bazel_worker/bazel_worker.dart';
import 'package:dev_compiler/src/compiler/command.dart';
Future main(List<String> args) async {
// Always returns a new modifiable list.
args = _preprocessArgs(args);
if (args.contains('--persistent_worker')) {
new _CompilerWorker(args..remove('--persistent_worker')).run();
} else {
exitCode = compile(args);
}
}
/// Runs the compiler worker loop.
class _CompilerWorker extends AsyncWorkerLoop {
/// The original args supplied to the executable.
final List<String> _startupArgs;
_CompilerWorker(this._startupArgs) : super();
/// Performs each individual work request.
Future<WorkResponse> performRequest(WorkRequest request) async {
var args = _startupArgs.toList()..addAll(request.arguments);
var output = new StringBuffer();
var exitCode = compile(args, printFn: output.writeln);
AnalysisEngine.instance.clearCaches();
return new WorkResponse()
..exitCode = exitCode
..output = output.toString();
}
}
/// Always returns a new modifiable list.
///
/// If the final arg is `@file_path` then read in all the lines of that file
/// and add those as args.
///
/// Bazel actions that support workers must provide all their per-WorkRequest
/// arguments in a file like this instead of as normal args.
List<String> _preprocessArgs(List<String> args) {
args = new List.from(args);
if (args.isNotEmpty && args.last.startsWith('@')) {
var fileArg = args.removeLast();
args.addAll(new File(fileArg.substring(1)).readAsLinesSync());
}
return args;
}