blob: c030cccb1518487b7b04fdbf996c126522c42a72 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.skyframe;
16
John Fielda97e17f2015-11-13 02:19:52 +000017import com.google.devtools.build.lib.cmdline.Label;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010018import com.google.devtools.build.lib.packages.RuleClassProvider;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import com.google.devtools.build.lib.syntax.BuildFileAST;
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000020import com.google.devtools.build.lib.syntax.Mutability;
21import com.google.devtools.build.lib.syntax.Runtime;
22import com.google.devtools.build.lib.syntax.ValidationEnvironment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010023import com.google.devtools.build.lib.vfs.Path;
24import com.google.devtools.build.lib.vfs.PathFragment;
25import com.google.devtools.build.lib.vfs.RootedPath;
26import com.google.devtools.build.skyframe.SkyFunction;
27import com.google.devtools.build.skyframe.SkyFunctionException;
28import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
29import com.google.devtools.build.skyframe.SkyKey;
30import com.google.devtools.build.skyframe.SkyValue;
31
32import java.io.IOException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010033
34import javax.annotation.Nullable;
35
36/**
John Fielda97e17f2015-11-13 02:19:52 +000037 * A SkyFunction for {@link ASTFileLookupValue}s.
38 *
39 * <p> Given a {@link Label} referencing a Skylark file, loads it as a syntax tree
40 * ({@link BuildFileAST}). The Label must be absolute, and must not reference the special
41 * {@code external} package. If the file (or the package containing it) doesn't exist, the
42 * function doesn't fail, but instead returns a specific {@code NO_FILE} {@link ASTFileLookupValue}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010043 */
44public class ASTFileLookupFunction implements SkyFunction {
45
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046 private final RuleClassProvider ruleClassProvider;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010047
John Fielda97e17f2015-11-13 02:19:52 +000048 public ASTFileLookupFunction(RuleClassProvider ruleClassProvider) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010049 this.ruleClassProvider = ruleClassProvider;
50 }
51
52 @Override
53 public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException,
54 InterruptedException {
John Fielda97e17f2015-11-13 02:19:52 +000055 Label fileLabel = (Label) skyKey.argument();
56 PathFragment filePathFragment = fileLabel.toPathFragment();
57
58 //
59 // Determine whether the package designated by fileLabel exists.
60 //
61 SkyKey pkgSkyKey = PackageLookupValue.key(fileLabel.getPackageIdentifier());
62 PackageLookupValue pkgLookupValue = null;
63 pkgLookupValue = (PackageLookupValue) env.getValue(pkgSkyKey);
64 if (pkgLookupValue == null) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010065 return null;
66 }
John Fielda97e17f2015-11-13 02:19:52 +000067 if (!pkgLookupValue.packageExists()) {
68 return ASTFileLookupValue.forBadPackage(fileLabel, pkgLookupValue.getErrorMsg());
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000069 }
John Fielda97e17f2015-11-13 02:19:52 +000070
71 //
72 // Determine whether the file designated by fileLabel exists.
73 //
74 Path packageRoot = pkgLookupValue.getRoot();
75 RootedPath rootedPath = RootedPath.toRootedPath(packageRoot, filePathFragment);
76 SkyKey fileSkyKey = FileValue.key(rootedPath);
77 FileValue fileValue = null;
John Field925dc5c2015-09-21 18:59:19 +000078 try {
John Fielda97e17f2015-11-13 02:19:52 +000079 fileValue = (FileValue) env.getValueOrThrow(fileSkyKey, IOException.class,
80 FileSymlinkException.class, InconsistentFilesystemException.class);
81 } catch (IOException | FileSymlinkException e) {
82 throw new ASTLookupFunctionException(new ErrorReadingSkylarkExtensionException(e),
83 Transience.PERSISTENT);
84 } catch (InconsistentFilesystemException e) {
85 throw new ASTLookupFunctionException(e, Transience.PERSISTENT);
86 }
87 if (fileValue == null) {
88 return null;
89 }
90 if (!fileValue.isFile()) {
91 return ASTFileLookupValue.forBadFile(fileLabel);
92 }
93
94 //
95 // Both the package and the file exist; load the file and parse it as an AST.
96 //
97 BuildFileAST ast = null;
98 Path path = rootedPath.asPath();
99 // Skylark files end with bzl
100 boolean parseAsSkylark = filePathFragment.getPathString().endsWith(".bzl");
101 try {
102 long astFileSize = fileValue.getSize();
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000103 if (parseAsSkylark) {
104 try (Mutability mutability = Mutability.create("validate")) {
John Fielda97e17f2015-11-13 02:19:52 +0000105 ast = BuildFileAST.parseSkylarkFile(path, astFileSize, env.getListener(),
Michajlo Matijkiw2a7c8022015-09-22 02:22:12 +0000106 new ValidationEnvironment(
107 ruleClassProvider.createSkylarkRuleClassEnvironment(
108 mutability,
109 env.getListener(),
110 // the two below don't matter for extracting the ValidationEnvironment:
111 /*astFileContentHashCode=*/null,
112 /*importMap=*/null)
Lukacs Berki5d9b8a02015-10-21 12:36:56 +0000113 .setupDynamic(Runtime.PKG_NAME, Runtime.NONE)
114 .setupDynamic(Runtime.REPOSITORY_NAME, Runtime.NONE)));
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000115 }
116 } else {
John Fielda97e17f2015-11-13 02:19:52 +0000117 ast = BuildFileAST.parseBuildFile(path, astFileSize, env.getListener(), false);
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000118 }
119 } catch (IOException e) {
John Fielda97e17f2015-11-13 02:19:52 +0000120 throw new ASTLookupFunctionException(new ErrorReadingSkylarkExtensionException(e),
121 Transience.TRANSIENT);
Michajlo Matijkiw2a7c8022015-09-22 02:22:12 +0000122 }
John Fielda97e17f2015-11-13 02:19:52 +0000123
Michajlo Matijkiw2a7c8022015-09-22 02:22:12 +0000124 return ASTFileLookupValue.withFile(ast);
125 }
126
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100127 @Nullable
128 @Override
129 public String extractTag(SkyKey skyKey) {
130 return null;
131 }
132
133 private static final class ASTLookupFunctionException extends SkyFunctionException {
134 private ASTLookupFunctionException(ErrorReadingSkylarkExtensionException e,
135 Transience transience) {
136 super(e, transience);
137 }
138
139 private ASTLookupFunctionException(InconsistentFilesystemException e, Transience transience) {
140 super(e, transience);
141 }
142 }
143}