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

Side by Side Diff: sdk/lib/_internal/pub_generated/lib/src/entrypoint.dart

Issue 937243002: Revert "Revert "Use native async/await support in pub."" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library pub.entrypoint;
6
7 import 'dart:async';
8
9 import 'package:path/path.dart' as path;
10 import 'package:barback/barback.dart';
11
12 import 'barback/asset_environment.dart';
13 import 'io.dart';
14 import 'lock_file.dart';
15 import 'log.dart' as log;
16 import 'package.dart';
17 import 'package_graph.dart';
18 import 'sdk.dart' as sdk;
19 import 'solver/version_solver.dart';
20 import 'source/cached.dart';
21 import 'system_cache.dart';
22 import 'utils.dart';
23
24 /// The context surrounding the root package pub is operating on.
25 ///
26 /// Pub operates over a directed graph of dependencies that starts at a root
27 /// "entrypoint" package. This is typically the package where the current
28 /// working directory is located. An entrypoint knows the [root] package it is
29 /// associated with and is responsible for managing the "packages" directory
30 /// for it.
31 ///
32 /// That directory contains symlinks to all packages used by an app. These links
33 /// point either to the [SystemCache] or to some other location on the local
34 /// filesystem.
35 ///
36 /// While entrypoints are typically applications, a pure library package may end
37 /// up being used as an entrypoint. Also, a single package may be used as an
38 /// entrypoint in one context but not in another. For example, a package that
39 /// contains a reusable library may not be the entrypoint when used by an app,
40 /// but may be the entrypoint when you're running its tests.
41 class Entrypoint {
42 /// The root package this entrypoint is associated with.
43 final Package root;
44
45 /// The system-wide cache which caches packages that need to be fetched over
46 /// the network.
47 final SystemCache cache;
48
49 /// Whether to create and symlink a "packages" directory containing links to
50 /// the installed packages.
51 final bool _packageSymlinks;
52
53 /// The lockfile for the entrypoint.
54 ///
55 /// If not provided to the entrypoint, it will be laoded lazily from disc.
56 LockFile _lockFile;
57
58 /// The graph of all packages reachable from the entrypoint.
59 PackageGraph _packageGraph;
60
61 /// Loads the entrypoint from a package at [rootDir].
62 ///
63 /// If [packageSymlinks] is `true`, this will create a "packages" directory
64 /// with symlinks to the installed packages. This directory will be symlinked
65 /// into any directory that might contain an entrypoint.
66 Entrypoint(String rootDir, SystemCache cache, {bool packageSymlinks: true})
67 : root = new Package.load(null, rootDir, cache.sources),
68 cache = cache,
69 _packageSymlinks = packageSymlinks;
70
71 /// Creates an entrypoint given package and lockfile objects.
72 Entrypoint.inMemory(this.root, this._lockFile, this.cache)
73 : _packageSymlinks = false;
74
75 /// The path to the entrypoint's "packages" directory.
76 String get packagesDir => root.path('packages');
77
78 /// `true` if the entrypoint package currently has a lock file.
79 bool get lockFileExists => _lockFile != null || entryExists(lockFilePath);
80
81 LockFile get lockFile {
82 if (_lockFile != null) return _lockFile;
83
84 if (!lockFileExists) {
85 _lockFile = new LockFile.empty();
86 } else {
87 _lockFile = new LockFile.load(lockFilePath, cache.sources);
88 }
89
90 return _lockFile;
91 }
92
93 /// The path to the entrypoint package's pubspec.
94 String get pubspecPath => root.path('pubspec.yaml');
95
96 /// The path to the entrypoint package's lockfile.
97 String get lockFilePath => root.path('pubspec.lock');
98
99 /// Gets all dependencies of the [root] package.
100 ///
101 /// Performs version resolution according to [SolveType].
102 ///
103 /// [useLatest], if provided, defines a list of packages that will be
104 /// unlocked and forced to their latest versions. If [upgradeAll] is
105 /// true, the previous lockfile is ignored and all packages are re-resolved
106 /// from scratch. Otherwise, it will attempt to preserve the versions of all
107 /// previously locked packages.
108 ///
109 /// Shows a report of the changes made relative to the previous lockfile. If
110 /// this is an upgrade or downgrade, all transitive dependencies are shown in
111 /// the report. Otherwise, only dependencies that were changed are shown. If
112 /// [dryRun] is `true`, no physical changes are made.
113 Future acquireDependencies(SolveType type, {List<String> useLatest,
114 bool dryRun: false}) {
115 final completer0 = new Completer();
116 scheduleMicrotask(() {
117 try {
118 new Future.value(
119 resolveVersions(
120 type,
121 cache.sources,
122 root,
123 lockFile: lockFile,
124 useLatest: useLatest)).then((x0) {
125 try {
126 var result = x0;
127 join0() {
128 result.showReport(type);
129 join1() {
130 join2() {
131 new Future.value(
132 Future.wait(result.packages.map(_get))).then((x1) {
133 try {
134 var ids = x1;
135 _saveLockFile(ids);
136 join3() {
137 _linkOrDeleteSecondaryPackageDirs();
138 result.summarizeChanges(type, dryRun: dryRun);
139 new Future.value(loadPackageGraph(result)).then((x2) {
140 try {
141 var packageGraph = x2;
142 packageGraph.loadTransformerCache().clearIfOutdated(
143 result.changedPackages);
144 join4() {
145 completer0.complete();
146 }
147 catch0(error, stackTrace) {
148 try {
149 log.exception(error, stackTrace);
150 join4();
151 } catch (error, stackTrace) {
152 completer0.completeError(error, stackTrace);
153 }
154 }
155 try {
156 new Future.value(
157 precompileDependencies(changed: result.changed Packages)).then((x3) {
158 try {
159 x3;
160 new Future.value(
161 precompileExecutables(changed: result.chan gedPackages)).then((x4) {
162 try {
163 x4;
164 join4();
165 } catch (e0, s0) {
166 catch0(e0, s0);
167 }
168 }, onError: catch0);
169 } catch (e1, s1) {
170 catch0(e1, s1);
171 }
172 }, onError: catch0);
173 } catch (e2, s2) {
174 catch0(e2, s2);
175 }
176 } catch (e3, s3) {
177 completer0.completeError(e3, s3);
178 }
179 }, onError: completer0.completeError);
180 }
181 if (_packageSymlinks) {
182 _linkSelf();
183 join3();
184 } else {
185 join3();
186 }
187 } catch (e4, s4) {
188 completer0.completeError(e4, s4);
189 }
190 }, onError: completer0.completeError);
191 }
192 if (_packageSymlinks) {
193 cleanDir(packagesDir);
194 join2();
195 } else {
196 deleteEntry(packagesDir);
197 join2();
198 }
199 }
200 if (dryRun) {
201 result.summarizeChanges(type, dryRun: dryRun);
202 completer0.complete(null);
203 } else {
204 join1();
205 }
206 }
207 if (!result.succeeded) {
208 throw result.error;
209 join0();
210 } else {
211 join0();
212 }
213 } catch (e5, s5) {
214 completer0.completeError(e5, s5);
215 }
216 }, onError: completer0.completeError);
217 } catch (e, s) {
218 completer0.completeError(e, s);
219 }
220 });
221 return completer0.future;
222 }
223
224 /// Precompile any transformed dependencies of the entrypoint.
225 ///
226 /// If [changed] is passed, only dependencies whose contents might be changed
227 /// if one of the given packages changes will be recompiled.
228 Future precompileDependencies({Iterable<String> changed}) {
229 final completer0 = new Completer();
230 scheduleMicrotask(() {
231 try {
232 join0() {
233 new Future.value(loadPackageGraph()).then((x0) {
234 try {
235 var graph = x0;
236 var depsDir = path.join('.pub', 'deps', 'debug');
237 var dependenciesToPrecompile =
238 graph.packages.values.where(((package) {
239 if (package.pubspec.transformers.isEmpty) return false;
240 if (graph.isPackageMutable(package.name)) return false;
241 if (!dirExists(path.join(depsDir, package.name))) return true;
242 if (changed == null) return true;
243 return overlaps(
244 graph.transitiveDependencies(
245 package.name).map((package) => package.name).toSet(),
246 changed);
247 })).map(((package) {
248 return package.name;
249 })).toSet();
250 join1() {
251 join2() {
252 join3() {
253 completer0.complete();
254 }
255 catch0(_, s0) {
256 try {
257 var it0 = dependenciesToPrecompile.iterator;
258 break0() {
259 completer0.completeError(_, s0);
260 }
261 var trampoline0;
262 continue0() {
263 trampoline0 = null;
264 if (it0.moveNext()) {
265 var package = it0.current;
266 deleteEntry(path.join(depsDir, package));
267 trampoline0 = continue0;
268 do trampoline0(); while (trampoline0 != null);
269 } else {
270 break0();
271 }
272 }
273 trampoline0 = continue0;
274 do trampoline0(); while (trampoline0 != null);
275 } catch (_, s0) {
276 completer0.completeError(_, s0);
277 }
278 }
279 try {
280 new Future.value(
281 log.progress("Precompiling dependencies", (() {
282 final completer0 = new Completer();
283 scheduleMicrotask(() {
284 try {
285 var packagesToLoad = unionAll(
286 dependenciesToPrecompile.map(graph.transitiveDepen dencies)).map(((package) {
287 return package.name;
288 })).toSet();
289 new Future.value(
290 AssetEnvironment.create(
291 this,
292 BarbackMode.DEBUG,
293 packages: packagesToLoad,
294 useDart2JS: false)).then((x0) {
295 try {
296 var environment = x0;
297 environment.barback.errors.listen(((_) {
298 }));
299 new Future.value(
300 environment.barback.getAllAssets()).then((x1) {
301 try {
302 var assets = x1;
303 new Future.value(
304 waitAndPrintErrors(assets.map(((asset) {
305 final completer0 = new Completer();
306 scheduleMicrotask(() {
307 try {
308 join0() {
309 var destPath =
310 path.join(depsDir, asset.id.packag e, path.fromUri(asset.id.path));
311 ensureDir(path.dirname(destPath));
312 new Future.value(
313 createFileFromStream(asset.read(), destPath)).then((x0) {
314 try {
315 x0;
316 completer0.complete();
317 } catch (e0, s0) {
318 completer0.completeError(e0, s0);
319 }
320 }, onError: completer0.completeError);
321 }
322 if (!dependenciesToPrecompile.contains(
323 asset.id.package)) {
324 completer0.complete(null);
325 } else {
326 join0();
327 }
328 } catch (e, s) {
329 completer0.completeError(e, s);
330 }
331 });
332 return completer0.future;
333 })))).then((x2) {
334 try {
335 x2;
336 log.message(
337 "Precompiled " +
338 toSentence(ordered(dependenciesToP recompile).map(log.bold)) +
339 ".");
340 completer0.complete();
341 } catch (e0, s0) {
342 completer0.completeError(e0, s0);
343 }
344 }, onError: completer0.completeError);
345 } catch (e1, s1) {
346 completer0.completeError(e1, s1);
347 }
348 }, onError: completer0.completeError);
349 } catch (e2, s2) {
350 completer0.completeError(e2, s2);
351 }
352 }, onError: completer0.completeError);
353 } catch (e, s) {
354 completer0.completeError(e, s);
355 }
356 });
357 return completer0.future;
358 }))).then((x1) {
359 try {
360 x1;
361 join3();
362 } catch (e0, s1) {
363 catch0(e0, s1);
364 }
365 }, onError: catch0);
366 } catch (e1, s2) {
367 catch0(e1, s2);
368 }
369 }
370 if (dependenciesToPrecompile.isEmpty) {
371 completer0.complete(null);
372 } else {
373 join2();
374 }
375 }
376 if (dirExists(depsDir)) {
377 var it1 = dependenciesToPrecompile.iterator;
378 break1() {
379 var it2 = listDir(depsDir).iterator;
380 break2() {
381 join1();
382 }
383 var trampoline2;
384 continue2() {
385 trampoline2 = null;
386 if (it2.moveNext()) {
387 var subdir = it2.current;
388 var package = graph.packages[path.basename(subdir)];
389 join4() {
390 trampoline2 = continue2;
391 do trampoline2(); while (trampoline2 != null);
392 }
393 if (package == null ||
394 package.pubspec.transformers.isEmpty ||
395 graph.isPackageMutable(package.name)) {
396 deleteEntry(subdir);
397 join4();
398 } else {
399 join4();
400 }
401 } else {
402 break2();
403 }
404 }
405 trampoline2 = continue2;
406 do trampoline2(); while (trampoline2 != null);
407 }
408 var trampoline1;
409 continue1() {
410 trampoline1 = null;
411 if (it1.moveNext()) {
412 var package = it1.current;
413 deleteEntry(path.join(depsDir, package));
414 trampoline1 = continue1;
415 do trampoline1(); while (trampoline1 != null);
416 } else {
417 break1();
418 }
419 }
420 trampoline1 = continue1;
421 do trampoline1(); while (trampoline1 != null);
422 } else {
423 join1();
424 }
425 } catch (e2, s3) {
426 completer0.completeError(e2, s3);
427 }
428 }, onError: completer0.completeError);
429 }
430 if (changed != null) {
431 changed = changed.toSet();
432 join0();
433 } else {
434 join0();
435 }
436 } catch (e, s) {
437 completer0.completeError(e, s);
438 }
439 });
440 return completer0.future;
441 }
442
443 /// Precompiles all executables from dependencies that don't transitively
444 /// depend on [this] or on a path dependency.
445 Future precompileExecutables({Iterable<String> changed}) {
446 final completer0 = new Completer();
447 scheduleMicrotask(() {
448 try {
449 join0() {
450 var binDir = path.join('.pub', 'bin');
451 var sdkVersionPath = path.join(binDir, 'sdk-version');
452 var sdkMatches =
453 fileExists(sdkVersionPath) &&
454 readTextFile(sdkVersionPath) == "${sdk.version}\n";
455 join1() {
456 new Future.value(loadPackageGraph()).then((x0) {
457 try {
458 var graph = x0;
459 var executables =
460 new Map.fromIterable(root.immediateDependencies, key: ((dep) {
461 return dep.name;
462 }), value: ((dep) {
463 return _executablesForPackage(graph, dep.name, changed);
464 }));
465 var it0 = executables.keys.toList().iterator;
466 break0() {
467 join2() {
468 join3() {
469 new Future.value(
470 log.progress("Precompiling executables", (() {
471 final completer0 = new Completer();
472 scheduleMicrotask(() {
473 try {
474 ensureDir(binDir);
475 writeTextFile(sdkVersionPath, "${sdk.version}\n");
476 var packagesToLoad =
477 unionAll(executables.keys.map(graph.transitiveDe pendencies)).map(((package) {
478 return package.name;
479 })).toSet();
480 var executableIds =
481 unionAll(executables.values.map(((ids) {
482 return ids.toSet();
483 })));
484 new Future.value(
485 AssetEnvironment.create(
486 this,
487 BarbackMode.RELEASE,
488 packages: packagesToLoad,
489 entrypoints: executableIds,
490 useDart2JS: false)).then((x0) {
491 try {
492 var environment = x0;
493 environment.barback.errors.listen(((error) {
494 log.error(log.red("Build error:\n$error"));
495 }));
496 new Future.value(
497 waitAndPrintErrors(executables.keys.map(((pa ckage) {
498 final completer0 = new Completer();
499 scheduleMicrotask(() {
500 try {
501 var dir = path.join(binDir, package);
502 cleanDir(dir);
503 new Future.value(
504 environment.precompileExecutables(
505 package,
506 dir,
507 executableIds: executables[package ])).then((x0) {
508 try {
509 x0;
510 completer0.complete();
511 } catch (e0, s0) {
512 completer0.completeError(e0, s0);
513 }
514 }, onError: completer0.completeError);
515 } catch (e, s) {
516 completer0.completeError(e, s);
517 }
518 });
519 return completer0.future;
520 })))).then((x1) {
521 try {
522 x1;
523 completer0.complete();
524 } catch (e0, s0) {
525 completer0.completeError(e0, s0);
526 }
527 }, onError: completer0.completeError);
528 } catch (e1, s1) {
529 completer0.completeError(e1, s1);
530 }
531 }, onError: completer0.completeError);
532 } catch (e, s) {
533 completer0.completeError(e, s);
534 }
535 });
536 return completer0.future;
537 }))).then((x1) {
538 try {
539 x1;
540 completer0.complete();
541 } catch (e0, s0) {
542 completer0.completeError(e0, s0);
543 }
544 }, onError: completer0.completeError);
545 }
546 if (executables.isEmpty) {
547 completer0.complete(null);
548 } else {
549 join3();
550 }
551 }
552 if (!sdkMatches) {
553 deleteEntry(binDir);
554 join2();
555 } else {
556 join2();
557 }
558 }
559 var trampoline0;
560 continue0() {
561 trampoline0 = null;
562 if (it0.moveNext()) {
563 var package = it0.current;
564 join4() {
565 trampoline0 = continue0;
566 do trampoline0(); while (trampoline0 != null);
567 }
568 if (executables[package].isEmpty) {
569 executables.remove(package);
570 join4();
571 } else {
572 join4();
573 }
574 } else {
575 break0();
576 }
577 }
578 trampoline0 = continue0;
579 do trampoline0(); while (trampoline0 != null);
580 } catch (e1, s1) {
581 completer0.completeError(e1, s1);
582 }
583 }, onError: completer0.completeError);
584 }
585 if (!sdkMatches) {
586 changed = null;
587 join1();
588 } else {
589 join1();
590 }
591 }
592 if (changed != null) {
593 changed = changed.toSet();
594 join0();
595 } else {
596 join0();
597 }
598 } catch (e, s) {
599 completer0.completeError(e, s);
600 }
601 });
602 return completer0.future;
603 }
604
605 /// Returns the list of all executable assets for [packageName] that should be
606 /// precompiled.
607 ///
608 /// If [changed] isn't `null`, executables for [packageName] will only be
609 /// compiled if they might depend on a package in [changed].
610 List<AssetId> _executablesForPackage(PackageGraph graph, String packageName,
611 Set<String> changed) {
612 var package = graph.packages[packageName];
613 var binDir = package.path('bin');
614 if (!dirExists(binDir)) return [];
615 if (graph.isPackageMutable(packageName)) return [];
616
617 var executables = package.executableIds;
618
619 // If we don't know which packages were changed, always precompile the
620 // executables.
621 if (changed == null) return executables;
622
623 // If any of the package's dependencies changed, recompile the executables.
624 if (graph.transitiveDependencies(
625 packageName).any((package) => changed.contains(package.name))) {
626 return executables;
627 }
628
629 // If any executables doesn't exist, precompile them regardless of what
630 // changed. Since we delete the bin directory before recompiling, we need to
631 // recompile all executables.
632 var executablesExist = executables.every(
633 (executable) =>
634 fileExists(
635 path.join(
636 '.pub',
637 'bin',
638 packageName,
639 "${path.url.basename(executable.path)}.snapshot")));
640 if (!executablesExist) return executables;
641
642 // Otherwise, we don't need to recompile.
643 return [];
644 }
645
646 /// Makes sure the package at [id] is locally available.
647 ///
648 /// This automatically downloads the package to the system-wide cache as well
649 /// if it requires network access to retrieve (specifically, if the package's
650 /// source is a [CachedSource]).
651 Future<PackageId> _get(PackageId id) {
652 if (id.isRoot) return new Future.value(id);
653
654 var source = cache.sources[id.source];
655 return new Future.sync(() {
656 if (!_packageSymlinks) {
657 if (source is! CachedSource) return null;
658 return source.downloadToSystemCache(id);
659 }
660
661 var packageDir = path.join(packagesDir, id.name);
662 if (entryExists(packageDir)) deleteEntry(packageDir);
663 return source.get(id, packageDir);
664 }).then((_) => source.resolveId(id));
665 }
666
667 /// Determines whether or not the lockfile is out of date with respect to the
668 /// pubspec.
669 ///
670 /// This will be `false` if there is no lockfile at all, or if the pubspec
671 /// contains dependencies that are not in the lockfile or that don't match
672 /// what's in there.
673 bool _isLockFileUpToDate(LockFile lockFile) {
674 /// If this is an entrypoint for an in-memory package, trust the in-memory
675 /// lockfile provided for it.
676 if (root.dir == null) return true;
677
678 return root.immediateDependencies.every((package) {
679 var locked = lockFile.packages[package.name];
680 if (locked == null) return false;
681
682 if (package.source != locked.source) return false;
683 if (!package.constraint.allows(locked.version)) return false;
684
685 var source = cache.sources[package.source];
686 if (source == null) return false;
687
688 return source.descriptionsEqual(package.description, locked.description);
689 });
690 }
691
692 /// Determines whether all of the packages in the lockfile are already
693 /// installed and available.
694 ///
695 /// Note: this assumes [isLockFileUpToDate] has already been called and
696 /// returned `true`.
697 Future<bool> _arePackagesAvailable(LockFile lockFile) {
698 return Future.wait(lockFile.packages.values.map((package) {
699 var source = cache.sources[package.source];
700
701 // This should only be called after [_isLockFileUpToDate] has returned
702 // `true`, which ensures all of the sources in the lock file are valid.
703 assert(source != null);
704
705 // We only care about cached sources. Uncached sources aren't "installed".
706 // If one of those is missing, we want to show the user the file not
707 // found error later since installing won't accomplish anything.
708 if (source is! CachedSource) return new Future.value(true);
709
710 // Get the directory.
711 return source.getDirectory(package).then((dir) {
712 // See if the directory is there and looks like a package.
713 return dirExists(dir) || fileExists(path.join(dir, "pubspec.yaml"));
714 });
715 })).then((results) {
716 // Make sure they are all true.
717 return results.every((result) => result);
718 });
719 }
720
721 /// Gets dependencies if the lockfile is out of date with respect to the
722 /// pubspec.
723 Future ensureLockFileIsUpToDate() {
724 return new Future.sync(() {
725 // If we don't have a current lock file, we definitely need to install.
726 if (!_isLockFileUpToDate(lockFile)) {
727 if (lockFileExists) {
728 log.message(
729 "Your pubspec has changed, so we need to update your lockfile:");
730 } else {
731 log.message(
732 "You don't have a lockfile, so we need to generate that:");
733 }
734
735 return false;
736 }
737
738 // If we do have a lock file, we still need to make sure the packages
739 // are actually installed. The user may have just gotten a package that
740 // includes a lockfile.
741 return _arePackagesAvailable(lockFile).then((available) {
742 if (!available) {
743 log.message(
744 "You are missing some dependencies, so we need to install them " " first:");
745 }
746
747 return available;
748 });
749 }).then((upToDate) {
750 if (upToDate) return null;
751 return acquireDependencies(SolveType.GET);
752 });
753 }
754
755 /// Loads the package graph for the application and all of its transitive
756 /// dependencies.
757 ///
758 /// If [result] is passed, this loads the graph from it without re-parsing the
759 /// lockfile or any pubspecs. Otherwise, before loading, this makes sure the
760 /// lockfile and dependencies are installed and up to date.
761 Future<PackageGraph> loadPackageGraph([SolveResult result]) {
762 final completer0 = new Completer();
763 scheduleMicrotask(() {
764 try {
765 join0() {
766 new Future.value(log.progress("Loading package graph", (() {
767 final completer0 = new Completer();
768 scheduleMicrotask(() {
769 try {
770 join0() {
771 new Future.value(ensureLockFileIsUpToDate()).then((x0) {
772 try {
773 x0;
774 new Future.value(
775 Future.wait(lockFile.packages.values.map(((id) {
776 final completer0 = new Completer();
777 scheduleMicrotask(() {
778 try {
779 var source = cache.sources[id.source];
780 new Future.value(
781 source.getDirectory(id)).then((x0) {
782 try {
783 var dir = x0;
784 completer0.complete(
785 new Package.load(id.name, dir, cache.sources ));
786 } catch (e0, s0) {
787 completer0.completeError(e0, s0);
788 }
789 }, onError: completer0.completeError);
790 } catch (e, s) {
791 completer0.completeError(e, s);
792 }
793 });
794 return completer0.future;
795 })))).then((x1) {
796 try {
797 var packages = x1;
798 var packageMap =
799 new Map.fromIterable(packages, key: ((p) {
800 return p.name;
801 }));
802 packageMap[root.name] = root;
803 completer0.complete(
804 new PackageGraph(this, lockFile, packageMap));
805 } catch (e0, s0) {
806 completer0.completeError(e0, s0);
807 }
808 }, onError: completer0.completeError);
809 } catch (e1, s1) {
810 completer0.completeError(e1, s1);
811 }
812 }, onError: completer0.completeError);
813 }
814 if (result != null) {
815 new Future.value(Future.wait(result.packages.map(((id) {
816 final completer0 = new Completer();
817 scheduleMicrotask(() {
818 try {
819 new Future.value(
820 cache.sources[id.source].getDirectory(id)).then((x0) {
821 try {
822 var dir = x0;
823 completer0.complete(
824 new Package(result.pubspecs[id.name], dir));
825 } catch (e0, s0) {
826 completer0.completeError(e0, s0);
827 }
828 }, onError: completer0.completeError);
829 } catch (e, s) {
830 completer0.completeError(e, s);
831 }
832 });
833 return completer0.future;
834 })))).then((x2) {
835 try {
836 var packages = x2;
837 completer0.complete(
838 new PackageGraph(
839 this,
840 new LockFile(result.packages),
841 new Map.fromIterable(packages, key: ((package) {
842 return package.name;
843 }))));
844 } catch (e2, s2) {
845 completer0.completeError(e2, s2);
846 }
847 }, onError: completer0.completeError);
848 } else {
849 join0();
850 }
851 } catch (e, s) {
852 completer0.completeError(e, s);
853 }
854 });
855 return completer0.future;
856 }), fine: true)).then((x0) {
857 try {
858 var graph = x0;
859 _packageGraph = graph;
860 completer0.complete(graph);
861 } catch (e0, s0) {
862 completer0.completeError(e0, s0);
863 }
864 }, onError: completer0.completeError);
865 }
866 if (_packageGraph != null) {
867 completer0.complete(_packageGraph);
868 } else {
869 join0();
870 }
871 } catch (e, s) {
872 completer0.completeError(e, s);
873 }
874 });
875 return completer0.future;
876 }
877
878 /// Saves a list of concrete package versions to the `pubspec.lock` file.
879 void _saveLockFile(List<PackageId> packageIds) {
880 _lockFile = new LockFile(packageIds);
881 var lockFilePath = root.path('pubspec.lock');
882 writeTextFile(lockFilePath, _lockFile.serialize(root.dir, cache.sources));
883 }
884
885 /// Creates a self-referential symlink in the `packages` directory that allows
886 /// a package to import its own files using `package:`.
887 void _linkSelf() {
888 var linkPath = path.join(packagesDir, root.name);
889 // Create the symlink if it doesn't exist.
890 if (entryExists(linkPath)) return;
891 ensureDir(packagesDir);
892 createPackageSymlink(
893 root.name,
894 root.dir,
895 linkPath,
896 isSelfLink: true,
897 relative: true);
898 }
899
900 /// If [packageSymlinks] is true, add "packages" directories to the whitelist
901 /// of directories that may contain Dart entrypoints.
902 ///
903 /// Otherwise, delete any "packages" directories in the whitelist of
904 /// directories that may contain Dart entrypoints.
905 void _linkOrDeleteSecondaryPackageDirs() {
906 // Only the main "bin" directory gets a "packages" directory, not its
907 // subdirectories.
908 var binDir = root.path('bin');
909 if (dirExists(binDir)) _linkOrDeleteSecondaryPackageDir(binDir);
910
911 // The others get "packages" directories in subdirectories too.
912 for (var dir in ['benchmark', 'example', 'test', 'tool', 'web']) {
913 _linkOrDeleteSecondaryPackageDirsRecursively(root.path(dir));
914 }
915 }
916
917 /// If [packageSymlinks] is true, creates a symlink to the "packages"
918 /// directory in [dir] and all its subdirectories.
919 ///
920 /// Otherwise, deletes any "packages" directories in [dir] and all its
921 /// subdirectories.
922 void _linkOrDeleteSecondaryPackageDirsRecursively(String dir) {
923 if (!dirExists(dir)) return;
924 _linkOrDeleteSecondaryPackageDir(dir);
925 _listDirWithoutPackages(
926 dir).where(dirExists).forEach(_linkOrDeleteSecondaryPackageDir);
927 }
928
929 // TODO(nweiz): roll this into [listDir] in io.dart once issue 4775 is fixed.
930 /// Recursively lists the contents of [dir], excluding hidden `.DS_Store`
931 /// files and `package` files.
932 List<String> _listDirWithoutPackages(dir) {
933 return flatten(listDir(dir).map((file) {
934 if (path.basename(file) == 'packages') return [];
935 if (!dirExists(file)) return [];
936 var fileAndSubfiles = [file];
937 fileAndSubfiles.addAll(_listDirWithoutPackages(file));
938 return fileAndSubfiles;
939 }));
940 }
941
942 /// If [packageSymlinks] is true, creates a symlink to the "packages"
943 /// directory in [dir].
944 ///
945 /// Otherwise, deletes a "packages" directories in [dir] if one exists.
946 void _linkOrDeleteSecondaryPackageDir(String dir) {
947 var symlink = path.join(dir, 'packages');
948 if (entryExists(symlink)) deleteEntry(symlink);
949 if (_packageSymlinks) createSymlink(packagesDir, symlink, relative: true);
950 }
951 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/pub_generated/lib/src/dart.dart ('k') | sdk/lib/_internal/pub_generated/lib/src/error_group.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698