diff --git a/build.gradle b/build.gradle index 67d75d9d0d..a70b5b6e23 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ import java.nio.file.Paths import com.github.spotbugs.snom.Confidence plugins { + id 'base' id 'application' id 'java-library' id 'java-test-fixtures' @@ -401,7 +402,6 @@ def omegatJarFilename = jar.archiveFileName.get() project(":machinetranslators") {jar.enabled = false} project(":spellchecker") {jar.enabled = false} -def distsDir = file(layout.buildDirectory.file("${distsDirName}")) def assetDir = findProperty('assetDir') ?: '../' def macJRE = fileTree(dir: assetDir, include: 'OpenJDK17U-jre_x64_mac_*.tar.gz') def armMacJRE = fileTree(dir: assetDir, include: 'OpenJDK17U-jre_aarch64_mac_*.tar.gz') @@ -762,12 +762,12 @@ tasks.register('mac') { } ext.makeMacTask = { args -> - def installTaskName = args.name + "InstallDist" - def signedInstallTaskName = args.name + "InstallSignedDist" + def installTaskName = 'install' + args.name.capitalize() + "Dist" + def signedInstallTaskName = 'install' + args.name.capitalize() + "SignedDist" def distZipTaskName = args.name + "DistZip" - def signedZipTaskName = args.name + "SignedDistZip" + def signedZipTaskName = args.name + "Signed" def notarizeTaskName = args.name + "Notarize" - def stapledNotarizedDistZipTaskName = args.name + "StapledNotarizedDistZip" + def stapledNotarizedDistZipTaskName = args.name + "StapledNotarized" tasks.register(distZipTaskName, Zip) { description = "Create Mac distribution for ${args.name}" @@ -803,6 +803,12 @@ ext.makeMacTask = { args -> } } } + outputs.upToDateWhen { + // detect up-to-date when OmegaT.jar exists and newer than libs/OmegaT.jar + def f1 = base.distsDirectory.file(archiveFileName).get().asFile + def f2 = base.libsDirectory.file('OmegaT.jar').get().asFile + f1.exists() && f2.exists() && f1.lastModified() > f2.lastModified() + } onlyIf { condition(!args.jrePath || !args.jrePath.empty, 'JRE not found') } @@ -845,7 +851,13 @@ ext.makeMacTask = { args -> } } duplicatesStrategy = DuplicatesStrategy.INCLUDE - destinationDir file(layout.buildDirectory.file("install/${application.applicationName}-${args.suffix}")) + destinationDir file(layout.buildDirectory.file("install/${application.applicationName}-${args.suffix}")) + outputs.upToDateWhen { + // detect up-to-date when OmegaT.jar exists and newer than libs/OmegaT.jar + def f1 = file("$destinationDir/OmegaT.app/Contents/Java/OmegaT.jar") + def f2 = base.libsDirectory.file('OmegaT.jar').get().asFile + f1.exists() && f2.exists() && f1.lastModified() > f2.lastModified() + } doFirst { delete "$destinationDir/OmegaT.app/Contents/PlugIns/jre.bundle" } @@ -1198,18 +1210,69 @@ tasks.register('win') { ext.makeWinTask = { args -> def fullVersion = project.version + omtVersion.beta def installerBasename = "OmegaT_${fullVersion}_${args.suffix}" - def installerExe = layout.buildDirectory.file("${distsDirName}/${installerBasename}.exe") - def signedExe = layout.buildDirectory.file("${distsDirName}/${installerBasename}_Signed.exe") - + def installerWinExe = base.distsDirectory.file("${installerBasename}.exe") + def signedWinExe = base.distsDirectory.file("${installerBasename}_Signed.exe") + def prepDistsTaskName = "${args.name}Prep" + def genDistsTaskName = "${args.name}Gen" + def distsTaskName = "${args.name}" def signedTaskName = "${args.name}Signed" + def signedTaskCommandArgs = { arg2 -> + def exe = exePresent('osslsigncode') ? 'osslsigncode' : file('ci/osslsigncode').toString() + def commandArgs = [exe, 'sign'] + if (project.hasProperty('pkcs11module')) { + commandArgs.addAll('-pkcs11module', project.property('pkcs11module')) + } + if (project.hasProperty('winCodesignCert')) { + commandArgs.addAll('-certs', project.property('winCodesignCert')) + } + if (project.hasProperty('pkcs11cert')) { + commandArgs.addAll('-pkcs11cert', project.property('pkcs11cert')) + } + if (project.hasProperty('winCodesignPassword')) { + commandArgs.addAll('-pass', project.property('winCodesignPassword')) + } + if (project.hasProperty('winCodesignDevice')) { + envVars['USBDEV'] = project.property('winCodesignDevice') + } + commandArgs.addAll( + '-t', project.hasProperty('winCodesignTimestampUrl') ? project.property('winCodesignTimestampUrl') : + 'http://time.certum.pl/', + '-n', application.applicationName, '-i', omtWebsite, '-h', 'sha256', + '-in', installerWinExe.get().asFile, + '-out', signedWinExe.get().asFile + ) + return commandArgs + } - tasks.register(args.name, Sync) { - description = "Create a Windows installer for ${args.name} distro. " + - 'Requires Inno Setup (http://www.jrsoftware.org/isinfo.php).' + tasks.register(prepDistsTaskName, Sync) { + onlyIf { + conditions([!args.jrePath || !args.jrePath.empty, 'JRE not found'], + [exePresent('iscc') || exePresent('docker') || exePresent('nerdctl'), + 'InnoSetup or Docker not installed']) + } + doFirst { + delete "$destinationDir/jre" + delete installerWinExe + } with distributions.main.contents - dependsOn createAllExecutables + destinationDir file(layout.buildDirectory.file("innosetup/${args.name}")) + outputs.upToDateWhen { + // detect up-to-date when OmegaT.jar exists and newer than libs/OmegaT.jar + def f1 = layout.buildDirectory.file("innosetup/${args.name}/OmegaT.jar").get().asFile + def f2 = base.libsDirectory.file('OmegaT.jar').get().asFile + f1.exists() && f2.exists() && f1.lastModified() > f2.lastModified() + } from('release/win32-specific') { include 'OmegaT.l4J.ini' + include 'OmegaT.iss' + filter(ReplaceTokens, tokens: [ + VERSION_NUMBER_SUBST : fullVersion, + OUTPUT_BASENAME_SUBST: installerBasename.toString(), + CUSTOM_MESSAGES_SUBST: getInnoSetupCustomMessages(), + ARCHITECTURE_SUBST : args.arch ?: '' + ]) + filter(FixCrLfFilter, eol: FixCrLfFilter.CrLf.newInstance('crlf')) + filteringCharset = 'UTF-8' } from('build/launch4j') { include '*.exe' @@ -1222,56 +1285,47 @@ ext.makeWinTask = { args -> } } } - destinationDir file(layout.buildDirectory.file("innosetup/${args.name}")) - outputs.file installerExe + dependsOn createAllExecutables + } + + tasks.register(genDistsTaskName, Exec) { onlyIf { conditions([!args.jrePath || !args.jrePath.empty, 'JRE not found'], [exePresent('iscc') || exePresent('docker') || exePresent('nerdctl'), 'InnoSetup or Docker not installed']) } - doFirst { - delete "$destinationDir/jre" - delete installerExe - project.copy { - from 'build' - into 'build' - include "innosetup/${args.name}/**/*" - dirMode 0777 - fileMode 0666 - } + dependsOn prepDistsTaskName + outputs.upToDateWhen { + // detect up-to-date when OmegaT.jar exists and newer than libs/OmegaT.jar + def f1 = layout.buildDirectory.file("innosetup/${args.name}/${installerBasename}.exe").get().asFile + def f2 = layout.buildDirectory.file("innosetup/${args.name}/OmegaT.jar").get().asFile + f1.exists() && f2.exists() && f1.lastModified() > f2.lastModified() } - doLast { - project.copy { - from('release/win32-specific') { - include 'OmegaT.iss' - } - into(destinationDir) - filter(ReplaceTokens, tokens: [ - VERSION_NUMBER_SUBST : fullVersion, - OUTPUT_BASENAME_SUBST: installerBasename.toString(), - CUSTOM_MESSAGES_SUBST: getInnoSetupCustomMessages(), - ARCHITECTURE_SUBST : args.arch ?: '' - ]) - filter(FixCrLfFilter, eol: FixCrLfFilter.CrLf.newInstance('crlf')) - filteringCharset = 'UTF-8' - } - exec { - // You'd think we could just set the PATH, but there be dragons here - // https://github.com/palantir/gradle-docker/issues/162 - def exe = exePresent('iscc') ? 'iscc' : file('ci/iscc') - commandLine exe, "${destinationDir}/OmegaT.iss" - } - project.copy { - from("${destinationDir}/${installerBasename}.exe") - into distsDir - } - delete file("${destinationDir}/${installerBasename}.exe") + // You'd think we could just set the PATH, but there be dragons here + // https://github.com/palantir/gradle-docker/issues/162 + def exe = exePresent('iscc') ? 'iscc' : file('ci/iscc') + def iss = layout.buildDirectory.file("innosetup/${args.name}/OmegaT.iss").get().asFile + commandLine exe, '/Qp', iss + } + + tasks.register(distsTaskName, Copy) { + description = "Create a Windows installer for ${args.name} distro. " + + 'Requires Inno Setup (http://www.jrsoftware.org/isinfo.php).' + onlyIf { + conditions([!args.jrePath || !args.jrePath.empty, 'JRE not found'], + [exePresent('iscc') || exePresent('docker') || exePresent('nerdctl'), + 'InnoSetup or Docker not installed']) } + from layout.buildDirectory.file("innosetup/${args.name}/${installerBasename}.exe") + into base.distsDirectory + outputs.file installerWinExe + dependsOn genDistsTaskName } + tasks.register(signedTaskName, Exec) { group = 'omegat distribution' - inputs.file installerExe - outputs.file signedExe + inputs.file installerWinExe skipWhenEmpty() + outputs.file signedWinExe // Starting from Nov 2022, certification provider force to use HSM to // store private keys. Starting on June 1, 2023, at 00:00 UTC, industry // standards will require private keys for standard code signing @@ -1289,34 +1343,13 @@ ext.makeWinTask = { args -> // [exePresent('osslsigncode') || exePresent('docker') || exePresent('nerdctl'), // 'neither osslsigncode or docker/nerdctl is not installed']) } - def exe = exePresent('osslsigncode') ? 'osslsigncode' : file('ci/osslsigncode') - def envVars = [:] - def commandArgs = [exe, 'sign'] - if (project.hasProperty('pkcs11module')) { - commandArgs.addAll('-pkcs11module', project.property('pkcs11module')) - } - if (project.hasProperty('winCodesignCert')) { - commandArgs.addAll('-certs', project.property('winCodesignCert')) - } - if (project.hasProperty('pkcs11cert')) { - commandArgs.addAll('-pkcs11cert', project.property('pkcs11cert')) - } - if (project.hasProperty('winCodesignPassword')) { - commandArgs.addAll('-pass', project.property('winCodesignPassword')) - } - if (project.hasProperty('winCodesignDevice')) { - envVars['USBDEV'] = project.property('winCodesignDevice') + doFirst { + delete signedWinExe } - commandArgs.addAll( - '-t', project.hasProperty('winCodesignTimestampUrl') ? project.property('winCodesignTimestampUrl') : - 'http://time.certum.pl/', - '-n', application.applicationName, '-i', omtWebsite, '-h', 'sha256', - '-in', installerExe.get().asFile.toString(), - '-out', signedExe.get().asFile.toString() - ) - commandLine(commandArgs) + def envVars = [:] + commandLine(signedTaskCommandArgs()) environment(envVars) - dependsOn args.name + dependsOn distsTaskName } assemble.dependsOn args.name, signedTaskName win.dependsOn args.name, signedTaskName @@ -1354,18 +1387,17 @@ processResources { } tasks.register('checksums') { - def algos = ['SHA-512', 'MD5'] + def algos = ['SHA-512'] description = "Generate ${algos.join(', ')} checksums for distribution files" - inputs.files fileTree(dir: distsDir, exclude: 'checksums') - def checksumsDir = file("${distsDir}/checksums") - outputs.dir checksumsDir + inputs.files fileTree(dir: base.distsDirectory, exclude: 'checksums') + outputs.dir base.distsDirectory.dir('checksums') onlyIf { - condition(distsDir.directory, 'Distfiles not found') + condition(base.distsDirectory.get().asFile.directory, 'Distfiles not found') } doLast { - distsDir.listFiles().findAll { it.file }.each { f -> + base.distsDirectory.get().asFile.listFiles().findAll { it.file }.each { f -> algos.each { algo -> - ant.checksum file: f, algorithm: algo, todir: checksumsDir + ant.checksum file: f, algorithm: algo, todir: distsDirectory.dir('checksums').get().asFile } } } diff --git a/ci/azure-pipelines/build_steps.yml b/ci/azure-pipelines/build_steps.yml index 63494fc753..952419a582 100644 --- a/ci/azure-pipelines/build_steps.yml +++ b/ci/azure-pipelines/build_steps.yml @@ -31,7 +31,7 @@ steps: displayName: 'Preparation for build' - task: Gradle@3 inputs: - tasks: 'clean sourceDistZip distZip mac linux win' + tasks: 'clean sourceDistZip distZip mac linux win checksums' options: '--build-cache -PenvIsCi -PassetDir=$(System.ArtifactsDirectory)/asset' jdkVersionOption: '1.17' displayName: 'Build distribution packages and docs' diff --git a/ci/azure-pipelines/publish_release.yml b/ci/azure-pipelines/publish_release.yml index cb0a75e854..57891d1d1e 100644 --- a/ci/azure-pipelines/publish_release.yml +++ b/ci/azure-pipelines/publish_release.yml @@ -15,5 +15,5 @@ steps: dest=$(SOURCEFORGE_FILE_USER)@frs.sourceforge.net destdir="/home/frs/project/omegat/OmegaT\\ -\\ Latest/OmegaT\\ ${{ parameters.omegatVersion }}/" echo "mkdir $destdir" | SSHPASS=$(SOURCEFORGE_FILE_PASS) sshpass -e sftp -v $dest || true - SSHPASS=$(SOURCEFORGE_FILE_PASS) sshpass -e scp -v -oStrictHostKeyChecking=no $srcdir/* "$dest:$destdir" + SSHPASS=$(SOURCEFORGE_FILE_PASS) sshpass -e scp -r -v -oStrictHostKeyChecking=no $srcdir/* "$dest:$destdir" diff --git a/ci/azure-pipelines/publish_weekly.yml b/ci/azure-pipelines/publish_weekly.yml index f56c668cf6..a12368fccc 100644 --- a/ci/azure-pipelines/publish_weekly.yml +++ b/ci/azure-pipelines/publish_weekly.yml @@ -16,4 +16,4 @@ steps: dest=$(SOURCEFORGE_FILE_USER)@frs.sourceforge.net destdir=/home/frs/project/omegat/Weekly echo "mkdir $destdir" | SSHPASS=$(SOURCEFORGE_FILE_PASS) sshpass -e sftp -v $dest || true - SSHPASS=$(SOURCEFORGE_FILE_PASS) sshpass -e scp -v -oStrictHostKeyChecking=no $srcdir/* $dest:$destdir + SSHPASS=$(SOURCEFORGE_FILE_PASS) sshpass -e scp -r -v -oStrictHostKeyChecking=no $srcdir/* $dest:$destdir