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 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 Loading... |
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 Loading... |
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 } |
OLD | NEW |