| // 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 static com.google.common.base.Preconditions.checkNotNull; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion; |
| import java.util.Collections; |
| import java.util.List; |
| |
| /** Builder for creating resource shrinker actions. */ |
| public class ResourceShrinkerActionBuilder { |
| private AndroidAaptVersion targetAaptVersion; |
| private Artifact resourceFilesZip; |
| private Artifact shrunkJar; |
| private Artifact proguardMapping; |
| private ValidatedAndroidResources primaryResources; |
| private ResourceDependencies dependencyResources; |
| private Artifact resourceApkOut; |
| private Artifact shrunkResourcesOut; |
| private Artifact logOut; |
| |
| private List<String> uncompressedExtensions = Collections.emptyList(); |
| private ResourceFilterFactory resourceFilterFactory = ResourceFilterFactory.empty(); |
| |
| public ResourceShrinkerActionBuilder setUncompressedExtensions( |
| List<String> uncompressedExtensions) { |
| this.uncompressedExtensions = uncompressedExtensions; |
| return this; |
| } |
| |
| /** @param resourceFilterFactory The filters to apply to the resources. */ |
| public ResourceShrinkerActionBuilder setResourceFilterFactory( |
| ResourceFilterFactory resourceFilterFactory) { |
| this.resourceFilterFactory = resourceFilterFactory; |
| return this; |
| } |
| |
| /** @param resourceFilesZip A zip file containing the merged assets and resources to be shrunk. */ |
| public ResourceShrinkerActionBuilder withResourceFiles(Artifact resourceFilesZip) { |
| this.resourceFilesZip = resourceFilesZip; |
| return this; |
| } |
| |
| /** @param shrunkJar The deploy jar of the rule after a dead code removal Proguard pass. */ |
| public ResourceShrinkerActionBuilder withShrunkJar(Artifact shrunkJar) { |
| this.shrunkJar = shrunkJar; |
| return this; |
| } |
| |
| /** @param proguardMapping The Proguard mapping between obfuscated and original code. */ |
| public ResourceShrinkerActionBuilder withProguardMapping(Artifact proguardMapping) { |
| this.proguardMapping = proguardMapping; |
| return this; |
| } |
| |
| /** |
| * @param primary The fully processed {@link ValidatedAndroidResources} of the resources to be |
| * shrunk. Must contain both an R.txt and merged manifest. |
| */ |
| public ResourceShrinkerActionBuilder withPrimary(ValidatedAndroidResources primary) { |
| checkNotNull(primary); |
| checkNotNull(primary.getManifest()); |
| checkNotNull(primary.getRTxt()); |
| this.primaryResources = primary; |
| return this; |
| } |
| |
| /** @param resourceDeps The full dependency tree of resources. */ |
| public ResourceShrinkerActionBuilder withDependencies(ResourceDependencies resourceDeps) { |
| this.dependencyResources = resourceDeps; |
| return this; |
| } |
| |
| /** @param resourceApkOut The location to write the shrunk resource ap_ package. */ |
| public ResourceShrinkerActionBuilder setResourceApkOut(Artifact resourceApkOut) { |
| this.resourceApkOut = resourceApkOut; |
| return this; |
| } |
| |
| /** @param shrunkResourcesOut The location to write the shrunk resource files zip. */ |
| public ResourceShrinkerActionBuilder setShrunkResourcesOut(Artifact shrunkResourcesOut) { |
| this.shrunkResourcesOut = shrunkResourcesOut; |
| return this; |
| } |
| |
| /** @param logOut The location to write the shrinker log. */ |
| public ResourceShrinkerActionBuilder setLogOut(Artifact logOut) { |
| this.logOut = logOut; |
| return this; |
| } |
| |
| /** @param androidAaptVersion The aapt version to target with this action. */ |
| public ResourceShrinkerActionBuilder setTargetAaptVersion(AndroidAaptVersion androidAaptVersion) { |
| this.targetAaptVersion = androidAaptVersion; |
| return this; |
| } |
| |
| public Artifact build(AndroidDataContext dataContext) { |
| |
| checkNotNull(resourceFilesZip); |
| checkNotNull(shrunkJar); |
| checkNotNull(proguardMapping); |
| checkNotNull(primaryResources); |
| checkNotNull(primaryResources.getRTxt()); |
| checkNotNull(primaryResources.getManifest()); |
| checkNotNull(resourceApkOut); |
| |
| BusyBoxActionBuilder builder; |
| if (targetAaptVersion == AndroidAaptVersion.AAPT2) { |
| builder = BusyBoxActionBuilder.create(dataContext, "SHRINK_AAPT2"); |
| } else { |
| builder = |
| BusyBoxActionBuilder.create(dataContext, "SHRINK") |
| .maybeAddVectoredFlag("--uncompressedExtensions", uncompressedExtensions) |
| // Order, for some reason, is important. |
| .addVectoredFlag( |
| "--resourcePackages", getResourcePackages(primaryResources, dependencyResources)) |
| .addInput("--primaryManifest", primaryResources.getManifest()) |
| .maybeAddInput("--dependencyManifest", getManifests(dependencyResources)) |
| .maybeAddFlag( |
| "--resourceConfigs", resourceFilterFactory.getConfigurationFilterString()); |
| } |
| |
| builder |
| .addAapt(targetAaptVersion) |
| .addAndroidJar() |
| .maybeAddFlag("--debug", dataContext.useDebug()) |
| .addInput("--resources", resourceFilesZip) |
| .addInput("--shrunkJar", shrunkJar) |
| .addInput("--proguardMapping", proguardMapping) |
| .addInput("--rTxt", primaryResources.getRTxt()) |
| .addOutput("--shrunkResourceApk", resourceApkOut) |
| .addOutput("--shrunkResources", shrunkResourcesOut) |
| .addOutput("--log", logOut) |
| .buildAndRegister("Shrinking resources", "ResourceShrinker"); |
| |
| return resourceApkOut; |
| } |
| |
| private ImmutableList<Artifact> getManifests(ResourceDependencies resourceDependencies) { |
| ImmutableList.Builder<Artifact> manifests = ImmutableList.builder(); |
| for (ValidatedAndroidResources resources : resourceDependencies.getResourceContainers()) { |
| if (resources.getManifest() != null) { |
| manifests.add(resources.getManifest()); |
| } |
| } |
| return manifests.build(); |
| } |
| |
| private ImmutableList<String> getResourcePackages( |
| ValidatedAndroidResources primaryResources, ResourceDependencies resourceDependencies) { |
| ImmutableList.Builder<String> resourcePackages = ImmutableList.builder(); |
| resourcePackages.add(primaryResources.getJavaPackage()); |
| for (ValidatedAndroidResources resources : resourceDependencies.getResourceContainers()) { |
| resourcePackages.add(resources.getJavaPackage()); |
| } |
| return resourcePackages.build(); |
| } |
| } |