/* * Copyright 2014-present Facebook, Inc. * * 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.facebook.buck.zip; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.jvm.java.Javac; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.rules.SourcePath; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.step.Step; import com.facebook.buck.step.fs.CopyStep; import com.facebook.buck.step.fs.MkdirStep; import com.facebook.buck.util.HumanReadableException; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; public class SrcZipAwareFileBundler { private final Path basePath; public SrcZipAwareFileBundler(BuildTarget target) { this(target.getBasePath()); } public SrcZipAwareFileBundler(Path basePath) { this.basePath = Preconditions.checkNotNull(basePath); } private void findAndAddRelativePathToMap( Path absoluteFilePath, Path relativeFilePath, Path assumedAbsoluteBasePath, Map<Path, Path> relativePathMap) { Path pathRelativeToBaseDir; if (relativeFilePath.startsWith(basePath)) { pathRelativeToBaseDir = basePath.relativize(relativeFilePath); } else { pathRelativeToBaseDir = assumedAbsoluteBasePath.relativize(absoluteFilePath); } if (relativePathMap.containsKey(pathRelativeToBaseDir)) { throw new HumanReadableException( "The file '%s' appears twice in the hierarchy", pathRelativeToBaseDir.getFileName()); } relativePathMap.put(pathRelativeToBaseDir, absoluteFilePath); } private ImmutableMap<Path, Path> createRelativeMap( ProjectFilesystem filesystem, final SourcePathResolver resolver, ImmutableSortedSet<SourcePath> toCopy) { Map<Path, Path> relativePathMap = new HashMap<>(); for (SourcePath sourcePath : toCopy) { Path absoluteBasePath = resolver.getAbsolutePath(sourcePath); try { if (Files.isDirectory(absoluteBasePath)) { ImmutableSet<Path> files = filesystem.getFilesUnderPath(absoluteBasePath); Path absoluteBasePathParent = absoluteBasePath.getParent(); for (Path file : files) { Path absoluteFilePath = filesystem.resolve(file); findAndAddRelativePathToMap( absoluteFilePath, file, absoluteBasePathParent, relativePathMap); } } else { findAndAddRelativePathToMap( absoluteBasePath, resolver.getRelativePath(sourcePath), absoluteBasePath.getParent(), relativePathMap); } } catch (IOException e) { throw new RuntimeException( String.format("Couldn't read directory [%s].", absoluteBasePath.toString()), e); } } return ImmutableMap.copyOf(relativePathMap); } public void copy( ProjectFilesystem filesystem, final SourcePathResolver resolver, ImmutableList.Builder<Step> steps, Path destinationDir, ImmutableSortedSet<SourcePath> toCopy) { Map<Path, Path> relativeMap = createRelativeMap(filesystem, resolver, toCopy); for (Map.Entry<Path, Path> pathEntry : relativeMap.entrySet()) { Path relativePath = pathEntry.getKey(); Path absolutePath = Preconditions.checkNotNull(pathEntry.getValue()); Path destination = destinationDir.resolve(relativePath); if (relativePath.toString().endsWith(Javac.SRC_ZIP) || relativePath.toString().endsWith(Javac.SRC_JAR)) { steps.add(new UnzipStep(filesystem, absolutePath, destination.getParent())); continue; } if (destination.getParent() != null) { steps.add(MkdirStep.of(filesystem, destination.getParent())); } steps.add(CopyStep.forFile(filesystem, absolutePath, destination)); } } }