// Copyright 2014 Google Inc. All rights reserved. // // 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.google.devtools.build.lib.pkgcache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.packages.BuildFileNotFoundException; import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.vfs.FileStatus; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.Symlinks; import com.google.devtools.build.lib.vfs.UnixGlob; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; /** * A mapping from the name of a package to the location of its BUILD file. * The implementation composes an ordered sequence of directories according to * the package-path rules. * *
All methods are thread-safe, and (assuming no change to the underlying
* filesystem) idempotent.
*/
public class PathPackageLocator implements Serializable {
public static final Set The package's root directory may be computed by calling getParentFile()
* on the result of this function.
*
* Instances of this interface do not attempt to do any caching, nor
* implement checks for package-boundary crossing logic; the PackageCache
* does that.
*
* If the same package exists beneath multiple package path entries, the
* first path that matches always wins.
*/
public Path getPackageBuildFile(String packageName) throws NoSuchPackageException {
Path buildFile = getPackageBuildFileNullable(packageName, UnixGlob.DEFAULT_SYSCALLS_REF);
if (buildFile == null) {
throw new BuildFileNotFoundException(packageName, "BUILD file not found on package path");
}
return buildFile;
}
/**
* Like #getPackageBuildFile(), but returns null instead of throwing.
*
* @param packageName the name of the package.
* @param cache a filesystem-level cache of stat() calls.
*/
public Path getPackageBuildFileNullable(String packageName,
AtomicReference extends UnixGlob.FilesystemCalls> cache) {
return getFilePath(new PathFragment(packageName).getRelative("BUILD"), cache);
}
/**
* Returns an immutable ordered list of the directories on the package path.
*/
public ImmutableList If there are WORKSPACE files beneath multiple package path entries, the first one always
* wins.
*/
public Path getWorkspaceFile() {
AtomicReference extends UnixGlob.FilesystemCalls> cache = UnixGlob.DEFAULT_SYSCALLS_REF;
// TODO(bazel-team): correctness in the presence of changes to the location of the WORKSPACE
// file.
return getFilePath(new PathFragment("WORKSPACE"), cache);
}
private Path getFilePath(PathFragment suffix,
AtomicReference extends UnixGlob.FilesystemCalls> cache) {
for (Path pathEntry : pathEntries) {
Path buildFile = pathEntry.getRelative(suffix);
FileStatus stat = cache.get().statNullable(buildFile, Symlinks.FOLLOW);
if (stat != null && stat.isFile()) {
return buildFile;
}
}
return null;
}
@Override
public int hashCode() {
return pathEntries.hashCode();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof PathPackageLocator)) {
return false;
}
return this.getPathEntries().equals(((PathPackageLocator) other).getPathEntries());
}
}