Skip to content

Commit

Permalink
Add killDescendants property, bump version
Browse files Browse the repository at this point in the history
  • Loading branch information
psxpaul committed Dec 19, 2019
1 parent c097751 commit d92af2b
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 24 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ For running a standard executable:

```groovy
plugins {
id 'com.github.psxpaul.execfork' version '0.1.12'
id 'com.github.psxpaul.execfork' version '0.1.13'
}
task startDaemon(type: com.github.psxpaul.task.ExecFork) {
Expand All @@ -27,7 +27,7 @@ For running a java main class:

```groovy
plugins {
id 'com.github.psxpaul.execfork' version '0.1.12'
id 'com.github.psxpaul.execfork' version '0.1.13'
}
task startDaemon(type: com.github.psxpaul.task.JavaExecFork) {
Expand Down Expand Up @@ -60,6 +60,8 @@ timeout | Long | *Optional.* The maximum number of seconds associated with the w
stopAfter | org.gradle.api.Task | *Optional.* A task that, when finished, will cause the process to stop. If none is specified, the process will stop at the very end of a build (whether successful or not).
executable | String | *Required.* The path to the executable.
environment | Two Strings OR one Map<String, String> | *Optional.* Environment variables to launch the executable with. You can either assign a Map with the '=' operator, or pass 2 Strings as key/value to the function. Note that multiple calls to this function are supported.
forceKill | Boolean | *Optional.* Kills the process foricbly. Forcible process destruction is defined as the immediate termination of a process, whereas normal termination allows the process to shut down cleanly.
killDescendants | Boolean | *Optional.* Kill all descendents of the started process. Default: `true`


#### JavaExecFork:
Expand All @@ -78,6 +80,8 @@ classpath | org.gradle.api.file.FileCollection | *Required.* The classpath to us
main | String | *Required.* The qualified name of the main java class to execute.
jvmArgs | List<String> | *Optional.* The list of arguments to give to the jvm when launching the java main class.
environment | Two Strings OR one Map<String, String> | *Optional.* Environment variables to launch the java main class with. You can either assign a Map with the '=' operator, or pass 2 Strings as key/value to the function. Note that multiple calls to this function are supported.
forceKill | Boolean | *Optional.* Kills the process foricbly. Forcible process destruction is defined as the immediate termination of a process, whereas normal termination allows the process to shut down cleanly.
killDescendants | Boolean | *Optional.* Kill all descendents of the started process. Default: `true`

## Compatibility

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.12
0.1.13
16 changes: 4 additions & 12 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,17 @@ repositories {
}

tasks {
val cleanSampleProjects by creating(GradleBuild::class) {
val sampleProjects by creating(GradleBuild::class) {
buildFile = File("${project.rootDir}/sample_projects/build.gradle")
tasks = listOf("clean")
tasks = listOf("clean", "build")
}
cleanSampleProjects.dependsOn("install")
"clean" { finalizedBy(cleanSampleProjects) }

val buildSampleProjects by creating(GradleBuild::class) {
buildFile = File("${project.rootDir}/sample_projects/build.gradle")
tasks = listOf("build")
}
buildSampleProjects.dependsOn("install")
"build" { finalizedBy(buildSampleProjects) }
sampleProjects.dependsOn("install")
"test" { finalizedBy(sampleProjects) }
named<Test>("test") {
testLogging.exceptionFormat = TestExceptionFormat.FULL
}
}


val javadocJar by tasks.creating(Jar::class) {
archiveClassifier.set("javadoc")
from("javadoc")
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#Wed Dec 04 10:26:32 PST 2019
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
Expand Down
29 changes: 21 additions & 8 deletions src/main/kotlin/com/github/psxpaul/task/AbstractExecFork.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ abstract class AbstractExecFork : DefaultTask(), ProcessForkOptions {
@Input
var forceKill: Boolean = false

private var process: Process? = null
@Input
@Optional
var killDescendants: Boolean = true

var process: Process? = null

@Input
var timeout: Long = 60
Expand Down Expand Up @@ -160,12 +164,19 @@ abstract class AbstractExecFork : DefaultTask(), ProcessForkOptions {
* Stop the process that this task has spawned
*/
fun stop() {
val process: Process = process ?: return
try {
stopDescendants()
if (killDescendants) {
stopDescendants()
}
} catch(e: Exception) {
log.warn("Failed to stop descendants", e)
}

stopRootProcess()
}

private fun stopRootProcess() {
val process: Process = process ?: return
if (process.isAlive && !forceKill) {
process.destroy()
process.waitFor(15, TimeUnit.SECONDS)
Expand All @@ -175,25 +186,27 @@ abstract class AbstractExecFork : DefaultTask(), ProcessForkOptions {
}
}

fun stopDescendants() {
private fun stopDescendants() {
val process: Process = process ?: return
if(!process.isAlive) {
return
}

val toHandle = process::class.memberFunctions.singleOrNull { it.name == "toHandle" }
if(toHandle == null) {
if (toHandle == null) {
log.error("Could not load Process.toHandle(). The killDescendants flag requires Java 9+. Please set killDescendants=false, or upgrade to Java 9+.")
return // not supported, pre java 9?
}

toHandle.isAccessible = true
val handle = toHandle.call(process)
if(handle == null) {
if (handle == null) {
log.warn("Could not get process handle. Process descendants may not be stopped.")
return
}
val descendants = handle::class.memberFunctions.single { it.name == "descendants" } as KFunction<Stream<*>>
val descendants = handle::class.memberFunctions.single { it.name == "descendants" }
descendants.isAccessible = true
val children = descendants.call(handle);
val children: Stream<*> = descendants.call(handle) as Stream<*>;
val destroy = handle::class.memberFunctions.single { it.name == if(forceKill) "destroyForcibly" else "destroy" }
destroy.isAccessible = true

Expand Down

0 comments on commit d92af2b

Please sign in to comment.