Search in sources :

Example 21 with RootedPath

use of com.google.devtools.build.lib.vfs.RootedPath in project bazel by bazelbuild.

the class NewRepositoryBuildFileHandler method getBuildFileValue.

private FileValue getBuildFileValue(Rule rule, Environment env) throws RepositoryFunctionException, InterruptedException {
    WorkspaceAttributeMapper mapper = WorkspaceAttributeMapper.of(rule);
    String buildFileAttribute;
    try {
        buildFileAttribute = mapper.get("build_file", Type.STRING);
    } catch (EvalException e) {
        throw new RepositoryFunctionException(e, Transience.PERSISTENT);
    }
    RootedPath rootedBuild;
    if (LabelValidator.isAbsolute(buildFileAttribute)) {
        try {
            // Parse a label
            Label label = Label.parseAbsolute(buildFileAttribute);
            SkyKey pkgSkyKey = PackageLookupValue.key(label.getPackageIdentifier());
            PackageLookupValue pkgLookupValue = (PackageLookupValue) env.getValue(pkgSkyKey);
            if (pkgLookupValue == null) {
                return null;
            }
            if (!pkgLookupValue.packageExists()) {
                throw new RepositoryFunctionException(new EvalException(rule.getLocation(), "Unable to load package for " + buildFileAttribute + ": not found."), Transience.PERSISTENT);
            }
            // And now for the file
            Path packageRoot = pkgLookupValue.getRoot();
            rootedBuild = RootedPath.toRootedPath(packageRoot, label.toPathFragment());
        } catch (LabelSyntaxException ex) {
            throw new RepositoryFunctionException(new EvalException(rule.getLocation(), String.format("In %s the 'build_file' attribute does not specify a valid label: %s", rule, ex.getMessage())), Transience.PERSISTENT);
        }
    } else {
        // TODO(dmarting): deprecate using a path for the build_file attribute.
        PathFragment buildFile = new PathFragment(buildFileAttribute);
        Path buildFileTarget = workspacePath.getRelative(buildFile);
        if (!buildFileTarget.exists()) {
            throw new RepositoryFunctionException(new EvalException(rule.getLocation(), String.format("In %s the 'build_file' attribute does not specify an existing file " + "(%s does not exist)", rule, buildFileTarget)), Transience.PERSISTENT);
        }
        if (buildFile.isAbsolute()) {
            rootedBuild = RootedPath.toRootedPath(buildFileTarget.getParentDirectory(), new PathFragment(buildFileTarget.getBaseName()));
        } else {
            rootedBuild = RootedPath.toRootedPath(workspacePath, buildFile);
        }
    }
    SkyKey buildFileKey = FileValue.key(rootedBuild);
    FileValue buildFileValue;
    try {
        // Note that this dependency is, strictly speaking, not necessary: the symlink could simply
        // point to this FileValue and the symlink chasing could be done while loading the package
        // but this results in a nicer error message and it's correct as long as RepositoryFunctions
        // don't write to things in the file system this FileValue depends on. In theory, the latter
        // is possible if the file referenced by build_file is a symlink to somewhere under the
        // external/ directory, but if you do that, you are really asking for trouble.
        buildFileValue = (FileValue) env.getValueOrThrow(buildFileKey, IOException.class, FileSymlinkException.class, InconsistentFilesystemException.class);
        if (buildFileValue == null) {
            return null;
        }
    } catch (IOException | FileSymlinkException | InconsistentFilesystemException e) {
        throw new RepositoryFunctionException(new IOException("Cannot lookup " + buildFileAttribute + ": " + e.getMessage()), Transience.TRANSIENT);
    }
    return buildFileValue;
}
Also used : SkyKey(com.google.devtools.build.skyframe.SkyKey) PackageLookupValue(com.google.devtools.build.lib.skyframe.PackageLookupValue) RootedPath(com.google.devtools.build.lib.vfs.RootedPath) Path(com.google.devtools.build.lib.vfs.Path) FileValue(com.google.devtools.build.lib.skyframe.FileValue) LabelSyntaxException(com.google.devtools.build.lib.cmdline.LabelSyntaxException) Label(com.google.devtools.build.lib.cmdline.Label) PathFragment(com.google.devtools.build.lib.vfs.PathFragment) EvalException(com.google.devtools.build.lib.syntax.EvalException) IOException(java.io.IOException) InconsistentFilesystemException(com.google.devtools.build.lib.skyframe.InconsistentFilesystemException) RootedPath(com.google.devtools.build.lib.vfs.RootedPath) FileSymlinkException(com.google.devtools.build.lib.skyframe.FileSymlinkException) RepositoryFunctionException(com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException)

