blob: 43ca31e4888d2c51b38cf47183a42ba2a1a473fc [file] [log] [blame]
Rico Wind23a05112019-03-27 08:00:44 +01001#!/usr/bin/env python
2# Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5
6import argparse
7import gradle
8import fnmatch
9import os
10import re
11import sys
12import utils
13import xml.etree.ElementTree as ET
14
15CLOUD_LOCATION = 'gs://r8-deps/maven_mirror'
16
17GRADLE_CACHE = os.path.join(utils.USER_HOME, '.gradle', 'caches')
18
19def parse_arguments():
20 parser = argparse.ArgumentParser()
21 parser.add_argument('--check_mirror',
22 help = 'Checks that all dependencies are mirrored, '
23 'returns non-zero if not.',
24 default = False,
25 action = 'store_true')
26 return parser.parse_args()
27
28
29def xml_get(element, tag):
30 # The tags are prefixed with like: {http://maven.apache.org/POM/4.0.0}parent
31 for child in element.iter():
32 if child.tag.endswith(tag):
33 yield child
34
35def xml_get_single(element, tag):
36 elements = list(xml_get(element, tag))
37 if len(elements) == 0:
38 return None
39 assert len(elements) == 1
40 return elements[0]
41
42def find_pom_in_gradle_cache(pom, cached_poms):
43 cached = [p for p in cached_poms if p.endswith(pom)]
44 assert len(cached) == 1, 'did not find %s in %s' % (pom, cached_poms)
45 return cached[0]
46
47# This is a hack, gradle does not provide access to parent poms, which
48# we need to mirror.
49def get_parent(pom_file, gradle_cached_poms):
50 tree = ET.parse(pom_file)
51 root = tree.getroot()
52 ns = {'pom': 'http://maven.apache.org/POM/4.0.0' }
53 parent = root.find('pom:parent', ns)
54 if parent is not None:
55 group = parent.find('pom:groupId', ns).text
56 artifact = parent.find('pom:artifactId', ns).text
57 version = parent.find('pom:version', ns).text
58 filename = '%s-%s.pom' % (artifact, version)
59 parent_path = find_pom_in_gradle_cache(filename, gradle_cached_poms)
60 return Entry(group, artifact, version, parent_path)
61
62# Returns a tuple: (group, artifact, version)
63def parse_descriptor(descriptor):
64 # Descriptor like org.ow2.asm:asm:6.2.1
65 split = descriptor.split(':')
66 return (split[0], split[1], split[2])
67
68class Entry(object):
69 def __init__(self, group, artifact, version, path):
70 self.group = group
71 self.artifact = artifact
72 self.version = version
73 self.path = path
74 assert os.path.exists(self.path)
75 self.jar = None
76
77 def set_jar(self, jar):
78 self.jar = jar
79 assert os.path.exists(jar)
80
81 def get_cloud_dir(self):
82 return os.path.join(CLOUD_LOCATION, '/'.join(self.group.split('.')))
83
84 def get_name(self):
85 return '%s-%s' % (self.artifact, self.version)
86
87 def get_cloud_destination(self):
88 return os.path.join(self.get_cloud_dir(), self.artifact, self.version,
89 self.get_name())
90
91 def get_cloud_jar_location(self):
92 assert self.jar is not None
93 suffix = self.jar[len(self.jar)-4:]
94 return self.get_cloud_destination() + suffix
95
96 def get_cloud_pom_location(self):
97 return self.get_cloud_destination() + '.pom'
98
99def read_gradle_cache_pom_files():
100 pom_files = []
101 for root, dirnames, filenames in os.walk(GRADLE_CACHE):
102 for filename in fnmatch.filter(filenames, '*.pom'):
103 pom_files.append(os.path.join(root, filename))
104 return pom_files
105
106# We set the name to be group:artifact:version, same as gradle prints
107def get_descriptor_from_path(entry):
108 # Example
109 # /usr.../org.ow2.asm/asm/6.2.1/3bc91be104d9292ff1dcc3dbf1002b7c320e767d/asm-6.2.1.pom
110 basename = os.path.basename(entry)
111 dirname = os.path.dirname(os.path.dirname(entry))
112 version = os.path.basename(dirname)
113 dirname = os.path.dirname(dirname)
114 artifact = os.path.basename(dirname)
115 dirname = os.path.dirname(dirname)
116 group = os.path.basename(dirname)
117 # Sanity, filename is artifact-version.{pom,jar}
118 assert '%s-%s' % (artifact, version) == basename[0:len(basename)-4]
119 return '%s:%s:%s' % (group, artifact, version)
120
121def Main():
122 args = parse_arguments()
123 # Ensure that everything is downloaded before generating the pom list
124 gradle.RunGradle(['-stop'])
125 gradle_deps = gradle.RunGradleGetOutput(
126 ['printMavenDeps', '-Pupdatemavendeps']).splitlines()
127 gradle_poms = read_gradle_cache_pom_files()
128
129 # Example output lines:
130 # POM: /usr.../org.ow2.asm/asm/6.2.1/3bc91be104d9292ff1dcc3dbf1002b7c320e767d/asm-6.2.1.pom org.ow2.asm:asm:6.2.1
131 # JAR: /usr.../com.google.code.gson/gson/2.7/751f548c85fa49f330cecbb1875893f971b33c4e/gson-2.7.jar
132 poms = [l[5:] for l in gradle_deps if l.startswith('POM: ')]
133 jars = [l[5:] for l in gradle_deps if l.startswith('JAR: ')]
134 descriptor_to_entry = {}
135 parents = []
136 for pom in poms:
137 split = pom.split(' ')
138 filepath = split[0]
139 gradle_descriptor = split[1]
140 descriptor = get_descriptor_from_path(filepath)
141 assert descriptor == gradle_descriptor
142 (group, artifact, version) = parse_descriptor(gradle_descriptor)
143 descriptor_to_entry[descriptor] = Entry(group, artifact, version, filepath)
144 parent = get_parent(filepath, gradle_poms)
145 while parent:
146 descriptor = get_descriptor_from_path(parent.path)
147 descriptor_to_entry[descriptor] = parent
148 parent = get_parent(parent.path, gradle_poms)
149 for jar in jars:
150 if jar.startswith(utils.REPO_ROOT):
151 continue
152 descriptor = get_descriptor_from_path(jar)
153 assert descriptor in descriptor_to_entry
154 descriptor_to_entry[descriptor].set_jar(jar)
155 has_missing = False
156 for descriptor in descriptor_to_entry:
157 entry = descriptor_to_entry[descriptor]
158 if not utils.file_exists_on_cloud_storage(entry.get_cloud_pom_location()):
159 if args.check_mirror:
160 has_missing = True
161 print 'Missing dependency for: ' + descriptor
162 else:
163 print 'Uploading: %s' % entry.path
164 utils.upload_file_to_cloud_storage(entry.path, entry.get_cloud_pom_location())
165 if entry.jar:
166 if not utils.file_exists_on_cloud_storage(entry.get_cloud_jar_location()):
167 if args.check_mirror:
168 has_missing = True
169 print 'Missing dependency for: ' + descriptor
170 else:
171 print 'Uploading: %s' % entry.jar
172 utils.upload_file_to_cloud_storage(entry.jar, entry.get_cloud_jar_location())
173
174 if args.check_mirror:
175 if has_missing:
176 print('The maven mirror has missing dependencies, please run'
177 'tools/maven_mirror.py')
178 return 1
179 else:
180 print('Mirror is up to date with all dependencies')
181
182if __name__ == '__main__':
183 sys.exit(Main())