OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """A wrapper script to manage a set of client modules in different SCM. | 6 """A wrapper script to manage a set of client modules in different SCM. |
7 | 7 |
8 This script is intended to be used to help basic management of client | 8 This script is intended to be used to help basic management of client |
9 program sources residing in one or more Subversion modules and Git | 9 program sources residing in one or more Subversion modules and Git |
10 repositories, along with other modules it depends on, also in Subversion or Git, | 10 repositories, along with other modules it depends on, also in Subversion or Git, |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 it will be removed from the list and the list will be extended | 48 it will be removed from the list and the list will be extended |
49 by the list of matching files. | 49 by the list of matching files. |
50 | 50 |
51 Example: | 51 Example: |
52 hooks = [ | 52 hooks = [ |
53 { "pattern": "\\.(gif|jpe?g|pr0n|png)$", | 53 { "pattern": "\\.(gif|jpe?g|pr0n|png)$", |
54 "action": ["python", "image_indexer.py", "--all"]}, | 54 "action": ["python", "image_indexer.py", "--all"]}, |
55 ] | 55 ] |
56 """ | 56 """ |
57 | 57 |
58 __version__ = "0.4" | 58 __version__ = "0.3.7" |
59 | 59 |
60 import errno | 60 import errno |
61 import logging | 61 import logging |
62 import optparse | 62 import optparse |
63 import os | 63 import os |
64 import pprint | 64 import pprint |
65 import re | 65 import re |
66 import sys | 66 import sys |
67 import urlparse | 67 import urlparse |
68 import urllib | 68 import urllib |
69 | 69 |
70 import breakpad | 70 import breakpad |
71 | 71 |
72 import gclient_scm | 72 import gclient_scm |
73 import gclient_utils | 73 import gclient_utils |
74 from third_party.repo.progress import Progress | 74 from third_party.repo.progress import Progress |
75 | 75 |
| 76 # default help text |
| 77 DEFAULT_USAGE_TEXT = ( |
| 78 """%prog <subcommand> [options] [--] [SCM options/args...] |
| 79 a wrapper for managing a set of svn client modules and/or git repositories. |
| 80 Version """ + __version__ + """ |
| 81 |
| 82 Options and extra arguments can be passed to invoked SCM commands by |
| 83 appending them to the command line. Note that if the first such |
| 84 appended option starts with a dash (-) then the options must be |
| 85 preceded by -- to distinguish them from gclient options. |
| 86 |
| 87 For additional help on a subcommand or examples of usage, try |
| 88 %prog help <subcommand> |
| 89 %prog help files |
| 90 """) |
| 91 |
76 | 92 |
77 def attr(attr, data): | 93 def attr(attr, data): |
78 """Sets an attribute on a function.""" | 94 """Sets an attribute on a function.""" |
79 def hook(fn): | 95 def hook(fn): |
80 setattr(fn, attr, data) | 96 setattr(fn, attr, data) |
81 return fn | 97 return fn |
82 return hook | 98 return hook |
83 | 99 |
84 | 100 |
85 ## GClient implementation. | 101 ## GClient implementation. |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 if d in solution_urls and solution_urls[d] != url: | 463 if d in solution_urls and solution_urls[d] != url: |
448 raise gclient_utils.Error( | 464 raise gclient_utils.Error( |
449 "Dependency \"%s\" conflicts with specified solution" % d) | 465 "Dependency \"%s\" conflicts with specified solution" % d) |
450 # Grab the dependency. | 466 # Grab the dependency. |
451 deps[d] = url | 467 deps[d] = url |
452 return deps | 468 return deps |
453 | 469 |
454 def _RunHookAction(self, hook_dict, matching_file_list): | 470 def _RunHookAction(self, hook_dict, matching_file_list): |
455 """Runs the action from a single hook. | 471 """Runs the action from a single hook. |
456 """ | 472 """ |
457 logging.info(hook_dict) | |
458 logging.info(matching_file_list) | |
459 command = hook_dict['action'][:] | 473 command = hook_dict['action'][:] |
460 if command[0] == 'python': | 474 if command[0] == 'python': |
461 # If the hook specified "python" as the first item, the action is a | 475 # If the hook specified "python" as the first item, the action is a |
462 # Python script. Run it by starting a new copy of the same | 476 # Python script. Run it by starting a new copy of the same |
463 # interpreter. | 477 # interpreter. |
464 command[0] = sys.executable | 478 command[0] = sys.executable |
465 | 479 |
466 if '$matching_files' in command: | 480 if '$matching_files' in command: |
467 splice_index = command.index('$matching_files') | 481 splice_index = command.index('$matching_files') |
468 command[splice_index:splice_index + 1] = matching_file_list | 482 command[splice_index:splice_index + 1] = matching_file_list |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
792 for x in sorted(entries.keys())])) | 806 for x in sorted(entries.keys())])) |
793 | 807 |
794 # Print the snapshot configuration file | 808 # Print the snapshot configuration file |
795 if self._options.snapshot: | 809 if self._options.snapshot: |
796 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} | 810 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} |
797 snapclient = GClient(self._root_dir, self._options) | 811 snapclient = GClient(self._root_dir, self._options) |
798 snapclient.SetConfig(config) | 812 snapclient.SetConfig(config) |
799 print(snapclient._config_content) | 813 print(snapclient._config_content) |
800 | 814 |
801 | 815 |
802 #### gclient commands. | 816 ## gclient commands. |
803 | 817 |
804 | 818 |
805 def CMDcleanup(parser, args): | 819 def CMDcleanup(parser, options, args): |
806 """Cleans up all working copies. | 820 """Clean up all working copies, using 'svn cleanup' for each module. |
807 | 821 |
808 Mostly svn-specific. Simply runs 'svn cleanup' for each module. | 822 Additional options and args may be passed to 'svn cleanup'. |
| 823 |
| 824 usage: cleanup [options] [--] [svn cleanup args/options] |
| 825 |
| 826 Valid options: |
| 827 --verbose : output additional diagnostics |
809 """ | 828 """ |
810 (options, args) = parser.parse_args(args) | |
811 client = GClient.LoadCurrentConfig(options) | 829 client = GClient.LoadCurrentConfig(options) |
812 if not client: | 830 if not client: |
813 raise gclient_utils.Error("client not configured; see 'gclient config'") | 831 raise gclient_utils.Error("client not configured; see 'gclient config'") |
814 if options.verbose: | 832 if options.verbose: |
815 # Print out the .gclient file. This is longer than if we just printed the | 833 # Print out the .gclient file. This is longer than if we just printed the |
816 # client dict, but more legible, and it might contain helpful comments. | 834 # client dict, but more legible, and it might contain helpful comments. |
817 print(client.ConfigContent()) | 835 print(client.ConfigContent()) |
818 return client.RunOnDeps('cleanup', args) | 836 return client.RunOnDeps('cleanup', args) |
819 | 837 |
820 | 838 |
821 @attr('usage', '[url] [safesync url]') | 839 def CMDconfig(parser, options, args): |
822 def CMDconfig(parser, args): | |
823 """Create a .gclient file in the current directory. | 840 """Create a .gclient file in the current directory. |
824 | 841 |
825 This specifies the configuration for further commands. After update/sync, | 842 This specifies the configuration for further commands. After update/sync, |
826 top-level DEPS files in each module are read to determine dependent | 843 top-level DEPS files in each module are read to determine dependent |
827 modules to operate on as well. If optional [url] parameter is | 844 modules to operate on as well. If optional [url] parameter is |
828 provided, then configuration is read from a specified Subversion server | 845 provided, then configuration is read from a specified Subversion server |
829 URL. | 846 URL. Otherwise, a --spec option must be provided. A --name option overrides |
| 847 the default name for the solutions. |
| 848 |
| 849 usage: config [option | url] [safesync url] |
| 850 |
| 851 Valid options: |
| 852 --name path : alternate relative path for the solution |
| 853 --spec=GCLIENT_SPEC : contents of .gclient are read from string parameter. |
| 854 *Note that due to Cygwin/Python brokenness, it |
| 855 probably can't contain any newlines.* |
| 856 |
| 857 Examples: |
| 858 gclient config https://gclient.googlecode.com/svn/trunk/gclient |
| 859 configure a new client to check out gclient.py tool sources |
| 860 gclient config --name tools https://gclient.googlecode.com/svn/trunk/gclient |
| 861 gclient config --spec='solutions=[{"name":"gclient", |
| 862 '"url":"https://gclient.googlecode.com/svn/trunk/gclient",' |
| 863 '"custom_deps":{}}]' |
830 """ | 864 """ |
831 parser.add_option("--spec", | |
832 help="create a gclient file containing the provided " | |
833 "string. Due to Cygwin/Python brokenness, it " | |
834 "probably can't contain any newlines.") | |
835 parser.add_option("--name", | |
836 help="overrides the default name for the solution") | |
837 (options, args) = parser.parse_args(args) | |
838 if len(args) < 1 and not options.spec: | 865 if len(args) < 1 and not options.spec: |
839 raise gclient_utils.Error("required argument missing; see 'gclient help " | 866 raise gclient_utils.Error("required argument missing; see 'gclient help " |
840 "config'") | 867 "config'") |
841 if os.path.exists(options.config_filename): | 868 if os.path.exists(options.config_filename): |
842 raise gclient_utils.Error("%s file already exists in the current directory" | 869 raise gclient_utils.Error("%s file already exists in the current directory" |
843 % options.config_filename) | 870 % options.config_filename) |
844 client = GClient('.', options) | 871 client = GClient('.', options) |
845 if options.spec: | 872 if options.spec: |
846 client.SetConfig(options.spec) | 873 client.SetConfig(options.spec) |
847 else: | 874 else: |
848 base_url = args[0].rstrip('/') | 875 base_url = args[0].rstrip('/') |
849 if not options.name: | 876 if not options.name: |
850 name = base_url.split("/")[-1] | 877 name = base_url.split("/")[-1] |
851 else: | 878 else: |
852 # specify an alternate relpath for the given URL. | 879 # specify an alternate relpath for the given URL. |
853 name = options.name | 880 name = options.name |
854 safesync_url = "" | 881 safesync_url = "" |
855 if len(args) > 1: | 882 if len(args) > 1: |
856 safesync_url = args[1] | 883 safesync_url = args[1] |
857 client.SetDefaultConfig(name, base_url, safesync_url) | 884 client.SetDefaultConfig(name, base_url, safesync_url) |
858 client.SaveConfig() | 885 client.SaveConfig() |
859 return 0 | 886 return 0 |
860 | 887 |
861 | 888 |
862 def CMDexport(parser, args): | 889 def CMDexport(parser, options, args): |
863 """Wrapper for svn export for all managed directories.""" | 890 """Wrapper for svn export for all managed directories.""" |
864 (options, args) = parser.parse_args(args) | |
865 if len(args) != 1: | 891 if len(args) != 1: |
866 raise gclient_utils.Error("Need directory name") | 892 raise gclient_utils.Error("Need directory name") |
867 client = GClient.LoadCurrentConfig(options) | 893 client = GClient.LoadCurrentConfig(options) |
868 | 894 |
869 if not client: | 895 if not client: |
870 raise gclient_utils.Error("client not configured; see 'gclient config'") | 896 raise gclient_utils.Error("client not configured; see 'gclient config'") |
871 | 897 |
872 if options.verbose: | 898 if options.verbose: |
873 # Print out the .gclient file. This is longer than if we just printed the | 899 # Print out the .gclient file. This is longer than if we just printed the |
874 # client dict, but more legible, and it might contain helpful comments. | 900 # client dict, but more legible, and it might contain helpful comments. |
875 print(client.ConfigContent()) | 901 print(client.ConfigContent()) |
876 return client.RunOnDeps('export', args) | 902 return client.RunOnDeps('export', args) |
877 | 903 |
878 | 904 |
879 @attr('epilog', """Example: | 905 def CMDpack(parser, options, args): |
880 gclient pack > patch.txt | |
881 generate simple patch for configured client and dependences | |
882 """) | |
883 def CMDpack(parser, args): | |
884 """Generate a patch which can be applied at the root of the tree. | 906 """Generate a patch which can be applied at the root of the tree. |
885 | 907 |
886 Internally, runs 'svn diff'/'git diff' on each checked out module and | 908 Internally, runs 'svn diff' on each checked out module and |
887 dependencies, and performs minimal postprocessing of the output. The | 909 dependencies, and performs minimal postprocessing of the output. The |
888 resulting patch is printed to stdout and can be applied to a freshly | 910 resulting patch is printed to stdout and can be applied to a freshly |
889 checked out tree via 'patch -p0 < patchfile'. | 911 checked out tree via 'patch -p0 < patchfile'. Additional args and |
| 912 options to 'svn diff' can be passed after gclient options. |
| 913 |
| 914 usage: pack [options] [--] [svn args/options] |
| 915 |
| 916 Valid options: |
| 917 --verbose : output additional diagnostics |
| 918 |
| 919 Examples: |
| 920 gclient pack > patch.txt |
| 921 generate simple patch for configured client and dependences |
| 922 gclient pack -- -x -b > patch.txt |
| 923 generate patch using 'svn diff -x -b' to suppress |
| 924 whitespace-only differences |
| 925 gclient pack -- -r HEAD -x -b > patch.txt |
| 926 generate patch, diffing each file versus the latest version of |
| 927 each module |
890 """ | 928 """ |
891 (options, args) = parser.parse_args(args) | |
892 client = GClient.LoadCurrentConfig(options) | 929 client = GClient.LoadCurrentConfig(options) |
893 if not client: | 930 if not client: |
894 raise gclient_utils.Error("client not configured; see 'gclient config'") | 931 raise gclient_utils.Error("client not configured; see 'gclient config'") |
895 if options.verbose: | 932 if options.verbose: |
896 # Print out the .gclient file. This is longer than if we just printed the | 933 # Print out the .gclient file. This is longer than if we just printed the |
897 # client dict, but more legible, and it might contain helpful comments. | 934 # client dict, but more legible, and it might contain helpful comments. |
898 print(client.ConfigContent()) | 935 print(client.ConfigContent()) |
899 return client.RunOnDeps('pack', args) | 936 return client.RunOnDeps('pack', args) |
900 | 937 |
901 | 938 |
902 def CMDstatus(parser, args): | 939 def CMDstatus(parser, options, args): |
903 """Show modification status for every dependencies.""" | 940 """Show the modification status of for every dependencies. |
904 (options, args) = parser.parse_args(args) | 941 |
| 942 Additional options and args may be passed to 'svn status'. |
| 943 |
| 944 usage: status [options] [--] [svn diff args/options] |
| 945 |
| 946 Valid options: |
| 947 --verbose : output additional diagnostics |
| 948 --nohooks : don't run the hooks after the update is complete |
| 949 """ |
905 client = GClient.LoadCurrentConfig(options) | 950 client = GClient.LoadCurrentConfig(options) |
906 if not client: | 951 if not client: |
907 raise gclient_utils.Error("client not configured; see 'gclient config'") | 952 raise gclient_utils.Error("client not configured; see 'gclient config'") |
908 if options.verbose: | 953 if options.verbose: |
909 # Print out the .gclient file. This is longer than if we just printed the | 954 # Print out the .gclient file. This is longer than if we just printed the |
910 # client dict, but more legible, and it might contain helpful comments. | 955 # client dict, but more legible, and it might contain helpful comments. |
911 print(client.ConfigContent()) | 956 print(client.ConfigContent()) |
912 return client.RunOnDeps('status', args) | 957 return client.RunOnDeps('status', args) |
913 | 958 |
914 | 959 |
915 @attr('epilog', """Examples: | 960 def CMDsync(parser, options, args): |
| 961 """Checkout/update the modules specified by the gclient configuration. |
| 962 |
| 963 Unless --revision is specified, then the latest revision of the root solutions |
| 964 is checked out, with dependent submodule versions updated according to DEPS |
| 965 files. If --revision is specified, then the given revision is used in place |
| 966 of the latest, either for a single solution or for all solutions. |
| 967 Unless the --force option is provided, solutions and modules whose |
| 968 local revision matches the one to update (i.e., they have not changed |
| 969 in the repository) are *not* modified. Unless --nohooks is provided, |
| 970 the hooks are run. See 'help config' for more information. |
| 971 |
| 972 usage: gclient sync [options] [--] [SCM update options/args] |
| 973 |
| 974 Valid options: |
| 975 --force : force update even for unchanged modules |
| 976 --nohooks : don't run the hooks after the update is complete |
| 977 --revision SOLUTION@REV : update given solution to specified revision |
| 978 --deps PLATFORM(S) : sync deps for the given platform(s), or 'all' |
| 979 --verbose : output additional diagnostics |
| 980 --head : update to latest revision, instead of last good |
| 981 revision |
| 982 --reset : resets any local changes before updating (git only) |
| 983 |
| 984 Examples: |
916 gclient sync | 985 gclient sync |
917 update files from SCM according to current configuration, | 986 update files from SCM according to current configuration, |
918 *for modules which have changed since last update or sync* | 987 *for modules which have changed since last update or sync* |
919 gclient sync --force | 988 gclient sync --force |
920 update files from SCM according to current configuration, for | 989 update files from SCM according to current configuration, for |
921 all modules (useful for recovering files deleted from local copy) | 990 all modules (useful for recovering files deleted from local copy) |
922 gclient sync --revision src@31000 | 991 gclient sync --revision src@31000 |
923 update src directory to r31000 | 992 update src directory to r31000 |
924 """) | 993 """ |
925 def CMDsync(parser, args): | |
926 """Checkout/update all modules.""" | |
927 parser.add_option("--force", action="store_true", | |
928 help="force update even for unchanged modules") | |
929 parser.add_option("--nohooks", action="store_true", | |
930 help="don't run hooks after the update is complete") | |
931 parser.add_option("-r", "--revision", action="append", | |
932 dest="revisions", metavar="REV", default=[], | |
933 help="update given solution to specified revision, " | |
934 "can be used multiple times for each solution, " | |
935 "e.g. -r src@123, -r internal@32") | |
936 parser.add_option("--head", action="store_true", | |
937 help="skips any safesync_urls specified in " | |
938 "configured solutions and sync to head instead") | |
939 parser.add_option("--delete_unversioned_trees", action="store_true", | |
940 help="delete any unexpected unversioned trees " | |
941 "that are in the checkout") | |
942 parser.add_option("--reset", action="store_true", | |
943 help="resets any local changes before updating (git only)") | |
944 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", | |
945 help="sync deps for the specified (comma-separated) " | |
946 "platform(s); 'all' will sync all platforms") | |
947 parser.add_option("--manually_grab_svn_rev", action="store_true", | |
948 help="Skip svn up whenever possible by requesting " | |
949 "actual HEAD revision from the repository") | |
950 (options, args) = parser.parse_args(args) | |
951 client = GClient.LoadCurrentConfig(options) | 994 client = GClient.LoadCurrentConfig(options) |
952 | 995 |
953 if not client: | 996 if not client: |
954 raise gclient_utils.Error("client not configured; see 'gclient config'") | 997 raise gclient_utils.Error("client not configured; see 'gclient config'") |
955 | 998 |
956 if not options.head: | 999 if not options.head: |
957 solutions = client.GetVar('solutions') | 1000 solutions = client.GetVar('solutions') |
958 if solutions: | 1001 if solutions: |
959 for s in solutions: | 1002 for s in solutions: |
960 if s.get('safesync_url', ''): | 1003 if s.get('safesync_url', ''): |
(...skipping 12 matching lines...) Expand all Loading... |
973 if len(rev): | 1016 if len(rev): |
974 options.revisions.append(s['name']+'@'+rev) | 1017 options.revisions.append(s['name']+'@'+rev) |
975 | 1018 |
976 if options.verbose: | 1019 if options.verbose: |
977 # Print out the .gclient file. This is longer than if we just printed the | 1020 # Print out the .gclient file. This is longer than if we just printed the |
978 # client dict, but more legible, and it might contain helpful comments. | 1021 # client dict, but more legible, and it might contain helpful comments. |
979 print(client.ConfigContent()) | 1022 print(client.ConfigContent()) |
980 return client.RunOnDeps('update', args) | 1023 return client.RunOnDeps('update', args) |
981 | 1024 |
982 | 1025 |
983 def CMDupdate(parser, args): | 1026 def CMDupdate(parser, options, args): |
984 """Alias for the sync command. Deprecated.""" | 1027 """Alias for the sync command. Deprecated.""" |
985 return CMDsync(parser, args) | 1028 return CMDsync(parser, options, args) |
986 | 1029 |
987 def CMDdiff(parser, args): | 1030 |
988 """Displays local diff for every dependencies.""" | 1031 def CMDdiff(parser, options, args): |
989 (options, args) = parser.parse_args(args) | 1032 """Display the differences between two revisions of modules. |
| 1033 |
| 1034 (Does 'svn diff' for each checked out module and dependences.) |
| 1035 Additional args and options to 'svn diff' can be passed after |
| 1036 gclient options. |
| 1037 |
| 1038 usage: diff [options] [--] [svn args/options] |
| 1039 |
| 1040 Valid options: |
| 1041 --verbose : output additional diagnostics |
| 1042 |
| 1043 Examples: |
| 1044 gclient diff |
| 1045 simple 'svn diff' for configured client and dependences |
| 1046 gclient diff -- -x -b |
| 1047 use 'svn diff -x -b' to suppress whitespace-only differences |
| 1048 gclient diff -- -r HEAD -x -b |
| 1049 diff versus the latest version of each module |
| 1050 """ |
990 client = GClient.LoadCurrentConfig(options) | 1051 client = GClient.LoadCurrentConfig(options) |
991 if not client: | 1052 if not client: |
992 raise gclient_utils.Error("client not configured; see 'gclient config'") | 1053 raise gclient_utils.Error("client not configured; see 'gclient config'") |
993 if options.verbose: | 1054 if options.verbose: |
994 # Print out the .gclient file. This is longer than if we just printed the | 1055 # Print out the .gclient file. This is longer than if we just printed the |
995 # client dict, but more legible, and it might contain helpful comments. | 1056 # client dict, but more legible, and it might contain helpful comments. |
996 print(client.ConfigContent()) | 1057 print(client.ConfigContent()) |
997 return client.RunOnDeps('diff', args) | 1058 return client.RunOnDeps('diff', args) |
998 | 1059 |
999 | 1060 |
1000 def CMDrevert(parser, args): | 1061 def CMDrevert(parser, options, args): |
1001 """Revert all modifications in every dependencies.""" | 1062 """Revert every file in every managed directory in the client view.""" |
1002 parser.add_option("--nohooks", action="store_true", | |
1003 help="don't run hooks after the revert is complete") | |
1004 (options, args) = parser.parse_args(args) | |
1005 # --force is implied. | |
1006 options.force = True | |
1007 client = GClient.LoadCurrentConfig(options) | 1063 client = GClient.LoadCurrentConfig(options) |
1008 if not client: | 1064 if not client: |
1009 raise gclient_utils.Error("client not configured; see 'gclient config'") | 1065 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1010 return client.RunOnDeps('revert', args) | 1066 return client.RunOnDeps('revert', args) |
1011 | 1067 |
1012 | 1068 |
1013 def CMDrunhooks(parser, args): | 1069 def CMDrunhooks(parser, options, args): |
1014 """Runs hooks for files that have been modified in the local working copy.""" | 1070 """Runs hooks for files that have been modified in the local working copy. |
1015 parser.add_option("--force", action="store_true", default=True, | 1071 |
1016 help="Deprecated. No effect.") | 1072 Implies --force. |
1017 (options, args) = parser.parse_args(args) | 1073 |
| 1074 usage: runhooks [options] |
| 1075 |
| 1076 Valid options: |
| 1077 --verbose : output additional diagnostics |
| 1078 """ |
1018 client = GClient.LoadCurrentConfig(options) | 1079 client = GClient.LoadCurrentConfig(options) |
1019 if not client: | 1080 if not client: |
1020 raise gclient_utils.Error("client not configured; see 'gclient config'") | 1081 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1021 if options.verbose: | 1082 if options.verbose: |
1022 # Print out the .gclient file. This is longer than if we just printed the | 1083 # Print out the .gclient file. This is longer than if we just printed the |
1023 # client dict, but more legible, and it might contain helpful comments. | 1084 # client dict, but more legible, and it might contain helpful comments. |
1024 print(client.ConfigContent()) | 1085 print(client.ConfigContent()) |
1025 options.force = True | 1086 options.force = True |
1026 options.nohooks = False | |
1027 return client.RunOnDeps('runhooks', args) | 1087 return client.RunOnDeps('runhooks', args) |
1028 | 1088 |
1029 | 1089 |
1030 def CMDrevinfo(parser, args): | 1090 def CMDrevinfo(parser, options, args): |
1031 """Outputs details for every dependencies.""" | 1091 """Outputs defails for every dependencies. |
1032 parser.add_option("--snapshot", action="store_true", | 1092 |
1033 help="create a snapshot file of the current " | 1093 This includes source path, server URL and revision information for every |
1034 "version of all repositories") | 1094 dependency in all solutions. |
1035 (options, args) = parser.parse_args(args) | 1095 |
| 1096 usage: revinfo [options] |
| 1097 """ |
| 1098 __pychecker__ = 'unusednames=args' |
1036 client = GClient.LoadCurrentConfig(options) | 1099 client = GClient.LoadCurrentConfig(options) |
1037 if not client: | 1100 if not client: |
1038 raise gclient_utils.Error("client not configured; see 'gclient config'") | 1101 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1039 client.PrintRevInfo() | 1102 client.PrintRevInfo() |
1040 return 0 | 1103 return 0 |
1041 | 1104 |
1042 | 1105 |
1043 def Command(name): | 1106 def CMDhelp(parser, options, args): |
1044 return getattr(sys.modules[__name__], 'CMD' + name, None) | 1107 """Prints general help or command-specific documentation.""" |
1045 | |
1046 | |
1047 def CMDhelp(parser, args): | |
1048 """Prints list of commands or help for a specific command.""" | |
1049 (options, args) = parser.parse_args(args) | |
1050 if len(args) == 1: | 1108 if len(args) == 1: |
1051 return Main(args + ['--help']) | 1109 command = Command(args[0]) |
| 1110 if command: |
| 1111 print getattr(sys.modules[__name__], 'CMD' + args[0]).__doc__ |
| 1112 return 0 |
| 1113 parser.usage = (DEFAULT_USAGE_TEXT + '\nCommands are:\n' + '\n'.join([ |
| 1114 ' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip()) |
| 1115 for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')])) |
1052 parser.print_help() | 1116 parser.print_help() |
1053 return 0 | 1117 return 0 |
1054 | 1118 |
1055 | 1119 |
1056 def GenUsage(parser, command): | 1120 def Command(command): |
1057 """Modify an OptParse object with the function's documentation.""" | 1121 return getattr(sys.modules[__name__], 'CMD' + command, CMDhelp) |
1058 obj = Command(command) | |
1059 if command == 'help': | |
1060 command = '<command>' | |
1061 # OptParser.description prefer nicely non-formatted strings. | |
1062 parser.description = re.sub('[\r\n ]{2,}', ' ', obj.__doc__) | |
1063 usage = getattr(obj, 'usage', '') | |
1064 parser.set_usage('%%prog %s [options] %s' % (command, usage)) | |
1065 parser.epilog = getattr(obj, 'epilog', None) | |
1066 | 1122 |
1067 | 1123 |
1068 def Main(argv): | 1124 def Main(argv): |
1069 """Doesn't parse the arguments here, just find the right subcommand to | 1125 parser = optparse.OptionParser(usage=DEFAULT_USAGE_TEXT, |
1070 execute.""" | 1126 version='%prog ' + __version__) |
1071 # Do it late so all commands are listed. | |
1072 CMDhelp.usage = ('\n\nCommands are:\n' + '\n'.join([ | |
1073 ' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip()) | |
1074 for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')])) | |
1075 parser = optparse.OptionParser(version='%prog ' + __version__) | |
1076 parser.add_option("-v", "--verbose", action="count", default=0, | 1127 parser.add_option("-v", "--verbose", action="count", default=0, |
1077 help="Produces additional output for diagnostics. Can be " | 1128 help="Produces additional output for diagnostics. Can be " |
1078 "used up to three times for more logging info.") | 1129 "used up to three times for more logging info.") |
1079 parser.add_option("--gclientfile", metavar="FILENAME", dest="config_filename", | 1130 parser.add_option("--gclientfile", metavar="FILENAME", dest="config_filename", |
1080 default=os.environ.get("GCLIENT_FILE", ".gclient"), | 1131 default=os.environ.get("GCLIENT_FILE", ".gclient"), |
1081 help="Specify an alternate .gclient file") | 1132 help="Specify an alternate .gclient file") |
| 1133 # The other options will be moved eventually. |
| 1134 parser.add_option("--force", action="store_true", |
| 1135 help="(update/sync only) force update even " |
| 1136 "for modules which haven't changed") |
| 1137 parser.add_option("--nohooks", action="store_true", |
| 1138 help="(update/sync/revert only) prevent the hooks " |
| 1139 "from running") |
| 1140 parser.add_option("--revision", action="append", dest="revisions", |
| 1141 metavar="REV", default=[], |
| 1142 help="(update/sync only) sync to a specific " |
| 1143 "revision, can be used multiple times for " |
| 1144 "each solution, e.g. --revision=src@123, " |
| 1145 "--revision=internal@32") |
| 1146 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", |
| 1147 help="(update/sync only) sync deps for the " |
| 1148 "specified (comma-separated) platform(s); " |
| 1149 "'all' will sync all platforms") |
| 1150 parser.add_option("--reset", action="store_true", |
| 1151 help="(update/sync only) resets any local changes " |
| 1152 "before updating (git only)") |
| 1153 parser.add_option("--spec", |
| 1154 help="(config only) create a gclient file " |
| 1155 "containing the provided string") |
| 1156 parser.add_option("--manually_grab_svn_rev", action="store_true", |
| 1157 help="Skip svn up whenever possible by requesting " |
| 1158 "actual HEAD revision from the repository") |
| 1159 parser.add_option("--head", action="store_true", |
| 1160 help="skips any safesync_urls specified in " |
| 1161 "configured solutions") |
| 1162 parser.add_option("--delete_unversioned_trees", action="store_true", |
| 1163 help="on update, delete any unexpected " |
| 1164 "unversioned trees that are in the checkout") |
| 1165 parser.add_option("--snapshot", action="store_true", |
| 1166 help="(revinfo only), create a snapshot file " |
| 1167 "of the current version of all repositories") |
| 1168 parser.add_option("--name", |
| 1169 help="specify alternate relative solution path") |
1082 # Integrate standard options processing. | 1170 # Integrate standard options processing. |
1083 old_parser = parser.parse_args | 1171 old_parser = parser.parse_args |
1084 def Parse(args): | 1172 def Parse(args): |
1085 (options, args) = old_parser(args) | 1173 (options, args) = old_parser(args) |
1086 if options.verbose == 2: | 1174 if options.verbose == 2: |
1087 logging.basicConfig(level=logging.INFO) | 1175 logging.basicConfig(level=logging.INFO) |
1088 elif options.verbose > 2: | 1176 elif options.verbose > 2: |
1089 logging.basicConfig(level=logging.DEBUG) | 1177 logging.basicConfig(level=logging.DEBUG) |
1090 options.entries_filename = options.config_filename + "_entries" | 1178 options.entries_filename = options.config_filename + "_entries" |
1091 if not hasattr(options, 'revisions'): | |
1092 # GClient.RunOnDeps expects it even if not applicable. | |
1093 options.revisions = [] | |
1094 return (options, args) | 1179 return (options, args) |
1095 parser.parse_args = Parse | 1180 parser.parse_args = Parse |
1096 # We don't want wordwrapping in epilog (usually examples) | 1181 # We don't want wordwrapping in epilog (usually examples) |
1097 parser.format_epilog = lambda _: parser.epilog or '' | 1182 parser.format_epilog = lambda _: parser.epilog or '' |
1098 if argv: | 1183 |
1099 command = Command(argv[0]) | 1184 if not len(argv): |
1100 if command: | 1185 argv = ['help'] |
1101 # "fix" the usage and the description now that we know the subcommand. | 1186 # Add manual support for --version as first argument. |
1102 GenUsage(parser, argv[0]) | 1187 if argv[0] == '--version': |
1103 return command(parser, argv[1:]) | 1188 parser.print_version() |
1104 # Not a known command. Default to help. | 1189 return 0 |
1105 GenUsage(parser, 'help') | 1190 # Add manual support for --help as first argument. |
1106 return CMDhelp(parser, argv) | 1191 if argv[0] == '--help': |
| 1192 argv[0] = 'help' |
| 1193 options, args = parser.parse_args(argv[1:]) |
| 1194 return Command(argv[0])(parser, options, args) |
1107 | 1195 |
1108 | 1196 |
1109 if "__main__" == __name__: | 1197 if "__main__" == __name__: |
1110 try: | 1198 try: |
1111 sys.exit(Main(sys.argv[1:])) | 1199 sys.exit(Main(sys.argv[1:])) |
1112 except gclient_utils.Error, e: | 1200 except gclient_utils.Error, e: |
1113 print >> sys.stderr, "Error: %s" % str(e) | 1201 print >> sys.stderr, "Error: %s" % str(e) |
1114 sys.exit(1) | 1202 sys.exit(1) |
1115 | 1203 |
1116 # vim: ts=2:sw=2:tw=80:et: | 1204 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |