blob: 0a84847de163b5d662ccad374035ab485183e26f [file] [log] [blame]
library pub.dart;
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'package:analyzer/analyzer.dart';
import 'package:path/path.dart' as path;
import '../../../compiler/compiler.dart' as compiler;
import '../../../compiler/implementation/filenames.dart' show appendSlash;
import '../../asset/dart/serialize.dart';
import 'io.dart';
import 'log.dart' as log;
abstract class CompilerProvider {
Uri get libraryRoot;
Future provideInput(Uri uri);
void handleDiagnostic(Uri uri, int begin, int end, String message,
compiler.Diagnostic kind);
EventSink<String> provideOutput(String name, String extension);
}
Future compile(String entrypoint, CompilerProvider provider,
{Iterable<String> commandLineOptions, bool checked: false, bool csp: false,
bool minify: true, bool verbose: false, Map<String, String> environment,
String packageRoot, bool analyzeAll: false, bool suppressWarnings: false,
bool suppressHints: false, bool suppressPackageWarnings: true, bool terse:
false, bool includeSourceMapUrls: false, bool toDart: false}) {
return new Future.sync(() {
var options = <String>['--categories=Client,Server'];
if (checked) options.add('--enable-checked-mode');
if (csp) options.add('--csp');
if (minify) options.add('--minify');
if (verbose) options.add('--verbose');
if (analyzeAll) options.add('--analyze-all');
if (suppressWarnings) options.add('--suppress-warnings');
if (suppressHints) options.add('--suppress-hints');
if (!suppressPackageWarnings) options.add('--show-package-warnings');
if (terse) options.add('--terse');
if (toDart) options.add('--output-type=dart');
var sourceUrl = path.toUri(entrypoint);
options.add("--out=$sourceUrl.js");
if (includeSourceMapUrls) {
options.add("--source-map=$sourceUrl.js.map");
}
if (environment == null) environment = {};
if (commandLineOptions != null) options.addAll(commandLineOptions);
if (packageRoot == null) {
packageRoot = path.join(path.dirname(entrypoint), 'packages');
}
return compiler.compile(
path.toUri(entrypoint),
provider.libraryRoot,
path.toUri(appendSlash(packageRoot)),
provider.provideInput,
provider.handleDiagnostic,
options,
provider.provideOutput,
environment);
});
}
bool isEntrypoint(CompilationUnit dart) {
return dart.declarations.any((node) {
return node is FunctionDeclaration &&
node.name.name == "main" &&
node.functionExpression.parameters.parameters.length <= 2;
});
}
List<UriBasedDirective> parseImportsAndExports(String contents, {String name}) {
var collector = new _DirectiveCollector();
parseDirectives(contents, name: name).accept(collector);
return collector.directives;
}
class _DirectiveCollector extends GeneralizingAstVisitor {
final directives = <UriBasedDirective>[];
visitUriBasedDirective(UriBasedDirective node) => directives.add(node);
}
Future runInIsolate(String code, message, {packageRoot, String snapshot}) {
final completer0 = new Completer();
scheduleMicrotask(() {
try {
join0() {
withTempDir(((dir) {
final completer0 = new Completer();
scheduleMicrotask(() {
try {
var dartPath = path.join(dir, 'runInIsolate.dart');
writeTextFile(dartPath, code, dontLogContents: true);
var port = new ReceivePort();
join0(x0) {
Isolate.spawn(_isolateBuffer, {
'replyTo': port.sendPort,
'uri': path.toUri(dartPath).toString(),
'packageRoot': x0,
'message': message
}).then((x1) {
try {
x1;
port.first.then((x2) {
try {
var response = x2;
join1() {
join2() {
ensureDir(path.dirname(snapshot));
var snapshotArgs = [];
join3() {
snapshotArgs.addAll(
['--snapshot=${snapshot}', dartPath]);
runProcess(
Platform.executable,
snapshotArgs).then((x3) {
try {
var result = x3;
join4() {
log.warning(
"Failed to compile a snapshot to " "${path.relative(snapshot)}:\n" +
result.stderr.join("\n"));
completer0.complete(null);
}
if (result.success) {
completer0.complete(null);
} else {
join4();
}
} catch (e2) {
completer0.completeError(e2);
}
}, onError: (e3) {
completer0.completeError(e3);
});
}
if (packageRoot != null) {
snapshotArgs.add('--package-root=${packageRoot}');
join3();
} else {
join3();
}
}
if (snapshot == null) {
completer0.complete(null);
} else {
join2();
}
}
if (response['type'] == 'error') {
completer0.completeError(
new CrossIsolateException.deserialize(response['error']));
} else {
join1();
}
} catch (e1) {
completer0.completeError(e1);
}
}, onError: (e4) {
completer0.completeError(e4);
});
} catch (e0) {
completer0.completeError(e0);
}
}, onError: (e5) {
completer0.completeError(e5);
});
}
if (packageRoot == null) {
join0(null);
} else {
join0(packageRoot.toString());
}
} catch (e6) {
completer0.completeError(e6);
}
});
return completer0.future;
})).then((x0) {
try {
x0;
completer0.complete(null);
} catch (e0) {
completer0.completeError(e0);
}
}, onError: (e1) {
completer0.completeError(e1);
});
}
if (snapshot != null && fileExists(snapshot)) {
log.fine("Spawning isolate from ${snapshot}.");
join1() {
join2(x1) {
join0();
}
finally0(cont0, v0) {
cont0(v0);
}
catch0(error) {
log.fine("Couldn't load existing snapshot ${snapshot}:\n${error}");
finally0(join2, null);
}
try {
Isolate.spawnUri(
path.toUri(snapshot),
[],
message,
packageRoot: packageRoot).then((x2) {
try {
x2;
finally0((v1) {
completer0.complete(v1);
}, null);
} catch (e2) {
catch0(e2);
}
}, onError: (e3) {
catch0(e3);
});
} catch (e4) {
catch0(e4);
}
}
if (packageRoot != null) {
packageRoot = packageRoot.toString();
join1();
} else {
join1();
}
} else {
join0();
}
} catch (e5) {
completer0.completeError(e5);
}
});
return completer0.future;
}
void _isolateBuffer(message) {
var replyTo = message['replyTo'];
var packageRoot = message['packageRoot'];
if (packageRoot != null) packageRoot = Uri.parse(packageRoot);
Isolate.spawnUri(
Uri.parse(message['uri']),
[],
message['message'],
packageRoot: packageRoot).then((_) => replyTo.send({
'type': 'success'
})).catchError((e, stack) {
replyTo.send({
'type': 'error',
'error': CrossIsolateException.serialize(e, stack)
});
});
}