mirror of
https://github.com/dart-lang/sdk
synced 2024-09-21 07:11:30 +00:00
70b6cd5c15
Review URL: https://codereview.chromium.org//1234873006 .
212 lines
5.5 KiB
Dart
212 lines
5.5 KiB
Dart
// Copyright (c) 2015, 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:io';
|
|
|
|
import 'dart:async' show
|
|
EventSink,
|
|
Future,
|
|
Stream,
|
|
StreamController,
|
|
StreamSubscription;
|
|
|
|
import 'package:dart2js_incremental/dart2js_incremental.dart' show
|
|
IncrementalCompilationFailed,
|
|
IncrementalCompiler;
|
|
|
|
import 'package:compiler/compiler_new.dart' show
|
|
CompilerOutput;
|
|
|
|
import 'package:compiler/src/old_to_new_api.dart' show
|
|
LegacyCompilerDiagnostics,
|
|
LegacyCompilerInput;
|
|
|
|
import 'package:compiler/src/source_file_provider.dart' show
|
|
FormattingDiagnosticHandler;
|
|
|
|
import 'watcher.dart';
|
|
|
|
main(List<String> arguments) {
|
|
int updateCount = 0;
|
|
StreamSubscription<CompilerEvent> subscription =
|
|
compile(Uri.base.resolve(arguments.first)).listen(null);
|
|
subscription.onData((CompilerEvent event) {
|
|
switch (event.kind) {
|
|
case IncrementalKind.FULL:
|
|
updateCount = 0;
|
|
print('// Compiled JavaScript:');
|
|
print(event['.js']);
|
|
break;
|
|
|
|
case IncrementalKind.INCREMENTAL:
|
|
Stopwatch sw = event.stopwatch..start();
|
|
String updates = '${event.compiler.allUpdates()}';
|
|
sw.stop();
|
|
|
|
print('// Patch after ${++updateCount} updates,');
|
|
print('// computed in ${sw.elapsedMicroseconds/1000000} seconds:');
|
|
print(updates);
|
|
break;
|
|
|
|
case IncrementalKind.ERROR:
|
|
updateCount = 0;
|
|
print("Compilation failed");
|
|
break;
|
|
|
|
default:
|
|
throw "Unknown kind: ${event.kind}";
|
|
}
|
|
});
|
|
subscription.onError((error, StackTrace trace) {
|
|
if (error is IncrementalCompilationFailed) {
|
|
print("Incremental compilation failed due to:\n${error.reason}");
|
|
} else {
|
|
throw error;
|
|
}
|
|
});
|
|
}
|
|
|
|
Stream<CompilerEvent> compile(Uri originalInput) {
|
|
StreamController<CompilerEvent> controller =
|
|
new StreamController<CompilerEvent>();
|
|
compileToStream(originalInput, controller);
|
|
return controller.stream;
|
|
}
|
|
|
|
compileToStream(
|
|
Uri originalInput,
|
|
StreamController<CompilerEvent> controller) async {
|
|
var watcher = new Watcher();
|
|
|
|
Uri libraryRoot = Uri.base.resolve('sdk/');
|
|
Uri packageRoot = Uri.base.resolve('packages/');
|
|
|
|
FormattingDiagnosticHandler diagnosticHandler =
|
|
new FormattingDiagnosticHandler();
|
|
|
|
OutputProvider outputProvider = new OutputProvider();
|
|
|
|
void resilientDiagnosticHandler(
|
|
Uri uri, int begin, int end, String message, kind) {
|
|
try {
|
|
diagnosticHandler(uri, begin, end, message, kind);
|
|
} catch (e) {
|
|
String name = diagnosticHandler.provider.relativizeUri(uri);
|
|
print('$name@$begin+${end - begin}: [$kind] $message}');
|
|
}
|
|
}
|
|
|
|
Future inputProvider(Uri uri) {
|
|
if (uri.scheme == "file") {
|
|
if (!'$uri'.startsWith('$libraryRoot')) {
|
|
watcher.watchFile(uri);
|
|
}
|
|
}
|
|
return diagnosticHandler.provider(uri);
|
|
}
|
|
|
|
while (true) {
|
|
Stopwatch sw = new Stopwatch()..start();
|
|
IncrementalCompiler compiler = new IncrementalCompiler(
|
|
libraryRoot: libraryRoot,
|
|
packageRoot: packageRoot,
|
|
inputProvider: new LegacyCompilerInput(inputProvider),
|
|
diagnosticHandler:
|
|
new LegacyCompilerDiagnostics(resilientDiagnosticHandler),
|
|
outputProvider: outputProvider);
|
|
|
|
bool success = await compiler.compile(originalInput);
|
|
sw.stop();
|
|
if (success) {
|
|
controller.add(
|
|
new CompilerEvent(
|
|
IncrementalKind.FULL, compiler, outputProvider.output, sw));
|
|
} else {
|
|
controller.add(
|
|
new CompilerEvent(
|
|
IncrementalKind.ERROR, compiler, outputProvider.output, sw));
|
|
}
|
|
|
|
while (await watcher.hasChanges()) {
|
|
try {
|
|
Map<Uri, Uri> changes = watcher.readChanges();
|
|
|
|
sw = new Stopwatch()..start();
|
|
String updates = await compiler.compileUpdates(changes);
|
|
sw.stop();
|
|
|
|
controller.add(
|
|
new CompilerEvent(
|
|
IncrementalKind.INCREMENTAL, compiler, outputProvider.output,
|
|
sw, updates: updates));
|
|
|
|
} on IncrementalCompilationFailed catch (error, trace) {
|
|
controller.addError(error, trace);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Output provider which collects output in [output].
|
|
class OutputProvider implements CompilerOutput {
|
|
final Map<String, String> output = new Map<String, String>();
|
|
|
|
EventSink<String> createEventSink(String name, String extension) {
|
|
return new StringEventSink((String data) {
|
|
output['$name.$extension'] = data;
|
|
});
|
|
}
|
|
|
|
String operator[](String key) => output[key];
|
|
}
|
|
|
|
/// Helper class to collect sources.
|
|
class StringEventSink implements EventSink<String> {
|
|
List<String> data = <String>[];
|
|
|
|
final Function onClose;
|
|
|
|
StringEventSink(this.onClose);
|
|
|
|
void add(String event) {
|
|
if (data == null) throw 'StringEventSink is closed.';
|
|
data.add(event);
|
|
}
|
|
|
|
void addError(errorEvent, [StackTrace stackTrace]) {
|
|
throw 'addError($errorEvent, $stackTrace)';
|
|
}
|
|
|
|
void close() {
|
|
if (data != null) {
|
|
onClose(data.join());
|
|
data = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
enum IncrementalKind {
|
|
FULL,
|
|
INCREMENTAL,
|
|
ERROR,
|
|
}
|
|
|
|
class CompilerEvent {
|
|
final IncrementalKind kind;
|
|
|
|
final IncrementalCompiler compiler;
|
|
|
|
final Map<String, String> _output;
|
|
|
|
final Stopwatch stopwatch;
|
|
|
|
final String updates;
|
|
|
|
CompilerEvent(
|
|
this.kind, this.compiler, this._output, this.stopwatch, {this.updates});
|
|
|
|
String operator[](String key) => _output[key];
|
|
}
|