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.3.7" | 58 __version__ = "0.4" |
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 | |
92 | 76 |
93 def attr(attr, data): | 77 def attr(attr, data): |
94 """Sets an attribute on a function.""" | 78 """Sets an attribute on a function.""" |
95 def hook(fn): | 79 def hook(fn): |
96 setattr(fn, attr, data) | 80 setattr(fn, attr, data) |
97 return fn | 81 return fn |
98 return hook | 82 return hook |
99 | 83 |
100 | 84 |
101 ## GClient implementation. | 85 ## GClient implementation. |
(...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
806 for x in sorted(entries.keys())])) | 790 for x in sorted(entries.keys())])) |
807 | 791 |
808 # Print the snapshot configuration file | 792 # Print the snapshot configuration file |
809 if self._options.snapshot: | 793 if self._options.snapshot: |
810 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} | 794 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} |
811 snapclient = GClient(self._root_dir, self._options) | 795 snapclient = GClient(self._root_dir, self._options) |
812 snapclient.SetConfig(config) | 796 snapclient.SetConfig(config) |
813 print(snapclient._config_content) | 797 print(snapclient._config_content) |
814 | 798 |
815 | 799 |
816 ## gclient commands. | 800 #### gclient commands. |
817 | 801 |
818 | 802 |
819 def CMDcleanup(parser, options, args): | 803 def CMDcleanup(parser, args): |
820 """Clean up all working copies, using 'svn cleanup' for each module. | 804 """Cleans up all working copies. |
821 | 805 |
822 Additional options and args may be passed to 'svn cleanup'. | 806 Mostly svn-specific. Simply runs 'svn cleanup' for each module. |
823 | |
824 usage: cleanup [options] [--] [svn cleanup args/options] | |
825 | |
826 Valid options: | |
827 --verbose : output additional diagnostics | |
828 """ | 807 """ |
| 808 (options, args) = parser.parse_args(args) |
829 client = GClient.LoadCurrentConfig(options) | 809 client = GClient.LoadCurrentConfig(options) |
830 if not client: | 810 if not client: |
831 raise gclient_utils.Error("client not configured; see 'gclient config'") | 811 raise gclient_utils.Error("client not configured; see 'gclient config'") |
832 if options.verbose: | 812 if options.verbose: |
833 # Print out the .gclient file. This is longer than if we just printed the | 813 # Print out the .gclient file. This is longer than if we just printed the |
834 # client dict, but more legible, and it might contain helpful comments. | 814 # client dict, but more legible, and it might contain helpful comments. |
835 print(client.ConfigContent()) | 815 print(client.ConfigContent()) |
836 return client.RunOnDeps('cleanup', args) | 816 return client.RunOnDeps('cleanup', args) |
837 | 817 |
838 | 818 |
839 def CMDconfig(parser, options, args): | 819 @attr('usage', '[url] [safesync url]') |
| 820 def CMDconfig(parser, args): |
840 """Create a .gclient file in the current directory. | 821 """Create a .gclient file in the current directory. |
841 | 822 |
842 This specifies the configuration for further commands. After update/sync, | 823 This specifies the configuration for further commands. After update/sync, |
843 top-level DEPS files in each module are read to determine dependent | 824 top-level DEPS files in each module are read to determine dependent |
844 modules to operate on as well. If optional [url] parameter is | 825 modules to operate on as well. If optional [url] parameter is |
845 provided, then configuration is read from a specified Subversion server | 826 provided, then configuration is read from a specified Subversion server |
846 URL. Otherwise, a --spec option must be provided. A --name option overrides | 827 URL. |
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":{}}]' | |
864 """ | 828 """ |
| 829 parser.add_option("--spec", |
| 830 help="create a gclient file containing the provided " |
| 831 "string. Due to Cygwin/Python brokenness, it " |
| 832 "probably can't contain any newlines.") |
| 833 parser.add_option("--name", |
| 834 help="overrides the default name for the solution") |
| 835 (options, args) = parser.parse_args(args) |
865 if len(args) < 1 and not options.spec: | 836 if len(args) < 1 and not options.spec: |
866 raise gclient_utils.Error("required argument missing; see 'gclient help " | 837 raise gclient_utils.Error("required argument missing; see 'gclient help " |
867 "config'") | 838 "config'") |
868 if os.path.exists(options.config_filename): | 839 if os.path.exists(options.config_filename): |
869 raise gclient_utils.Error("%s file already exists in the current directory" | 840 raise gclient_utils.Error("%s file already exists in the current directory" |
870 % options.config_filename) | 841 % options.config_filename) |
871 client = GClient('.', options) | 842 client = GClient('.', options) |
872 if options.spec: | 843 if options.spec: |
873 client.SetConfig(options.spec) | 844 client.SetConfig(options.spec) |
874 else: | 845 else: |
875 base_url = args[0].rstrip('/') | 846 base_url = args[0].rstrip('/') |
876 if not options.name: | 847 if not options.name: |
877 name = base_url.split("/")[-1] | 848 name = base_url.split("/")[-1] |
878 else: | 849 else: |
879 # specify an alternate relpath for the given URL. | 850 # specify an alternate relpath for the given URL. |
880 name = options.name | 851 name = options.name |
881 safesync_url = "" | 852 safesync_url = "" |
882 if len(args) > 1: | 853 if len(args) > 1: |
883 safesync_url = args[1] | 854 safesync_url = args[1] |
884 client.SetDefaultConfig(name, base_url, safesync_url) | 855 client.SetDefaultConfig(name, base_url, safesync_url) |
885 client.SaveConfig() | 856 client.SaveConfig() |
886 return 0 | 857 return 0 |
887 | 858 |
888 | 859 |
889 def CMDexport(parser, options, args): | 860 def CMDexport(parser, args): |
890 """Wrapper for svn export for all managed directories.""" | 861 """Wrapper for svn export for all managed directories.""" |
| 862 (options, args) = parser.parse_args(args) |
891 if len(args) != 1: | 863 if len(args) != 1: |
892 raise gclient_utils.Error("Need directory name") | 864 raise gclient_utils.Error("Need directory name") |
893 client = GClient.LoadCurrentConfig(options) | 865 client = GClient.LoadCurrentConfig(options) |
894 | 866 |
895 if not client: | 867 if not client: |
896 raise gclient_utils.Error("client not configured; see 'gclient config'") | 868 raise gclient_utils.Error("client not configured; see 'gclient config'") |
897 | 869 |
898 if options.verbose: | 870 if options.verbose: |
899 # Print out the .gclient file. This is longer than if we just printed the | 871 # Print out the .gclient file. This is longer than if we just printed the |
900 # client dict, but more legible, and it might contain helpful comments. | 872 # client dict, but more legible, and it might contain helpful comments. |
901 print(client.ConfigContent()) | 873 print(client.ConfigContent()) |
902 return client.RunOnDeps('export', args) | 874 return client.RunOnDeps('export', args) |
903 | 875 |
904 | 876 |
905 def CMDpack(parser, options, args): | 877 @attr('epilog', """Example: |
| 878 gclient pack > patch.txt |
| 879 generate simple patch for configured client and dependences |
| 880 """) |
| 881 def CMDpack(parser, args): |
906 """Generate a patch which can be applied at the root of the tree. | 882 """Generate a patch which can be applied at the root of the tree. |
907 | 883 |
908 Internally, runs 'svn diff' on each checked out module and | 884 Internally, runs 'svn diff'/'git diff' on each checked out module and |
909 dependencies, and performs minimal postprocessing of the output. The | 885 dependencies, and performs minimal postprocessing of the output. The |
910 resulting patch is printed to stdout and can be applied to a freshly | 886 resulting patch is printed to stdout and can be applied to a freshly |
911 checked out tree via 'patch -p0 < patchfile'. Additional args and | 887 checked out tree via 'patch -p0 < patchfile'. |
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 | |
928 """ | 888 """ |
| 889 (options, args) = parser.parse_args(args) |
929 client = GClient.LoadCurrentConfig(options) | 890 client = GClient.LoadCurrentConfig(options) |
930 if not client: | 891 if not client: |
931 raise gclient_utils.Error("client not configured; see 'gclient config'") | 892 raise gclient_utils.Error("client not configured; see 'gclient config'") |
932 if options.verbose: | 893 if options.verbose: |
933 # Print out the .gclient file. This is longer than if we just printed the | 894 # Print out the .gclient file. This is longer than if we just printed the |
934 # client dict, but more legible, and it might contain helpful comments. | 895 # client dict, but more legible, and it might contain helpful comments. |
935 print(client.ConfigContent()) | 896 print(client.ConfigContent()) |
936 return client.RunOnDeps('pack', args) | 897 return client.RunOnDeps('pack', args) |
937 | 898 |
938 | 899 |
939 def CMDstatus(parser, options, args): | 900 def CMDstatus(parser, args): |
940 """Show the modification status of for every dependencies. | 901 """Show modification status for every dependencies.""" |
941 | 902 (options, args) = parser.parse_args(args) |
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 """ | |
950 client = GClient.LoadCurrentConfig(options) | 903 client = GClient.LoadCurrentConfig(options) |
951 if not client: | 904 if not client: |
952 raise gclient_utils.Error("client not configured; see 'gclient config'") | 905 raise gclient_utils.Error("client not configured; see 'gclient config'") |
953 if options.verbose: | 906 if options.verbose: |
954 # Print out the .gclient file. This is longer than if we just printed the | 907 # Print out the .gclient file. This is longer than if we just printed the |
955 # client dict, but more legible, and it might contain helpful comments. | 908 # client dict, but more legible, and it might contain helpful comments. |
956 print(client.ConfigContent()) | 909 print(client.ConfigContent()) |
957 return client.RunOnDeps('status', args) | 910 return client.RunOnDeps('status', args) |
958 | 911 |
959 | 912 |
960 def CMDsync(parser, options, args): | 913 @attr('epilog', """Examples: |
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: | |
985 gclient sync | 914 gclient sync |
986 update files from SCM according to current configuration, | 915 update files from SCM according to current configuration, |
987 *for modules which have changed since last update or sync* | 916 *for modules which have changed since last update or sync* |
988 gclient sync --force | 917 gclient sync --force |
989 update files from SCM according to current configuration, for | 918 update files from SCM according to current configuration, for |
990 all modules (useful for recovering files deleted from local copy) | 919 all modules (useful for recovering files deleted from local copy) |
991 gclient sync --revision src@31000 | 920 gclient sync --revision src@31000 |
992 update src directory to r31000 | 921 update src directory to r31000 |
993 """ | 922 """) |
| 923 def CMDsync(parser, args): |
| 924 """Checkout/update all modules.""" |
| 925 parser.add_option("--force", action="store_true", |
| 926 help="force update even for unchanged modules") |
| 927 parser.add_option("--nohooks", action="store_true", |
| 928 help="don't run hooks after the update is complete") |
| 929 parser.add_option("-r", "--revision", action="append", |
| 930 dest="revisions", metavar="REV", default=[], |
| 931 help="update given solution to specified revision, " |
| 932 "can be used multiple times for each solution, " |
| 933 "e.g. -r src@123, -r internal@32") |
| 934 parser.add_option("--head", action="store_true", |
| 935 help="skips any safesync_urls specified in " |
| 936 "configured solutions and sync to head instead") |
| 937 parser.add_option("--delete_unversioned_trees", action="store_true", |
| 938 help="delete any unexpected unversioned trees " |
| 939 "that are in the checkout") |
| 940 parser.add_option("--reset", action="store_true", |
| 941 help="resets any local changes before updating (git only)") |
| 942 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST", |
| 943 help="sync deps for the specified (comma-separated) " |
| 944 "platform(s); 'all' will sync all platforms") |
| 945 parser.add_option("--manually_grab_svn_rev", action="store_true", |
| 946 help="Skip svn up whenever possible by requesting " |
| 947 "actual HEAD revision from the repository") |
| 948 (options, args) = parser.parse_args(args) |
994 client = GClient.LoadCurrentConfig(options) | 949 client = GClient.LoadCurrentConfig(options) |
995 | 950 |
996 if not client: | 951 if not client: |
997 raise gclient_utils.Error("client not configured; see 'gclient config'") | 952 raise gclient_utils.Error("client not configured; see 'gclient config'") |
998 | 953 |
999 if not options.head: | 954 if not options.head: |
1000 solutions = client.GetVar('solutions') | 955 solutions = client.GetVar('solutions') |
1001 if solutions: | 956 if solutions: |
1002 for s in solutions: | 957 for s in solutions: |
1003 if s.get('safesync_url', ''): | 958 if s.get('safesync_url', ''): |
(...skipping 12 matching lines...) Expand all Loading... |
1016 if len(rev): | 971 if len(rev): |
1017 options.revisions.append(s['name']+'@'+rev) | 972 options.revisions.append(s['name']+'@'+rev) |
1018 | 973 |
1019 if options.verbose: | 974 if options.verbose: |
1020 # Print out the .gclient file. This is longer than if we just printed the | 975 # Print out the .gclient file. This is longer than if we just printed the |
1021 # client dict, but more legible, and it might contain helpful comments. | 976 # client dict, but more legible, and it might contain helpful comments. |
1022 print(client.ConfigContent()) | 977 print(client.ConfigContent()) |
1023 return client.RunOnDeps('update', args) | 978 return client.RunOnDeps('update', args) |
1024 | 979 |
1025 | 980 |
1026 def CMDupdate(parser, options, args): | 981 def CMDupdate(parser, args): |
1027 """Alias for the sync command. Deprecated.""" | 982 """Alias for the sync command. Deprecated.""" |
1028 return CMDsync(parser, options, args) | 983 return CMDsync(parser, args) |
1029 | 984 |
1030 | 985 def CMDdiff(parser, args): |
1031 def CMDdiff(parser, options, args): | 986 """Displays local diff for every dependencies.""" |
1032 """Display the differences between two revisions of modules. | 987 (options, args) = parser.parse_args(args) |
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 """ | |
1051 client = GClient.LoadCurrentConfig(options) | 988 client = GClient.LoadCurrentConfig(options) |
1052 if not client: | 989 if not client: |
1053 raise gclient_utils.Error("client not configured; see 'gclient config'") | 990 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1054 if options.verbose: | 991 if options.verbose: |
1055 # Print out the .gclient file. This is longer than if we just printed the | 992 # Print out the .gclient file. This is longer than if we just printed the |
1056 # client dict, but more legible, and it might contain helpful comments. | 993 # client dict, but more legible, and it might contain helpful comments. |
1057 print(client.ConfigContent()) | 994 print(client.ConfigContent()) |
1058 return client.RunOnDeps('diff', args) | 995 return client.RunOnDeps('diff', args) |
1059 | 996 |
1060 | 997 |
1061 def CMDrevert(parser, options, args): | 998 def CMDrevert(parser, args): |
1062 """Revert every file in every managed directory in the client view.""" | 999 """Revert all modifications in every dependencies.""" |
| 1000 parser.add_option("--nohooks", action="store_true", |
| 1001 help="don't run hooks after the revert is complete") |
| 1002 (options, args) = parser.parse_args(args) |
1063 client = GClient.LoadCurrentConfig(options) | 1003 client = GClient.LoadCurrentConfig(options) |
1064 if not client: | 1004 if not client: |
1065 raise gclient_utils.Error("client not configured; see 'gclient config'") | 1005 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1066 return client.RunOnDeps('revert', args) | 1006 return client.RunOnDeps('revert', args) |
1067 | 1007 |
1068 | 1008 |
1069 def CMDrunhooks(parser, options, args): | 1009 def CMDrunhooks(parser, args): |
1070 """Runs hooks for files that have been modified in the local working copy. | 1010 """Runs hooks for files that have been modified in the local working copy.""" |
1071 | 1011 parser.add_option("--force", action="store_true", default=True, |
1072 Implies --force. | 1012 help="Deprecated. No effect.") |
1073 | 1013 (options, args) = parser.parse_args(args) |
1074 usage: runhooks [options] | |
1075 | |
1076 Valid options: | |
1077 --verbose : output additional diagnostics | |
1078 """ | |
1079 client = GClient.LoadCurrentConfig(options) | 1014 client = GClient.LoadCurrentConfig(options) |
1080 if not client: | 1015 if not client: |
1081 raise gclient_utils.Error("client not configured; see 'gclient config'") | 1016 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1082 if options.verbose: | 1017 if options.verbose: |
1083 # Print out the .gclient file. This is longer than if we just printed the | 1018 # Print out the .gclient file. This is longer than if we just printed the |
1084 # client dict, but more legible, and it might contain helpful comments. | 1019 # client dict, but more legible, and it might contain helpful comments. |
1085 print(client.ConfigContent()) | 1020 print(client.ConfigContent()) |
1086 options.force = True | 1021 options.force = True |
1087 return client.RunOnDeps('runhooks', args) | 1022 return client.RunOnDeps('runhooks', args) |
1088 | 1023 |
1089 | 1024 |
1090 def CMDrevinfo(parser, options, args): | 1025 def CMDrevinfo(parser, args): |
1091 """Outputs defails for every dependencies. | 1026 """Outputs details for every dependencies.""" |
1092 | 1027 parser.add_option("--snapshot", action="store_true", |
1093 This includes source path, server URL and revision information for every | 1028 help="create a snapshot file of the current " |
1094 dependency in all solutions. | 1029 "version of all repositories") |
1095 | 1030 (options, args) = parser.parse_args(args) |
1096 usage: revinfo [options] | |
1097 """ | |
1098 __pychecker__ = 'unusednames=args' | |
1099 client = GClient.LoadCurrentConfig(options) | 1031 client = GClient.LoadCurrentConfig(options) |
1100 if not client: | 1032 if not client: |
1101 raise gclient_utils.Error("client not configured; see 'gclient config'") | 1033 raise gclient_utils.Error("client not configured; see 'gclient config'") |
1102 client.PrintRevInfo() | 1034 client.PrintRevInfo() |
1103 return 0 | 1035 return 0 |
1104 | 1036 |
1105 | 1037 |
1106 def CMDhelp(parser, options, args): | 1038 def Command(name): |
1107 """Prints general help or command-specific documentation.""" | 1039 return getattr(sys.modules[__name__], 'CMD' + name, None) |
| 1040 |
| 1041 |
| 1042 def CMDhelp(parser, args): |
| 1043 """Prints list of commands or help for a specific command.""" |
| 1044 (options, args) = parser.parse_args(args) |
1108 if len(args) == 1: | 1045 if len(args) == 1: |
1109 command = Command(args[0]) | 1046 return Main(args + ['--help']) |
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')])) | |
1116 parser.print_help() | 1047 parser.print_help() |
1117 return 0 | 1048 return 0 |
1118 | 1049 |
1119 | 1050 |
1120 def Command(command): | 1051 def GenUsage(parser, command): |
1121 return getattr(sys.modules[__name__], 'CMD' + command, CMDhelp) | 1052 """Modify an OptParse object with the function's documentation.""" |
| 1053 obj = Command(command) |
| 1054 if command == 'help': |
| 1055 command = '<command>' |
| 1056 # OptParser.description prefer nicely non-formatted strings. |
| 1057 parser.description = re.sub('[\r\n ]{2,}', ' ', obj.__doc__) |
| 1058 usage = getattr(obj, 'usage', '') |
| 1059 parser.set_usage('%%prog %s [options] %s' % (command, usage)) |
| 1060 parser.epilog = getattr(obj, 'epilog', None) |
1122 | 1061 |
1123 | 1062 |
1124 def Main(argv): | 1063 def Main(argv): |
1125 parser = optparse.OptionParser(usage=DEFAULT_USAGE_TEXT, | 1064 """Doesn't parse the arguments here, just find the right subcommand to |
1126 version='%prog ' + __version__) | 1065 execute.""" |
| 1066 # Do it late so all commands are listed. |
| 1067 CMDhelp.usage = ('\n\nCommands are:\n' + '\n'.join([ |
| 1068 ' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip()) |
| 1069 for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')])) |
| 1070 parser = optparse.OptionParser(version='%prog ' + __version__) |
1127 parser.add_option("-v", "--verbose", action="count", default=0, | 1071 parser.add_option("-v", "--verbose", action="count", default=0, |
1128 help="Produces additional output for diagnostics. Can be " | 1072 help="Produces additional output for diagnostics. Can be " |
1129 "used up to three times for more logging info.") | 1073 "used up to three times for more logging info.") |
1130 parser.add_option("--gclientfile", metavar="FILENAME", dest="config_filename", | 1074 parser.add_option("--gclientfile", metavar="FILENAME", dest="config_filename", |
1131 default=os.environ.get("GCLIENT_FILE", ".gclient"), | 1075 default=os.environ.get("GCLIENT_FILE", ".gclient"), |
1132 help="Specify an alternate .gclient file") | 1076 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") | |
1170 # Integrate standard options processing. | 1077 # Integrate standard options processing. |
1171 old_parser = parser.parse_args | 1078 old_parser = parser.parse_args |
1172 def Parse(args): | 1079 def Parse(args): |
1173 (options, args) = old_parser(args) | 1080 (options, args) = old_parser(args) |
1174 if options.verbose == 2: | 1081 if options.verbose == 2: |
1175 logging.basicConfig(level=logging.INFO) | 1082 logging.basicConfig(level=logging.INFO) |
1176 elif options.verbose > 2: | 1083 elif options.verbose > 2: |
1177 logging.basicConfig(level=logging.DEBUG) | 1084 logging.basicConfig(level=logging.DEBUG) |
1178 options.entries_filename = options.config_filename + "_entries" | 1085 options.entries_filename = options.config_filename + "_entries" |
1179 return (options, args) | 1086 return (options, args) |
1180 parser.parse_args = Parse | 1087 parser.parse_args = Parse |
1181 # We don't want wordwrapping in epilog (usually examples) | 1088 # We don't want wordwrapping in epilog (usually examples) |
1182 parser.format_epilog = lambda _: parser.epilog or '' | 1089 parser.format_epilog = lambda _: parser.epilog or '' |
1183 | 1090 if argv: |
1184 if not len(argv): | 1091 command = Command(argv[0]) |
1185 argv = ['help'] | 1092 if command: |
1186 # Add manual support for --version as first argument. | 1093 # "fix" the usage and the description now that we know the subcommand. |
1187 if argv[0] == '--version': | 1094 GenUsage(parser, argv[0]) |
1188 parser.print_version() | 1095 return command(parser, argv[1:]) |
1189 return 0 | 1096 # Not a known command. Default to help. |
1190 # Add manual support for --help as first argument. | 1097 GenUsage(parser, 'help') |
1191 if argv[0] == '--help': | 1098 return CMDhelp(parser, argv) |
1192 argv[0] = 'help' | |
1193 options, args = parser.parse_args(argv[1:]) | |
1194 return Command(argv[0])(parser, options, args) | |
1195 | 1099 |
1196 | 1100 |
1197 if "__main__" == __name__: | 1101 if "__main__" == __name__: |
1198 try: | 1102 try: |
1199 sys.exit(Main(sys.argv[1:])) | 1103 sys.exit(Main(sys.argv[1:])) |
1200 except gclient_utils.Error, e: | 1104 except gclient_utils.Error, e: |
1201 print >> sys.stderr, "Error: %s" % str(e) | 1105 print >> sys.stderr, "Error: %s" % str(e) |
1202 sys.exit(1) | 1106 sys.exit(1) |
1203 | 1107 |
1204 # vim: ts=2:sw=2:tw=80:et: | 1108 # vim: ts=2:sw=2:tw=80:et: |
OLD | NEW |