-
Notifications
You must be signed in to change notification settings - Fork 128
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use external binary to extract class name from stdin Java sources
- Loading branch information
1 parent
5ab04a5
commit bfc96d6
Showing
17 changed files
with
269 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
modules/build/src/main/java/scala/build/internal/JavaParserProxyMakerSubst.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<String> javaClassNameVersionOpt, | ||
scala.build.Logger logger | ||
) { | ||
return new JavaParserProxyBinary(archiveCache, logger, javaClassNameVersionOpt); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
modules/build/src/main/scala/scala/build/internal/JavaParserProxy.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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]] | ||
} |
57 changes: 57 additions & 0 deletions
57
modules/build/src/main/scala/scala/build/internal/JavaParserProxyBinary.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
modules/build/src/main/scala/scala/build/internal/JavaParserProxyJvm.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) | ||
} |
24 changes: 24 additions & 0 deletions
24
modules/build/src/main/scala/scala/build/internal/JavaParserProxyMaker.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.