| #!/usr/bin/env python3 |
| # Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file |
| # for details. All rights reserved. Use of this source code is governed by a |
| # BSD-style license that can be found in the LICENSE file. |
| |
| import argparse |
| import gradle |
| import fnmatch |
| import os |
| import re |
| import sys |
| import utils |
| import xml.etree.ElementTree as ET |
| |
| CLOUD_LOCATION = 'gs://r8-deps/maven_mirror' |
| |
| GRADLE_CACHE = os.path.join(utils.USER_HOME, '.gradle', 'caches') |
| |
| def parse_arguments(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument('--check_mirror', |
| help = 'Checks that all dependencies are mirrored, ' |
| 'returns non-zero if not.', |
| default = False, |
| action = 'store_true') |
| return parser.parse_args() |
| |
| |
| def xml_get(element, tag): |
| # The tags are prefixed with like: {http://maven.apache.org/POM/4.0.0}parent |
| for child in element.iter(): |
| if child.tag.endswith(tag): |
| yield child |
| |
| def xml_get_single(element, tag): |
| elements = list(xml_get(element, tag)) |
| if len(elements) == 0: |
| return None |
| assert len(elements) == 1 |
| return elements[0] |
| |
| def find_pom_in_gradle_cache(pom, cached_poms): |
| cached = [p for p in cached_poms if p.endswith(pom)] |
| assert len(cached) == 1, 'did not find %s in %s' % (pom, cached_poms) |
| return cached[0] |
| |
| # This is a hack, gradle does not provide access to parent poms, which |
| # we need to mirror. |
| def get_parent(pom_file, gradle_cached_poms): |
| tree = ET.parse(pom_file) |
| root = tree.getroot() |
| ns = {'pom': 'http://maven.apache.org/POM/4.0.0' } |
| parent = root.find('pom:parent', ns) |
| if parent is not None: |
| group = parent.find('pom:groupId', ns).text |
| artifact = parent.find('pom:artifactId', ns).text |
| version = parent.find('pom:version', ns).text |
| filename = '%s-%s.pom' % (artifact, version) |
| parent_path = find_pom_in_gradle_cache(filename, gradle_cached_poms) |
| return Entry(group, artifact, version, parent_path) |
| |
| # Returns a tuple: (group, artifact, version) |
| def parse_descriptor(descriptor): |
| # Descriptor like org.ow2.asm:asm:6.2.1 |
| split = descriptor.split(':') |
| return (split[0], split[1], split[2]) |
| |
| class Entry(object): |
| def __init__(self, group, artifact, version, path): |
| self.group = group |
| self.artifact = artifact |
| self.version = version |
| self.path = path |
| assert os.path.exists(self.path) |
| self.jar = None |
| |
| def set_jar(self, jar): |
| self.jar = jar |
| assert os.path.exists(jar) |
| |
| def get_cloud_dir(self): |
| return os.path.join(CLOUD_LOCATION, '/'.join(self.group.split('.'))) |
| |
| def get_name(self): |
| return '%s-%s' % (self.artifact, self.version) |
| |
| def get_cloud_destination(self): |
| return os.path.join(self.get_cloud_dir(), self.artifact, self.version, |
| self.get_name()) |
| |
| def get_cloud_jar_location(self): |
| assert self.jar is not None |
| suffix = self.jar[len(self.jar)-4:] |
| return self.get_cloud_destination() + suffix |
| |
| def get_cloud_pom_location(self): |
| return self.get_cloud_destination() + '.pom' |
| |
| def read_gradle_cache_pom_files(): |
| pom_files = [] |
| for root, dirnames, filenames in os.walk(GRADLE_CACHE): |
| for filename in fnmatch.filter(filenames, '*.pom'): |
| pom_files.append(os.path.join(root, filename)) |
| return pom_files |
| |
| # We set the name to be group:artifact:version, same as gradle prints |
| def get_descriptor_from_path(entry): |
| # Example |
| # /usr.../org.ow2.asm/asm/6.2.1/3bc91be104d9292ff1dcc3dbf1002b7c320e767d/asm-6.2.1.pom |
| basename = os.path.basename(entry) |
| dirname = os.path.dirname(os.path.dirname(entry)) |
| version = os.path.basename(dirname) |
| dirname = os.path.dirname(dirname) |
| artifact = os.path.basename(dirname) |
| dirname = os.path.dirname(dirname) |
| group = os.path.basename(dirname) |
| # Sanity, filename is artifact-version.{pom,jar} |
| assert '%s-%s' % (artifact, version) == basename[0:len(basename)-4] |
| return '%s:%s:%s' % (group, artifact, version) |
| |
| def Main(): |
| args = parse_arguments() |
| # Ensure that everything is downloaded before generating the pom list |
| gradle.RunGradle(['-stop']) |
| gradle_deps = gradle.RunGradleGetOutput( |
| ['printMavenDeps', '-Pupdatemavendeps']).splitlines() |
| gradle_poms = read_gradle_cache_pom_files() |
| |
| # Example output lines: |
| # POM: /usr.../org.ow2.asm/asm/6.2.1/3bc91be104d9292ff1dcc3dbf1002b7c320e767d/asm-6.2.1.pom org.ow2.asm:asm:6.2.1 |
| # JAR: /usr.../com.google.code.gson/gson/2.7/751f548c85fa49f330cecbb1875893f971b33c4e/gson-2.7.jar |
| poms = [l[5:] for l in gradle_deps if l.startswith('POM: ')] |
| jars = [l[5:] for l in gradle_deps if l.startswith('JAR: ')] |
| descriptor_to_entry = {} |
| parents = [] |
| for pom in poms: |
| split = pom.split(' ') |
| filepath = split[0] |
| gradle_descriptor = split[1] |
| descriptor = get_descriptor_from_path(filepath) |
| assert descriptor == gradle_descriptor |
| (group, artifact, version) = parse_descriptor(gradle_descriptor) |
| descriptor_to_entry[descriptor] = Entry(group, artifact, version, filepath) |
| parent = get_parent(filepath, gradle_poms) |
| while parent: |
| descriptor = get_descriptor_from_path(parent.path) |
| descriptor_to_entry[descriptor] = parent |
| parent = get_parent(parent.path, gradle_poms) |
| for jar in jars: |
| if jar.startswith(utils.REPO_ROOT): |
| continue |
| descriptor = get_descriptor_from_path(jar) |
| assert descriptor in descriptor_to_entry |
| descriptor_to_entry[descriptor].set_jar(jar) |
| has_missing = False |
| for descriptor in descriptor_to_entry: |
| entry = descriptor_to_entry[descriptor] |
| if not utils.file_exists_on_cloud_storage(entry.get_cloud_pom_location()): |
| if args.check_mirror: |
| has_missing = True |
| print 'Missing dependency for: ' + descriptor |
| else: |
| print 'Uploading: %s' % entry.path |
| utils.upload_file_to_cloud_storage(entry.path, entry.get_cloud_pom_location()) |
| if entry.jar: |
| if not utils.file_exists_on_cloud_storage(entry.get_cloud_jar_location()): |
| if args.check_mirror: |
| has_missing = True |
| print 'Missing dependency for: ' + descriptor |
| else: |
| print 'Uploading: %s' % entry.jar |
| utils.upload_file_to_cloud_storage(entry.jar, entry.get_cloud_jar_location()) |
| |
| if args.check_mirror: |
| if has_missing: |
| print('The maven mirror has missing dependencies, please run' |
| 'tools/maven_mirror.py') |
| return 1 |
| else: |
| print('Mirror is up to date with all dependencies') |
| |
| if __name__ == '__main__': |
| sys.exit(Main()) |