OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:io'; | 6 import 'dart:io'; |
7 | 7 |
8 import 'package:barback/barback.dart'; | 8 import 'package:barback/barback.dart'; |
9 import 'package:package_config/packages_file.dart' as packages_file; | 9 import 'package:package_config/packages_file.dart' as packages_file; |
10 import 'package:path/path.dart' as p; | 10 import 'package:path/path.dart' as p; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
64 /// contains a reusable library may not be the entrypoint when used by an app, | 64 /// contains a reusable library may not be the entrypoint when used by an app, |
65 /// but may be the entrypoint when you're running its tests. | 65 /// but may be the entrypoint when you're running its tests. |
66 class Entrypoint { | 66 class Entrypoint { |
67 /// The root package this entrypoint is associated with. | 67 /// The root package this entrypoint is associated with. |
68 final Package root; | 68 final Package root; |
69 | 69 |
70 /// The system-wide cache which caches packages that need to be fetched over | 70 /// The system-wide cache which caches packages that need to be fetched over |
71 /// the network. | 71 /// the network. |
72 final SystemCache cache; | 72 final SystemCache cache; |
73 | 73 |
74 /// Whether to create and symlink a "packages" directory containing links to | |
75 /// the installed packages. | |
76 final bool _packageSymlinks; | |
77 | |
78 /// Whether this entrypoint is in memory only, as opposed to representing a | 74 /// Whether this entrypoint is in memory only, as opposed to representing a |
79 /// real directory on disk. | 75 /// real directory on disk. |
80 final bool _inMemory; | 76 final bool _inMemory; |
81 | 77 |
82 /// Whether this is an entrypoint for a globally-activated package. | 78 /// Whether this is an entrypoint for a globally-activated package. |
83 final bool isGlobal; | 79 final bool isGlobal; |
84 | 80 |
85 /// The lockfile for the entrypoint. | 81 /// The lockfile for the entrypoint. |
86 /// | 82 /// |
87 /// If not provided to the entrypoint, it will be loaded lazily from disk. | 83 /// If not provided to the entrypoint, it will be loaded lazily from disk. |
(...skipping 24 matching lines...) Expand all Loading... | |
112 key: (id) => id.name, | 108 key: (id) => id.name, |
113 value: (id) => cache.load(id)); | 109 value: (id) => cache.load(id)); |
114 packages[root.name] = root; | 110 packages[root.name] = root; |
115 | 111 |
116 _packageGraph = new PackageGraph(this, lockFile, packages); | 112 _packageGraph = new PackageGraph(this, lockFile, packages); |
117 return _packageGraph; | 113 return _packageGraph; |
118 } | 114 } |
119 PackageGraph _packageGraph; | 115 PackageGraph _packageGraph; |
120 | 116 |
121 /// The path to the entrypoint's "packages" directory. | 117 /// The path to the entrypoint's "packages" directory. |
122 String get packagesDir => root.path('packages'); | 118 String get packagesPath => root.path('packages'); |
123 | 119 |
124 /// The path to the entrypoint's ".packages" file. | 120 /// The path to the entrypoint's ".packages" file. |
125 String get packagesFile => root.path('.packages'); | 121 String get packagesFile => root.path('.packages'); |
126 | 122 |
127 /// The path to the entrypoint package's pubspec. | 123 /// The path to the entrypoint package's pubspec. |
128 String get pubspecPath => root.path('pubspec.yaml'); | 124 String get pubspecPath => root.path('pubspec.yaml'); |
129 | 125 |
130 /// The path to the entrypoint package's lockfile. | 126 /// The path to the entrypoint package's lockfile. |
131 String get lockFilePath => root.path('pubspec.lock'); | 127 String get lockFilePath => root.path('pubspec.lock'); |
132 | 128 |
133 /// The path to the directory containing precompiled dependencies. | 129 /// The path to the directory containing precompiled dependencies. |
134 /// | 130 /// |
135 /// We just precompile the debug version of a package. We're mostly interested | 131 /// We just precompile the debug version of a package. We're mostly interested |
136 /// in improving speed for development iteration loops, which usually use | 132 /// in improving speed for development iteration loops, which usually use |
137 /// debug mode. | 133 /// debug mode. |
138 String get _precompiledDepsPath => root.path('.pub', 'deps', 'debug'); | 134 String get _precompiledDepsPath => root.path('.pub', 'deps', 'debug'); |
139 | 135 |
140 /// The path to the directory containing dependency executable snapshots. | 136 /// The path to the directory containing dependency executable snapshots. |
141 String get _snapshotPath => root.path('.pub', 'bin'); | 137 String get _snapshotPath => root.path('.pub', 'bin'); |
142 | 138 |
143 /// Loads the entrypoint from a package at [rootDir]. | 139 /// Loads the entrypoint from a package at [rootDir]. |
144 /// | 140 Entrypoint(String rootDir, SystemCache cache, {this.isGlobal: false}) |
145 /// If [packageSymlinks] is `true`, this will create a "packages" directory | |
146 /// with symlinks to the installed packages. This directory will be symlinked | |
147 /// into any directory that might contain an entrypoint. | |
148 Entrypoint(String rootDir, SystemCache cache, {bool packageSymlinks: true, | |
149 this.isGlobal: false}) | |
150 : root = new Package.load(null, rootDir, cache.sources), | 141 : root = new Package.load(null, rootDir, cache.sources), |
151 cache = cache, | 142 cache = cache, |
152 _packageSymlinks = packageSymlinks, | |
153 _inMemory = false; | 143 _inMemory = false; |
154 | 144 |
155 /// Creates an entrypoint given package and lockfile objects. | 145 /// Creates an entrypoint given package and lockfile objects. |
156 Entrypoint.inMemory(this.root, this._lockFile, this.cache, | 146 Entrypoint.inMemory(this.root, this._lockFile, this.cache, |
157 {this.isGlobal: false}) | 147 {this.isGlobal: false}) |
158 : _packageSymlinks = false, | 148 : _inMemory = true; |
159 _inMemory = true; | |
160 | 149 |
161 /// Creates an entrypoint given a package and a [solveResult], from which the | 150 /// Creates an entrypoint given a package and a [solveResult], from which the |
162 /// package graph and lockfile will be computed. | 151 /// package graph and lockfile will be computed. |
163 Entrypoint.fromSolveResult(this.root, this.cache, SolveResult solveResult, | 152 Entrypoint.fromSolveResult(this.root, this.cache, SolveResult solveResult, |
164 {this.isGlobal: false}) | 153 {this.isGlobal: false}) |
165 : _packageSymlinks = false, | 154 : _inMemory = true { |
166 _inMemory = true { | |
167 _packageGraph = new PackageGraph.fromSolveResult(this, solveResult); | 155 _packageGraph = new PackageGraph.fromSolveResult(this, solveResult); |
168 _lockFile = _packageGraph.lockFile; | 156 _lockFile = _packageGraph.lockFile; |
169 } | 157 } |
170 | 158 |
171 /// Gets all dependencies of the [root] package. | 159 /// Gets all dependencies of the [root] package. |
172 /// | 160 /// |
173 /// Performs version resolution according to [SolveType]. | 161 /// Performs version resolution according to [SolveType]. |
174 /// | 162 /// |
175 /// [useLatest], if provided, defines a list of packages that will be | 163 /// [useLatest], if provided, defines a list of packages that will be |
176 /// unlocked and forced to their latest versions. If [upgradeAll] is | 164 /// unlocked and forced to their latest versions. If [upgradeAll] is |
177 /// true, the previous lockfile is ignored and all packages are re-resolved | 165 /// true, the previous lockfile is ignored and all packages are re-resolved |
178 /// from scratch. Otherwise, it will attempt to preserve the versions of all | 166 /// from scratch. Otherwise, it will attempt to preserve the versions of all |
179 /// previously locked packages. | 167 /// previously locked packages. |
180 /// | 168 /// |
181 /// Shows a report of the changes made relative to the previous lockfile. If | 169 /// Shows a report of the changes made relative to the previous lockfile. If |
182 /// this is an upgrade or downgrade, all transitive dependencies are shown in | 170 /// this is an upgrade or downgrade, all transitive dependencies are shown in |
183 /// the report. Otherwise, only dependencies that were changed are shown. If | 171 /// the report. Otherwise, only dependencies that were changed are shown. If |
184 /// [dryRun] is `true`, no physical changes are made. | 172 /// [dryRun] is `true`, no physical changes are made. |
185 /// | 173 /// |
186 /// If [precompile] is `true` (the default), this snapshots dependencies' | 174 /// If [precompile] is `true` (the default), this snapshots dependencies' |
187 /// executables and runs transformers on transformed dependencies. | 175 /// executables and runs transformers on transformed dependencies. |
188 /// | 176 /// |
177 /// If [packagesDir] is `true`, this will create "packages" directory with | |
178 /// symlinks to the installed packages. This directory will be symlinked into | |
179 /// any directory that might contain an entrypoint. | |
180 /// | |
189 /// Updates [lockFile] and [packageRoot] accordingly. | 181 /// Updates [lockFile] and [packageRoot] accordingly. |
190 Future acquireDependencies(SolveType type, {List<String> useLatest, | 182 Future acquireDependencies(SolveType type, {List<String> useLatest, |
191 bool dryRun: false, bool precompile: true}) async { | 183 bool dryRun: false, bool precompile: true, bool packagesDir: false}) |
Bob Nystrom
2016/08/16 22:19:43
The name "packagesDir" reads like it *is* the pack
nweiz
2016/08/16 22:27:57
I generally prefer short names to totally unambigu
| |
184 async { | |
192 var result = await resolveVersions(type, cache, root, | 185 var result = await resolveVersions(type, cache, root, |
193 lockFile: lockFile, useLatest: useLatest); | 186 lockFile: lockFile, useLatest: useLatest); |
194 if (!result.succeeded) throw result.error; | 187 if (!result.succeeded) throw result.error; |
195 | 188 |
196 result.showReport(type); | 189 result.showReport(type); |
197 | 190 |
198 if (dryRun) { | 191 if (dryRun) { |
199 result.summarizeChanges(type, dryRun: dryRun); | 192 result.summarizeChanges(type, dryRun: dryRun); |
200 return; | 193 return; |
201 } | 194 } |
202 | 195 |
203 // Install the packages and maybe link them into the entrypoint. | 196 // Install the packages and maybe link them into the entrypoint. |
204 if (_packageSymlinks) { | 197 if (packagesDir) { |
205 cleanDir(packagesDir); | 198 cleanDir(packagesPath); |
206 } else { | 199 } else { |
207 deleteEntry(packagesDir); | 200 deleteEntry(packagesPath); |
208 } | 201 } |
209 | 202 |
210 await Future.wait(result.packages.map(_get)); | 203 await Future.wait(result.packages |
204 .map((id) => _get(id, packagesDir: packagesDir))); | |
211 _saveLockFile(result); | 205 _saveLockFile(result); |
212 | 206 |
213 if (_packageSymlinks) _linkSelf(); | 207 if (packagesDir) _linkSelf(); |
214 _linkOrDeleteSecondaryPackageDirs(); | 208 _linkOrDeleteSecondaryPackageDirs(packagesDir: packagesDir); |
215 | 209 |
216 result.summarizeChanges(type, dryRun: dryRun); | 210 result.summarizeChanges(type, dryRun: dryRun); |
217 | 211 |
218 /// Build a package graph from the version solver results so we don't | 212 /// Build a package graph from the version solver results so we don't |
219 /// have to reload and reparse all the pubspecs. | 213 /// have to reload and reparse all the pubspecs. |
220 _packageGraph = new PackageGraph.fromSolveResult(this, result); | 214 _packageGraph = new PackageGraph.fromSolveResult(this, result); |
221 packageGraph.loadTransformerCache().clearIfOutdated(result.changedPackages); | 215 packageGraph.loadTransformerCache().clearIfOutdated(result.changedPackages); |
222 | 216 |
223 try { | 217 try { |
224 if (precompile) { | 218 if (precompile) { |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
442 | 436 |
443 // Otherwise, we don't need to recompile. | 437 // Otherwise, we don't need to recompile. |
444 return []; | 438 return []; |
445 } | 439 } |
446 | 440 |
447 /// Makes sure the package at [id] is locally available. | 441 /// Makes sure the package at [id] is locally available. |
448 /// | 442 /// |
449 /// This automatically downloads the package to the system-wide cache as well | 443 /// This automatically downloads the package to the system-wide cache as well |
450 /// if it requires network access to retrieve (specifically, if the package's | 444 /// if it requires network access to retrieve (specifically, if the package's |
451 /// source is a [CachedSource]). | 445 /// source is a [CachedSource]). |
452 Future _get(PackageId id) async { | 446 Future _get(PackageId id, {bool packagesDir: false}) async { |
453 if (id.isRoot) return; | 447 if (id.isRoot) return; |
454 | 448 |
455 var source = cache.source(id.source); | 449 var source = cache.source(id.source); |
456 if (!_packageSymlinks) { | 450 if (!packagesDir) { |
457 if (source is CachedSource) await source.downloadToSystemCache(id); | 451 if (source is CachedSource) await source.downloadToSystemCache(id); |
458 return; | 452 return; |
459 } | 453 } |
460 | 454 |
461 var packageDir = p.join(packagesDir, id.name); | 455 var packagePath = p.join(packagesPath, id.name); |
462 if (entryExists(packageDir)) deleteEntry(packageDir); | 456 if (entryExists(packagePath)) deleteEntry(packagePath); |
463 await source.get(id, packageDir); | 457 await source.get(id, packagePath); |
464 } | 458 } |
465 | 459 |
466 /// Throws a [DataError] if the `.packages` file doesn't exist or if it's | 460 /// Throws a [DataError] if the `.packages` file doesn't exist or if it's |
467 /// out-of-date relative to the lockfile or the pubspec. | 461 /// out-of-date relative to the lockfile or the pubspec. |
468 void assertUpToDate() { | 462 void assertUpToDate() { |
469 if (_inMemory) return; | 463 if (_inMemory) return; |
470 | 464 |
471 if (!entryExists(lockFilePath)) { | 465 if (!entryExists(lockFilePath)) { |
472 dataError('No pubspec.lock file found, please run "pub get" first.'); | 466 dataError('No pubspec.lock file found, please run "pub get" first.'); |
473 } | 467 } |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
647 /// Saves a list of concrete package versions to the `pubspec.lock` file. | 641 /// Saves a list of concrete package versions to the `pubspec.lock` file. |
648 void _saveLockFile(SolveResult result) { | 642 void _saveLockFile(SolveResult result) { |
649 _lockFile = result.lockFile; | 643 _lockFile = result.lockFile; |
650 var lockFilePath = root.path('pubspec.lock'); | 644 var lockFilePath = root.path('pubspec.lock'); |
651 writeTextFile(lockFilePath, _lockFile.serialize(root.dir)); | 645 writeTextFile(lockFilePath, _lockFile.serialize(root.dir)); |
652 } | 646 } |
653 | 647 |
654 /// Creates a self-referential symlink in the `packages` directory that allows | 648 /// Creates a self-referential symlink in the `packages` directory that allows |
655 /// a package to import its own files using `package:`. | 649 /// a package to import its own files using `package:`. |
656 void _linkSelf() { | 650 void _linkSelf() { |
657 var linkPath = p.join(packagesDir, root.name); | 651 var linkPath = p.join(packagesPath, root.name); |
658 // Create the symlink if it doesn't exist. | 652 // Create the symlink if it doesn't exist. |
659 if (entryExists(linkPath)) return; | 653 if (entryExists(linkPath)) return; |
660 ensureDir(packagesDir); | 654 ensureDir(packagesPath); |
661 createPackageSymlink(root.name, root.dir, linkPath, | 655 createPackageSymlink(root.name, root.dir, linkPath, |
662 isSelfLink: true, relative: true); | 656 isSelfLink: true, relative: true); |
663 } | 657 } |
664 | 658 |
665 /// If [packageSymlinks] is true, add "packages" directories to the whitelist | 659 /// If [packagesDir] is true, add "packages" directories to the whitelist of |
666 /// of directories that may contain Dart entrypoints. | 660 /// directories that may contain Dart entrypoints. |
667 /// | 661 /// |
668 /// Otherwise, delete any "packages" directories in the whitelist of | 662 /// Otherwise, delete any "packages" directories in the whitelist of |
669 /// directories that may contain Dart entrypoints. | 663 /// directories that may contain Dart entrypoints. |
670 void _linkOrDeleteSecondaryPackageDirs() { | 664 void _linkOrDeleteSecondaryPackageDirs({bool packagesDir: false}) { |
671 // Only the main "bin" directory gets a "packages" directory, not its | 665 // Only the main "bin" directory gets a "packages" directory, not its |
672 // subdirectories. | 666 // subdirectories. |
673 var binDir = root.path('bin'); | 667 var binDir = root.path('bin'); |
674 if (dirExists(binDir)) _linkOrDeleteSecondaryPackageDir(binDir); | 668 if (dirExists(binDir)) { |
669 _linkOrDeleteSecondaryPackageDir(binDir, packagesDir: packagesDir); | |
670 } | |
675 | 671 |
676 // The others get "packages" directories in subdirectories too. | 672 // The others get "packages" directories in subdirectories too. |
677 for (var dir in ['benchmark', 'example', 'test', 'tool', 'web']) { | 673 for (var dir in ['benchmark', 'example', 'test', 'tool', 'web']) { |
678 _linkOrDeleteSecondaryPackageDirsRecursively(root.path(dir)); | 674 _linkOrDeleteSecondaryPackageDirsRecursively(root.path(dir), |
675 packagesDir: packagesDir); | |
679 } | 676 } |
680 } | 677 } |
681 | 678 |
682 /// If [packageSymlinks] is true, creates a symlink to the "packages" | 679 /// If [packagesDir] is true, creates a symlink to the "packages" directory in |
683 /// directory in [dir] and all its subdirectories. | 680 /// [dir] and all its subdirectories. |
684 /// | 681 /// |
685 /// Otherwise, deletes any "packages" directories in [dir] and all its | 682 /// Otherwise, deletes any "packages" directories in [dir] and all its |
686 /// subdirectories. | 683 /// subdirectories. |
687 void _linkOrDeleteSecondaryPackageDirsRecursively(String dir) { | 684 void _linkOrDeleteSecondaryPackageDirsRecursively(String dir, |
685 {bool packagesDir: false}) { | |
688 if (!dirExists(dir)) return; | 686 if (!dirExists(dir)) return; |
689 _linkOrDeleteSecondaryPackageDir(dir); | 687 _linkOrDeleteSecondaryPackageDir(dir, packagesDir: packagesDir); |
690 _listDirWithoutPackages(dir) | 688 for (var subdir in _listDirWithoutPackages(dir)) { |
691 .where(dirExists) | 689 if (!dirExists(subdir)) continue; |
692 .forEach(_linkOrDeleteSecondaryPackageDir); | 690 _linkOrDeleteSecondaryPackageDir(subdir, packagesDir: packagesDir); |
691 } | |
693 } | 692 } |
694 | 693 |
695 // TODO(nweiz): roll this into [listDir] in io.dart once issue 4775 is fixed. | 694 // TODO(nweiz): roll this into [listDir] in io.dart once issue 4775 is fixed. |
696 /// Recursively lists the contents of [dir], excluding hidden `.DS_Store` | 695 /// Recursively lists the contents of [dir], excluding hidden `.DS_Store` |
697 /// files and `package` files. | 696 /// files and `package` files. |
698 List<String> _listDirWithoutPackages(dir) { | 697 List<String> _listDirWithoutPackages(dir) { |
699 return listDir(dir).expand/*<String>*/((file) { | 698 return listDir(dir).expand/*<String>*/((file) { |
700 if (p.basename(file) == 'packages') return []; | 699 if (p.basename(file) == 'packages') return []; |
701 if (!dirExists(file)) return []; | 700 if (!dirExists(file)) return []; |
702 var fileAndSubfiles = [file]; | 701 var fileAndSubfiles = [file]; |
703 fileAndSubfiles.addAll(_listDirWithoutPackages(file)); | 702 fileAndSubfiles.addAll(_listDirWithoutPackages(file)); |
704 return fileAndSubfiles; | 703 return fileAndSubfiles; |
705 }); | 704 }); |
706 } | 705 } |
707 | 706 |
708 /// If [packageSymlinks] is true, creates a symlink to the "packages" | 707 /// If [packagesDir] is true, creates a symlink to the "packages" directory in |
709 /// directory in [dir]. | 708 /// [dir]. |
710 /// | 709 /// |
711 /// Otherwise, deletes a "packages" directories in [dir] if one exists. | 710 /// Otherwise, deletes a "packages" directories in [dir] if one exists. |
712 void _linkOrDeleteSecondaryPackageDir(String dir) { | 711 void _linkOrDeleteSecondaryPackageDir(String dir, {bool packagesDir: false}) { |
713 var symlink = p.join(dir, 'packages'); | 712 var symlink = p.join(dir, 'packages'); |
714 if (entryExists(symlink)) deleteEntry(symlink); | 713 if (entryExists(symlink)) deleteEntry(symlink); |
715 if (_packageSymlinks) createSymlink(packagesDir, symlink, relative: true); | 714 if (packagesDir) createSymlink(packagesPath, symlink, relative: true); |
716 } | 715 } |
717 } | 716 } |
OLD | NEW |