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

Side by Side Diff: gclient.py

Issue 672004: Add a --snapshot option for revinfo. If set, revinfo prints a .gclient file... (Closed) Base URL: http://src.chromium.org/svn/trunk/tools/depot_tools/
Patch Set: '' Created 10 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | 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 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 # To use the trunk of a component instead of what's in DEPS: 272 # To use the trunk of a component instead of what's in DEPS:
273 #"component": "https://svnserver/component/trunk/", 273 #"component": "https://svnserver/component/trunk/",
274 # To exclude a component from your working copy: 274 # To exclude a component from your working copy:
275 #"data/really_large_component": None, 275 #"data/really_large_component": None,
276 }, 276 },
277 "safesync_url": "%(safesync_url)s" 277 "safesync_url": "%(safesync_url)s"
278 }, 278 },
279 ] 279 ]
280 """) 280 """)
281 281
282 DEFAULT_SNAPSHOT_SOLUTION_TEXT = ("""\
283 { "name" : "%(solution_name)s",
284 "url" : "%(solution_url)s",
285 "custom_deps" : {
286 %(solution_deps)s,
287 },
288 "safesync_url": "%(safesync_url)s"
289 },
290 """)
291
292 DEFAULT_SNAPSHOT_FILE_TEXT = ("""\
293 # An element of this array (a "solution") describes a repository directory
294 # that will be checked out into your working copy. Each solution may
295 # optionally define additional dependencies (via its DEPS file) to be
296 # checked out alongside the solution's directory. A solution may also
297 # specify custom dependencies (via the "custom_deps" property) that
298 # override or augment the dependencies specified by the DEPS file.
299 # If a "safesync_url" is specified, it is assumed to reference the location of
300 # a text file which contains nothing but the last known good SCM revision to
301 # sync against. It is fetched if specified and used unless --head is passed
302
303 solutions = [
304 %(solution_list)s
305 ]
306 """)
307
282 308
283 ## GClient implementation. 309 ## GClient implementation.
284 310
285 311
286 class GClient(object): 312 class GClient(object):
287 """Object that represent a gclient checkout.""" 313 """Object that represent a gclient checkout."""
288 314
289 supported_commands = [ 315 supported_commands = [
290 'cleanup', 'diff', 'export', 'pack', 'revert', 'status', 'update', 316 'cleanup', 'diff', 'export', 'pack', 'revert', 'status', 'update',
291 'runhooks' 317 'runhooks'
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after
794 if revision_overrides.has_key(revision_elem[0]) and \ 820 if revision_overrides.has_key(revision_elem[0]) and \
795 revision_overrides[revision_elem[0]] != revision_elem[1]: 821 revision_overrides[revision_elem[0]] != revision_elem[1]:
796 raise gclient_utils.Error( 822 raise gclient_utils.Error(
797 "Conflicting revision numbers specified.") 823 "Conflicting revision numbers specified.")
798 revision_overrides[revision_elem[0]] = revision_elem[1] 824 revision_overrides[revision_elem[0]] = revision_elem[1]
799 825
800 solutions = self.GetVar("solutions") 826 solutions = self.GetVar("solutions")
801 if not solutions: 827 if not solutions:
802 raise gclient_utils.Error("No solution specified") 828 raise gclient_utils.Error("No solution specified")
803 829
804 entries = {}
805 entries_deps_content = {}
806
807 # Inner helper to generate base url and rev tuple (including honoring 830 # Inner helper to generate base url and rev tuple (including honoring
808 # |revision_overrides|) 831 # |revision_overrides|)
809 def GetURLAndRev(name, original_url): 832 def GetURLAndRev(name, original_url):
810 url, revision = gclient_utils.SplitUrlRevision(original_url) 833 url, revision = gclient_utils.SplitUrlRevision(original_url)
811 if not revision: 834 if not revision:
812 if revision_overrides.has_key(name): 835 if revision_overrides.has_key(name):
813 return (url, revision_overrides[name]) 836 return (url, revision_overrides[name])
814 else: 837 else:
815 scm = gclient_scm.CreateSCM(solution["url"], self._root_dir, name) 838 scm = gclient_scm.CreateSCM(solution["url"], self._root_dir, name)
816 return (url, scm.revinfo(self._options, [], None)) 839 return (url, scm.revinfo(self._options, [], None))
817 else: 840 else:
818 if revision_overrides.has_key(name): 841 if revision_overrides.has_key(name):
819 return (url, revision_overrides[name]) 842 return (url, revision_overrides[name])
820 else: 843 else:
821 return (url, revision) 844 return (url, revision)
822 845
846 # text of the snapshot gclient file
847 new_gclient = ""
848 # Dictionary of { path : SCM url } to ensure no duplicate solutions
849 solution_names = {}
823 # Run on the base solutions first. 850 # Run on the base solutions first.
824 for solution in solutions: 851 for solution in solutions:
852 # Dictionary of { path : SCM url } to describe the gclient checkout
853 entries = {}
854 entries_deps_content = {}
825 name = solution["name"] 855 name = solution["name"]
826 if name in entries: 856 if name in solution_names:
827 raise gclient_utils.Error("solution %s specified more than once" % name) 857 raise gclient_utils.Error("solution %s specified more than once" % name)
828 (url, rev) = GetURLAndRev(name, solution["url"]) 858 (url, rev) = GetURLAndRev(name, solution["url"])
829 entries[name] = "%s@%s" % (url, rev) 859 entries[name] = "%s@%s" % (url, rev)
860 solution_names[name] = "%s@%s" % (url, rev)
830 deps_file = solution.get("deps_file", self._options.deps_file) 861 deps_file = solution.get("deps_file", self._options.deps_file)
831 if '/' in deps_file or '\\' in deps_file: 862 if '/' in deps_file or '\\' in deps_file:
832 raise gclient_utils.Error('deps_file name must not be a path, just a ' 863 raise gclient_utils.Error('deps_file name must not be a path, just a '
833 'filename.') 864 'filename.')
834 try: 865 try:
835 deps_content = gclient_utils.FileRead( 866 deps_content = gclient_utils.FileRead(
836 os.path.join(self._root_dir, name, deps_file)) 867 os.path.join(self._root_dir, name, deps_file))
837 except IOError, e: 868 except IOError, e:
838 if e.errno != errno.ENOENT: 869 if e.errno != errno.ENOENT:
839 raise 870 raise
840 deps_content = "" 871 deps_content = ""
841 entries_deps_content[name] = deps_content 872 entries_deps_content[name] = deps_content
842 873
843 # Process the dependencies next (sort alphanumerically to ensure that 874 # Process the dependencies next (sort alphanumerically to ensure that
844 # containing directories get populated first and for readability) 875 # containing directories get populated first and for readability)
845 deps = self._ParseAllDeps(entries, entries_deps_content) 876 deps = self._ParseAllDeps(entries, entries_deps_content)
846 deps_to_process = deps.keys() 877 deps_to_process = deps.keys()
847 deps_to_process.sort() 878 deps_to_process.sort()
848 879
849 # First pass for direct dependencies. 880 # First pass for direct dependencies.
850 for d in deps_to_process: 881 for d in deps_to_process:
851 if type(deps[d]) == str: 882 if type(deps[d]) == str:
852 (url, rev) = GetURLAndRev(d, deps[d]) 883 (url, rev) = GetURLAndRev(d, deps[d])
853 entries[d] = "%s@%s" % (url, rev) 884 entries[d] = "%s@%s" % (url, rev)
854 885
855 # Second pass for inherited deps (via the From keyword) 886 # Second pass for inherited deps (via the From keyword)
856 for d in deps_to_process: 887 for d in deps_to_process:
857 if type(deps[d]) != str: 888 if type(deps[d]) != str:
858 deps_parent_url = entries[deps[d].module_name] 889 deps_parent_url = entries[deps[d].module_name]
859 if deps_parent_url.find("@") < 0: 890 if deps_parent_url.find("@") < 0:
860 raise gclient_utils.Error("From %s missing revisioned url" % 891 raise gclient_utils.Error("From %s missing revisioned url" %
861 deps[d].module_name) 892 deps[d].module_name)
862 content = gclient_utils.FileRead(os.path.join(self._root_dir, 893 content = gclient_utils.FileRead(os.path.join(
863 deps[d].module_name, 894 self._root_dir,
864 self._options.deps_file)) 895 deps[d].module_name,
865 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {}) 896 self._options.deps_file))
866 (url, rev) = GetURLAndRev(d, sub_deps[d]) 897 sub_deps = self._ParseSolutionDeps(deps[d].module_name, content, {})
867 entries[d] = "%s@%s" % (url, rev) 898 (url, rev) = GetURLAndRev(d, sub_deps[d])
868 print(";\n".join(["%s: %s" % (x, entries[x]) 899 entries[d] = "%s@%s" % (url, rev)
869 for x in sorted(entries.keys())])) 900
870 901 # Build the snapshot configuration string
871 902 if self._options.snapshot:
903 url = entries.pop(name)
904 custom_deps = ",\n ".join(["\"%s\": \"%s\"" % (x, entries[x])
905 for x in sorted(entries.keys())])
906
907 new_gclient += DEFAULT_SNAPSHOT_SOLUTION_TEXT % {
908 'solution_name': name,
909 'solution_url': url,
910 'safesync_url' : "",
911 'solution_deps': custom_deps,
912 }
913 else:
914 print(";\n".join(["%s: %s" % (x, entries[x])
915 for x in sorted(entries.keys())]))
916
917 # Print the snapshot configuration file
918 if self._options.snapshot:
919 config = DEFAULT_SNAPSHOT_FILE_TEXT % {'solution_list': new_gclient}
920 snapclient = GClient(self._root_dir, self._options)
921 snapclient.SetConfig(config)
922 print(snapclient._config_content)
923
924
872 ## gclient commands. 925 ## gclient commands.
873 926
874 927
875 def DoCleanup(options, args): 928 def DoCleanup(options, args):
876 """Handle the cleanup subcommand. 929 """Handle the cleanup subcommand.
877 930
878 Raises: 931 Raises:
879 Error: if client isn't configured properly. 932 Error: if client isn't configured properly.
880 """ 933 """
881 client = GClient.LoadCurrentConfig(options) 934 client = GClient.LoadCurrentConfig(options)
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
1144 default=False, 1197 default=False,
1145 help="Skip svn up whenever possible by requesting " 1198 help="Skip svn up whenever possible by requesting "
1146 "actual HEAD revision from the repository") 1199 "actual HEAD revision from the repository")
1147 option_parser.add_option("", "--head", action="store_true", default=False, 1200 option_parser.add_option("", "--head", action="store_true", default=False,
1148 help=("skips any safesync_urls specified in " 1201 help=("skips any safesync_urls specified in "
1149 "configured solutions")) 1202 "configured solutions"))
1150 option_parser.add_option("", "--delete_unversioned_trees", 1203 option_parser.add_option("", "--delete_unversioned_trees",
1151 action="store_true", default=False, 1204 action="store_true", default=False,
1152 help=("on update, delete any unexpected " 1205 help=("on update, delete any unexpected "
1153 "unversioned trees that are in the checkout")) 1206 "unversioned trees that are in the checkout"))
1207 option_parser.add_option("", "--snapshot", action="store_true", default=False,
1208 help=("(revinfo only), create a snapshot file "
1209 "of the current version of all repositories"))
1210 option_parser.add_option("", "--gclientfile", default=None,
1211 metavar="FILENAME",
1212 help=("specify an alternate .gclient file"))
1154 1213
1155 if len(argv) < 2: 1214 if len(argv) < 2:
1156 # Users don't need to be told to use the 'help' command. 1215 # Users don't need to be told to use the 'help' command.
1157 option_parser.print_help() 1216 option_parser.print_help()
1158 return 1 1217 return 1
1159 # Add manual support for --version as first argument. 1218 # Add manual support for --version as first argument.
1160 if argv[1] == '--version': 1219 if argv[1] == '--version':
1161 option_parser.print_version() 1220 option_parser.print_version()
1162 return 0 1221 return 0
1163 1222
1164 # Add manual support for --help as first argument. 1223 # Add manual support for --help as first argument.
1165 if argv[1] == '--help': 1224 if argv[1] == '--help':
1166 argv[1] = 'help' 1225 argv[1] = 'help'
1167 1226
1168 command = argv[1] 1227 command = argv[1]
1169 options, args = option_parser.parse_args(argv[2:]) 1228 options, args = option_parser.parse_args(argv[2:])
1170 1229
1171 if len(argv) < 3 and command == "help": 1230 if len(argv) < 3 and command == "help":
1172 option_parser.print_help() 1231 option_parser.print_help()
1173 return 0 1232 return 0
1174 1233
1175 if options.verbose > 1: 1234 if options.verbose > 1:
1176 logging.basicConfig(level=logging.DEBUG) 1235 logging.basicConfig(level=logging.DEBUG)
1177 1236
1178 # Files used for configuration and state saving. 1237 # Files used for configuration and state saving.
1179 options.config_filename = os.environ.get("GCLIENT_FILE", ".gclient") 1238 options.config_filename = os.environ.get("GCLIENT_FILE", ".gclient")
1180 options.entries_filename = ".gclient_entries" 1239 if options.gclientfile:
1240 options.config_filename = options.gclientfile
1241 options.entries_filename = options.config_filename + "_entries"
1181 options.deps_file = "DEPS" 1242 options.deps_file = "DEPS"
1182 1243
1183 options.platform = sys.platform 1244 options.platform = sys.platform
1184 return DispatchCommand(command, options, args) 1245 return DispatchCommand(command, options, args)
1185 1246
1186 1247
1187 if "__main__" == __name__: 1248 if "__main__" == __name__:
1188 try: 1249 try:
1189 result = Main(sys.argv) 1250 result = Main(sys.argv)
1190 except gclient_utils.Error, e: 1251 except gclient_utils.Error, e:
1191 print >> sys.stderr, "Error: %s" % str(e) 1252 print >> sys.stderr, "Error: %s" % str(e)
1192 result = 1 1253 result = 1
1193 sys.exit(result) 1254 sys.exit(result)
1194 1255
1195 # vim: ts=2:sw=2:tw=80:et: 1256 # vim: ts=2:sw=2:tw=80:et:
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698