Merge changes I721183e5,I1c0489d1
* changes:
Rewrite signature annotations for applications which are not minified
Refactor GenericSignatureRewriter to be independent of Minifier
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
similarity index 100%
rename from infra/config/cr-buildbucket.cfg
rename to infra/config/global/cr-buildbucket.cfg
diff --git a/infra/config/luci-logdog.cfg b/infra/config/global/luci-logdog.cfg
similarity index 100%
rename from infra/config/luci-logdog.cfg
rename to infra/config/global/luci-logdog.cfg
diff --git a/infra/config/luci-milo.cfg b/infra/config/global/luci-milo.cfg
similarity index 100%
rename from infra/config/luci-milo.cfg
rename to infra/config/global/luci-milo.cfg
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
similarity index 100%
rename from infra/config/luci-scheduler.cfg
rename to infra/config/global/luci-scheduler.cfg
diff --git a/infra/config/project.cfg b/infra/config/global/project.cfg
similarity index 100%
rename from infra/config/project.cfg
rename to infra/config/global/project.cfg
diff --git a/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphEdgeInfo.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphEdgeInfo.java
index ca3a732..3e55242 100644
--- a/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphEdgeInfo.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphEdgeInfo.java
@@ -3,10 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.experimental.graphinfo;
-import com.android.tools.r8.errors.Unreachable;
-
public class GraphEdgeInfo {
+ private static GraphEdgeInfo UNKNOWN = new GraphEdgeInfo(EdgeKind.Unknown);
+
+ public static GraphEdgeInfo unknown() {
+ return UNKNOWN;
+ }
+
// TODO(b/120959039): Simplify these. Most of the information is present in the source node.
public enum EdgeKind {
// Prioritized list of edge types.
@@ -23,7 +27,8 @@
ReachableFromLiveType,
ReferencedInAnnotation,
IsLibraryMethod,
- MethodHandleUseFrom
+ MethodHandleUseFrom,
+ Unknown
}
private final EdgeKind kind;
@@ -66,7 +71,10 @@
case MethodHandleUseFrom:
return "referenced by method handle";
default:
- throw new Unreachable("Unexpected edge kind: " + edgeKind());
+ assert false : "Unknown edge kind: " + edgeKind();
+ // fall through
+ case Unknown:
+ return "kept for unknown reasons";
}
}
diff --git a/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphNode.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphNode.java
index b99485a..12661c0 100644
--- a/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphNode.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphNode.java
@@ -8,12 +8,38 @@
@Keep
public abstract class GraphNode {
+ private static final GraphNode CYCLE =
+ new GraphNode(false) {
+ @Override
+ public boolean equals(Object o) {
+ return o == this;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "cycle";
+ }
+ };
+
private final boolean isLibraryNode;
public GraphNode(boolean isLibraryNode) {
this.isLibraryNode = isLibraryNode;
}
+ public static GraphNode cycle() {
+ return CYCLE;
+ }
+
+ public final boolean isCycle() {
+ return this == cycle();
+ }
+
public boolean isLibraryNode() {
return isLibraryNode;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java b/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java
index 89a6f0e..d56e455 100644
--- a/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java
+++ b/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.experimental.graphinfo.ClassGraphNode;
import com.android.tools.r8.experimental.graphinfo.FieldGraphNode;
import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
@@ -32,6 +31,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -125,50 +125,53 @@
out.println(DescriptorUtils.descriptorToJavaType(clazz.getDescriptor()));
}
- public List<Pair<GraphNode, GraphEdgeInfo>> findShortestPathTo(final GraphNode node) {
+ private List<Pair<GraphNode, GraphEdgeInfo>> findShortestPathTo(final GraphNode node) {
if (node == null) {
return null;
}
- Deque<GraphPath> queue;
- {
- Map<GraphNode, Set<GraphEdgeInfo>> sources = getSourcesTargeting(node);
- if (sources == null) {
- // The node is not targeted at all (it is not reachable).
- return null;
- }
- queue = new LinkedList<>();
- for (GraphNode source : sources.keySet()) {
- queue.addLast(new GraphPath(source, null));
- }
- }
Map<GraphNode, GraphNode> seen = new IdentityHashMap<>();
- while (!queue.isEmpty()) {
- GraphPath path = queue.removeFirst();
- Map<GraphNode, Set<GraphEdgeInfo>> sources = getSourcesTargeting(path.node);
+ Deque<GraphPath> queue = new LinkedList<>();
+ GraphPath path = null;
+ GraphNode current = node;
+ while (true) {
+ Map<GraphNode, Set<GraphEdgeInfo>> sources = getSourcesTargeting(current);
if (sources == null) {
+ // We have reached a root or the current node is not targeted at all.
return getCanonicalPath(path, node);
}
+ assert !sources.isEmpty();
for (GraphNode source : sources.keySet()) {
- if (seen.containsKey(source)) {
- continue;
+ if (!seen.containsKey(source)) {
+ seen.put(source, source);
+ queue.addLast(new GraphPath(source, path));
}
- seen.put(source, source);
- queue.addLast(new GraphPath(source, path));
}
+ // The source set was not empty, thus we don't have a real root, but all sources are seen!
+ if (queue.isEmpty()) {
+ return getCanonicalPath(new GraphPath(GraphNode.cycle(), path), node);
+ }
+ path = queue.removeFirst();
+ current = path.node;
}
- throw new Unreachable("Failed to find a root from node: " + node);
}
// Convert a internal path representation to the external API and compute the edge reasons.
private List<Pair<GraphNode, GraphEdgeInfo>> getCanonicalPath(
GraphPath path, GraphNode endTarget) {
- assert path != null;
+ if (path == null) {
+ // If there is no path to endTarget, treat it as not kept by returning a null path.
+ return null;
+ }
List<Pair<GraphNode, GraphEdgeInfo>> canonical = new ArrayList<>();
while (path.path != null) {
GraphNode source = path.node;
- GraphNode target = path.path.node;
- Set<GraphEdgeInfo> infos = getSourcesTargeting(target).get(source);
- canonical.add(new Pair<>(source, getCanonicalInfo(infos)));
+ if (source.isCycle()) {
+ canonical.add(new Pair<>(source, new GraphEdgeInfo(EdgeKind.Unknown)));
+ } else {
+ GraphNode target = path.path.node;
+ Set<GraphEdgeInfo> infos = getSourcesTargeting(target).get(source);
+ canonical.add(new Pair<>(source, getCanonicalInfo(infos)));
+ }
path = path.path;
}
Set<GraphEdgeInfo> infos = getSourcesTargeting(endTarget).get(path.node);
@@ -186,7 +189,8 @@
}
}
}
- throw new Unreachable("Unexpected empty set of graph edge info");
+ assert false : "Unexpected empty set of graph edge info";
+ return GraphEdgeInfo.unknown();
}
private void printEdge(GraphNode node, GraphEdgeInfo info, Formatter formatter) {
@@ -225,7 +229,11 @@
? keepRuleNode.getContent()
: keepRuleNode.getOrigin() + ":" + shortPositionInfo(keepRuleNode.getPosition());
}
- throw new Unreachable("Unexpected graph node type: " + node);
+ if (node == GraphNode.cycle()) {
+ return "only cyclic dependencies remain, failed to determine a path from a keep rule";
+ }
+ assert false : "Unexpected graph node type: " + node;
+ return Objects.toString(node);
}
private void addNodeMessage(GraphNode node, Formatter formatter) {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 85c4876..64a9c67 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -288,8 +288,7 @@
public LineNumberOptimization lineNumberOptimization = LineNumberOptimization.ON;
public static boolean shouldEnableKeepRuleSynthesisForRecompilation() {
- return Version.isDev()
- && System.getProperty("com.android.tools.r8.keepRuleSynthesisForRecompilation") != null;
+ return System.getProperty("com.android.tools.r8.keepRuleSynthesisForRecompilation") != null;
}
private static Set<String> getExtensiveLoggingFilter() {
diff --git a/src/test/java/com/android/tools/r8/shaking/ServiceLoaderTest.java b/src/test/java/com/android/tools/r8/shaking/ServiceLoaderTest.java
index 29e5bcd..ac4ac5f 100644
--- a/src/test/java/com/android/tools/r8/shaking/ServiceLoaderTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ServiceLoaderTest.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.references.Reference.classFromClass;
+import static com.android.tools.r8.references.Reference.methodFromMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
@@ -11,14 +13,19 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.DataEntryResource;
+import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.graph.AppServices;
import com.android.tools.r8.naming.AdaptResourceFileContentsTest.DataResourceConsumerForTesting;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.graphinspector.GraphInspector;
+import com.android.tools.r8.utils.graphinspector.GraphInspector.QueryNode;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.ServiceLoader;
@@ -54,7 +61,7 @@
serviceImplementations.add(WorldGreeter.class.getTypeName());
}
- CodeInspector inspector =
+ R8TestRunResult result =
testForR8(backend)
.addInnerClasses(ServiceLoaderTest.class)
.addKeepMainRule(TestClass.class)
@@ -69,9 +76,11 @@
new DataResourceConsumerForTesting(options.dataResourceConsumer);
options.dataResourceConsumer = dataResourceConsumer;
})
+ .enableGraphInspector()
.run(TestClass.class)
- .assertSuccessWithOutput(expectedOutput)
- .inspector();
+ .assertSuccessWithOutput(expectedOutput);
+
+ CodeInspector inspector = result.inspector();
ClassSubject greeterSubject = inspector.clazz(Greeter.class);
assertEquals(includeWorldGreeter, greeterSubject.isPresent());
@@ -92,7 +101,45 @@
assertEquals(worldGreeterSubject.getFinalName(), lines.get(1));
}
- // TODO(b/124181030): Verify that -whyareyoukeeping works as intended.
+ verifyGraphInformation(result.graphInspector());
+ }
+
+ private void verifyGraphInformation(GraphInspector graphInspector) throws Exception {
+ assertEquals(1, graphInspector.getRoots().size());
+ QueryNode keepMain = graphInspector.rule(Origin.unknown(), 1, 1).assertRoot();
+
+ MethodReference mainMethod =
+ methodFromMethod(TestClass.class.getDeclaredMethod("main", String[].class));
+ graphInspector.method(mainMethod).assertKeptBy(keepMain);
+
+ ClassReference helloGreeterClass = classFromClass(HelloGreeter.class);
+ MethodReference helloGreeterInitMethod = methodFromMethod(HelloGreeter.class.getConstructor());
+ MethodReference helloGreeterGreetingMethod =
+ methodFromMethod(HelloGreeter.class.getDeclaredMethod("greeting"));
+
+ graphInspector.clazz(helloGreeterClass).assertKeptBy(graphInspector.method(mainMethod));
+ graphInspector.clazz(helloGreeterClass).assertReflectedFrom(mainMethod);
+ graphInspector.method(helloGreeterInitMethod).assertReflectedFrom(mainMethod);
+
+ // TODO(b/121313747): greeting() is called from main(), so this should be strengthened to
+ // `assertInvokedFrom(mainMethod)`.
+ graphInspector.method(helloGreeterGreetingMethod).assertPresent();
+
+ if (includeWorldGreeter) {
+ ClassReference worldGreeterClass = classFromClass(WorldGreeter.class);
+ MethodReference worldGreeterInitMethod =
+ methodFromMethod(WorldGreeter.class.getConstructor());
+ MethodReference worldGreeterGreetingMethod =
+ methodFromMethod(WorldGreeter.class.getDeclaredMethod("greeting"));
+
+ graphInspector.clazz(worldGreeterClass).assertKeptBy(graphInspector.method(mainMethod));
+ graphInspector.clazz(worldGreeterClass).assertReflectedFrom(mainMethod);
+ graphInspector.method(worldGreeterInitMethod).assertReflectedFrom(mainMethod);
+
+ // TODO(b/121313747): greeting() is called from main(), so this should be strengthened to
+ // `assertInvokedFrom(mainMethod)`.
+ graphInspector.method(worldGreeterGreetingMethod).assertPresent();
+ }
}
@Test
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java
new file mode 100644
index 0000000..344721f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java
@@ -0,0 +1,126 @@
+// 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.
+package com.android.tools.r8.shaking.keptgraph;
+
+import static com.android.tools.r8.references.Reference.classFromClass;
+import static com.android.tools.r8.references.Reference.methodFromMethod;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.VmTestRunner.IgnoreIfVmOlderThan;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.graphinspector.GraphInspector;
+import com.android.tools.r8.utils.graphinspector.GraphInspector.QueryNode;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.function.Supplier;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KeptViaClassInitializerTestRunner extends TestBase {
+
+ @NeverMerge
+ @NeverClassInline
+ public static class A {
+
+ @Override
+ public String toString() {
+ return "I'm an A";
+ }
+ }
+
+ @NeverMerge
+ @NeverClassInline
+ public enum T {
+ A(A::new);
+
+ private final Supplier<Object> factory;
+
+ T(Supplier<Object> factory) {
+ this.factory = factory;
+ }
+
+ public Object create() {
+ return factory.get();
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ System.out.println(T.A.create());
+ }
+ }
+
+ private static final Class<?> CLASS = Main.class;
+ private static final String EXPECTED = StringUtils.lines("I'm an A");
+
+ private final Backend backend;
+
+ @Parameters(name = "{0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ public KeptViaClassInitializerTestRunner(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ @IgnoreIfVmOlderThan(Version.V7_0_0)
+ public void testKeptMethod() throws Exception {
+ MethodReference mainMethod =
+ methodFromMethod(Main.class.getDeclaredMethod("main", String[].class));
+
+ WhyAreYouKeepingConsumer consumer = new WhyAreYouKeepingConsumer(null);
+ GraphInspector inspector =
+ testForR8(backend)
+ .enableGraphInspector(consumer)
+ .enableInliningAnnotations()
+ .addProgramClassesAndInnerClasses(Main.class, A.class, T.class)
+ .addKeepMethodRules(mainMethod)
+ .apply(
+ b -> {
+ if (backend == Backend.DEX) {
+ b.setMinApi(AndroidApiLevel.N);
+ b.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.N));
+ }
+ })
+ .run(Main.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .graphInspector();
+
+ // The only root should be the keep main-method rule.
+ assertEquals(1, inspector.getRoots().size());
+ QueryNode root = inspector.rule(Origin.unknown(), 1, 1).assertRoot();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ consumer.printWhyAreYouKeeping(classFromClass(A.class), new PrintStream(baos));
+
+ // TODO(b/124501298): Currently the rooted path is not found.
+ assertThat(baos.toString(), containsString("is kept for unknown reason"));
+
+ // TODO(b/124499108): Currently synthetic lambda classes are referenced,
+ // should be their originating context.
+ if (backend == Backend.DEX) {
+ assertThat(baos.toString(), containsString("-$$Lambda$"));
+ } else {
+ assertThat(baos.toString(), not(containsString("-$$Lambda$")));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java
new file mode 100644
index 0000000..da94e04
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/WhyAreYouKeepingAllTest.java
@@ -0,0 +1,44 @@
+// 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.
+package com.android.tools.r8.shaking.keptgraph;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Test;
+
+/**
+ * Run compiling R8 with R8 using a match-all -whyareyoukeeping rule to check that it does not cause
+ * compilation to fail.
+ */
+public class WhyAreYouKeepingAllTest extends TestBase {
+
+ private static final Path MAIN_KEEP = Paths.get("src/main/keep.txt");
+
+ private static final String WHY_ARE_YOU_KEEPING_ALL = StringUtils.lines(
+ "-whyareyoukeeping class ** { *; }",
+ "-whyareyoukeeping @interface ** { *; }"
+ );
+
+ @Test
+ public void test() throws Throwable {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ testForR8(Backend.CF)
+ .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR)
+ .addKeepRuleFiles(MAIN_KEEP)
+ .addKeepRules(WHY_ARE_YOU_KEEPING_ALL)
+ .redirectStdOut(new PrintStream(baos))
+ .compile();
+ assertThat(baos.toString(), containsString("referenced in keep rule"));
+ // TODO(b/124655065): We should always know the reason for keeping.
+ assertThat(baos.toString(), containsString("kept for unknown reasons"));
+ }
+}
diff --git a/third_party/opensource_apps.tar.gz.sha1 b/third_party/opensource_apps.tar.gz.sha1
index 4ee5113..1695642 100644
--- a/third_party/opensource_apps.tar.gz.sha1
+++ b/third_party/opensource_apps.tar.gz.sha1
@@ -1 +1 @@
-efed1b4bf62340b626cf2d0addb4f334664c0727
\ No newline at end of file
+682d306b6e9a1c6356f1dbfe23f5acef4bc23a2f
\ No newline at end of file
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index f3cc2eb..7f5e79f 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -27,8 +27,7 @@
WORKING_DIR = os.environ['R8_BENCHMARK_DIR']
# For running on Golem all APPS are bundled as an x20-dependency and then copied
-# to WORKING_DIR. To make it easier to update the app-bundle, remove the folder
-# WORKING_DIR and then run run_on_as_app.py --download-only.
+# to WORKING_DIR. To update the app-bundle use 'run_on_as_app_x20_packager.py'.
APPS = {
# 'app-name': {
# 'git_repo': ...
@@ -100,7 +99,7 @@
'app_id': 'io.rover.app.debug',
'app_module': 'debug-app',
'git_repo': 'https://github.com/mkj-gram/rover-android.git',
- 'revision': 'd2e876e597b3af7eab406e38a0e08327a38bd942',
+ 'revision': '859af82ba56fe9035ae9949156c7a88e6012d930',
},
'Signal-Android': {
'app_id': 'org.thoughtcrime.securesms',
@@ -108,7 +107,7 @@
'flavor': 'play',
'git_repo': 'https://github.com/mkj-gram/Signal-Android.git',
'main_dex_rules': 'multidex-config.pro',
- 'revision': '85e1a10993e5e9ffe923f0798b26cbc44068ba31',
+ 'revision': 'a45d0c1fed20fa39e8b9445fe7790326f46b3166',
'releaseTarget': 'assemblePlayRelease',
'signed-apk-name': 'Signal-play-release-4.32.7.apk',
},
@@ -193,14 +192,14 @@
def IsTrackedByGit(file):
return subprocess.check_output(['git', 'ls-files', file]).strip() != ''
-def GitClone(git_url, revision, checkout_dir, options):
+def GitClone(git_url, revision, checkout_dir, quiet):
result = subprocess.check_output(
['git', 'clone', git_url, checkout_dir]).strip()
head_rev = utils.get_HEAD_sha1_for_checkout(checkout_dir)
if revision == head_rev:
return result
warn('Target revision is not head in {}.'.format(checkout_dir))
- with utils.ChangedWorkingDirectory(checkout_dir, quiet=options.quiet):
+ with utils.ChangedWorkingDirectory(checkout_dir, quiet=quiet):
subprocess.check_output(['git', 'reset', '--hard', revision])
return result
@@ -268,7 +267,8 @@
if not os.path.exists(checkout_dir) and not options.golem:
with utils.ChangedWorkingDirectory(WORKING_DIR, quiet=options.quiet):
- GitClone(config['git_repo'], config['revision'], checkout_dir, options)
+ GitClone(
+ config['git_repo'], config['revision'], checkout_dir, options.quiet)
checkout_rev = utils.get_HEAD_sha1_for_checkout(checkout_dir)
if config['revision'] != checkout_rev:
@@ -346,7 +346,12 @@
# Sanity check that keep rules have changed.
with open(ext_proguard_config_file) as new:
with open(proguard_config_file) as old:
- assert(sum(1 for line in new) > sum(1 for line in old))
+ assert(
+ sum(1 for line in new
+ if line.strip() and '-printconfiguration' not in line)
+ >
+ sum(1 for line in old
+ if line.strip() and '-printconfiguration' not in line))
# Extract min-sdk and target-sdk
(min_sdk, compile_sdk) = as_utils.GetMinAndCompileSdk(app, config,
@@ -714,13 +719,13 @@
assert shrinker in SHRINKERS
return (options, args)
-def download_apps(options):
+def download_apps(quiet):
# Download apps and place in build
with utils.ChangedWorkingDirectory(WORKING_DIR):
for app, config in APPS.iteritems():
app_dir = os.path.join(WORKING_DIR, app)
if not os.path.exists(app_dir):
- GitClone(config['git_repo'], config['revision'], app_dir, options)
+ GitClone(config['git_repo'], config['revision'], app_dir, quiet)
def main(argv):
@@ -738,7 +743,7 @@
os.makedirs(WORKING_DIR)
if options.download_only:
- download_apps(options)
+ download_apps(options.quiet)
return
with utils.TempDir() as temp_dir:
diff --git a/tools/run_on_as_app_x20_packager.py b/tools/run_on_as_app_x20_packager.py
new file mode 100755
index 0000000..5c84626
--- /dev/null
+++ b/tools/run_on_as_app_x20_packager.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# 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 os
+import run_on_as_app
+import shutil
+import sys
+import upload_to_x20
+import utils
+
+def main():
+ # We need prodaccess to upload to x20
+ utils.check_prodacces()
+
+ working_dir = run_on_as_app.WORKING_DIR
+
+ print 'Removing directories that do not match checked out revision'
+ with utils.ChangedWorkingDirectory(working_dir):
+ for app, config in run_on_as_app.APPS.iteritems():
+ app_dir = os.path.join(working_dir, app)
+ if os.path.exists(app_dir) \
+ and utils.get_HEAD_sha1_for_checkout(app_dir) != config['revision']:
+ print 'Removing %s' % app_dir
+ shutil.rmtree(app_dir)
+
+ print 'Downloading all missing apps'
+ run_on_as_app.download_apps(quiet=False)
+
+ # Package all files as x20 dependency
+ parent_dir = os.path.dirname(working_dir)
+ with utils.ChangedWorkingDirectory(parent_dir):
+ print 'Creating archive for opensource_apps (this may take some time)'
+ working_dir_name = os.path.basename(working_dir)
+ app_dirs = [working_dir_name + '/' + name
+ for name in run_on_as_app.APPS.keys()]
+ filename = utils.create_archive("opensource_apps", app_dirs)
+ sha1 = utils.get_sha1(filename)
+ dest = os.path.join(upload_to_x20.GMSCORE_DEPS, sha1)
+ upload_to_x20.uploadFile(filename, dest)
+ sha1_file = '%s.sha1' % filename
+ with open(sha1_file, 'w') as output:
+ output.write(sha1)
+ shutil.move(sha1_file,
+ os.path.join(utils.THIRD_PARTY, 'opensource_apps.tar.gz.sha1'))
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/tools/utils.py b/tools/utils.py
index 892fe7d..f6e0a70 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -271,9 +271,13 @@
subprocess.check_call(cmd)
def create_archive(name):
+ return create_archive(name, [name])
+
+def create_archive(name, sources):
tarname = '%s.tar.gz' % name
with tarfile.open(tarname, 'w:gz') as tar:
- tar.add(name)
+ for source in sources:
+ tar.add(source)
return tarname
def extract_dir(filename):
@@ -288,6 +292,9 @@
with tarfile.open(filename, 'r:gz') as tar:
tar.extractall(path=dirname)
+def check_prodacces():
+ subprocess.check_call(['prodaccess'])
+
# Note that gcs is eventually consistent with regards to list operations.
# This is not a problem in our case, but don't ever use this method
# for synchronization.