Index: src/scripts/make_relative_solution |
diff --git a/src/scripts/make_relative_solution b/src/scripts/make_relative_solution |
new file mode 100755 |
index 0000000000000000000000000000000000000000..d12159e1b247cd2dfc46ae05959b526aae8d6c7b |
--- /dev/null |
+++ b/src/scripts/make_relative_solution |
@@ -0,0 +1,207 @@ |
+#!/usr/bin/python |
+# |
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Generates a pinned solutions file with relative git repository URLs. |
+ |
+make_relative_solution reads a pinned solution file generated by |
+'gclient revinfo --snapshot' and writes to stdout a pinned solution file |
+with relative git repository URLs. |
+ |
+ |
+The resulting solution file can be used to check out a fixed version of |
+a gclient set of repositories. The base URL to fetch from can be changed |
+by editing one line in the generated solution file. |
+""" |
+ |
+import optparse |
+import sys |
+ |
+ |
+def ReadSnapshot(filename): |
+ """Reads a gclient revinfo snapshot file. |
+ |
+ Minimal verification of the structure of the file is performed. |
+ |
+ Args: |
+ filename: The name of a snapshot file to read. |
+ |
+ Returns: |
+ The solutions array parsed from the snapshot file. |
+ """ |
+ |
+ env = {} |
+ execfile(filename, env) |
+ |
+ assert 'solutions' in env |
+ assert env['solutions'] |
+ |
+ return env['solutions'] |
+ |
+ |
+def BaseRepository(url): |
+ """Finds the base repository path. |
+ |
+ This only works if the top level repository is not in a subdirectory relative |
+ to the other repositories on the server. |
+ |
+ Args: |
+ url: git repository url |
+ |
+ Returns: |
+ The prefix of the URL that does not contain the repository name and SHA. |
+ """ |
+ |
+ base, versioned_repository = url.rsplit('/', 1) |
+ |
+ assert base and versioned_repository |
+ return base |
+ |
+ |
+def WriteBaseURL(base, solution): |
+ print ' "%s": "%s",' % (solution['name'], base) |
+ |
+ |
+def IsRelativeRepository(base, url): |
+ return url.startswith(base) |
+ |
+ |
+def RelativeRepository(base, url): |
+ if IsRelativeRepository(base, url): |
+ return url[len(base):] |
+ else: |
+ return url |
+ |
+ |
+def RelativeDep(base, dep): |
+ path, repository = dep |
+ |
+ return (path, |
+ RelativeRepository(base, repository), |
+ IsRelativeRepository(base, repository)) |
+ |
+ |
+def RelativeDeps(base, solution): |
+ return [RelativeDep(base, dep) for dep in solution['custom_deps'].items()] |
+ |
+ |
+def WritePinnedDep(name, dep, indent): |
+ """Writes a pinned dep. |
+ |
+ The output is indented so that the URLs all line up for ease of reading. If |
+ the dep is for a relative git repository then we emit the base_url lookup as |
+ well. |
+ |
+ Args: |
+ name: The name of the solution that is being written out. |
+ dep: The relative dep that is to be written out. |
+ indent: The total number of characters to use for the path component. |
+ |
+ Returns: |
+ Nothing |
+ """ |
+ |
+ path, repository, relative = dep |
+ remainder = path.partition('/')[2] |
+ spaces = indent - len(path) |
+ |
+ if remainder == 'deps': |
+ return |
+ |
+ if relative: |
+ print ' "%s": %*sbase_url["%s"] + "%s",' % (path, |
+ spaces, '', |
+ name, |
+ repository) |
+ else: |
+ print ' "%s": %*s"%s",' % (path, |
+ spaces, '', |
+ repository) |
+ |
+ |
+def WritePinnedSolution(solution): |
+ """Writes out a pinned and solution file with relative repository paths. |
+ |
+ The relative repository paths make it easier for a user to modify where |
+ they are pulling source from. |
+ |
+ Args: |
+ solution: gclient solution object. |
+ |
+ Returns: |
+ Nothing |
+ """ |
+ |
+ base = BaseRepository(solution['url']) |
+ url = RelativeRepository(base, solution['url']) |
+ deps = RelativeDeps(base, solution) |
+ indent = max(len(dep[0]) for dep in deps) |
+ |
+ deps.sort(key=lambda dep: dep[1]) |
+ |
+ print (' { "name" : "%s",\n' |
+ ' "url" : base_url["%s"] + "%s",\n' |
+ ' "custom_deps" : {') % (solution['name'], |
+ solution['name'], |
+ url) |
+ |
+ for dep in deps: |
+ WritePinnedDep(solution['name'], dep, indent) |
+ |
+ print (' },\n' |
+ ' },') |
+ |
+ |
+def main(argv): |
+ usage = 'Usage: %prog [options] filename' |
+ option_parser = optparse.OptionParser(usage=usage) |
+ option_parser.disable_interspersed_args() |
+ option_parser.add_option('-s', '--substitute', |
+ action='store_true', |
+ dest='substitute', |
+ default=False, |
+ help='substitute a new base git URL') |
+ option_parser.add_option('-b', '--base', |
+ dest='base', |
+ default='http://src.chromium.org/git', |
+ metavar='URL', |
+ help='base git URL to substitute [%default]') |
+ |
+ options, args = option_parser.parse_args(argv[1:]) |
+ |
+ if len(args) != 1: |
+ option_parser.print_help() |
+ return 1 |
+ |
+ filename = args.pop(0) |
+ solutions = ReadSnapshot(filename) |
+ |
+ print ('#\n' |
+ '# Autogenerated pinned gclient solution file. This file was\n' |
+ '# created by running make_relative_solution.\n' |
+ '#\n' |
+ '\n' |
+ 'base_url = {') |
+ |
+ for solution in solutions: |
+ if options.substitute: |
+ base = options.base |
+ else: |
+ base = BaseRepository(solution['url']) |
+ |
+ WriteBaseURL(base, solution) |
+ |
+ print ('}\n' |
+ '\n' |
+ 'solutions = [') |
+ |
+ for solution in solutions: |
+ WritePinnedSolution(solution) |
+ |
+ print ']\n' |
+ |
+ |
+if __name__ == '__main__': |
+ main(sys.argv) |