Search in sources :

Example 21 with ModuleEntry

use of com.android.tools.build.bundletool.model.ModuleEntry in project bundletool by google.

the class ZipFlingerAppBundleSerializer method addNewEntries.

/**
 * Adds new and modified entries to an archive, compressing them.
 */
private static void addNewEntries(ZipArchive archive, ImmutableListMultimap<BundleModule, ModuleEntry> entries) throws IOException {
    for (Map.Entry<BundleModule, ModuleEntry> moduleAndEntry : entries.entries()) {
        BundleModule module = moduleAndEntry.getKey();
        ModuleEntry moduleEntry = moduleAndEntry.getValue();
        checkState(!moduleEntry.getBundleLocation().isPresent());
        ZipPath moduleDir = ZipPath.create(module.getName().toString());
        ZipPath destPath = moduleDir.resolve(moduleEntry.getPath());
        archive.add(new BytesSource(moduleEntry.getContent().read(), destPath.toString(), DEFAULT_COMPRESSION_LEVEL));
    }
}
Also used : BytesSource(com.android.zipflinger.BytesSource) SpecialModuleEntry(com.android.tools.build.bundletool.model.BundleModule.SpecialModuleEntry) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) ZipPath(com.android.tools.build.bundletool.model.ZipPath) HashMap(java.util.HashMap) Map(java.util.Map) BundleModule(com.android.tools.build.bundletool.model.BundleModule)

Example 22 with ModuleEntry

use of com.android.tools.build.bundletool.model.ModuleEntry in project bundletool by google.

the class BundleModuleMerger method getAllEntriesExceptDexAndSpecial.

private static ImmutableSet<ModuleEntry> getAllEntriesExceptDexAndSpecial(Set<BundleModule> bundleModulesToFuse) {
    Map<ZipPath, ModuleEntry> mergedEntriesByPath = new HashMap<>();
    bundleModulesToFuse.stream().flatMap(module -> module.getEntries().stream()).filter(moduleEntry -> !moduleEntry.getPath().startsWith(DEX_DIRECTORY) && !moduleEntry.isSpecialEntry()).forEach(moduleEntry -> {
        ModuleEntry existingModuleEntry = mergedEntriesByPath.putIfAbsent(moduleEntry.getPath(), moduleEntry);
        if (existingModuleEntry != null && !existingModuleEntry.equals(moduleEntry)) {
            throw InvalidBundleException.builder().withUserMessage("Existing module entry '%s' with different contents.", moduleEntry.getPath()).build();
        }
    });
    return ImmutableSet.copyOf(mergedEntriesByPath.values());
}
Also used : ImmutableListMultimap.flatteningToImmutableListMultimap(com.google.common.collect.ImmutableListMultimap.flatteningToImmutableListMultimap) FUSE_APPLICATION_ELEMENTS_FROM_FEATURE_MANIFESTS(com.android.tools.build.bundletool.model.version.VersionGuardedFeature.FUSE_APPLICATION_ELEMENTS_FROM_FEATURE_MANIFESTS) BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) ZipPath(com.android.tools.build.bundletool.model.ZipPath) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) HashMap(java.util.HashMap) AndroidManifestMerger.fusingMergerOnlyReplaceActivities(com.android.tools.build.bundletool.mergers.AndroidManifestMerger.fusingMergerOnlyReplaceActivities) AndroidManifestMerger.fusingMergerApplicationElements(com.android.tools.build.bundletool.mergers.AndroidManifestMerger.fusingMergerApplicationElements) HashMultimap(com.google.common.collect.HashMultimap) Multimaps.toMultimap(com.google.common.collect.Multimaps.toMultimap) ImmutableList(com.google.common.collect.ImmutableList) Map(java.util.Map) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) ModuleType(com.android.tools.build.bundletool.model.BundleModule.ModuleType) Version(com.android.tools.build.bundletool.model.version.Version) ResourceTable(com.android.aapt.Resources.ResourceTable) DEX_DIRECTORY(com.android.tools.build.bundletool.model.BundleModule.DEX_DIRECTORY) BundleToolVersion(com.android.tools.build.bundletool.model.version.BundleToolVersion) ImmutableSet(com.google.common.collect.ImmutableSet) InvalidBundleException(com.android.tools.build.bundletool.model.exceptions.InvalidBundleException) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Set(java.util.Set) IOException(java.io.IOException) NativeLibraries(com.android.bundle.Files.NativeLibraries) ApexImages(com.android.bundle.Files.ApexImages) MERGE_INSTALL_TIME_MODULES_INTO_BASE(com.android.tools.build.bundletool.model.version.VersionGuardedFeature.MERGE_INSTALL_TIME_MODULES_INTO_BASE) Stream(java.util.stream.Stream) BundleConfig(com.android.bundle.Config.BundleConfig) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) Optional(java.util.Optional) Assets(com.android.bundle.Files.Assets) AppBundle(com.android.tools.build.bundletool.model.AppBundle) BundleModule(com.android.tools.build.bundletool.model.BundleModule) HashMap(java.util.HashMap) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) ZipPath(com.android.tools.build.bundletool.model.ZipPath)

