Index: sdk/lib/_internal/pub_generated/lib/src/global_packages.dart |
diff --git a/sdk/lib/_internal/pub_generated/lib/src/global_packages.dart b/sdk/lib/_internal/pub_generated/lib/src/global_packages.dart |
index 65b22690603633f60e6a43501397fd2b875c19c2..6eb66cd3bd9712aaed8f7e95af6ff16eabc616c1 100644 |
--- a/sdk/lib/_internal/pub_generated/lib/src/global_packages.dart |
+++ b/sdk/lib/_internal/pub_generated/lib/src/global_packages.dart |
@@ -1,9 +1,16 @@ |
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
library pub.global_packages; |
+ |
import 'dart:async'; |
import 'dart:io'; |
+ |
import 'package:path/path.dart' as p; |
import 'package:barback/barback.dart'; |
import 'package:pub_semver/pub_semver.dart'; |
+ |
import 'barback/asset_environment.dart'; |
import 'entrypoint.dart'; |
import 'executable.dart' as exe; |
@@ -19,12 +26,62 @@ import 'source/git.dart'; |
import 'source/path.dart'; |
import 'system_cache.dart'; |
import 'utils.dart'; |
+ |
+/// Matches the package name that a binstub was created for inside the contents |
+/// of the shell script. |
final _binStubPackagePattern = new RegExp(r"Package: ([a-zA-Z0-9_-]+)"); |
+ |
+/// Maintains the set of packages that have been globally activated. |
+/// |
+/// These have been hand-chosen by the user to make their executables in bin/ |
+/// available to the entire system. This lets them access them even when the |
+/// current working directory is not inside another entrypoint package. |
+/// |
+/// Only one version of a given package name can be globally activated at a |
+/// time. Activating a different version of a package will deactivate the |
+/// previous one. |
+/// |
+/// This handles packages from uncached and cached sources a little differently. |
+/// For a cached source, the package is physically in the user's pub cache and |
+/// we don't want to mess with it by putting a lockfile in there. Instead, when |
+/// we activate the package, we create a full lockfile and put it in the |
+/// "global_packages" directory. It's named "<package>.lock". Unlike a normal |
+/// lockfile, it also contains an entry for the root package itself, so that we |
+/// know the version and description that was activated. |
+/// |
+/// Uncached packages (i.e. "path" packages) are somewhere else on the user's |
+/// local file system and can have a lockfile directly in place. (And, in fact, |
+/// we want to ensure we honor the user's lockfile there.) To activate it, we |
+/// just need to know where that package directory is. For that, we create a |
+/// lockfile that *only* contains the root package's [PackageId] -- basically |
+/// just the path to the directory where the real lockfile lives. |
class GlobalPackages { |
+ /// The [SystemCache] containing the global packages. |
final SystemCache cache; |
+ |
+ /// The directory where the lockfiles for activated packages are stored. |
String get _directory => p.join(cache.rootDir, "global_packages"); |
+ |
+ /// The directory where binstubs for global package executables are stored. |
String get _binStubDir => p.join(cache.rootDir, "bin"); |
+ |
+ /// Creates a new global package registry backed by the given directory on |
+ /// the user's file system. |
+ /// |
+ /// The directory may not physically exist yet. If not, this will create it |
+ /// when needed. |
GlobalPackages(this.cache); |
+ |
+ /// Caches the package located in the Git repository [repo] and makes it the |
+ /// active global version. |
+ /// |
+ /// [executables] is the names of the executables that should have binstubs. |
+ /// If `null`, all executables in the package will get binstubs. If empty, no |
+ /// binstubs will be created. |
+ /// |
+ /// if [overwriteBinStubs] is `true`, any binstubs that collide with |
+ /// existing binstubs in other packages will be overwritten by this one's. |
+ /// Otherwise, the previous ones will be preserved. |
Future activateGit(String repo, List<String> executables, |
{bool overwriteBinStubs}) { |
final completer0 = new Completer(); |
@@ -41,25 +98,32 @@ class GlobalPackages { |
overwriteBinStubs: overwriteBinStubs).then((x1) { |
try { |
x1; |
- completer0.complete(null); |
- } catch (e1) { |
- completer0.completeError(e1); |
+ completer0.complete(); |
+ } catch (e0, s0) { |
+ completer0.completeError(e0, s0); |
} |
- }, onError: (e2) { |
- completer0.completeError(e2); |
- }); |
- } catch (e0) { |
- completer0.completeError(e0); |
+ }, onError: completer0.completeError); |
+ } catch (e1, s1) { |
+ completer0.completeError(e1, s1); |
} |
- }, onError: (e3) { |
- completer0.completeError(e3); |
- }); |
- } catch (e4) { |
- completer0.completeError(e4); |
+ }, onError: completer0.completeError); |
+ } catch (e, s) { |
+ completer0.completeError(e, s); |
} |
}); |
return completer0.future; |
} |
+ |
+ /// Finds the latest version of the hosted package with [name] that matches |
+ /// [constraint] and makes it the active global version. |
+ /// |
+ /// [executables] is the names of the executables that should have binstubs. |
+ /// If `null`, all executables in the package will get binstubs. If empty, no |
+ /// binstubs will be created. |
+ /// |
+ /// if [overwriteBinStubs] is `true`, any binstubs that collide with |
+ /// existing binstubs in other packages will be overwritten by this one's. |
+ /// Otherwise, the previous ones will be preserved. |
Future activateHosted(String name, VersionConstraint constraint, |
List<String> executables, {bool overwriteBinStubs}) { |
final completer0 = new Completer(); |
@@ -72,19 +136,27 @@ class GlobalPackages { |
overwriteBinStubs: overwriteBinStubs).then((x0) { |
try { |
x0; |
- completer0.complete(null); |
- } catch (e0) { |
- completer0.completeError(e0); |
+ completer0.complete(); |
+ } catch (e0, s0) { |
+ completer0.completeError(e0, s0); |
} |
- }, onError: (e1) { |
- completer0.completeError(e1); |
- }); |
- } catch (e2) { |
- completer0.completeError(e2); |
+ }, onError: completer0.completeError); |
+ } catch (e, s) { |
+ completer0.completeError(e, s); |
} |
}); |
return completer0.future; |
} |
+ |
+ /// Makes the local package at [path] globally active. |
+ /// |
+ /// [executables] is the names of the executables that should have binstubs. |
+ /// If `null`, all executables in the package will get binstubs. If empty, no |
+ /// binstubs will be created. |
+ /// |
+ /// if [overwriteBinStubs] is `true`, any binstubs that collide with |
+ /// existing binstubs in other packages will be overwritten by this one's. |
+ /// Otherwise, the previous ones will be preserved. |
Future activatePath(String path, List<String> executables, |
{bool overwriteBinStubs}) { |
final completer0 = new Completer(); |
@@ -109,7 +181,7 @@ class GlobalPackages { |
entrypoint.root, |
executables, |
overwriteBinStubs: overwriteBinStubs); |
- completer0.complete(null); |
+ completer0.complete(); |
} |
if (dirExists(binDir)) { |
deleteEntry(binDir); |
@@ -117,18 +189,18 @@ class GlobalPackages { |
} else { |
join0(); |
} |
- } catch (e0) { |
- completer0.completeError(e0); |
+ } catch (e0, s0) { |
+ completer0.completeError(e0, s0); |
} |
- }, onError: (e1) { |
- completer0.completeError(e1); |
- }); |
- } catch (e2) { |
- completer0.completeError(e2); |
+ }, onError: completer0.completeError); |
+ } catch (e, s) { |
+ completer0.completeError(e, s); |
} |
}); |
return completer0.future; |
} |
+ |
+ /// Installs the package [dep] and its dependencies into the system cache. |
Future _installInCache(PackageDep dep, List<String> executables, |
{bool overwriteBinStubs}) { |
final completer0 = new Completer(); |
@@ -166,30 +238,25 @@ class GlobalPackages { |
executables, |
overwriteBinStubs: overwriteBinStubs, |
snapshots: snapshots); |
- completer0.complete(null); |
- } catch (e3) { |
- completer0.completeError(e3); |
+ completer0.complete(); |
+ } catch (e0, s0) { |
+ completer0.completeError(e0, s0); |
} |
- }, onError: (e4) { |
- completer0.completeError(e4); |
- }); |
- } catch (e2) { |
- completer0.completeError(e2); |
+ }, onError: completer0.completeError); |
+ } catch (e1, s1) { |
+ completer0.completeError(e1, s1); |
} |
- }, onError: (e5) { |
- completer0.completeError(e5); |
- }); |
- } catch (e1) { |
- completer0.completeError(e1); |
+ }, onError: completer0.completeError); |
+ } catch (e2, s2) { |
+ completer0.completeError(e2, s2); |
} |
- }, onError: (e6) { |
- completer0.completeError(e6); |
- }); |
+ }, onError: completer0.completeError); |
} |
if (!result.succeeded) { |
join1() { |
join2() { |
- completer0.completeError(result.error); |
+ throw result.error; |
+ join0(); |
} |
if (result.error is NoVersionException) { |
dataError(result.error.message); |
@@ -199,25 +266,30 @@ class GlobalPackages { |
} |
} |
if (result.error.package != dep.name) { |
- completer0.completeError(result.error); |
+ throw result.error; |
+ join1(); |
} else { |
join1(); |
} |
} else { |
join0(); |
} |
- } catch (e0) { |
- completer0.completeError(e0); |
+ } catch (e3, s3) { |
+ completer0.completeError(e3, s3); |
} |
- }, onError: (e7) { |
- completer0.completeError(e7); |
- }); |
- } catch (e8) { |
- completer0.completeError(e8); |
+ }, onError: completer0.completeError); |
+ } catch (e, s) { |
+ completer0.completeError(e, s); |
} |
}); |
return completer0.future; |
} |
+ |
+ /// Precompiles the executables for [package] and saves them in the global |
+ /// cache. |
+ /// |
+ /// Returns a map from executable name to path for the snapshots that were |
+ /// successfully precompiled. |
Future<Map<String, String>> _precompileExecutables(Entrypoint entrypoint, |
String package) { |
return log.progress("Precompiling executables", () { |
@@ -241,25 +313,25 @@ class GlobalPackages { |
})); |
completer0.complete( |
environment.precompileExecutables(package, binDir)); |
- } catch (e1) { |
- completer0.completeError(e1); |
+ } catch (e0, s0) { |
+ completer0.completeError(e0, s0); |
} |
- }, onError: (e2) { |
- completer0.completeError(e2); |
- }); |
- } catch (e0) { |
- completer0.completeError(e0); |
+ }, onError: completer0.completeError); |
+ } catch (e1, s1) { |
+ completer0.completeError(e1, s1); |
} |
- }, onError: (e3) { |
- completer0.completeError(e3); |
- }); |
- } catch (e4) { |
- completer0.completeError(e4); |
+ }, onError: completer0.completeError); |
+ } catch (e, s) { |
+ completer0.completeError(e, s); |
} |
}); |
return completer0.future; |
}); |
} |
+ |
+ /// Downloads [id] into the system cache if it's a cached package. |
+ /// |
+ /// Returns the resolved [PackageId] for [id]. |
Future<PackageId> _cacheDependency(PackageId id) { |
final completer0 = new Completer(); |
scheduleMicrotask(() { |
@@ -273,35 +345,44 @@ class GlobalPackages { |
try { |
x0; |
join0(); |
- } catch (e0) { |
- completer0.completeError(e0); |
+ } catch (e0, s0) { |
+ completer0.completeError(e0, s0); |
} |
- }, onError: (e1) { |
- completer0.completeError(e1); |
- }); |
+ }, onError: completer0.completeError); |
} else { |
join0(); |
} |
- } catch (e2) { |
- completer0.completeError(e2); |
+ } catch (e, s) { |
+ completer0.completeError(e, s); |
} |
}); |
return completer0.future; |
} |
+ |
+ /// Finishes activating package [package] by saving [lockFile] in the cache. |
void _writeLockFile(String package, LockFile lockFile) { |
ensureDir(p.join(_directory, package)); |
+ |
+ // TODO(nweiz): This cleans up Dart 1.6's old lockfile location. Remove it |
+ // when Dart 1.6 is old enough that we don't think anyone will have these |
+ // lockfiles anymore (issue 20703). |
var oldPath = p.join(_directory, "$package.lock"); |
if (fileExists(oldPath)) deleteEntry(oldPath); |
+ |
writeTextFile( |
_getLockFilePath(package), |
lockFile.serialize(cache.rootDir, cache.sources)); |
+ |
var id = lockFile.packages[package]; |
log.message('Activated ${_formatPackage(id)}.'); |
} |
+ |
+ /// Shows the user the currently active package with [name], if any. |
void _describeActive(String name) { |
try { |
var lockFile = new LockFile.load(_getLockFilePath(name), cache.sources); |
var id = lockFile.packages[name]; |
+ |
if (id.source == 'git') { |
var url = GitSource.urlFromDescription(id.description); |
log.message( |
@@ -317,20 +398,35 @@ class GlobalPackages { |
'${log.bold(id.version)}.'); |
} |
} on IOException catch (error) { |
+ // If we couldn't read the lock file, it's not activated. |
return null; |
} |
} |
+ |
+ /// Deactivates a previously-activated package named [name]. |
+ /// |
+ /// Returns `false` if no package with [name] was currently active. |
bool deactivate(String name) { |
var dir = p.join(_directory, name); |
if (!dirExists(dir)) return false; |
+ |
_deleteBinStubs(name); |
+ |
var lockFile = new LockFile.load(_getLockFilePath(name), cache.sources); |
var id = lockFile.packages[name]; |
log.message('Deactivated package ${_formatPackage(id)}.'); |
+ |
deleteEntry(dir); |
+ |
return true; |
} |
+ |
+ /// Finds the active package with [name]. |
+ /// |
+ /// Returns an [Entrypoint] loaded with the active package if found. |
Future<Entrypoint> find(String name) { |
+ // TODO(rnystrom): Use async/await here when on __ catch is supported. |
+ // See: https://github.com/dart-lang/async_await/issues/27 |
return new Future.sync(() { |
var lockFilePath = _getLockFilePath(name); |
var lockFile; |
@@ -339,31 +435,57 @@ class GlobalPackages { |
} on IOException catch (error) { |
var oldLockFilePath = p.join(_directory, '$name.lock'); |
try { |
+ // TODO(nweiz): This looks for Dart 1.6's old lockfile location. |
+ // Remove it when Dart 1.6 is old enough that we don't think anyone |
+ // will have these lockfiles anymore (issue 20703). |
lockFile = new LockFile.load(oldLockFilePath, cache.sources); |
} on IOException catch (error) { |
+ // If we couldn't read the lock file, it's not activated. |
dataError("No active package ${log.bold(name)}."); |
} |
+ |
+ // Move the old lockfile to its new location. |
ensureDir(p.dirname(lockFilePath)); |
new File(oldLockFilePath).renameSync(lockFilePath); |
} |
+ |
+ // Load the package from the cache. |
var id = lockFile.packages[name]; |
lockFile.packages.remove(name); |
+ |
var source = cache.sources[id.source]; |
if (source is CachedSource) { |
+ // For cached sources, the package itself is in the cache and the |
+ // lockfile is the one we just loaded. |
return cache.sources[id.source].getDirectory( |
id).then((dir) => new Package.load(name, dir, cache.sources)).then((package) { |
return new Entrypoint.inMemory(package, lockFile, cache); |
}); |
} |
+ |
+ // For uncached sources (i.e. path), the ID just points to the real |
+ // directory for the package. |
assert(id.source == "path"); |
return new Entrypoint( |
PathSource.pathFromDescription(id.description), |
cache); |
}); |
} |
+ |
+ /// Runs [package]'s [executable] with [args]. |
+ /// |
+ /// If [executable] is available in its precompiled form, that will be |
+ /// recompiled if the SDK has been upgraded since it was first compiled and |
+ /// then run. Otherwise, it will be run from source. |
+ /// |
+ /// If [mode] is passed, it's used as the barback mode; it defaults to |
+ /// [BarbackMode.RELEASE]. |
+ /// |
+ /// Returns the exit code from the executable. |
Future<int> runExecutable(String package, String executable, |
Iterable<String> args, {BarbackMode mode}) { |
if (mode == null) mode = BarbackMode.RELEASE; |
+ |
var binDir = p.join(_directory, package, 'bin'); |
if (mode != BarbackMode.RELEASE || |
!fileExists(p.join(binDir, '$executable.dart.snapshot'))) { |
@@ -377,9 +499,13 @@ class GlobalPackages { |
isGlobal: true); |
}); |
} |
+ |
+ // Unless the user overrides the verbosity, we want to filter out the |
+ // normal pub output shown while loading the environment. |
if (log.verbosity == log.Verbosity.NORMAL) { |
log.verbosity = log.Verbosity.WARNING; |
} |
+ |
var snapshotPath = p.join(binDir, '$executable.dart.snapshot'); |
return exe.runSnapshot(snapshotPath, args, recompile: () { |
log.fine( |
@@ -391,14 +517,22 @@ class GlobalPackages { |
(graph) => _precompileExecutables(graph.entrypoint, package)); |
}); |
} |
+ |
+ /// Gets the path to the lock file for an activated cached package with |
+ /// [name]. |
String _getLockFilePath(String name) => |
p.join(_directory, name, "pubspec.lock"); |
+ |
+ /// Shows to the user formatted list of globally activated packages. |
void listActivePackages() { |
if (!dirExists(_directory)) return; |
+ |
+ // Loads lock [file] and returns [PackageId] of the activated package. |
loadPackageId(file, name) { |
var lockFile = new LockFile.load(p.join(_directory, file), cache.sources); |
return lockFile.packages[name]; |
} |
+ |
var packages = listDir(_directory).map((entry) { |
if (fileExists(entry)) { |
return loadPackageId(entry, p.basenameWithoutExtension(entry)); |
@@ -406,10 +540,13 @@ class GlobalPackages { |
return loadPackageId(p.join(entry, 'pubspec.lock'), p.basename(entry)); |
} |
}).toList(); |
+ |
packages |
..sort((id1, id2) => id1.name.compareTo(id2.name)) |
..forEach((id) => log.message(_formatPackage(id))); |
} |
+ |
+ /// Returns formatted string representing the package [id]. |
String _formatPackage(PackageId id) { |
if (id.source == 'git') { |
var url = GitSource.urlFromDescription(id.description); |
@@ -421,21 +558,49 @@ class GlobalPackages { |
return '${log.bold(id.name)} ${id.version}'; |
} |
} |
+ |
+ /// Updates the binstubs for [package]. |
+ /// |
+ /// A binstub is a little shell script in `PUB_CACHE/bin` that runs an |
+ /// executable from a globally activated package. This removes any old |
+ /// binstubs from the previously activated version of the package and |
+ /// (optionally) creates new ones for the executables listed in the package's |
+ /// pubspec. |
+ /// |
+ /// [executables] is the names of the executables that should have binstubs. |
+ /// If `null`, all executables in the package will get binstubs. If empty, no |
+ /// binstubs will be created. |
+ /// |
+ /// If [overwriteBinStubs] is `true`, any binstubs that collide with |
+ /// existing binstubs in other packages will be overwritten by this one's. |
+ /// Otherwise, the previous ones will be preserved. |
+ /// |
+ /// If [snapshots] is given, it is a map of the names of executables whose |
+ /// snapshots that were precompiled to their paths. Binstubs for those will |
+ /// run the snapshot directly and skip pub entirely. |
void _updateBinStubs(Package package, List<String> executables, |
{bool overwriteBinStubs, Map<String, String> snapshots}) { |
if (snapshots == null) snapshots = const {}; |
+ |
+ // Remove any previously activated binstubs for this package, in case the |
+ // list of executables has changed. |
_deleteBinStubs(package.name); |
+ |
if ((executables != null && executables.isEmpty) || |
package.pubspec.executables.isEmpty) { |
return; |
} |
+ |
ensureDir(_binStubDir); |
+ |
var installed = []; |
var collided = {}; |
var allExecutables = ordered(package.pubspec.executables.keys); |
for (var executable in allExecutables) { |
if (executables != null && !executables.contains(executable)) continue; |
+ |
var script = package.pubspec.executables[executable]; |
+ |
var previousPackage = _createBinStub( |
package, |
executable, |
@@ -444,14 +609,19 @@ class GlobalPackages { |
snapshot: snapshots[script]); |
if (previousPackage != null) { |
collided[executable] = previousPackage; |
+ |
if (!overwriteBinStubs) continue; |
} |
+ |
installed.add(executable); |
} |
+ |
if (installed.isNotEmpty) { |
var names = namedSequence("executable", installed.map(log.bold)); |
log.message("Installed $names."); |
} |
+ |
+ // Show errors for any collisions. |
if (collided.isNotEmpty) { |
for (var command in ordered(collided.keys)) { |
if (overwriteBinStubs) { |
@@ -464,12 +634,15 @@ class GlobalPackages { |
"from ${log.bold(collided[command])}."); |
} |
} |
+ |
if (!overwriteBinStubs) { |
log.warning( |
"Deactivate the other package(s) or activate " |
"${log.bold(package.name)} using --overwrite."); |
} |
} |
+ |
+ // Show errors for any unknown executables. |
if (executables != null) { |
var unknown = ordered( |
executables.where((exe) => !package.pubspec.executables.keys.contains(exe))); |
@@ -477,6 +650,10 @@ class GlobalPackages { |
dataError("Unknown ${namedSequence('executable', unknown)}."); |
} |
} |
+ |
+ // Show errors for any missing scripts. |
+ // TODO(rnystrom): This can print false positives since a script may be |
+ // produced by a transformer. Do something better. |
var binFiles = package.listFiles( |
beneath: "bin", |
recursive: false).map((path) => package.relative(path)).toList(); |
@@ -489,12 +666,28 @@ class GlobalPackages { |
'which was not found in ${log.bold(package.name)}.'); |
} |
} |
+ |
if (installed.isNotEmpty) _suggestIfNotOnPath(installed); |
} |
+ |
+ /// Creates a binstub named [executable] that runs [script] from [package]. |
+ /// |
+ /// If [overwrite] is `true`, this will replace an existing binstub with that |
+ /// name for another package. |
+ /// |
+ /// If [snapshot] is non-null, it is a path to a snapshot file. The binstub |
+ /// will invoke that directly. Otherwise, it will run `pub global run`. |
+ /// |
+ /// If a collision occurs, returns the name of the package that owns the |
+ /// existing binstub. Otherwise returns `null`. |
String _createBinStub(Package package, String executable, String script, |
{bool overwrite, String snapshot}) { |
var binStubPath = p.join(_binStubDir, executable); |
+ |
if (Platform.operatingSystem == "windows") binStubPath += ".bat"; |
+ |
+ // See if the binstub already exists. If so, it's for another package |
+ // since we already deleted all of this package's binstubs. |
var previousPackage; |
if (fileExists(binStubPath)) { |
var contents = readTextFile(binStubPath); |
@@ -506,13 +699,19 @@ class GlobalPackages { |
log.fine("Could not parse binstub $binStubPath:\n$contents"); |
} |
} |
+ |
+ // If the script was precompiled to a snapshot, just invoke that directly |
+ // and skip pub global run entirely. |
var invocation; |
if (snapshot != null) { |
+ // We expect absolute paths from the precompiler since relative ones |
+ // won't be relative to the right directory when the user runs this. |
assert(p.isAbsolute(snapshot)); |
invocation = 'dart "$snapshot"'; |
} else { |
invocation = "pub global run ${package.name}:$script"; |
} |
+ |
if (Platform.operatingSystem == "windows") { |
var batch = """ |
@echo off |
@@ -535,22 +734,31 @@ $invocation %* |
$invocation "\$@" |
"""; |
writeTextFile(binStubPath, bash); |
+ |
+ // Make it executable. |
var result = Process.runSync('chmod', ['+x', binStubPath]); |
if (result.exitCode != 0) { |
+ // Couldn't make it executable so don't leave it laying around. |
try { |
deleteEntry(binStubPath); |
} on IOException catch (err) { |
+ // Do nothing. We're going to fail below anyway. |
log.fine("Could not delete binstub:\n$err"); |
} |
+ |
fail( |
'Could not make "$binStubPath" executable (exit code ' |
'${result.exitCode}):\n${result.stderr}'); |
} |
} |
+ |
return previousPackage; |
} |
+ |
+ /// Deletes all existing binstubs for [package]. |
void _deleteBinStubs(String package) { |
if (!dirExists(_binStubDir)) return; |
+ |
for (var file in listDir(_binStubDir, includeDirs: false)) { |
var contents = readTextFile(file); |
var match = _binStubPackagePattern.firstMatch(contents); |
@@ -558,16 +766,23 @@ $invocation "\$@" |
log.fine("Could not parse binstub $file:\n$contents"); |
continue; |
} |
+ |
if (match[1] == package) { |
log.fine("Deleting old binstub $file"); |
deleteEntry(file); |
} |
} |
} |
+ |
+ /// Checks to see if the binstubs are on the user's PATH and, if not, suggests |
+ /// that the user add the directory to their PATH. |
void _suggestIfNotOnPath(List<String> installed) { |
if (Platform.operatingSystem == "windows") { |
+ // See if the shell can find one of the binstubs. |
+ // "\q" means return exit code 0 if found or 1 if not. |
var result = runProcessSync("where", [r"\q", installed.first + ".bat"]); |
if (result.exitCode == 0) return; |
+ |
log.warning( |
"${log.yellow('Warning:')} Pub installs executables into " |
"${log.bold(_binStubDir)}, which is not on your path.\n" |
@@ -575,13 +790,16 @@ $invocation "\$@" |
'"Path" environment variable.\n' |
'A web search for "configure windows path" will show you how.'); |
} else { |
+ // See if the shell can find one of the binstubs. |
var result = runProcessSync("which", [installed.first]); |
if (result.exitCode == 0) return; |
+ |
var binDir = _binStubDir; |
if (binDir.startsWith(Platform.environment['HOME'])) { |
binDir = |
p.join("~", p.relative(binDir, from: Platform.environment['HOME'])); |
} |
+ |
log.warning( |
"${log.yellow('Warning:')} Pub installs executables into " |
"${log.bold(binDir)}, which is not on your path.\n" |