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