|
19 | 19 | import com.google.common.annotations.VisibleForTesting;
|
20 | 20 | import com.google.common.base.Preconditions;
|
21 | 21 | import com.google.common.collect.BiMap;
|
22 |
| -import com.google.common.collect.HashBiMap; |
23 | 22 | import com.google.common.collect.ImmutableList;
|
24 | 23 | import com.google.common.collect.ImmutableMap;
|
25 | 24 | import com.google.common.collect.ImmutableSet;
|
@@ -978,7 +977,10 @@ public boolean recordLoadedModules() {
|
978 | 977 | private License defaultLicense = License.NO_LICENSE;
|
979 | 978 | private Set<License.DistributionType> defaultDistributionSet = License.DEFAULT_DISTRIB;
|
980 | 979 |
|
981 |
| - private BiMap<String, Target> targets = HashBiMap.create(); |
| 980 | + // All targets added to the package. We use SnapshottableBiMap to help track insertion order of |
| 981 | + // Rule targets, for use by native.existing_rules(). |
| 982 | + private BiMap<String, Target> targets = |
| 983 | + new SnapshottableBiMap<>(target -> target instanceof Rule); |
982 | 984 | private final Map<Label, EnvironmentGroup> environmentGroups = new HashMap<>();
|
983 | 985 |
|
984 | 986 | /**
|
@@ -1479,20 +1481,46 @@ Target getTarget(String name) {
|
1479 | 1481 | }
|
1480 | 1482 |
|
1481 | 1483 | /**
|
1482 |
| - * Removes a target from the {@link Package} under construction. Intended to be used only by |
1483 |
| - * {@link com.google.devtools.build.lib.skyframe.PackageFunction} to remove targets whose labels |
1484 |
| - * cross subpackage boundaries. |
| 1484 | + * Replaces a target in the {@link Package} under construction with a new target with the same |
| 1485 | + * name and belonging to the same package. |
| 1486 | + * |
| 1487 | + * <p>A hack needed for {@link WorkspaceFactoryHelper}. |
1485 | 1488 | */
|
1486 |
| - void removeTarget(Target target) { |
1487 |
| - if (target.getPackage() == pkg) { |
1488 |
| - this.targets.remove(target.getName()); |
1489 |
| - } |
| 1489 | + void replaceTarget(Target newTarget) { |
| 1490 | + Preconditions.checkArgument( |
| 1491 | + targets.containsKey(newTarget.getName()), |
| 1492 | + "No existing target with name '%s' in the targets map", |
| 1493 | + newTarget.getName()); |
| 1494 | + Preconditions.checkArgument( |
| 1495 | + newTarget.getPackage() == pkg, // pointer comparison since we're constructing `pkg` |
| 1496 | + "Replacement target belongs to package '%s', expected '%s'", |
| 1497 | + newTarget.getPackage(), |
| 1498 | + pkg); |
| 1499 | + targets.put(newTarget.getName(), newTarget); |
1490 | 1500 | }
|
1491 | 1501 |
|
1492 | 1502 | public Set<Target> getTargets() {
|
1493 | 1503 | return Package.getTargets(targets);
|
1494 | 1504 | }
|
1495 | 1505 |
|
| 1506 | + /** |
| 1507 | + * Returns a lightweight snapshot view of the names of all rule targets belonging to this |
| 1508 | + * package at the time of this call. |
| 1509 | + * |
| 1510 | + * @throws IllegalStateException if this method is called after {@link beforeBuild} has been |
| 1511 | + * called. |
| 1512 | + */ |
| 1513 | + Map<String, Rule> getRulesSnapshotView() { |
| 1514 | + if (targets instanceof SnapshottableBiMap<?, ?>) { |
| 1515 | + return Maps.transformValues( |
| 1516 | + ((SnapshottableBiMap<String, Target>) targets).getTrackedSnapshot(), |
| 1517 | + target -> (Rule) target); |
| 1518 | + } else { |
| 1519 | + throw new IllegalStateException( |
| 1520 | + "getRulesSnapshotView() cannot be used after beforeBuild() has been called"); |
| 1521 | + } |
| 1522 | + } |
| 1523 | + |
1496 | 1524 | /**
|
1497 | 1525 | * Returns an (immutable, unordered) view of all the targets belonging to this package which are
|
1498 | 1526 | * instances of the specified class.
|
@@ -1556,8 +1584,10 @@ void setVisibilityAndLicense(InputFile inputFile, RuleVisibility visibility, Lic
|
1556 | 1584 | if (!((InputFile) cacheInstance).isVisibilitySpecified()
|
1557 | 1585 | || cacheInstance.getVisibility() != visibility
|
1558 | 1586 | || !Objects.equals(cacheInstance.getLicense(), license)) {
|
1559 |
| - targets.put(filename, new InputFile( |
1560 |
| - pkg, cacheInstance.getLabel(), cacheInstance.getLocation(), visibility, license)); |
| 1587 | + targets.put( |
| 1588 | + filename, |
| 1589 | + new InputFile( |
| 1590 | + pkg, cacheInstance.getLabel(), cacheInstance.getLocation(), visibility, license)); |
1561 | 1591 | }
|
1562 | 1592 | }
|
1563 | 1593 |
|
@@ -1718,6 +1748,17 @@ private Builder beforeBuild(boolean discoverAssumedInputFiles) throws NoSuchPack
|
1718 | 1748 | getPackageIdentifier(), ioExceptionMessage, ioException, ioExceptionDetailedExitCode);
|
1719 | 1749 | }
|
1720 | 1750 |
|
| 1751 | + // SnapshottableBiMap does not allow removing targets (in order to efficiently track rule |
| 1752 | + // insertion order). However, we *do* need to support removal of targets in |
| 1753 | + // PackageFunction.handleLabelsCrossingSubpackagesAndPropagateInconsistentFilesystemExceptions |
| 1754 | + // which is called *between* calls to beforeBuild and finishBuild. We thus repoint the targets |
| 1755 | + // map to the SnapshottableBiMap's underlying bimap and thus stop tracking insertion order. |
| 1756 | + // After this point, snapshots of targets should no longer be used, and any further |
| 1757 | + // getRulesSnapshotView calls will throw. |
| 1758 | + if (targets instanceof SnapshottableBiMap<?, ?>) { |
| 1759 | + targets = ((SnapshottableBiMap<String, Target>) targets).getUnderlyingBiMap(); |
| 1760 | + } |
| 1761 | + |
1721 | 1762 | // We create the original BUILD InputFile when the package filename is set; however, the
|
1722 | 1763 | // visibility may be overridden with an exports_files directive, so we need to obtain the
|
1723 | 1764 | // current instance here.
|
|
0 commit comments