diff --git a/compiler/src/dotty/tools/MainGenericRunner.scala b/compiler/src/dotty/tools/MainGenericRunner.scala index eac96c799310..ec8fb8f9cfd5 100644 --- a/compiler/src/dotty/tools/MainGenericRunner.scala +++ b/compiler/src/dotty/tools/MainGenericRunner.scala @@ -12,6 +12,8 @@ import scala.annotation.internal.sharable import dotty.tools.dotc.util.ClasspathFromClassloader import dotty.tools.runner.ObjectRunner import dotty.tools.dotc.config.Properties.envOrNone +import java.util.jar._ +import java.util.jar.Attributes.Name enum ExecuteMode: case Guess @@ -31,6 +33,7 @@ case class Settings( targetScript: String = "", save: Boolean = false, modeShouldBeRun: Boolean = false, + compiler: Boolean = false, ) { def withExecuteMode(em: ExecuteMode): Settings = this.executeMode match case ExecuteMode.Guess => @@ -65,6 +68,9 @@ case class Settings( def withModeShouldBeRun: Settings = this.copy(modeShouldBeRun = true) + + def withCompiler: Settings = + this.copy(compiler = true) } object MainGenericRunner { @@ -97,6 +103,8 @@ object MainGenericRunner { ) case "-save" :: tail => process(tail, settings.withSave) + case "-with-compiler" :: tail => + process(tail, settings.withCompiler) case (o @ javaOption(striped)) :: tail => process(tail, settings.withJavaArgs(striped).withScalaArgs(o)) case (o @ scalaOption(_*)) :: tail => @@ -128,8 +136,34 @@ object MainGenericRunner { repl.Main.main(properArgs.toArray) case ExecuteMode.Run => val scalaClasspath = ClasspathFromClassloader(Thread.currentThread().getContextClassLoader).split(classpathSeparator) - val newClasspath = (settings.classPath ++ scalaClasspath :+ ".").map(File(_).toURI.toURL) - errorFn("", ObjectRunner.runAndCatch(newClasspath, settings.residualArgs.head, settings.residualArgs.drop(1))) + + def removeCompiler(cp: Array[String]) = + if (!settings.compiler) then // Let's remove compiler from the classpath + val compilerLibs = Seq("scala3-compiler", "scala3-interfaces", "tasty-core", "scala-asm", "scala3-staging", "scala3-tasty-inspector") + cp.filterNot(c => compilerLibs.exists(c.contains)) + else + cp + val newClasspath = (settings.classPath ++ removeCompiler(scalaClasspath) :+ ".").map(File(_).toURI.toURL) + + val res = ObjectRunner.runAndCatch(newClasspath, settings.residualArgs.head, settings.residualArgs.drop(1)).flatMap { + case ex: ClassNotFoundException if ex.getMessage == settings.residualArgs.head => + val file = settings.residualArgs.head + def withJarInput[T](f: JarInputStream => T): T = + val in = new JarInputStream(java.io.FileInputStream(file)) + try f(in) + finally in.close() + val manifest = withJarInput(s => Option(s.getManifest)) + manifest match + case None => Some(IllegalArgumentException(s"Cannot find manifest in jar: $file")) + case Some(f) => + f.getMainAttributes.get(Name.MAIN_CLASS) match + case mainClass: String => + ObjectRunner.runAndCatch(newClasspath :+ File(file).toURI.toURL, mainClass, settings.residualArgs) + case _ => + Some(IllegalArgumentException(s"No main class defined in manifest in jar: $file")) + case ex => Some(ex) + } + errorFn("", res) case ExecuteMode.Script => val properArgs = List("-classpath", settings.classPath.mkString(classpathSeparator)).filter(Function.const(settings.classPath.nonEmpty)) diff --git a/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala b/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala index e80f187321df..5a09b9ab3a9b 100644 --- a/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala +++ b/compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala @@ -92,6 +92,12 @@ class CoursierScalaTests: assertTrue(source.getParentFile.listFiles.find(_.getName == "myfile.jar").isDefined) jar() + def runThatJar() = + val source = new File(getClass.getResource("/run/myfile.jar").getPath) + val output = CoursierScalaTests.csCmd(source.absPath) + assertEquals(output.mkString("\n"), "Hello") + runThatJar() + object CoursierScalaTests: def execCmd(command: String, options: String*): List[String] =