Example 22 with RootedPath

use of com.google.devtools.build.lib.vfs.RootedPath in project bazel by bazelbuild.

the class RepositoryFunction method addExternalFilesDependencies.

/**
   * For files that are under $OUTPUT_BASE/external, add a dependency on the corresponding rule so
   * that if the WORKSPACE file changes, the File/DirectoryStateValue will be re-evaluated.
   *
   * <p>Note that: - We don't add a dependency on the parent directory at the package root boundary,
   * so the only transitive dependencies from files inside the package roots to external files are
   * through symlinks. So the upwards transitive closure of external files is small. - The only way
   * other than external repositories for external source files to get into the skyframe graph in
   * the first place is through symlinks outside the package roots, which we neither want to
   * encourage nor optimize for since it is not common. So the set of external files is small.
   */
public static void addExternalFilesDependencies(RootedPath rootedPath, BlazeDirectories directories, Environment env) throws IOException, InterruptedException {
    Path externalRepoDir = getExternalRepositoryDirectory(directories);
    PathFragment repositoryPath = rootedPath.asPath().relativeTo(externalRepoDir);
    if (repositoryPath.segmentCount() == 0) {
        // repository path.
        return;
    }
    String repositoryName = repositoryPath.getSegment(0);
    try {
        // Add a dependency to the repository rule. RepositoryDirectoryValue does add this dependency
        // already but we want to catch RepositoryNotFoundException, so invoke #getRule first.
        RepositoryFunction.getRule(repositoryName, env);
        if (repositoryPath.segmentCount() > 1) {
            // For all file under the repository directory, depends on the actual RepositoryDirectory
            // function so we get invalidation when the repository is fetched.
            // For the repository directory itself, we cannot depends on the RepositoryDirectoryValue
            // (cycle).
            env.getValue(RepositoryDirectoryValue.key(RepositoryName.create("@" + repositoryName)));
        }
    } catch (RepositoryFunction.RepositoryNotFoundException ex) {
        // of the resolution. Therefore we are safe to ignore that Exception.
        return;
    } catch (RepositoryFunctionException | LabelSyntaxException ex) {
        // This should never happen.
        throw new IllegalStateException("Repository " + repositoryName + " cannot be resolved for path " + rootedPath, ex);
    }
}
Also used : RootedPath(com.google.devtools.build.lib.vfs.RootedPath) Path(com.google.devtools.build.lib.vfs.Path) LabelSyntaxException(com.google.devtools.build.lib.cmdline.LabelSyntaxException) PathFragment(com.google.devtools.build.lib.vfs.PathFragment)

Example 23 with RootedPath

use of com.google.devtools.build.lib.vfs.RootedPath in project bazel by bazelbuild.

the class PathWindowsTest method testCaseInsensitiveRootedPath.

@Test
public void testCaseInsensitiveRootedPath() {
    Path ancestor = filesystem.getPath("C:\\foo\\bar");
    assertThat(ancestor).isInstanceOf(WindowsPath.class);
    Path child = filesystem.getPath("C:\\FOO\\Bar\\baz");
    assertThat(child).isInstanceOf(WindowsPath.class);
    assertThat(child.startsWith(ancestor)).isTrue();
    assertThat(child.relativeTo(ancestor)).isEqualTo(new PathFragment("baz"));
    RootedPath actual = RootedPath.toRootedPath(ancestor, child);
    assertThat(actual.getRoot()).isEqualTo(ancestor);
    assertThat(actual.getRelativePath()).isEqualTo(new PathFragment("baz"));
}
Also used : RootedPath(com.google.devtools.build.lib.vfs.RootedPath) WindowsPath(com.google.devtools.build.lib.windows.WindowsFileSystem.WindowsPath) Path(com.google.devtools.build.lib.vfs.Path) PathFragment(com.google.devtools.build.lib.vfs.PathFragment) RootedPath(com.google.devtools.build.lib.vfs.RootedPath) Test(org.junit.Test)

