Skip to content

Commit

Permalink
Track repo rule label attributes after the first non-existent one
Browse files Browse the repository at this point in the history
Even with this commit, the fact that a particular label in a repository
rule's label attributes does not resolve to a regular file is not
tracked, which means that there is still a potential for incorrect
incremental fetches.

Work towards bazelbuild#13441
  • Loading branch information
fmeum committed May 10, 2023
1 parent a741c8f commit fbcbf98
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.google.devtools.build.lib.packages.StructProvider;
import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
import com.google.devtools.build.lib.repository.RepositoryFetchProgress;
import com.google.devtools.build.lib.rules.repository.NeedsSkyframeRestartException;
import com.google.devtools.build.lib.rules.repository.RepositoryFunction.RepositoryFunctionException;
import com.google.devtools.build.lib.rules.repository.WorkspaceAttributeMapper;
import com.google.devtools.build.lib.runtime.ProcessWrapper;
Expand Down Expand Up @@ -516,26 +517,42 @@ public String toString() {
*/
// TODO(wyv): somehow migrate this to the base context too.
public void enforceLabelAttributes() throws EvalException, InterruptedException {
// TODO: If a labels fails to resolve to an existing regular file, we do not add a dependency on
// that fact - if the file is created later or changes its type, it will not trigger a rerun of
// the repository function.
StructImpl attr = getAttr();
for (String name : attr.getFieldNames()) {
Object value = attr.getValue(name);
if (value instanceof Label) {
getPathFromLabel((Label) value);
dependOnLabelIgnoringErrors((Label) value);
}
if (value instanceof Sequence) {
for (Object entry : (Sequence) value) {
if (entry instanceof Label) {
getPathFromLabel((Label) entry);
dependOnLabelIgnoringErrors((Label) entry);
}
}
}
if (value instanceof Dict) {
for (Object entry : ((Dict) value).keySet()) {
if (entry instanceof Label) {
getPathFromLabel((Label) entry);
dependOnLabelIgnoringErrors((Label) entry);
}
}
}
}
}

private void dependOnLabelIgnoringErrors(Label label) throws InterruptedException, EvalException {
try {
getPathFromLabel(label);
} catch (EvalException e) {
if (e instanceof NeedsSkyframeRestartException) {
throw e;
}
// EvalExceptions indicate labels not referring to existing files. This is fine,
// as long as they are never resolved to files in the execution of the rule; we allow
// non-strict rules.
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,6 @@ public RepositoryDirectoryValue.Builder fetch(
} catch (NeedsSkyframeRestartException e) {
// Missing values are expected; just restart before we actually start the rule
return null;
} catch (EvalException e) {
// EvalExceptions indicate labels not referring to existing files. This is fine,
// as long as they are never resolved to files in the execution of the rule; we allow
// non-strict rules. So now we have to start evaluating the actual rule, even if that
// means the rule might get restarted for legitimate reasons.
}

// This rule is mainly executed for its side effect. Nevertheless, the return value is
Expand Down
44 changes: 44 additions & 0 deletions src/test/shell/bazel/starlark_prefetching_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -227,4 +227,48 @@ EOF
bazel build @ext//:foo || fail "expected success"
}

# Regression test for https://github.com/bazelbuild/bazel/issues/13441
function test_files_tracked_with_non_existing_files() {
cat > rules.bzl <<'EOF'
def _repo_impl(ctx):
ctx.symlink(ctx.path(Label("@//:WORKSPACE")).dirname, "link")
print("b.txt: " + ctx.read("link/b.txt"))
print("c.txt: " + ctx.read("link/c.txt"))
ctx.file("BUILD")
ctx.file("WORKSPACE")
repo = repository_rule(
_repo_impl,
attrs = {"_files": attr.label_list(
default = [
Label("@//:a.txt"),
Label("@//:b.txt"),
Label("@//:c.txt"),
],
)},
)
EOF

cat > WORKSPACE <<'EOF'
load(":rules.bzl", "repo")
repo(name = "ext")
EOF
touch BUILD

# a.txt is intentionally not created
echo "bbbb" > b.txt
echo "cccc" > c.txt

# The missing file dependency is tolerated.
bazel build @ext//:all &> "$TEST_log" || fail "Expected repository rule to build"
expect_log "b.txt: bbbb"
expect_log "c.txt: cccc"

echo "not_cccc" > c.txt
bazel build @ext//:all &> "$TEST_log" || fail "Expected repository rule to build"
expect_log "b.txt: bbbb"
expect_log "c.txt: not_cccc"
}

run_suite "Starlark repo prefetching tests"

0 comments on commit fbcbf98

Please sign in to comment.