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 85a1983f66e66f026736507a0325d3125e37b403..7035105649086102fafdaebc48d3a51b6b6737f7 100644 |
--- a/sdk/lib/_internal/pub_generated/lib/src/global_packages.dart |
+++ b/sdk/lib/_internal/pub_generated/lib/src/global_packages.dart |
@@ -11,18 +11,22 @@ import 'lock_file.dart'; |
import 'log.dart' as log; |
import 'package.dart'; |
import 'pubspec.dart'; |
-import 'system_cache.dart'; |
+import 'sdk.dart' as sdk; |
import 'solver/version_solver.dart'; |
import 'source/cached.dart'; |
import 'source/git.dart'; |
import 'source/path.dart'; |
+import 'system_cache.dart'; |
import 'utils.dart'; |
import 'version.dart'; |
+final _binStubPackagePattern = new RegExp(r"Package: ([a-zA-Z0-9_-]+)"); |
class GlobalPackages { |
final SystemCache cache; |
String get _directory => p.join(cache.rootDir, "global_packages"); |
+ String get _binStubDir => p.join(cache.rootDir, "bin"); |
GlobalPackages(this.cache); |
- Future activateGit(String repo) { |
+ Future activateGit(String repo, List<String> executables, |
+ {bool overwriteBinStubs}) { |
final completer0 = new Completer(); |
scheduleMicrotask(() { |
try { |
@@ -34,7 +38,11 @@ class GlobalPackages { |
_installInCache( |
new PackageDep(name, "git", VersionConstraint.any, repo)).then((x1) { |
try { |
- x1; |
+ var package = x1; |
+ _updateBinStubs( |
+ package, |
+ executables, |
+ overwriteBinStubs: overwriteBinStubs); |
completer0.complete(null); |
} catch (e1) { |
completer0.completeError(e1); |
@@ -54,11 +62,35 @@ class GlobalPackages { |
}); |
return completer0.future; |
} |
- Future activateHosted(String name, VersionConstraint constraint) { |
- _describeActive(name); |
- return _installInCache(new PackageDep(name, "hosted", constraint, name)); |
+ Future activateHosted(String name, VersionConstraint constraint, |
+ List<String> executables, {bool overwriteBinStubs}) { |
+ final completer0 = new Completer(); |
+ scheduleMicrotask(() { |
+ try { |
+ _describeActive(name); |
+ _installInCache( |
+ new PackageDep(name, "hosted", constraint, name)).then((x0) { |
+ try { |
+ var package = x0; |
+ _updateBinStubs( |
+ package, |
+ executables, |
+ overwriteBinStubs: overwriteBinStubs); |
+ completer0.complete(null); |
+ } catch (e0) { |
+ completer0.completeError(e0); |
+ } |
+ }, onError: (e1) { |
+ completer0.completeError(e1); |
+ }); |
+ } catch (e2) { |
+ completer0.completeError(e2); |
+ } |
+ }); |
+ return completer0.future; |
} |
- Future activatePath(String path) { |
+ Future activatePath(String path, List<String> executables, |
+ {bool overwriteBinStubs}) { |
final completer0 = new Completer(); |
scheduleMicrotask(() { |
try { |
@@ -77,6 +109,10 @@ class GlobalPackages { |
_writeLockFile(name, new LockFile([id])); |
var binDir = p.join(_directory, name, 'bin'); |
join0() { |
+ _updateBinStubs( |
+ entrypoint.root, |
+ executables, |
+ overwriteBinStubs: overwriteBinStubs); |
completer0.complete(null); |
} |
if (dirExists(binDir)) { |
@@ -97,7 +133,7 @@ class GlobalPackages { |
}); |
return completer0.future; |
} |
- Future _installInCache(PackageDep dep) { |
+ Future<Package> _installInCache(PackageDep dep) { |
final completer0 = new Completer(); |
scheduleMicrotask(() { |
try { |
@@ -128,7 +164,7 @@ class GlobalPackages { |
try { |
x3; |
_writeLockFile(dep.name, lockFile); |
- completer0.complete(null); |
+ completer0.complete(graph.packages[dep.name]); |
} catch (e3) { |
completer0.completeError(e3); |
} |
@@ -255,14 +291,13 @@ class GlobalPackages { |
return null; |
} |
} |
- bool deactivate(String name, {bool logDeactivate: false}) { |
+ bool deactivate(String name) { |
var dir = p.join(_directory, name); |
if (!dirExists(dir)) return false; |
- if (logDeactivate) { |
- var lockFile = new LockFile.load(_getLockFilePath(name), cache.sources); |
- var id = lockFile.packages[name]; |
- log.message('Deactivated package ${_formatPackage(id)}.'); |
- } |
+ _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; |
} |
@@ -357,4 +392,132 @@ class GlobalPackages { |
return '${log.bold(id.name)} ${id.version}'; |
} |
} |
+ void _updateBinStubs(Package package, List<String> executables, |
+ {bool overwriteBinStubs}) { |
+ _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, script, overwrite: overwriteBinStubs); |
+ 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."); |
+ } |
+ if (collided.isNotEmpty) { |
+ for (var command in ordered(collided.keys)) { |
+ if (overwriteBinStubs) { |
+ log.warning( |
+ "Replaced ${log.bold(command)} previously installed from " |
+ "${log.bold(collided[command])}."); |
+ } else { |
+ log.warning( |
+ "Executable ${log.bold(command)} was already installed " |
+ "from ${log.bold(collided[command])}."); |
+ } |
+ } |
+ if (!overwriteBinStubs) { |
+ log.warning( |
+ "Deactivate the other package(s) or activate " |
+ "${log.bold(package.name)} using --overwrite-executables."); |
+ } |
+ } |
+ if (executables != null) { |
+ var unknown = ordered( |
+ executables.where((exe) => !package.pubspec.executables.keys.contains(exe))); |
+ if (unknown.isNotEmpty) { |
+ dataError("Unknown ${namedSequence('executable', unknown)}."); |
+ } |
+ } |
+ var binFiles = package.listFiles( |
+ beneath: "bin", |
+ recursive: false).map((path) => p.relative(path, from: package.dir)).toList(); |
+ for (var executable in installed) { |
+ var script = package.pubspec.executables[executable]; |
+ var scriptPath = p.join("bin", "$script.dart"); |
+ if (!binFiles.contains(scriptPath)) { |
+ log.warning( |
+ 'Warning: Executable "$executable" runs "$scriptPath", ' |
+ 'which was not found in ${log.bold(package.name)}.'); |
+ } |
+ } |
+ } |
+ String _createBinStub(Package package, String executable, String script, |
+ {bool overwrite}) { |
+ var binStubPath = p.join(_binStubDir, executable); |
+ var previousPackage; |
+ if (fileExists(binStubPath)) { |
+ var contents = readTextFile(binStubPath); |
+ var match = _binStubPackagePattern.firstMatch(contents); |
+ if (match != null) { |
+ previousPackage = match[1]; |
+ if (!overwrite) return previousPackage; |
+ } else { |
+ log.fine("Could not parse binstub $binStubPath:\n$contents"); |
+ } |
+ } |
+ if (Platform.operatingSystem == "windows") { |
+ var batch = """ |
+@echo off |
+rem This file was created by pub v${sdk.version}. |
+rem Package: ${package.name} |
+rem Version: ${package.version} |
+rem Executable: ${executable} |
+rem Script: ${script} |
+pub global run ${package.name}:$script "%*" |
+"""; |
+ writeTextFile(binStubPath, batch); |
+ } else { |
+ var bash = """ |
+# This file was created by pub v${sdk.version}. |
+# Package: ${package.name} |
+# Version: ${package.version} |
+# Executable: ${executable} |
+# Script: ${script} |
+pub global run ${package.name}:$script "\$@" |
+"""; |
+ writeTextFile(binStubPath, bash); |
+ var result = Process.runSync('chmod', ['+x', binStubPath]); |
+ if (result.exitCode != 0) { |
+ try { |
+ deleteEntry(binStubPath); |
+ } on IOException catch (err) { |
+ log.fine("Could not delete binstub:\n$err"); |
+ } |
+ fail( |
+ 'Could not make "$binStubPath" executable (exit code ' |
+ '${result.exitCode}):\n${result.stderr}'); |
+ } |
+ } |
+ return previousPackage; |
+ } |
+ 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); |
+ if (match == null) { |
+ log.fine("Could not parse binstub $file:\n$contents"); |
+ continue; |
+ } |
+ if (match[1] == package) { |
+ log.fine("Deleting old binstub $file"); |
+ deleteEntry(file); |
+ } |
+ } |
+ } |
} |