diff --git a/build.sc b/build.sc index ace43aff00..6fc71d8b36 100644 --- a/build.sc +++ b/build.sc @@ -71,7 +71,6 @@ object `cli-options` extends CliOptions object `build-macros` extends Cross[BuildMacros](Scala.mainVersions: _*) object options extends Cross[Options](Scala.mainVersions: _*) object scalaparse extends ScalaParse -object javaparse extends JavaParse object directives extends Cross[Directives](Scala.mainVersions: _*) object core extends Cross[Core](Scala.mainVersions: _*) object `build-module` extends Cross[Build](Scala.mainVersions: _*) @@ -400,6 +399,7 @@ class Core(val crossScalaVersion: String) extends BuildLikeModule { | def defaultGraalVMVersion = "${deps.graalVmVersion}" | | def scalaCliSigningVersion = "${Deps.signingCli.dep.version}" + | def javaClassNameVersion = "${Deps.javaClassName.dep.version}" | | def libsodiumVersion = "${deps.libsodiumVersion}" | def libsodiumjniVersion = "${Deps.libsodiumjni.dep.version}" @@ -498,34 +498,6 @@ trait ScalaParse extends SbtModule with ScalaCliPublishModule with ScalaCliCompi def scalaVersion = Scala.scala213 } -trait JavaParse extends SbtModule with ScalaCliPublishModule with ScalaCliCompile { - def ivyDeps = super.ivyDeps() ++ Agg(Deps.scala3Compiler(scalaVersion())) - - // pin scala3-library suffix, so that 2.13 modules can have us as moduleDep fine - def mandatoryIvyDeps = T { - super.mandatoryIvyDeps().map { dep => - val isScala3Lib = - dep.dep.module.organization.value == "org.scala-lang" && - dep.dep.module.name.value == "scala3-library" && - (dep.cross match { - case _: CrossVersion.Binary => true - case _ => false - }) - if (isScala3Lib) - dep.copy( - dep = dep.dep.withModule( - dep.dep.module.withName( - coursier.ModuleName(dep.dep.module.name.value + "_3") - ) - ), - cross = CrossVersion.empty(dep.cross.platformed) - ) - else dep - } - } - def scalaVersion = Scala.scala3 -} - trait Scala3Runtime extends SbtModule with ScalaCliPublishModule with ScalaCliCompile { def ivyDeps = super.ivyDeps() def scalaVersion = Scala.scala3 @@ -561,7 +533,6 @@ class Build(val crossScalaVersion: String) extends BuildLikeModule { def moduleDeps = Seq( options(), scalaparse, - javaparse, directives(), `scala-cli-bsp`, `test-runner`(), @@ -578,6 +549,7 @@ class Build(val crossScalaVersion: String) extends BuildLikeModule { def ivyDeps = super.ivyDeps() ++ Agg( Deps.asm, Deps.collectionCompat, + Deps.javaClassName, Deps.jsoniterCore, Deps.nativeTestRunner, Deps.osLib, diff --git a/modules/build/src/main/java/scala/build/internal/JavaParserProxyMakerSubst.java b/modules/build/src/main/java/scala/build/internal/JavaParserProxyMakerSubst.java new file mode 100644 index 0000000000..1f58923a84 --- /dev/null +++ b/modules/build/src/main/java/scala/build/internal/JavaParserProxyMakerSubst.java @@ -0,0 +1,22 @@ +package scala.build.internal; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; + +/** + * This makes [[JavaParserProxyMaker.get]] provide a [[JavaParserProxyBinary]] + * rather than a [[JavaParserProxyJvm]], from native launchers. + * + * See [[JavaParserProxyMaker]] for more details. + */ +@TargetClass(className = "scala.build.internal.JavaParserProxyMaker") +public final class JavaParserProxyMakerSubst { + @Substitute + public JavaParserProxy get( + Object archiveCache, + scala.Option javaClassNameVersionOpt, + scala.build.Logger logger + ) { + return new JavaParserProxyBinary(archiveCache, logger, javaClassNameVersionOpt); + } +} diff --git a/modules/build/src/main/scala/scala/build/Build.scala b/modules/build/src/main/scala/scala/build/Build.scala index 872fb0c390..cb2702a0b0 100644 --- a/modules/build/src/main/scala/scala/build/Build.scala +++ b/modules/build/src/main/scala/scala/build/Build.scala @@ -152,7 +152,9 @@ object Build { CrossSources.forInputs( inputs, Sources.defaultPreprocessors( - options.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper) + options.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper), + options.archiveCache, + options.internal.javaClassNameVersionOpt ), logger ) diff --git a/modules/build/src/main/scala/scala/build/Sources.scala b/modules/build/src/main/scala/scala/build/Sources.scala index 527e4354c3..11e3b10f8a 100644 --- a/modules/build/src/main/scala/scala/build/Sources.scala +++ b/modules/build/src/main/scala/scala/build/Sources.scala @@ -1,5 +1,8 @@ package scala.build +import coursier.cache.ArchiveCache +import coursier.util.Task + import scala.build.internal.CodeWrapper import scala.build.options.{BuildOptions, Scope} import scala.build.preprocessing.* @@ -69,10 +72,26 @@ object Sources { topWrapperLen: Int ) - def defaultPreprocessors(codeWrapper: CodeWrapper): Seq[Preprocessor] = + /** The default preprocessor list. + * + * @param codeWrapper + * used by the Scala script preprocessor to "wrap" user code + * @param archiveCache + * used from native launchers by the Java preprocessor, to download a java-class-name binary, + * used to infer the class name of unnamed Java sources (like stdin) + * @param javaClassNameVersionOpt + * if using a java-class-name binary, the version we should download. If empty, the default + * version is downloaded. + * @return + */ + def defaultPreprocessors( + codeWrapper: CodeWrapper, + archiveCache: ArchiveCache[Task], + javaClassNameVersionOpt: Option[String] + ): Seq[Preprocessor] = Seq( ScriptPreprocessor(codeWrapper), - JavaPreprocessor, + JavaPreprocessor(archiveCache, javaClassNameVersionOpt), ScalaPreprocessor, DataPreprocessor ) diff --git a/modules/build/src/main/scala/scala/build/bsp/BspImpl.scala b/modules/build/src/main/scala/scala/build/bsp/BspImpl.scala index a2a12ea167..67d37b0628 100644 --- a/modules/build/src/main/scala/scala/build/bsp/BspImpl.scala +++ b/modules/build/src/main/scala/scala/build/bsp/BspImpl.scala @@ -61,7 +61,9 @@ final class BspImpl( CrossSources.forInputs( inputs, Sources.defaultPreprocessors( - buildOptions.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper) + buildOptions.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper), + buildOptions.archiveCache, + buildOptions.internal.javaClassNameVersionOpt ), persistentLogger ).left.map((_, Scope.Main)) diff --git a/modules/build/src/main/scala/scala/build/internal/JavaParserProxy.scala b/modules/build/src/main/scala/scala/build/internal/JavaParserProxy.scala new file mode 100644 index 0000000000..3873ea0fc2 --- /dev/null +++ b/modules/build/src/main/scala/scala/build/internal/JavaParserProxy.scala @@ -0,0 +1,22 @@ +package scala.build.internal + +import scala.build.errors.BuildException + +/** Helper to get class names from Java sources + * + * See [[JavaParserProxyJvm]] for the implementation that runs things in memory using + * java-class-name from the class path, and [[JavaParserProxyBinary]] for the implementation that + * downloads and runs a java-class-name binary. + */ +trait JavaParserProxy { + + /** Extracts the class name of a Java source, using the dotty Java parser. + * + * @param content + * the Java source to extract a class name from + * @return + * either some class name (if one was found) or none (if none was found), or a + * [[BuildException]] + */ + def className(content: Array[Byte]): Either[BuildException, Option[String]] +} diff --git a/modules/build/src/main/scala/scala/build/internal/JavaParserProxyBinary.scala b/modules/build/src/main/scala/scala/build/internal/JavaParserProxyBinary.scala new file mode 100644 index 0000000000..7ae06947c6 --- /dev/null +++ b/modules/build/src/main/scala/scala/build/internal/JavaParserProxyBinary.scala @@ -0,0 +1,57 @@ +package scala.build.internal + +import coursier.cache.ArchiveCache +import coursier.util.Task + +import scala.build.EitherCps.{either, value} +import scala.build.Logger +import scala.build.errors.BuildException +import scala.util.Properties + +/** Downloads and runs java-class-name as an external binary. */ +class JavaParserProxyBinary( + archiveCache: ArchiveCache[Task], + javaClassNameVersionOpt: Option[String], + logger: Logger +) extends JavaParserProxy { + + /** For internal use only + * + * Passing archiveCache as an Object, to work around issues with higher-kind type params from + * Java code. + */ + def this( + archiveCache: Object, + logger: Logger, + javaClassNameVersionOpt: Option[String] + ) = + this(archiveCache.asInstanceOf[ArchiveCache[Task]], javaClassNameVersionOpt, logger) + + def className(content: Array[Byte]): Either[BuildException, Option[String]] = either { + + val platformSuffix = FetchExternalBinary.platformSuffix() + val version = javaClassNameVersionOpt.getOrElse(Constants.javaClassNameVersion) + val (tag, changing) = + if (version == "latest") ("nightly", true) + else ("v" + version, false) + val ext = if (Properties.isWin) ".zip" else ".gz" + val url = + s"https://github.com/scala-cli/java-class-name/releases/download/$tag/java-class-name-$platformSuffix$ext" + + val binary = + value(FetchExternalBinary.fetch(url, changing, archiveCache, logger, "java-class-name")) + + val source = + os.temp(content, suffix = ".java", perms = if (Properties.isWin) null else "rw-------") + val output = + try { + logger.debug(s"Running $binary $source") + val res = os.proc(binary, source).call() + res.out.text().trim + } + finally os.remove(source) + + if (output.isEmpty) None + else Some(output) + } +} diff --git a/modules/build/src/main/scala/scala/build/internal/JavaParserProxyJvm.scala b/modules/build/src/main/scala/scala/build/internal/JavaParserProxyJvm.scala new file mode 100644 index 0000000000..daa30bd709 --- /dev/null +++ b/modules/build/src/main/scala/scala/build/internal/JavaParserProxyJvm.scala @@ -0,0 +1,14 @@ +package scala.build.internal + +import scala.build.errors.BuildException +import scala.cli.javaclassname.JavaParser + +/** A [[JavaParserProxy]] that relies on java-class-name in the class path, rather than downloading + * it and running it as an external binary. + * + * Should be used from Scala CLI when it's run on the JVM. + */ +class JavaParserProxyJvm extends JavaParserProxy { + override def className(content: Array[Byte]): Either[BuildException, Option[String]] = + Right(JavaParser.parseRootPublicClassName(content)) +} diff --git a/modules/build/src/main/scala/scala/build/internal/JavaParserProxyMaker.scala b/modules/build/src/main/scala/scala/build/internal/JavaParserProxyMaker.scala new file mode 100644 index 0000000000..8db6563aa9 --- /dev/null +++ b/modules/build/src/main/scala/scala/build/internal/JavaParserProxyMaker.scala @@ -0,0 +1,24 @@ +package scala.build.internal + +import scala.build.Logger + +/** On the JVM, provides [[JavaParserProxyJvm]] as [[JavaParserProxy]] instance. + * + * From native launchers, [[JavaParserProxyMakerSubst]] takes over this, and gives + * [[JavaParserProxyBinary]] instead. + * + * That way, no reference to [[JavaParserProxyJvm]] remains in the native call graph, and that + * class and those it pulls (the java-class-name classes, which includes parts of the dotty parser) + * are not embedded the native launcher. + * + * Note that this is a class and not an object, to make it easier to write substitutions for that + * in Java. + */ +class JavaParserProxyMaker { + def get( + archiveCache: Object, // Actually a ArchiveCache[Task], but having issues with the higher-kind type param from Java… + javaClassNameVersionOpt: Option[String], + logger: Logger + ): JavaParserProxy = + new JavaParserProxyJvm +} diff --git a/modules/build/src/main/scala/scala/build/preprocessing/JavaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/JavaPreprocessor.scala index 5020eb5b36..3ed048e448 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/JavaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/JavaPreprocessor.scala @@ -1,18 +1,35 @@ package scala.build.preprocessing import com.virtuslab.using_directives.custom.model.UsingDirectiveKind +import coursier.cache.ArchiveCache +import coursier.util.Task import java.nio.charset.StandardCharsets import scala.build.EitherCps.{either, value} import scala.build.errors.BuildException -import scala.build.internal.JavaParser +import scala.build.internal.JavaParserProxyMaker import scala.build.options.BuildRequirements import scala.build.preprocessing.ExtractedDirectives.from import scala.build.preprocessing.ScalaPreprocessor._ import scala.build.{Inputs, Logger} -case object JavaPreprocessor extends Preprocessor { +/** Java source preprocessor. + * + * Doesn't modify Java sources. This only extracts using directives from them, and for unnamed + * sources (like stdin), tries to infer a class name from the sources themselves. + * + * @param archiveCache + * when using a java-class-name external binary to infer a class name (see [[JavaParserProxy]]), + * a cache to download that binary with + * @param javaClassNameVersionOpt + * when using a java-class-name external binary to infer a class name (see [[JavaParserProxy]]), + * this forces the java-class-name version to download + */ +final case class JavaPreprocessor( + archiveCache: ArchiveCache[Task], + javaClassNameVersionOpt: Option[String] +) extends Preprocessor { def preprocess( input: Inputs.SingleElement, logger: Logger @@ -45,27 +62,39 @@ case object JavaPreprocessor extends Preprocessor { )) }) case v: Inputs.VirtualJavaFile => - val relPath = - if (v.isStdin) { - val fileName = JavaParser.parseRootPublicClassName(v.content).map( - _ + ".java" - ).getOrElse("stdin.java") - os.sub / fileName - } - else v.subPath - val content = new String(v.content, StandardCharsets.UTF_8) - val s = PreprocessedSource.InMemory( - originalPath = Left(v.source), - relPath = relPath, - code = content, - ignoreLen = 0, - options = None, - requirements = None, - scopedRequirements = Nil, - mainClassOpt = None, - scopePath = v.scopePath - ) - Some(Right(Seq(s))) + val res = either { + val relPath = + if (v.isStdin) { + val classNameOpt = value { + (new JavaParserProxyMaker) + .get( + archiveCache, + javaClassNameVersionOpt, + logger + ) + .className(v.content) + } + val fileName = classNameOpt + .map(_ + ".java") + .getOrElse("stdin.java") + os.sub / fileName + } + else v.subPath + val content = new String(v.content, StandardCharsets.UTF_8) + val s = PreprocessedSource.InMemory( + originalPath = Left(v.source), + relPath = relPath, + code = content, + ignoreLen = 0, + options = None, + requirements = None, + scopedRequirements = Nil, + mainClassOpt = None, + scopePath = v.scopePath + ) + Seq(s) + } + Some(res) case _ => None } diff --git a/modules/build/src/test/scala/scala/build/tests/SourcesTests.scala b/modules/build/src/test/scala/scala/build/tests/SourcesTests.scala index 8c3454cf74..3095cfa776 100644 --- a/modules/build/src/test/scala/scala/build/tests/SourcesTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/SourcesTests.scala @@ -1,6 +1,8 @@ package scala.build.tests import com.eed3si9n.expecty.Expecty.expect +import coursier.cache.{ArchiveCache, Cache} +import coursier.util.{Artifact, Task} import dependency._ import scala.build.Ops._ @@ -18,6 +20,18 @@ class SourcesTests extends munit.FunSuite { def scalaParams = ScalaParameters(scalaVersion) def scalaBinaryVersion = scalaParams.scalaBinaryVersion + val preprocessors = Sources.defaultPreprocessors( + CustomCodeWrapper, + ArchiveCache().withCache( + new Cache[Task] { + def fetch = _ => sys.error("shouldn't be used") + def file(artifact: Artifact) = sys.error("shouldn't be used") + def ec = sys.error("shouldn't be used") + } + ), + None + ) + test("dependencies in .scala - $ivy") { val testInputs = TestInputs( os.rel / "something.scala" -> @@ -40,7 +54,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -76,7 +90,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -109,7 +123,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -140,7 +154,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -171,7 +185,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -205,7 +219,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -241,7 +255,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -269,7 +283,7 @@ class SourcesTests extends munit.FunSuite { testInputs.withInputs { (_, inputs) => val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ) expect(crossSources.isLeft) @@ -296,7 +310,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -361,7 +375,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -393,7 +407,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -428,7 +442,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -454,7 +468,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -491,7 +505,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ).orThrow val scopedSources = crossSources.scopedSources(BuildOptions()).orThrow @@ -530,7 +544,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ) crossSources match { @@ -550,7 +564,7 @@ class SourcesTests extends munit.FunSuite { val crossSources = CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + preprocessors, TestLogger() ) crossSources match { diff --git a/modules/cli/src/main/scala/scala/cli/commands/Export.scala b/modules/cli/src/main/scala/scala/cli/commands/Export.scala index 87b3f1fe6d..cada8013b0 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/Export.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/Export.scala @@ -29,7 +29,9 @@ object Export extends ScalaCommand[ExportOptions] { CrossSources.forInputs( inputs, Sources.defaultPreprocessors( - buildOptions.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper) + buildOptions.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper), + buildOptions.archiveCache, + buildOptions.internal.javaClassNameVersionOpt ), logger ) diff --git a/modules/cli/src/main/scala/scala/cli/commands/Fmt.scala b/modules/cli/src/main/scala/scala/cli/commands/Fmt.scala index 0f63bc0885..b432b65c0d 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/Fmt.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/Fmt.scala @@ -144,7 +144,9 @@ object Fmt extends ScalaCommand[FmtOptions] { CrossSources.forInputs( inputs, Sources.defaultPreprocessors( - buildOptions.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper) + buildOptions.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper), + buildOptions.archiveCache, + buildOptions.internal.javaClassNameVersionOpt ), logger ).orExit(logger) diff --git a/modules/cli/src/main/scala/scala/cli/commands/SetupIde.scala b/modules/cli/src/main/scala/scala/cli/commands/SetupIde.scala index 02bbd9a723..9dd0b48469 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/SetupIde.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/SetupIde.scala @@ -33,7 +33,11 @@ object SetupIde extends ScalaCommand[SetupIdeOptions] { val crossSources = value { CrossSources.forInputs( inputs, - Sources.defaultPreprocessors(CustomCodeWrapper), + Sources.defaultPreprocessors( + CustomCodeWrapper, + options.archiveCache, + options.internal.javaClassNameVersionOpt + ), logger ) } diff --git a/modules/javaparse/src/main/scala/scala/build/internal/JavaParser.scala b/modules/javaparse/src/main/scala/scala/build/internal/JavaParser.scala deleted file mode 100644 index 80f2c7bdae..0000000000 --- a/modules/javaparse/src/main/scala/scala/build/internal/JavaParser.scala +++ /dev/null @@ -1,39 +0,0 @@ -package scala.build.internal - -import dotty.tools.dotc.ast.{Trees, untpd} -import dotty.tools.dotc.core.Contexts.{Context, ContextBase} -import dotty.tools.dotc.parsing.JavaParsers.OutlineJavaParser -import dotty.tools.dotc.util.SourceFile -import dotty.tools.io.VirtualFile -import dotty.tools.dotc.ast.untpd.{ModuleDef, PackageDef, Tree, TypeDef} -import dotty.tools.dotc.core.Symbols.ClassSymbol -import dotty.tools.dotc.core.{SymbolLoaders, Flags} -import dotty.tools.dotc.ast.untpd.Modifiers -import scala.io.Codec - -object JavaParser { - private def parseOutline(byteContent: Array[Byte]): untpd.Tree = { - given Context = ContextBase().initialCtx.fresh - val virtualFile = VirtualFile("placeholder.java", byteContent) - val sourceFile = SourceFile(virtualFile, Codec.UTF8) - val outlineParser = OutlineJavaParser(sourceFile) - outlineParser.parse() - } - - extension(mdef: untpd.DefTree) { - def nonPackagePrivate: Boolean = mdef.mods.privateWithin.toTermName.toString != "" - def isPrivate: Boolean = mdef.mods.flags.is(Flags.Private) - def isProtected: Boolean = mdef.mods.flags.is(Flags.Protected) - } - - def parseRootPublicClassName(byteContent: Array[Byte]): Option[String] = - Option(parseOutline(byteContent)) - .flatMap { - case pd: Trees.PackageDef[_] => Some(pd.stats) - case _ => None - } - .flatMap(_.collectFirst { - case mdef: ModuleDef if mdef.nonPackagePrivate && !mdef.isPrivate && !mdef.isProtected => - mdef.name.toString - }) -} diff --git a/modules/options/src/main/scala/scala/build/options/InternalOptions.scala b/modules/options/src/main/scala/scala/build/options/InternalOptions.scala index 3a5b22cc0e..beca204528 100644 --- a/modules/options/src/main/scala/scala/build/options/InternalOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/InternalOptions.scala @@ -10,7 +10,8 @@ final case class InternalOptions( verbosity: Option[Int] = None, // FIXME Should be removed, not a real option (not meant to be set from using directives) strictBloopJsonCheck: Option[Boolean] = None, - interactive: Option[Boolean] = None + interactive: Option[Boolean] = None, + javaClassNameVersionOpt: Option[String] = None ) { def verbosityOrDefault = verbosity.getOrElse(0) def strictBloopJsonCheckOrDefault = diff --git a/project/deps.sc b/project/deps.sc index aca1ff5890..cf7413dfd2 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -81,11 +81,12 @@ object Deps { def dependency = ivy"io.get-coursier::dependency:0.2.2" def dockerClient = ivy"com.spotify:docker-client:8.16.0" // TODO bump once 0.15.5 is out - def expecty = ivy"com.eed3si9n.expecty::expecty:0.15.4+22-9c7fb771-SNAPSHOT" - def guava = ivy"com.google.guava:guava:31.1-jre" - def jgit = ivy"org.eclipse.jgit:org.eclipse.jgit:6.1.0.202203080745-r" - def jimfs = ivy"com.google.jimfs:jimfs:1.2" - def jniUtils = ivy"io.get-coursier.jniutils:windows-jni-utils:0.3.3" + def expecty = ivy"com.eed3si9n.expecty::expecty:0.15.4+22-9c7fb771-SNAPSHOT" + def guava = ivy"com.google.guava:guava:31.1-jre" + def javaClassName = ivy"io.github.alexarchambault.scala-cli:java-class-name_3:0.1.0" + def jgit = ivy"org.eclipse.jgit:org.eclipse.jgit:6.1.0.202203080745-r" + def jimfs = ivy"com.google.jimfs:jimfs:1.2" + def jniUtils = ivy"io.get-coursier.jniutils:windows-jni-utils:0.3.3" def jsoniterCore = ivy"com.github.plokhotnyuk.jsoniter-scala:jsoniter-scala-core_2.13:${Versions.jsoniterScala}" def jsoniterMacros =