diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java new file mode 100644 index 0000000000..6dcc224ed7 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ASTFileLookupFunction.java @@ -0,0 +1,177 @@ +// 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.devtools.build.lib.packages.CachingPackageLocator; +import com.google.devtools.build.lib.packages.RuleClassProvider; +import com.google.devtools.build.lib.pkgcache.PathPackageLocator; +import com.google.devtools.build.lib.syntax.BuildFileAST; +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.SkyFunctionException; +import com.google.devtools.build.skyframe.SkyFunctionException.Transience; +import com.google.devtools.build.skyframe.SkyKey; +import com.google.devtools.build.skyframe.SkyValue; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; + +import javax.annotation.Nullable; + +/** + * A SkyFunction for {@link ASTFileLookupValue}s. Tries to locate a file and load it as a + * syntax tree and cache the resulting {@link BuildFileAST}. If the file doesn't exist + * the function doesn't fail but returns a specific NO_FILE ASTLookupValue. + */ +public class ASTFileLookupFunction implements SkyFunction { + + private abstract static class FileLookupResult { + /** Returns whether the file lookup was successful. */ + public abstract boolean lookupSuccessful(); + + /** If {@code lookupSuccessful()}, returns the {@link RootedPath} to the file. */ + public abstract RootedPath rootedPath(); + + static FileLookupResult noFile() { + return UnsuccessfulFileResult.INSTANCE; + } + + static FileLookupResult file(RootedPath rootedPath) { + return new SuccessfulFileResult(rootedPath); + } + + private static class SuccessfulFileResult extends FileLookupResult { + private final RootedPath rootedPath; + + private SuccessfulFileResult(RootedPath rootedPath) { + this.rootedPath = rootedPath; + } + + @Override + public boolean lookupSuccessful() { + return true; + } + + @Override + public RootedPath rootedPath() { + return rootedPath; + } + } + + private static class UnsuccessfulFileResult extends FileLookupResult { + private static final UnsuccessfulFileResult INSTANCE = new UnsuccessfulFileResult(); + private UnsuccessfulFileResult() { + } + + @Override + public boolean lookupSuccessful() { + return false; + } + + @Override + public RootedPath rootedPath() { + throw new IllegalStateException("unsucessful lookup"); + } + } + } + + private final AtomicReference<PathPackageLocator> pkgLocator; + private final RuleClassProvider ruleClassProvider; + private final CachingPackageLocator packageManager; + + public ASTFileLookupFunction(AtomicReference<PathPackageLocator> pkgLocator, + CachingPackageLocator packageManager, + RuleClassProvider ruleClassProvider) { + this.pkgLocator = pkgLocator; + this.packageManager = packageManager; + this.ruleClassProvider = ruleClassProvider; + } + + @Override + public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException, + InterruptedException { + PathFragment astFilePathFragment = (PathFragment) skyKey.argument(); + FileLookupResult lookupResult = getASTFile(env, astFilePathFragment); + if (lookupResult == null) { + return null; + } + + BuildFileAST ast = null; + if (!lookupResult.lookupSuccessful()) { + // Return the specific NO_FILE ASTLookupValue instance if no file was found. + return ASTFileLookupValue.NO_FILE; + } else { + Path path = lookupResult.rootedPath().asPath(); + // Skylark files end with bzl. + boolean parseAsSkylark = astFilePathFragment.getPathString().endsWith(".bzl"); + try { + ast = parseAsSkylark + ? BuildFileAST.parseSkylarkFile(path, env.getListener(), + packageManager, ruleClassProvider.getSkylarkValidationEnvironment().clone()) + : BuildFileAST.parseBuildFile(path, env.getListener(), + packageManager, false); + } catch (IOException e) { + throw new ASTLookupFunctionException(new ErrorReadingSkylarkExtensionException( + e.getMessage()), Transience.TRANSIENT); + } + } + + return new ASTFileLookupValue(ast); + } + + private FileLookupResult getASTFile(Environment env, PathFragment astFilePathFragment) + throws ASTLookupFunctionException { + for (Path packagePathEntry : pkgLocator.get().getPathEntries()) { + RootedPath rootedPath = RootedPath.toRootedPath(packagePathEntry, astFilePathFragment); + SkyKey fileSkyKey = FileValue.key(rootedPath); + FileValue fileValue = null; + try { + fileValue = (FileValue) env.getValueOrThrow(fileSkyKey, IOException.class, + FileSymlinkCycleException.class, InconsistentFilesystemException.class); + } catch (IOException | FileSymlinkCycleException e) { + throw new ASTLookupFunctionException(new ErrorReadingSkylarkExtensionException( + e.getMessage()), Transience.PERSISTENT); + } catch (InconsistentFilesystemException e) { + throw new ASTLookupFunctionException(e, Transience.PERSISTENT); + } + if (fileValue == null) { + return null; + } + if (fileValue.isFile()) { + return FileLookupResult.file(rootedPath); + } + } + return FileLookupResult.noFile(); + } + + @Nullable + @Override + public String extractTag(SkyKey skyKey) { + return null; + } + + private static final class ASTLookupFunctionException extends SkyFunctionException { + private ASTLookupFunctionException(ErrorReadingSkylarkExtensionException e, + Transience transience) { + super(e, transience); + } + + private ASTLookupFunctionException(InconsistentFilesystemException e, Transience transience) { + super(e, transience); + } + } +} |