Skip to content

Commit 7fa844c

Browse files
committed
Move ProcessUtil, customize builder
1 parent 1deca8f commit 7fa844c

File tree

3 files changed

+88
-107
lines changed

3 files changed

+88
-107
lines changed

buildSrc/src/main/kotlin/ProcessUtil.kt

Lines changed: 0 additions & 88 deletions
This file was deleted.

jacodb-ets/build.gradle.kts

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import com.github.gradle.node.npm.task.NpmTask
2+
import kotlinx.coroutines.CoroutineScope
3+
import kotlinx.coroutines.Dispatchers
4+
import kotlinx.coroutines.joinAll
5+
import kotlinx.coroutines.launch
6+
import kotlinx.coroutines.runBlocking
27
import java.io.FileNotFoundException
8+
import java.io.Reader
9+
import kotlin.time.Duration
310
import kotlin.time.Duration.Companion.minutes
411

512
plugins {
@@ -87,23 +94,92 @@ tasks.register("generateTestResources") {
8794
outputDir.relativeTo(resources).path,
8895
"-t",
8996
)
90-
println("Running: '${cmd.joinToString(" ")}'")
97+
logger.lifecycle("Running command: ${cmd.joinToString(" ")}")
9198
val result = ProcessUtil.run(cmd, timeout = 1.minutes) {
9299
directory(resources)
93100
}
94101
if (result.stdout.isNotBlank()) {
95-
println("[STDOUT]:\n--------\n${result.stdout}\n--------")
102+
logger.lifecycle("[STDOUT]:\n--------\n${result.stdout}\n--------")
96103
}
97104
if (result.stderr.isNotBlank()) {
98-
println("[STDERR]:\n--------\n${result.stderr}\n--------")
105+
logger.lifecycle("[STDERR]:\n--------\n${result.stderr}\n--------")
99106
}
100107
if (result.isTimeout) {
101-
println("Timeout!")
108+
logger.warn("Timeout!")
102109
}
103110
if (result.exitCode != 0) {
104-
println("Exit code: ${result.exitCode}")
111+
logger.warn("Exit code: ${result.exitCode}")
105112
}
106113

107114
println("Done generating test resources in %.1fs".format((System.currentTimeMillis() - startTime) / 1000.0))
108115
}
109116
}
117+
118+
object ProcessUtil {
119+
data class Result(
120+
val exitCode: Int,
121+
val stdout: String,
122+
val stderr: String,
123+
val isTimeout: Boolean, // true if the process was terminated due to timeout
124+
)
125+
126+
fun run(
127+
command: List<String>,
128+
input: Reader = "".reader(),
129+
timeout: Duration? = null,
130+
builder: ProcessBuilder.() -> Unit = {},
131+
): Result {
132+
val process = ProcessBuilder(command).apply(builder).start()
133+
return communicate(process, input, timeout)
134+
}
135+
136+
private fun communicate(
137+
process: Process,
138+
input: Reader,
139+
timeout: Duration? = null,
140+
): Result {
141+
val stdout = StringBuilder()
142+
val stderr = StringBuilder()
143+
144+
val scope = CoroutineScope(Dispatchers.IO)
145+
146+
// Handle process input
147+
val stdinJob = scope.launch {
148+
process.outputStream.bufferedWriter().use { writer ->
149+
input.copyTo(writer)
150+
}
151+
}
152+
153+
// Launch output capture coroutines
154+
val stdoutJob = scope.launch {
155+
process.inputStream.bufferedReader().useLines { lines ->
156+
lines.forEach { stdout.appendLine(it) }
157+
}
158+
}
159+
val stderrJob = scope.launch {
160+
process.errorStream.bufferedReader().useLines { lines ->
161+
lines.forEach { stderr.appendLine(it) }
162+
}
163+
}
164+
165+
// Wait for completion
166+
val isTimeout = if (timeout != null) {
167+
!process.waitFor(timeout.inWholeNanoseconds, TimeUnit.NANOSECONDS)
168+
} else {
169+
process.waitFor()
170+
false
171+
}
172+
173+
// Wait for all coroutines to finish
174+
runBlocking {
175+
joinAll(stdinJob, stdoutJob, stderrJob)
176+
}
177+
178+
return Result(
179+
exitCode = process.exitValue(),
180+
stdout = stdout.toString(),
181+
stderr = stderr.toString(),
182+
isTimeout = isTimeout,
183+
)
184+
}
185+
}

jacodb-ets/src/main/kotlin/org/jacodb/ets/utils/ProcessUtil.kt

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package org.jacodb.ets.utils
1818

1919
import kotlinx.coroutines.CoroutineScope
2020
import kotlinx.coroutines.Dispatchers
21+
import kotlinx.coroutines.joinAll
2122
import kotlinx.coroutines.launch
2223
import kotlinx.coroutines.runBlocking
2324
import mu.KotlinLogging
@@ -37,20 +38,12 @@ object ProcessUtil {
3738

3839
fun run(
3940
command: List<String>,
40-
input: String? = null,
41-
timeout: Duration? = null,
42-
): Result {
43-
val reader = input?.reader() ?: "".reader()
44-
return run(command, reader, timeout)
45-
}
46-
47-
fun run(
48-
command: List<String>,
49-
input: Reader,
41+
input: Reader = "".reader(),
5042
timeout: Duration? = null,
43+
builder: ProcessBuilder.() -> Unit = {},
5144
): Result {
5245
logger.debug { "Running command: $command" }
53-
val process = ProcessBuilder(command).start()
46+
val process = ProcessBuilder(command).apply(builder).start()
5447
return communicate(process, input, timeout)
5548
}
5649

@@ -90,10 +83,10 @@ object ProcessUtil {
9083
process.waitFor()
9184
false
9285
}
86+
87+
// Wait for all coroutines to finish
9388
runBlocking {
94-
stdinJob.join()
95-
stdoutJob.join()
96-
stderrJob.join()
89+
joinAll(stdinJob, stdoutJob, stderrJob)
9790
}
9891

9992
return Result(

0 commit comments

Comments
 (0)