diff options
author | Han-Wen Nienhuys <hanwen@google.com> | 2015-02-25 16:45:20 +0100 |
---|---|---|
committer | Han-Wen Nienhuys <hanwen@google.com> | 2015-02-25 16:45:20 +0100 |
commit | d08b27fa9701fecfdb69e1b0d1ac2459efc2129b (patch) | |
tree | 5d50963026239ca5aebfb47ea5b8db7e814e57c8 /src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java |
Update from Google.
--
MOE_MIGRATED_REVID=85702957
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java new file mode 100644 index 0000000000..11ed3be239 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursivePkgFunction.java @@ -0,0 +1,151 @@ +// 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.skyframe; + +import com.google.common.collect.Lists; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.collect.nestedset.Order; +import com.google.devtools.build.lib.events.Event; +import com.google.devtools.build.lib.packages.NoSuchPackageException; +import com.google.devtools.build.lib.packages.PackageIdentifier; +import com.google.devtools.build.lib.pkgcache.PathPackageLocator; +import com.google.devtools.build.lib.vfs.Dirent; +import com.google.devtools.build.lib.vfs.Dirent.Type; +import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.vfs.PathFragment; +import com.google.devtools.build.lib.vfs.RootedPath; +import com.google.devtools.build.skyframe.SkyFunction; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; + +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + +/** + * RecursivePkgFunction builds up the set of packages underneath a given directory + * transitively. + * + * <p>Example: foo/BUILD, foo/sub/x, foo/subpkg/BUILD would yield transitive packages "foo" and + * "foo/subpkg". + */ +public class RecursivePkgFunction implements SkyFunction { + + private static final Order ORDER = Order.STABLE_ORDER; + + @Override + public SkyValue compute(SkyKey skyKey, Environment env) { + RootedPath rootedPath = (RootedPath) skyKey.argument(); + Path root = rootedPath.getRoot(); + PathFragment rootRelativePath = rootedPath.getRelativePath(); + + SkyKey fileKey = FileValue.key(rootedPath); + FileValue fileValue = (FileValue) env.getValue(fileKey); + if (fileValue == null) { + return null; + } + + if (!fileValue.isDirectory()) { + return new RecursivePkgValue(NestedSetBuilder.<String>emptySet(ORDER)); + } + + if (fileValue.isSymlink()) { + // We do not follow directory symlinks when we look recursively for packages. It also + // prevents symlink loops. + return new RecursivePkgValue(NestedSetBuilder.<String>emptySet(ORDER)); + } + + PackageIdentifier packageId = PackageIdentifier.createInDefaultRepo( + rootRelativePath.getPathString()); + PackageLookupValue pkgLookupValue = + (PackageLookupValue) env.getValue(PackageLookupValue.key(packageId)); + if (pkgLookupValue == null) { + return null; + } + + NestedSetBuilder<String> packages = new NestedSetBuilder<>(ORDER); + + if (pkgLookupValue.packageExists()) { + if (pkgLookupValue.getRoot().equals(root)) { + try { + PackageValue pkgValue = (PackageValue) + env.getValueOrThrow(PackageValue.key(packageId), + NoSuchPackageException.class); + if (pkgValue == null) { + return null; + } + packages.add(pkgValue.getPackage().getName()); + } catch (NoSuchPackageException e) { + // The package had errors, but don't fail-fast as there might subpackages below the + // current directory. + env.getListener().handle(Event.error( + "package contains errors: " + rootRelativePath.getPathString())); + if (e.getPackage() != null) { + packages.add(e.getPackage().getName()); + } + } + } + // The package lookup succeeded, but was under a different root. We still, however, need to + // recursively consider subdirectories. For example: + // + // Pretend --package_path=rootA/workspace:rootB/workspace and these are the only files: + // rootA/workspace/foo/ + // rootA/workspace/foo/bar/BUILD + // rootB/workspace/foo/BUILD + // If we're doing a recursive package lookup under 'rootA/workspace' starting at 'foo', note + // that even though the package 'foo' is under 'rootB/workspace', there is still a package + // 'foo/bar' under 'rootA/workspace'. + } + + DirectoryListingValue dirValue = (DirectoryListingValue) + env.getValue(DirectoryListingValue.key(rootedPath)); + if (dirValue == null) { + return null; + } + + List<SkyKey> childDeps = Lists.newArrayList(); + for (Dirent dirent : dirValue.getDirents()) { + if (dirent.getType() != Type.DIRECTORY) { + // Non-directories can never host packages, and we do not follow symlinks (see above). + continue; + } + String basename = dirent.getName(); + if (rootRelativePath.equals(PathFragment.EMPTY_FRAGMENT) + && PathPackageLocator.DEFAULT_TOP_LEVEL_EXCLUDES.contains(basename)) { + continue; + } + SkyKey req = RecursivePkgValue.key(RootedPath.toRootedPath(root, + rootRelativePath.getRelative(basename))); + childDeps.add(req); + } + Map<SkyKey, SkyValue> childValueMap = env.getValues(childDeps); + if (env.valuesMissing()) { + return null; + } + // Aggregate the transitive subpackages. + for (SkyValue childValue : childValueMap.values()) { + if (childValue != null) { + packages.addTransitive(((RecursivePkgValue) childValue).getPackages()); + } + } + return new RecursivePkgValue(packages.build()); + } + + @Nullable + @Override + public String extractTag(SkyKey skyKey) { + return null; + } +} |