com.facebook.buck.util.PackagedResource.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.util.PackagedResource.java

Source

/*
 * Copyright 2015-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.util;

import static com.facebook.buck.zip.Unzip.ExistingFileMode.OVERWRITE;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.zip.Unzip;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.io.ByteStreams;
import com.google.common.io.Resources;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * Represents a zip that has been packaged as a resource with Buck, but which should be expanded at
 * most once during Buck's execution (not per-build).
 */
public class PackagedResource implements Supplier<Path> {

    private final ProjectFilesystem filesystem;
    private final String name;
    private final Class<?> relativeTo;
    private final Path filename;
    private final Supplier<Path> supplier;

    public PackagedResource(ProjectFilesystem filesystem, Class<?> relativeTo, String pathRelativeToClass) {
        this.filesystem = filesystem;
        this.relativeTo = relativeTo;

        // We could magically detect the class we're relative to by examining the stacktrace but that
        // would be incredibly fragile. So we won't.
        this.name = pathRelativeToClass;
        this.filename = Paths.get(pathRelativeToClass).getFileName();

        this.supplier = Suppliers.memoize(this::unpack);
    }

    @Override
    public Path get() {
        return supplier.get();
    }

    /**
     * Use this as unique ID for resource when hashing is not enabled
     * @return Class name followed by relative file path.
     * E.g. com.facebook.buck.MyClass#some_resource_file.abc
     */
    public String getResourceIdentifier() {
        return relativeTo.getName() + "#" + name;
    }

    /**
     * Use this combined with file hash as unique ID when hashing is enabled.
     * @return {@link Path} representing filename of packaged resource
     */
    public Path getFilenamePath() {
        return filename;
    }

    private Path unpack() {
        try (InputStream inner = Preconditions
                .checkNotNull(Resources.getResource(relativeTo, name), "Unable to find: %s", name).openStream();
                BufferedInputStream stream = new BufferedInputStream(inner)) {

            Path outputPath = filesystem.getBuckPaths().getResDir().resolve(relativeTo.getCanonicalName())
                    .resolve(filename);

            // If the path already exists, delete it.
            if (filesystem.exists(outputPath)) {
                filesystem.deleteRecursivelyIfExists(outputPath);
            }

            String extension = com.google.common.io.Files.getFileExtension(filename.toString());
            if (extension.equals("zip")) {
                filesystem.mkdirs(outputPath);
                // Copy the zip to a temporary file, and mark that for deletion once the VM exits.
                Path zip = Files.createTempFile(filename.toString(), ".zip");
                // Ensure we tidy up
                Files.copy(stream, zip, REPLACE_EXISTING);
                Unzip.extractZipFile(zip, filesystem, outputPath, OVERWRITE);
                Files.delete(zip);
            } else {
                filesystem.createParentDirs(outputPath);
                Path tempFilePath = filesystem.createTempFile(outputPath.getParent(),
                        outputPath.getFileName().toString() + ".", ".tmp");
                try (OutputStream outputStream = filesystem.newFileOutputStream(tempFilePath)) {
                    ByteStreams.copy(stream, outputStream);
                }
                filesystem.move(tempFilePath, outputPath);
            }
            return outputPath;
        } catch (IOException ioe) {
            throw new RuntimeException("Unable to unpack " + name, ioe);
        }
    }

}