Skip to content

Commit 63681d5

Browse files
Support Package Resolution Configuration files.
BUG=http://dartbug.com/23371 [email protected] Committed: 36c29d0 Review URL: https://codereview.chromium.org//1162363004.
1 parent d2f80cf commit 63681d5

File tree

14 files changed

+191
-65
lines changed

14 files changed

+191
-65
lines changed

DEPS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ vars = {
7676
"oauth2_rev": "@1bff41f4d54505c36f2d1a001b83b8b745c452f5",
7777
"observe_rev": "@eee2b8ec34236fa46982575fbccff84f61202ac6",
7878
"observatory_pub_packages_rev": "@45565",
79-
"package_config_tag": "@0.0.2+4",
79+
"package_config_tag": "@0.0.3+1",
8080
"path_rev": "@93b3e2aa1db0ac0c8bab9d341588d77acda60320",
8181
"petitparser_rev" : "@37878",
8282
"ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",

pkg/compiler/lib/compiler.dart

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
library compiler;
66

77
import 'dart:async';
8+
import 'package:package_config/packages.dart';
89
import 'src/apiimpl.dart';
910

1011
// Unless explicitly allowed, passing [:null:] for any argument to the
@@ -58,13 +59,19 @@ typedef EventSink<String> CompilerOutputProvider(String name,
5859
* [:null:]. If [uri] is not [:null:], neither are [begin] and
5960
* [end]. [uri] indicates the compilation unit from where the
6061
* diagnostic originates. [begin] and [end] are zero-based character
61-
* offsets from the beginning of the compilaton unit. [message] is the
62+
* offsets from the beginning of the compilation unit. [message] is the
6263
* diagnostic message, and [kind] indicates indicates what kind of
6364
* diagnostic it is.
6465
*/
6566
typedef void DiagnosticHandler(Uri uri, int begin, int end,
6667
String message, Diagnostic kind);
6768

69+
/**
70+
* Provides a package lookup mechanism in the case that no package root or
71+
* package resolution configuration file are explicitly specified.
72+
*/
73+
typedef Future<Packages> PackagesDiscoveryProvider(Uri uri);
74+
6875
/// Information resulting from the compilation.
6976
class CompilationResult {
7077
/// `true` if the compilation succeeded, that is, compilation didn't fail due
@@ -103,7 +110,9 @@ Future<CompilationResult> compile(
103110
DiagnosticHandler handler,
104111
[List<String> options = const [],
105112
CompilerOutputProvider outputProvider,
106-
Map<String, dynamic> environment = const {}]) {
113+
Map<String, dynamic> environment = const {},
114+
Uri packageConfig,
115+
PackagesDiscoveryProvider packagesDiscoveryProvider]) {
107116
if (!libraryRoot.path.endsWith("/")) {
108117
throw new ArgumentError("libraryRoot must end with a /");
109118
}
@@ -118,7 +127,9 @@ Future<CompilationResult> compile(
118127
libraryRoot,
119128
packageRoot,
120129
options,
121-
environment);
130+
environment,
131+
packageConfig,
132+
packagesDiscoveryProvider);
122133
return compiler.run(script).then((bool success) {
123134
return new CompilationResult(compiler, isSuccess: success);
124135
});

pkg/compiler/lib/src/apiimpl.dart

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
library leg_apiimpl;
66

77
import 'dart:async';
8+
import 'dart:convert';
89

910
import '../compiler.dart' as api;
1011
import 'dart2jslib.dart' as leg;
@@ -13,6 +14,11 @@ import 'elements/elements.dart' as elements;
1314
import 'package:_internal/libraries.dart' hide LIBRARIES;
1415
import 'package:_internal/libraries.dart' as library_info show LIBRARIES;
1516
import 'io/source_file.dart';
17+
import 'package:package_config/packages.dart';
18+
import 'package:package_config/packages_file.dart' as pkgs;
19+
import 'package:package_config/src/packages_impl.dart'
20+
show NonFilePackagesDirectoryPackages, MapPackages;
21+
import 'package:package_config/src/util.dart' show checkValidPackageUri;
1622

1723
const bool forceIncrementalSupport =
1824
const bool.fromEnvironment('DART2JS_EXPERIMENTAL_INCREMENTAL_SUPPORT');
@@ -21,22 +27,28 @@ class Compiler extends leg.Compiler {
2127
api.CompilerInputProvider provider;
2228
api.DiagnosticHandler handler;
2329
final Uri libraryRoot;
30+
final Uri packageConfig;
2431
final Uri packageRoot;
32+
final api.PackagesDiscoveryProvider packagesDiscoveryProvider;
33+
Packages packages;
2534
List<String> options;
2635
Map<String, dynamic> environment;
2736
bool mockableLibraryUsed = false;
2837
final Set<String> allowedLibraryCategories;
2938

3039
leg.GenericTask userHandlerTask;
3140
leg.GenericTask userProviderTask;
41+
leg.GenericTask userPackagesDiscoveryTask;
3242

3343
Compiler(this.provider,
3444
api.CompilerOutputProvider outputProvider,
3545
this.handler,
3646
this.libraryRoot,
3747
this.packageRoot,
3848
List<String> options,
39-
this.environment)
49+
this.environment,
50+
[this.packageConfig,
51+
this.packagesDiscoveryProvider])
4052
: this.options = options,
4153
this.allowedLibraryCategories = getAllowedLibraryCategories(options),
4254
super(
@@ -96,17 +108,20 @@ class Compiler extends leg.Compiler {
96108
tasks.addAll([
97109
userHandlerTask = new leg.GenericTask('Diagnostic handler', this),
98110
userProviderTask = new leg.GenericTask('Input provider', this),
111+
userPackagesDiscoveryTask =
112+
new leg.GenericTask('Package discovery', this),
99113
]);
100114
if (libraryRoot == null) {
101115
throw new ArgumentError("[libraryRoot] is null.");
102116
}
103117
if (!libraryRoot.path.endsWith("/")) {
104118
throw new ArgumentError("[libraryRoot] must end with a /.");
105119
}
106-
if (packageRoot == null) {
107-
throw new ArgumentError("[packageRoot] is null.");
120+
if (packageRoot != null && packageConfig != null) {
121+
throw new ArgumentError("Only one of [packageRoot] or [packageConfig] "
122+
"may be given.");
108123
}
109-
if (!packageRoot.path.endsWith("/")) {
124+
if (packageRoot != null && !packageRoot.path.endsWith("/")) {
110125
throw new ArgumentError("[packageRoot] must end with a /.");
111126
}
112127
if (!analyzeOnly) {
@@ -160,8 +175,7 @@ class Compiler extends leg.Compiler {
160175

161176
// TODO(johnniwinther): Merge better with [translateDartUri] when
162177
// [scanBuiltinLibrary] is removed.
163-
String lookupLibraryPath(String dartLibraryName) {
164-
LibraryInfo info = lookupLibraryInfo(dartLibraryName);
178+
String lookupLibraryPath(LibraryInfo info) {
165179
if (info == null) return null;
166180
if (!info.isDart2jsLibrary) return null;
167181
if (!allowedLibraryCategories.contains(info.category)) return null;
@@ -225,6 +239,7 @@ class Compiler extends leg.Compiler {
225239
}
226240

227241
Uri resourceUri = translateUri(node, readableUri);
242+
if (resourceUri == null) return synthesizeScript(node, readableUri);
228243
if (resourceUri.scheme == 'dart-ext') {
229244
if (!allowNativeExtensions) {
230245
withCurrentElement(element, () {
@@ -260,12 +275,11 @@ class Compiler extends leg.Compiler {
260275
}
261276

262277
Future<leg.Script> synthesizeScript(leg.Spannable node, Uri readableUri) {
263-
Uri resourceUri = translateUri(node, readableUri);
264278
return new Future.value(
265279
new leg.Script(
266-
readableUri, resourceUri,
280+
readableUri, readableUri,
267281
new StringSourceFile.fromUri(
268-
resourceUri,
282+
readableUri,
269283
"// Synthetic source file generated for '$readableUri'."),
270284
isSynthesized: true));
271285
}
@@ -285,7 +299,7 @@ class Compiler extends leg.Compiler {
285299
Uri translateDartUri(elements.LibraryElement importingLibrary,
286300
Uri resolvedUri, tree.Node node) {
287301
LibraryInfo libraryInfo = lookupLibraryInfo(resolvedUri.path);
288-
String path = lookupLibraryPath(resolvedUri.path);
302+
String path = lookupLibraryPath(libraryInfo);
289303
if (libraryInfo != null &&
290304
libraryInfo.category == "Internal") {
291305
bool allowInternalLibraryAccess = false;
@@ -333,25 +347,66 @@ class Compiler extends leg.Compiler {
333347
}
334348

335349
Uri translatePackageUri(leg.Spannable node, Uri uri) {
336-
return packageRoot.resolve(uri.path);
350+
try {
351+
checkValidPackageUri(uri);
352+
} on ArgumentError catch (e) {
353+
reportError(
354+
node,
355+
leg.MessageKind.INVALID_PACKAGE_URI,
356+
{'uri': uri, 'exception': e.message});
357+
return null;
358+
}
359+
return packages.resolve(uri,
360+
notFound: (Uri notFound) {
361+
reportError(
362+
node,
363+
leg.MessageKind.LIBRARY_NOT_FOUND,
364+
{'resolvedUri': uri}
365+
);
366+
return null;
367+
});
368+
}
369+
370+
Future setupPackages(Uri uri) async {
371+
if (packageRoot != null) {
372+
// Use "non-file" packages because the file version requires a [Directory]
373+
// and we can't depend on 'dart:io' classes.
374+
packages = new NonFilePackagesDirectoryPackages(packageRoot);
375+
} else if (packageConfig != null) {
376+
var packageConfigContents = await provider(packageConfig);
377+
if (packageConfigContents is String) {
378+
packageConfigContents = UTF8.encode(packageConfigContents);
379+
}
380+
packages =
381+
new MapPackages(pkgs.parse(packageConfigContents, packageConfig));
382+
} else {
383+
if (packagesDiscoveryProvider == null) {
384+
packages = Packages.noPackages;
385+
} else {
386+
packages = await callUserPackagesDiscovery(uri);
387+
}
388+
}
337389
}
338390

339-
Future<bool> run(Uri uri) {
391+
Future<bool> run(Uri uri) async {
340392
log('Allowed library categories: $allowedLibraryCategories');
341-
return super.run(uri).then((bool success) {
342-
int cumulated = 0;
343-
for (final task in tasks) {
344-
int elapsed = task.timing;
345-
if (elapsed != 0) {
346-
cumulated += elapsed;
347-
log('${task.name} took ${elapsed}msec');
348-
}
393+
394+
await setupPackages(uri);
395+
assert(packages != null);
396+
397+
bool success = await super.run(uri);
398+
int cumulated = 0;
399+
for (final task in tasks) {
400+
int elapsed = task.timing;
401+
if (elapsed != 0) {
402+
cumulated += elapsed;
403+
log('${task.name} took ${elapsed}msec');
349404
}
350-
int total = totalCompileTime.elapsedMilliseconds;
351-
log('Total compile-time ${total}msec;'
352-
' unaccounted ${total - cumulated}msec');
353-
return success;
354-
});
405+
}
406+
int total = totalCompileTime.elapsedMilliseconds;
407+
log('Total compile-time ${total}msec;'
408+
' unaccounted ${total - cumulated}msec');
409+
return success;
355410
}
356411

357412
void reportDiagnostic(leg.Spannable node,
@@ -368,8 +423,7 @@ class Compiler extends leg.Compiler {
368423
if (span == null || span.uri == null) {
369424
callUserHandler(null, null, null, '$message', kind);
370425
} else {
371-
callUserHandler(
372-
translateUri(null, span.uri), span.begin, span.end, '$message', kind);
426+
callUserHandler(span.uri, span.begin, span.end, '$message', kind);
373427
}
374428
}
375429

@@ -400,6 +454,16 @@ class Compiler extends leg.Compiler {
400454
}
401455
}
402456

457+
Future<Packages> callUserPackagesDiscovery(Uri uri) {
458+
try {
459+
return userPackagesDiscoveryTask.measure(
460+
() => packagesDiscoveryProvider(uri));
461+
} catch (ex, s) {
462+
diagnoseCrashInUserCode('Uncaught exception in package discovery', ex, s);
463+
rethrow;
464+
}
465+
}
466+
403467
void diagnoseCrashInUserCode(String message, exception, stackTrace) {
404468
hasCrashed = true;
405469
print('$message: ${tryToString(exception)}');

pkg/compiler/lib/src/dart2js.dart

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import 'util/uri_extras.dart';
1919
import 'util/util.dart' show stackTraceFilePrefix;
2020
import 'util/command_line.dart';
2121
import 'package:_internal/libraries.dart';
22+
import 'package:package_config/discovery.dart' show findPackages;
2223

2324
const String LIBRARY_ROOT = '../../../../../sdk';
2425
const String OUTPUT_LANGUAGE_DART = 'Dart';
@@ -105,6 +106,7 @@ Future<api.CompilationResult> compile(List<String> argv) {
105106
Uri libraryRoot = currentDirectory;
106107
Uri out = currentDirectory.resolve('out.js');
107108
Uri sourceMapOut = currentDirectory.resolve('out.js.map');
109+
Uri packageConfig = null;
108110
Uri packageRoot = null;
109111
List<String> options = new List<String>();
110112
bool explicitOut = false;
@@ -140,6 +142,10 @@ Future<api.CompilationResult> compile(List<String> argv) {
140142
packageRoot = currentDirectory.resolve(extractPath(argument));
141143
}
142144

145+
setPackageConfig(String argument) {
146+
packageConfig = currentDirectory.resolve(extractPath(argument));
147+
}
148+
143149
setOutput(Iterator<String> arguments) {
144150
optionsImplyCompilation.add(arguments.current);
145151
String path;
@@ -329,6 +335,7 @@ Future<api.CompilationResult> compile(List<String> argv) {
329335
(_) => setTrustPrimitives(
330336
'--trust-primitives')),
331337
new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true),
338+
new OptionHandler('--packages=.+', setPackageConfig),
332339
new OptionHandler('--package-root=.+|-p.+', setPackageRoot),
333340
new OptionHandler('--analyze-all', setAnalyzeAll),
334341
new OptionHandler('--analyze-only', setAnalyzeOnly),
@@ -404,9 +411,8 @@ Future<api.CompilationResult> compile(List<String> argv) {
404411
"checked mode.");
405412
}
406413

407-
Uri uri = currentDirectory.resolve(arguments[0]);
408-
if (packageRoot == null) {
409-
packageRoot = uri.resolve('./packages/');
414+
if (packageRoot != null && packageConfig != null) {
415+
helpAndFail("Cannot specify both '--package-root' and '--packages.");
410416
}
411417

412418
if ((analyzeOnly || analyzeAll) && !optionsImplyCompilation.isEmpty) {
@@ -432,8 +438,6 @@ Future<api.CompilationResult> compile(List<String> argv) {
432438
"combination with the '--output-type=dart' option.");
433439
}
434440

435-
diagnosticHandler.info('Package root is $packageRoot');
436-
437441
options.add('--out=$out');
438442
options.add('--source-map=$sourceMapOut');
439443

@@ -468,9 +472,10 @@ Future<api.CompilationResult> compile(List<String> argv) {
468472
return result;
469473
}
470474

471-
return compileFunc(uri, libraryRoot, packageRoot,
472-
inputProvider, diagnosticHandler,
473-
options, outputProvider, environment)
475+
Uri uri = currentDirectory.resolve(arguments[0]);
476+
return compileFunc(uri, libraryRoot, packageRoot, inputProvider,
477+
diagnosticHandler, options, outputProvider, environment,
478+
packageConfig, findPackages)
474479
.then(compilationDone);
475480
}
476481

@@ -552,7 +557,12 @@ Supported options:
552557
Display version information.
553558
554559
-p<path>, --package-root=<path>
555-
Where to find packages, that is, "package:..." imports.
560+
Where to find packages, that is, "package:..." imports. This option cannot
561+
be used with --packages.
562+
563+
--packages=<path>
564+
Path to the package resolution configuration file, which supplies a mapping
565+
of package names to paths. This option cannot be used with --package-root.
556566
557567
--analyze-all
558568
Analyze all code. Without this option, the compiler only analyzes

pkg/compiler/lib/src/mirrors/analyze.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ Future<MirrorSystem> analyze(List<Uri> libraries,
2626
Uri packageRoot,
2727
api.CompilerInputProvider inputProvider,
2828
api.DiagnosticHandler diagnosticHandler,
29-
[List<String> options = const <String>[]]) {
29+
[List<String> options = const <String>[],
30+
Uri packageConfig,
31+
api.PackagesDiscoveryProvider findPackages]) {
3032
if (!libraryRoot.path.endsWith("/")) {
3133
throw new ArgumentError("libraryRoot must end with a /");
3234
}
@@ -54,9 +56,12 @@ Future<MirrorSystem> analyze(List<Uri> libraries,
5456
Compiler compiler = new apiimpl.Compiler(inputProvider,
5557
null,
5658
internalDiagnosticHandler,
57-
libraryRoot, packageRoot,
59+
libraryRoot,
60+
packageRoot,
5861
options,
59-
const {});
62+
const {},
63+
packageConfig,
64+
findPackages);
6065
compiler.librariesToAnalyzeWhenRun = libraries;
6166
return compiler.run(null).then((bool success) {
6267
if (success && !compilationFailed) {

0 commit comments

Comments
 (0)