blob: 8e30d9abcf48de9322e41578415982466f0bacd5 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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.android.tools.appbundle.bundletool;
import static com.google.common.base.Preconditions.checkArgument;
import com.android.tools.appbundle.bundletool.utils.FlagParser;
import com.google.auto.value.AutoValue;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
/** Command responsible for building an App Bundle module. */
@AutoValue
public abstract class BuildModuleCommand {
public static final String COMMAND_NAME = "build-module";
private static final String OUTPUT_FLAG = "output";
private static final String MANIFEST_FLAG = "manifest";
private static final String MANIFEST_DIR_FLAG = "manifest-dir";
private static final String DEX_FLAG = "dex";
private static final String DEX_DIR_FLAG = "dex-dir";
private static final String RESOURCES_DIR_FLAG = "resources-dir";
private static final String ASSETS_DIR_FLAG = "assets-dir";
private static final String NATIVE_DIR_FLAG = "native-dir";
abstract Path getOutputPath();
abstract Optional<Path> getManifestPath();
abstract Optional<Path> getManifestDirPath();
abstract Optional<Path> getDexPath();
abstract Optional<Path> getDexDirPath();
abstract Optional<Path> getResourcesDirPath();
abstract Optional<Path> getAssetsDirPath();
abstract Optional<Path> getNativeDirPath();
public static Builder builder() {
return new AutoValue_BuildModuleCommand.Builder();
}
/** Builder for the {@link BuildModuleCommand} */
@AutoValue.Builder
public abstract static class Builder {
abstract Builder setOutputPath(Path outputPath);
abstract Builder setManifestPath(Path manifestPath);
abstract Builder setManifestDirPath(Path manifestDirPath);
abstract Builder setDexPath(Path dexPath);
abstract Builder setDexDirPath(Path dexDirPath);
abstract Builder setResourcesDirPath(Path resourcesDirPath);
abstract Builder setAssetsDirPath(Path assetsDirPath);
abstract Builder setNativeDirPath(Path nativeDirPath);
abstract BuildModuleCommand build();
}
static BuildModuleCommand fromFlags(FlagParser flagParser) {
Builder builder =
builder().setOutputPath(Paths.get(flagParser.getRequiredFlagValue(OUTPUT_FLAG)));
flagParser.getFlagValueAsPath(MANIFEST_FLAG).ifPresent(builder::setManifestPath);
flagParser.getFlagValueAsPath(MANIFEST_DIR_FLAG).ifPresent(builder::setManifestDirPath);
flagParser.getFlagValueAsPath(DEX_FLAG).ifPresent(builder::setDexPath);
flagParser.getFlagValueAsPath(DEX_DIR_FLAG).ifPresent(builder::setDexDirPath);
flagParser.getFlagValueAsPath(RESOURCES_DIR_FLAG).ifPresent(builder::setResourcesDirPath);
flagParser.getFlagValueAsPath(ASSETS_DIR_FLAG).ifPresent(builder::setAssetsDirPath);
flagParser.getFlagValueAsPath(NATIVE_DIR_FLAG).ifPresent(builder::setNativeDirPath);
return builder.build();
}
public void execute() {
validateInput();
}
private void validateInput() {
checkArgument(
getManifestPath().isPresent() || getManifestDirPath().isPresent(),
"One of --%s or --%s is required.",
MANIFEST_FLAG,
MANIFEST_DIR_FLAG);
checkArgument(
!getManifestPath().isPresent() || !getManifestDirPath().isPresent(),
"Cannot set both --%s and --%s flags.",
MANIFEST_FLAG,
MANIFEST_DIR_FLAG);
checkArgument(
!getDexPath().isPresent() || !getDexDirPath().isPresent(),
"Cannot set both --%s and --%s flags.",
DEX_FLAG,
DEX_DIR_FLAG);
checkArgument(!Files.exists(getOutputPath()), "File %s already exists.", getOutputPath());
checkFileExistsAndReadable(getManifestPath());
checkDirectoryExists(getManifestDirPath());
checkFileExistsAndReadable(getDexPath());
checkDirectoryExists(getDexDirPath());
checkDirectoryExists(getResourcesDirPath());
checkDirectoryExists(getAssetsDirPath());
checkDirectoryExists(getNativeDirPath());
}
private static void checkFileExistsAndReadable(Optional<Path> pathOptional) {
if (pathOptional.isPresent()) {
Path path = pathOptional.get();
checkArgument(Files.exists(path), "File '%s' was not found.", path);
checkArgument(Files.isReadable(path), "File '%s' is not readable.", path);
}
}
private static void checkDirectoryExists(Optional<Path> pathOptional) {
if (pathOptional.isPresent()) {
Path path = pathOptional.get();
checkArgument(Files.exists(path), "Directory '%s' was not found.", path);
checkArgument(Files.isDirectory(path), "'%s' is not a directory.");
}
}
public static void help() {
System.out.println(
String.format(
"bundletool %s --output=<path/to/module.zip> "
+ "[--%s=<path/to/AndroidManifest.flat>|--%s=<path/to/manifest-dir/>] "
+ "[--%s=<path/to/classes.dex>|--%s=<path/to/dex-dir/>] "
+ "[--%s=<path/to/res/>] "
+ "[--%s=<path/to/assets/>] "
+ "[--%s=<path/to/lib/>] ",
COMMAND_NAME,
MANIFEST_FLAG,
MANIFEST_DIR_FLAG,
DEX_FLAG,
DEX_DIR_FLAG,
RESOURCES_DIR_FLAG,
ASSETS_DIR_FLAG,
NATIVE_DIR_FLAG));
System.out.println();
System.out.println(
"Builds a module as a zip from an app's project. Note that the resources and the "
+ "AndroidManifest.xml must already have been compiled with aapt2.");
System.out.println();
System.out.println("--output: Path to the zip file to build.");
System.out.printf(
"--%s: Path to the AndroidManifest.flat compiled by aapt2. Use --%s if there "
+ "are more than one.\n",
MANIFEST_FLAG, MANIFEST_DIR_FLAG);
System.out.printf(
"--%s: Path to the directory containing multiple Android manifests compiled by aapt2. "
+ "A file named 'manifest-targeting.xml' must be present in the directory "
+ "describing the targeting of each manifest present.\n",
MANIFEST_DIR_FLAG);
System.out.printf(
"--%s: Path to the dex file. Use --%s if there are more than one.\n",
DEX_FLAG, DEX_DIR_FLAG);
System.out.printf(
"--%s: Path to the directory containing multiple dex files. Unless all dex files must "
+ "be included in the generated APKs (for MultiDex), a file named "
+ "'dex-targeting.xml' must be present in the directory describing the targeting "
+ "of the different dex files.\n",
DEX_DIR_FLAG);
System.out.printf(
"--%s: Path to the directory containing the resources file(s). A file named "
+ "'resources.flat' must be present in that directory corresponding to the output "
+ "of the aapt2 compilation of the resources.\n",
RESOURCES_DIR_FLAG);
System.out.printf("--%s: Path to the directory containing the assets.\n", ASSETS_DIR_FLAG);
System.out.printf(
"--%s: Path to the directory containing the native libraries.\n", NATIVE_DIR_FLAG);
}
}