@@ -4,7 +4,7 @@ package vulpix
4
4
5
5
import scala .language .unsafeNulls
6
6
7
- import java .io .{ File => JFile , InputStreamReader , BufferedReader , PrintStream }
7
+ import java .io .{ File => JFile , InputStreamReader , IOException , BufferedReader , PrintStream }
8
8
import java .nio .file .Paths
9
9
import java .nio .charset .StandardCharsets
10
10
import java .util .concurrent .atomic .AtomicBoolean
@@ -48,8 +48,11 @@ trait RunnerOrchestration {
48
48
/** Destroy and respawn process after each test */
49
49
def safeMode : Boolean
50
50
51
+ /** Open JDI connection for testing the debugger */
52
+ def debugMode : Boolean = false
53
+
51
54
/** Running a `Test` class's main method from the specified `dir` */
52
- def runMain (classPath : String , toolArgs : ToolArgs )(implicit summaryReport : SummaryReporting ): Status =
55
+ def runMain (classPath : String )(implicit summaryReport : SummaryReporting ): Status =
53
56
monitor.runMain(classPath)
54
57
55
58
/** Kill all processes */
@@ -70,7 +73,7 @@ trait RunnerOrchestration {
70
73
def runMain (classPath : String )(implicit summaryReport : SummaryReporting ): Status =
71
74
withRunner(_.runMain(classPath))
72
75
73
- private class Runner (private var process : Process ) {
76
+ private class Runner (private var process : RunnerProcess ) {
74
77
private var childStdout : BufferedReader = uninitialized
75
78
private var childStdin : PrintStream = uninitialized
76
79
@@ -114,7 +117,7 @@ trait RunnerOrchestration {
114
117
}
115
118
116
119
if (childStdin eq null )
117
- childStdin = new PrintStream (process.getOutputStream, /* autoFlush = */ true )
120
+ childStdin = new PrintStream (process.getOutputStream() , /* autoFlush = */ true )
118
121
119
122
// pass file to running process
120
123
childStdin.println(classPath)
@@ -124,7 +127,7 @@ trait RunnerOrchestration {
124
127
val sb = new StringBuilder
125
128
126
129
if (childStdout eq null )
127
- childStdout = new BufferedReader (new InputStreamReader (process.getInputStream, StandardCharsets .UTF_8 ))
130
+ childStdout = new BufferedReader (new InputStreamReader (process.getInputStream() , StandardCharsets .UTF_8 ))
128
131
129
132
var childOutput : String = childStdout.readLine()
130
133
@@ -138,7 +141,7 @@ trait RunnerOrchestration {
138
141
childOutput = childStdout.readLine()
139
142
}
140
143
141
- if (process.isAlive && childOutput != null ) Success (sb.toString)
144
+ if (process.isAlive() && childOutput != null ) Success (sb.toString)
142
145
else Failure (sb.toString)
143
146
}
144
147
@@ -159,18 +162,33 @@ trait RunnerOrchestration {
159
162
}
160
163
}
161
164
165
+ // A Java process and its JDI port for debugging, if debugMode is enabled.
166
+ private class RunnerProcess (p : Process , val port : Option [Int ]):
167
+ export p .*
168
+
162
169
/** Create a process which has the classpath of the `ChildJVMMain` and the
163
170
* scala library.
164
171
*/
165
- private def createProcess : Process = {
172
+ private def createProcess : RunnerProcess = {
166
173
val url = classOf [ChildJVMMain ].getProtectionDomain.getCodeSource.getLocation
167
174
val cp = Paths .get(url.toURI).toString + JFile .pathSeparator + Properties .scalaLibrary
168
175
val javaBin = Paths .get(sys.props(" java.home" ), " bin" , " java" ).toString
169
- new ProcessBuilder (javaBin, " -Dfile.encoding=UTF-8" , " -Duser.language=en" , " -Duser.country=US" , " -Xmx1g" , " -cp" , cp, " dotty.tools.vulpix.ChildJVMMain" )
176
+ val args = Seq (" -Dfile.encoding=UTF-8" , " -Duser.language=en" , " -Duser.country=US" , " -Xmx1g" , " -cp" , cp) ++
177
+ (if debugMode then Seq (" -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,quiet=n" ) else Seq .empty)
178
+ val command = (javaBin +: args) :+ " dotty.tools.vulpix.ChildJVMMain"
179
+ val process = new ProcessBuilder (command* )
170
180
.redirectErrorStream(true )
171
181
.redirectInput(ProcessBuilder .Redirect .PIPE )
172
182
.redirectOutput(ProcessBuilder .Redirect .PIPE )
173
183
.start()
184
+
185
+ val jdiPort = Option .when(debugMode):
186
+ val reader = new BufferedReader (new InputStreamReader (process.getInputStream, StandardCharsets .UTF_8 ))
187
+ reader.readLine() match
188
+ case s " Listening for transport dt_socket at address: $port" => port.toInt
189
+ case line => throw new IOException (s " Failed getting JDI port of child JVM: got $line" )
190
+
191
+ RunnerProcess (process, jdiPort)
174
192
}
175
193
176
194
private val freeRunners = mutable.Queue .empty[Runner ]
0 commit comments