diff options
Diffstat (limited to 'src/main/java/com/google')
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); + } +} |