aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com
diff options
context:
space:
mode:
authorGravatar Dmitry Lomov <dslomov@google.com>2016-02-24 22:20:34 +0000
committerGravatar Philipp Wollermann <philwo@google.com>2016-02-25 14:13:28 +0000
commit029dcc7929493f9a2c72daa8720c9ff06e003483 (patch)
treea0f48b90c0c1c1b3c9839bc83d742b802bc0e16d /src/main/java/com
parentd188735707db1d1ec969ca84d959fb8c6e716b06 (diff)
Expose Android resources in Skylark API.
Also expose functionality to calculate resource source directory from Android resource artifact. -- MOS_MIGRATED_REVID=115492705
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java63
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java60
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkApiProvider.java36
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkCommon.java41
6 files changed, 156 insertions, 61 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index d5e19f766d..9df8a6fa54 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -17,6 +17,7 @@ package com.google.devtools.build.lib.bazel.rules;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.BaseRuleClasses;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider.PrerequisiteValidator;
@@ -76,6 +77,7 @@ import com.google.devtools.build.lib.rules.android.AndroidBinaryOnlyRule;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration;
import com.google.devtools.build.lib.rules.android.AndroidLibraryBaseRule;
import com.google.devtools.build.lib.rules.android.AndroidRuleClasses;
+import com.google.devtools.build.lib.rules.android.AndroidSkylarkCommon;
import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions;
import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
import com.google.devtools.build.lib.rules.apple.AppleToolchain;
@@ -124,6 +126,7 @@ import com.google.devtools.build.lib.rules.repository.BindRule;
import com.google.devtools.build.lib.rules.repository.LocalRepositoryRule;
import com.google.devtools.build.lib.rules.repository.NewLocalRepositoryRule;
import com.google.devtools.build.lib.rules.repository.WorkspaceBaseRule;
+import com.google.devtools.build.lib.syntax.SkylarkType;
import com.google.devtools.build.lib.util.ResourceFileLoader;
import java.io.IOException;
@@ -222,6 +225,13 @@ public class BazelRuleClassProvider {
AndroidConfiguration.Options.class
);
+ /**
+ * Java objects accessible from Skylark rule implementations using this module.
+ */
+ public static final ImmutableMap<String, SkylarkType> skylarkBuiltinJavaObects =
+ ImmutableMap.of("android_common", SkylarkType.of(AndroidSkylarkCommon.class));
+
+
public static void setup(ConfiguredRuleClassProvider.Builder builder) {
builder
.addBuildInfoFactory(new BazelJavaBuildInfoFactory())
@@ -231,7 +241,9 @@ public class BazelRuleClassProvider {
.setPrelude("//tools/build_rules:prelude_bazel")
.setRunfilesPrefix("")
.setToolsRepository("@bazel_tools")
- .setPrerequisiteValidator(new BazelPrerequisiteValidator());
+ .setPrerequisiteValidator(new BazelPrerequisiteValidator())
+ .setSkylarkAccessibleJavaClasses(ImmutableMap.<String, SkylarkType>of())
+ .setSkylarkAccessibleJavaClasses(skylarkBuiltinJavaObects);
builder.addBuildOptions(BUILD_OPTIONS);
diff --git a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
index 1e1f2535e5..4749ab69bf 100644
--- a/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/ideinfo/AndroidStudioInfoAspect.java
@@ -315,8 +315,7 @@ public class AndroidStudioInfoAspect implements ConfiguredNativeAspectFactory {
if (ruleKind == Kind.ANDROID_LIBRARY
|| ruleKind == Kind.ANDROID_BINARY
|| ruleKind == Kind.ANDROID_TEST) {
- outputBuilder.setAndroidRuleIdeInfo(
- makeAndroidRuleIdeInfo(base, ideResolveArtifacts));
+ outputBuilder.setAndroidRuleIdeInfo(makeAndroidRuleIdeInfo(base, ideResolveArtifacts));
}
AndroidStudioInfoFilesProvider provider = providerBuilder.build();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
index 306418e08a..061018ce90 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
@@ -292,6 +292,69 @@ public class AndroidCommon {
}
}
+ static PathFragment getSourceDirectoryRelativePathFromResource(Artifact resource) {
+ PathFragment resourceDir = LocalResourceContainer.Builder.findResourceDir(resource);
+ if (resourceDir == null) {
+ return null;
+ }
+ return trimTo(resource.getRootRelativePath(), resourceDir);
+ }
+
+ /**
+ * Finds the rightmost occurrence of the needle and returns subfragment of the haystack from
+ * left to the end of the occurrence inclusive of the needle.
+ *
+ * <pre>
+ * `Example:
+ * Given the haystack:
+ * res/research/handwriting/res/values/strings.xml
+ * And the needle:
+ * res
+ * Returns:
+ * res/research/handwriting/res
+ * </pre>
+ */
+ static PathFragment trimTo(PathFragment haystack, PathFragment needle) {
+ if (needle.equals(PathFragment.EMPTY_FRAGMENT)) {
+ return haystack;
+ }
+ // Compute the overlap offset for duplicated parts of the needle.
+ int[] overlap = new int[needle.segmentCount() + 1];
+ // Start overlap at -1, as it will cancel out the increment in the search.
+ // See http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm for the
+ // details.
+ overlap[0] = -1;
+ for (int i = 0, j = -1; i < needle.segmentCount(); j++, i++, overlap[i] = j) {
+ while (j >= 0 && !needle.getSegment(i).equals(needle.getSegment(j))) {
+ // Walk the overlap until the bound is found.
+ j = overlap[j];
+ }
+ }
+ // TODO(corysmith): reverse the search algorithm.
+ // Keep the index of the found so that the rightmost index is taken.
+ int found = -1;
+ for (int i = 0, j = 0; i < haystack.segmentCount(); i++) {
+
+ while (j >= 0 && !haystack.getSegment(i).equals(needle.getSegment(j))) {
+ // Not matching, walk the needle index to attempt another match.
+ j = overlap[j];
+ }
+ j++;
+ // Needle index is exhausted, so the needle must match.
+ if (j == needle.segmentCount()) {
+ // Record the found index + 1 to be inclusive of the end index.
+ found = i + 1;
+ // Subtract one from the needle index to restart the search process
+ j = j - 1;
+ }
+ }
+ if (found != -1) {
+ // Return the subsection of the haystack.
+ return haystack.subFragment(0, found);
+ }
+ throw new IllegalArgumentException(String.format("%s was not found in %s", needle, haystack));
+ }
+
Artifact compileDexWithJack(
MultidexMode mode, Optional<Artifact> mainDexList, Collection<Artifact> proguardSpecs) {
return jackCompilationHelper.compileAsDex(mode, mainDexList, proguardSpecs);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java
index 8a5184ad29..d39365a17a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdeInfoProvider.java
@@ -239,11 +239,10 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
}
public Builder addResourceSource(Artifact resource) {
- PathFragment resourceDir = LocalResourceContainer.Builder.findResourceDir(resource);
resourceDirs.add(
SourceDirectory.fromRoot(
resource.getRoot(),
- trimTo(resource.getRootRelativePath(), resourceDir)));
+ AndroidCommon.getSourceDirectoryRelativePathFromResource(resource)));
return this;
}
@@ -264,8 +263,7 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
public Builder addAssetSource(Artifact asset, PathFragment assetDir) {
assetDirs.add(
SourceDirectory.fromRoot(
- asset.getRoot(),
- trimTo(asset.getRootRelativePath(), assetDir)));
+ asset.getRoot(), AndroidCommon.trimTo(asset.getRootRelativePath(), assetDir)));
return this;
}
@@ -274,60 +272,6 @@ public final class AndroidIdeInfoProvider implements TransitiveInfoProvider {
return this;
}
- /**
- * Finds the rightmost occurrence of the needle and returns subfragment of the haystack from
- * left to the end of the occurrence inclusive of the needle.
- *
- * <pre>
- * `Example:
- * Given the haystack:
- * res/research/handwriting/res/values/strings.xml
- * And the needle:
- * res
- * Returns:
- * res/research/handwriting/res
- * </pre>
- */
- private static PathFragment trimTo(PathFragment haystack, PathFragment needle) {
- if (needle.equals(PathFragment.EMPTY_FRAGMENT)) {
- return haystack;
- }
- // Compute the overlap offset for duplicated parts of the needle.
- int[] overlap = new int[needle.segmentCount() + 1];
- // Start overlap at -1, as it will cancel out the increment in the search.
- // See http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm for the
- // details.
- overlap[0] = -1;
- for (int i = 0, j = -1; i < needle.segmentCount(); j++, i++, overlap[i] = j) {
- while (j >= 0 && !needle.getSegment(i).equals(needle.getSegment(j))) {
- // Walk the overlap until the bound is found.
- j = overlap[j];
- }
- }
- // TODO(corysmith): reverse the search algorithm.
- // Keep the index of the found so that the rightmost index is taken.
- int found = -1;
- for (int i = 0, j = 0; i < haystack.segmentCount(); i++) {
-
- while (j >= 0 && !haystack.getSegment(i).equals(needle.getSegment(j))) {
- // Not matching, walk the needle index to attempt another match.
- j = overlap[j];
- }
- j++;
- // Needle index is exhausted, so the needle must match.
- if (j == needle.segmentCount()) {
- // Record the found index + 1 to be inclusive of the end index.
- found = i + 1;
- // Subtract one from the needle index to restart the search process
- j = j - 1;
- }
- }
- if (found != -1) {
- // Return the subsection of the haystack.
- return haystack.subFragment(0, found);
- }
- throw new IllegalArgumentException(String.format("%s was not found in %s", needle, haystack));
- }
}
private final String javaPackage;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkApiProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkApiProvider.java
index 2580a05b85..707e8ed794 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkApiProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkApiProvider.java
@@ -13,9 +13,16 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.android;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.rules.SkylarkApiProvider;
+import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceContainer;
+import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceType;
import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.OutputJar;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
@@ -100,6 +107,35 @@ public class AndroidSkylarkApiProvider extends SkylarkApiProvider {
return idlInfo;
}
+ @SkylarkCallable(
+ name = "resources",
+ structField = true,
+ doc = "Returns resources defined by this target."
+ )
+ public NestedSet<Artifact> getResources() {
+ return collectDirectArtifacts(ResourceType.RESOURCES);
+ }
+
+ private NestedSet<Artifact> collectDirectArtifacts(final ResourceType resources) {
+ AndroidResourcesProvider provider = getInfo().getProvider(AndroidResourcesProvider.class);
+ if (provider == null) {
+ return NestedSetBuilder.emptySet(Order.STABLE_ORDER);
+ }
+ // This will iterate over all (direct) resources. If this turns out to be a performance
+ // problem, {@link ResourceContainer#getArtifacts} can be changed to return NestedSets.
+ return NestedSetBuilder.wrap(
+ Order.STABLE_ORDER,
+ Iterables.concat(
+ Iterables.transform(
+ provider.getDirectAndroidResources(),
+ new Function<ResourceContainer, Iterable<Artifact>>() {
+ @Override
+ public Iterable<Artifact> apply(ResourceContainer resourceContainer) {
+ return resourceContainer.getArtifacts(resources);
+ }
+ })));
+ }
+
/**
* Helper class to provide information about IDLs related to this rule.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkCommon.java
new file mode 100644
index 0000000000..1724cfa4f8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkCommon.java
@@ -0,0 +1,41 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.rules.android;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+/**
+ * Common utilities for Skylark rules related to Android.
+ */
+@SkylarkModule(
+ name = "android_common",
+ doc = "Common utilities and fucntionality related to Android rules."
+)
+public class AndroidSkylarkCommon {
+ @SkylarkCallable(
+ name = "resource_source_directory",
+ allowReturnNones = true,
+ doc =
+ "Returns a source directory for Android resource file. "
+ + "The source directory is a prefix of resource's relative path up to "
+ + "a directory that designates resource kind (cf. "
+ + "http://developer.android.com/guide/topics/resources/providing-resources.html)."
+ )
+ public static PathFragment getSourceDirectoryRelativePathFromResource(Artifact resource) {
+ return AndroidCommon.getSourceDirectoryRelativePathFromResource(resource);
+ }
+}