Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: sdk/lib/_internal/pub_generated/lib/src/global_packages.dart

Issue 745153002: Make pub's binstubs resilient to changes in snapshot format. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 library pub.global_packages; 5 library pub.global_packages;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:io'; 8 import 'dart:io';
9 9
10 import 'package:path/path.dart' as p; 10 import 'package:path/path.dart' as p;
11 import 'package:barback/barback.dart'; 11 import 'package:barback/barback.dart';
12 import 'package:pub_semver/pub_semver.dart'; 12 import 'package:pub_semver/pub_semver.dart';
13 13
14 import 'barback/asset_environment.dart'; 14 import 'barback/asset_environment.dart';
15 import 'entrypoint.dart'; 15 import 'entrypoint.dart';
16 import 'exceptions.dart';
16 import 'executable.dart' as exe; 17 import 'executable.dart' as exe;
17 import 'io.dart'; 18 import 'io.dart';
18 import 'lock_file.dart'; 19 import 'lock_file.dart';
19 import 'log.dart' as log; 20 import 'log.dart' as log;
20 import 'package.dart'; 21 import 'package.dart';
21 import 'pubspec.dart'; 22 import 'pubspec.dart';
22 import 'sdk.dart' as sdk; 23 import 'sdk.dart' as sdk;
23 import 'solver/version_solver.dart'; 24 import 'solver/version_solver.dart';
24 import 'source/cached.dart'; 25 import 'source/cached.dart';
25 import 'source/git.dart'; 26 import 'source/git.dart';
26 import 'source/path.dart'; 27 import 'source/path.dart';
27 import 'system_cache.dart'; 28 import 'system_cache.dart';
28 import 'utils.dart'; 29 import 'utils.dart';
29 30
30 /// Matches the package name that a binstub was created for inside the contents
31 /// of the shell script.
32 final _binStubPackagePattern = new RegExp(r"Package: ([a-zA-Z0-9_-]+)");
33
34 /// Maintains the set of packages that have been globally activated. 31 /// Maintains the set of packages that have been globally activated.
35 /// 32 ///
36 /// These have been hand-chosen by the user to make their executables in bin/ 33 /// These have been hand-chosen by the user to make their executables in bin/
37 /// available to the entire system. This lets them access them even when the 34 /// available to the entire system. This lets them access them even when the
38 /// current working directory is not inside another entrypoint package. 35 /// current working directory is not inside another entrypoint package.
39 /// 36 ///
40 /// Only one version of a given package name can be globally activated at a 37 /// Only one version of a given package name can be globally activated at a
41 /// time. Activating a different version of a package will deactivate the 38 /// time. Activating a different version of a package will deactivate the
42 /// previous one. 39 /// previous one.
43 /// 40 ///
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 517
521 /// Gets the path to the lock file for an activated cached package with 518 /// Gets the path to the lock file for an activated cached package with
522 /// [name]. 519 /// [name].
523 String _getLockFilePath(String name) => 520 String _getLockFilePath(String name) =>
524 p.join(_directory, name, "pubspec.lock"); 521 p.join(_directory, name, "pubspec.lock");
525 522
526 /// Shows to the user formatted list of globally activated packages. 523 /// Shows to the user formatted list of globally activated packages.
527 void listActivePackages() { 524 void listActivePackages() {
528 if (!dirExists(_directory)) return; 525 if (!dirExists(_directory)) return;
529 526
530 // Loads lock [file] and returns [PackageId] of the activated package. 527 return listDir(_directory).map(_loadPackageId).toList()
531 loadPackageId(file, name) { 528 ..sort((id1, id2) => id1.name.compareTo(id2.name))
532 var lockFile = new LockFile.load(p.join(_directory, file), cache.sources); 529 ..forEach((id) => log.message(_formatPackage(id)));
533 return lockFile.packages[name]; 530 }
531
532 void _loadPackageId(String path) {
533 var name = p.basenameWithoutExtension(path);
534 if (!fileExists(path)) path = p.join(path, 'pubspec.lock');
535
536 var id =
537 new LockFile.load(p.join(_directory, path), cache.sources).packages[name ];
538
539 if (id == null) {
540 throw new FormatException(
541 "Pubspec for activated package $name didn't " "contain an entry for it self.");
534 } 542 }
535 543
536 var packages = listDir(_directory).map((entry) { 544 return id;
537 if (fileExists(entry)) {
538 return loadPackageId(entry, p.basenameWithoutExtension(entry));
539 } else {
540 return loadPackageId(p.join(entry, 'pubspec.lock'), p.basename(entry));
541 }
542 }).toList();
543
544 packages
545 ..sort((id1, id2) => id1.name.compareTo(id2.name))
546 ..forEach((id) => log.message(_formatPackage(id)));
547 } 545 }
548 546
549 /// Returns formatted string representing the package [id]. 547 /// Returns formatted string representing the package [id].
550 String _formatPackage(PackageId id) { 548 String _formatPackage(PackageId id) {
551 if (id.source == 'git') { 549 if (id.source == 'git') {
552 var url = GitSource.urlFromDescription(id.description); 550 var url = GitSource.urlFromDescription(id.description);
553 return '${log.bold(id.name)} ${id.version} from Git repository "$url"'; 551 return '${log.bold(id.name)} ${id.version} from Git repository "$url"';
554 } else if (id.source == 'path') { 552 } else if (id.source == 'path') {
555 var path = PathSource.pathFromDescription(id.description); 553 var path = PathSource.pathFromDescription(id.description);
556 return '${log.bold(id.name)} ${id.version} at path "$path"'; 554 return '${log.bold(id.name)} ${id.version} at path "$path"';
557 } else { 555 } else {
558 return '${log.bold(id.name)} ${id.version}'; 556 return '${log.bold(id.name)} ${id.version}';
559 } 557 }
560 } 558 }
561 559
560 Future<Pair<int, int>> repairActivatedPackages() {
561 final completer0 = new Completer();
562 scheduleMicrotask(() {
563 try {
564 var executables = {};
565 join0() {
566 var successes = 0;
567 var failures = 0;
568 join1() {
569 join2() {
570 completer0.complete(new Pair(successes, failures));
571 }
572 if (executables.isNotEmpty) {
573 var packages = pluralize("package", executables.length);
574 var message =
575 new StringBuffer("Binstubs exist for non-activated " "packages :\n");
576 executables.forEach(((package, executableNames) {
577 message.writeln(
578 " From ${log.bold(package)}: " "${toSentence(executableName s)}");
579 }));
580 log.error(message);
581 join2();
582 } else {
583 join2();
584 }
585 }
586 if (dirExists(_directory)) {
587 Future.wait(listDir(_directory).map(((entry) {
588 final completer0 = new Completer();
589 scheduleMicrotask(() {
590 try {
591 var id;
592 join0() {
593 completer0.complete();
594 }
595 catch0(error, stackTrace) {
596 try {
597 var message =
598 "Failed to reactivate " "${log.bold(p.basenameWithoutE xtension(entry))}";
599 join1() {
600 log.error(message, error, stackTrace);
601 failures++;
602 join0();
603 }
604 if (id != null) {
605 message += " ${id.version}";
606 join2() {
607 join1();
608 }
609 if (id.source != "hosted") {
610 message += " from ${id.source}";
611 join2();
612 } else {
613 join2();
614 }
615 } else {
616 join1();
617 }
618 } catch (error, stackTrace) {
619 completer0.completeError(error, stackTrace);
620 }
621 }
622 try {
623 id = _loadPackageId(entry);
624 log.message(
625 "Reactivating ${log.bold(id.name)} ${id.version}...");
626 find(id.name).then((x0) {
627 try {
628 var entrypoint = x0;
629 entrypoint.loadPackageGraph().then((x1) {
630 try {
631 var graph = x1;
632 _precompileExecutables(
633 entrypoint,
634 id.name).then((x2) {
635 try {
636 var snapshots = x2;
637 var packageExecutables =
638 executables.remove(id.name);
639 join3() {
640 _updateBinStubs(
641 graph.packages[id.name],
642 packageExecutables,
643 overwriteBinStubs: true,
644 snapshots: snapshots,
645 pathSuggestion: false);
646 successes++;
647 join0();
648 }
649 if (packageExecutables == null) {
650 packageExecutables = [];
651 join3();
652 } else {
653 join3();
654 }
655 } catch (e0, s0) {
656 catch0(e0, s0);
657 }
658 }, onError: catch0);
659 } catch (e1, s1) {
660 catch0(e1, s1);
661 }
662 }, onError: catch0);
663 } catch (e2, s2) {
664 catch0(e2, s2);
665 }
666 }, onError: catch0);
667 } catch (e3, s3) {
668 catch0(e3, s3);
669 }
670 } catch (e, s) {
671 completer0.completeError(e, s);
672 }
673 });
674 return completer0.future;
675 }))).then((x0) {
676 try {
677 x0;
678 join1();
679 } catch (e0, s0) {
680 completer0.completeError(e0, s0);
681 }
682 }, onError: completer0.completeError);
683 } else {
684 join1();
685 }
686 }
687 if (dirExists(_binStubDir)) {
688 var it0 = listDir(_binStubDir).iterator;
689 break0() {
690 join0();
691 }
692 var trampoline0;
693 continue0() {
694 trampoline0 = null;
695 if (it0.moveNext()) {
696 var entry = it0.current;
697 join3() {
698 trampoline0 = continue0;
699 }
700 catch0(error, stackTrace) {
701 try {
702 log.error(
703 "Error reading binstub for " "\"${p.basenameWithoutExtensi on(entry)}\"",
704 error,
705 stackTrace);
706 join3();
707 } catch (error, stackTrace) {
708 completer0.completeError(error, stackTrace);
709 }
710 }
711 try {
712 var binstub = readTextFile(entry);
713 var package = _binStubProperty(binstub, "Package");
714 join4() {
715 var executable = _binStubProperty(binstub, "Executable");
716 join5() {
717 executables.putIfAbsent(package, (() {
718 return [];
719 })).add(executable);
720 join3();
721 }
722 if (executable == null) {
723 throw new ApplicationException("No 'Executable' property.");
724 join5();
725 } else {
726 join5();
727 }
728 }
729 if (package == null) {
730 throw new ApplicationException("No 'Package' property.");
731 join4();
732 } else {
733 join4();
734 }
735 } catch (e1, s1) {
736 catch0(e1, s1);
737 }
738 } else {
739 break0();
740 }
741 }
742 trampoline0 = continue0;
743 do trampoline0(); while (trampoline0 != null);
744 } else {
745 join0();
746 }
747 } catch (e, s) {
748 completer0.completeError(e, s);
749 }
750 });
751 return completer0.future;
752 }
753
562 /// Updates the binstubs for [package]. 754 /// Updates the binstubs for [package].
563 /// 755 ///
564 /// A binstub is a little shell script in `PUB_CACHE/bin` that runs an 756 /// A binstub is a little shell script in `PUB_CACHE/bin` that runs an
565 /// executable from a globally activated package. This removes any old 757 /// executable from a globally activated package. This removes any old
566 /// binstubs from the previously activated version of the package and 758 /// binstubs from the previously activated version of the package and
567 /// (optionally) creates new ones for the executables listed in the package's 759 /// (optionally) creates new ones for the executables listed in the package's
568 /// pubspec. 760 /// pubspec.
569 /// 761 ///
570 /// [executables] is the names of the executables that should have binstubs. 762 /// [executables] is the names of the executables that should have binstubs.
571 /// If `null`, all executables in the package will get binstubs. If empty, no 763 /// If `null`, all executables in the package will get binstubs. If empty, no
572 /// binstubs will be created. 764 /// binstubs will be created.
573 /// 765 ///
574 /// If [overwriteBinStubs] is `true`, any binstubs that collide with 766 /// If [overwriteBinStubs] is `true`, any binstubs that collide with
575 /// existing binstubs in other packages will be overwritten by this one's. 767 /// existing binstubs in other packages will be overwritten by this one's.
576 /// Otherwise, the previous ones will be preserved. 768 /// Otherwise, the previous ones will be preserved.
577 /// 769 ///
578 /// If [snapshots] is given, it is a map of the names of executables whose 770 /// If [snapshots] is given, it is a map of the names of executables whose
579 /// snapshots that were precompiled to their paths. Binstubs for those will 771 /// snapshots were precompiled to the paths of those snapshots. Binstubs for
580 /// run the snapshot directly and skip pub entirely. 772 /// those will run the snapshot directly and skip pub entirely.
773 ///
774 /// If [pathSuggestion] is `true` (the default), this will warn the user if
775 /// the bin directory isn't on their path.
581 void _updateBinStubs(Package package, List<String> executables, 776 void _updateBinStubs(Package package, List<String> executables,
582 {bool overwriteBinStubs, Map<String, String> snapshots}) { 777 {bool overwriteBinStubs, Map<String, String> snapshots, bool pathSuggestio n:
778 true}) {
583 if (snapshots == null) snapshots = const {}; 779 if (snapshots == null) snapshots = const {};
584 780
585 // Remove any previously activated binstubs for this package, in case the 781 // Remove any previously activated binstubs for this package, in case the
586 // list of executables has changed. 782 // list of executables has changed.
587 _deleteBinStubs(package.name); 783 _deleteBinStubs(package.name);
588 784
589 if ((executables != null && executables.isEmpty) || 785 if ((executables != null && executables.isEmpty) ||
590 package.pubspec.executables.isEmpty) { 786 package.pubspec.executables.isEmpty) {
591 return; 787 return;
592 } 788 }
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 for (var executable in installed) { 856 for (var executable in installed) {
661 var script = package.pubspec.executables[executable]; 857 var script = package.pubspec.executables[executable];
662 var scriptPath = p.join("bin", "$script.dart"); 858 var scriptPath = p.join("bin", "$script.dart");
663 if (!binFiles.contains(scriptPath)) { 859 if (!binFiles.contains(scriptPath)) {
664 log.warning( 860 log.warning(
665 'Warning: Executable "$executable" runs "$scriptPath", ' 861 'Warning: Executable "$executable" runs "$scriptPath", '
666 'which was not found in ${log.bold(package.name)}.'); 862 'which was not found in ${log.bold(package.name)}.');
667 } 863 }
668 } 864 }
669 865
670 if (installed.isNotEmpty) _suggestIfNotOnPath(installed); 866 if (pathSuggestion && installed.isNotEmpty) {
867 _suggestIfNotOnPath(installed.first);
868 }
671 } 869 }
672 870
673 /// Creates a binstub named [executable] that runs [script] from [package]. 871 /// Creates a binstub named [executable] that runs [script] from [package].
674 /// 872 ///
675 /// If [overwrite] is `true`, this will replace an existing binstub with that 873 /// If [overwrite] is `true`, this will replace an existing binstub with that
676 /// name for another package. 874 /// name for another package.
677 /// 875 ///
678 /// If [snapshot] is non-null, it is a path to a snapshot file. The binstub 876 /// If [snapshot] is non-null, it is a path to a snapshot file. The binstub
679 /// will invoke that directly. Otherwise, it will run `pub global run`. 877 /// will invoke that directly. Otherwise, it will run `pub global run`.
680 /// 878 ///
681 /// If a collision occurs, returns the name of the package that owns the 879 /// If a collision occurs, returns the name of the package that owns the
682 /// existing binstub. Otherwise returns `null`. 880 /// existing binstub. Otherwise returns `null`.
683 String _createBinStub(Package package, String executable, String script, 881 String _createBinStub(Package package, String executable, String script,
684 {bool overwrite, String snapshot}) { 882 {bool overwrite, String snapshot}) {
685 var binStubPath = p.join(_binStubDir, executable); 883 var binStubPath = p.join(_binStubDir, executable);
686 884
687 if (Platform.operatingSystem == "windows") binStubPath += ".bat"; 885 if (Platform.operatingSystem == "windows") binStubPath += ".bat";
688 886
689 // See if the binstub already exists. If so, it's for another package 887 // See if the binstub already exists. If so, it's for another package
690 // since we already deleted all of this package's binstubs. 888 // since we already deleted all of this package's binstubs.
691 var previousPackage; 889 var previousPackage;
692 if (fileExists(binStubPath)) { 890 if (fileExists(binStubPath)) {
693 var contents = readTextFile(binStubPath); 891 var contents = readTextFile(binStubPath);
694 var match = _binStubPackagePattern.firstMatch(contents); 892 previousPackage = _binStubProperty(contents, "Package");
695 if (match != null) { 893 if (previousPackage == null) {
696 previousPackage = match[1];
697 if (!overwrite) return previousPackage;
698 } else {
699 log.fine("Could not parse binstub $binStubPath:\n$contents"); 894 log.fine("Could not parse binstub $binStubPath:\n$contents");
895 } else if (!overwrite) {
896 return previousPackage;
700 } 897 }
701 } 898 }
702 899
703 // If the script was precompiled to a snapshot, just invoke that directly 900 // If the script was precompiled to a snapshot, just invoke that directly
704 // and skip pub global run entirely. 901 // and skip pub global run entirely.
705 var invocation; 902 var invocation;
903 var pubGlobalInvocation = "pub global run ${package.name}:$script";
706 if (snapshot != null) { 904 if (snapshot != null) {
707 // We expect absolute paths from the precompiler since relative ones 905 // We expect absolute paths from the precompiler since relative ones
708 // won't be relative to the right directory when the user runs this. 906 // won't be relative to the right directory when the user runs this.
709 assert(p.isAbsolute(snapshot)); 907 assert(p.isAbsolute(snapshot));
710 invocation = 'dart "$snapshot"'; 908 invocation = 'dart "$snapshot"';
711 } else { 909 } else {
712 invocation = "pub global run ${package.name}:$script"; 910 invocation = pubGlobalInvocation;
713 } 911 }
714 912
715 if (Platform.operatingSystem == "windows") { 913 if (Platform.operatingSystem == "windows") {
716 var batch = """ 914 var batch = """
717 @echo off 915 @echo off
718 rem This file was created by pub v${sdk.version}. 916 rem This file was created by pub v${sdk.version}.
719 rem Package: ${package.name} 917 rem Package: ${package.name}
720 rem Version: ${package.version} 918 rem Version: ${package.version}
721 rem Executable: ${executable} 919 rem Executable: ${executable}
722 rem Script: ${script} 920 rem Script: ${script}
723 $invocation %* 921 $invocation %*
724 """; 922 """;
923
924 if (snapshot != null) {
925 batch += """
926
927 if errorlevel 255 (
928 exit /b %errorlevel%
929 )
930
931 $pubGlobalInvocation
932 """;
933 }
934
725 writeTextFile(binStubPath, batch); 935 writeTextFile(binStubPath, batch);
726 } else { 936 } else {
727 var bash = """ 937 var bash = """
728 #!/usr/bin/env sh 938 #!/usr/bin/env sh
729 # This file was created by pub v${sdk.version}. 939 # This file was created by pub v${sdk.version}.
730 # Package: ${package.name} 940 # Package: ${package.name}
731 # Version: ${package.version} 941 # Version: ${package.version}
732 # Executable: ${executable} 942 # Executable: ${executable}
733 # Script: ${script} 943 # Script: ${script}
734 $invocation "\$@" 944 $invocation "\$@"
735 """; 945 """;
946
947 if (snapshot != null) {
948 bash += """
949
950 exit_code=\$?
951 if [[ \$exit_code != 255 ]]; then
952 exit \$exit_code
953 fi
954
955 rm "$snapshot"
956 $pubGlobalInvocation
957 """;
958 }
959
736 writeTextFile(binStubPath, bash); 960 writeTextFile(binStubPath, bash);
737 961
738 // Make it executable. 962 // Make it executable.
739 var result = Process.runSync('chmod', ['+x', binStubPath]); 963 var result = Process.runSync('chmod', ['+x', binStubPath]);
740 if (result.exitCode != 0) { 964 if (result.exitCode != 0) {
741 // Couldn't make it executable so don't leave it laying around. 965 // Couldn't make it executable so don't leave it laying around.
742 try { 966 try {
743 deleteEntry(binStubPath); 967 deleteEntry(binStubPath);
744 } on IOException catch (err) { 968 } on IOException catch (err) {
745 // Do nothing. We're going to fail below anyway. 969 // Do nothing. We're going to fail below anyway.
746 log.fine("Could not delete binstub:\n$err"); 970 log.fine("Could not delete binstub:\n$err");
747 } 971 }
748 972
749 fail( 973 fail(
750 'Could not make "$binStubPath" executable (exit code ' 974 'Could not make "$binStubPath" executable (exit code '
751 '${result.exitCode}):\n${result.stderr}'); 975 '${result.exitCode}):\n${result.stderr}');
752 } 976 }
753 } 977 }
754 978
755 return previousPackage; 979 return previousPackage;
756 } 980 }
757 981
758 /// Deletes all existing binstubs for [package]. 982 /// Deletes all existing binstubs for [package].
759 void _deleteBinStubs(String package) { 983 void _deleteBinStubs(String package) {
760 if (!dirExists(_binStubDir)) return; 984 if (!dirExists(_binStubDir)) return;
761 985
762 for (var file in listDir(_binStubDir, includeDirs: false)) { 986 for (var file in listDir(_binStubDir, includeDirs: false)) {
763 var contents = readTextFile(file); 987 var contents = readTextFile(file);
764 var match = _binStubPackagePattern.firstMatch(contents); 988 var binStubPackage = _binStubProperty(contents, "Package");
765 if (match == null) { 989 if (binStubPackage == null) {
766 log.fine("Could not parse binstub $file:\n$contents"); 990 log.fine("Could not parse binstub $file:\n$contents");
767 continue; 991 continue;
768 } 992 }
769 993
770 if (match[1] == package) { 994 if (binStubPackage == package) {
771 log.fine("Deleting old binstub $file"); 995 log.fine("Deleting old binstub $file");
772 deleteEntry(file); 996 deleteEntry(file);
773 } 997 }
774 } 998 }
775 } 999 }
776 1000
777 /// Checks to see if the binstubs are on the user's PATH and, if not, suggests 1001 /// Checks to see if the binstubs are on the user's PATH and, if not, suggests
778 /// that the user add the directory to their PATH. 1002 /// that the user add the directory to their PATH.
779 void _suggestIfNotOnPath(List<String> installed) { 1003 ///
1004 /// [installed] should be the name of an installed executable that can be used
1005 /// to test whether accessing it on the path works.
1006 void _suggestIfNotOnPath(String installed) {
780 if (Platform.operatingSystem == "windows") { 1007 if (Platform.operatingSystem == "windows") {
781 // See if the shell can find one of the binstubs. 1008 // See if the shell can find one of the binstubs.
782 // "\q" means return exit code 0 if found or 1 if not. 1009 // "\q" means return exit code 0 if found or 1 if not.
783 var result = runProcessSync("where", [r"\q", installed.first + ".bat"]); 1010 var result = runProcessSync("where", [r"\q", installed + ".bat"]);
784 if (result.exitCode == 0) return; 1011 if (result.exitCode == 0) return;
785 1012
786 log.warning( 1013 log.warning(
787 "${log.yellow('Warning:')} Pub installs executables into " 1014 "${log.yellow('Warning:')} Pub installs executables into "
788 "${log.bold(_binStubDir)}, which is not on your path.\n" 1015 "${log.bold(_binStubDir)}, which is not on your path.\n"
789 "You can fix that by adding that directory to your system's " 1016 "You can fix that by adding that directory to your system's "
790 '"Path" environment variable.\n' 1017 '"Path" environment variable.\n'
791 'A web search for "configure windows path" will show you how.'); 1018 'A web search for "configure windows path" will show you how.');
792 } else { 1019 } else {
793 // See if the shell can find one of the binstubs. 1020 // See if the shell can find one of the binstubs.
794 var result = runProcessSync("which", [installed.first]); 1021 var result = runProcessSync("which", [installed]);
795 if (result.exitCode == 0) return; 1022 if (result.exitCode == 0) return;
796 1023
797 var binDir = _binStubDir; 1024 var binDir = _binStubDir;
798 if (binDir.startsWith(Platform.environment['HOME'])) { 1025 if (binDir.startsWith(Platform.environment['HOME'])) {
799 binDir = 1026 binDir =
800 p.join("~", p.relative(binDir, from: Platform.environment['HOME'])); 1027 p.join("~", p.relative(binDir, from: Platform.environment['HOME']));
801 } 1028 }
802 1029
803 log.warning( 1030 log.warning(
804 "${log.yellow('Warning:')} Pub installs executables into " 1031 "${log.yellow('Warning:')} Pub installs executables into "
805 "${log.bold(binDir)}, which is not on your path.\n" 1032 "${log.bold(binDir)}, which is not on your path.\n"
806 "You can fix that by adding this to your shell's config file " 1033 "You can fix that by adding this to your shell's config file "
807 "(.bashrc, .bash_profile, etc.):\n" "\n" 1034 "(.bashrc, .bash_profile, etc.):\n" "\n"
808 " ${log.bold('export PATH="\$PATH":"$binDir"')}\n" "\n"); 1035 " ${log.bold('export PATH="\$PATH":"$binDir"')}\n" "\n");
809 } 1036 }
810 } 1037 }
1038
1039 String _binStubProperty(String source, String name) {
1040 var pattern = new RegExp(quoteRegExp(name) + r": ([a-zA-Z0-9_-]+)");
1041 var match = pattern.firstMatch(source);
1042 return match == null ? null : match[1];
1043 }
811 } 1044 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698