@@ -4,7 +4,7 @@ package vulpix
44
55import scala .language .unsafeNulls
66
7- import java .io .{ File => JFile , InputStreamReader , BufferedReader , PrintStream }
7+ import java .io .{ File => JFile , InputStreamReader , IOException , BufferedReader , PrintStream }
88import java .nio .file .Paths
99import java .nio .charset .StandardCharsets
1010import java .util .concurrent .atomic .AtomicBoolean
@@ -48,8 +48,11 @@ trait RunnerOrchestration {
4848 /** Destroy and respawn process after each test */
4949 def safeMode : Boolean
5050
51+ /** Open JDI connection for testing the debugger */
52+ def debugMode : Boolean = false
53+
5154 /** 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 =
5356 monitor.runMain(classPath)
5457
5558 /** Kill all processes */
@@ -70,7 +73,7 @@ trait RunnerOrchestration {
7073 def runMain (classPath : String )(implicit summaryReport : SummaryReporting ): Status =
7174 withRunner(_.runMain(classPath))
7275
73- private class Runner (private var process : Process ) {
76+ private class Runner (private var process : RunnerProcess ) {
7477 private var childStdout : BufferedReader = uninitialized
7578 private var childStdin : PrintStream = uninitialized
7679
@@ -114,7 +117,7 @@ trait RunnerOrchestration {
114117 }
115118
116119 if (childStdin eq null )
117- childStdin = new PrintStream (process.getOutputStream, /* autoFlush = */ true )
120+ childStdin = new PrintStream (process.getOutputStream() , /* autoFlush = */ true )
118121
119122 // pass file to running process
120123 childStdin.println(classPath)
@@ -124,7 +127,7 @@ trait RunnerOrchestration {
124127 val sb = new StringBuilder
125128
126129 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 ))
128131
129132 var childOutput : String = childStdout.readLine()
130133
@@ -138,7 +141,7 @@ trait RunnerOrchestration {
138141 childOutput = childStdout.readLine()
139142 }
140143
141- if (process.isAlive && childOutput != null ) Success (sb.toString)
144+ if (process.isAlive() && childOutput != null ) Success (sb.toString)
142145 else Failure (sb.toString)
143146 }
144147
@@ -159,18 +162,33 @@ trait RunnerOrchestration {
159162 }
160163 }
161164
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+
162169 /** Create a process which has the classpath of the `ChildJVMMain` and the
163170 * scala library.
164171 */
165- private def createProcess : Process = {
172+ private def createProcess : RunnerProcess = {
166173 val url = classOf [ChildJVMMain ].getProtectionDomain.getCodeSource.getLocation
167174 val cp = Paths .get(url.toURI).toString + JFile .pathSeparator + Properties .scalaLibrary
168175 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* )
170180 .redirectErrorStream(true )
171181 .redirectInput(ProcessBuilder .Redirect .PIPE )
172182 .redirectOutput(ProcessBuilder .Redirect .PIPE )
173183 .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)
174192 }
175193
176194 private val freeRunners = mutable.Queue .empty[Runner ]
0 commit comments