Chromium Code Reviews| 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 library pub.entrypoint; | 5 library pub.entrypoint; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:path/path.dart' as path; | 9 import 'package:path/path.dart' as path; |
| 10 | 10 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 34 /// contains a reusable library may not be the entrypoint when used by an app, | 34 /// contains a reusable library may not be the entrypoint when used by an app, |
| 35 /// but may be the entrypoint when you're running its tests. | 35 /// but may be the entrypoint when you're running its tests. |
| 36 class Entrypoint { | 36 class Entrypoint { |
| 37 /// The root package this entrypoint is associated with. | 37 /// The root package this entrypoint is associated with. |
| 38 final Package root; | 38 final Package root; |
| 39 | 39 |
| 40 /// The system-wide cache which caches packages that need to be fetched over | 40 /// The system-wide cache which caches packages that need to be fetched over |
| 41 /// the network. | 41 /// the network. |
| 42 final SystemCache cache; | 42 final SystemCache cache; |
| 43 | 43 |
| 44 /// Packages which are either currently being asynchronously installed to the | 44 /// Packages which are either currently being asynchronously downloaded to the |
| 45 /// directory, or have already been installed. | 45 /// directory, or have already been downloaded. |
|
nweiz
2013/10/07 21:25:15
It seems weird that the docstring says "download"
Bob Nystrom
2013/10/07 22:32:25
Yeah. Reworded.
| |
| 46 final _installs = new Map<PackageId, Future<PackageId>>(); | 46 final _pendingGets = new Map<PackageId, Future<PackageId>>(); |
| 47 | 47 |
| 48 /// Loads the entrypoint from a package at [rootDir]. | 48 /// Loads the entrypoint from a package at [rootDir]. |
| 49 Entrypoint(String rootDir, SystemCache cache) | 49 Entrypoint(String rootDir, SystemCache cache) |
| 50 : root = new Package.load(null, rootDir, cache.sources), | 50 : root = new Package.load(null, rootDir, cache.sources), |
| 51 cache = cache; | 51 cache = cache; |
| 52 | 52 |
| 53 // TODO(rnystrom): Make this path configurable. | 53 // TODO(rnystrom): Make this path configurable. |
| 54 /// The path to the entrypoint's "packages" directory. | 54 /// The path to the entrypoint's "packages" directory. |
| 55 String get packagesDir => path.join(root.dir, 'packages'); | 55 String get packagesDir => path.join(root.dir, 'packages'); |
| 56 | 56 |
| 57 /// `true` if the entrypoint package currently has a lock file. | 57 /// `true` if the entrypoint package currently has a lock file. |
| 58 bool get lockFileExists => entryExists(lockFilePath); | 58 bool get lockFileExists => entryExists(lockFilePath); |
| 59 | 59 |
| 60 /// The path to the entrypoint package's lockfile. | 60 /// The path to the entrypoint package's lockfile. |
| 61 String get lockFilePath => path.join(root.dir, 'pubspec.lock'); | 61 String get lockFilePath => path.join(root.dir, 'pubspec.lock'); |
| 62 | 62 |
| 63 /// Ensures that the package identified by [id] is installed to the directory. | 63 /// Gets package [id] and makes it available for use by this entrypoint. |
| 64 /// Returns the resolved [PackageId]. | |
| 65 /// | 64 /// |
| 66 /// If this completes successfully, the package is guaranteed to be importable | 65 /// If this completes successfully, the package is guaranteed to be importable |
| 67 /// using the `package:` scheme. | 66 /// using the `package:` scheme. Returns the resolved [PackageId]. |
| 68 /// | 67 /// |
| 69 /// This will automatically install the package to the system-wide cache as | 68 /// This automatically downloads the package to the system-wide cache as well |
| 70 /// well if it requires network access to retrieve (specifically, if the | 69 /// if it requires network access to retrieve (specifically, if the package's |
| 71 /// package's source has [shouldCache] as `true`). | 70 /// source has [shouldCache] as `true`). |
| 72 /// | 71 /// |
| 73 /// See also [installDependencies]. | 72 /// See also [getDependencies]. |
| 74 Future<PackageId> install(PackageId id) { | 73 Future<PackageId> get(PackageId id) { |
| 75 var pending = _installs[id]; | 74 var pending = _pendingGets[id]; |
| 76 if (pending != null) return pending; | 75 if (pending != null) return pending; |
| 77 | 76 |
| 78 var packageDir = path.join(packagesDir, id.name); | 77 var packageDir = path.join(packagesDir, id.name); |
| 79 var source; | 78 var source; |
| 80 | 79 |
| 81 var future = new Future.sync(() { | 80 var future = new Future.sync(() { |
| 82 ensureDir(path.dirname(packageDir)); | 81 ensureDir(path.dirname(packageDir)); |
| 83 | 82 |
| 84 if (entryExists(packageDir)) { | 83 if (entryExists(packageDir)) { |
| 85 // TODO(nweiz): figure out when to actually delete the directory, and | 84 // TODO(nweiz): figure out when to actually delete the directory, and |
| 86 // when we can just re-use the existing symlink. | 85 // when we can just re-use the existing symlink. |
| 87 log.fine("Deleting package directory for ${id.name} before install."); | 86 log.fine("Deleting package directory for ${id.name} before get."); |
| 88 deleteEntry(packageDir); | 87 deleteEntry(packageDir); |
| 89 } | 88 } |
| 90 | 89 |
| 91 source = cache.sources[id.source]; | 90 source = cache.sources[id.source]; |
| 92 | 91 |
| 93 if (source.shouldCache) { | 92 if (source.shouldCache) { |
| 94 return cache.install(id).then( | 93 return cache.download(id).then( |
| 95 (pkg) => createPackageSymlink(id.name, pkg.dir, packageDir)); | 94 (pkg) => createPackageSymlink(id.name, pkg.dir, packageDir)); |
| 96 } else { | 95 } else { |
| 97 return source.install(id, packageDir).then((found) { | 96 return source.get(id, packageDir).then((found) { |
| 98 if (found) return null; | 97 if (found) return null; |
| 99 fail('Package ${id.name} not found in source "${id.source}".'); | 98 fail('Package ${id.name} not found in source "${id.source}".'); |
| 100 }); | 99 }); |
| 101 } | 100 } |
| 102 }).then((_) => source.resolveId(id)); | 101 }).then((_) => source.resolveId(id)); |
| 103 | 102 |
| 104 _installs[id] = future; | 103 _pendingGets[id] = future; |
| 105 | 104 |
| 106 return future; | 105 return future; |
| 107 } | 106 } |
| 108 | 107 |
| 109 /// Installs all dependencies of the [root] package to its "packages" | 108 /// Gets all dependencies of the [root] package and places them in its |
|
nweiz
2013/10/07 21:25:15
"Gets" -> "Downloads", since placing them in the "
Bob Nystrom
2013/10/07 22:32:25
I've tried to have "download" consistently mean "p
nweiz
2013/10/07 23:23:08
I feel like if you're going to use "get" here you
Bob Nystrom
2013/10/08 21:15:03
Done. See: https://codereview.chromium.org/2628400
| |
| 110 /// directory, respecting the [LockFile] if present. Returns a [Future] that | 109 /// "packages" directory, respecting the [LockFile] if present. Returns a |
| 111 /// completes when all dependencies are installed. | 110 /// [Future] that completes when all dependencies are available. |
| 112 Future installDependencies() { | 111 Future getDependencies() { |
| 113 return new Future.sync(() { | 112 return new Future.sync(() { |
| 114 return resolveVersions(cache.sources, root, lockFile: loadLockFile()); | 113 return resolveVersions(cache.sources, root, lockFile: loadLockFile()); |
| 115 }).then(_installDependencies); | 114 }).then(_getDependencies); |
| 116 } | 115 } |
| 117 | 116 |
| 118 /// Installs the latest available versions of all dependencies of the [root] | 117 /// Gets the latest available versions of all dependencies of the [root] |
| 119 /// package to its "package" directory, writing a new [LockFile]. Returns a | 118 /// package and places them in its "package" directory, writing a new |
| 120 /// [Future] that completes when all dependencies are installed. | 119 /// [LockFile]. Returns a [Future] that completes when all dependencies are |
| 121 Future updateAllDependencies() { | 120 /// available. |
| 122 return resolveVersions(cache.sources, root).then(_installDependencies); | 121 Future upgradeAllDependencies() { |
| 122 return resolveVersions(cache.sources, root).then(_getDependencies); | |
| 123 } | 123 } |
| 124 | 124 |
| 125 /// Installs the latest available versions of [dependencies], while leaving | 125 /// Gets the latest available versions of [dependencies], while leaving |
| 126 /// other dependencies as specified by the [LockFile] if possible. Returns a | 126 /// other dependencies as specified by the [LockFile] if possible. Returns a |
| 127 /// [Future] that completes when all dependencies are installed. | 127 /// [Future] that completes when all dependencies are available. |
| 128 Future updateDependencies(List<String> dependencies) { | 128 Future upgradeDependencies(List<String> dependencies) { |
| 129 return new Future.sync(() { | 129 return new Future.sync(() { |
| 130 return resolveVersions(cache.sources, root, | 130 return resolveVersions(cache.sources, root, |
| 131 lockFile: loadLockFile(), useLatest: dependencies); | 131 lockFile: loadLockFile(), useLatest: dependencies); |
| 132 }).then(_installDependencies); | 132 }).then(_getDependencies); |
| 133 } | 133 } |
| 134 | 134 |
| 135 /// Removes the old packages directory, installs all dependencies listed in | 135 /// Removes the old packages directory, gets all dependencies listed in |
| 136 /// [result], and writes a [LockFile]. | 136 /// [result], and writes a [LockFile]. |
| 137 Future _installDependencies(SolveResult result) { | 137 Future _getDependencies(SolveResult result) { |
| 138 return new Future.sync(() { | 138 return new Future.sync(() { |
| 139 if (!result.succeeded) throw result.error; | 139 if (!result.succeeded) throw result.error; |
| 140 | 140 |
| 141 cleanDir(packagesDir); | 141 cleanDir(packagesDir); |
| 142 return Future.wait(result.packages.map((id) { | 142 return Future.wait(result.packages.map((id) { |
| 143 if (id.isRoot) return new Future.value(id); | 143 if (id.isRoot) return new Future.value(id); |
| 144 return install(id); | 144 return get(id); |
| 145 }).toList()); | 145 }).toList()); |
| 146 }).then((ids) { | 146 }).then((ids) { |
| 147 _saveLockFile(ids); | 147 _saveLockFile(ids); |
| 148 _installSelfReference(); | 148 _linkSelf(); |
| 149 _linkSecondaryPackageDirs(); | 149 _linkSecondaryPackageDirs(); |
| 150 }); | 150 }); |
| 151 } | 151 } |
| 152 | 152 |
| 153 /// Loads the list of concrete package versions from the `pubspec.lock`, if it | 153 /// Loads the list of concrete package versions from the `pubspec.lock`, if it |
| 154 /// exists. If it doesn't, this completes to an empty [LockFile]. | 154 /// exists. If it doesn't, this completes to an empty [LockFile]. |
| 155 LockFile loadLockFile() { | 155 LockFile loadLockFile() { |
| 156 if (!lockFileExists) return new LockFile.empty(); | 156 if (!lockFileExists) return new LockFile.empty(); |
| 157 return new LockFile.load(lockFilePath, cache.sources); | 157 return new LockFile.load(lockFilePath, cache.sources); |
| 158 } | 158 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 208 void _saveLockFile(List<PackageId> packageIds) { | 208 void _saveLockFile(List<PackageId> packageIds) { |
| 209 var lockFile = new LockFile.empty(); | 209 var lockFile = new LockFile.empty(); |
| 210 for (var id in packageIds) { | 210 for (var id in packageIds) { |
| 211 if (!id.isRoot) lockFile.packages[id.name] = id; | 211 if (!id.isRoot) lockFile.packages[id.name] = id; |
| 212 } | 212 } |
| 213 | 213 |
| 214 var lockFilePath = path.join(root.dir, 'pubspec.lock'); | 214 var lockFilePath = path.join(root.dir, 'pubspec.lock'); |
| 215 writeTextFile(lockFilePath, lockFile.serialize()); | 215 writeTextFile(lockFilePath, lockFile.serialize()); |
| 216 } | 216 } |
| 217 | 217 |
| 218 /// Installs a self-referential symlink in the `packages` directory that will | 218 /// Creates a self-referential symlink in the `packages` directory that allows |
| 219 /// allow a package to import its own files using `package:`. | 219 /// a package to import its own files using `package:`. |
| 220 void _installSelfReference() { | 220 void _linkSelf() { |
| 221 var linkPath = path.join(packagesDir, root.name); | 221 var linkPath = path.join(packagesDir, root.name); |
| 222 // Create the symlink if it doesn't exist. | 222 // Create the symlink if it doesn't exist. |
| 223 if (entryExists(linkPath)) return; | 223 if (entryExists(linkPath)) return; |
| 224 ensureDir(packagesDir); | 224 ensureDir(packagesDir); |
| 225 createPackageSymlink(root.name, root.dir, linkPath, | 225 createPackageSymlink(root.name, root.dir, linkPath, |
| 226 isSelfLink: true, relative: true); | 226 isSelfLink: true, relative: true); |
| 227 } | 227 } |
| 228 | 228 |
| 229 /// Add "packages" directories to the whitelist of directories that may | 229 /// Add "packages" directories to the whitelist of directories that may |
| 230 /// contain Dart entrypoints. | 230 /// contain Dart entrypoints. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 313 // Skip directories and broken symlinks. | 313 // Skip directories and broken symlinks. |
| 314 if (!fileExists(file)) return false; | 314 if (!fileExists(file)) return false; |
| 315 | 315 |
| 316 var relative = path.relative(file, from: beneath); | 316 var relative = path.relative(file, from: beneath); |
| 317 if (_BLACKLISTED_FILES.contains(path.basename(relative))) return false; | 317 if (_BLACKLISTED_FILES.contains(path.basename(relative))) return false; |
| 318 return !path.split(relative).any(_BLACKLISTED_DIRS.contains); | 318 return !path.split(relative).any(_BLACKLISTED_DIRS.contains); |
| 319 }).toList(); | 319 }).toList(); |
| 320 }); | 320 }); |
| 321 } | 321 } |
| 322 } | 322 } |
| OLD | NEW |