Example 24 with RootedPath

use of com.google.devtools.build.lib.vfs.RootedPath in project bazel by bazelbuild.

the class SkylarkRepositoryContext method getPathFromLabel.

// Resolve the label given by value into a file path.
private SkylarkPath getPathFromLabel(Label label) throws EvalException, InterruptedException {
    RootedPath rootedPath = getRootedPathFromLabel(label, env);
    SkyKey fileSkyKey = FileValue.key(rootedPath);
    FileValue fileValue = null;
    try {
        fileValue = (FileValue) env.getValueOrThrow(fileSkyKey, IOException.class, FileSymlinkException.class, InconsistentFilesystemException.class);
    } catch (IOException | FileSymlinkException | InconsistentFilesystemException e) {
        throw new EvalException(Location.BUILTIN, e);
    }
    if (fileValue == null) {
        throw SkylarkRepositoryFunction.restart();
    }
    if (!fileValue.isFile()) {
        throw new EvalException(Location.BUILTIN, "Not a file: " + rootedPath.asPath().getPathString());
    }
    // A label do not contains space so it safe to use as a key.
    markerData.put("FILE:" + label, Integer.toString(fileValue.realFileStateValue().hashCode()));
    return new SkylarkPath(rootedPath.asPath());
}
Also used : SkyKey(com.google.devtools.build.skyframe.SkyKey) FileValue(com.google.devtools.build.lib.skyframe.FileValue) FileSymlinkException(com.google.devtools.build.lib.skyframe.FileSymlinkException) IOException(java.io.IOException) EvalException(com.google.devtools.build.lib.syntax.EvalException) InconsistentFilesystemException(com.google.devtools.build.lib.skyframe.InconsistentFilesystemException) RootedPath(com.google.devtools.build.lib.vfs.RootedPath)

Example 25 with RootedPath

use of com.google.devtools.build.lib.vfs.RootedPath in project bazel by bazelbuild.

the class GlobFunction method compute.

