diff --git a/modules/build/src/main/scala/scala/build/CrossSources.scala b/modules/build/src/main/scala/scala/build/CrossSources.scala index 05d5afa9c0..bccdfe6e11 100644 --- a/modules/build/src/main/scala/scala/build/CrossSources.scala +++ b/modules/build/src/main/scala/scala/build/CrossSources.scala @@ -10,12 +10,13 @@ import scala.build.errors.{ BuildException, CompositeBuildException, ExcludeDefinitionError, - MalformedDirectiveError + MalformedDirectiveError, + Severity } import scala.build.input.ElementsUtils.* import scala.build.input.* import scala.build.internal.Constants -import scala.build.internal.util.RegexUtils +import scala.build.internal.util.{RegexUtils, WarningMessages} import scala.build.options.{ BuildOptions, BuildRequirements, @@ -214,6 +215,9 @@ object CrossSources { value(preprocessSources(inputsElemFromDirectives.pipe(elements => value(excludeSources(elements, inputs.workspace, allExclude)) ))) + + warnAboutChainedUsingFileDirectives(preprocessedSourcesFromDirectives, logger) + val allInputs = inputs.add(inputsElemFromDirectives).pipe(inputs => val filteredElements = value(excludeSources(inputs.elements, inputs.workspace, allExclude)) inputs.withElements(elements = filteredElements) @@ -462,4 +466,21 @@ object CrossSources { )) } } + + /** When a source file added by a `using file` directive, itself, contains `using file` directives + * there should be a warning printed that transitive `using file` directives are not supported. + */ + def warnAboutChainedUsingFileDirectives( + sourcesAddedWithDirectives: Seq[PreprocessedSource], + logger: Logger + ): Unit = for { + additionalSource <- sourcesAddedWithDirectives + buildOptions <- additionalSource.options + transitiveAdditionalSource <- buildOptions.internal.extraSourceFiles + } do + logger.diagnostic( + WarningMessages.chainingUsingFileDirective, + Severity.Warning, + transitiveAdditionalSource.positions + ) } diff --git a/modules/build/src/main/scala/scala/build/internal/util/WarningMessages.scala b/modules/build/src/main/scala/scala/build/internal/util/WarningMessages.scala index 49d46916fa..12ce43ebc8 100644 --- a/modules/build/src/main/scala/scala/build/internal/util/WarningMessages.scala +++ b/modules/build/src/main/scala/scala/build/internal/util/WarningMessages.scala @@ -95,4 +95,7 @@ object WarningMessages { "directive", handler.scalaSpecificationLevel ) + + val chainingUsingFileDirective: String = + "Chaining the 'using file' directive is not supported, the source won't be included in the build." } diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Sources.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Sources.scala index f3d19f69d0..c382910c5f 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Sources.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Sources.scala @@ -18,7 +18,9 @@ import scala.util.Try |`//> using files` _path1_ _path2_ … |""".stripMargin ) -@DirectiveDescription("Manually add sources to the project") +@DirectiveDescription( + "Manually add sources to the project. Does not support chaining, sources are added only once, not recursively." +) @DirectiveLevel(SpecificationLevel.SHOULD) // format: off final case class Sources( diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala index 29da426132..84d9717b69 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunTestDefinitions.scala @@ -1663,7 +1663,7 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String]) } // Credentials tests - test("Repository credentials passed to coursier") { + test("repository credentials passed to coursier") { val testOrg = "test-org" val testName = "the-messages" val testVersion = "0.1.2" @@ -1818,4 +1818,67 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String]) } } } + + test("warn about transitive `using file` directive") { + TestInputs( + os.rel / "Main.scala" -> + """//> using file "bar/Bar.scala" + |//> using file "abc/Abc.scala" + |object Main extends App { + | println(Bar(42)) + |} + |""".stripMargin, + os.rel / "bar" / "Bar.scala" -> + """//> using file "xyz/Xyz.scala" + |//> using file "xyz/NonExistent.scala" + |case class Bar(x: Int) + |""".stripMargin, + os.rel / "abc" / "Abc.scala" -> + """//> using file "xyz/Xyz.scala" + |//> using file "xyz/NonExistent.scala" + |case class Abc(x: Int) + |""".stripMargin, + os.rel / "xyz" / "Xyz.scala" -> + """val xyz = 42 + |""".stripMargin + ).fromRoot { root => + val res = os.proc( + TestUtil.cli, + "compile", + "Main.scala", + "--suppress-directives-in-multiple-files-warning" + ) + .call(cwd = root, mergeErrIntoOut = true) + + val output = TestUtil.removeAnsiColors(res.out.trim()) + + expect(output.contains( + """[warn] Chaining the 'using file' directive is not supported, the source won't be included in the build. + |[warn] //> using file "xyz/Xyz.scala" + |[warn] ^^^^^^^^^^^^^ + |""".stripMargin + )) + + expect(output.contains( + """[warn] Chaining the 'using file' directive is not supported, the source won't be included in the build. + |[warn] //> using file "xyz/NonExistent.scala" + |[warn] ^^^^^^^^^^^^^^^^^^^^^ + |""".stripMargin + )) + + expect(output.contains( + """[warn] Chaining the 'using file' directive is not supported, the source won't be included in the build. + |[warn] //> using file "xyz/Xyz.scala" + |[warn] ^^^^^^^^^^^^^ + |""".stripMargin + )) + + expect(output.contains( + """[warn] Chaining the 'using file' directive is not supported, the source won't be included in the build. + |[warn] //> using file "xyz/NonExistent.scala" + |[warn] ^^^^^^^^^^^^^^^^^^^^^ + |""".stripMargin + )) + } + } } diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index 330b7d8be4..fb87de1706 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -73,7 +73,7 @@ Manually add JAR(s) to the class path ### Custom sources -Manually add sources to the project +Manually add sources to the project. Does not support chaining, sources are added only once, not recursively. `//> using file` _path_ diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index 1bd0cc1c50..f31934b9f9 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -123,7 +123,7 @@ Manually add JAR(s) to the class path ### Custom sources -Manually add sources to the project +Manually add sources to the project. Does not support chaining, sources are added only once, not recursively. `//> using file` _path_