blob: 662d53e61ec678905d2bcc9296ce576979604a34 [file] [log] [blame]
Mads Agera9745612017-11-02 12:42:15 +01001#!/usr/bin/env python
2# Copyright (c) 2017, 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
Mads Agera9745612017-11-02 12:42:15 +01006import argparse
Mads Agera4911eb2017-11-22 13:19:36 +01007import gradle
8import hashlib
Mads Agera9745612017-11-02 12:42:15 +01009from os import makedirs
10from os.path import join
11from shutil import copyfile, make_archive, rmtree
12import subprocess
13import sys
14from string import Template
15import tempfile
Mads Ager0fab4912017-11-20 13:52:48 +010016import utils
Mads Agera9745612017-11-02 12:42:15 +010017
Mads Agera4911eb2017-11-22 13:19:36 +010018DEPENDENCYTEMPLATE = Template(
Mads Agera9745612017-11-02 12:42:15 +010019"""
Mads Agera4911eb2017-11-22 13:19:36 +010020 <dependency>
21 <groupId>$group</groupId>
22 <artifactId>$artifact</artifactId>
23 <version>$version</version>
24 </dependency>""")
Mads Agera9745612017-11-02 12:42:15 +010025
26POMTEMPLATE = Template(
27"""<project
28 xmlns="http://maven.apache.org/POM/4.0.0"
29 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
30 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
31 <modelVersion>4.0.0</modelVersion>
32 <groupId>com.android.tools</groupId>
33 <artifactId>r8</artifactId>
34 <version>$version</version>
35 <name>D8 dexer and R8 shrinker</name>
36 <description>
37 D8 dexer and R8 shrinker.
38 </description>
39 <url>http://r8.googlesource.com/r8</url>
40 <inceptionYear>2016</inceptionYear>
41 <licenses>
42 <license>
43 <name>BSD-3-Clause</name>
44 <url>https://opensource.org/licenses/BSD-3-Clause</url>
45 <distribution>repo</distribution>
Mads Agera4911eb2017-11-22 13:19:36 +010046 </license>
Mads Ager73460192017-11-08 10:02:50 +010047 </licenses>
Mads Agera4911eb2017-11-22 13:19:36 +010048 <dependencies>$dependencies
49 </dependencies>
Mads Agera9745612017-11-02 12:42:15 +010050 <developers>
51 <developer>
52 <name>The Android Open Source Project</name>
53 </developer>
54 </developers>
55 <scm>
56 <connection>
57 https://r8.googlesource.com/r8.git
58 </connection>
59 <url>
60 https://r8.googlesource.com/r8
61 </url>
62 </scm>
63</project>
64""")
65
66def parse_options(argv):
67 result = argparse.ArgumentParser()
Mads Agera9745612017-11-02 12:42:15 +010068 result.add_argument('--out', help='directory in which to put the output zip file')
69 return result.parse_args(argv)
70
Mads Agera4911eb2017-11-22 13:19:36 +010071def determine_version():
72 version_file = join(
73 utils.SRC_ROOT, 'com', 'android', 'tools', 'r8', 'Version.java')
74 with open(version_file, 'r') as file:
75 for line in file:
76 if 'final String LABEL ' in line:
Rico Wind6feccf22018-05-08 11:18:22 +020077 result = line[line.find('"') + 1:]
Mads Agera4911eb2017-11-22 13:19:36 +010078 result = result[:result.find('"')]
79 return result
80 raise Exception('Unable to determine version.')
Mads Agera9745612017-11-02 12:42:15 +010081
82def generate_library_licenses():
83 license_prefix = 'license: '
84 licenses = []
85 license_url_prefix = 'licenseUrl: '
86 license_urls = []
87 with open('LIBRARY-LICENSE', 'r') as file:
88 for line in file:
89 trimmed = line.strip()
90 if trimmed.startswith(license_prefix):
Mads Ager73460192017-11-08 10:02:50 +010091 # Assert checking that licenses come in name/url pairs.
Mads Agera9745612017-11-02 12:42:15 +010092 assert len(licenses) == len(license_urls)
93 name = trimmed[len(license_prefix):]
94 if not name in licenses:
95 licenses.append(name)
96 if trimmed.startswith(license_url_prefix):
97 url = trimmed[len(license_url_prefix):]
98 if not url in license_urls:
99 license_urls.append(url)
Mads Ager73460192017-11-08 10:02:50 +0100100 # Assert checking that licenses come in name/url pairs.
Mads Agera9745612017-11-02 12:42:15 +0100101 assert len(licenses) == len(license_urls)
102 result = ''
103 for i in range(len(licenses)):
104 name = licenses[i]
105 url = license_urls[i]
106 result += LICENSETEMPLATE.substitute(name=name, url=url)
107 return result
108
Mads Agera4911eb2017-11-22 13:19:36 +0100109
110# Generate the dependencies block for the pom file.
111#
112# We ask gradle to list all dependencies. In that output
113# we locate the runtimeClasspath block for 'main' which
114# looks something like:
115#
116# runtimeClasspath - Runtime classpath of source set 'main'.
117# +--- net.sf.jopt-simple:jopt-simple:4.6
118# +--- com.googlecode.json-simple:json-simple:1.1
119# +--- com.google.guava:guava:23.0
120# +--- it.unimi.dsi:fastutil:7.2.0
121# +--- org.ow2.asm:asm:6.0
122# +--- org.ow2.asm:asm-commons:6.0
123# | \--- org.ow2.asm:asm-tree:6.0
124# | \--- org.ow2.asm:asm:6.0
125# +--- org.ow2.asm:asm-tree:6.0 (*)
126# +--- org.ow2.asm:asm-analysis:6.0
127# | \--- org.ow2.asm:asm-tree:6.0 (*)
128# \--- org.ow2.asm:asm-util:6.0
129# \--- org.ow2.asm:asm-tree:6.0 (*)
130#
131# We filter out the repeats that are marked by '(*)'.
132#
133# For each remaining line, we remove the junk at the start
134# in chunks. As an example:
135#
136# ' | \--- org.ow2.asm:asm-tree:6.0 ' --strip-->
137# '| \--- org.ow2.asm:asm-tree:6.0' -->
138# '\--- org.ow2.asm:asm-tree:6.0' -->
139# 'org.ow2.asm:asm-tree:6.0'
140#
141# The end result is the dependency we are looking for:
142#
143# groupId: org.ow2.asm
144# artifact: asm-tree
145# version: 6.0
146def generate_dependencies():
147 dependencies = gradle.RunGradleGetOutput(['dependencies'])
148 dependency_lines = []
149 collect = False
150 for line in dependencies.splitlines():
151 if 'runtimeClasspath' in line and "'main'" in line:
152 collect = True
153 continue
154 if collect:
155 if not len(line) == 0:
156 if not '(*)' in line:
157 trimmed = line.strip()
158 while trimmed.find(' ') != -1:
159 trimmed = trimmed[trimmed.find(' ') + 1:].strip()
160 if not trimmed in dependency_lines:
161 dependency_lines.append(trimmed)
162 else:
163 break
164 result = ''
165 for dep in dependency_lines:
166 components = dep.split(':')
167 assert len(components) == 3
168 group = components[0]
169 artifact = components[1]
170 version = components[2]
171 result += DEPENDENCYTEMPLATE.substitute(
172 group=group, artifact=artifact, version=version)
173 return result
174
Mads Agera9745612017-11-02 12:42:15 +0100175def write_pom_file(version, pom_file):
Mads Agera4911eb2017-11-22 13:19:36 +0100176 dependencies = generate_dependencies()
177 version_pom = POMTEMPLATE.substitute(
178 version=version, dependencies=dependencies)
Mads Agera9745612017-11-02 12:42:15 +0100179 with open(pom_file, 'w') as file:
180 file.write(version_pom)
181
182def hash_for(file, hash):
183 with open(file, 'rb') as f:
184 while True:
185 # Read chunks of 1MB
186 chunk = f.read(2 ** 20)
187 if not chunk:
188 break
189 hash.update(chunk)
190 return hash.hexdigest()
191
192def write_md5_for(file):
193 hexdigest = hash_for(file, hashlib.md5())
194 with (open(file + '.md5', 'w')) as file:
195 file.write(hexdigest)
196
197def write_sha1_for(file):
198 hexdigest = hash_for(file, hashlib.sha1())
199 with (open(file + '.sha1', 'w')) as file:
200 file.write(hexdigest)
201
202def main(argv):
203 options = parse_options(argv)
Mads Agera9745612017-11-02 12:42:15 +0100204 outdir = options.out
Mads Agera4911eb2017-11-22 13:19:36 +0100205 if outdir == None:
206 print 'Need to supply output dir with --out.'
Mads Agera9745612017-11-02 12:42:15 +0100207 exit(1)
Mads Agera4911eb2017-11-22 13:19:36 +0100208 # Build the R8 no deps artifact.
209 gradle.RunGradleExcludeDeps([utils.R8])
Mads Agera9745612017-11-02 12:42:15 +0100210 # Create directory structure for this version.
Mads Agera4911eb2017-11-22 13:19:36 +0100211 version = determine_version()
Mads Ager14d9b072017-11-20 13:42:55 +0100212 with utils.TempDir() as tmp_dir:
Rico Windc0b16382018-05-17 13:23:43 +0200213 version_dir = join(tmp_dir, utils.get_maven_path(version))
Mads Ager14d9b072017-11-20 13:42:55 +0100214 makedirs(version_dir)
215 # Write the pom file.
216 pom_file = join(version_dir, 'r8-' + version + '.pom')
217 write_pom_file(version, pom_file)
218 # Copy the jar to the output.
219 target_jar = join(version_dir, 'r8-' + version + '.jar')
Mads Agera4911eb2017-11-22 13:19:36 +0100220 copyfile(utils.R8_JAR, target_jar)
Mads Ager14d9b072017-11-20 13:42:55 +0100221 # Create check sums.
222 write_md5_for(target_jar)
223 write_md5_for(pom_file)
224 write_sha1_for(target_jar)
225 write_sha1_for(pom_file)
226 # Zip it up.
227 make_archive(join(outdir, 'r8'), 'zip', tmp_dir)
Mads Agera9745612017-11-02 12:42:15 +0100228
229if __name__ == "__main__":
230 exit(main(sys.argv[1:]))