diff options
author | ajmichael <ajmichael@google.com> | 2017-05-05 04:19:34 +0200 |
---|---|---|
committer | Damien Martin-Guillerez <dmarting@google.com> | 2017-05-05 15:27:23 +0200 |
commit | 14747a8bf2d35846d75ac9058e1b514a89f68f07 (patch) | |
tree | 51693a3aaf6ec6421bc0226355dc0c66a306fce3 /src/main/java/com/google/devtools/build | |
parent | f2528c1b96751692aae233aa839f86d0f887b75f (diff) |
Create new android_device_script_fixture rule.
This rule simply provides a shell script that is run on a device as part of a
test which can come from an input file or as a string command.
It also takes a list of APKs that need to be installed before the fixture can
be run.
Note that this CL does _not_ install the rule in the BazelRuleClassProvider, so
this CL does not make it usable by anyone. Once the other android testing rules are ready, I will install them all.
One small step towards https://github.com/bazelbuild/bazel/issues/903.
RELNOTES: None
PiperOrigin-RevId: 155155984
Diffstat (limited to 'src/main/java/com/google/devtools/build')
5 files changed, 235 insertions, 0 deletions
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 922d87e7dc..f8aebaefd4 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 @@ -64,6 +64,7 @@ import com.google.devtools.build.lib.rules.java.JavaUtil; import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider; import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector.InstrumentationSpec; import com.google.devtools.build.lib.syntax.Type; +import com.google.devtools.build.lib.util.FileType; import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; @@ -962,4 +963,26 @@ public class AndroidCommon { return new JavaCommon(ruleContext, semantics, srcs, compileDeps, runtimeDeps, bothDeps); } + + /** + * Gets the transitive support APKs required by this rule through the {@code support_apks} + * attribute. + */ + static NestedSet<Artifact> getSupportApks(RuleContext ruleContext) { + NestedSetBuilder<Artifact> supportApks = NestedSetBuilder.stableOrder(); + for (TransitiveInfoCollection dep : ruleContext.getPrerequisites("support_apks", Mode.TARGET)) { + ApkProvider apkProvider = dep.getProvider(ApkProvider.class); + FileProvider fileProvider = dep.getProvider(FileProvider.class); + // If ApkProvider is present, do not check FileProvider for .apk files. For example, + // android_binary creates a FileProvider containing both the signed and unsigned APKs. + if (apkProvider != null) { + supportApks.addTransitive(apkProvider.getTransitiveApks()); + } else if (fileProvider != null) { + // The rule definition should enforce that only .apk files are allowed, however, it can't + // hurt to double check. + supportApks.addAll(FileType.filter(fileProvider.getFilesToBuild(), AndroidRuleClasses.APK)); + } + } + return supportApks.build(); + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java new file mode 100644 index 0000000000..648b282831 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java @@ -0,0 +1,85 @@ +// Copyright 2017 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.common.collect.Iterables; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.analysis.actions.FileWriteAction; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; +import com.google.devtools.build.lib.syntax.Type; + +/** An implementation of the {@code android_device_script_fixture} rule. */ +public class AndroidDeviceScriptFixture implements RuleConfiguredTargetFactory { + + @Override + public ConfiguredTarget create(RuleContext ruleContext) + throws InterruptedException, RuleErrorException { + Artifact fixtureScript = getFixtureScript(ruleContext); + return new RuleConfiguredTargetBuilder(ruleContext) + .setFilesToBuild(NestedSetBuilder.<Artifact>stableOrder().add(fixtureScript).build()) + .addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY) + .addNativeDeclaredProvider( + new AndroidDeviceScriptFixtureInfoProvider( + fixtureScript, + AndroidCommon.getSupportApks(ruleContext), + ruleContext.attributes().get("daemon", Type.BOOLEAN), + ruleContext.attributes().get("strict_exit", Type.BOOLEAN))) + .build(); + } + + /** + * Gets the fixture script from the {@code script} attribute if set or else writes a file + * containing the contents of the {@code cmd} attribute. Also, checks that exactly one of {@code + * script} and {@code cmd} is set. + */ + private static Artifact getFixtureScript(RuleContext ruleContext) + throws RuleErrorException, InterruptedException { + String cmd = null; + if (ruleContext.attributes().isAttributeValueExplicitlySpecified("cmd")) { + cmd = ruleContext.attributes().get("cmd", Type.STRING); + } + TransitiveInfoCollection script = ruleContext.getPrerequisite("script", Mode.TARGET); + + if (((cmd == null) && (script == null)) || ((cmd != null) && (script != null))) { + ruleContext.throwWithRuleError( + "android_host_service_fixture requires that exactly one of the script and cmd attributes " + + "be specified"); + } + + if (cmd == null) { + // The fact that there is only one file and that it has the right extension is enforced by the + // rule definition. + return Iterables.getOnlyElement(script.getProvider(FileProvider.class).getFilesToBuild()); + } else { + return writeFixtureScript(ruleContext, cmd); + } + } + + private static Artifact writeFixtureScript(RuleContext ruleContext, String cmd) + throws InterruptedException { + Artifact output = + ruleContext.getUniqueDirectoryArtifact( + "cmd_device_fixtures", "cmd.sh", ruleContext.getBinOrGenfilesDirectory()); + ruleContext.registerAction(FileWriteAction.create(ruleContext, output, cmd, false)); + return output; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureInfoProvider.java new file mode 100644 index 0000000000..42b7b11a70 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureInfoProvider.java @@ -0,0 +1,65 @@ +// Copyright 2017 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.common.collect.ImmutableMap; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.NativeClassObjectConstructor; +import com.google.devtools.build.lib.packages.SkylarkClassObject; + +/** + * Information about an {@code android_device_script_fixture} to run as part of an {@code + * android_instrumentation_test}. + */ +@Immutable +public class AndroidDeviceScriptFixtureInfoProvider extends SkylarkClassObject + implements TransitiveInfoProvider { + + private static final String SKYLARK_NAME = "DeviceScriptFixtureInfo"; + public static final NativeClassObjectConstructor ANDROID_DEVICE_SCRIPT_FIXTURE_INFO = + new NativeClassObjectConstructor(SKYLARK_NAME) {}; + + private final Artifact fixtureScript; + private final NestedSet<Artifact> supportApks; + private final boolean daemon; + private final boolean strictExit; + + public AndroidDeviceScriptFixtureInfoProvider( + Artifact fixtureScript, NestedSet<Artifact> supportApks, boolean daemon, boolean strictExit) { + super(ANDROID_DEVICE_SCRIPT_FIXTURE_INFO, ImmutableMap.<String, Object>of()); + this.fixtureScript = fixtureScript; + this.supportApks = supportApks; + this.daemon = daemon; + this.strictExit = strictExit; + } + + public Artifact getFixtureScript() { + return fixtureScript; + } + + public NestedSet<Artifact> getSupportApks() { + return supportApks; + } + + public boolean getDaemon() { + return daemon; + } + + public boolean getStrictExit() { + return strictExit; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureRule.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureRule.java new file mode 100644 index 0000000000..9904978c4c --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixtureRule.java @@ -0,0 +1,61 @@ +// Copyright 2017 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 static com.google.devtools.build.lib.packages.Attribute.attr; +import static com.google.devtools.build.lib.packages.BuildType.LABEL; +import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; +import static com.google.devtools.build.lib.syntax.Type.BOOLEAN; +import static com.google.devtools.build.lib.syntax.Type.STRING; + +import com.google.devtools.build.lib.analysis.BaseRuleClasses; +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleClass.Builder; +import com.google.devtools.build.lib.util.FileType; + +/** Rule definition for the {@code android_device_script_fixture} rule. */ +public class AndroidDeviceScriptFixtureRule implements RuleDefinition { + + static final FileType DEVICE_SCRIPT_FIXTURE = FileType.of(".sh"); + + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) { + return builder + .setUndocumented() + .add( + attr("script", LABEL) + .exec() + .allowedFileTypes(DEVICE_SCRIPT_FIXTURE) + .allowedRuleClasses()) + .add(attr("cmd", STRING)) + .add( + attr("support_apks", LABEL_LIST) + .allowedFileTypes(AndroidRuleClasses.APK) + .allowedRuleClasses("android_binary")) + .add(attr("daemon", BOOLEAN).value(Boolean.FALSE)) + .add(attr("strict_exit", BOOLEAN).value(Boolean.TRUE)) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("android_device_script_fixture") + .ancestors(BaseRuleClasses.RuleBase.class) + .factoryClass(AndroidDeviceScriptFixture.class) + .build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java index d352144810..d70894dabf 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java @@ -171,6 +171,7 @@ public final class AndroidRuleClasses { fromTemplates("%{name}_images/userdata_images.dat"); public static final SafeImplicitOutputsFunction ANDROID_DEVICE_EMULATOR_METADATA = fromTemplates("%{name}_images/emulator-meta-data.pb"); + static final FileType APK = FileType.of(".apk"); /** * The default label of android_sdk option |