From 39b8e976138045883bda600f2ee3a1724c2ddbf6 Mon Sep 17 00:00:00 2001 From: Dawid Weiss Date: Tue, 30 Mar 2021 14:38:13 +0200 Subject: [PATCH] LUCENE-9896: Add 'quiet exec' utility suppressing exec output unless a failure occurs --- .../documentation/check-broken-links.gradle | 25 +++------ gradle/documentation/render-javadoc.gradle | 37 +------------ gradle/generation/icu.gradle | 20 +++---- gradle/generation/jflex.gradle | 17 +++--- gradle/generation/kuromoji.gradle | 2 +- gradle/generation/snowball.gradle | 2 +- gradle/generation/util.gradle | 4 +- gradle/globals.gradle | 53 +++++++++++++++++++ 8 files changed, 80 insertions(+), 80 deletions(-) diff --git a/gradle/documentation/check-broken-links.gradle b/gradle/documentation/check-broken-links.gradle index 79a08182e2a..235bca06fbb 100644 --- a/gradle/documentation/check-broken-links.gradle +++ b/gradle/documentation/check-broken-links.gradle @@ -45,23 +45,14 @@ class CheckBrokenLinksTask extends DefaultTask { @TaskAction def check() { - def result - output.withOutputStream { output -> - result = project.exec { - executable project.externalTool("python3") - ignoreExitValue = true - standardOutput = output - errorOutput = output - args = [ - "-B", - validationScript.absolutePath, - docsDir.get().getAsFile() - ] - } - } - - if (result.getExitValue() != 0) { - throw new GradleException("Broken links check failed. Command output at: ${output}") + project.quietExec { + executable project.externalTool("python3") + ignoreExitValue = false + args = [ + "-B", + validationScript.absolutePath, + docsDir.get().getAsFile() + ] } } } diff --git a/gradle/documentation/render-javadoc.gradle b/gradle/documentation/render-javadoc.gradle index 4503f8ebb31..e852794a431 100644 --- a/gradle/documentation/render-javadoc.gradle +++ b/gradle/documentation/render-javadoc.gradle @@ -451,46 +451,11 @@ class RenderJavadocTask extends DefaultTask { logger.info("Javadoc executable used: ${javadocCmd}") - def outputFile = project.file("${getTemporaryDir()}/javadoc-output.txt") - def result - - outputFile.withOutputStream { output -> - result = project.exec { + project.quietExec { executable javadocCmd - // we want to capture both stdout and stderr to the same - // stream but gradle attempts to close these separately - // (it has two independent pumping threads) and it can happen - // that one still tries to write something when the other closed - // the underlying output stream. - def wrapped = new java.io.FilterOutputStream(output) { - public void close() { - // no-op. we close this stream manually. - } - } - standardOutput = wrapped - errorOutput = wrapped - args += [ "@${optionsFile}" ] args += jOpts - - ignoreExitValue true - } - } - - if (result.getExitValue() != 0) { - // Pipe the output to console. Intentionally skips any encoding conversion - // and pumps raw bytes. - System.out.write(outputFile.bytes) - System.out.flush() - - def cause - try { - result.rethrowFailure() - } catch (ex) { - cause = ex - } - throw new GradleException("Javadoc generation failed for ${project.path},\n Options file at: ${optionsFile}\n Command output at: ${outputFile}", cause) } // append some special table css, prettify css diff --git a/gradle/generation/icu.gradle b/gradle/generation/icu.gradle index fca3d8a5ca8..d450d4878f0 100644 --- a/gradle/generation/icu.gradle +++ b/gradle/generation/icu.gradle @@ -63,9 +63,8 @@ configure(project(":lucene:analysis:icu")) { ] } - project.exec { + project.quietExec { executable gennorm - ignoreExitValue = false args = [ "-v", "-s", @@ -77,9 +76,9 @@ configure(project(":lucene:analysis:icu")) { "NativeDigitFolding.txt" ] } - project.exec { + + project.quietExec { executable icupkg - ignoreExitValue = false args = [ "-tb", "${buildDir}/utr30.tmp", @@ -157,10 +156,8 @@ configure(project(":lucene:analysis:icu")) { project.delete icuSrcDir // Extract the tgz - project.exec { + project.quietExec { executable "tar" - ignoreExitValue false - workingDir icuBuildDir args = [ "-zxvf", @@ -169,9 +166,8 @@ configure(project(":lucene:analysis:icu")) { } // Compile: (cd icu/source && ./configure --prefix=$(pwd) --enable-rpath && make -j4) - project.exec { + project.quietExec { executable "sh" - ignoreExitValue false workingDir icuSrcDir args = [ @@ -181,9 +177,8 @@ configure(project(":lucene:analysis:icu")) { ] } - project.exec { + project.quietExec { executable "make" - ignoreExitValue false workingDir icuSrcDir args = [ "-j4" @@ -192,9 +187,8 @@ configure(project(":lucene:analysis:icu")) { // Test that the binaries work: derb -V logger.lifecycle("Compiled ICU, checking...") - project.exec { + project.quietExec { executable "./derb" - ignoreExitValue false workingDir icuBinDir args = [ "-V" diff --git a/gradle/generation/jflex.gradle b/gradle/generation/jflex.gradle index 8f6f5ca65ea..3e9a949c8a8 100644 --- a/gradle/generation/jflex.gradle +++ b/gradle/generation/jflex.gradle @@ -157,16 +157,13 @@ configure(project(":lucene:analysis:common")) { doFirst { // Regenerate HTMLCharacterEntities.jflex first. def target = file('src/java/org/apache/lucene/analysis/charfilter/HTMLCharacterEntities.jflex') - target.withOutputStream { output -> - project.exec { - executable = project.externalTool("python3") - workingDir = target.parentFile - standardOutput = output - args += [ - "-B", // don't write any bytecode cache - "htmlentity.py" - ] - } + quietExec { + executable = project.externalTool("python3") + workingDir = target.parentFile + args += [ + "-B", // don't write any bytecode cache + "htmlentity.py" + ] } project.ant.fixcrlf( diff --git a/gradle/generation/kuromoji.gradle b/gradle/generation/kuromoji.gradle index 49e32ae3436..566eaec4ceb 100644 --- a/gradle/generation/kuromoji.gradle +++ b/gradle/generation/kuromoji.gradle @@ -71,7 +71,7 @@ configure(project(":lucene:analysis:kuromoji")) { } // Apply patch via local git. - project.exec { + project.quietExec { workingDir = unpackedDir executable "git" // TODO: better use jgit to apply patch, this is not portable!!! args += [ diff --git a/gradle/generation/snowball.gradle b/gradle/generation/snowball.gradle index 5f2ff716367..7ea455647bd 100644 --- a/gradle/generation/snowball.gradle +++ b/gradle/generation/snowball.gradle @@ -106,7 +106,7 @@ configure(project(":lucene:analysis:common")) { dependsOn downloadSnowballData doFirst { - project.exec { + project.quietExec { executable "bash" args = [snowballScript, snowballStemmerDir, snowballWebsiteDir, snowballDataDir, projectDir] } diff --git a/gradle/generation/util.gradle b/gradle/generation/util.gradle index 2484f44128a..e672ecc4d67 100644 --- a/gradle/generation/util.gradle +++ b/gradle/generation/util.gradle @@ -44,7 +44,7 @@ configure(project(":lucene:core")) { ['gen_BulkOperation.py', 'gen_Packed64SingleBlock.py'].each { prog -> logger.lifecycle("Executing: ${prog} in ${targetDir}") - project.exec { + quietExec { workingDir targetDir executable project.externalTool("python3") args = ['-B', "${prog}"] @@ -69,7 +69,7 @@ configure(project(":lucene:core")) { ['1', '2'].each { num -> ['True', 'False'].each { transpose -> - project.exec { + quietExec { workingDir targetDir executable project.externalTool("python3") args = ['-B', 'createLevAutomata.py', num, transpose, "${momanDir}/finenight/python"] diff --git a/gradle/globals.gradle b/gradle/globals.gradle index 0ca1af1a60e..fbcbb2dd30c 100644 --- a/gradle/globals.gradle +++ b/gradle/globals.gradle @@ -72,5 +72,58 @@ allprojects { } } } + + // Utility function similar to project.exec but not emitting + // any output unless an error code is returned from the executed command. + quietExec = { closure -> + // Resolve any properties against the provided closure. + resolveStrategy = Closure.DELEGATE_ONLY + delegate = closure.delegate + + File outputFile = File.createTempFile("exec-output-", ".txt", getTemporaryDir()) + ExecResult result + boolean saveIgnoreExitValue + ExecSpec saveExecSpec + + outputFile.withOutputStream { output -> + // we want to capture both stdout and stderr to the same + // stream but gradle attempts to close these separately + // (it has two independent pumping threads) and it can happen + // that one still tries to write something when the other closed + // the underlying output stream. + def wrapped = new java.io.FilterOutputStream(output) { + public void close() { + // no-op. we close this stream manually. + } + } + + result = project.exec { ExecSpec execSpec -> + project.configure(execSpec, closure) + + saveIgnoreExitValue = execSpec.ignoreExitValue + saveExecSpec = execSpec + + standardOutput = wrapped + errorOutput = wrapped + ignoreExitValue true + } + } + + if (result.getExitValue() != 0) { + // Pipe the output to console. Intentionally skips any encoding conversion + // and pumps raw bytes. + logger.error(new String(outputFile.bytes)) + + if (!saveIgnoreExitValue) { + result.rethrowFailure() + throw new GradleException("The executed process ${saveExecSpec.executable} " + + "returned an odd status " + + "code: ${result.exitValue}, " + + "output at: ${outputFile} (and logged above).") + } + } + + return result + } } }