blob: aa2a5e31d83e7595698cba75108a8df2a77fc445 [file] [log] [blame]
# Copyright (c) 2013 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.
"""A tool that updates remotes in all historical manifests to point to GoB.
It clones manifest-versions repository, scans through all manifests there and
replaces known old gerrit/gerrit-int URLs with Gerrit on Borg ones.
It doesn't commit or push any changes, just updates files in a working
directory.
"""
from __future__ import print_function
import collections
import os
from xml.etree import ElementTree
from chromite.cbuildbot import config_lib
from chromite.cbuildbot import manifest_version
from chromite.lib import commandline
from chromite.lib import cros_logging as logging
from chromite.lib import osutils
site_config = config_lib.GetConfig()
GOB_EXTERNAL = 'https://chromium.googlesource.com'
GOB_INTERNAL = 'https://chrome-internal.googlesource.com'
GERRIT_EXTERNAL = 'https://chromium-review.googlesource.com'
GERRIT_INTERNAL = 'https://chrome-internal-review.googlesource.com'
# Old fetch URL -> new fetch URL.
# Old fetch urls are found by grepping through manifest-versions repo.
FETCH_URLS = {
'http://git.chromium.org': GOB_EXTERNAL,
'http://git.chromium.org/git': GOB_EXTERNAL,
'https://git.chromium.org/git': GOB_EXTERNAL,
'ssh://gerrit.chromium.org:29418': GOB_EXTERNAL,
'ssh://git@gitrw.chromium.org:9222': GOB_EXTERNAL,
'ssh://gerrit-int.chromium.org:29419': GOB_INTERNAL,
}
# Old review URL -> new review URL.
REVIEW_URLS = {
'gerrit.chromium.org/gerrit': GERRIT_EXTERNAL,
'gerrit-int.chromium.org': GERRIT_INTERNAL,
}
# Single remote entry in a manifest.
Remote = collections.namedtuple('Remote', ['name', 'fetch', 'review'])
def EnumerateManifests(directory):
"""Yields paths to manifest files inside a directory."""
for path, directories, files in os.walk(directory):
# Find regular (not a symlink) xml files.
for name in files:
if not name.endswith('.xml'):
continue
full_path = os.path.join(path, name)
if os.path.isfile(full_path) and not os.path.islink(full_path):
yield full_path
# Skip 'hidden' directories.
for hidden in [name for name in directories if name.startswith('.')]:
directories.remove(hidden)
def UpdateRemotes(manifest):
"""Updates remotes in manifest to use Gerrit on Borg URLs.
Args:
manifest: Path to manifest file to modify in place.
Returns:
True if file was modified.
"""
# Read manifest file as str.
body = osutils.ReadFile(manifest)
original = body
# Update fetch="..." entries.
for old, new in FETCH_URLS.iteritems():
body = body.replace('fetch="%s"' % old, 'fetch="%s"' % new)
# Update review="..." entries.
for old, new in REVIEW_URLS.iteritems():
body = body.replace('review="%s"' % old, 'review="%s"' % new)
# Write back only if modified.
if original != body:
osutils.WriteFile(manifest, body)
return True
return False
def GetRemotes(manifest):
"""Returns list of remotes referenced in manifest.
Args:
manifest: Path to manifest file to scan for remotes.
Returns:
List of Remote tuples.
"""
doc = ElementTree.parse(manifest)
root = doc.getroot()
return [Remote(
remote.attrib['name'], remote.attrib['fetch'],
remote.attrib.get('review'))
for remote in root.findall('remote')]
def GetParser():
"""Creates the argparse parser."""
parser = commandline.ArgumentParser(description=__doc__)
parser.add_argument(
'--skip-update', action='store_true', default=False,
help='Do not revert versions manifest checkout to original state')
parser.add_argument(
'--remotes-summary', action='store_true', default=False,
help='Scan all manifests and print all various remotes found in them')
parser.add_argument(
'manifest_versions_dir', type='path',
help='Directory to checkout manifest versions repository into')
return parser
def main(argv):
parser = GetParser()
options = parser.parse_args(argv)
# Clone manifest-versions repository.
manifest_repo_url = site_config.params.MANIFEST_VERSIONS_INT_GOB_URL
if not options.skip_update:
manifest_version.RefreshManifestCheckout(
options.manifest_versions_dir, manifest_repo_url)
if options.remotes_summary:
# Find all unique remotes.
logging.info('Scanning manifests for remotes...')
remotes = set()
for manifest in EnumerateManifests(options.manifest_versions_dir):
remotes.update(GetRemotes(manifest))
# Pretty print a table.
print('Remotes found:')
row_formatter = lambda a, b, c: ''.join(
[a, ' ' * (16 - len(a)), b, ' ' * (45 - len(b)), c])
print(row_formatter('Name', 'Remote', 'Review'))
print('-' * 80)
for remote in sorted(remotes):
print(row_formatter(remote.name, remote.fetch, remote.review or ''))
return 0
logging.info('Updating manifests...')
up_to_date = True
for manifest in EnumerateManifests(options.manifest_versions_dir):
if UpdateRemotes(manifest):
up_to_date = False
logging.info('Updated manifest: %s', manifest)
if up_to_date:
logging.info('All manifests are up to date')
else:
logging.info('Done')
return 0