OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 |
| 7 """Generates a pinned solutions file with relative git repository URLs. |
| 8 |
| 9 make_relative_solution reads a pinned solution file generated by |
| 10 'gclient revinfo --snapshot' and writes to stdout a pinned solution file |
| 11 with relative git repository URLs. |
| 12 |
| 13 |
| 14 The resulting solution file can be used to check out a fixed version of |
| 15 a gclient set of repositories. The base URL to fetch from can be changed |
| 16 by editing one line in the generated solution file. |
| 17 """ |
| 18 |
| 19 import optparse |
| 20 import sys |
| 21 |
| 22 |
| 23 def ReadSnapshot(filename): |
| 24 """Reads a gclient revinfo snapshot file. |
| 25 |
| 26 Minimal verification of the structure of the file is performed. |
| 27 |
| 28 Args: |
| 29 filename: The name of a snapshot file to read. |
| 30 |
| 31 Returns: |
| 32 The solutions array parsed from the snapshot file. |
| 33 """ |
| 34 |
| 35 env = {} |
| 36 execfile(filename, env) |
| 37 |
| 38 assert 'solutions' in env |
| 39 assert env['solutions'] |
| 40 |
| 41 return env['solutions'] |
| 42 |
| 43 |
| 44 def BaseRepository(url): |
| 45 """Finds the base repository path. |
| 46 |
| 47 This only works if the top level repository is not in a subdirectory relative |
| 48 to the other repositories on the server. |
| 49 |
| 50 Args: |
| 51 url: git repository url |
| 52 |
| 53 Returns: |
| 54 The prefix of the URL that does not contain the repository name and SHA. |
| 55 """ |
| 56 |
| 57 base, versioned_repository = url.rsplit('/', 1) |
| 58 |
| 59 assert base and versioned_repository |
| 60 return base |
| 61 |
| 62 |
| 63 def WriteBaseURL(base, solution): |
| 64 print ' "%s": "%s",' % (solution['name'], base) |
| 65 |
| 66 |
| 67 def IsRelativeRepository(base, url): |
| 68 return url.startswith(base) |
| 69 |
| 70 |
| 71 def RelativeRepository(base, url): |
| 72 if IsRelativeRepository(base, url): |
| 73 return url[len(base):] |
| 74 else: |
| 75 return url |
| 76 |
| 77 |
| 78 def RelativeDep(base, dep): |
| 79 path, repository = dep |
| 80 |
| 81 return (path, |
| 82 RelativeRepository(base, repository), |
| 83 IsRelativeRepository(base, repository)) |
| 84 |
| 85 |
| 86 def RelativeDeps(base, solution): |
| 87 return [RelativeDep(base, dep) for dep in solution['custom_deps'].items()] |
| 88 |
| 89 |
| 90 def WritePinnedDep(name, dep, indent): |
| 91 """Writes a pinned dep. |
| 92 |
| 93 The output is indented so that the URLs all line up for ease of reading. If |
| 94 the dep is for a relative git repository then we emit the base_url lookup as |
| 95 well. |
| 96 |
| 97 Args: |
| 98 name: The name of the solution that is being written out. |
| 99 dep: The relative dep that is to be written out. |
| 100 indent: The total number of characters to use for the path component. |
| 101 |
| 102 Returns: |
| 103 Nothing |
| 104 """ |
| 105 |
| 106 path, repository, relative = dep |
| 107 remainder = path.partition('/')[2] |
| 108 spaces = indent - len(path) |
| 109 |
| 110 if remainder == 'deps': |
| 111 return |
| 112 |
| 113 if relative: |
| 114 print ' "%s": %*sbase_url["%s"] + "%s",' % (path, |
| 115 spaces, '', |
| 116 name, |
| 117 repository) |
| 118 else: |
| 119 print ' "%s": %*s"%s",' % (path, |
| 120 spaces, '', |
| 121 repository) |
| 122 |
| 123 |
| 124 def WritePinnedSolution(solution): |
| 125 """Writes out a pinned and solution file with relative repository paths. |
| 126 |
| 127 The relative repository paths make it easier for a user to modify where |
| 128 they are pulling source from. |
| 129 |
| 130 Args: |
| 131 solution: gclient solution object. |
| 132 |
| 133 Returns: |
| 134 Nothing |
| 135 """ |
| 136 |
| 137 base = BaseRepository(solution['url']) |
| 138 url = RelativeRepository(base, solution['url']) |
| 139 deps = RelativeDeps(base, solution) |
| 140 indent = max(len(dep[0]) for dep in deps) |
| 141 |
| 142 deps.sort(key=lambda dep: dep[1]) |
| 143 |
| 144 print (' { "name" : "%s",\n' |
| 145 ' "url" : base_url["%s"] + "%s",\n' |
| 146 ' "custom_deps" : {') % (solution['name'], |
| 147 solution['name'], |
| 148 url) |
| 149 |
| 150 for dep in deps: |
| 151 WritePinnedDep(solution['name'], dep, indent) |
| 152 |
| 153 print (' },\n' |
| 154 ' },') |
| 155 |
| 156 |
| 157 def main(argv): |
| 158 usage = 'Usage: %prog [options] filename' |
| 159 option_parser = optparse.OptionParser(usage=usage) |
| 160 option_parser.disable_interspersed_args() |
| 161 option_parser.add_option('-s', '--substitute', |
| 162 action='store_true', |
| 163 dest='substitute', |
| 164 default=False, |
| 165 help='substitute a new base git URL') |
| 166 option_parser.add_option('-b', '--base', |
| 167 dest='base', |
| 168 default='http://src.chromium.org/git', |
| 169 metavar='URL', |
| 170 help='base git URL to substitute [%default]') |
| 171 |
| 172 options, args = option_parser.parse_args(argv[1:]) |
| 173 |
| 174 if len(args) != 1: |
| 175 option_parser.print_help() |
| 176 return 1 |
| 177 |
| 178 filename = args.pop(0) |
| 179 solutions = ReadSnapshot(filename) |
| 180 |
| 181 print ('#\n' |
| 182 '# Autogenerated pinned gclient solution file. This file was\n' |
| 183 '# created by running make_relative_solution.\n' |
| 184 '#\n' |
| 185 '\n' |
| 186 'base_url = {') |
| 187 |
| 188 for solution in solutions: |
| 189 if options.substitute: |
| 190 base = options.base |
| 191 else: |
| 192 base = BaseRepository(solution['url']) |
| 193 |
| 194 WriteBaseURL(base, solution) |
| 195 |
| 196 print ('}\n' |
| 197 '\n' |
| 198 'solutions = [') |
| 199 |
| 200 for solution in solutions: |
| 201 WritePinnedSolution(solution) |
| 202 |
| 203 print ']\n' |
| 204 |
| 205 |
| 206 if __name__ == '__main__': |
| 207 main(sys.argv) |
OLD | NEW |