| 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 6eb66cd3bd9712aaed8f7e95af6ff16eabc616c1..0f50040f63db9d3b85edef6bfff312f865ed5acb 100644
|
| --- a/sdk/lib/_internal/pub_generated/lib/src/global_packages.dart
|
| +++ b/sdk/lib/_internal/pub_generated/lib/src/global_packages.dart
|
| @@ -13,6 +13,7 @@ import 'package:pub_semver/pub_semver.dart';
|
|
|
| import 'barback/asset_environment.dart';
|
| import 'entrypoint.dart';
|
| +import 'exceptions.dart';
|
| import 'executable.dart' as exe;
|
| import 'io.dart';
|
| import 'lock_file.dart';
|
| @@ -27,10 +28,6 @@ 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/
|
| @@ -527,25 +524,26 @@ class GlobalPackages {
|
| 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));
|
| - } else {
|
| - return loadPackageId(p.join(entry, 'pubspec.lock'), p.basename(entry));
|
| - }
|
| - }).toList();
|
| -
|
| - packages
|
| + return listDir(_directory).map(_loadPackageId).toList()
|
| ..sort((id1, id2) => id1.name.compareTo(id2.name))
|
| ..forEach((id) => log.message(_formatPackage(id)));
|
| }
|
|
|
| + void _loadPackageId(String path) {
|
| + var name = p.basenameWithoutExtension(path);
|
| + if (!fileExists(path)) path = p.join(path, 'pubspec.lock');
|
| +
|
| + var id =
|
| + new LockFile.load(p.join(_directory, path), cache.sources).packages[name];
|
| +
|
| + if (id == null) {
|
| + throw new FormatException(
|
| + "Pubspec for activated package $name didn't " "contain an entry for itself.");
|
| + }
|
| +
|
| + return id;
|
| + }
|
| +
|
| /// Returns formatted string representing the package [id].
|
| String _formatPackage(PackageId id) {
|
| if (id.source == 'git') {
|
| @@ -559,6 +557,200 @@ class GlobalPackages {
|
| }
|
| }
|
|
|
| + Future<Pair<int, int>> repairActivatedPackages() {
|
| + final completer0 = new Completer();
|
| + scheduleMicrotask(() {
|
| + try {
|
| + var executables = {};
|
| + join0() {
|
| + var successes = 0;
|
| + var failures = 0;
|
| + join1() {
|
| + join2() {
|
| + completer0.complete(new Pair(successes, failures));
|
| + }
|
| + if (executables.isNotEmpty) {
|
| + var packages = pluralize("package", executables.length);
|
| + var message =
|
| + new StringBuffer("Binstubs exist for non-activated " "packages:\n");
|
| + executables.forEach(((package, executableNames) {
|
| + message.writeln(
|
| + " From ${log.bold(package)}: " "${toSentence(executableNames)}");
|
| + }));
|
| + log.error(message);
|
| + join2();
|
| + } else {
|
| + join2();
|
| + }
|
| + }
|
| + if (dirExists(_directory)) {
|
| + Future.wait(listDir(_directory).map(((entry) {
|
| + final completer0 = new Completer();
|
| + scheduleMicrotask(() {
|
| + try {
|
| + var id;
|
| + join0() {
|
| + completer0.complete();
|
| + }
|
| + catch0(error, stackTrace) {
|
| + try {
|
| + var message =
|
| + "Failed to reactivate " "${log.bold(p.basenameWithoutExtension(entry))}";
|
| + join1() {
|
| + log.error(message, error, stackTrace);
|
| + failures++;
|
| + join0();
|
| + }
|
| + if (id != null) {
|
| + message += " ${id.version}";
|
| + join2() {
|
| + join1();
|
| + }
|
| + if (id.source != "hosted") {
|
| + message += " from ${id.source}";
|
| + join2();
|
| + } else {
|
| + join2();
|
| + }
|
| + } else {
|
| + join1();
|
| + }
|
| + } catch (error, stackTrace) {
|
| + completer0.completeError(error, stackTrace);
|
| + }
|
| + }
|
| + try {
|
| + id = _loadPackageId(entry);
|
| + log.message(
|
| + "Reactivating ${log.bold(id.name)} ${id.version}...");
|
| + find(id.name).then((x0) {
|
| + try {
|
| + var entrypoint = x0;
|
| + entrypoint.loadPackageGraph().then((x1) {
|
| + try {
|
| + var graph = x1;
|
| + _precompileExecutables(
|
| + entrypoint,
|
| + id.name).then((x2) {
|
| + try {
|
| + var snapshots = x2;
|
| + var packageExecutables =
|
| + executables.remove(id.name);
|
| + join3() {
|
| + _updateBinStubs(
|
| + graph.packages[id.name],
|
| + packageExecutables,
|
| + overwriteBinStubs: true,
|
| + snapshots: snapshots,
|
| + pathSuggestion: false);
|
| + successes++;
|
| + join0();
|
| + }
|
| + if (packageExecutables == null) {
|
| + packageExecutables = [];
|
| + join3();
|
| + } else {
|
| + join3();
|
| + }
|
| + } catch (e0, s0) {
|
| + catch0(e0, s0);
|
| + }
|
| + }, onError: catch0);
|
| + } catch (e1, s1) {
|
| + catch0(e1, s1);
|
| + }
|
| + }, onError: catch0);
|
| + } catch (e2, s2) {
|
| + catch0(e2, s2);
|
| + }
|
| + }, onError: catch0);
|
| + } catch (e3, s3) {
|
| + catch0(e3, s3);
|
| + }
|
| + } catch (e, s) {
|
| + completer0.completeError(e, s);
|
| + }
|
| + });
|
| + return completer0.future;
|
| + }))).then((x0) {
|
| + try {
|
| + x0;
|
| + join1();
|
| + } catch (e0, s0) {
|
| + completer0.completeError(e0, s0);
|
| + }
|
| + }, onError: completer0.completeError);
|
| + } else {
|
| + join1();
|
| + }
|
| + }
|
| + if (dirExists(_binStubDir)) {
|
| + var it0 = listDir(_binStubDir).iterator;
|
| + break0() {
|
| + join0();
|
| + }
|
| + var trampoline0;
|
| + continue0() {
|
| + trampoline0 = null;
|
| + if (it0.moveNext()) {
|
| + var entry = it0.current;
|
| + join3() {
|
| + trampoline0 = continue0;
|
| + }
|
| + catch0(error, stackTrace) {
|
| + try {
|
| + log.error(
|
| + "Error reading binstub for " "\"${p.basenameWithoutExtension(entry)}\"",
|
| + error,
|
| + stackTrace);
|
| + join3();
|
| + } catch (error, stackTrace) {
|
| + completer0.completeError(error, stackTrace);
|
| + }
|
| + }
|
| + try {
|
| + var binstub = readTextFile(entry);
|
| + var package = _binStubProperty(binstub, "Package");
|
| + join4() {
|
| + var executable = _binStubProperty(binstub, "Executable");
|
| + join5() {
|
| + executables.putIfAbsent(package, (() {
|
| + return [];
|
| + })).add(executable);
|
| + join3();
|
| + }
|
| + if (executable == null) {
|
| + throw new ApplicationException("No 'Executable' property.");
|
| + join5();
|
| + } else {
|
| + join5();
|
| + }
|
| + }
|
| + if (package == null) {
|
| + throw new ApplicationException("No 'Package' property.");
|
| + join4();
|
| + } else {
|
| + join4();
|
| + }
|
| + } catch (e1, s1) {
|
| + catch0(e1, s1);
|
| + }
|
| + } else {
|
| + break0();
|
| + }
|
| + }
|
| + trampoline0 = continue0;
|
| + do trampoline0(); while (trampoline0 != null);
|
| + } else {
|
| + join0();
|
| + }
|
| + } catch (e, s) {
|
| + completer0.completeError(e, s);
|
| + }
|
| + });
|
| + return completer0.future;
|
| + }
|
| +
|
| /// Updates the binstubs for [package].
|
| ///
|
| /// A binstub is a little shell script in `PUB_CACHE/bin` that runs an
|
| @@ -576,10 +768,14 @@ class GlobalPackages {
|
| /// 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.
|
| + /// snapshots were precompiled to the paths of those snapshots. Binstubs for
|
| + /// those will run the snapshot directly and skip pub entirely.
|
| + ///
|
| + /// If [pathSuggestion] is `true` (the default), this will warn the user if
|
| + /// the bin directory isn't on their path.
|
| void _updateBinStubs(Package package, List<String> executables,
|
| - {bool overwriteBinStubs, Map<String, String> snapshots}) {
|
| + {bool overwriteBinStubs, Map<String, String> snapshots, bool pathSuggestion:
|
| + true}) {
|
| if (snapshots == null) snapshots = const {};
|
|
|
| // Remove any previously activated binstubs for this package, in case the
|
| @@ -667,7 +863,9 @@ class GlobalPackages {
|
| }
|
| }
|
|
|
| - if (installed.isNotEmpty) _suggestIfNotOnPath(installed);
|
| + if (pathSuggestion && installed.isNotEmpty) {
|
| + _suggestIfNotOnPath(installed.first);
|
| + }
|
| }
|
|
|
| /// Creates a binstub named [executable] that runs [script] from [package].
|
| @@ -691,25 +889,25 @@ class GlobalPackages {
|
| 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 {
|
| + previousPackage = _binStubProperty(contents, "Package");
|
| + if (previousPackage == null) {
|
| log.fine("Could not parse binstub $binStubPath:\n$contents");
|
| + } else if (!overwrite) {
|
| + return previousPackage;
|
| }
|
| }
|
|
|
| // If the script was precompiled to a snapshot, just invoke that directly
|
| // and skip pub global run entirely.
|
| var invocation;
|
| + var pubGlobalInvocation = "pub global run ${package.name}:$script";
|
| 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";
|
| + invocation = pubGlobalInvocation;
|
| }
|
|
|
| if (Platform.operatingSystem == "windows") {
|
| @@ -722,6 +920,18 @@ rem Executable: ${executable}
|
| rem Script: ${script}
|
| $invocation %*
|
| """;
|
| +
|
| + if (snapshot != null) {
|
| + batch += """
|
| +
|
| +if errorlevel 255 (
|
| + exit /b %errorlevel%
|
| +)
|
| +
|
| +$pubGlobalInvocation
|
| +""";
|
| + }
|
| +
|
| writeTextFile(binStubPath, batch);
|
| } else {
|
| var bash = """
|
| @@ -733,6 +943,20 @@ $invocation %*
|
| # Script: ${script}
|
| $invocation "\$@"
|
| """;
|
| +
|
| + if (snapshot != null) {
|
| + bash += """
|
| +
|
| +exit_code=\$?
|
| +if [[ \$exit_code != 255 ]]; then
|
| + exit \$exit_code
|
| +fi
|
| +
|
| +rm "$snapshot"
|
| +$pubGlobalInvocation
|
| +""";
|
| + }
|
| +
|
| writeTextFile(binStubPath, bash);
|
|
|
| // Make it executable.
|
| @@ -761,13 +985,13 @@ $invocation "\$@"
|
|
|
| for (var file in listDir(_binStubDir, includeDirs: false)) {
|
| var contents = readTextFile(file);
|
| - var match = _binStubPackagePattern.firstMatch(contents);
|
| - if (match == null) {
|
| + var binStubPackage = _binStubProperty(contents, "Package");
|
| + if (binStubPackage == null) {
|
| log.fine("Could not parse binstub $file:\n$contents");
|
| continue;
|
| }
|
|
|
| - if (match[1] == package) {
|
| + if (binStubPackage == package) {
|
| log.fine("Deleting old binstub $file");
|
| deleteEntry(file);
|
| }
|
| @@ -776,11 +1000,14 @@ $invocation "\$@"
|
|
|
| /// 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) {
|
| + ///
|
| + /// [installed] should be the name of an installed executable that can be used
|
| + /// to test whether accessing it on the path works.
|
| + void _suggestIfNotOnPath(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"]);
|
| + var result = runProcessSync("where", [r"\q", installed + ".bat"]);
|
| if (result.exitCode == 0) return;
|
|
|
| log.warning(
|
| @@ -791,7 +1018,7 @@ $invocation "\$@"
|
| '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]);
|
| + var result = runProcessSync("which", [installed]);
|
| if (result.exitCode == 0) return;
|
|
|
| var binDir = _binStubDir;
|
| @@ -808,4 +1035,10 @@ $invocation "\$@"
|
| " ${log.bold('export PATH="\$PATH":"$binDir"')}\n" "\n");
|
| }
|
| }
|
| +
|
| + String _binStubProperty(String source, String name) {
|
| + var pattern = new RegExp(quoteRegExp(name) + r": ([a-zA-Z0-9_-]+)");
|
| + var match = pattern.firstMatch(source);
|
| + return match == null ? null : match[1];
|
| + }
|
| }
|
|
|