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

Side by Side Diff: gclient.py

Issue 2265002: Reapply 48271 with fix (again) (Closed)
Patch Set: Another fix + more smoke tests Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « PRESUBMIT.py ('k') | tests/fake_repos.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 "From": self.FromImpl, 331 "From": self.FromImpl,
348 "Var": var.Lookup, 332 "Var": var.Lookup,
349 "deps_os": {}, 333 "deps_os": {},
350 } 334 }
351 exec(solution_deps_content, global_scope, local_scope) 335 exec(solution_deps_content, global_scope, local_scope)
352 deps = local_scope.get("deps", {}) 336 deps = local_scope.get("deps", {})
353 337
354 # load os specific dependencies if defined. these dependencies may 338 # load os specific dependencies if defined. these dependencies may
355 # override or extend the values defined by the 'deps' member. 339 # override or extend the values defined by the 'deps' member.
356 if "deps_os" in local_scope: 340 if "deps_os" in local_scope:
357
358 if self._options.deps_os is not None: 341 if self._options.deps_os is not None:
359 deps_to_include = self._options.deps_os.split(",") 342 deps_to_include = self._options.deps_os.split(",")
360 if "all" in deps_to_include: 343 if "all" in deps_to_include:
361 deps_to_include = list(set(self.deps_os_choices.itervalues())) 344 deps_to_include = list(set(self.deps_os_choices.itervalues()))
362 else: 345 else:
363 deps_to_include = [self.deps_os_choices.get(sys.platform, "unix")] 346 deps_to_include = [self.deps_os_choices.get(sys.platform, "unix")]
364 347
365 deps_to_include = set(deps_to_include) 348 deps_to_include = set(deps_to_include)
366 for deps_os_key in deps_to_include: 349 for deps_os_key in deps_to_include:
367 os_deps = local_scope["deps_os"].get(deps_os_key, {}) 350 os_deps = local_scope["deps_os"].get(deps_os_key, {})
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
463 if d in solution_urls and solution_urls[d] != url: 446 if d in solution_urls and solution_urls[d] != url:
464 raise gclient_utils.Error( 447 raise gclient_utils.Error(
465 "Dependency \"%s\" conflicts with specified solution" % d) 448 "Dependency \"%s\" conflicts with specified solution" % d)
466 # Grab the dependency. 449 # Grab the dependency.
467 deps[d] = url 450 deps[d] = url
468 return deps 451 return deps
469 452
470 def _RunHookAction(self, hook_dict, matching_file_list): 453 def _RunHookAction(self, hook_dict, matching_file_list):
471 """Runs the action from a single hook. 454 """Runs the action from a single hook.
472 """ 455 """
456 logging.info(hook_dict)
457 logging.info(matching_file_list)
473 command = hook_dict['action'][:] 458 command = hook_dict['action'][:]
474 if command[0] == 'python': 459 if command[0] == 'python':
475 # If the hook specified "python" as the first item, the action is a 460 # If the hook specified "python" as the first item, the action is a
476 # Python script. Run it by starting a new copy of the same 461 # Python script. Run it by starting a new copy of the same
477 # interpreter. 462 # interpreter.
478 command[0] = sys.executable 463 command[0] = sys.executable
479 464
480 if '$matching_files' in command: 465 if '$matching_files' in command:
481 splice_index = command.index('$matching_files') 466 splice_index = command.index('$matching_files')
482 command[splice_index:splice_index + 1] = matching_file_list 467 command[splice_index:splice_index + 1] = matching_file_list
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
806 for x in sorted(entries.keys())])) 791 for x in sorted(entries.keys())]))
807 792
808 # Print the snapshot configuration file 793 # Print the snapshot configuration file
809 if self._options.snapshot: 794 if self._options.snapshot:
810 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient} 795 config = self.DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient}
811 snapclient = GClient(self._root_dir, self._options) 796 snapclient = GClient(self._root_dir, self._options)
812 snapclient.SetConfig(config) 797 snapclient.SetConfig(config)
813 print(snapclient._config_content) 798 print(snapclient._config_content)
814 799
815 800
816 ## gclient commands. 801 #### gclient commands.
817 802
818 803
819 def CMDcleanup(parser, options, args): 804 def CMDcleanup(parser, args):
820 """Clean up all working copies, using 'svn cleanup' for each module. 805 """Cleans up all working copies.
821 806
822 Additional options and args may be passed to 'svn cleanup'. 807 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 """ 808 """
809 (options, args) = parser.parse_args(args)
829 client = GClient.LoadCurrentConfig(options) 810 client = GClient.LoadCurrentConfig(options)
830 if not client: 811 if not client:
831 raise gclient_utils.Error("client not configured; see 'gclient config'") 812 raise gclient_utils.Error("client not configured; see 'gclient config'")
832 if options.verbose: 813 if options.verbose:
833 # Print out the .gclient file. This is longer than if we just printed the 814 # 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. 815 # client dict, but more legible, and it might contain helpful comments.
835 print(client.ConfigContent()) 816 print(client.ConfigContent())
836 return client.RunOnDeps('cleanup', args) 817 return client.RunOnDeps('cleanup', args)
837 818
838 819
839 def CMDconfig(parser, options, args): 820 @attr('usage', '[url] [safesync url]')
821 def CMDconfig(parser, args):
840 """Create a .gclient file in the current directory. 822 """Create a .gclient file in the current directory.
841 823
842 This specifies the configuration for further commands. After update/sync, 824 This specifies the configuration for further commands. After update/sync,
843 top-level DEPS files in each module are read to determine dependent 825 top-level DEPS files in each module are read to determine dependent
844 modules to operate on as well. If optional [url] parameter is 826 modules to operate on as well. If optional [url] parameter is
845 provided, then configuration is read from a specified Subversion server 827 provided, then configuration is read from a specified Subversion server
846 URL. Otherwise, a --spec option must be provided. A --name option overrides 828 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 """ 829 """
830 parser.add_option("--spec",
831 help="create a gclient file containing the provided "
832 "string. Due to Cygwin/Python brokenness, it "
833 "probably can't contain any newlines.")
834 parser.add_option("--name",
835 help="overrides the default name for the solution")
836 (options, args) = parser.parse_args(args)
865 if len(args) < 1 and not options.spec: 837 if len(args) < 1 and not options.spec:
866 raise gclient_utils.Error("required argument missing; see 'gclient help " 838 raise gclient_utils.Error("required argument missing; see 'gclient help "
867 "config'") 839 "config'")
868 if os.path.exists(options.config_filename): 840 if os.path.exists(options.config_filename):
869 raise gclient_utils.Error("%s file already exists in the current directory" 841 raise gclient_utils.Error("%s file already exists in the current directory"
870 % options.config_filename) 842 % options.config_filename)
871 client = GClient('.', options) 843 client = GClient('.', options)
872 if options.spec: 844 if options.spec:
873 client.SetConfig(options.spec) 845 client.SetConfig(options.spec)
874 else: 846 else:
875 base_url = args[0].rstrip('/') 847 base_url = args[0].rstrip('/')
876 if not options.name: 848 if not options.name:
877 name = base_url.split("/")[-1] 849 name = base_url.split("/")[-1]
878 else: 850 else:
879 # specify an alternate relpath for the given URL. 851 # specify an alternate relpath for the given URL.
880 name = options.name 852 name = options.name
881 safesync_url = "" 853 safesync_url = ""
882 if len(args) > 1: 854 if len(args) > 1:
883 safesync_url = args[1] 855 safesync_url = args[1]
884 client.SetDefaultConfig(name, base_url, safesync_url) 856 client.SetDefaultConfig(name, base_url, safesync_url)
885 client.SaveConfig() 857 client.SaveConfig()
886 return 0 858 return 0
887 859
888 860
889 def CMDexport(parser, options, args): 861 def CMDexport(parser, args):
890 """Wrapper for svn export for all managed directories.""" 862 """Wrapper for svn export for all managed directories."""
863 (options, args) = parser.parse_args(args)
891 if len(args) != 1: 864 if len(args) != 1:
892 raise gclient_utils.Error("Need directory name") 865 raise gclient_utils.Error("Need directory name")
893 client = GClient.LoadCurrentConfig(options) 866 client = GClient.LoadCurrentConfig(options)
894 867
895 if not client: 868 if not client:
896 raise gclient_utils.Error("client not configured; see 'gclient config'") 869 raise gclient_utils.Error("client not configured; see 'gclient config'")
897 870
898 if options.verbose: 871 if options.verbose:
899 # Print out the .gclient file. This is longer than if we just printed the 872 # 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. 873 # client dict, but more legible, and it might contain helpful comments.
901 print(client.ConfigContent()) 874 print(client.ConfigContent())
902 return client.RunOnDeps('export', args) 875 return client.RunOnDeps('export', args)
903 876
904 877
905 def CMDpack(parser, options, args): 878 @attr('epilog', """Example:
879 gclient pack > patch.txt
880 generate simple patch for configured client and dependences
881 """)
882 def CMDpack(parser, args):
906 """Generate a patch which can be applied at the root of the tree. 883 """Generate a patch which can be applied at the root of the tree.
907 884
908 Internally, runs 'svn diff' on each checked out module and 885 Internally, runs 'svn diff'/'git diff' on each checked out module and
909 dependencies, and performs minimal postprocessing of the output. The 886 dependencies, and performs minimal postprocessing of the output. The
910 resulting patch is printed to stdout and can be applied to a freshly 887 resulting patch is printed to stdout and can be applied to a freshly
911 checked out tree via 'patch -p0 < patchfile'. Additional args and 888 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 """ 889 """
890 (options, args) = parser.parse_args(args)
929 client = GClient.LoadCurrentConfig(options) 891 client = GClient.LoadCurrentConfig(options)
930 if not client: 892 if not client:
931 raise gclient_utils.Error("client not configured; see 'gclient config'") 893 raise gclient_utils.Error("client not configured; see 'gclient config'")
932 if options.verbose: 894 if options.verbose:
933 # Print out the .gclient file. This is longer than if we just printed the 895 # 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. 896 # client dict, but more legible, and it might contain helpful comments.
935 print(client.ConfigContent()) 897 print(client.ConfigContent())
936 return client.RunOnDeps('pack', args) 898 return client.RunOnDeps('pack', args)
937 899
938 900
939 def CMDstatus(parser, options, args): 901 def CMDstatus(parser, args):
940 """Show the modification status of for every dependencies. 902 """Show modification status for every dependencies."""
941 903 (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) 904 client = GClient.LoadCurrentConfig(options)
951 if not client: 905 if not client:
952 raise gclient_utils.Error("client not configured; see 'gclient config'") 906 raise gclient_utils.Error("client not configured; see 'gclient config'")
953 if options.verbose: 907 if options.verbose:
954 # Print out the .gclient file. This is longer than if we just printed the 908 # 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. 909 # client dict, but more legible, and it might contain helpful comments.
956 print(client.ConfigContent()) 910 print(client.ConfigContent())
957 return client.RunOnDeps('status', args) 911 return client.RunOnDeps('status', args)
958 912
959 913
960 def CMDsync(parser, options, args): 914 @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 915 gclient sync
986 update files from SCM according to current configuration, 916 update files from SCM according to current configuration,
987 *for modules which have changed since last update or sync* 917 *for modules which have changed since last update or sync*
988 gclient sync --force 918 gclient sync --force
989 update files from SCM according to current configuration, for 919 update files from SCM according to current configuration, for
990 all modules (useful for recovering files deleted from local copy) 920 all modules (useful for recovering files deleted from local copy)
991 gclient sync --revision src@31000 921 gclient sync --revision src@31000
992 update src directory to r31000 922 update src directory to r31000
993 """ 923 """)
924 def CMDsync(parser, args):
925 """Checkout/update all modules."""
926 parser.add_option("--force", action="store_true",
927 help="force update even for unchanged modules")
928 parser.add_option("--nohooks", action="store_true",
929 help="don't run hooks after the update is complete")
930 parser.add_option("-r", "--revision", action="append",
931 dest="revisions", metavar="REV", default=[],
932 help="update given solution to specified revision, "
933 "can be used multiple times for each solution, "
934 "e.g. -r src@123, -r internal@32")
935 parser.add_option("--head", action="store_true",
936 help="skips any safesync_urls specified in "
937 "configured solutions and sync to head instead")
938 parser.add_option("--delete_unversioned_trees", action="store_true",
939 help="delete any unexpected unversioned trees "
940 "that are in the checkout")
941 parser.add_option("--reset", action="store_true",
942 help="resets any local changes before updating (git only)")
943 parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
944 help="sync deps for the specified (comma-separated) "
945 "platform(s); 'all' will sync all platforms")
946 parser.add_option("--manually_grab_svn_rev", action="store_true",
947 help="Skip svn up whenever possible by requesting "
948 "actual HEAD revision from the repository")
949 (options, args) = parser.parse_args(args)
994 client = GClient.LoadCurrentConfig(options) 950 client = GClient.LoadCurrentConfig(options)
995 951
996 if not client: 952 if not client:
997 raise gclient_utils.Error("client not configured; see 'gclient config'") 953 raise gclient_utils.Error("client not configured; see 'gclient config'")
998 954
999 if not options.head: 955 if not options.head:
1000 solutions = client.GetVar('solutions') 956 solutions = client.GetVar('solutions')
1001 if solutions: 957 if solutions:
1002 for s in solutions: 958 for s in solutions:
1003 if s.get('safesync_url', ''): 959 if s.get('safesync_url', ''):
(...skipping 12 matching lines...) Expand all
1016 if len(rev): 972 if len(rev):
1017 options.revisions.append(s['name']+'@'+rev) 973 options.revisions.append(s['name']+'@'+rev)
1018 974
1019 if options.verbose: 975 if options.verbose:
1020 # Print out the .gclient file. This is longer than if we just printed the 976 # 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. 977 # client dict, but more legible, and it might contain helpful comments.
1022 print(client.ConfigContent()) 978 print(client.ConfigContent())
1023 return client.RunOnDeps('update', args) 979 return client.RunOnDeps('update', args)
1024 980
1025 981
1026 def CMDupdate(parser, options, args): 982 def CMDupdate(parser, args):
1027 """Alias for the sync command. Deprecated.""" 983 """Alias for the sync command. Deprecated."""
1028 return CMDsync(parser, options, args) 984 return CMDsync(parser, args)
1029 985
1030 986 def CMDdiff(parser, args):
1031 def CMDdiff(parser, options, args): 987 """Displays local diff for every dependencies."""
1032 """Display the differences between two revisions of modules. 988 (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) 989 client = GClient.LoadCurrentConfig(options)
1052 if not client: 990 if not client:
1053 raise gclient_utils.Error("client not configured; see 'gclient config'") 991 raise gclient_utils.Error("client not configured; see 'gclient config'")
1054 if options.verbose: 992 if options.verbose:
1055 # Print out the .gclient file. This is longer than if we just printed the 993 # 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. 994 # client dict, but more legible, and it might contain helpful comments.
1057 print(client.ConfigContent()) 995 print(client.ConfigContent())
1058 return client.RunOnDeps('diff', args) 996 return client.RunOnDeps('diff', args)
1059 997
1060 998
1061 def CMDrevert(parser, options, args): 999 def CMDrevert(parser, args):
1062 """Revert every file in every managed directory in the client view.""" 1000 """Revert all modifications in every dependencies."""
1001 parser.add_option("--nohooks", action="store_true",
1002 help="don't run hooks after the revert is complete")
1003 (options, args) = parser.parse_args(args)
1004 # --force is implied.
1005 options.force = True
1063 client = GClient.LoadCurrentConfig(options) 1006 client = GClient.LoadCurrentConfig(options)
1064 if not client: 1007 if not client:
1065 raise gclient_utils.Error("client not configured; see 'gclient config'") 1008 raise gclient_utils.Error("client not configured; see 'gclient config'")
1066 return client.RunOnDeps('revert', args) 1009 return client.RunOnDeps('revert', args)
1067 1010
1068 1011
1069 def CMDrunhooks(parser, options, args): 1012 def CMDrunhooks(parser, args):
1070 """Runs hooks for files that have been modified in the local working copy. 1013 """Runs hooks for files that have been modified in the local working copy."""
1071 1014 parser.add_option("--force", action="store_true", default=True,
1072 Implies --force. 1015 help="Deprecated. No effect.")
1073 1016 (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) 1017 client = GClient.LoadCurrentConfig(options)
1080 if not client: 1018 if not client:
1081 raise gclient_utils.Error("client not configured; see 'gclient config'") 1019 raise gclient_utils.Error("client not configured; see 'gclient config'")
1082 if options.verbose: 1020 if options.verbose:
1083 # Print out the .gclient file. This is longer than if we just printed the 1021 # 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. 1022 # client dict, but more legible, and it might contain helpful comments.
1085 print(client.ConfigContent()) 1023 print(client.ConfigContent())
1086 options.force = True 1024 options.force = True
1025 options.nohooks = False
1026 options.deps_os = None
1087 return client.RunOnDeps('runhooks', args) 1027 return client.RunOnDeps('runhooks', args)
1088 1028
1089 1029
1090 def CMDrevinfo(parser, options, args): 1030 def CMDrevinfo(parser, args):
1091 """Outputs defails for every dependencies. 1031 """Outputs details for every dependencies."""
1092 1032 parser.add_option("--snapshot", action="store_true",
1093 This includes source path, server URL and revision information for every 1033 help="create a snapshot file of the current "
1094 dependency in all solutions. 1034 "version of all repositories")
1095 1035 (options, args) = parser.parse_args(args)
1096 usage: revinfo [options]
1097 """
1098 __pychecker__ = 'unusednames=args'
1099 client = GClient.LoadCurrentConfig(options) 1036 client = GClient.LoadCurrentConfig(options)
1100 if not client: 1037 if not client:
1101 raise gclient_utils.Error("client not configured; see 'gclient config'") 1038 raise gclient_utils.Error("client not configured; see 'gclient config'")
1102 client.PrintRevInfo() 1039 client.PrintRevInfo()
1103 return 0 1040 return 0
1104 1041
1105 1042
1106 def CMDhelp(parser, options, args): 1043 def Command(name):
1107 """Prints general help or command-specific documentation.""" 1044 return getattr(sys.modules[__name__], 'CMD' + name, None)
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)
1108 if len(args) == 1: 1050 if len(args) == 1:
1109 command = Command(args[0]) 1051 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() 1052 parser.print_help()
1117 return 0 1053 return 0
1118 1054
1119 1055
1120 def Command(command): 1056 def GenUsage(parser, command):
1121 return getattr(sys.modules[__name__], 'CMD' + command, CMDhelp) 1057 """Modify an OptParse object with the function's documentation."""
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)
1122 1066
1123 1067
1124 def Main(argv): 1068 def Main(argv):
1125 parser = optparse.OptionParser(usage=DEFAULT_USAGE_TEXT, 1069 """Doesn't parse the arguments here, just find the right subcommand to
1126 version='%prog ' + __version__) 1070 execute."""
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__)
1127 parser.add_option("-v", "--verbose", action="count", default=0, 1076 parser.add_option("-v", "--verbose", action="count", default=0,
1128 help="Produces additional output for diagnostics. Can be " 1077 help="Produces additional output for diagnostics. Can be "
1129 "used up to three times for more logging info.") 1078 "used up to three times for more logging info.")
1130 parser.add_option("--gclientfile", metavar="FILENAME", dest="config_filename", 1079 parser.add_option("--gclientfile", metavar="FILENAME", dest="config_filename",
1131 default=os.environ.get("GCLIENT_FILE", ".gclient"), 1080 default=os.environ.get("GCLIENT_FILE", ".gclient"),
1132 help="Specify an alternate .gclient file") 1081 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. 1082 # Integrate standard options processing.
1171 old_parser = parser.parse_args 1083 old_parser = parser.parse_args
1172 def Parse(args): 1084 def Parse(args):
1173 (options, args) = old_parser(args) 1085 (options, args) = old_parser(args)
1174 if options.verbose == 2: 1086 if options.verbose == 2:
1175 logging.basicConfig(level=logging.INFO) 1087 logging.basicConfig(level=logging.INFO)
1176 elif options.verbose > 2: 1088 elif options.verbose > 2:
1177 logging.basicConfig(level=logging.DEBUG) 1089 logging.basicConfig(level=logging.DEBUG)
1178 options.entries_filename = options.config_filename + "_entries" 1090 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 = []
1179 return (options, args) 1094 return (options, args)
1180 parser.parse_args = Parse 1095 parser.parse_args = Parse
1181 # We don't want wordwrapping in epilog (usually examples) 1096 # We don't want wordwrapping in epilog (usually examples)
1182 parser.format_epilog = lambda _: parser.epilog or '' 1097 parser.format_epilog = lambda _: parser.epilog or ''
1183 1098 if argv:
1184 if not len(argv): 1099 command = Command(argv[0])
1185 argv = ['help'] 1100 if command:
1186 # Add manual support for --version as first argument. 1101 # "fix" the usage and the description now that we know the subcommand.
1187 if argv[0] == '--version': 1102 GenUsage(parser, argv[0])
1188 parser.print_version() 1103 return command(parser, argv[1:])
1189 return 0 1104 # Not a known command. Default to help.
1190 # Add manual support for --help as first argument. 1105 GenUsage(parser, 'help')
1191 if argv[0] == '--help': 1106 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 1107
1196 1108
1197 if "__main__" == __name__: 1109 if "__main__" == __name__:
1198 try: 1110 try:
1199 sys.exit(Main(sys.argv[1:])) 1111 sys.exit(Main(sys.argv[1:]))
1200 except gclient_utils.Error, e: 1112 except gclient_utils.Error, e:
1201 print >> sys.stderr, "Error: %s" % str(e) 1113 print >> sys.stderr, "Error: %s" % str(e)
1202 sys.exit(1) 1114 sys.exit(1)
1203 1115
1204 # vim: ts=2:sw=2:tw=80:et: 1116 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « PRESUBMIT.py ('k') | tests/fake_repos.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698