Example 23 with ModuleEntry

use of com.android.tools.build.bundletool.model.ModuleEntry in project bundletool by google.

the class AbiApexImagesSplitter method split.

/**
 * Generates {@link ModuleSplit} objects dividing the APEX images by ABI.
 */
@Override
public ImmutableCollection<ModuleSplit> split(ModuleSplit moduleSplit) {
    if (!moduleSplit.isApex()) {
        return ImmutableList.of(moduleSplit);
    }
    List<TargetedApexImage> allTargetedImages = moduleSplit.getApexConfig().get().getImageList();
    // A set of all MultiAbis (flattened for repeated values) for easy generation of alternatives.
    ImmutableSet<MultiAbi> allTargeting = allTargetedImages.stream().flatMap(image -> image.getTargeting().getMultiAbi().getValueList().stream()).collect(toImmutableSet());
    // This prevents O(n^2).
    ImmutableMap<String, ModuleEntry> apexPathToEntryMap = buildApexPathToEntryMap(allTargetedImages, moduleSplit);
    ImmutableList.Builder<ModuleSplit> splits = new ImmutableList.Builder<>();
    for (TargetedApexImage targetedApexImage : allTargetedImages) {
        ModuleEntry entry = apexPathToEntryMap.get(targetedApexImage.getPath());
        List<MultiAbi> targeting = targetedApexImage.getTargeting().getMultiAbi().getValueList();
        ModuleSplit.Builder splitBuilder = moduleSplit.toBuilder().setApkTargeting(moduleSplit.getApkTargeting().toBuilder().setMultiAbiTargeting(MultiAbiTargeting.newBuilder().addAllValue(targeting).addAllAlternatives(Sets.difference(allTargeting, ImmutableSet.copyOf(targeting)))).build()).setMasterSplit(false).setEntries(targetedApexImage.getBuildInfoPath().isEmpty() ? ImmutableList.of(entry) : ImmutableList.of(entry, apexPathToEntryMap.get(targetedApexImage.getBuildInfoPath())));
        splits.add(splitBuilder.build());
    }
    return splits.build();
}
Also used : ImmutableSet(com.google.common.collect.ImmutableSet) MultiAbiTargeting(com.android.bundle.Targeting.MultiAbiTargeting) ImmutableMap(com.google.common.collect.ImmutableMap) ImmutableCollection(com.google.common.collect.ImmutableCollection) Maps(com.google.common.collect.Maps) Sets(com.google.common.collect.Sets) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) List(java.util.List) TargetedApexImage(com.android.bundle.Files.TargetedApexImage) Stream(java.util.stream.Stream) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) ImmutableList(com.google.common.collect.ImmutableList) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) Function.identity(java.util.function.Function.identity) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) MultiAbi(com.android.bundle.Targeting.MultiAbi) ImmutableList(com.google.common.collect.ImmutableList) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) TargetedApexImage(com.android.bundle.Files.TargetedApexImage) MultiAbi(com.android.bundle.Targeting.MultiAbi)

Example 24 with ModuleEntry

use of com.android.tools.build.bundletool.model.ModuleEntry in project bundletool by google.

the class AssetsDimensionSplitterFactory method createSplitter.

