diff --git a/project/Build.scala b/project/Build.scala index bbb069c072c4..4bb241148d96 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -455,13 +455,13 @@ object Build { // Creates a scalaInstance by fetching the compiler from Maven. // Used by non-bootstrapped projects that need a published compiler. - def fetchedScalaInstanceSettings(version: Def.Initialize[String]) = Def.settings( + def fetchedScalaInstanceSettings = Def.settings( // sbt adds all the projects to scala-tool config which breaks building the scalaInstance // as a workaround, we build it manually by only adding the compiler scalaInstance := { val lm = dependencyResolution.value val log = streams.value.log - val ver = version.value + val ver = scalaVersion.value val retrieveDir = streams.value.cacheDirectory / "scala3-compiler" / ver val comp = lm.retrieve("org.scala-lang" % "scala3-compiler_3" % ver, scalaModuleInfo = None, retrieveDir, log) @@ -827,7 +827,7 @@ object Build { publish / skip := false, // Project specific target folder. sbt doesn't like having two projects using the same target folder target := target.value / "scala3-sbt-bridge-nonbootstrapped", - fetchedScalaInstanceSettings(scalaVersion), + fetchedScalaInstanceSettings, ) // ============================================================================================== @@ -1184,19 +1184,9 @@ object Build { autoScalaLibrary := false, // Drop all the scala tools in this project, so we can never generate any bytecode, or documentation managedScalaInstance := false, + fetchedScalaInstanceSettings, // This Project only has a dependency to `org.scala-lang:scala-library:*.**.**-nonbootstrapped` - Compile / sources := Seq(), - Compile / resources := Seq(), - Test / sources := Seq(), - Test / resources := Seq(), - // Bridge the common task to call the ones of the actual library project - Compile / compile := (`scala-library-nonbootstrapped` / Compile / compile).value, - Compile / doc := (`scala-library-nonbootstrapped` / Compile / doc).value, - Compile / run := (`scala-library-nonbootstrapped` / Compile / run).evaluated, - Test / compile := (`scala-library-nonbootstrapped` / Test / compile).value, - Test / doc := (`scala-library-nonbootstrapped` / Test / doc).value, - Test / run := (`scala-library-nonbootstrapped` / Test / run).evaluated, - Test / test := (`scala-library-nonbootstrapped` / Test / test).value, + emptyPublishedJarSettings, // Validate JAR is empty (only META-INF) // Packaging configuration of the stdlib Compile / publishArtifact := true, Test / publishArtifact := false, @@ -1266,20 +1256,10 @@ object Build { crossPaths := true, // org.scala-lang:scala3-library has a crosspath // Do not depend on the `org.scala-lang:scala3-library` automatically, we manually depend on `scala-library-bootstrapped` autoScalaLibrary := false, - // Drop all the scala tools in this project, so we can never generate any bytecode, or documentation - managedScalaInstance := false, + // Configure to use the non-bootstrapped compiler + bootstrappedScalaInstanceSettings, // This Project only has a dependency to `org.scala-lang:scala-library:*.**.**-bootstrapped` - Compile / sources := Seq(), - Compile / resources := Seq(), - Test / sources := Seq(), - Test / resources := Seq(), - // Bridge the common task to call the ones of the actual library project - Compile / compile := (`scala-library-bootstrapped` / Compile / compile).value, - Compile / doc := (`scala-library-bootstrapped` / Compile / doc).value, - Compile / run := (`scala-library-bootstrapped` / Compile / run).evaluated, - Test / compile := (`scala-library-bootstrapped` / Test / compile).value, - Test / doc := (`scala-library-bootstrapped` / Test / doc).value, - Test / run := (`scala-library-bootstrapped` / Test / run).evaluated, + emptyPublishedJarSettings, // Validate JAR is empty (only META-INF) // Packaging configuration of the stdlib Compile / publishArtifact := true, Test / publishArtifact := false, @@ -1403,20 +1383,10 @@ object Build { crossPaths := true, // org.scala-lang:scala3-library_sjs1 has a crosspath // Do not depend on the `org.scala-lang:scala3-library` automatically, we manually depend on `scala-library-bootstrapped` autoScalaLibrary := false, - // Drop all the scala tools in this project, so we can never generate any bytecode, or documentation - managedScalaInstance := false, + // Configure to use the non-bootstrapped compiler + bootstrappedScalaInstanceSettings, // This Project only has a dependency to `org.scala-js:scalajs-scalalib:*.**.**-bootstrapped` - Compile / sources := Seq(), - Compile / resources := Seq(), - Test / sources := Seq(), - Test / resources := Seq(), - // Bridge the common task to call the ones of the actual library project - Compile / compile := (`scala-library-sjs` / Compile / compile).value, - Compile / doc := (`scala-library-sjs` / Compile / doc).value, - Compile / run := (`scala-library-sjs` / Compile / run).evaluated, - Test / compile := (`scala-library-sjs` / Test / compile).value, - Test / doc := (`scala-library-sjs` / Test / doc).value, - Test / run := (`scala-library-sjs` / Test / run).evaluated, + emptyPublishedJarSettings, // Validate JAR is empty (only META-INF) // Packaging configuration of the stdlib Compile / publishArtifact := true, Test / publishArtifact := false, @@ -1461,7 +1431,7 @@ object Build { publish / skip := false, // Project specific target folder. sbt doesn't like having two projects using the same target folder target := target.value / "tasty-core-nonbootstrapped", - fetchedScalaInstanceSettings(scalaVersion), + fetchedScalaInstanceSettings, // Add configuration of the test Test / envVars ++= Map( "EXPECTED_TASTY_VERSION" -> expectedTastyVersion, @@ -1564,13 +1534,14 @@ object Build { // sbt adds all the projects to scala-tool config which breaks building the scalaInstance // as a workaround, I build it manually by only adding the compiler managedScalaInstance := false, - fetchedScalaInstanceSettings(Def.setting(referenceVersion)), + fetchedScalaInstanceSettings, scalaCompilerBridgeBinaryJar := { val lm = dependencyResolution.value val log = streams.value.log - val retrieveDir = streams.value.cacheDirectory / "scala3-sbt-bridge" / referenceVersion + val version = scalaVersion.value + val retrieveDir = streams.value.cacheDirectory / "scala3-sbt-bridge" / version val comp = lm.retrieve("org.scala-lang" % "scala3-sbt-bridge" % - referenceVersion, scalaModuleInfo = None, retrieveDir, log) + version, scalaModuleInfo = None, retrieveDir, log) .fold(w => throw w.resolveException, identity) Some(comp(0)) }, @@ -2831,6 +2802,44 @@ object Build { assert(!tastyIsExperimental, "Stable version cannot use experimental TASTY") } } + + /** Helper to validate JAR contents */ + private def validateJarIsEmpty(jar: File): File = { + val jarFile = new java.util.jar.JarFile(jar) + try { + import scala.jdk.CollectionConverters._ + val nonMetaInfEntries = jarFile.entries().asScala + .map(_.getName) + .filterNot(name => name.startsWith("META-INF/") || name == "META-INF") + .toList + + if (nonMetaInfEntries.nonEmpty) { + val entriesList = nonMetaInfEntries.take(10).mkString("\n - ", "\n - ", "") + val truncated = if (nonMetaInfEntries.size > 10) s"\n ... and ${nonMetaInfEntries.size - 10} more" else "" + sys.error( + s"""JAR ${jar.getName} should only contain META-INF entries but found ${nonMetaInfEntries.size} other entries:$entriesList$truncated + | + |This artifact is intended to be an empty placeholder that only declares dependencies. + |If you need to add content, please verify this is intentional.""".stripMargin + ) + } + } finally jarFile.close() + jar + } + + /** Settings for projects that should produce empty JARs (only META-INF allowed). + * These are dependency placeholder projects like scala3-library-bootstrapped-new and scala3-library-sjs. + * Validates: .jar, -sources.jar, and -javadoc.jar + */ + lazy val emptyPublishedJarSettings = Def.settings( + Compile / sources := Seq(), + Compile / resources := Seq(), + Test / sources := Seq(), + Test / resources := Seq(), + Compile / packageBin := (Compile / packageBin).map(validateJarIsEmpty).value, + Compile / packageSrc := (Compile / packageSrc).map(validateJarIsEmpty).value, + Compile / packageDoc := (Compile / packageDoc).map(validateJarIsEmpty).value, + ) } object ScaladocConfigs { @@ -2952,4 +2961,5 @@ object ScaladocConfigs { .withTargets((`scala-library-bootstrapped` / Compile / products).value.map(_.getAbsolutePath)) } + }