Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Unified Diff: lib/src/server/server.dart

Issue 1235503010: fixes #219, able to compile multiple entry points (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lib/src/server/server.dart
diff --git a/lib/devc.dart b/lib/src/server/server.dart
similarity index 64%
copy from lib/devc.dart
copy to lib/src/server/server.dart
index ae22b89cdb66e14d92748ab54fd1639bf81ffa27..b9a69d510fed22e1c59cdb4b7381a1c5bcea2a98 100644
--- a/lib/devc.dart
+++ b/lib/src/server/server.dart
@@ -2,100 +2,66 @@
// 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 tool to run the checker on a Dart program.
-library dev_compiler.devc;
+/// Development server that compiles Dart to JS on the fly.
+library dev_compiler.src.server;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
+import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver;
+import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, ChangeSet;
-import 'package:analyzer/src/generated/error.dart'
- show AnalysisError, AnalysisErrorListener, ErrorSeverity, ErrorType;
-import 'package:analyzer/src/generated/source.dart' show Source;
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
import 'package:logging/logging.dart' show Level, Logger, LogRecord;
import 'package:path/path.dart' as path;
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as shelf;
import 'package:shelf_static/shelf_static.dart' as shelf_static;
-import 'src/analysis_context.dart';
-import 'src/checker/checker.dart';
-import 'src/checker/rules.dart';
-import 'src/codegen/code_generator.dart' show CodeGenerator;
-import 'src/codegen/html_codegen.dart';
-import 'src/codegen/js_codegen.dart';
-import 'src/dependency_graph.dart';
-import 'src/info.dart'
+import 'package:dev_compiler/src/codegen/code_generator.dart'
+ show CodeGenerator;
+import 'package:dev_compiler/src/codegen/html_codegen.dart'
+ show generateEntryHtml;
+import 'package:dev_compiler/src/codegen/js_codegen.dart';
+import 'package:dev_compiler/src/analysis_context.dart';
+import 'package:dev_compiler/src/compiler.dart' show AbstractCompiler;
+import 'package:dev_compiler/src/info.dart'
show AnalyzerMessage, CheckerResults, LibraryInfo, LibraryUnit;
-import 'src/options.dart';
-import 'src/report.dart';
-import 'src/utils.dart';
-
-/// Sets up the type checker logger to print a span that highlights error
-/// messages.
-StreamSubscription setupLogger(Level level, printFn) {
- Logger.root.level = level;
- return Logger.root.onRecord.listen((LogRecord rec) {
- printFn('${rec.level.name.toLowerCase()}: ${rec.message}');
- });
-}
+import 'package:dev_compiler/src/options.dart';
+import 'package:dev_compiler/src/report.dart';
+import 'package:dev_compiler/src/utils.dart';
-abstract class AbstractCompiler {
- CompilerOptions get options;
- AnalysisContext get context;
- TypeRules get rules;
- Uri get entryPointUri;
-}
+import 'dependency_graph.dart';
-/// Encapsulates the logic to do a one-off compilation or a partial compilation
-/// when the compiler is run as a development server.
-class Compiler implements AbstractCompiler {
- final CompilerOptions options;
- final AnalysisContext context;
- final AnalysisErrorListener _reporter;
- final TypeRules rules;
- final CodeChecker _checker;
+/// Encapsulates the logic when the compiler is run as a development server.
+class ServerCompiler extends AbstractCompiler {
final SourceNode _entryNode;
List<LibraryInfo> _libraries = <LibraryInfo>[];
final _generators = <CodeGenerator>[];
bool _hashing;
bool _failure = false;
- factory Compiler(CompilerOptions options,
- {AnalysisContext context, AnalysisErrorListener reporter}) {
- var strongOpts = options.strongOptions;
- var sourceOpts = options.sourceOptions;
- if (context == null) {
- context = createAnalysisContextWithSources(strongOpts, sourceOpts);
- }
-
- if (reporter == null) {
- reporter = options.dumpInfo
- ? new SummaryReporter(context, options.logLevel)
- : new LogReporter(context, useColors: options.useColors);
- }
- var graph = new SourceGraph(context, reporter, options);
- var rules = new RestrictedRules(context.typeProvider,
- options: options.strongOptions);
- var checker = new CodeChecker(rules, reporter, strongOpts);
-
- var inputFile = sourceOpts.entryPointFile;
+ factory ServerCompiler(AnalysisContext context, CompilerOptions options,
+ {AnalysisErrorListener reporter}) {
+ var srcOpts = options.sourceOptions;
+ var inputFile = options.inputs[0];
var inputUri = inputFile.startsWith('dart:') ||
inputFile.startsWith('package:')
? Uri.parse(inputFile)
- : new Uri.file(path.absolute(sourceOpts.useImplicitHtml
+ : new Uri.file(path.absolute(srcOpts.useImplicitHtml
? SourceResolverOptions.implicitHtmlFile
: inputFile));
+ var graph = new SourceGraph(context, reporter, options);
var entryNode = graph.nodeFromUri(inputUri);
- return new Compiler._(
- options, context, reporter, rules, checker, entryNode);
+ return new ServerCompiler._(options, context, reporter, entryNode);
}
- Compiler._(this.options, this.context, this._reporter, this.rules,
- this._checker, this._entryNode) {
+ ServerCompiler._(context, options, reporter, this._entryNode)
+ : super(options, context, reporter) {
if (outputDir != null) {
_generators.add(new JSGenerator(this));
}
@@ -104,7 +70,23 @@ class Compiler implements AbstractCompiler {
}
Uri get entryPointUri => _entryNode.uri;
- String get outputDir => options.codegenOptions.outputDir;
+
+ CheckerResults run() {
+ var clock = new Stopwatch()..start();
+
+ // TODO(sigmund): we are missing a couple failures here. The
+ // dependency_graph now detects broken imports or unsupported features
+ // like more than one script tag (see .severe messages in
+ // dependency_graph.dart). Such failures should be reported back
+ // here so we can mark failure=true in the CheckerResults.
+ rebuild(_entryNode, _buildSource);
+ _dumpInfoIfRequested();
+ clock.stop();
+ var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2);
+ _log.fine('Compiled ${_libraries.length} libraries in ${time} s\n');
+ return new CheckerResults(
+ _libraries, rules, _failure || options.codegenOptions.forceCompile);
+ }
bool _buildSource(SourceNode node) {
if (node is HtmlSourceNode) {
@@ -117,18 +99,19 @@ class Compiler implements AbstractCompiler {
assert(false); // should not get a build request on PartSourceNode
}
- // TODO(sigmund): don't always return true. Use summarization to better
- // determine when rebuilding is needed.
+ // TODO(sigmund): don't always return true.
+ // Use summaries to determine when rebuilding is needed.
return true;
}
void _buildHtmlFile(HtmlSourceNode node) {
if (outputDir == null) return;
- var output = generateEntryHtml(node, options);
+ var output = generateEntryHtml(node, this);
if (output == null) {
_failure = true;
return;
}
+
var filename = path.basename(node.uri.path);
String outputFile = path.join(outputDir, filename);
new File(outputFile).writeAsStringSync(output);
@@ -149,11 +132,6 @@ class Compiler implements AbstractCompiler {
if (_hashing) node.cachingHash = computeHashFromFile(filepath);
}
- bool _isEntry(DartSourceNode node) {
- if (_entryNode is DartSourceNode) return _entryNode == node;
- return (_entryNode as HtmlSourceNode).scripts.contains(node);
- }
-
void _buildDartLibrary(DartSourceNode node) {
var source = node.source;
// TODO(sigmund): find out from analyzer team if there is a better way
@@ -165,10 +143,9 @@ class Compiler implements AbstractCompiler {
if (current != null) {
assert(current.library == lib);
} else {
- node.info = current = new LibraryInfo(lib, _isEntry(node));
+ node.info = current = new LibraryInfo(lib);
}
_libraries.add(current);
- rules.currentLibraryInfo = current;
var resolvedParts = node.parts
.map((p) => context.resolveCompilationUnit2(p.source, source))
@@ -177,9 +154,10 @@ class Compiler implements AbstractCompiler {
bool failureInLib = false;
for (var unit in libraryUnit.libraryThenParts) {
var unitSource = unit.element.source;
+ // TODO(sigmund): integrate analyzer errors with static-info (issue #6).
failureInLib = logErrors(unitSource) || failureInLib;
- _checker.visitCompilationUnit(unit);
- if (_checker.failure) failureInLib = true;
+ checker.visitCompilationUnit(unit);
+ if (checker.failure) failureInLib = true;
}
if (failureInLib) {
_failure = true;
@@ -187,53 +165,11 @@ class Compiler implements AbstractCompiler {
}
for (var cg in _generators) {
- var hash = cg.generateLibrary(libraryUnit, current);
+ var hash = cg.generateLibrary(libraryUnit);
if (_hashing) node.cachingHash = hash;
}
}
- /// Log any errors encountered when resolving [source] and return whether any
- /// errors were found.
- bool logErrors(Source source) {
- context.computeErrors(source);
- List<AnalysisError> errors = context.getErrors(source).errors;
- bool failure = false;
- if (errors.isNotEmpty) {
- for (var error in errors) {
- // Always skip TODOs.
- if (error.errorCode.type == ErrorType.TODO) continue;
-
- // Skip hints for now. In the future these could be turned on via flags.
- if (error.errorCode.errorSeverity.ordinal <
- ErrorSeverity.WARNING.ordinal) {
- continue;
- }
-
- // All analyzer warnings or errors are errors for DDC.
- failure = true;
- _reporter.onError(error);
- }
- }
- return failure;
- }
-
- CheckerResults run() {
- var clock = new Stopwatch()..start();
-
- // TODO(sigmund): we are missing a couple failures here. The
- // dependency_graph now detects broken imports or unsupported features
- // like more than one script tag (see .severe messages in
- // dependency_graph.dart). Such failures should be reported back
- // here so we can mark failure=true in the CheckerResutls.
- rebuild(_entryNode, _buildSource);
- _dumpInfoIfRequested();
- clock.stop();
- var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2);
- _log.fine('Compiled ${_libraries.length} libraries in ${time} s\n');
- return new CheckerResults(
- _libraries, rules, _failure || options.codegenOptions.forceCompile);
- }
-
void _runAgain() {
var clock = new Stopwatch()..start();
_libraries = <LibraryInfo>[];
@@ -251,8 +187,8 @@ class Compiler implements AbstractCompiler {
}
_dumpInfoIfRequested() {
- if (!options.dumpInfo || _reporter is! SummaryReporter) return;
- var result = (_reporter as SummaryReporter).result;
+ if (!options.dumpInfo || reporter is! SummaryReporter) return;
+ var result = (reporter as SummaryReporter).result;
if (!options.serverMode) print(summaryToString(result));
var filepath = options.serverMode
? path.join(outputDir, 'messages.json')
@@ -262,15 +198,26 @@ class Compiler implements AbstractCompiler {
}
}
-class CompilerServer {
- final Compiler compiler;
+class DevServer {
+ final ServerCompiler compiler;
final String outDir;
final String host;
final int port;
final String _entryPath;
- factory CompilerServer(CompilerOptions options) {
- var entryPath = path.basename(options.sourceOptions.entryPointFile);
+ factory DevServer(CompilerOptions options) {
+ assert(options.inputs.length == 1);
+
+ var fileResolvers = createFileResolvers(options.sourceOptions);
+ if (options.sourceOptions.useImplicitHtml) {
+ fileResolvers.insert(0, _createImplicitEntryResolver(options.inputs[0]));
+ }
+
+ var context = createAnalysisContextWithSources(
+ options.strongOptions, options.sourceOptions,
+ fileResolvers: fileResolvers);
+
+ var entryPath = path.basename(options.inputs[0]);
var extension = path.extension(entryPath);
if (extension != '.html' && !options.sourceOptions.useImplicitHtml) {
print('error: devc in server mode requires an HTML or Dart entry point.');
@@ -286,12 +233,12 @@ class CompilerServer {
}
var port = options.port;
var host = options.host;
- var compiler = new Compiler(options);
- return new CompilerServer._(compiler, outDir, host, port, entryPath);
+ var compiler = new ServerCompiler(context, options);
+ return new DevServer._(compiler, outDir, host, port, entryPath);
}
- CompilerServer._(
- Compiler compiler, this.outDir, this.host, this.port, String entryPath)
+ DevServer._(ServerCompiler compiler, this.outDir, this.host, this.port,
+ String entryPath)
: this.compiler = compiler,
// TODO(jmesserly): this logic is duplicated in a few places
this._entryPath = compiler.options.sourceOptions.useImplicitHtml
@@ -335,5 +282,28 @@ class CompilerServer {
};
}
-final _log = new Logger('dev_compiler');
+UriResolver _createImplicitEntryResolver(String entryPath) {
+ var entry = path.absolute(SourceResolverOptions.implicitHtmlFile);
+ var src = path.absolute(entryPath);
+ var provider = new MemoryResourceProvider();
+ provider.newFile(
+ entry, '<body><script type="application/dart" src="$src"></script>');
+ return new _ExistingSourceUriResolver(new ResourceUriResolver(provider));
+}
+
+/// A UriResolver that continues to the next one if it fails to find an existing
+/// source file. This is unlike normal URI resolvers, that always return
+/// something, even if it is a non-existing file.
+class _ExistingSourceUriResolver implements UriResolver {
+ final UriResolver resolver;
+ _ExistingSourceUriResolver(this.resolver);
+
+ Source resolveAbsolute(Uri uri) {
+ var src = resolver.resolveAbsolute(uri);
+ return src.exists() ? src : null;
+ }
+ Uri restoreAbsolute(Source source) => resolver.restoreAbsolute(source);
+}
+
+final _log = new Logger('dev_compiler.src.server');
final _earlyErrorResult = new CheckerResults(const [], null, true);

Powered by Google App Engine
This is Rietveld 408576698