This is an automated email from the ASF dual-hosted git repository. benw pushed a commit to branch gradle-improvements in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
commit a43d289522aab2b4aacc746773f4de67339631d4 Author: Ben Weidig <b...@netzgut.net> AuthorDate: Sun Jun 15 13:06:31 2025 +0200 TAP5-2809: split build.gradle further, modernize --- beanmodel/build.gradle | 3 +- buildSrc/build.gradle | 2 + .../main/groovy/t5build/GenerateChecksums.groovy | 61 ++++++++++ buildSrc/src/main/groovy/t5build/SSshExec.groovy | 21 ++++ buildSrc/src/main/groovy/t5build/Scp.groovy | 36 ++++++ buildSrc/src/main/groovy/t5build/SshTask.groovy | 94 ++++++++++++++++ .../main/groovy/t5build/TapestryBuildLogic.groovy | 22 ++++ .../src/main/groovy/tapestry.ssh-convention.gradle | 15 +++ gradle/libs.versions.toml | 2 + md5.gradle | 25 ----- sha256.gradle | 27 ----- ssh.gradle | 124 --------------------- 12 files changed, 255 insertions(+), 177 deletions(-) diff --git a/beanmodel/build.gradle b/beanmodel/build.gradle index e8d491dc2..09b48b253 100644 --- a/beanmodel/build.gradle +++ b/beanmodel/build.gradle @@ -28,7 +28,8 @@ clean.delete generateGrammarSource.outputDirectory compileJava { dependsOn generateGrammarSource - options.fork(memoryMaximumSize: '512m') + options.fork = true + options.forkOptions.memoryMaximumSize = '512M' } tasks.named('sourcesJar') { diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 94cb7679d..34a0503f1 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -14,5 +14,7 @@ dependencies { exclude module: 'gmaven-runtime-1.7' exclude module: 'less4j' } + implementation 'org.apache.ant:ant-jsch:1.8.2' + gradleApi() } diff --git a/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy b/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy new file mode 100644 index 000000000..dd9f9997f --- /dev/null +++ b/buildSrc/src/main/groovy/t5build/GenerateChecksums.groovy @@ -0,0 +1,61 @@ +package t5build + +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.gradle.api.tasks.SourceTask +import org.gradle.api.file.ConfigurableFileCollection + +import java.security.MessageDigest + +class GenerateChecksums extends SourceTask { + + enum Algorithm { + MD5('MD5', 32, 'md5'), + SHA256('SHA-256', 64, 'sha256') + + final String name + final int padding + final String extension + + Algorithm(String name, int padding, String extension) { + this.name = name + this.padding = padding + this.extension = extension + } + } + + @OutputDirectory + File outputDir + + + @TaskAction + void generate() { + source.each { file -> + // Create a map of MessageDigest instances, one for each algorithm, + // so it's easier to update them and use later + def digests = Algorithm.values().collectEntries { alg -> + [(alg): MessageDigest.getInstance(alg.name)] + } + + // use inputstream so to avoid loading whole file into memory + file.withInputStream { is -> + byte[] buffer = new byte[8192] + int bytesRead + while ((bytesRead = is.read(buffer)) != -1) { + digests.values().each { digest -> + digest.update(buffer, 0, bytesRead) + } + } + } + + // Write checksum files + digests.each { algo, digest -> + def checksum = new BigInteger(1, digest.digest()).toString(16).padLeft(algo.padding, '0') + new File(outputDir, "${file.name}.${algo.extension}").text = checksum + } + } + } +} diff --git a/buildSrc/src/main/groovy/t5build/SSshExec.groovy b/buildSrc/src/main/groovy/t5build/SSshExec.groovy new file mode 100644 index 000000000..e985b4591 --- /dev/null +++ b/buildSrc/src/main/groovy/t5build/SSshExec.groovy @@ -0,0 +1,21 @@ +package t5build + +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +class SshExec extends SshTask { + + @Input + List<String[]> commandLines = [] + + void commandLine(String... commandLine) { + commandLines << commandLine + } + + @TaskAction + void doActions() { + commandLines.each { commandLine -> + ssh(*commandLine) + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/t5build/Scp.groovy b/buildSrc/src/main/groovy/t5build/Scp.groovy new file mode 100644 index 000000000..3280cfb9d --- /dev/null +++ b/buildSrc/src/main/groovy/t5build/Scp.groovy @@ -0,0 +1,36 @@ +package t5build + +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.SkipWhenEmpty +import org.gradle.api.tasks.TaskAction +import java.io.File + +class Scp extends SshTask { + + @InputFiles @SkipWhenEmpty + def source + + @Input + String destination + + @Input + boolean isDir = false + + @TaskAction + void doActions() { + if (isDir) { + scpDir(source, destination) + return + } + project.files(source).each { doFile(it) } + } + + private void doFile(File file) { + if (file.isDirectory()) { + file.eachFile { doFile(it) } + } else { + scpFile(file, destination) + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/t5build/SshTask.groovy b/buildSrc/src/main/groovy/t5build/SshTask.groovy new file mode 100644 index 000000000..769b32adf --- /dev/null +++ b/buildSrc/src/main/groovy/t5build/SshTask.groovy @@ -0,0 +1,94 @@ +package t5build + +import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection +import org.gradle.api.logging.LogLevel +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal + +abstract class SshTask extends DefaultTask { + + @InputFiles + FileCollection sshAntClasspath + + @Input + String host + + @Input + String userName + + // TODO: Passwords should not be plain @Input. + @Input + String password + + @Input + boolean verbose = false + + private boolean antInited = false + + protected void initAnt() { + if (antInited) { + return + } + ant.taskdef(name: 'scp', + classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp', + classpath: sshAntClasspath.asPath, + loaderref: 'ssh') + + ant.taskdef(name: 'sshexec', + classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', + classpath: sshAntClasspath.asPath, + loaderref: 'ssh') + antInited = true + } + + protected void withInfoLogging(Closure action) { + def oldLogLevel = getLogging().getLevel() + getLogging().setLevel([LogLevel.INFO, oldLogLevel].min()) + try { + action() + } finally { + if (oldLogLevel != null) { + getLogging().setLevel(oldLogLevel) + } + } + } + + protected void scpFile(Object source, String destination) { + initAnt() + withInfoLogging { + // TODO: This keyfile is hardcoded and uses an old algorithm (dsa) + ant.scp(localFile: project.files(source).singleFile, + remoteToFile: "${userName}@${host}:${destination}", + keyfile: "${System.properties['user.home']}/.ssh/id_dsa", + verbose: verbose) + } + } + + protected void scpDir(Object source, String destination) { + initAnt() + withInfoLogging { + ant.sshexec(host: host, + username: userName, + password: password, + command: "mkdir -p ${destination}") + + ant.scp(remoteTodir: "${userName}@${host}:${destination}", + keyfile: "${System.properties['user.home']}/.ssh/id_dsa", + verbose: verbose) { + project.files(source).addToAntBuilder(ant, 'fileSet', FileCollection.AntType.FileSet) + } + } + } + + protected void ssh(Object... commandLine) { + initAnt() + withInfoLogging { + ant.sshexec(host: host, + username: userName, + password: password, + command: commandLine.join(' ')) + } + } +} diff --git a/buildSrc/src/main/groovy/t5build/TapestryBuildLogic.groovy b/buildSrc/src/main/groovy/t5build/TapestryBuildLogic.groovy new file mode 100644 index 000000000..13f9b935a --- /dev/null +++ b/buildSrc/src/main/groovy/t5build/TapestryBuildLogic.groovy @@ -0,0 +1,22 @@ +package t5build + +import org.gradle.api.Project + +class TapestryBuildLogic { + + static boolean isSnapshot(Project project) { + return tapestryVersion(project).endsWith('SNAPSHOT') + } + + static boolean isWindows() { + return System.properties['os.name'].toLowerCase().contains('windows') + } + + static String tapestryVersion(Project project) { + String major = project.rootProject.ext.tapestryMajorVersion + String minor = project.rootProject.ext.tapestryMinorVersion + + boolean isCiBuild = project.rootProject.hasProperty('continuousIntegrationBuild') && project.rootProject.continuousIntegrationBuild + return isCiBuild ? major + '-SNAPSHOT' : major + minor + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/tapestry.ssh-convention.gradle b/buildSrc/src/main/groovy/tapestry.ssh-convention.gradle new file mode 100644 index 000000000..0a66e2636 --- /dev/null +++ b/buildSrc/src/main/groovy/tapestry.ssh-convention.gradle @@ -0,0 +1,15 @@ +import t5build.SshTask + +// This configuration will hold the ant-jsch.jar at runtime +configurations { + sshAntTask +} + +dependencies { + sshAntTask libs.ant.jsch +} + +// Configure all SshTask instances to use the files from the configuration +tasks.withType(SshTask).configureEach { + it.sshAntClasspath = configurations.sshAntTask +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0990af421..2153aade1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,7 @@ json = "20140107" xmlApis = "1.4.01" guice = "3.0" groovy = "3.0.13" +ant-jsch = "1.8.2" # TESTING slf4j-simple = "2.0.17" @@ -96,6 +97,7 @@ hamcrest-core = { module = "org.hamcrest:hamcrest-core", version.ref = "hamcrest json = { module = "org.json:json", version.ref = "json" } xml-apis = { module = "xml-apis:xml-apis", version.ref = "xmlApis" } guice = { module = "com.google.inject:guice", version.ref = "guice" } +ant-jsch = { module = "org.apache.ant:ant-jsch", version.ref = "ant-jsch" } # GROOVY groovy-core = { group = "org.codehaus.groovy", name = "groovy", version.ref = "groovy" } diff --git a/md5.gradle b/md5.gradle deleted file mode 100644 index ab978c522..000000000 --- a/md5.gradle +++ /dev/null @@ -1,25 +0,0 @@ -import java.security.MessageDigest - -class GenMD5 extends SourceTask { - - def outputDir - - @OutputDirectory - File getOutputDir() { project.file(outputDir) } - - @TaskAction - void writeMD5s() { - - source.each { file -> - MessageDigest digest = MessageDigest.getInstance("MD5") - - digest.update(file.bytes) - - def checksum = new BigInteger(1, digest.digest()).toString(16).padLeft(32, "0") - - new File(outputDir, file.name + ".md5").text = checksum - } - } -} - -project.ext.GenMD5 = GenMD5.class diff --git a/sha256.gradle b/sha256.gradle deleted file mode 100644 index 5153fc8ce..000000000 --- a/sha256.gradle +++ /dev/null @@ -1,27 +0,0 @@ -import java.security.MessageDigest - -class GenSHA256 extends SourceTask { - - def outputDir - - @OutputDirectory - File getOutputDir() { - project.file(outputDir) - } - - @TaskAction - void writeSHA256s() { - - source.each { file -> - MessageDigest digest = MessageDigest.getInstance("SHA-256") - - digest.update(file.bytes) - - def checksum = new BigInteger(1, digest.digest()).toString(16).padLeft(32, "0") - - new File(outputDir, file.name + ".sha256").text = checksum - } - } -} - -project.ext.GenSHA256 = GenSHA256.class \ No newline at end of file diff --git a/ssh.gradle b/ssh.gradle deleted file mode 100644 index fb5fe76df..000000000 --- a/ssh.gradle +++ /dev/null @@ -1,124 +0,0 @@ -project.ext.Scp = Scp.class -project.ext.SshExec = SshExec.class -project.ext.SshTask = SshTask.class - -configurations { - sshAntTask -} - -dependencies { - sshAntTask "org.apache.ant:ant-jsch:1.8.2" -} - -tasks.withType(SshTask) { - sshAntClasspath = configurations.sshAntTask -} - -class SshTask extends DefaultTask { - @InputFiles - FileCollection sshAntClasspath - - @Input - String host - - @Input - String userName - - @Input - String password - - boolean verbose = false - - private boolean antInited = false - - protected initAnt() { - if (!antInited) { - ant.taskdef(name: 'scp', - classname: 'org.apache.tools.ant.taskdefs.optional.ssh.Scp', - classpath: sshAntClasspath.asPath, - loaderref: 'ssh') - ant.taskdef(name: 'sshexec', - classname: 'org.apache.tools.ant.taskdefs.optional.ssh.SSHExec', - classpath: sshAntClasspath.asPath, - loaderref: 'ssh') - antInited = true - } - } - - protected withInfoLogging(Closure action) { - def oldLogLevel = logging.level - logging.level = [LogLevel.INFO, oldLogLevel].min() - try { - action() - } finally { - if (oldLogLevel) { - logging.level = oldLogLevel - } - } - } - - def scpFile(source, destination) { - initAnt() - withInfoLogging { - ant.scp(localFile: project.files(source).singleFile, remoteToFile: "${userName}@${host}:${destination}", keyfile : "${System.properties['user.home']}/.ssh/id_dsa", verbose: verbose) - } - } - - def scpDir(source, destination) { - initAnt() - withInfoLogging { - ant.sshexec(host: host, username: userName, password: password, command: "mkdir -p ${destination}") - ant.scp(remoteTodir: "${userName}@${host}:${destination}", keyfile : "${System.properties['user.home']}/.ssh/id_dsa", verbose: verbose) { - project.files(source).addToAntBuilder(ant, "fileSet", FileCollection.AntType.FileSet) - } - } - } - - def ssh(Object... commandLine) { - initAnt() - withInfoLogging { - ant.sshexec(host: host, username: userName, password: password, command: commandLine.join(' ')) - } - } -} - -class Scp extends SshTask { - @InputFiles @SkipWhenEmpty source - @Input destination - boolean isDir = false - - @TaskAction - void doActions() { - if (isDir) { - scpDir(source, destination) - return - } - - project.files(source).each { doFile(it) } - } - - void doFile(File file) { - - if (file.directory) { - file.eachFile { doFile(it) } - } else { - scpFile(file, destination) - } - } -} - -class SshExec extends SshTask { - @Input - List<String[]> commandLines = [] - - void commandLine(String... commandLine) { - commandLines << commandLine - } - - @TaskAction - void doActions() { - commandLines.each { commandLine -> - ssh(* commandLine) - } - } -} \ No newline at end of file