Search in sources :

Example 1 with ClasspathTraversal

use of com.facebook.buck.jvm.java.classes.ClasspathTraversal in project buck by facebook.

the class EstimateDexWeightStep method execute.

@Override
public StepExecutionResult execute(ExecutionContext context) {
    Path path = filesystem.resolve(pathToJarOrClassesDirectory);
    ClasspathTraversal traversal = new ClasspathTraversal(Collections.singleton(path), filesystem) {

        private int totalWeightEstimate = 0;

        @Override
        public void visit(FileLike fileLike) throws IOException {
            // in .class, which should be ignored.
            if (!FileLikes.isClassFile(fileLike)) {
                return;
            }
            totalWeightEstimate += dexWeightEstimator.getEstimate(fileLike);
        }

        @Override
        public Integer getResult() {
            return totalWeightEstimate;
        }
    };
    try {
        new DefaultClasspathTraverser().traverse(traversal);
    } catch (IOException e) {
        context.logError(e, "Error accumulating class names for %s.", pathToJarOrClassesDirectory);
        return StepExecutionResult.ERROR;
    }
    this.weightEstimate = (Integer) traversal.getResult();
    return StepExecutionResult.SUCCESS;
}
Also used : Path(java.nio.file.Path) ClasspathTraversal(com.facebook.buck.jvm.java.classes.ClasspathTraversal) DefaultClasspathTraverser(com.facebook.buck.jvm.java.classes.DefaultClasspathTraverser) IOException(java.io.IOException) FileLike(com.facebook.buck.jvm.java.classes.FileLike)

Example 2 with ClasspathTraversal

use of com.facebook.buck.jvm.java.classes.ClasspathTraversal in project buck by facebook.

the class APKModuleGraph method getAPKModuleToClassesMap.

/**
   * Group the classes in the input jars into a multimap based on the APKModule they belong to
   *
   * @param apkModuleToJarPathMap the mapping of APKModules to the path for the jar files
   * @param translatorFunction function used to translate obfuscated names
   * @param filesystem filesystem representation for resolving paths
   * @return The mapping of APKModules to the class names they contain
   * @throws IOException
   */
public static ImmutableMultimap<APKModule, String> getAPKModuleToClassesMap(final ImmutableMultimap<APKModule, Path> apkModuleToJarPathMap, final Function<String, String> translatorFunction, final ProjectFilesystem filesystem) throws IOException {
    final ImmutableMultimap.Builder<APKModule, String> builder = ImmutableMultimap.builder();
    if (!apkModuleToJarPathMap.isEmpty()) {
        for (final APKModule dexStore : apkModuleToJarPathMap.keySet()) {
            for (Path jarFilePath : apkModuleToJarPathMap.get(dexStore)) {
                ClasspathTraverser classpathTraverser = new DefaultClasspathTraverser();
                classpathTraverser.traverse(new ClasspathTraversal(ImmutableSet.of(jarFilePath), filesystem) {

                    @Override
                    public void visit(FileLike entry) {
                        if (!entry.getRelativePath().endsWith(".class")) {
                            // ignore everything but class files in the jar.
                            return;
                        }
                        builder.put(dexStore, translatorFunction.apply(entry.getRelativePath()));
                    }
                });
            }
        }
    }
    return builder.build();
}
Also used : Path(java.nio.file.Path) ClasspathTraversal(com.facebook.buck.jvm.java.classes.ClasspathTraversal) DefaultClasspathTraverser(com.facebook.buck.jvm.java.classes.DefaultClasspathTraverser) ClasspathTraverser(com.facebook.buck.jvm.java.classes.ClasspathTraverser) DefaultClasspathTraverser(com.facebook.buck.jvm.java.classes.DefaultClasspathTraverser) ImmutableMultimap(com.google.common.collect.ImmutableMultimap) FileLike(com.facebook.buck.jvm.java.classes.FileLike)

Example 3 with ClasspathTraversal

use of com.facebook.buck.jvm.java.classes.ClasspathTraversal in project buck by facebook.

the class AccumulateClassNamesStep method calculateClassHashes.

/**
   * @return an Optional that will be absent if there was an error.
   */
public static Optional<ImmutableSortedMap<String, HashCode>> calculateClassHashes(ExecutionContext context, ProjectFilesystem filesystem, Path path) {
    final Map<String, HashCode> classNames = new HashMap<>();
    ClasspathTraversal traversal = new ClasspathTraversal(Collections.singleton(path), filesystem) {

        @Override
        public void visit(final FileLike fileLike) throws IOException {
            // end in .class, which should be ignored.
            if (!FileLikes.isClassFile(fileLike)) {
                return;
            }
            String key = FileLikes.getFileNameWithoutClassSuffix(fileLike);
            ByteSource input = new ByteSource() {

                @Override
                public InputStream openStream() throws IOException {
                    return fileLike.getInput();
                }
            };
            HashCode value = input.hash(Hashing.sha1());
            HashCode existing = classNames.putIfAbsent(key, value);
            if (existing != null && !existing.equals(value)) {
                throw new IllegalArgumentException(String.format("Multiple entries with same key but differing values: %1$s=%2$s and %1$s=%3$s", key, value, existing));
            }
        }
    };
    try {
        new DefaultClasspathTraverser().traverse(traversal);
    } catch (IOException e) {
        context.logError(e, "Error accumulating class names for %s.", path);
        return Optional.empty();
    }
    return Optional.of(ImmutableSortedMap.copyOf(classNames, Ordering.natural()));
}
Also used : ClasspathTraversal(com.facebook.buck.jvm.java.classes.ClasspathTraversal) HashCode(com.google.common.hash.HashCode) HashMap(java.util.HashMap) DefaultClasspathTraverser(com.facebook.buck.jvm.java.classes.DefaultClasspathTraverser) ByteSource(com.google.common.io.ByteSource) IOException(java.io.IOException) FileLike(com.facebook.buck.jvm.java.classes.FileLike)

Example 4 with ClasspathTraversal

use of com.facebook.buck.jvm.java.classes.ClasspathTraversal in project buck by facebook.

the class DalvikAwareZipSplitter method execute.

@Override
public ImmutableMultimap<APKModule, Path> execute() throws IOException {
    ClasspathTraverser classpathTraverser = new DefaultClasspathTraverser();
    final Set<String> secondaryTail = new HashSet<String>();
    // Start out by writing the primary zip and recording which entries were added to it.
    primaryOut = newZipOutput(outPrimary);
    secondaryDexWriter.reset();
    final ImmutableMap.Builder<String, FileLike> entriesBuilder = ImmutableMap.builder();
    final List<String> additionalDexStoreEntries = new ArrayList<>();
    // Iterate over all of the inFiles and add all entries that match the requiredInPrimaryZip
    // predicate.
    LOG.debug("Traversing classpath for primary zip");
    classpathTraverser.traverse(new ClasspathTraversal(inFiles, filesystem) {

        @Override
        public void visit(FileLike entry) throws IOException {
            LOG.debug("Visiting " + entry.getRelativePath());
            String relativePath = entry.getRelativePath();
            if (!relativePath.endsWith(".class")) {
                // We don't need resources in dex jars, so just drop them.
                return;
            }
            Preconditions.checkNotNull(primaryOut);
            Preconditions.checkNotNull(classPathToDexStore);
            if (requiredInPrimaryZip.apply(relativePath)) {
                primaryOut.putEntry(entry);
            } else if (wantedInPrimaryZip.contains(relativePath) || (secondaryHeadSet != null && secondaryHeadSet.contains(relativePath))) {
                entriesBuilder.put(relativePath, new BufferedFileLike(entry));
            } else if (secondaryTailSet != null && secondaryTailSet.contains(relativePath)) {
                entriesBuilder.put(relativePath, new BufferedFileLike(entry));
                secondaryTail.add(relativePath);
            } else {
                ImmutableCollection<APKModule> containingModule = classPathToDexStore.get(relativePath);
                if (!containingModule.isEmpty()) {
                    if (containingModule.size() > 1) {
                        throw new IllegalStateException(String.format("classpath %s is contained in multiple dex stores: %s", relativePath, classPathToDexStore.get(relativePath).asList().toString()));
                    }
                    APKModule dexStore = containingModule.iterator().next();
                    if (!dexStore.equals(apkModuleGraph.getRootAPKModule())) {
                        MySecondaryDexHelper dexHelper = additionalDexWriters.get(dexStore);
                        Preconditions.checkNotNull(dexHelper);
                        dexHelper.getOutputToWriteTo(entry).putEntry(entry);
                        additionalDexStoreEntries.add(relativePath);
                    }
                }
            }
        }
    });
    // Put as many of the items wanted in the primary dex as we can into the primary dex.
    ImmutableMap<String, FileLike> entries = entriesBuilder.build();
    for (String wanted : wantedInPrimaryZip) {
        FileLike entry = entries.get(wanted);
        if ((entry != null) && !primaryOut.containsEntry(entry) && primaryOut.canPutEntry(entry)) {
            primaryOut.putEntry(entry);
        }
    }
    if (secondaryHeadSet != null) {
        for (String head : secondaryHeadSet) {
            FileLike headEntry = entries.get(head);
            if ((headEntry != null) && !primaryOut.containsEntry(headEntry)) {
                secondaryDexWriter.getOutputToWriteTo(headEntry).putEntry(headEntry);
            }
        }
    }
    LOG.debug("Traversing classpath for secondary zip");
    // Now that all of the required entries have been added to the primary zip, fill the rest of
    // the zip up with the remaining entries.
    classpathTraverser.traverse(new ClasspathTraversal(inFiles, filesystem) {

        @Override
        public void visit(FileLike entry) throws IOException {
            Preconditions.checkNotNull(primaryOut);
            String relativePath = entry.getRelativePath();
            // skip if it is the primary dex, is part of a modular dex store, or is not a class file
            if (primaryOut.containsEntry(entry) || additionalDexStoreEntries.contains(relativePath)) {
                return;
            }
            LOG.debug("Visiting " + entry.getRelativePath());
            // room in the primary dex for the current entry in the traversal.
            if (dexSplitStrategy == DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE && primaryOut.canPutEntry(entry)) {
                primaryOut.putEntry(entry);
            } else {
                if (secondaryHeadSet != null && secondaryHeadSet.contains(relativePath)) {
                    return;
                }
                if (secondaryTail.contains(relativePath)) {
                    return;
                }
                secondaryDexWriter.getOutputToWriteTo(entry).putEntry(entry);
            }
        }
    });
    if (secondaryTailSet != null) {
        for (String tail : secondaryTailSet) {
            FileLike tailEntry = entries.get(tail);
            if ((tailEntry != null) && !primaryOut.containsEntry(tailEntry) && secondaryTail.contains(tail)) {
                secondaryDexWriter.getOutputToWriteTo(tailEntry).putEntry(tailEntry);
            }
        }
    }
    primaryOut.close();
    secondaryDexWriter.close();
    ImmutableMultimap.Builder<APKModule, Path> outputFilesBuilder = ImmutableMultimap.builder();
    APKModule secondaryDexStore = apkModuleGraph.getRootAPKModule();
    outputFilesBuilder.putAll(secondaryDexStore, secondaryDexWriter.getFiles());
    for (Map.Entry<APKModule, MySecondaryDexHelper> entry : additionalDexWriters.entrySet()) {
        if (!entry.getKey().equals(secondaryDexStore)) {
            entry.getValue().close();
            outputFilesBuilder.putAll(entry.getKey(), entry.getValue().getFiles());
        }
    }
    return outputFilesBuilder.build();
}
Also used : Path(java.nio.file.Path) ClasspathTraversal(com.facebook.buck.jvm.java.classes.ClasspathTraversal) ImmutableCollection(com.google.common.collect.ImmutableCollection) DefaultClasspathTraverser(com.facebook.buck.jvm.java.classes.DefaultClasspathTraverser) ClasspathTraverser(com.facebook.buck.jvm.java.classes.ClasspathTraverser) DefaultClasspathTraverser(com.facebook.buck.jvm.java.classes.DefaultClasspathTraverser) ArrayList(java.util.ArrayList) APKModule(com.facebook.buck.android.APKModule) IOException(java.io.IOException) AbstractFileLike(com.facebook.buck.jvm.java.classes.AbstractFileLike) FileLike(com.facebook.buck.jvm.java.classes.FileLike) ImmutableMap(com.google.common.collect.ImmutableMap) ImmutableMultimap(com.google.common.collect.ImmutableMultimap) HashMap(java.util.HashMap) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) HashSet(java.util.HashSet)

