Skip to content
This repository was archived by the owner on Apr 23, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,18 @@ It is also possible to set the name of the pid file allowing more than one proce
ready 'Started Application'
pidLockFileName '.other.pid.lock'
}

###Log File

The `SpawnProcessTask` works by directly reading the output stream of the child process it starts, looking for the ready statement.
If you specify a `logFileName` it will instead route the output stream to that file and then tail that file looking for the ready statement.
This is very useful for long lived processes that generate lots of output and would otherwise deadlock (see http://stackoverflow.com/questions/3285408/java-processbuilder-resultant-process-hangs#answer-3285479)

The log file will be removed by the `SpawnProcessTask` if it exists before spawning the process, effectively truncating it.

task startServer(type: SpawnProcessTask) {
command "java -jar someScriptHere.sh"
ready 'Started Application'
pidLockFileName '.other.pid.lock'
logFileName = 'myServerLog.txt'
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class SpawnProcessTask extends DefaultSpawnTask {
String command
String ready
List<Closure> outputActions = new ArrayList<Closure>()
String logFileName = null;

@Input
Map<String, String> environmentVariables = new HashMap<String, String>()
Expand All @@ -24,6 +25,10 @@ class SpawnProcessTask extends DefaultSpawnTask {
outputActions.add(outputClosure)
}

File getLogFile() {
return logFileName == null ? null : new File(directory, logFileName)
}

@TaskAction
void spawn() {
if (!(command && ready)) {
Expand All @@ -32,13 +37,14 @@ class SpawnProcessTask extends DefaultSpawnTask {

def pidFile = getPidFile()
if (pidFile.exists()) throw new GradleException("Server already running!")
//if (logFile != null && logFile.exists()) logFile.delete()

def process = buildProcess(directory, command)
waitToProcessReadyOrClosed(process)
}

private void waitToProcessReadyOrClosed(Process process) {
boolean isReady = waitUntilIsReadyOrEnd(process)
boolean isReady = waitUntilIsReadyOrEnd(logFile, process)
if (isReady) {
stampLockFile(pidFile, process)
} else {
Expand All @@ -57,18 +63,29 @@ class SpawnProcessTask extends DefaultSpawnTask {
}
}

private boolean waitUntilIsReadyOrEnd(Process process) {
private boolean waitUntilIsReadyOrEnd(File logFile, Process process) {
def line
def reader = new BufferedReader(new InputStreamReader(process.getInputStream()))
def reader = logFile == null ?
new BufferedReader(new InputStreamReader(process.getInputStream())) :
new BufferedReader(new InputStreamReader(new FileInputStream(logFile)))
boolean isReady = false
while (!isReady && (line = reader.readLine()) != null) {
logger.quiet line
runOutputActions(line)
if (line.contains(ready)) {
logger.quiet "$command is ready."
isReady = true
while (!isReady) {
line = reader.readLine()
if (line == null){
if (logFile != null && process.alive)
Thread.sleep(10)
else
break
} else {
logger.quiet line
runOutputActions(line)
if (line.contains(ready)) {
logger.quiet "$command is ready."
isReady = true
}
}
}
if (logFile != null) reader.close()
isReady
}

Expand All @@ -78,9 +95,12 @@ class SpawnProcessTask extends DefaultSpawnTask {
}
}

private Process buildProcess(String directory, String command) {
def builder = new ProcessBuilder(command.split(' '))
private Process buildProcess(String directory, String ... command) {
def builder = new ProcessBuilder(command)
builder.redirectErrorStream(true)
if (logFile != null){
builder.redirectOutput(logFile)
}
builder.environment().putAll(environmentVariables)
builder.directory(new File(directory))
builder.start()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,70 @@ class SpawnProcessTaskSpec extends Specification {
task.getPidFile().exists()
}

void "should property start process when using log file"() {
given:
def command = './process.sh'
def ready = 'It is done...'

and:
setExecutableProcess("process.sh")

and:
task.command = command
task.ready = ready
task.directory = directory.toString()
task.logFileName = "log.txt"

when:
task.spawn()

then:
task.getPidFile().exists()
}

void "should record all output in log file when using a log file"() {
given:
def command = './process.sh'
def ready = 'It is done...'

and:
setExecutableProcess("process.sh")

and:
task.command = command
task.ready = ready
task.directory = directory.toString()
task.logFileName = "log.txt"

when:
task.spawn()

then:
task.logFile.text.startsWith("Starting...\nIt is done...\n")
}

void "should remove log file before starting process"() {
given:
def command = './process.sh'
def ready = 'It is done...'

and:
setExecutableProcess("process.sh")

and:
task.command = command
task.ready = ready
task.directory = directory.toString()
task.logFileName = "log.txt"
task.logFile.text = "Remove me"

when:
task.spawn()

then:
task.logFile.text.startsWith("Starting...\nIt is done...\n")
}

void "should allow the name of the pid lock file to be overriden"() {
given:
def command = './process.sh'
Expand Down