Move most license checking logic into a module to make it easier to eventually remove. There's basically four groups of license-related logic in Bazel: 1) Syntactic support in BUILD files 2) Semantics that checks third_party rules have licenses() declared 3) LicenseProvider, which collects rules' transitive license declarations 4) Semantics that checks if a build's licenses are valid This change only covers 4). This also simplifies AnalysisPhaseRunner and License. Part of #7444. PiperOrigin-RevId: 235585865
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD index a05ecf9..6a92c8b 100644 --- a/src/main/java/com/google/devtools/build/lib/BUILD +++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -808,6 +808,22 @@ ) java_library( + name = "bazel/LicenseCheckingModule", + srcs = ["bazel/LicenseCheckingModule.java"], + deps = [ + ":build-base", + ":events", + ":packages-internal", + ":runtime", + "//src/main/java/com/google/devtools/build/lib/cmdline", + "//src/main/java/com/google/devtools/build/lib/collect", + "//src/main/java/com/google/devtools/build/lib/collect/nestedset", + "//src/main/java/com/google/devtools/build/lib/profiler", + "//third_party:guava", + ], +) + +java_library( name = "bazel-main", srcs = ["bazel/Bazel.java"], resources = [ @@ -845,8 +861,10 @@ exclude = [ "bazel/Bazel.java", "bazel/BazelRepositoryModule.java", + "bazel/LicenseCheckingModule.java", ], ), + exports = [":bazel/LicenseCheckingModule"], deps = [ ":build-base", ":build-info",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/Bazel.java b/src/main/java/com/google/devtools/build/lib/bazel/Bazel.java index f2829af..4ece65e 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/Bazel.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/Bazel.java
@@ -43,6 +43,7 @@ com.google.devtools.build.lib.bazel.BazelWorkspaceStatusModule.class, com.google.devtools.build.lib.bazel.BazelDiffAwarenessModule.class, com.google.devtools.build.lib.bazel.BazelRepositoryModule.class, + com.google.devtools.build.lib.bazel.LicenseCheckingModule.class, com.google.devtools.build.lib.bazel.debug.WorkspaceRuleModule.class, com.google.devtools.build.lib.bazel.coverage.BazelCoverageReportModule.class, com.google.devtools.build.lib.skylarkdebug.module.SkylarkDebuggerModule.class,
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/LicenseCheckingModule.java b/src/main/java/com/google/devtools/build/lib/bazel/LicenseCheckingModule.java new file mode 100644 index 0000000..869b9a0 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/bazel/LicenseCheckingModule.java
@@ -0,0 +1,256 @@ +// Copyright 2019 The Bazel Authors. 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.bazel; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Table; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.LicensesProvider; +import com.google.devtools.build.lib.analysis.LicensesProvider.TargetLicense; +import com.google.devtools.build.lib.analysis.StaticallyLinkedMarkerProvider; +import com.google.devtools.build.lib.analysis.ViewCreationFailedException; +import com.google.devtools.build.lib.analysis.config.BuildConfiguration; +import com.google.devtools.build.lib.analysis.config.BuildOptions; +import com.google.devtools.build.lib.buildtool.BuildRequest; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.events.Event; +import com.google.devtools.build.lib.events.EventHandler; +import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.packages.InputFile; +import com.google.devtools.build.lib.packages.License; +import com.google.devtools.build.lib.packages.License.DistributionType; +import com.google.devtools.build.lib.packages.License.LicenseType; +import com.google.devtools.build.lib.packages.NoSuchPackageException; +import com.google.devtools.build.lib.packages.NoSuchTargetException; +import com.google.devtools.build.lib.packages.Rule; +import com.google.devtools.build.lib.packages.Target; +import com.google.devtools.build.lib.packages.TargetUtils; +import com.google.devtools.build.lib.profiler.ProfilePhase; +import com.google.devtools.build.lib.profiler.Profiler; +import com.google.devtools.build.lib.profiler.SilentCloseable; +import com.google.devtools.build.lib.runtime.BlazeModule; +import com.google.devtools.build.lib.runtime.CommandEnvironment; +import java.util.EnumSet; +import java.util.Set; + +/** + * Module responsible for checking third party license compliance. + * + * <p><b>This is outdated logic marked for removal.</b> See <a + * href="https://github.com/bazelbuild/bazel/issues/7444">#7444</a> for details. + */ +public class LicenseCheckingModule extends BlazeModule { + + private boolean shouldCheckLicenses(BuildOptions buildOptions) { + return buildOptions.get(BuildConfiguration.Options.class).checkLicenses; + } + + @Override + public void afterAnalysis( + CommandEnvironment env, + BuildRequest request, + BuildOptions buildOptions, + Iterable<ConfiguredTarget> configuredTargets) + throws InterruptedException, ViewCreationFailedException { + // Check licenses. + // We check licenses if the first target configuration has license checking enabled. Right + // now, it is not possible to have multiple target configurations with different settings + // for this flag, which allows us to take this short cut. + if (shouldCheckLicenses(buildOptions)) { + Profiler.instance().markPhase(ProfilePhase.LICENSE); + try (SilentCloseable c = Profiler.instance().profile("validateLicensingForTargets")) { + validateLicensingForTargets(env, configuredTargets, request.getKeepGoing()); + } + } + } + + /** + * Takes a set of configured targets, and checks if the distribution methods declared for the + * targets are compatible with the constraints imposed by their prerequisites' licenses. + * + * @param configuredTargets the targets to check + * @param keepGoing if false, and a licensing error is encountered, both generates an error + * message on the reporter, <em>and</em> throws an exception. If true, then just generates a + * message on the reporter. + * @throws ViewCreationFailedException if the license checking failed (and not --keep_going) + */ + private static void validateLicensingForTargets( + CommandEnvironment env, Iterable<ConfiguredTarget> configuredTargets, boolean keepGoing) + throws ViewCreationFailedException { + for (ConfiguredTarget configuredTarget : configuredTargets) { + Target target = null; + try { + target = env.getPackageManager().getTarget(env.getReporter(), configuredTarget.getLabel()); + } catch (NoSuchPackageException | NoSuchTargetException | InterruptedException e) { + env.getReporter().handle(Event.error("Failed to get target to validate license")); + throw new ViewCreationFailedException( + "Build aborted due to issue getting targets to validate licenses", e); + } + + if (TargetUtils.isTestRule(target)) { + continue; // Tests are exempt from license checking + } + + final Set<DistributionType> distribs = target.getDistributions(); + StaticallyLinkedMarkerProvider markerProvider = + configuredTarget.getProvider(StaticallyLinkedMarkerProvider.class); + boolean staticallyLinked = markerProvider != null && markerProvider.isLinkedStatically(); + + LicensesProvider provider = configuredTarget.getProvider(LicensesProvider.class); + if (provider != null) { + NestedSet<TargetLicense> licenses = provider.getTransitiveLicenses(); + for (TargetLicense targetLicense : licenses) { + if (!checkCompatibility( + targetLicense.getLicense(), + distribs, + target, + targetLicense.getLabel(), + env.getReporter(), + staticallyLinked)) { + if (!keepGoing) { + throw new ViewCreationFailedException("Build aborted due to licensing error"); + } + } + } + } else if (target instanceof InputFile) { + // Input file targets do not provide licenses because they do not + // depend on the rule where their license is taken from. This is usually + // not a problem, because the transitive collection of licenses always + // hits the rule they come from, except when the input file is a + // top-level target. Thus, we need to handle that case specially here. + // + // See FileTarget#getLicense for more information about the handling of + // license issues with File targets. + License license = target.getLicense(); + if (!checkCompatibility( + license, + distribs, + target, + configuredTarget.getLabel(), + env.getReporter(), + staticallyLinked)) { + if (!keepGoing) { + throw new ViewCreationFailedException("Build aborted due to licensing error"); + } + } + } + } + } + + private static final Object MARKER = new Object(); + + /** + * The license incompatibility set. This contains the set of (Distribution,License) pairs that + * should generate errors. + */ + private static final Table<DistributionType, LicenseType, Object> licenseIncompatibilies = + createLicenseIncompatibilitySet(); + + private static Table<DistributionType, LicenseType, Object> createLicenseIncompatibilitySet() { + Table<DistributionType, LicenseType, Object> result = HashBasedTable.create(); + result.put(DistributionType.CLIENT, LicenseType.RESTRICTED, MARKER); + result.put(DistributionType.EMBEDDED, LicenseType.RESTRICTED, MARKER); + result.put(DistributionType.INTERNAL, LicenseType.BY_EXCEPTION_ONLY, MARKER); + result.put(DistributionType.CLIENT, LicenseType.BY_EXCEPTION_ONLY, MARKER); + result.put(DistributionType.WEB, LicenseType.BY_EXCEPTION_ONLY, MARKER); + result.put(DistributionType.EMBEDDED, LicenseType.BY_EXCEPTION_ONLY, MARKER); + return ImmutableTable.copyOf(result); + } + + /** + * The license warning set. This contains the set of (Distribution,License) pairs that should + * generate warnings when the user requests verbose license checking. + */ + private static final Table<DistributionType, LicenseType, Object> licenseWarnings = + createLicenseWarningsSet(); + + private static Table<DistributionType, LicenseType, Object> createLicenseWarningsSet() { + Table<DistributionType, LicenseType, Object> result = HashBasedTable.create(); + result.put(DistributionType.CLIENT, LicenseType.RECIPROCAL, MARKER); + result.put(DistributionType.EMBEDDED, LicenseType.RECIPROCAL, MARKER); + result.put(DistributionType.CLIENT, LicenseType.NOTICE, MARKER); + result.put(DistributionType.EMBEDDED, LicenseType.NOTICE, MARKER); + return ImmutableTable.copyOf(result); + } + + /** + * Checks if the given license is compatible with distributing a particular target in some set of + * distribution modes. + * + * @param license the license to check + * @param dists the modes of distribution + * @param target the target which is being checked, and which will be used for checking exceptions + * @param licensedTarget the target which declared the license being checked. + * @param eventHandler a reporter where any licensing issues discovered should be reported + * @param staticallyLinked whether the target is statically linked under this command + * @return true if the license is compatible with the distributions + */ + @VisibleForTesting + public static boolean checkCompatibility( + License license, + Set<DistributionType> dists, + Target target, + Label licensedTarget, + EventHandler eventHandler, + boolean staticallyLinked) { + Location location = (target instanceof Rule) ? ((Rule) target).getLocation() : null; + + LicenseType leastRestrictiveLicense; + if (license.getLicenseTypes().contains(LicenseType.RESTRICTED_IF_STATICALLY_LINKED)) { + Set<LicenseType> tempLicenses = EnumSet.copyOf(license.getLicenseTypes()); + tempLicenses.remove(LicenseType.RESTRICTED_IF_STATICALLY_LINKED); + if (staticallyLinked) { + tempLicenses.add(LicenseType.RESTRICTED); + } else { + tempLicenses.add(LicenseType.UNENCUMBERED); + } + leastRestrictiveLicense = License.leastRestrictive(tempLicenses); + } else { + leastRestrictiveLicense = License.leastRestrictive(license.getLicenseTypes()); + } + for (DistributionType dt : dists) { + if (licenseIncompatibilies.contains(dt, leastRestrictiveLicense)) { + if (!license.getExceptions().contains(target.getLabel())) { + eventHandler.handle( + Event.error( + location, + "Build target '" + + target.getLabel() + + "' is not compatible with license '" + + license + + "' from target '" + + licensedTarget + + "'")); + return false; + } + } else if (licenseWarnings.contains(dt, leastRestrictiveLicense)) { + eventHandler.handle( + Event.warn( + location, + "Build target '" + + target + + "' has a potential licensing issue with a '" + + license + + "' license from target '" + + licensedTarget + + "'")); + } + } + return true; + } +}
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java index 8cc38c0..6af3eb8 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java
@@ -21,9 +21,6 @@ import com.google.devtools.build.lib.analysis.AnalysisResult; import com.google.devtools.build.lib.analysis.BuildView; import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.LicensesProvider; -import com.google.devtools.build.lib.analysis.LicensesProvider.TargetLicense; -import com.google.devtools.build.lib.analysis.StaticallyLinkedMarkerProvider; import com.google.devtools.build.lib.analysis.ViewCreationFailedException; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.BuildOptions; @@ -35,19 +32,13 @@ import com.google.devtools.build.lib.buildtool.buildevent.TestFilteringCompleteEvent; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.TargetParsingException; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.events.Event; -import com.google.devtools.build.lib.packages.InputFile; -import com.google.devtools.build.lib.packages.License; -import com.google.devtools.build.lib.packages.License.DistributionType; -import com.google.devtools.build.lib.packages.NoSuchPackageException; -import com.google.devtools.build.lib.packages.NoSuchTargetException; import com.google.devtools.build.lib.packages.Target; -import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.pkgcache.LoadingFailedException; import com.google.devtools.build.lib.profiler.ProfilePhase; import com.google.devtools.build.lib.profiler.Profiler; import com.google.devtools.build.lib.profiler.SilentCloseable; +import com.google.devtools.build.lib.runtime.BlazeModule; import com.google.devtools.build.lib.runtime.CommandEnvironment; import com.google.devtools.build.lib.skyframe.BuildConfigurationValue; import com.google.devtools.build.lib.skyframe.TargetPatternPhaseValue; @@ -118,16 +109,8 @@ runAnalysisPhase(request, loadingResult, buildOptions, request.getMultiCpus()); } - // Check licenses. - // We check licenses if the first target configuration has license checking enabled. Right - // now, it is not possible to have multiple target configurations with different settings - // for this flag, which allows us to take this short cut. - boolean checkLicenses = buildOptions.get(BuildConfiguration.Options.class).checkLicenses; - if (checkLicenses) { - Profiler.instance().markPhase(ProfilePhase.LICENSE); - try (SilentCloseable c = Profiler.instance().profile("validateLicensingForTargets")) { - validateLicensingForTargets(analysisResult.getTargetsToBuild(), request.getKeepGoing()); - } + for (BlazeModule module : env.getRuntime().getBlazeModules()) { + module.afterAnalysis(env, request, buildOptions, analysisResult.getTargetsToBuild()); } reportTargets(analysisResult); @@ -288,73 +271,4 @@ "Found " + targetCount + (targetCount == 1 ? " target..." : " targets..."))); } } - - /** - * Takes a set of configured targets, and checks if the distribution methods declared for the - * targets are compatible with the constraints imposed by their prerequisites' licenses. - * - * @param configuredTargets the targets to check - * @param keepGoing if false, and a licensing error is encountered, both generates an error - * message on the reporter, <em>and</em> throws an exception. If true, then just generates a - * message on the reporter. - * @throws ViewCreationFailedException if the license checking failed (and not --keep_going) - */ - private void validateLicensingForTargets( - Iterable<ConfiguredTarget> configuredTargets, boolean keepGoing) - throws ViewCreationFailedException { - for (ConfiguredTarget configuredTarget : configuredTargets) { - Target target = null; - try { - target = env.getPackageManager().getTarget(env.getReporter(), configuredTarget.getLabel()); - } catch (NoSuchPackageException | NoSuchTargetException | InterruptedException e) { - env.getReporter().handle(Event.error("Failed to get target to validate license")); - throw new ViewCreationFailedException( - "Build aborted due to issue getting targets to validate licenses", e); - } - - if (TargetUtils.isTestRule(target)) { - continue; // Tests are exempt from license checking - } - - final Set<DistributionType> distribs = target.getDistributions(); - StaticallyLinkedMarkerProvider markerProvider = - configuredTarget.getProvider(StaticallyLinkedMarkerProvider.class); - boolean staticallyLinked = markerProvider != null && markerProvider.isLinkedStatically(); - - LicensesProvider provider = configuredTarget.getProvider(LicensesProvider.class); - if (provider != null) { - NestedSet<TargetLicense> licenses = provider.getTransitiveLicenses(); - for (TargetLicense targetLicense : licenses) { - if (!targetLicense - .getLicense() - .checkCompatibility( - distribs, - target, - targetLicense.getLabel(), - env.getReporter(), - staticallyLinked)) { - if (!keepGoing) { - throw new ViewCreationFailedException("Build aborted due to licensing error"); - } - } - } - } else if (target instanceof InputFile) { - // Input file targets do not provide licenses because they do not - // depend on the rule where their license is taken from. This is usually - // not a problem, because the transitive collection of licenses always - // hits the rule they come from, except when the input file is a - // top-level target. Thus, we need to handle that case specially here. - // - // See FileTarget#getLicense for more information about the handling of - // license issues with File targets. - License license = target.getLicense(); - if (!license.checkCompatibility( - distribs, target, configuredTarget.getLabel(), env.getReporter(), staticallyLinked)) { - if (!keepGoing) { - throw new ViewCreationFailedException("Build aborted due to licensing error"); - } - } - } - } - } }
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java index 87cf21a..e6213e4 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
@@ -223,7 +223,7 @@ } /** Returns the value of the --keep_going option. */ - boolean getKeepGoing() { + public boolean getKeepGoing() { return getOptions(KeepGoingOption.class).keepGoing; }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/License.java b/src/main/java/com/google/devtools/build/lib/packages/License.java index 8c68447..c980444 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/License.java +++ b/src/main/java/com/google/devtools/build/lib/packages/License.java
@@ -15,19 +15,13 @@ package com.google.devtools.build.lib.packages; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.HashBasedTable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableTable; import com.google.common.collect.Sets; -import com.google.common.collect.Table; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; -import com.google.devtools.build.lib.events.Event; -import com.google.devtools.build.lib.events.EventHandler; -import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization; import com.google.devtools.build.lib.skylarkbuildapi.LicenseApi; @@ -75,15 +69,16 @@ } /** - * Gets the least restrictive license type from the list of licenses declared - * for a target. For the purposes of license checking, the license type set of - * a declared license can be reduced to its least restrictive member. + * Gets the least restrictive license type from the list of licenses declared for a target. For + * the purposes of license checking, the license type set of a declared license can be reduced to + * its least restrictive member. * * @param types a collection of license types * @return the least restrictive license type */ @VisibleForTesting - static LicenseType leastRestrictive(Collection<LicenseType> types) { + public static LicenseType leastRestrictive(Collection<LicenseType> types) { + // TODO(gregce): move this method to LicenseCheckingModule when Bazel's tests no longer use it return types.isEmpty() ? LicenseType.BY_EXCEPTION_ONLY : Collections.max(types); } @@ -138,43 +133,6 @@ } } - private static final Object MARKER = new Object(); - - /** - * The license incompatibility set. This contains the set of - * (Distribution,License) pairs that should generate errors. - */ - private static Table<DistributionType, LicenseType, Object> LICENSE_INCOMPATIBILIES = - createLicenseIncompatibilitySet(); - - private static Table<DistributionType, LicenseType, Object> createLicenseIncompatibilitySet() { - Table<DistributionType, LicenseType, Object> result = HashBasedTable.create(); - result.put(DistributionType.CLIENT, LicenseType.RESTRICTED, MARKER); - result.put(DistributionType.EMBEDDED, LicenseType.RESTRICTED, MARKER); - result.put(DistributionType.INTERNAL, LicenseType.BY_EXCEPTION_ONLY, MARKER); - result.put(DistributionType.CLIENT, LicenseType.BY_EXCEPTION_ONLY, MARKER); - result.put(DistributionType.WEB, LicenseType.BY_EXCEPTION_ONLY, MARKER); - result.put(DistributionType.EMBEDDED, LicenseType.BY_EXCEPTION_ONLY, MARKER); - return ImmutableTable.copyOf(result); - } - - /** - * The license warning set. This contains the set of - * (Distribution,License) pairs that should generate warnings when the user - * requests verbose license checking. - */ - private static Table<DistributionType, LicenseType, Object> LICENSE_WARNINGS = - createLicenseWarningsSet(); - - private static Table<DistributionType, LicenseType, Object> createLicenseWarningsSet() { - Table<DistributionType, LicenseType, Object> result = HashBasedTable.create(); - result.put(DistributionType.CLIENT, LicenseType.RECIPROCAL, MARKER); - result.put(DistributionType.EMBEDDED, LicenseType.RECIPROCAL, MARKER); - result.put(DistributionType.CLIENT, LicenseType.NOTICE, MARKER); - result.put(DistributionType.EMBEDDED, LicenseType.NOTICE, MARKER); - return ImmutableTable.copyOf(result); - } - @AutoCodec.Instantiator @VisibleForSerialization License(ImmutableSet<LicenseType> licenseTypes, ImmutableSet<Label> exceptions) { @@ -232,55 +190,6 @@ } /** - * Checks if this license is compatible with distributing a particular target - * in some set of distribution modes. - * - * @param dists the modes of distribution - * @param target the target which is being checked, and which will be used for - * checking exceptions - * @param licensedTarget the target which declared the license being checked. - * @param eventHandler a reporter where any licensing issues discovered should be - * reported - * @param staticallyLinked whether the target is statically linked under this command - * @return true if the license is compatible with the distributions - */ - public boolean checkCompatibility(Set<DistributionType> dists, - Target target, Label licensedTarget, EventHandler eventHandler, - boolean staticallyLinked) { - Location location = (target instanceof Rule) ? ((Rule) target).getLocation() : null; - - LicenseType leastRestrictiveLicense; - if (licenseTypes.contains(LicenseType.RESTRICTED_IF_STATICALLY_LINKED)) { - Set<LicenseType> tempLicenses = EnumSet.copyOf(licenseTypes); - tempLicenses.remove(LicenseType.RESTRICTED_IF_STATICALLY_LINKED); - if (staticallyLinked) { - tempLicenses.add(LicenseType.RESTRICTED); - } else { - tempLicenses.add(LicenseType.UNENCUMBERED); - } - leastRestrictiveLicense = leastRestrictive(tempLicenses); - } else { - leastRestrictiveLicense = leastRestrictive(licenseTypes); - } - for (DistributionType dt : dists) { - if (LICENSE_INCOMPATIBILIES.contains(dt, leastRestrictiveLicense)) { - if (!exceptions.contains(target.getLabel())) { - eventHandler.handle(Event.error(location, "Build target '" + target.getLabel() - + "' is not compatible with license '" + this + "' from target '" - + licensedTarget + "'")); - return false; - } - } else if (LICENSE_WARNINGS.contains(dt, leastRestrictiveLicense)) { - eventHandler.handle( - Event.warn(location, "Build target '" + target - + "' has a potential licensing issue " - + "with a '" + this + "' license from target '" + licensedTarget + "'")); - } - } - return true; - } - - /** * @return an immutable set of {@link LicenseType}s contained in this {@code * License} */
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeModule.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeModule.java index 03bf031..dda1465 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeModule.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeModule.java
@@ -19,7 +19,9 @@ import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.BlazeVersionInfo; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.ServerDirectories; +import com.google.devtools.build.lib.analysis.ViewCreationFailedException; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.test.CoverageReportActionFactory; import com.google.devtools.build.lib.buildtool.BuildRequest; @@ -246,6 +248,22 @@ } /** + * Called after Bazel analyzes the build's top-level targets. This is called once per build if + * --analyze is enabled. Modules can override this to perform extra checks on analysis results. + * + * @param env the command environment + * @param request the build request + * @param buildOptions the build's top-level options + * @param configuredTargets the build's requested top-level targets as {@link ConfiguredTarget}s + */ + public void afterAnalysis( + CommandEnvironment env, + BuildRequest request, + BuildOptions buildOptions, + Iterable<ConfiguredTarget> configuredTargets) + throws InterruptedException, ViewCreationFailedException {} + + /** * Called when Bazel initializes the action execution subsystem. This is called once per build if * action execution is enabled. Modules can override this method to affect how execution is * performed.
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD index 6f17d30..13e090d 100644 --- a/src/test/java/com/google/devtools/build/lib/BUILD +++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -650,6 +650,7 @@ "//src/main/java/com/google/devtools/build/lib:bazel-main", "//src/main/java/com/google/devtools/build/lib:bazel-repository", "//src/main/java/com/google/devtools/build/lib:bazel-rules", + "//src/main/java/com/google/devtools/build/lib:bazel/LicenseCheckingModule", "//src/main/java/com/google/devtools/build/lib:build-base", "//src/main/java/com/google/devtools/build/lib:build-request-options", "//src/main/java/com/google/devtools/build/lib:core-rules", @@ -859,6 +860,7 @@ ":testutil", "//src/main/java/com/google/devtools/build/lib:bazel-main", "//src/main/java/com/google/devtools/build/lib:bazel-rules", + "//src/main/java/com/google/devtools/build/lib:bazel/LicenseCheckingModule", "//src/main/java/com/google/devtools/build/lib:build-base", "//src/main/java/com/google/devtools/build/lib:events", "//src/main/java/com/google/devtools/build/lib:packages",
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/LicensingTests.java b/src/test/java/com/google/devtools/build/lib/analysis/LicensingTests.java index 7bcb052..b70021a 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/LicensingTests.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/LicensingTests.java
@@ -26,6 +26,7 @@ import com.google.devtools.build.lib.analysis.LicensesProvider.TargetLicense; import com.google.devtools.build.lib.analysis.util.AnalysisMock; import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; +import com.google.devtools.build.lib.bazel.LicenseCheckingModule; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.packages.License; @@ -552,8 +553,13 @@ Maps.filterKeys(getTransitiveLicenses(used), AnalysisMock.get().ccSupport().labelFilter()); Label usedLabel = Label.parseAbsolute("//used", ImmutableMap.of()); License license = usedActual.get(usedLabel); - license.checkCompatibility(EnumSet.of(DistributionType.CLIENT), - getTarget("//user"), usedLabel, reporter, false); + LicenseCheckingModule.checkCompatibility( + license, + EnumSet.of(DistributionType.CLIENT), + getTarget("//user"), + usedLabel, + reporter, + false); assertNoEvents(); } @@ -576,8 +582,13 @@ Maps.filterKeys(getTransitiveLicenses(used), AnalysisMock.get().ccSupport().labelFilter()); Label usedLabel = Label.parseAbsolute("//used", ImmutableMap.of()); License license = usedActual.get(usedLabel); - license.checkCompatibility(EnumSet.of(DistributionType.CLIENT), - getTarget("//user"), usedLabel, reporter, false); + LicenseCheckingModule.checkCompatibility( + license, + EnumSet.of(DistributionType.CLIENT), + getTarget("//user"), + usedLabel, + reporter, + false); assertNoEvents(); }