Example 5 with ClasspathTraversal

use of com.facebook.buck.jvm.java.classes.ClasspathTraversal in project buck by facebook.

the class HashInputJarsToDexStep method execute.

@Override
public StepExecutionResult execute(final ExecutionContext context) {
    ImmutableList.Builder<Path> allInputs = ImmutableList.builder();
    allInputs.addAll(primaryInputsToDex.get());
    if (secondaryOutputToInputs.isPresent()) {
        allInputs.addAll(secondaryOutputToInputs.get().get().values());
    }
    final Map<String, HashCode> classNamesToHashes = classNamesToHashesSupplier.get();
    for (Path path : allInputs.build()) {
        try {
            final Hasher hasher = Hashing.sha1().newHasher();
            new DefaultClasspathTraverser().traverse(new ClasspathTraversal(Collections.singleton(path), filesystem) {

                @Override
                public void visit(FileLike fileLike) throws IOException {
                    String className = fileLike.getRelativePath().replaceAll("\\.class$", "");
                    if (classNamesToHashes.containsKey(className)) {
                        HashCode classHash = Preconditions.checkNotNull(classNamesToHashes.get(className));
                        hasher.putBytes(classHash.asBytes());
                    }
                }
            });
            dexInputsToHashes.put(path, Sha1HashCode.fromHashCode(hasher.hash()));
        } catch (IOException e) {
            context.logError(e, "Error hashing smart dex input: %s", path);
            return StepExecutionResult.ERROR;
        }
    }
    stepFinished = true;
    return StepExecutionResult.SUCCESS;
}
Also used : Path(java.nio.file.Path) ClasspathTraversal(com.facebook.buck.jvm.java.classes.ClasspathTraversal) Hasher(com.google.common.hash.Hasher) HashCode(com.google.common.hash.HashCode) Sha1HashCode(com.facebook.buck.util.sha1.Sha1HashCode) ImmutableList(com.google.common.collect.ImmutableList) DefaultClasspathTraverser(com.facebook.buck.jvm.java.classes.DefaultClasspathTraverser) IOException(java.io.IOException) FileLike(com.facebook.buck.jvm.java.classes.FileLike)

Aggregations

ClasspathTraversal (com.facebook.buck.jvm.java.classes.ClasspathTraversal)5 DefaultClasspathTraverser (com.facebook.buck.jvm.java.classes.DefaultClasspathTraverser)5 FileLike (com.facebook.buck.jvm.java.classes.FileLike)5 IOException (java.io.IOException)4 Path (java.nio.file.Path)4 ClasspathTraverser (com.facebook.buck.jvm.java.classes.ClasspathTraverser)2 ImmutableMultimap (com.google.common.collect.ImmutableMultimap)2 HashCode (com.google.common.hash.HashCode)2 HashMap (java.util.HashMap)2 APKModule (com.facebook.buck.android.APKModule)1 AbstractFileLike (com.facebook.buck.jvm.java.classes.AbstractFileLike)1 Sha1HashCode (com.facebook.buck.util.sha1.Sha1HashCode)1 ImmutableCollection (com.google.common.collect.ImmutableCollection)1 ImmutableList (com.google.common.collect.ImmutableList)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 Hasher (com.google.common.hash.Hasher)1 ByteSource (com.google.common.io.ByteSource)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1