/**
 * Creates a {@link ModuleSplitSplitter} capable of splitting on a given Asset targeting
 * dimension, with, optionally, a dimension to be removed from asset paths.
 *
 * @param <T> the proto buffer message class representing the splitting targeting dimension.
 * @param dimensionGetter function that extracts the sub-message representing a targeting
 *     dimension.
 * @param targetingSetter function that creates a split targeting that will be merged with the
 *     targeting of the input {@link ModuleSplit}.
 * @param hasTargeting predicate to test if the input {@link ModuleSplit} is already targeting on
 *     the dimension of this splitter.
 * @param targetingDimensionToRemove If not empty, the targeting for this dimension will be
 * removed from asset paths (i.e: suffixes like #tcf_xxx will be removed from paths).
 * @return {@link ModuleSplitSplitter} for a given dimension functions.
 */
public static <T extends Message> ModuleSplitSplitter createSplitter(Function<AssetsDirectoryTargeting, T> dimensionGetter, Function<T, ApkTargeting> targetingSetter, Predicate<ApkTargeting> hasTargeting, Optional<TargetingDimension> targetingDimensionToRemove) {
    return new ModuleSplitSplitter() {

        @Override
        public ImmutableCollection<ModuleSplit> split(ModuleSplit split) {
            checkArgument(!hasTargeting.test(split.getApkTargeting()), "Split is already targeting the splitting dimension.");
            return split.getAssetsConfig().map(assetsConfig -> splitAssetsDirectories(assetsConfig, split)).orElse(ImmutableList.of(split)).stream().map(moduleSplit -> moduleSplit.isMasterSplit() ? moduleSplit : removeAssetsTargeting(moduleSplit)).collect(toImmutableList());
        }

        private ModuleSplit removeAssetsTargeting(ModuleSplit split) {
            return targetingDimensionToRemove.isPresent() ? SuffixStripper.createForDimension(targetingDimensionToRemove.get()).removeAssetsTargeting(split) : split;
        }

        private ImmutableList<ModuleSplit> splitAssetsDirectories(Assets assets, ModuleSplit split) {
            Multimap<T, TargetedAssetsDirectory> directoriesMap = Multimaps.filterKeys(Multimaps.index(assets.getDirectoryList(), targetedDirectory -> dimensionGetter.apply(targetedDirectory.getTargeting())), not(this::isDefaultTargeting));
            ImmutableList.Builder<ModuleSplit> splitsBuilder = new ImmutableList.Builder<>();
            // Generate config splits.
            directoriesMap.asMap().entrySet().forEach(entry -> {
                ImmutableList<ModuleEntry> entries = listEntriesFromDirectories(entry.getValue(), split);
                if (entries.isEmpty()) {
                    return;
                }
                ModuleSplit.Builder modifiedSplit = split.toBuilder();
                modifiedSplit.setEntries(entries).setApkTargeting(generateTargeting(split.getApkTargeting(), entry.getKey())).setMasterSplit(false).addMasterManifestMutator(withSplitsRequired(true));
                splitsBuilder.add(modifiedSplit.build());
            });
            // Ensure that master split (even an empty one) always exists.
            ModuleSplit defaultSplit = getDefaultAssetsSplit(split, splitsBuilder.build());
            if (defaultSplit.isMasterSplit() || !defaultSplit.getEntries().isEmpty()) {
                splitsBuilder.add(defaultSplit);
            }
            return splitsBuilder.build();
        }

        private ModuleSplit getDefaultAssetsSplit(ModuleSplit inputSplit, ImmutableList<ModuleSplit> configSplits) {
            ImmutableSet<ModuleEntry> claimedEntries = configSplits.stream().map(ModuleSplit::getEntries).flatMap(Collection::stream).collect(toImmutableSet());
            return inputSplit.toBuilder().setEntries(inputSplit.getEntries().stream().filter(not(claimedEntries::contains)).collect(toImmutableList())).build();
        }

        private boolean isDefaultTargeting(T splittingDimensionTargeting) {
            return splittingDimensionTargeting.equals(splittingDimensionTargeting.getDefaultInstanceForType());
        }

        private ApkTargeting generateTargeting(ApkTargeting splitTargeting, T extraTargeting) {
            if (isDefaultTargeting(extraTargeting)) {
                return splitTargeting;
            }
            return splitTargeting.toBuilder().mergeFrom(targetingSetter.apply(extraTargeting)).build();
        }

        private ImmutableList<ModuleEntry> listEntriesFromDirectories(Collection<TargetedAssetsDirectory> directories, ModuleSplit moduleSplit) {
            return directories.stream().map(targetedAssetsDirectory -> ZipPath.create(targetedAssetsDirectory.getPath())).flatMap(moduleSplit::getEntriesInDirectory).collect(toImmutableList());
        }
    };
}
Also used : ApkTargeting(com.android.bundle.Targeting.ApkTargeting) ZipPath(com.android.tools.build.bundletool.model.ZipPath) ImmutableCollection(com.google.common.collect.ImmutableCollection) Multimap(com.google.common.collect.Multimap) TargetingDimension(com.android.tools.build.bundletool.model.targeting.TargetingDimension) Multimaps(com.google.common.collect.Multimaps) ManifestMutator.withSplitsRequired(com.android.tools.build.bundletool.model.ManifestMutator.withSplitsRequired) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) SameTargetingMerger(com.android.tools.build.bundletool.mergers.SameTargetingMerger) Predicates.not(com.google.common.base.Predicates.not) ImmutableList(com.google.common.collect.ImmutableList) AssetsDirectoryTargeting(com.android.bundle.Targeting.AssetsDirectoryTargeting) Function(com.google.common.base.Function) ImmutableSet(com.google.common.collect.ImmutableSet) Predicate(java.util.function.Predicate) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Collection(java.util.Collection) ImmutableCollectors.toImmutableSet(com.android.utils.ImmutableCollectors.toImmutableSet) SuffixStripper(com.android.tools.build.bundletool.shards.SuffixStripper) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) Message(com.google.protobuf.Message) Optional(java.util.Optional) TargetedAssetsDirectory(com.android.bundle.Files.TargetedAssetsDirectory) Assets(com.android.bundle.Files.Assets) TargetedAssetsDirectory(com.android.bundle.Files.TargetedAssetsDirectory) ApkTargeting(com.android.bundle.Targeting.ApkTargeting) ImmutableList(com.google.common.collect.ImmutableList) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) Assets(com.android.bundle.Files.Assets) ImmutableCollection(com.google.common.collect.ImmutableCollection) Collection(java.util.Collection)

