Gradle, js, webpack: report progress
#KT-31013
This commit is contained in:
+25
-7
@@ -7,14 +7,16 @@ package org.jetbrains.kotlin.gradle.internal
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.process.ExecResult
|
||||
import org.gradle.process.internal.ExecAction
|
||||
import org.gradle.process.internal.ExecActionFactory
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.PipedInputStream
|
||||
import java.io.PipedOutputStream
|
||||
import java.nio.CharBuffer
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
internal fun Project.execWithProgress(description: String, body: (ExecAction) -> Unit) {
|
||||
internal fun Project.execWithProgress(description: String, readStdErr: Boolean = false, body: (ExecAction) -> Unit): ExecResult {
|
||||
this as ProjectInternal
|
||||
|
||||
val stderr = ByteArrayOutputStream()
|
||||
@@ -22,22 +24,38 @@ internal fun Project.execWithProgress(description: String, body: (ExecAction) ->
|
||||
val stdInPipe = PipedInputStream()
|
||||
val exec = services.get(ExecActionFactory::class.java).newExecAction()
|
||||
body(exec)
|
||||
project.operation(description) {
|
||||
exec.errorOutput = stderr
|
||||
return project.operation(description) {
|
||||
exec.standardOutput = PipedOutputStream(stdInPipe)
|
||||
val outputReaderThread = thread(name = "output reader for [$description]") {
|
||||
stdInPipe.reader().useLines { lines ->
|
||||
lines.forEach {
|
||||
stdout.appendln(it)
|
||||
progress(it)
|
||||
stdInPipe.reader().use { reader ->
|
||||
val buffer = StringBuilder()
|
||||
while (true) {
|
||||
val read = reader.read()
|
||||
if (read == -1) break;
|
||||
val ch = read.toChar()
|
||||
if (ch == '\b' || ch == '\n' || ch == '\r') {
|
||||
if (buffer.isNotEmpty()) {
|
||||
val str = buffer.toString()
|
||||
stdout.append(str)
|
||||
progress(str.trim())
|
||||
buffer.setLength(0)
|
||||
}
|
||||
stdout.append(ch)
|
||||
} else buffer.append(ch)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (readStdErr) {
|
||||
exec.errorOutput = exec.standardOutput
|
||||
} else {
|
||||
exec.errorOutput = System.err
|
||||
}
|
||||
exec.isIgnoreExitValue = true
|
||||
val result = exec.execute()
|
||||
outputReaderThread.join()
|
||||
if (result.exitValue != 0) {
|
||||
error(stderr.toString() + "\n" + stdout)
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -10,17 +10,17 @@ import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.internal.logging.events.ProgressStartEvent
|
||||
import org.gradle.internal.logging.progress.ProgressLogger
|
||||
|
||||
fun Project.operation(
|
||||
fun <T> Project.operation(
|
||||
description: String,
|
||||
initialStatus: String? = null,
|
||||
body: ProgressLogger.() -> Unit
|
||||
) {
|
||||
body: ProgressLogger.() -> T
|
||||
): T {
|
||||
val services = (project as ProjectInternal).services
|
||||
val progressFactory = services.get(org.gradle.internal.logging.progress.ProgressLoggerFactory::class.java)
|
||||
val operation = progressFactory.newOperation(ProgressStartEvent.BUILD_OP_CATEGORY)
|
||||
operation.start(description, initialStatus)
|
||||
try {
|
||||
operation.body()
|
||||
return operation.body()
|
||||
} finally {
|
||||
operation.completed()
|
||||
}
|
||||
|
||||
+3
-1
@@ -114,7 +114,9 @@ class KotlinKarma(override val compilation: KotlinJsCompilation) : KotlinJsTestF
|
||||
KotlinWebpackConfigWriter(
|
||||
configDirectory = project.projectDir.resolve("webpack.config.d").takeIf { it.isDirectory },
|
||||
sourceMaps = true,
|
||||
export = false
|
||||
export = false,
|
||||
progressReporter = true,
|
||||
progressReporterPathFilter = project.nodeJs.root.rootPackageDir.absolutePath
|
||||
).appendTo(it)
|
||||
|
||||
it.appendln(" return config;")
|
||||
|
||||
+11
-4
@@ -54,7 +54,7 @@ open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies {
|
||||
var saveEvaluatedConfigFile: Boolean = true
|
||||
|
||||
open val outputPath: File
|
||||
@OutputDirectory get() = project.buildDir.resolve("lib")
|
||||
@OutputDirectory get() = project.buildDir.resolve("libs")
|
||||
|
||||
open val configDirectory: File?
|
||||
@Optional @InputDirectory get() = project.projectDir.resolve("webpack.config.d").takeIf { it.isDirectory }
|
||||
@@ -98,7 +98,7 @@ open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies {
|
||||
}
|
||||
|
||||
private fun createRunner() = KotlinWebpackRunner(
|
||||
compilation!!.npmProject,
|
||||
compilation.npmProject,
|
||||
configFile,
|
||||
execHandleFactory,
|
||||
bin,
|
||||
@@ -121,13 +121,20 @@ open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies {
|
||||
val runner = createRunner()
|
||||
|
||||
if (project.gradle.startParameter.isContinuous) {
|
||||
val continuousRunner = runner
|
||||
|
||||
val deploymentRegistry = services.get(DeploymentRegistry::class.java)
|
||||
val deploymentHandle = deploymentRegistry.get("webpack", Handle::class.java)
|
||||
if (deploymentHandle == null) {
|
||||
deploymentRegistry.start("webpack", DeploymentRegistry.ChangeBehavior.BLOCK, Handle::class.java, runner)
|
||||
deploymentRegistry.start("webpack", DeploymentRegistry.ChangeBehavior.BLOCK, Handle::class.java, continuousRunner)
|
||||
}
|
||||
} else {
|
||||
runner.execute()
|
||||
runner.copy(
|
||||
configWriter = runner.configWriter.copy(
|
||||
progressReporter = true,
|
||||
progressReporterPathFilter = project.nodeJs.root.rootPackageDir.absolutePath
|
||||
)
|
||||
).execute()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-2
@@ -15,7 +15,7 @@ import java.io.Serializable
|
||||
import java.io.StringWriter
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class KotlinWebpackConfigWriter(
|
||||
data class KotlinWebpackConfigWriter(
|
||||
val mode: Mode = Mode.DEVELOPMENT,
|
||||
val entry: File? = null,
|
||||
val outputPath: File? = null,
|
||||
@@ -26,7 +26,9 @@ class KotlinWebpackConfigWriter(
|
||||
val showProgress: Boolean = false,
|
||||
val sourceMaps: Boolean = false,
|
||||
val sourceMapsRuntime: Boolean = false,
|
||||
val export: Boolean = true
|
||||
val export: Boolean = true,
|
||||
val progressReporter: Boolean = false,
|
||||
val progressReporterPathFilter: String? = null
|
||||
) {
|
||||
enum class Mode(val code: String) {
|
||||
DEVELOPMENT("development"),
|
||||
@@ -88,6 +90,7 @@ class KotlinWebpackConfigWriter(
|
||||
appendReport()
|
||||
appendFromConfigDir()
|
||||
appendEvaluatedFileReport()
|
||||
appendProgressReporter()
|
||||
|
||||
if (export) {
|
||||
//language=JavaScript 1.8
|
||||
@@ -207,6 +210,29 @@ class KotlinWebpackConfigWriter(
|
||||
)
|
||||
}
|
||||
|
||||
private fun Appendable.appendProgressReporter() {
|
||||
if (!progressReporter) return
|
||||
|
||||
appendln(
|
||||
"""
|
||||
// Report progress to console
|
||||
(function(config) {
|
||||
const webpack = require('webpack');
|
||||
const handler = (percentage, message, ...args) => {
|
||||
const p = percentage*100;
|
||||
let msg = Math.trunc(p/100) + Math.trunc(p%100) + '% ' + message + ' ' + args.join(' ');
|
||||
${if (progressReporterPathFilter == null) "" else """
|
||||
msg = msg.replace(new RegExp(${jsQuotedString(progressReporterPathFilter ?: "")}, 'g'), '');
|
||||
""".trimIndent()}
|
||||
console.log(msg);
|
||||
};
|
||||
|
||||
config.plugins.push(new webpack.ProgressPlugin(handler))
|
||||
})(config);
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun json(obj: Any) = StringWriter().also {
|
||||
GsonBuilder().setPrettyPrinting().create().toJson(obj, it)
|
||||
|
||||
+13
-22
@@ -3,55 +3,46 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress(
|
||||
"JSAnnotator",
|
||||
"NodeJsCodingAssistanceForCoreModules",
|
||||
"BadExpressionStatementJS",
|
||||
"JSUnresolvedFunction"
|
||||
)
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.webpack
|
||||
|
||||
import org.gradle.process.ExecResult
|
||||
import org.gradle.process.ExecSpec
|
||||
import org.gradle.process.internal.ExecHandle
|
||||
import org.gradle.process.internal.ExecHandleFactory
|
||||
import org.jetbrains.kotlin.gradle.internal.execWithProgress
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver
|
||||
import java.io.File
|
||||
|
||||
internal class KotlinWebpackRunner(
|
||||
internal data class KotlinWebpackRunner(
|
||||
val npmProject: NpmProject,
|
||||
val configFile: File,
|
||||
val execHandleFactory: ExecHandleFactory,
|
||||
val bin: String,
|
||||
val configWriter: KotlinWebpackConfigWriter
|
||||
) {
|
||||
fun execute(): ExecResult {
|
||||
val exec = start()
|
||||
val result = exec.waitForFinish()
|
||||
check(result.exitValue == 0) {
|
||||
"Webpack exited with non zero exit code (${result.exitValue})"
|
||||
}
|
||||
return result
|
||||
fun execute() = npmProject.project.execWithProgress("webpack") {
|
||||
configureExec(it)
|
||||
}
|
||||
|
||||
fun start(): ExecHandle {
|
||||
val execFactory = execHandleFactory.newExec()
|
||||
configureExec(execFactory)
|
||||
val exec = execFactory.build()
|
||||
exec.start()
|
||||
return exec
|
||||
}
|
||||
|
||||
private fun configureExec(execFactory: ExecSpec) {
|
||||
check(configWriter.entry?.isFile == true) {
|
||||
"${this}: Entry file not existed \"${configWriter.entry}\""
|
||||
}
|
||||
|
||||
configWriter.save(configFile)
|
||||
|
||||
val execFactory = execHandleFactory.newExec()
|
||||
|
||||
val args = mutableListOf<String>("--config", configFile.absolutePath)
|
||||
if (configWriter.showProgress) {
|
||||
args.add("--progress")
|
||||
}
|
||||
|
||||
npmProject.useTool(execFactory, ".bin/$bin", *args.toTypedArray())
|
||||
val exec = execFactory.build()
|
||||
exec.start()
|
||||
return exec
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user