com.facebook.buck.jvm.java.ClasspathChecker.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.jvm.java.ClasspathChecker.java

Source

/*
 * Copyright 2016-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.jvm.java;

import com.facebook.buck.io.PathListing;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.List;
import java.util.Locale;

public class ClasspathChecker {

    private static final ImmutableSet<String> ALLOWED_EXTENSIONS_SET = ImmutableSet.of("jar", "zip");

    private final String separator;
    private final String pathSeparator;
    private final Function<String, Path> toPathFunc;
    private final Function<Path, Boolean> isDirectoryFunc;
    private final Function<Path, Boolean> isFileFunc;
    private final BiFunction<Path, String, Iterable<Path>> globberFunc;

    public ClasspathChecker() {
        this(File.separator, File.pathSeparator, Paths::get, Files::isDirectory, Files::isRegularFile,
                (path, glob) -> {
                    try {
                        return PathListing.listMatchingPaths(path, glob, PathListing.GET_PATH_MODIFIED_TIME);
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                });
    }

    @VisibleForTesting
    ClasspathChecker(String separator, String pathSeparator, Function<String, Path> toPathFunc,
            Function<Path, Boolean> isDirectoryFunc, Function<Path, Boolean> isFileFunc,
            BiFunction<Path, String, Iterable<Path>> globberFunc) {
        this.separator = separator;
        this.pathSeparator = pathSeparator;
        this.toPathFunc = toPathFunc;
        this.isDirectoryFunc = isDirectoryFunc;
        this.isFileFunc = isFileFunc;
        this.globberFunc = globberFunc;
    }

    /**
     * Parses a Java classpath string ("path/to/foo:baz.jar:blech.zip:path/to/*")
     * and checks if at least one entry is valid (exists on disk).
     *
     * From http://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html :
     *
     * Class path entries can contain the basename wildcard character *,
     * which is considered equivalent to specifying a list of all the
     * files in the directory with the extension .jar or .JAR. For
     * example, the class path entry foo/* specifies all JAR files in the
     * directory named foo. A classpath entry consisting simply of *
     * expands to a list of all the jar files in the current directory.
     */
    public boolean validateClasspath(String classpath) {
        for (String entry : Splitter.on(pathSeparator).split(classpath)) {
            // On Windows, Path.endsWith("*") throws an error:
            //
            // java.nio.file.InvalidPathException: Illegal char <*> at index 0
            //
            // So, we split manually.
            List<String> classpathComponents = Splitter.on(separator).splitToList(entry);
            if (classpathComponents.isEmpty()) {
                continue;
            }

            if (Iterables.getLast(classpathComponents).equals("*")) {
                // Trim the * off the path.
                List<String> dirComponents = classpathComponents.subList(0, classpathComponents.size() - 1);
                Path entryDir = toPathFunc.apply(Joiner.on(separator).join(dirComponents));
                if (!Iterables.isEmpty(globberFunc.apply(entryDir, "*.jar"))) {
                    return true;
                } else if (!Iterables.isEmpty(globberFunc.apply(entryDir, "*.JAR"))) {
                    return true;
                }
            } else {
                Path entryPath = toPathFunc.apply(entry);
                if (isDirectoryFunc.apply(entryPath)) {
                    return true;
                } else if (isFileFunc.apply(entryPath) && ALLOWED_EXTENSIONS_SET.contains(
                        com.google.common.io.Files.getFileExtension(entryPath.toString().toLowerCase(Locale.US)))) {
                    return true;
                }
            }
        }
        return false;
    }
}