diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java index 9be9ef3c875043..f31818fd289987 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java @@ -89,6 +89,11 @@ public String getSrcsVersionDocURL() { public void validate(RuleContext ruleContext, PyCommon common) { } + @Override + public boolean prohibitHyphensInPackagePaths() { + return false; + } + @Override public void collectRunfilesForBinary( RuleContext ruleContext, Runfiles.Builder builder, PyCommon common, CcInfo ccInfo) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java index 3242e571d8b8cd..51379d0c0c4194 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyCommon.java @@ -218,7 +218,7 @@ public PyCommon( this.transitivePythonSources = initTransitivePythonSources(ruleContext); this.directPythonSources = initAndMaybeValidateDirectPythonSources( - ruleContext, /*validate=*/ validatePackageAndSources); + ruleContext, semantics, /*validate=*/ validatePackageAndSources); this.usesSharedLibraries = initUsesSharedLibraries(ruleContext); this.imports = initImports(ruleContext, semantics); this.hasPy2OnlySources = initHasPy2OnlySources(ruleContext, this.sourcesVersion); @@ -229,7 +229,7 @@ public PyCommon( validateLegacyProviderNotUsedIfDisabled(); maybeValidateLoadedFromBzl(); if (validatePackageAndSources) { - validatePackageName(ruleContext); + validatePackageName(); } } @@ -282,13 +282,15 @@ private static void collectTransitivePythonSourcesFromDeps( } private static List initAndMaybeValidateDirectPythonSources( - RuleContext ruleContext, boolean validate) { + RuleContext ruleContext, PythonSemantics semantics, boolean validate) { List sourceFiles = new ArrayList<>(); // TODO(bazel-team): Need to get the transitive deps closure, not just the sources of the rule. for (TransitiveInfoCollection src : ruleContext.getPrerequisitesIf("srcs", FileProvider.class)) { // Make sure that none of the sources contain hyphens. - if (validate && Util.containsHyphen(src.getLabel().getPackageFragment())) { + if (validate + && semantics.prohibitHyphensInPackagePaths() + && Util.containsHyphen(src.getLabel().getPackageFragment())) { ruleContext.attributeError( "srcs", src.getLabel() + ": paths to Python packages may not contain '-'"); } @@ -613,8 +615,9 @@ private void maybeValidateLoadedFromBzl() { } /** Checks that the package name of this Python rule does not contain a '-'. */ - private static void validatePackageName(RuleContext ruleContext) { - if (Util.containsHyphen(ruleContext.getLabel().getPackageFragment())) { + private void validatePackageName() { + if (semantics.prohibitHyphensInPackagePaths() + && Util.containsHyphen(ruleContext.getLabel().getPackageFragment())) { ruleContext.ruleError("paths to Python packages may not contain '-'"); } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PythonSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/python/PythonSemantics.java index 5a055ce2fdd9cf..42de9de20ad727 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/python/PythonSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/rules/python/PythonSemantics.java @@ -42,6 +42,12 @@ public interface PythonSemantics { */ void validate(RuleContext ruleContext, PyCommon common); + /** + * Returns whether we are prohibiting hyphen ('-') characters in the package paths of Python + * targets and source files. + */ + boolean prohibitHyphensInPackagePaths(); + /** * Extends for the default and data runfiles of {@code py_binary} and {@code py_test} rules with * custom elements. @@ -61,14 +67,10 @@ void collectDefaultRunfilesForBinary( /** Collects a rule's default runfiles. */ void collectDefaultRunfiles(RuleContext ruleContext, Runfiles.Builder builder); - /** - * Returns the coverage instrumentation specification to be used in Python rules. - */ + /** Returns the coverage instrumentation specification to be used in Python rules. */ InstrumentationSpec getCoverageInstrumentationSpec(); - /** - * Utility function to compile multiple .py files to .pyc files, if required. - */ + /** Utility function to compile multiple .py files to .pyc files, if required. */ Collection precompiledPythonFiles( RuleContext ruleContext, Collection sources, PyCommon common); diff --git a/src/test/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryConfiguredTargetTest.java b/src/test/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryConfiguredTargetTest.java index b0fb195c1726e4..ea191eb86eb055 100644 --- a/src/test/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryConfiguredTargetTest.java +++ b/src/test/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyBinaryConfiguredTargetTest.java @@ -436,33 +436,29 @@ public void explicitInitPy_CanBeSelectivelyEnabled() throws Exception { } @Test - public void packageNameCannotHaveHyphen() throws Exception { - checkError( - "pkg-hyphenated", - "foo", - // error: - "paths to Python packages may not contain '-'", - // build file: + public void packageNameCanHaveHyphen() throws Exception { + scratch.file( + "pkg-hyphenated/BUILD", // "py_binary(", " name = 'foo',", " srcs = ['foo.py'],", ")"); + assertThat(getConfiguredTarget("//pkg-hyphenated:foo")).isNotNull(); + assertNoEvents(); } @Test - public void srcsPackageNameCannotHaveHyphen() throws Exception { + public void srcsPackageNameCanHaveHyphen() throws Exception { scratch.file( "pkg-hyphenated/BUILD", // "exports_files(['bar.py'])"); - checkError( - "otherpkg", - "foo", - // error: - "paths to Python packages may not contain '-'", - // build file: + scratch.file( + "otherpkg/BUILD", // "py_binary(", " name = 'foo',", " srcs = ['foo.py', '//pkg-hyphenated:bar.py'],", ")"); + assertThat(getConfiguredTarget("//otherpkg:foo")).isNotNull(); + assertNoEvents(); } }