Skip to content

Commit

Permalink
Prepare for release 0.6.2.
Browse files Browse the repository at this point in the history
  • Loading branch information
tdobek committed Oct 31, 2018
1 parent 2144300 commit 324b913
Show file tree
Hide file tree
Showing 54 changed files with 1,922 additions and 156 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ Read more about the App Bundle format and Bundletool's usage at

## Releases

Latest release: [0.6.1](https://github.com/google/bundletool/releases)
Latest release: [0.6.2](https://github.com/google/bundletool/releases)
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
release_version = 0.6.1
release_version = 0.6.2
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ ListeningExecutorService getExecutorService() {

abstract boolean isExecutorServiceCreatedByBundleTool();

public abstract boolean getCreateApkSetArchive();


public abstract Optional<ApkListener> getApkListener();

Expand All @@ -132,6 +134,7 @@ public static Builder builder() {
.setOverwriteOutput(false)
.setGenerateOnlyUniversalApk(false)
.setGenerateOnlyForConnectedDevice(false)
.setCreateApkSetArchive(true)
.setOptimizationDimensions(ImmutableSet.of());
}

Expand Down Expand Up @@ -218,6 +221,14 @@ public Builder setExecutorService(ListeningExecutorService executorService) {
*/
abstract Builder setExecutorServiceCreatedByBundleTool(boolean value);

/**
* If false will extract the APK set to the output directory without creating the final archive.
* Important: if this mode is used, the caller should still provide a "apks file" as the output
* file parameter. This is because there is a lots of validation here that assumes that. The
* command will return the directory where the APK files were copied to.
*/
public abstract Builder setCreateApkSetArchive(boolean value);


/**
* Provides an {@link ApkListener} that will be notified at defined stages of APK creation.
Expand Down Expand Up @@ -278,12 +289,15 @@ public BuildApksCommand build() {
"Setting --device-id requires using the --connected-device flag.");
}

if (!APK_SET_ARCHIVE_EXTENSION.equals(MoreFiles.getFileExtension(command.getOutputFile()))) {
throw ValidationException.builder()
.withMessage(
"Flag --output should be the path where to generate the APK Set. "
+ "Its extension must be '.apks'.")
.build();
if (command.getCreateApkSetArchive()) {
if (!APK_SET_ARCHIVE_EXTENSION.equals(
MoreFiles.getFileExtension(command.getOutputFile()))) {
throw ValidationException.builder()
.withMessage(
"Flag --output should be the path where to generate the APK Set. "
+ "Its extension must be '.apks'.")
.build();
}
}

return command;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.android.tools.build.bundletool.commands;

import static com.android.tools.build.bundletool.utils.TargetingProtoUtils.sdkVersionFrom;
import static com.android.tools.build.bundletool.utils.files.FilePreconditions.checkDirectoryExists;
import static com.android.tools.build.bundletool.utils.files.FilePreconditions.checkFileDoesNotExist;
import static com.android.tools.build.bundletool.utils.files.FilePreconditions.checkFileExistsAndExecutable;
import static com.android.tools.build.bundletool.utils.files.FilePreconditions.checkFileExistsAndReadable;
Expand Down Expand Up @@ -234,7 +235,6 @@ public Path execute(Path tempDir) {
}
}


return command.getOutputFile();
}

Expand All @@ -257,6 +257,10 @@ private ApkSetBuilder createApkSetBuilder(
new StandaloneApkSerializer(
apkPathmanager, aapt2Command, signingConfiguration, compression);

if (!command.getCreateApkSetArchive()) {
return ApkSetBuilderFactory.createApkSetWithoutArchiveBuilder(
splitApkSerializer, standaloneApkSerializer, command.getOutputFile());
}
return ApkSetBuilderFactory.createApkSetBuilder(
splitApkSerializer, standaloneApkSerializer, tempDir);
}
Expand All @@ -274,8 +278,12 @@ private static Aapt2Command extractAapt2FromJar(Path tempDir) {

private void validateInput() {
checkFileExistsAndReadable(command.getBundlePath());
if (!command.getOverwriteOutput()) {
checkFileDoesNotExist(command.getOutputFile());
if (command.getCreateApkSetArchive()) {
if (!command.getOverwriteOutput()) {
checkFileDoesNotExist(command.getOutputFile());
}
} else {
checkDirectoryExists(command.getOutputFile());
}

if (command.getGenerateOnlyForConnectedDevice()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.android.tools.build.bundletool.exceptions.CommandExecutionException;
import com.android.tools.build.bundletool.exceptions.ValidationException;
import com.android.tools.build.bundletool.io.ZipBuilder;
import com.android.tools.build.bundletool.io.ZipBuilder.EntryOption;
import com.android.tools.build.bundletool.model.BundleMetadata;
import com.android.tools.build.bundletool.model.BundleModule;
import com.android.tools.build.bundletool.model.InputStreamSupplier;
Expand All @@ -45,14 +46,14 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Closer;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import java.io.IOException;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.zip.ZipException;
Expand All @@ -69,6 +70,7 @@ public abstract class BuildBundleCommand {
private static final Flag<ImmutableList<Path>> MODULES_FLAG = Flag.pathList("modules");
private static final Flag<ImmutableMap<ZipPath, Path>> METADATA_FILES_FLAG =
Flag.mapCollector("metadata-file", ZipPath.class, Path.class);
private static final Flag<Boolean> UNCOMPRESSED_FLAG = Flag.booleanFlag("uncompressed");

public abstract Path getOutputPath();

Expand All @@ -80,8 +82,11 @@ public abstract class BuildBundleCommand {
/** Returns the bundle metadata. */
public abstract BundleMetadata getBundleMetadata();

abstract boolean getUncompressedBundle();

public static Builder builder() {
return new AutoValue_BuildBundleCommand.Builder();
// By default, everything is compressed.
return new AutoValue_BuildBundleCommand.Builder().setUncompressedBundle(false);
}

/** Builder for the {@link BuildBundleCommand}. */
Expand Down Expand Up @@ -136,6 +141,13 @@ public Builder setMainDexListFile(Path file) {
BundleMetadata.BUNDLETOOL_NAMESPACE, BundleMetadata.MAIN_DEX_LIST_FILE_NAME, file);
}

/**
* Sets whether the generated App Bundle should have its entries all uncompressed.
*
* <p>Defaults to {@code false}.
*/
public abstract Builder setUncompressedBundle(boolean uncompressed);

public abstract BuildBundleCommand build();
}

Expand All @@ -152,6 +164,7 @@ public static BuildBundleCommand fromFlags(ParsedFlags flags) {
METADATA_FILES_FLAG
.getValue(flags)
.ifPresent(metadataFiles -> metadataFiles.forEach(builder::addMetadataFileInternal));
UNCOMPRESSED_FLAG.getValue(flags).ifPresent(builder::setUncompressedBundle);

flags.checkNoUnknownFlags();

Expand All @@ -163,29 +176,29 @@ public void execute() {

ZipBuilder bundleBuilder = new ZipBuilder();

List<ZipFile> openedZipFiles = new ArrayList<>();
try {
try (Closer closer = Closer.create()) {
EntryOption[] compression =
getUncompressedBundle() ? new EntryOption[] {EntryOption.UNCOMPRESSED} : new EntryOption[0];

// Merge in all the modules, each module into its own sub-directory.
for (Path module : getModulesPaths()) {
try {
ZipFile moduleZipFile = new ZipFile(module.toFile());
openedZipFiles.add(moduleZipFile);

ZipFile moduleZipFile = closer.register(new ZipFile(module.toFile()));
ZipPath moduleDir = ZipPath.create(getNameWithoutExtension(module));

bundleBuilder.copyAllContentsFromZip(moduleDir, moduleZipFile);
bundleBuilder.copyAllContentsFromZip(moduleDir, moduleZipFile, compression);

Optional<Assets> assetsTargeting = generateAssetsTargeting(moduleZipFile);
if (assetsTargeting.isPresent()) {
bundleBuilder.addFileWithProtoContent(
moduleDir.resolve("assets.pb"), assetsTargeting.get());
moduleDir.resolve("assets.pb"), assetsTargeting.get(), compression);
}

Optional<NativeLibraries> nativeLibrariesTargeting =
generateNativeLibrariesTargeting(moduleZipFile);
if (nativeLibrariesTargeting.isPresent()) {
bundleBuilder.addFileWithProtoContent(
moduleDir.resolve("native.pb"), nativeLibrariesTargeting.get());
moduleDir.resolve("native.pb"), nativeLibrariesTargeting.get(), compression);
}
} catch (ZipException e) {
throw CommandExecutionException.builder()
Expand Down Expand Up @@ -216,13 +229,15 @@ public void execute() {
.setVersion(BundleToolVersion.getCurrentVersion().toString()))
.build();
bundleBuilder.addFileWithContent(
ZipPath.create(BUNDLE_CONFIG_FILE_NAME), bundleConfig.toByteArray());
ZipPath.create(BUNDLE_CONFIG_FILE_NAME), bundleConfig.toByteArray(), compression);

// Add metadata files.
for (Map.Entry<ZipPath, InputStreamSupplier> metadataEntry :
getBundleMetadata().getFileDataMap().entrySet()) {
bundleBuilder.addFile(
METADATA_DIRECTORY.resolve(metadataEntry.getKey()), metadataEntry.getValue());
METADATA_DIRECTORY.resolve(metadataEntry.getKey()),
metadataEntry.getValue(),
compression);
}

try {
Expand All @@ -233,8 +248,8 @@ public void execute() {
.withMessage("Unable to write file to location '%s'.")
.build();
}
} finally {
ZipUtils.closeZipFiles(openedZipFiles);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import com.android.tools.build.bundletool.utils.flags.Flag;
import com.android.tools.build.bundletool.utils.flags.ParsedFlags;
import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import java.nio.file.Path;
import java.util.Optional;
Expand All @@ -36,22 +38,43 @@ public abstract class GetSizeCommand {

public static final String COMMAND_NAME = "get-size";

/** Dimensions to expand the sizes in the output against. */
public enum Dimension {
SDK,
ABI,
LANGUAGE,
SCREEN_DENSITY,
ALL
}

private static final Flag<Path> APKS_ARCHIVE_FILE_FLAG = Flag.path("apks");
private static final Flag<Path> DEVICE_SPEC_FLAG = Flag.path("device-spec");
private static final Flag<ImmutableSet<String>> MODULES_FLAG = Flag.stringSet("modules");
private static final Flag<Boolean> INSTANT_FLAG = Flag.booleanFlag("instant");
private static final Flag<ImmutableSet<Dimension>> DIMENSIONS_FLAG =
Flag.enumSet("dimensions", Dimension.class);
private static final Joiner COMMA_JOINER = Joiner.on(',');

@VisibleForTesting
static final ImmutableSet<Dimension> SUPPORTED_DIMENSIONS =
ImmutableSet.of(Dimension.SDK, Dimension.ABI, Dimension.LANGUAGE, Dimension.SCREEN_DENSITY);

public abstract Path getApksArchivePath();

public abstract DeviceSpec getDeviceSpec();

public abstract Optional<ImmutableSet<String>> getModules();

public abstract ImmutableSet<Dimension> getDimensions();

/** Gets whether instant APKs should be used for size calculation. */
public abstract boolean getInstant();

public static Builder builder() {
return new AutoValue_GetSizeCommand.Builder().setInstant(false);
return new AutoValue_GetSizeCommand.Builder()
.setDeviceSpec(DeviceSpec.getDefaultInstance())
.setInstant(false)
.setDimensions(ImmutableSet.of());
}

/** Builder for the {@link GetSizeCommand}. */
Expand All @@ -63,6 +86,8 @@ public abstract static class Builder {

public abstract Builder setModules(ImmutableSet<String> modules);

public abstract Builder setDimensions(ImmutableSet<Dimension> dimensions);

/**
* Sets whether only instant APKs should be used in size calculation.
*
Expand All @@ -79,6 +104,8 @@ public static GetSizeCommand fromFlags(ParsedFlags flags) {
Optional<Path> deviceSpecPath = DEVICE_SPEC_FLAG.getValue(flags);
Optional<ImmutableSet<String>> modules = MODULES_FLAG.getValue(flags);
Optional<Boolean> instant = INSTANT_FLAG.getValue(flags);

ImmutableSet<Dimension> dimensions = DIMENSIONS_FLAG.getValue(flags).orElse(ImmutableSet.of());
flags.checkNoUnknownFlags();

checkFileExistsAndReadable(apksArchivePath);
Expand All @@ -95,6 +122,12 @@ public static GetSizeCommand fromFlags(ParsedFlags flags) {

instant.ifPresent(command::setInstant);

if (dimensions.contains(Dimension.ALL)) {
dimensions = SUPPORTED_DIMENSIONS;
}

command.setDimensions(dimensions);

return command.build();
}

Expand Down Expand Up @@ -126,6 +159,17 @@ public static CommandHelp help() {
+ "file as opposed to the spec generated by '%s'.",
GetDeviceSpecCommand.COMMAND_NAME)
.build())
.addFlag(
FlagDescription.builder()
.setFlagName(DIMENSIONS_FLAG.getName())
.setExampleValue(COMMA_JOINER.join(Dimension.values()))
.setOptional(true)
.setDescription(
"Specifies which dimensions to expand the sizes in the output "
+ "against. Note that ALL is a shortcut to all other dimensions and "
+ "including ALL here would cause the output to be expanded over "
+ "all possible dimensions.")
.build())
.addFlag(
FlagDescription.builder()
.setFlagName(MODULES_FLAG.getName())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* 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.build.bundletool.exceptions.manifest;

import static com.google.common.collect.ImmutableSet.toImmutableSet;

import com.android.bundle.Errors.BundleToolError;
import com.android.bundle.Errors.ManifestDuplicateAttributeError;
import com.android.tools.build.bundletool.utils.xmlproto.XmlProtoAttribute;
import com.google.common.collect.ImmutableSet;

/**
* Exception thrown when a manifest attribute is filled multiple times while it is expected only
* once.
*/
public class ManifestDuplicateAttributeException extends ManifestValidationException {

private final String attributeName;
private final String moduleName;

public ManifestDuplicateAttributeException(
String attributeName, ImmutableSet<XmlProtoAttribute> attributes, String moduleName) {
super(
"The attribute '%s' cannot be declared more than once (module '%s', values %s).",
attributeName,
moduleName,
attributes.stream()
.map(attr -> "'" + attr.getValueAsString() + "'")
.collect(toImmutableSet()));
this.attributeName = attributeName;
this.moduleName = moduleName;
}

@Override
protected void customizeProto(BundleToolError.Builder builder) {
builder.setManifestDuplicateAttribute(
ManifestDuplicateAttributeError.newBuilder()
.setAttributeName(attributeName)
.setModuleName(moduleName));
}
}
Loading

0 comments on commit 324b913

Please sign in to comment.