Skip to content
Permalink
Browse files

Call `aapt` with multiple `-A` flags

Test Plan: CI
  • Loading branch information...
sdwilsh committed Nov 4, 2015
1 parent a6aecdd commit 03a5c117fcb9e62664f830827f5b63a4f04c7266
@@ -19,7 +19,6 @@
import com.facebook.buck.android.AaptPackageResources.BuildOutput;
import com.facebook.buck.android.AndroidBinary.PackageType;
import com.facebook.buck.dalvik.EstimateLinearAllocStep;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.jvm.java.AccumulateClassNamesStep;
import com.facebook.buck.jvm.java.HasJavaClassHashes;
import com.facebook.buck.jvm.java.JavacOptions;
@@ -45,31 +44,24 @@
import com.facebook.buck.step.fs.MkdirAndSymlinkFileStep;
import com.facebook.buck.step.fs.MkdirStep;
import com.facebook.buck.step.fs.TouchStep;
import com.facebook.buck.util.HumanReadableException;
import com.facebook.buck.zip.ZipScrubberStep;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Functions;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Ordering;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* Packages the resources using {@code aapt}.
@@ -206,55 +198,6 @@ private Path getPathToRDotTxtFile() {
getResolver().deprecatedGetPath(manifest),
getAndroidManifestXml()));

// Copy the transitive closure of files in assets to a single directory, if any.
// TODO(mbolin): Older versions of aapt did not support multiple -A flags, so we can probably
// eliminate this now.
Step collectAssets = new Step() {
@Override
public int execute(ExecutionContext context) throws IOException, InterruptedException {
// This must be done in a Command because the files and directories that are specified may
// not exist at the time this Command is created because the previous Commands have not run
// yet.
ImmutableList.Builder<Step> commands = ImmutableList.builder();
try {
createAllAssetsDirectory(
ImmutableSet.copyOf(getResolver().deprecatedAllPaths(assetsDirectories)),
commands,
getProjectFilesystem());
} catch (IOException e) {
context.logError(e, "Error creating all assets directory in %s.", getBuildTarget());
return 1;
}

for (Step command : commands.build()) {
int exitCode = command.execute(context);
if (exitCode != 0) {
throw new HumanReadableException("Error running " + command.getDescription(context));
}
}

return 0;
}

@Override
public String getShortName() {
return "symlink_assets";
}

@Override
public String getDescription(ExecutionContext context) {
return getShortName();
}
};
steps.add(collectAssets);

Optional<Path> assetsDirectory;
if (assetsDirectories.isEmpty()) {
assetsDirectory = Optional.absent();
} else {
assetsDirectory = Optional.of(getPathToAllAssetsDirectory());
}

steps.add(new MkdirStep(getProjectFilesystem(), getResourceApkPath().getParent()));

Path rDotTxtDir = getPathToRDotTxtDir();
@@ -273,7 +216,8 @@ public String getDescription(ExecutionContext context) {
getProjectFilesystem().getRootPath(),
getAndroidManifestXml(),
filteredResourcesProvider.getResDirectories(),
assetsDirectory,
FluentIterable.from(getResolver().getAllAbsolutePaths(assetsDirectories))
.toSortedSet(Ordering.<Path>natural()),
getResourceApkPath(),
rDotTxtDir,
pathToGeneratedProguardConfig,
@@ -421,69 +365,13 @@ Path getAndroidManifestXml() {
return BuildTargets.getScratchPath(getBuildTarget(), "__manifest_%s__/AndroidManifest.xml");
}

/**
* Given a set of assets directories to include in the APK (which may be empty), return the path
* to the directory that contains the union of all the assets. If any work needs to be done to
* create such a directory, the appropriate commands should be added to the {@code commands}
* list builder.
* <p>
* If there are no assets (i.e., {@code assetsDirectories} is empty), then the return value will
* be an empty {@link Optional}.
*/
@VisibleForTesting
Optional<Path> createAllAssetsDirectory(
Set<Path> assetsDirectories,
ImmutableList.Builder<Step> steps,
ProjectFilesystem filesystem) throws IOException {
if (assetsDirectories.isEmpty()) {
return Optional.absent();
}

// Due to a limitation of aapt, only one assets directory can be specified, so if multiple are
// specified in Buck, then all of the contents must be symlinked to a single directory.
Path destination = getPathToAllAssetsDirectory();
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), destination));
final ImmutableMap.Builder<Path, Path> allAssets = ImmutableMap.builder();

for (final Path assetsDirectory : assetsDirectories) {
if (!filesystem.exists(assetsDirectory)) {
continue;
}
filesystem.walkRelativeFileTree(
assetsDirectory, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (!AaptStep.isSilentlyIgnored(file)) {
allAssets.put(assetsDirectory.relativize(file), file);
}
return FileVisitResult.CONTINUE;
}
});
}

for (Map.Entry<Path, Path> entry : allAssets.build().entrySet()) {
steps.add(
new MkdirAndSymlinkFileStep(
getProjectFilesystem(),
entry.getValue(),
destination.resolve(entry.getKey())));
}

return Optional.of(destination);
}

/**
* @return Path to the unsigned APK generated by this {@link com.facebook.buck.rules.BuildRule}.
*/
public Path getResourceApkPath() {
return BuildTargets.getGenPath(getBuildTarget(), "%s.unsigned.ap_");
}

@VisibleForTesting
Path getPathToAllAssetsDirectory() {
return BuildTargets.getScratchPath(getBuildTarget(), "__assets_%s__");
}

public Sha1HashCode getResourcePackageHash() {
return buildOutputInitializer.getBuildOutput().resourcePackageHash;
}
@@ -23,6 +23,7 @@
import com.facebook.buck.util.MoreStrings;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;

import java.nio.file.Path;

@@ -64,7 +65,7 @@ public static boolean isSilentlyIgnored(Path path) {

private final Path androidManifest;
private final ImmutableList<Path> resDirectories;
private final Optional<Path> assetsDirectory;
private final ImmutableSortedSet<Path> assetsDirectories;
private final Path pathToOutputApkFile;
private final Path pathToRDotTxtDir;
private final Optional<Path> pathToGeneratedProguardConfig;
@@ -75,15 +76,15 @@ public AaptStep(
Path workingDirectory,
Path androidManifest,
ImmutableList<Path> resDirectories,
Optional<Path> assetsDirectory,
ImmutableSortedSet<Path> assetsDirectories,
Path pathToOutputApkFile,
Path pathToRDotTxtDir,
Optional<Path> pathToGeneratedProguardConfig,
boolean isCrunchPngFiles) {
super(workingDirectory);
this.androidManifest = androidManifest;
this.resDirectories = resDirectories;
this.assetsDirectory = assetsDirectory;
this.assetsDirectories = assetsDirectories;
this.pathToOutputApkFile = pathToOutputApkFile;
this.pathToRDotTxtDir = pathToRDotTxtDir;
this.pathToGeneratedProguardConfig = pathToGeneratedProguardConfig;
@@ -122,11 +123,8 @@ public AaptStep(
}

// Include the assets/ directory, if any.
// According to the aapt documentation, it appears that it should be possible to specify the -A
// flag multiple times; however, in practice, when it is specified multiple times, only one of
// the folders is included in the final APK.
if (assetsDirectory.isPresent()) {
builder.add("-A", assetsDirectory.get().toString());
for (Path assetDir : assetsDirectories) {
builder.add("-A", assetDir.toString());
}

builder.add("--output-text-symbols").add(pathToRDotTxtDir.toString());
Oops, something went wrong.

0 comments on commit 03a5c11

Please sign in to comment.
You can’t perform that action at this time.