OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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:path/path.dart' as p; | 8 import 'package:path/path.dart' as p; |
9 import 'package:barback/barback.dart'; | 9 import 'package:barback/barback.dart'; |
10 import 'package:pub_semver/pub_semver.dart'; | 10 import 'package:pub_semver/pub_semver.dart'; |
11 | 11 |
12 import 'barback/asset_environment.dart'; | 12 import 'barback/asset_environment.dart'; |
13 import 'entrypoint.dart'; | 13 import 'entrypoint.dart'; |
14 import 'exceptions.dart'; | 14 import 'exceptions.dart'; |
15 import 'executable.dart' as exe; | 15 import 'executable.dart' as exe; |
16 import 'io.dart'; | 16 import 'io.dart'; |
17 import 'lock_file.dart'; | 17 import 'lock_file.dart'; |
18 import 'log.dart' as log; | 18 import 'log.dart' as log; |
19 import 'package.dart'; | 19 import 'package.dart'; |
20 import 'pubspec.dart'; | 20 import 'pubspec.dart'; |
21 import 'sdk.dart' as sdk; | 21 import 'sdk.dart' as sdk; |
22 import 'solver/version_solver.dart'; | 22 import 'solver/version_solver.dart'; |
23 import 'source/cached.dart'; | 23 import 'source/cached.dart'; |
24 import 'source/git.dart'; | |
25 import 'source/hosted.dart'; | |
26 import 'source/path.dart'; | |
27 import 'system_cache.dart'; | 24 import 'system_cache.dart'; |
28 import 'utils.dart'; | 25 import 'utils.dart'; |
29 | 26 |
30 /// Maintains the set of packages that have been globally activated. | 27 /// Maintains the set of packages that have been globally activated. |
31 /// | 28 /// |
32 /// These have been hand-chosen by the user to make their executables in bin/ | 29 /// These have been hand-chosen by the user to make their executables in bin/ |
33 /// available to the entire system. This lets them access them even when the | 30 /// available to the entire system. This lets them access them even when the |
34 /// current working directory is not inside another entrypoint package. | 31 /// current working directory is not inside another entrypoint package. |
35 /// | 32 /// |
36 /// Only one version of a given package name can be globally activated at a | 33 /// Only one version of a given package name can be globally activated at a |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 /// | 70 /// |
74 /// [executables] is the names of the executables that should have binstubs. | 71 /// [executables] is the names of the executables that should have binstubs. |
75 /// If `null`, all executables in the package will get binstubs. If empty, no | 72 /// If `null`, all executables in the package will get binstubs. If empty, no |
76 /// binstubs will be created. | 73 /// binstubs will be created. |
77 /// | 74 /// |
78 /// if [overwriteBinStubs] is `true`, any binstubs that collide with | 75 /// if [overwriteBinStubs] is `true`, any binstubs that collide with |
79 /// existing binstubs in other packages will be overwritten by this one's. | 76 /// existing binstubs in other packages will be overwritten by this one's. |
80 /// Otherwise, the previous ones will be preserved. | 77 /// Otherwise, the previous ones will be preserved. |
81 Future activateGit(String repo, List<String> executables, | 78 Future activateGit(String repo, List<String> executables, |
82 {bool overwriteBinStubs}) async { | 79 {bool overwriteBinStubs}) async { |
83 var source = cache.sources["git"] as GitSource; | 80 var name = await cache.git.getPackageNameFromRepo(repo); |
84 var name = await source.getPackageNameFromRepo(repo); | |
85 // Call this just to log what the current active package is, if any. | 81 // Call this just to log what the current active package is, if any. |
86 _describeActive(name); | 82 _describeActive(name); |
87 | 83 |
88 // TODO(nweiz): Add some special handling for git repos that contain path | 84 // TODO(nweiz): Add some special handling for git repos that contain path |
89 // dependencies. Their executables shouldn't be cached, and there should | 85 // dependencies. Their executables shouldn't be cached, and there should |
90 // be a mechanism for redoing dependency resolution if a path pubspec has | 86 // be a mechanism for redoing dependency resolution if a path pubspec has |
91 // changed (see also issue 20499). | 87 // changed (see also issue 20499). |
92 await _installInCache( | 88 await _installInCache( |
93 GitSource.refFor(name, repo).withConstraint(VersionConstraint.any), | 89 cache.git.source.refFor(name, repo) |
| 90 .withConstraint(VersionConstraint.any), |
94 executables, overwriteBinStubs: overwriteBinStubs); | 91 executables, overwriteBinStubs: overwriteBinStubs); |
95 } | 92 } |
96 | 93 |
97 /// Finds the latest version of the hosted package with [name] that matches | 94 /// Finds the latest version of the hosted package with [name] that matches |
98 /// [constraint] and makes it the active global version. | 95 /// [constraint] and makes it the active global version. |
99 /// | 96 /// |
100 /// [executables] is the names of the executables that should have binstubs. | 97 /// [executables] is the names of the executables that should have binstubs. |
101 /// If `null`, all executables in the package will get binstubs. If empty, no | 98 /// If `null`, all executables in the package will get binstubs. If empty, no |
102 /// binstubs will be created. | 99 /// binstubs will be created. |
103 /// | 100 /// |
104 /// if [overwriteBinStubs] is `true`, any binstubs that collide with | 101 /// if [overwriteBinStubs] is `true`, any binstubs that collide with |
105 /// existing binstubs in other packages will be overwritten by this one's. | 102 /// existing binstubs in other packages will be overwritten by this one's. |
106 /// Otherwise, the previous ones will be preserved. | 103 /// Otherwise, the previous ones will be preserved. |
107 Future activateHosted(String name, VersionConstraint constraint, | 104 Future activateHosted(String name, VersionConstraint constraint, |
108 List<String> executables, {bool overwriteBinStubs}) async { | 105 List<String> executables, {bool overwriteBinStubs}) async { |
109 _describeActive(name); | 106 _describeActive(name); |
110 await _installInCache(HostedSource.refFor(name).withConstraint(constraint), | 107 await _installInCache( |
111 executables, overwriteBinStubs: overwriteBinStubs); | 108 cache.hosted.source.refFor(name).withConstraint(constraint), |
| 109 executables, |
| 110 overwriteBinStubs: overwriteBinStubs); |
112 } | 111 } |
113 | 112 |
114 /// Makes the local package at [path] globally active. | 113 /// Makes the local package at [path] globally active. |
115 /// | 114 /// |
116 /// [executables] is the names of the executables that should have binstubs. | 115 /// [executables] is the names of the executables that should have binstubs. |
117 /// If `null`, all executables in the package will get binstubs. If empty, no | 116 /// If `null`, all executables in the package will get binstubs. If empty, no |
118 /// binstubs will be created. | 117 /// binstubs will be created. |
119 /// | 118 /// |
120 /// if [overwriteBinStubs] is `true`, any binstubs that collide with | 119 /// if [overwriteBinStubs] is `true`, any binstubs that collide with |
121 /// existing binstubs in other packages will be overwritten by this one's. | 120 /// existing binstubs in other packages will be overwritten by this one's. |
122 /// Otherwise, the previous ones will be preserved. | 121 /// Otherwise, the previous ones will be preserved. |
123 Future activatePath(String path, List<String> executables, | 122 Future activatePath(String path, List<String> executables, |
124 {bool overwriteBinStubs}) async { | 123 {bool overwriteBinStubs}) async { |
125 var entrypoint = new Entrypoint(path, cache, isGlobal: true); | 124 var entrypoint = new Entrypoint(path, cache, isGlobal: true); |
126 | 125 |
127 // Get the package's dependencies. | 126 // Get the package's dependencies. |
128 await entrypoint.acquireDependencies(SolveType.GET); | 127 await entrypoint.acquireDependencies(SolveType.GET); |
129 var name = entrypoint.root.name; | 128 var name = entrypoint.root.name; |
130 | 129 |
131 // Call this just to log what the current active package is, if any. | 130 // Call this just to log what the current active package is, if any. |
132 _describeActive(name); | 131 _describeActive(name); |
133 | 132 |
134 // Write a lockfile that points to the local package. | 133 // Write a lockfile that points to the local package. |
135 var fullPath = canonicalize(entrypoint.root.dir); | 134 var fullPath = canonicalize(entrypoint.root.dir); |
136 var id = PathSource.idFor(name, entrypoint.root.version, fullPath); | 135 var id = cache.path.source.idFor(name, entrypoint.root.version, fullPath); |
137 | 136 |
138 // TODO(rnystrom): Look in "bin" and display list of binaries that | 137 // TODO(rnystrom): Look in "bin" and display list of binaries that |
139 // user can run. | 138 // user can run. |
140 _writeLockFile(name, new LockFile([id], cache.sources)); | 139 _writeLockFile(name, new LockFile([id], cache.sources)); |
141 | 140 |
142 var binDir = p.join(_directory, name, 'bin'); | 141 var binDir = p.join(_directory, name, 'bin'); |
143 if (dirExists(binDir)) deleteEntry(binDir); | 142 if (dirExists(binDir)) deleteEntry(binDir); |
144 | 143 |
145 _updateBinStubs(entrypoint.root, executables, | 144 _updateBinStubs(entrypoint.root, executables, |
146 overwriteBinStubs: overwriteBinStubs); | 145 overwriteBinStubs: overwriteBinStubs); |
147 } | 146 } |
148 | 147 |
149 /// Installs the package [dep] and its dependencies into the system cache. | 148 /// Installs the package [dep] and its dependencies into the system cache. |
150 Future _installInCache(PackageDep dep, List<String> executables, | 149 Future _installInCache(PackageDep dep, List<String> executables, |
151 {bool overwriteBinStubs}) async { | 150 {bool overwriteBinStubs}) async { |
152 // Create a dummy package with just [dep] so we can do resolution on it. | 151 // Create a dummy package with just [dep] so we can do resolution on it. |
153 var root = new Package.inMemory(new Pubspec("pub global activate", | 152 var root = new Package.inMemory(new Pubspec("pub global activate", |
154 dependencies: [dep], sources: cache.sources)); | 153 dependencies: [dep], sources: cache.sources)); |
155 | 154 |
156 // Resolve it and download its dependencies. | 155 // Resolve it and download its dependencies. |
157 var result = await resolveVersions(SolveType.GET, cache.sources, root); | 156 var result = await resolveVersions(SolveType.GET, cache, root); |
158 if (!result.succeeded) { | 157 if (!result.succeeded) { |
159 // If the package specified by the user doesn't exist, we want to | 158 // If the package specified by the user doesn't exist, we want to |
160 // surface that as a [DataError] with the associated exit code. | 159 // surface that as a [DataError] with the associated exit code. |
161 if (result.error.package != dep.name) throw result.error; | 160 if (result.error.package != dep.name) throw result.error; |
162 if (result.error is NoVersionException) dataError(result.error.message); | 161 if (result.error is NoVersionException) dataError(result.error.message); |
163 throw result.error; | 162 throw result.error; |
164 } | 163 } |
165 result.showReport(SolveType.GET); | 164 result.showReport(SolveType.GET); |
166 | 165 |
167 // Make sure all of the dependencies are locally installed. | 166 // Make sure all of the dependencies are locally installed. |
168 await Future.wait(result.packages.map(_cacheDependency)); | 167 await Future.wait(result.packages.map(_cacheDependency)); |
169 | 168 |
170 // Load the package graph from [result] so we don't need to re-parse all | 169 // Load the package graph from [result] so we don't need to re-parse all |
171 // the pubspecs. | 170 // the pubspecs. |
172 var entrypoint = new Entrypoint.fromSolveResult(root, cache, result, | 171 var entrypoint = new Entrypoint.fromSolveResult(root, cache, result, |
173 isGlobal: true); | 172 isGlobal: true); |
174 var snapshots = await _precompileExecutables(entrypoint, dep.name); | 173 var snapshots = await _precompileExecutables(entrypoint, dep.name); |
175 | 174 |
176 var lockFile = result.lockFile; | 175 var lockFile = result.lockFile; |
177 _writeLockFile(dep.name, lockFile); | 176 _writeLockFile(dep.name, lockFile); |
178 writeTextFile(_getPackagesFilePath(dep.name), lockFile.packagesFile()); | 177 writeTextFile(_getPackagesFilePath(dep.name), lockFile.packagesFile(cache)); |
179 | 178 |
180 _updateBinStubs(entrypoint.packageGraph.packages[dep.name], executables, | 179 _updateBinStubs(entrypoint.packageGraph.packages[dep.name], executables, |
181 overwriteBinStubs: overwriteBinStubs, snapshots: snapshots); | 180 overwriteBinStubs: overwriteBinStubs, snapshots: snapshots); |
182 } | 181 } |
183 | 182 |
184 /// Precompiles the executables for [package] and saves them in the global | 183 /// Precompiles the executables for [package] and saves them in the global |
185 /// cache. | 184 /// cache. |
186 /// | 185 /// |
187 /// Returns a map from executable name to path for the snapshots that were | 186 /// Returns a map from executable name to path for the snapshots that were |
188 /// successfully precompiled. | 187 /// successfully precompiled. |
(...skipping 12 matching lines...) Expand all Loading... |
201 }); | 200 }); |
202 | 201 |
203 return environment.precompileExecutables(package, binDir); | 202 return environment.precompileExecutables(package, binDir); |
204 }); | 203 }); |
205 } | 204 } |
206 | 205 |
207 /// Downloads [id] into the system cache if it's a cached package. | 206 /// Downloads [id] into the system cache if it's a cached package. |
208 Future _cacheDependency(PackageId id) async { | 207 Future _cacheDependency(PackageId id) async { |
209 if (id.isRoot) return; | 208 if (id.isRoot) return; |
210 | 209 |
211 var source = cache.sources[id.source]; | 210 var source = cache.source(id.source); |
212 if (source is! CachedSource) return; | 211 if (source is! CachedSource) return; |
213 | 212 |
214 await source.downloadToSystemCache(id); | 213 await source.downloadToSystemCache(id); |
215 } | 214 } |
216 | 215 |
217 /// Finishes activating package [package] by saving [lockFile] in the cache. | 216 /// Finishes activating package [package] by saving [lockFile] in the cache. |
218 void _writeLockFile(String package, LockFile lockFile) { | 217 void _writeLockFile(String package, LockFile lockFile) { |
219 ensureDir(p.join(_directory, package)); | 218 ensureDir(p.join(_directory, package)); |
220 | 219 |
221 // TODO(nweiz): This cleans up Dart 1.6's old lockfile location. Remove it | 220 // TODO(nweiz): This cleans up Dart 1.6's old lockfile location. Remove it |
222 // when Dart 1.6 is old enough that we don't think anyone will have these | 221 // when Dart 1.6 is old enough that we don't think anyone will have these |
223 // lockfiles anymore (issue 20703). | 222 // lockfiles anymore (issue 20703). |
224 var oldPath = p.join(_directory, "$package.lock"); | 223 var oldPath = p.join(_directory, "$package.lock"); |
225 if (fileExists(oldPath)) deleteEntry(oldPath); | 224 if (fileExists(oldPath)) deleteEntry(oldPath); |
226 | 225 |
227 writeTextFile(_getLockFilePath(package), lockFile.serialize(cache.rootDir)); | 226 writeTextFile(_getLockFilePath(package), lockFile.serialize(cache.rootDir)); |
228 | 227 |
229 var id = lockFile.packages[package]; | 228 var id = lockFile.packages[package]; |
230 log.message('Activated ${_formatPackage(id)}.'); | 229 log.message('Activated ${_formatPackage(id)}.'); |
231 } | 230 } |
232 | 231 |
233 /// Shows the user the currently active package with [name], if any. | 232 /// Shows the user the currently active package with [name], if any. |
234 void _describeActive(String name) { | 233 void _describeActive(String name) { |
235 try { | 234 try { |
236 var lockFile = new LockFile.load(_getLockFilePath(name), cache.sources); | 235 var lockFile = new LockFile.load(_getLockFilePath(name), cache.sources); |
237 var id = lockFile.packages[name]; | 236 var id = lockFile.packages[name]; |
238 | 237 |
239 if (id.source == 'git') { | 238 if (id.source == 'git') { |
240 var url = GitSource.urlFromDescription(id.description); | 239 var url = cache.git.source.urlFromDescription(id.description); |
241 log.message('Package ${log.bold(name)} is currently active from Git ' | 240 log.message('Package ${log.bold(name)} is currently active from Git ' |
242 'repository "${url}".'); | 241 'repository "${url}".'); |
243 } else if (id.source == 'path') { | 242 } else if (id.source == 'path') { |
244 var path = PathSource.pathFromDescription(id.description); | 243 var path = cache.path.source.pathFromDescription(id.description); |
245 log.message('Package ${log.bold(name)} is currently active at path ' | 244 log.message('Package ${log.bold(name)} is currently active at path ' |
246 '"$path".'); | 245 '"$path".'); |
247 } else { | 246 } else { |
248 log.message('Package ${log.bold(name)} is currently active at version ' | 247 log.message('Package ${log.bold(name)} is currently active at version ' |
249 '${log.bold(id.version)}.'); | 248 '${log.bold(id.version)}.'); |
250 } | 249 } |
251 } on IOException { | 250 } on IOException { |
252 // If we couldn't read the lock file, it's not activated. | 251 // If we couldn't read the lock file, it's not activated. |
253 return null; | 252 return null; |
254 } | 253 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 ensureDir(p.dirname(lockFilePath)); | 295 ensureDir(p.dirname(lockFilePath)); |
297 new File(oldLockFilePath).renameSync(lockFilePath); | 296 new File(oldLockFilePath).renameSync(lockFilePath); |
298 } | 297 } |
299 | 298 |
300 // Remove the package itself from the lockfile. We put it in there so we | 299 // Remove the package itself from the lockfile. We put it in there so we |
301 // could find and load the [Package] object, but normally an entrypoint | 300 // could find and load the [Package] object, but normally an entrypoint |
302 // doesn't expect to be in its own lockfile. | 301 // doesn't expect to be in its own lockfile. |
303 var id = lockFile.packages[name]; | 302 var id = lockFile.packages[name]; |
304 lockFile = lockFile.removePackage(name); | 303 lockFile = lockFile.removePackage(name); |
305 | 304 |
306 var source = cache.sources[id.source]; | 305 var source = cache.source(id.source); |
307 var entrypoint; | 306 var entrypoint; |
308 if (source is CachedSource) { | 307 if (source is CachedSource) { |
309 // For cached sources, the package itself is in the cache and the | 308 // For cached sources, the package itself is in the cache and the |
310 // lockfile is the one we just loaded. | 309 // lockfile is the one we just loaded. |
311 entrypoint = new Entrypoint.inMemory( | 310 entrypoint = new Entrypoint.inMemory( |
312 cache.sources.load(id), lockFile, cache, isGlobal: true); | 311 cache.load(id), lockFile, cache, isGlobal: true); |
313 } else { | 312 } else { |
314 // For uncached sources (i.e. path), the ID just points to the real | 313 // For uncached sources (i.e. path), the ID just points to the real |
315 // directory for the package. | 314 // directory for the package. |
316 assert(id.source == "path"); | 315 assert(id.source == "path"); |
317 entrypoint = new Entrypoint( | 316 entrypoint = new Entrypoint( |
318 PathSource.pathFromDescription(id.description), cache, | 317 cache.path.source.pathFromDescription(id.description), cache, |
319 isGlobal: true); | 318 isGlobal: true); |
320 } | 319 } |
321 | 320 |
322 if (entrypoint.root.pubspec.environment.sdkVersion.allows(sdk.version)) { | 321 if (entrypoint.root.pubspec.environment.sdkVersion.allows(sdk.version)) { |
323 return entrypoint; | 322 return entrypoint; |
324 } | 323 } |
325 | 324 |
326 dataError("${log.bold(name)} ${entrypoint.root.version} doesn't support " | 325 dataError("${log.bold(name)} ${entrypoint.root.version} doesn't support " |
327 "Dart ${sdk.version}."); | 326 "Dart ${sdk.version}."); |
328 } | 327 } |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 throw new FormatException("Pubspec for activated package $name didn't " | 400 throw new FormatException("Pubspec for activated package $name didn't " |
402 "contain an entry for itself."); | 401 "contain an entry for itself."); |
403 } | 402 } |
404 | 403 |
405 return id; | 404 return id; |
406 } | 405 } |
407 | 406 |
408 /// Returns formatted string representing the package [id]. | 407 /// Returns formatted string representing the package [id]. |
409 String _formatPackage(PackageId id) { | 408 String _formatPackage(PackageId id) { |
410 if (id.source == 'git') { | 409 if (id.source == 'git') { |
411 var url = GitSource.urlFromDescription(id.description); | 410 var url = cache.sources.git.urlFromDescription(id.description); |
412 return '${log.bold(id.name)} ${id.version} from Git repository "$url"'; | 411 return '${log.bold(id.name)} ${id.version} from Git repository "$url"'; |
413 } else if (id.source == 'path') { | 412 } else if (id.source == 'path') { |
414 var path = PathSource.pathFromDescription(id.description); | 413 var path = cache.sources.path.pathFromDescription(id.description); |
415 return '${log.bold(id.name)} ${id.version} at path "$path"'; | 414 return '${log.bold(id.name)} ${id.version} at path "$path"'; |
416 } else { | 415 } else { |
417 return '${log.bold(id.name)} ${id.version}'; | 416 return '${log.bold(id.name)} ${id.version}'; |
418 } | 417 } |
419 } | 418 } |
420 | 419 |
421 /// Repairs any corrupted globally-activated packages and their binstubs. | 420 /// Repairs any corrupted globally-activated packages and their binstubs. |
422 /// | 421 /// |
423 /// Returns a pair of two lists of strings. The first indicates which packages | 422 /// Returns a pair of two lists of strings. The first indicates which packages |
424 /// were successfully re-activated; the second indicates which failed. | 423 /// were successfully re-activated; the second indicates which failed. |
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 } | 787 } |
789 | 788 |
790 /// Returns the value of the property named [name] in the bin stub script | 789 /// Returns the value of the property named [name] in the bin stub script |
791 /// [source]. | 790 /// [source]. |
792 String _binStubProperty(String source, String name) { | 791 String _binStubProperty(String source, String name) { |
793 var pattern = new RegExp(quoteRegExp(name) + r": ([a-zA-Z0-9_-]+)"); | 792 var pattern = new RegExp(quoteRegExp(name) + r": ([a-zA-Z0-9_-]+)"); |
794 var match = pattern.firstMatch(source); | 793 var match = pattern.firstMatch(source); |
795 return match == null ? null : match[1]; | 794 return match == null ? null : match[1]; |
796 } | 795 } |
797 } | 796 } |
OLD | NEW |