blob: c27ea04dc7ec0182ff889e1d453183bf9f621f12 [file] [log] [blame]
// Copyright (c) 2017, 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.
import 'dart:async';
import 'dart:io';
import 'package:args/args.dart';
import 'package:bazel_worker/bazel_worker.dart';
import 'package:front_end/front_end.dart' hide FileSystemException;
import 'package:front_end/src/fasta/command_line_reporting.dart';
import 'package:kernel/target/targets.dart';
main(List<String> args) async {
args = preprocessArgs(args);
if (args.contains('--persistent_worker')) {
if (args.length != 1) {
throw new StateError(
"unexpected args, expected only --persistent-worker but got: $args");
}
await new SummaryWorker().run();
} else {
await computeSummary(args);
}
}
/// A bazel worker loop that can compute summaries.
class SummaryWorker extends AsyncWorkerLoop {
Future<WorkResponse> performRequest(WorkRequest request) async {
var outputBuffer = new StringBuffer();
var response = new WorkResponse()..exitCode = 0;
try {
await computeSummary(request.arguments,
isWorker: true, outputBuffer: outputBuffer);
} catch (_, s) {
outputBuffer.writeln(s);
response.exitCode = 15;
}
response.output = outputBuffer.toString();
return response;
}
}
/// If the last arg starts with `@`, this reads the file it points to and treats
/// each line as an additional arg.
///
/// This is how individual work request args are differentiated from startup
/// args in bazel (inidividual work request args go in that file).
List<String> preprocessArgs(List<String> args) {
args = new List.from(args);
if (args.isEmpty) {
return args;
}
String lastArg = args.last;
if (lastArg.startsWith('@')) {
File argsFile = new File(lastArg.substring(1));
try {
args.removeLast();
args.addAll(argsFile.readAsLinesSync());
} on FileSystemException catch (e) {
throw new Exception('Failed to read file specified by $lastArg : $e');
}
}
return args;
}
/// An [ArgParser] for generating kernel summaries.
final summaryArgsParser = new ArgParser()
..addOption('dart-sdk-summary')
..addOption('input-summary', allowMultiple: true)
..addOption('multi-root', allowMultiple: true)
..addOption('packages-file')
..addOption('source', allowMultiple: true)
..addOption('output');
/// Computes a kernel summary based on [args].
///
/// If [isWorker] is true then exit codes will not be set on failure.
///
/// If [outputBuffer] is provided then messages will be written to that buffer
/// instead of printed to the console.
Future computeSummary(List<String> args,
{bool isWorker: false, StringBuffer outputBuffer}) async {
var parsedArgs = summaryArgsParser.parse(args);
var options = new CompilerOptions()
..packagesFileUri = Uri.parse(parsedArgs['packages-file'])
..inputSummaries = parsedArgs['input-summary'].map(Uri.parse).toList()
..sdkSummary = Uri.parse(parsedArgs['dart-sdk-summary'])
..multiRoots = parsedArgs['multi-root'].map(Uri.parse).toList()
..target = new NoneTarget(new TargetFlags());
if (outputBuffer != null) {
options.onError = (CompilationMessage error) {
var severityString = severityName(error.severity, capitalized: true);
outputBuffer.writeln('$severityString: ${error.message}');
if (error.severity != Severity.nit) {
throw error;
}
};
} else {
options.throwOnWarnings = true;
}
var sources = parsedArgs['source'].map(Uri.parse).toList();
var program = await summaryFor(sources, options);
var outputFile = new File(parsedArgs['output']);
outputFile.createSync(recursive: true);
outputFile.writeAsBytesSync(program);
}