|
50 | 50 | import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
|
51 | 51 | import com.google.devtools.build.lib.server.FailureDetails.StarlarkLoading;
|
52 | 52 | import com.google.devtools.build.lib.server.FailureDetails.StarlarkLoading.Code;
|
| 53 | +import com.google.devtools.build.lib.skyframe.PackageLookupValue.NoRepositoryPackageLookupValue; |
53 | 54 | import com.google.devtools.build.lib.skyframe.StarlarkBuiltinsFunction.BuiltinsFailedException;
|
54 | 55 | import com.google.devtools.build.lib.util.DetailedExitCode;
|
55 | 56 | import com.google.devtools.build.lib.util.Fingerprint;
|
|
63 | 64 | import com.google.devtools.build.skyframe.SkyKey;
|
64 | 65 | import com.google.devtools.build.skyframe.SkyValue;
|
65 | 66 | import com.google.devtools.build.skyframe.SkyframeLookupResult;
|
| 67 | +import java.util.ArrayList; |
66 | 68 | import java.util.HashMap;
|
67 | 69 | import java.util.HashSet;
|
68 | 70 | import java.util.LinkedHashSet;
|
@@ -644,45 +646,103 @@ private BzlCompileValue.Key validatePackageAndGetCompileKey(
|
644 | 646 | return key.getCompileKey(getBuiltinsRoot(builtinsBzlPath));
|
645 | 647 | }
|
646 | 648 |
|
647 |
| - // Do package lookup. |
648 |
| - PathFragment dir = Label.getContainingDirectory(label); |
649 |
| - PackageIdentifier dirId = PackageIdentifier.create(label.getRepository(), dir); |
650 |
| - ContainingPackageLookupValue packageLookup; |
651 |
| - try { |
652 |
| - packageLookup = |
653 |
| - (ContainingPackageLookupValue) |
654 |
| - env.getValueOrThrow( |
655 |
| - ContainingPackageLookupValue.key(dirId), |
656 |
| - BuildFileNotFoundException.class, |
657 |
| - InconsistentFilesystemException.class); |
658 |
| - } catch (BuildFileNotFoundException | InconsistentFilesystemException e) { |
659 |
| - throw BzlLoadFailedException.errorFindingContainingPackage(label.toPathFragment(), e); |
660 |
| - } |
661 |
| - if (packageLookup == null) { |
662 |
| - return null; |
| 649 | + // The block below derives all (sub)directories that could possibly contain (sub)packages and |
| 650 | + // add them to a list of PackageLookup keys. These (sub)directories include the label path, and |
| 651 | + // all subdirectories from label path to the bzl file. For example, |
| 652 | + // 1. If the label is //a/b/c:d.bzl, allPackageLookupKeys only contains //a/b/c. There is no |
| 653 | + // subdirectory under label path. |
| 654 | + // 2. If the label name contains '/', for example, //a/b/c:d/e/f.bzl, allPackageLookupKeys |
| 655 | + // contain //a/b/c, //a/b/c/d and //a/b/c/d/e. |
| 656 | + List<PackageLookupValue.Key> allPackageLookupKeys = new ArrayList<>(); |
| 657 | + allPackageLookupKeys.add(PackageLookupValue.key(label.getPackageIdentifier())); |
| 658 | + RepositoryName labelRepository = label.getRepository(); |
| 659 | + PathFragment subpkgPath = label.getPackageFragment(); |
| 660 | + PathFragment labelAsRelativePath = PathFragment.create(label.getName()).getParentDirectory(); |
| 661 | + for (String segment : labelAsRelativePath.segments()) { |
| 662 | + subpkgPath = subpkgPath.getRelative(segment); |
| 663 | + PackageLookupValue.Key currentPackageLookupKey = |
| 664 | + PackageLookupValue.key(PackageIdentifier.create(labelRepository, subpkgPath)); |
| 665 | + allPackageLookupKeys.add(currentPackageLookupKey); |
| 666 | + } |
| 667 | + |
| 668 | + SkyframeLookupResult packageLookupResults = env.getValuesAndExceptions(allPackageLookupKeys); |
| 669 | + |
| 670 | + // We intentionally choose not to check `env.valuesMissing()` here. It is possible that all |
| 671 | + // PackageLookupValues are already not null but `env.valuesMissing()` is still true from a prior |
| 672 | + // request. Returning `null` in this case causes unnecessary Skyframe restarts. |
| 673 | + |
| 674 | + PackageLookupValue.Key candidateKey = null; |
| 675 | + PackageLookupValue candidateValue = null; |
| 676 | + for (PackageLookupValue.Key packageLookupKey : allPackageLookupKeys) { |
| 677 | + // Iterate in order of the directory structure so that the candidate{Key,Value} will end up as |
| 678 | + // the deepest package, in other words the "containing package". |
| 679 | + PackageLookupValue packageLookupValue; |
| 680 | + try { |
| 681 | + packageLookupValue = |
| 682 | + (PackageLookupValue) |
| 683 | + packageLookupResults.getOrThrow( |
| 684 | + packageLookupKey, |
| 685 | + BuildFileNotFoundException.class, |
| 686 | + InconsistentFilesystemException.class); |
| 687 | + } catch (BuildFileNotFoundException | InconsistentFilesystemException e) { |
| 688 | + throw BzlLoadFailedException.errorFindingContainingPackage(label.toPathFragment(), e); |
| 689 | + } |
| 690 | + |
| 691 | + if (packageLookupValue == null) { |
| 692 | + return null; |
| 693 | + } |
| 694 | + |
| 695 | + if (packageLookupValue instanceof NoRepositoryPackageLookupValue) { |
| 696 | + throw BzlLoadFailedException.noBuildFile(label, packageLookupValue.getErrorMsg()); |
| 697 | + } |
| 698 | + |
| 699 | + if (packageLookupValue.packageExists()) { |
| 700 | + candidateKey = packageLookupKey; |
| 701 | + candidateValue = packageLookupValue; |
| 702 | + } |
663 | 703 | }
|
664 | 704 |
|
665 |
| - // Resolve to compile key or error. |
666 |
| - BzlCompileValue.Key compileKey; |
667 |
| - boolean packageOk = |
668 |
| - packageLookup.hasContainingPackage() |
669 |
| - && packageLookup.getContainingPackageName().equals(label.getPackageIdentifier()); |
670 |
| - if (key.isBuildPrelude() && !packageOk) { |
671 |
| - // Ignore the prelude, its package doesn't exist. |
672 |
| - compileKey = BzlCompileValue.EMPTY_PRELUDE_KEY; |
673 |
| - } else { |
674 |
| - if (packageOk) { |
675 |
| - compileKey = key.getCompileKey(packageLookup.getContainingPackageRoot()); |
| 705 | + if (candidateKey != null && candidateKey.argument().equals(label.getPackageIdentifier())) { |
| 706 | + if (candidateValue.packageExists()) { |
| 707 | + return key.getCompileKey(candidateValue.getRoot()); |
676 | 708 | } else {
|
677 |
| - if (!packageLookup.hasContainingPackage()) { |
678 |
| - throw BzlLoadFailedException.noBuildFile( |
679 |
| - label, packageLookup.getReasonForNoContainingPackage()); |
| 709 | + throw BzlLoadFailedException.noBuildFile(label, candidateValue.getErrorMsg()); |
| 710 | + } |
| 711 | + } else { |
| 712 | + if (key.isBuildPrelude()) { |
| 713 | + return BzlCompileValue.EMPTY_PRELUDE_KEY; |
| 714 | + } |
| 715 | + if (candidateKey == null) { |
| 716 | + // If we cannot find any subpackage below label's package directory, it is still possible |
| 717 | + // that the label's package is a subpackage itself. This case should be rare, so we choose |
| 718 | + // to still handle it using ContainingPackageLookup node. |
| 719 | + ContainingPackageLookupValue containingPackageLookup; |
| 720 | + try { |
| 721 | + containingPackageLookup = |
| 722 | + (ContainingPackageLookupValue) |
| 723 | + env.getValueOrThrow( |
| 724 | + ContainingPackageLookupValue.key(label.getPackageIdentifier()), |
| 725 | + BuildFileNotFoundException.class, |
| 726 | + InconsistentFilesystemException.class); |
| 727 | + } catch (BuildFileNotFoundException | InconsistentFilesystemException e) { |
| 728 | + throw BzlLoadFailedException.errorFindingContainingPackage(label.toPathFragment(), e); |
| 729 | + } |
| 730 | + |
| 731 | + if (containingPackageLookup == null) { |
| 732 | + return null; |
| 733 | + } |
| 734 | + |
| 735 | + if (containingPackageLookup.hasContainingPackage()) { |
| 736 | + throw BzlLoadFailedException.labelSubpackageCrossesBoundary( |
| 737 | + label, containingPackageLookup); |
680 | 738 | } else {
|
681 |
| - throw BzlLoadFailedException.labelCrossesPackageBoundary(label, packageLookup); |
| 739 | + throw BzlLoadFailedException.noBuildFile(label, /* reason= */ null); |
682 | 740 | }
|
| 741 | + } else { |
| 742 | + throw BzlLoadFailedException.subpackageCrossesLabelPackageBoundary( |
| 743 | + label, candidateKey.argument(), candidateValue); |
683 | 744 | }
|
684 | 745 | }
|
685 |
| - return compileKey; |
686 | 746 | }
|
687 | 747 |
|
688 | 748 | private Root getBuiltinsRoot(String builtinsBzlPath) {
|
@@ -1583,17 +1643,21 @@ static BzlLoadFailedException noBuildFile(Label file, @Nullable String reason) {
|
1583 | 1643 | Code.PACKAGE_NOT_FOUND);
|
1584 | 1644 | }
|
1585 | 1645 |
|
1586 |
| - static BzlLoadFailedException labelCrossesPackageBoundary( |
| 1646 | + static BzlLoadFailedException labelSubpackageCrossesBoundary( |
1587 | 1647 | Label label, ContainingPackageLookupValue containingPackageLookupValue) {
|
1588 | 1648 | return new BzlLoadFailedException(
|
1589 |
| - ContainingPackageLookupValue.getErrorMessageForLabelCrossingPackageBoundary( |
1590 |
| - // We don't actually know the proper Root to pass in here (since we don't e.g. know |
1591 |
| - // the root of the bzl/BUILD file that is trying to load 'label'). Therefore we just |
1592 |
| - // pass in the Root of the containing package in order to still get a useful error |
1593 |
| - // message for the user. |
1594 |
| - containingPackageLookupValue.getContainingPackageRoot(), |
1595 |
| - label, |
1596 |
| - containingPackageLookupValue), |
| 1649 | + ContainingPackageLookupValue.getErrorMessageForLabelSubpackageCrossesBoundary( |
| 1650 | + containingPackageLookupValue, label), |
| 1651 | + Code.LABEL_CROSSES_PACKAGE_BOUNDARY); |
| 1652 | + } |
| 1653 | + |
| 1654 | + static BzlLoadFailedException subpackageCrossesLabelPackageBoundary( |
| 1655 | + Label label, |
| 1656 | + PackageIdentifier subpackageIdentifier, |
| 1657 | + PackageLookupValue packageLookupValue) { |
| 1658 | + return new BzlLoadFailedException( |
| 1659 | + PackageLookupValue.getErrorMessageForSubpackageCrossesLabelPackageBoundary( |
| 1660 | + packageLookupValue.getRoot(), label, subpackageIdentifier, packageLookupValue), |
1597 | 1661 | Code.LABEL_CROSSES_PACKAGE_BOUNDARY);
|
1598 | 1662 | }
|
1599 | 1663 |
|
|
0 commit comments