Example 25 with ModuleEntry

use of com.android.tools.build.bundletool.model.ModuleEntry in project bundletool by google.

the class EntryClashValidator method checkEqualEntries.

private static void checkEqualEntries(ZipPath path, BundleModule module1, BundleModule module2) {
    ModuleEntry entry1 = module1.getEntry(path).get();
    ModuleEntry entry2 = module2.getEntry(path).get();
    if (!entry1.equals(entry2)) {
        throw InvalidBundleException.builder().withUserMessage("Modules '%s' and '%s' contain entry '%s' with different content.", module1.getName(), module2.getName(), path).build();
    }
}
Also used : ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry)

Aggregations

ModuleEntry (com.android.tools.build.bundletool.model.ModuleEntry)41 ModuleSplit (com.android.tools.build.bundletool.model.ModuleSplit)22 ZipPath (com.android.tools.build.bundletool.model.ZipPath)18 ImmutableList (com.google.common.collect.ImmutableList)18 Test (org.junit.Test)13 BundleModule (com.android.tools.build.bundletool.model.BundleModule)12 ImmutableSet (com.google.common.collect.ImmutableSet)12 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)10 SpecialModuleEntry (com.android.tools.build.bundletool.model.BundleModule.SpecialModuleEntry)8 BundleModuleBuilder (com.android.tools.build.bundletool.testing.BundleModuleBuilder)6 HashMap (java.util.HashMap)6 Optional (java.util.Optional)6 TargetedAssetsDirectory (com.android.bundle.Files.TargetedAssetsDirectory)5 ImmutableSet.toImmutableSet (com.google.common.collect.ImmutableSet.toImmutableSet)5 IOException (java.io.IOException)5 Map (java.util.Map)5 ResourceTable (com.android.aapt.Resources.ResourceTable)4 ApkTargeting (com.android.bundle.Targeting.ApkTargeting)4 BundleModuleName (com.android.tools.build.bundletool.model.BundleModuleName)4 ApkOptimizations (com.android.tools.build.bundletool.optimizations.ApkOptimizations)4