@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws GlobFunctionException, InterruptedException {
    GlobDescriptor glob = (GlobDescriptor) skyKey.argument();
    // Note that the glob's package is assumed to exist which implies that the package's BUILD file
    // exists which implies that the package's directory exists.
    PathFragment globSubdir = glob.getSubdir();
    if (!globSubdir.equals(PathFragment.EMPTY_FRAGMENT)) {
        PackageLookupValue globSubdirPkgLookupValue = (PackageLookupValue) env.getValue(PackageLookupValue.key(PackageIdentifier.create(glob.getPackageId().getRepository(), glob.getPackageId().getPackageFragment().getRelative(globSubdir))));
        if (globSubdirPkgLookupValue == null) {
            return null;
        }
        if (globSubdirPkgLookupValue.packageExists()) {
            // defines another package, so glob expansion should not descend into that subdir.
            return GlobValue.EMPTY;
        }
    }
    String pattern = glob.getPattern();
    // Split off the first path component of the pattern.
    int slashPos = pattern.indexOf('/');
    String patternHead;
    String patternTail;
    if (slashPos == -1) {
        patternHead = pattern;
        patternTail = null;
    } else {
        // Substrings will share the backing array of the original glob string. That should be fine.
        patternHead = pattern.substring(0, slashPos);
        patternTail = pattern.substring(slashPos + 1);
    }
    NestedSetBuilder<PathFragment> matches = NestedSetBuilder.stableOrder();
    boolean globMatchesBareFile = patternTail == null;
    // "**" also matches an empty segment, so try the case where it is not present.
    if ("**".equals(patternHead)) {
        if (globMatchesBareFile) {
            // Recursive globs aren't supposed to match the package's directory.
            if (!glob.excludeDirs() && !globSubdir.equals(PathFragment.EMPTY_FRAGMENT)) {
                matches.add(globSubdir);
            }
        } else {
            SkyKey globKey = GlobValue.internalKey(glob.getPackageId(), glob.getPackageRoot(), globSubdir, patternTail, glob.excludeDirs());
            GlobValue globValue = (GlobValue) env.getValue(globKey);
            if (globValue == null) {
                return null;
            }
            matches.addTransitive(globValue.getMatches());
        }
    }
    PathFragment dirPathFragment = glob.getPackageId().getPackageFragment().getRelative(globSubdir);
    RootedPath dirRootedPath = RootedPath.toRootedPath(glob.getPackageRoot(), dirPathFragment);
    if (alwaysUseDirListing || containsGlobs(patternHead)) {
        String subdirPattern = "**".equals(patternHead) ? glob.getPattern() : patternTail;
        // Pattern contains globs, so a directory listing is required.
        //
        // Note that we have good reason to believe the directory exists: if this is the
        // top-level directory of the package, the package's existence implies the directory's
        // existence; if this is a lower-level directory in the package, then we got here from
        // previous directory listings. Filesystem operations concurrent with build could mean the
        // directory no longer exists, but DirectoryListingFunction handles that gracefully.
        DirectoryListingValue listingValue = (DirectoryListingValue) env.getValue(DirectoryListingValue.key(dirRootedPath));
        if (listingValue == null) {
            return null;
        }
        // In order to batch Skyframe requests, we do three passes over the directory:
        // (1) Process every dirent, keeping track of values we need to request if the dirent cannot
        //     be processed with current information (symlink targets and subdirectory globs/package
        //     lookups for some subdirectories).
        // (2) Get those values and process the symlinks, keeping track of subdirectory globs/package
        //     lookups we may need to request in case the symlink's target is a directory.
        // (3) Process the necessary subdirectories.
        int direntsSize = listingValue.getDirents().size();
        Map<SkyKey, Dirent> symlinkFileMap = Maps.newHashMapWithExpectedSize(direntsSize);
        Map<SkyKey, Dirent> subdirMap = Maps.newHashMapWithExpectedSize(direntsSize);
        Map<Dirent, Object> sortedResultMap = Maps.newTreeMap();
        // First pass: do normal files and collect SkyKeys to request for subdirectories and symlinks.
        for (Dirent dirent : listingValue.getDirents()) {
            Type direntType = dirent.getType();
            String fileName = dirent.getName();
            if (!UnixGlob.matches(patternHead, fileName, regexPatternCache)) {
                continue;
            }
            if (direntType == Dirent.Type.SYMLINK) {
                // TODO(bazel-team): Consider extracting the symlink resolution logic.
                // For symlinks, look up the corresponding FileValue. This ensures that if the symlink
                // changes and "switches types" (say, from a file to a directory), this value will be
                // invalidated. We also need the target's type to properly process the symlink.
                symlinkFileMap.put(FileValue.key(RootedPath.toRootedPath(glob.getPackageRoot(), dirPathFragment.getRelative(fileName))), dirent);
                continue;
            }
            if (direntType == Dirent.Type.DIRECTORY) {
                SkyKey keyToRequest = getSkyKeyForSubdir(fileName, glob, subdirPattern);
                if (keyToRequest != null) {
                    subdirMap.put(keyToRequest, dirent);
                }
            } else if (globMatchesBareFile) {
                sortedResultMap.put(dirent, glob.getSubdir().getRelative(fileName));
            }
        }
        Map<SkyKey, SkyValue> subdirAndSymlinksResult = env.getValues(Sets.union(subdirMap.keySet(), symlinkFileMap.keySet()));
        if (env.valuesMissing()) {
            return null;
        }
        Map<SkyKey, Dirent> symlinkSubdirMap = Maps.newHashMapWithExpectedSize(symlinkFileMap.size());
        // Also process any known directories.
        for (Map.Entry<SkyKey, SkyValue> lookedUpKeyAndValue : subdirAndSymlinksResult.entrySet()) {
            if (symlinkFileMap.containsKey(lookedUpKeyAndValue.getKey())) {
                FileValue symlinkFileValue = (FileValue) lookedUpKeyAndValue.getValue();
                if (!symlinkFileValue.isSymlink()) {
                    throw new GlobFunctionException(new InconsistentFilesystemException("readdir and stat disagree about whether " + ((RootedPath) lookedUpKeyAndValue.getKey().argument()).asPath() + " is a symlink."), Transience.TRANSIENT);
                }
                if (!symlinkFileValue.exists()) {
                    continue;
                }
                Dirent dirent = symlinkFileMap.get(lookedUpKeyAndValue.getKey());
                String fileName = dirent.getName();
                if (symlinkFileValue.isDirectory()) {
                    SkyKey keyToRequest = getSkyKeyForSubdir(fileName, glob, subdirPattern);
                    if (keyToRequest != null) {
                        symlinkSubdirMap.put(keyToRequest, dirent);
                    }
                } else if (globMatchesBareFile) {
                    sortedResultMap.put(dirent, glob.getSubdir().getRelative(fileName));
                }
            } else {
                processSubdir(lookedUpKeyAndValue, subdirMap, glob, sortedResultMap);
            }
        }
        Map<SkyKey, SkyValue> symlinkSubdirResult = env.getValues(symlinkSubdirMap.keySet());
        if (env.valuesMissing()) {
            return null;
        }
        // pass.
        for (Map.Entry<SkyKey, SkyValue> lookedUpKeyAndValue : symlinkSubdirResult.entrySet()) {
            processSubdir(lookedUpKeyAndValue, symlinkSubdirMap, glob, sortedResultMap);
        }
        for (Map.Entry<Dirent, Object> fileMatches : sortedResultMap.entrySet()) {
            addToMatches(fileMatches.getValue(), matches);
        }
    } else {
        // Pattern does not contain globs, so a direct stat is enough.
        String fileName = patternHead;
        RootedPath fileRootedPath = RootedPath.toRootedPath(glob.getPackageRoot(), dirPathFragment.getRelative(fileName));
        FileValue fileValue = (FileValue) env.getValue(FileValue.key(fileRootedPath));
        if (fileValue == null) {
            return null;
        }
        if (fileValue.exists()) {
            if (fileValue.isDirectory()) {
                SkyKey keyToRequest = getSkyKeyForSubdir(fileName, glob, patternTail);
                if (keyToRequest != null) {
                    SkyValue valueRequested = env.getValue(keyToRequest);
                    if (env.valuesMissing()) {
                        return null;
                    }
                    Object fileMatches = getSubdirMatchesFromSkyValue(fileName, glob, valueRequested);
                    if (fileMatches != null) {
                        addToMatches(fileMatches, matches);
                    }
                }
            } else if (globMatchesBareFile) {
                matches.add(glob.getSubdir().getRelative(fileName));
            }
        }
    }
    Preconditions.checkState(!env.valuesMissing(), skyKey);
    NestedSet<PathFragment> matchesBuilt = matches.build();
    // Use the same value to represent that we did not match anything.
    if (matchesBuilt.isEmpty()) {
        return GlobValue.EMPTY;
    }
    return new GlobValue(matchesBuilt);
}
Also used : PathFragment(com.google.devtools.build.lib.vfs.PathFragment) RootedPath(com.google.devtools.build.lib.vfs.RootedPath) SkyValue(com.google.devtools.build.skyframe.SkyValue) Dirent(com.google.devtools.build.lib.vfs.Dirent) SkyKey(com.google.devtools.build.skyframe.SkyKey) Type(com.google.devtools.build.lib.vfs.Dirent.Type) Map(java.util.Map)

