@@ -3,7 +3,7 @@ package dotty.tools
3
3
4
4
import scala .annotation .tailrec
5
5
import scala .io .Source
6
- import scala .util .Try
6
+ import scala .util .{ Try , Success , Failure }
7
7
import java .net .URLClassLoader
8
8
import sys .process ._
9
9
import java .io .File
@@ -15,12 +15,14 @@ import dotty.tools.dotc.config.Properties.envOrNone
15
15
import java .util .jar ._
16
16
import java .util .jar .Attributes .Name
17
17
import dotty .tools .io .Jar
18
+ import dotty .tools .runner .ScalaClassLoader
18
19
19
20
enum ExecuteMode :
20
21
case Guess
21
22
case Script
22
23
case Repl
23
24
case Run
25
+ case PossibleRun
24
26
25
27
case class Settings (
26
28
verbose : Boolean = false ,
@@ -30,14 +32,17 @@ case class Settings(
30
32
javaArgs : List [String ] = List .empty,
31
33
scalaArgs : List [String ] = List .empty,
32
34
residualArgs : List [String ] = List .empty,
35
+ possibleEntryPaths : List [String ] = List .empty,
33
36
scriptArgs : List [String ] = List .empty,
34
37
targetScript : String = " " ,
38
+ targetToRun : String = " " ,
35
39
save : Boolean = false ,
40
+ modeShouldBePossibleRun : Boolean = false ,
36
41
modeShouldBeRun : Boolean = false ,
37
42
compiler : Boolean = false ,
38
43
) {
39
44
def withExecuteMode (em : ExecuteMode ): Settings = this .executeMode match
40
- case ExecuteMode .Guess =>
45
+ case ExecuteMode .Guess | ExecuteMode . PossibleRun =>
41
46
this .copy(executeMode = em)
42
47
case _ =>
43
48
println(s " execute_mode==[ $executeMode], attempted overwrite by [ $em] " )
@@ -53,6 +58,9 @@ case class Settings(
53
58
def withResidualArgs (args : String * ): Settings =
54
59
this .copy(residualArgs = residualArgs.appendedAll(args.toList))
55
60
61
+ def withPossibleEntryPaths (args : String * ): Settings =
62
+ this .copy(possibleEntryPaths = possibleEntryPaths.appendedAll(args.toList))
63
+
56
64
def withScriptArgs (args : String * ): Settings =
57
65
this .copy(scriptArgs = scriptArgs.appendedAll(args.toList))
58
66
@@ -64,9 +72,15 @@ case class Settings(
64
72
this .copy(exitCode = 2 )
65
73
end withTargetScript
66
74
75
+ def withTargetToRun (targetToRun : String ): Settings =
76
+ this .copy(targetToRun = targetToRun)
77
+
67
78
def withSave : Settings =
68
79
this .copy(save = true )
69
80
81
+ def withModeShouldBePossibleRun : Settings =
82
+ this .copy(modeShouldBePossibleRun = true )
83
+
70
84
def withModeShouldBeRun : Settings =
71
85
this .copy(modeShouldBeRun = true )
72
86
@@ -85,8 +99,8 @@ object MainGenericRunner {
85
99
def process (args : List [String ], settings : Settings ): Settings = args match
86
100
case Nil =>
87
101
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) )
90
104
case (" -cp" | " -classpath" | " --class-path" ) :: cp :: tail =>
91
105
process(tail, settings.copy(classPath = settings.classPath.appended(cp)))
92
106
case (" -version" | " --version" ) :: _ =>
@@ -120,7 +134,7 @@ object MainGenericRunner {
120
134
.withTargetScript(arg)
121
135
.withScriptArgs(tail* )
122
136
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
124
138
process(tail, newSettings.withResidualArgs(arg))
125
139
126
140
def main (args : Array [String ]): Unit =
@@ -129,12 +143,27 @@ object MainGenericRunner {
129
143
val settings = process(allArgs.toList, Settings ())
130
144
if settings.exitCode != 0 then System .exit(settings.exitCode)
131
145
132
- def run (mode : ExecuteMode ): Unit = mode match
146
+ def run (settings : Settings ): Unit = settings.executeMode match
133
147
case ExecuteMode .Repl =>
134
148
val properArgs =
135
149
List (" -classpath" , settings.classPath.mkString(classpathSeparator)).filter(Function .const(settings.classPath.nonEmpty))
136
150
++ settings.residualArgs
137
151
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 ))
138
167
case ExecuteMode .Run =>
139
168
val scalaClasspath = ClasspathFromClassloader (Thread .currentThread().getContextClassLoader).split(classpathSeparator)
140
169
@@ -146,9 +175,9 @@ object MainGenericRunner {
146
175
cp
147
176
val newClasspath = (settings.classPath ++ removeCompiler(scalaClasspath) :+ " ." ).map(File (_).toURI.toURL)
148
177
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
152
181
Jar (file).mainClass match
153
182
case Some (mc) =>
154
183
ObjectRunner .runAndCatch(newClasspath :+ File (file).toURI.toURL, mc, settings.residualArgs)
@@ -167,12 +196,14 @@ object MainGenericRunner {
167
196
++ settings.scriptArgs
168
197
scripting.Main .main(properArgs.toArray)
169
198
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 ))
172
203
else
173
- run(ExecuteMode .Repl )
204
+ run(settings.withExecuteMode( ExecuteMode .Repl ) )
174
205
175
- run(settings.executeMode )
206
+ run(settings)
176
207
177
208
178
209
def errorFn (str : String , e : Option [Throwable ] = None , isFailure : Boolean = true ): Boolean = {
0 commit comments