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 |