@@ -3,7 +3,7 @@ package dotty.tools
33
44import scala .annotation .tailrec
55import scala .io .Source
6- import scala .util .Try
6+ import scala .util .{ Try , Success , Failure }
77import java .net .URLClassLoader
88import sys .process ._
99import java .io .File
@@ -15,12 +15,14 @@ import dotty.tools.dotc.config.Properties.envOrNone
1515import java .util .jar ._
1616import java .util .jar .Attributes .Name
1717import dotty .tools .io .Jar
18+ import dotty .tools .runner .ScalaClassLoader
1819
1920enum ExecuteMode :
2021 case Guess
2122 case Script
2223 case Repl
2324 case Run
25+ case PossibleRun
2426
2527case class Settings (
2628 verbose : Boolean = false ,
@@ -30,14 +32,17 @@ case class Settings(
3032 javaArgs : List [String ] = List .empty,
3133 scalaArgs : List [String ] = List .empty,
3234 residualArgs : List [String ] = List .empty,
35+ possibleEntryPaths : List [String ] = List .empty,
3336 scriptArgs : List [String ] = List .empty,
3437 targetScript : String = " " ,
38+ targetToRun : String = " " ,
3539 save : Boolean = false ,
40+ modeShouldBePossibleRun : Boolean = false ,
3641 modeShouldBeRun : Boolean = false ,
3742 compiler : Boolean = false ,
3843) {
3944 def withExecuteMode (em : ExecuteMode ): Settings = this .executeMode match
40- case ExecuteMode .Guess =>
45+ case ExecuteMode .Guess | ExecuteMode . PossibleRun =>
4146 this .copy(executeMode = em)
4247 case _ =>
4348 println(s " execute_mode==[ $executeMode], attempted overwrite by [ $em] " )
@@ -53,6 +58,9 @@ case class Settings(
5358 def withResidualArgs (args : String * ): Settings =
5459 this .copy(residualArgs = residualArgs.appendedAll(args.toList))
5560
61+ def withPossibleEntryPaths (args : String * ): Settings =
62+ this .copy(possibleEntryPaths = possibleEntryPaths.appendedAll(args.toList))
63+
5664 def withScriptArgs (args : String * ): Settings =
5765 this .copy(scriptArgs = scriptArgs.appendedAll(args.toList))
5866
@@ -64,9 +72,15 @@ case class Settings(
6472 this .copy(exitCode = 2 )
6573 end withTargetScript
6674
75+ def withTargetToRun (targetToRun : String ): Settings =
76+ this .copy(targetToRun = targetToRun)
77+
6778 def withSave : Settings =
6879 this .copy(save = true )
6980
81+ def withModeShouldBePossibleRun : Settings =
82+ this .copy(modeShouldBePossibleRun = true )
83+
7084 def withModeShouldBeRun : Settings =
7185 this .copy(modeShouldBeRun = true )
7286
@@ -85,8 +99,8 @@ object MainGenericRunner {
8599 def process (args : List [String ], settings : Settings ): Settings = args match
86100 case Nil =>
87101 settings
88- case " -run" :: tail =>
89- process(tail, settings.withExecuteMode(ExecuteMode .Run ))
102+ case " -run" :: fqName :: tail =>
103+ process(tail, settings.withExecuteMode(ExecuteMode .Run ).withTargetToRun(fqName) )
90104 case (" -cp" | " -classpath" | " --class-path" ) :: cp :: tail =>
91105 process(tail, settings.copy(classPath = settings.classPath.appended(cp)))
92106 case (" -version" | " --version" ) :: _ =>
@@ -120,7 +134,7 @@ object MainGenericRunner {
120134 .withTargetScript(arg)
121135 .withScriptArgs(tail* )
122136 else
123- val newSettings = if arg.startsWith(" -" ) then settings else settings.withModeShouldBeRun
137+ val newSettings = if arg.startsWith(" -" ) then settings else settings.withPossibleEntryPaths(arg).withModeShouldBePossibleRun
124138 process(tail, newSettings.withResidualArgs(arg))
125139
126140 def main (args : Array [String ]): Unit =
@@ -129,12 +143,27 @@ object MainGenericRunner {
129143 val settings = process(allArgs.toList, Settings ())
130144 if settings.exitCode != 0 then System .exit(settings.exitCode)
131145
132- def run (mode : ExecuteMode ): Unit = mode match
146+ def run (settings : Settings ): Unit = settings.executeMode match
133147 case ExecuteMode .Repl =>
134148 val properArgs =
135149 List (" -classpath" , settings.classPath.mkString(classpathSeparator)).filter(Function .const(settings.classPath.nonEmpty))
136150 ++ settings.residualArgs
137151 repl.Main .main(properArgs.toArray)
152+
153+ case ExecuteMode .PossibleRun =>
154+ val newClasspath = (settings.classPath :+ " ." ).map(File (_).toURI.toURL)
155+ import dotty .tools .runner .RichClassLoader ._
156+ val newClassLoader = ScalaClassLoader .fromURLsParallelCapable(newClasspath)
157+ val targetToRun = settings.possibleEntryPaths.to(LazyList ).find { entryPath =>
158+ newClassLoader.tryToLoadClass(entryPath).orElse {
159+ Option .when(Jar .isJarOrZip(dotty.tools.io.Path (entryPath)))(Jar (entryPath).mainClass).flatten
160+ }.isDefined
161+ }
162+ targetToRun match
163+ case Some (fqName) =>
164+ run(settings.withTargetToRun(fqName).withResidualArgs(settings.residualArgs.filter { _ != fqName }* ).withExecuteMode(ExecuteMode .Run ))
165+ case None =>
166+ run(settings.withExecuteMode(ExecuteMode .Repl ))
138167 case ExecuteMode .Run =>
139168 val scalaClasspath = ClasspathFromClassloader (Thread .currentThread().getContextClassLoader).split(classpathSeparator)
140169
@@ -146,9 +175,9 @@ object MainGenericRunner {
146175 cp
147176 val newClasspath = (settings.classPath ++ removeCompiler(scalaClasspath) :+ " ." ).map(File (_).toURI.toURL)
148177
149- val res = ObjectRunner .runAndCatch(newClasspath, settings.residualArgs.head , settings.residualArgs.drop( 1 ) ).flatMap {
150- case ex : ClassNotFoundException if ex.getMessage == settings.residualArgs.head =>
151- val file = settings.residualArgs.head
178+ val res = ObjectRunner .runAndCatch(newClasspath, settings.targetToRun , settings.residualArgs).flatMap {
179+ case ex : ClassNotFoundException if ex.getMessage == settings.targetToRun =>
180+ val file = settings.targetToRun
152181 Jar (file).mainClass match
153182 case Some (mc) =>
154183 ObjectRunner .runAndCatch(newClasspath :+ File (file).toURI.toURL, mc, settings.residualArgs)
@@ -167,12 +196,14 @@ object MainGenericRunner {
167196 ++ settings.scriptArgs
168197 scripting.Main .main(properArgs.toArray)
169198 case ExecuteMode .Guess =>
170- if settings.modeShouldBeRun then
171- run(ExecuteMode .Run )
199+ if settings.modeShouldBePossibleRun then
200+ run(settings.withExecuteMode(ExecuteMode .PossibleRun ))
201+ else if settings.modeShouldBeRun then
202+ run(settings.withExecuteMode(ExecuteMode .Run ))
172203 else
173- run(ExecuteMode .Repl )
204+ run(settings.withExecuteMode( ExecuteMode .Repl ) )
174205
175- run(settings.executeMode )
206+ run(settings)
176207
177208
178209 def errorFn (str : String , e : Option [Throwable ] = None , isFailure : Boolean = true ): Boolean = {
0 commit comments