1*9712c20fSFrederick Mayle#!/usr/bin/env python3 2*9712c20fSFrederick Mayle# Copyright 2016 Google LLC 3*9712c20fSFrederick Mayle# 4*9712c20fSFrederick Mayle# Redistribution and use in source and binary forms, with or without 5*9712c20fSFrederick Mayle# modification, are permitted provided that the following conditions are 6*9712c20fSFrederick Mayle# met: 7*9712c20fSFrederick Mayle# 8*9712c20fSFrederick Mayle# * Redistributions of source code must retain the above copyright 9*9712c20fSFrederick Mayle# notice, this list of conditions and the following disclaimer. 10*9712c20fSFrederick Mayle# * Redistributions in binary form must reproduce the above 11*9712c20fSFrederick Mayle# copyright notice, this list of conditions and the following disclaimer 12*9712c20fSFrederick Mayle# in the documentation and/or other materials provided with the 13*9712c20fSFrederick Mayle# distribution. 14*9712c20fSFrederick Mayle# * Neither the name of Google LLC nor the names of its 15*9712c20fSFrederick Mayle# contributors may be used to endorse or promote products derived from 16*9712c20fSFrederick Mayle# this software without specific prior written permission. 17*9712c20fSFrederick Mayle# 18*9712c20fSFrederick Mayle# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19*9712c20fSFrederick Mayle# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20*9712c20fSFrederick Mayle# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21*9712c20fSFrederick Mayle# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22*9712c20fSFrederick Mayle# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23*9712c20fSFrederick Mayle# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24*9712c20fSFrederick Mayle# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25*9712c20fSFrederick Mayle# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26*9712c20fSFrederick Mayle# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27*9712c20fSFrederick Mayle# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28*9712c20fSFrederick Mayle# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29*9712c20fSFrederick Mayle 30*9712c20fSFrederick Mayle"""Convert gclient's DEPS file to repo's manifest xml file.""" 31*9712c20fSFrederick Mayle 32*9712c20fSFrederick Mayleimport argparse 33*9712c20fSFrederick Mayleimport os 34*9712c20fSFrederick Mayleimport sys 35*9712c20fSFrederick Mayle 36*9712c20fSFrederick Mayle 37*9712c20fSFrederick MayleREMOTES = { 38*9712c20fSFrederick Mayle 'chromium': 'https://chromium.googlesource.com/', 39*9712c20fSFrederick Mayle 'github': 'https://github.com/', 40*9712c20fSFrederick Mayle} 41*9712c20fSFrederick MayleREVIEWS = { 42*9712c20fSFrederick Mayle 'chromium': 'https://chromium-review.googlesource.com', 43*9712c20fSFrederick Mayle} 44*9712c20fSFrederick Mayle 45*9712c20fSFrederick MayleMANIFEST_HEAD = """<?xml version='1.0' encoding='UTF-8'?> 46*9712c20fSFrederick Mayle<!-- AUTOGENERATED BY %(prog)s; DO NOT EDIT --> 47*9712c20fSFrederick Mayle<manifest> 48*9712c20fSFrederick Mayle 49*9712c20fSFrederick Mayle <default revision='refs/heads/main' 50*9712c20fSFrederick Mayle remote='chromium' 51*9712c20fSFrederick Mayle sync-c='true' 52*9712c20fSFrederick Mayle sync-j='8' /> 53*9712c20fSFrederick Mayle""" 54*9712c20fSFrederick Mayle 55*9712c20fSFrederick MayleMANIFEST_REMOTE = """ 56*9712c20fSFrederick Mayle <remote name='%(name)s' 57*9712c20fSFrederick Mayle fetch='%(fetch)s' 58*9712c20fSFrederick Mayle review='%(review)s' /> 59*9712c20fSFrederick Mayle""" 60*9712c20fSFrederick Mayle 61*9712c20fSFrederick MayleMANIFEST_PROJECT = """ 62*9712c20fSFrederick Mayle <project path='%(path)s' 63*9712c20fSFrederick Mayle name='%(name)s' 64*9712c20fSFrederick Mayle revision='%(revision)s' 65*9712c20fSFrederick Mayle remote='%(remote)s' /> 66*9712c20fSFrederick Mayle""" 67*9712c20fSFrederick Mayle 68*9712c20fSFrederick MayleMANIFEST_TAIL = """ 69*9712c20fSFrederick Mayle</manifest> 70*9712c20fSFrederick Mayle""" 71*9712c20fSFrederick Mayle 72*9712c20fSFrederick Mayle 73*9712c20fSFrederick Mayledef ConvertDepsToManifest(deps, manifest): 74*9712c20fSFrederick Mayle """Convert the |deps| file to the |manifest|.""" 75*9712c20fSFrederick Mayle # Load the DEPS file data. 76*9712c20fSFrederick Mayle ctx = {} 77*9712c20fSFrederick Mayle with open(deps, 'rb') as file: 78*9712c20fSFrederick Mayle exec(compile(file.read(), deps, 'exec'), ctx) 79*9712c20fSFrederick Mayle 80*9712c20fSFrederick Mayle new_contents = '' 81*9712c20fSFrederick Mayle 82*9712c20fSFrederick Mayle # Write out the common header. 83*9712c20fSFrederick Mayle data = { 84*9712c20fSFrederick Mayle 'prog': os.path.basename(__file__), 85*9712c20fSFrederick Mayle } 86*9712c20fSFrederick Mayle new_contents += MANIFEST_HEAD % data 87*9712c20fSFrederick Mayle 88*9712c20fSFrederick Mayle # Write out the <remote> sections. 89*9712c20fSFrederick Mayle for name, fetch in REMOTES.items(): 90*9712c20fSFrederick Mayle data = { 91*9712c20fSFrederick Mayle 'name': name, 92*9712c20fSFrederick Mayle 'fetch': fetch, 93*9712c20fSFrederick Mayle 'review': REVIEWS.get(name, ''), 94*9712c20fSFrederick Mayle } 95*9712c20fSFrederick Mayle new_contents += MANIFEST_REMOTE % data 96*9712c20fSFrederick Mayle 97*9712c20fSFrederick Mayle # Write out the main repo itself. 98*9712c20fSFrederick Mayle data = { 99*9712c20fSFrederick Mayle 'path': 'src', 100*9712c20fSFrederick Mayle 'name': 'breakpad/breakpad', 101*9712c20fSFrederick Mayle 'revision': 'refs/heads/main', 102*9712c20fSFrederick Mayle 'remote': 'chromium', 103*9712c20fSFrederick Mayle } 104*9712c20fSFrederick Mayle new_contents += MANIFEST_PROJECT % data 105*9712c20fSFrederick Mayle 106*9712c20fSFrederick Mayle # Write out the <project> sections. 107*9712c20fSFrederick Mayle for path, url in ctx['deps'].items(): 108*9712c20fSFrederick Mayle for name, fetch in REMOTES.items(): 109*9712c20fSFrederick Mayle if url.startswith(fetch): 110*9712c20fSFrederick Mayle remote = name 111*9712c20fSFrederick Mayle break 112*9712c20fSFrederick Mayle else: 113*9712c20fSFrederick Mayle raise ValueError('Unknown DEPS remote: %s: %s' % (path, url)) 114*9712c20fSFrederick Mayle 115*9712c20fSFrederick Mayle # The DEPS url will look like: 116*9712c20fSFrederick Mayle # https://chromium.googlesource.com/external/gyp/@e8ab0833a42691cd2 117*9712c20fSFrederick Mayle remote_path, rev = url.split('@') 118*9712c20fSFrederick Mayle remote_path = remote_path[len(fetch):] 119*9712c20fSFrederick Mayle 120*9712c20fSFrederick Mayle # If it's not a revision, assume it's a tag. Repo wants full ref names. 121*9712c20fSFrederick Mayle if len(rev) != 40: 122*9712c20fSFrederick Mayle rev = 'refs/tags/%s' % rev 123*9712c20fSFrederick Mayle 124*9712c20fSFrederick Mayle data = { 125*9712c20fSFrederick Mayle 'path': path, 126*9712c20fSFrederick Mayle 'name': remote_path, 127*9712c20fSFrederick Mayle 'revision': rev, 128*9712c20fSFrederick Mayle 'remote': remote, 129*9712c20fSFrederick Mayle } 130*9712c20fSFrederick Mayle new_contents += MANIFEST_PROJECT % data 131*9712c20fSFrederick Mayle 132*9712c20fSFrederick Mayle # Write out the common footer. 133*9712c20fSFrederick Mayle new_contents += MANIFEST_TAIL 134*9712c20fSFrederick Mayle 135*9712c20fSFrederick Mayle # See if the manifest has actually changed contents to avoid thrashing. 136*9712c20fSFrederick Mayle try: 137*9712c20fSFrederick Mayle old_contents = open(manifest).read() 138*9712c20fSFrederick Mayle except IOError: 139*9712c20fSFrederick Mayle # In case the file doesn't exist yet. 140*9712c20fSFrederick Mayle old_contents = '' 141*9712c20fSFrederick Mayle if old_contents != new_contents: 142*9712c20fSFrederick Mayle print('Updating %s due to changed %s' % (manifest, deps)) 143*9712c20fSFrederick Mayle with open(manifest, 'w') as fp: 144*9712c20fSFrederick Mayle fp.write(new_contents) 145*9712c20fSFrederick Mayle 146*9712c20fSFrederick Mayle 147*9712c20fSFrederick Mayledef GetParser(): 148*9712c20fSFrederick Mayle """Return a CLI parser.""" 149*9712c20fSFrederick Mayle parser = argparse.ArgumentParser(description=__doc__) 150*9712c20fSFrederick Mayle parser.add_argument('deps', 151*9712c20fSFrederick Mayle help='The DEPS file to convert') 152*9712c20fSFrederick Mayle parser.add_argument('manifest', 153*9712c20fSFrederick Mayle help='The manifest xml to generate') 154*9712c20fSFrederick Mayle return parser 155*9712c20fSFrederick Mayle 156*9712c20fSFrederick Mayle 157*9712c20fSFrederick Mayledef main(argv): 158*9712c20fSFrederick Mayle """The main func!""" 159*9712c20fSFrederick Mayle parser = GetParser() 160*9712c20fSFrederick Mayle opts = parser.parse_args(argv) 161*9712c20fSFrederick Mayle ConvertDepsToManifest(opts.deps, opts.manifest) 162*9712c20fSFrederick Mayle 163*9712c20fSFrederick Mayle 164*9712c20fSFrederick Mayleif __name__ == '__main__': 165*9712c20fSFrederick Mayle sys.exit(main(sys.argv[1:])) 166