Aggregations

RootedPath (com.google.devtools.build.lib.vfs.RootedPath)84 PathFragment (com.google.devtools.build.lib.vfs.PathFragment)43 SkyKey (com.google.devtools.build.skyframe.SkyKey)41 Test (org.junit.Test)33 Path (com.google.devtools.build.lib.vfs.Path)28 Artifact (com.google.devtools.build.lib.actions.Artifact)21 IOException (java.io.IOException)15 Package (com.google.devtools.build.lib.packages.Package)13 SkyValue (com.google.devtools.build.skyframe.SkyValue)11 TraversalRequest (com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.TraversalRequest)9 ResolvedFile (com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.ResolvedFile)8 FilesetTraversalParams (com.google.devtools.build.lib.actions.FilesetTraversalParams)7 EvalException (com.google.devtools.build.lib.syntax.EvalException)7 ErrorInfo (com.google.devtools.build.skyframe.ErrorInfo)7 Dirent (com.google.devtools.build.lib.vfs.Dirent)6 LabelSyntaxException (com.google.devtools.build.lib.cmdline.LabelSyntaxException)5 BuildFileNotFoundException (com.google.devtools.build.lib.packages.BuildFileNotFoundException)5 NoSuchPackageException (com.google.devtools.build.lib.packages.NoSuchPackageException)5 FileValue (com.google.devtools.build.lib.skyframe.FileValue)5 Map (java.util.Map)5