@@ -256,12 +256,12 @@ tasks.register("copyJar", Copy::class) {
256256 from(tasks.jar).into(layout.buildDirectory.dir(" jmods" ))
257257}
258258
259- private fun runCmd (vararg args : String ): String {
259+ private fun runCmd (currentDir : File , vararg args : String ): String {
260260 println (" Executing command: ${args.joinToString(" " )} " )
261261
262262 val output = StringBuilder ()
263263 val process = ProcessBuilder (* args)
264- .directory(layout.projectDirectory.asFile )
264+ .directory(currentDir )
265265 .start()
266266
267267 // Print stdout
@@ -286,49 +286,72 @@ private fun runCmd(vararg args: String): String {
286286 return output.toString()
287287}
288288
289+ private fun runCmd (vararg args : String ): String {
290+ return runCmd(layout.projectDirectory.asFile, * args)
291+ }
292+
289293private fun codesign (file : File , useRuntimeEntitlement : Boolean = false) {
290- runCmd(
291- " codesign" ,
292- " -vvvv" ,
293- " --options" ,
294- " runtime" ,
295- " --entitlements" ,
296- if (useRuntimeEntitlement) {
297- " runtime-entitlements.plist"
298- } else {
299- " entitlements.plist"
300- },
301- " --timestamp" ,
302- " --force" ,
303- " --sign" ,
304- macDeveloperApplicationCertName,
305- file.absolutePath,
306- )
294+ if (currentOS == OS .MAC ) {
295+ runCmd(
296+ " codesign" ,
297+ " -vvvv" ,
298+ " --options" ,
299+ " runtime" ,
300+ " --entitlements" ,
301+ if (useRuntimeEntitlement) {
302+ " runtime-entitlements.plist"
303+ } else {
304+ " entitlements.plist"
305+ },
306+ " --timestamp" ,
307+ " --force" ,
308+ " --sign" ,
309+ macDeveloperApplicationCertName,
310+ file.absolutePath,
311+ )
312+ }
307313}
308314
309315private fun isCodesignable (file : File ): Boolean {
310- val excludedExtensions = setOf (" so" , " a" , " xml" )
311- return file.extension == " dylib" ||
312- file.extension == " jnilib" ||
313- (! excludedExtensions.contains(file.extension) && file.toPath().isExecutable())
316+ if (currentOS == OS .MAC ) {
317+ val excludedExtensions = setOf (" so" , " a" , " xml" )
318+ return file.extension == " dylib" ||
319+ file.extension == " jnilib" ||
320+ (! excludedExtensions.contains(file.extension) && file.toPath().isExecutable())
321+ } else if (currentOS == OS .WINDOWS ) {
322+ return file.extension == " dll"
323+ } else {
324+ throw Exception (" Unsupported OS: $currentOS " )
325+ }
326+ }
327+
328+ private fun isValidLibFile (file : File ): Boolean {
329+ if (currentOS == OS .MAC ) {
330+ return ! (
331+ file.absolutePath.contains(" darwin-x86-64" ) || // for libjnidispatch.jnilib
332+ file.absolutePath.contains(" x86_64" ) // for liblz4-java.dylib
333+ )
334+ } else if (currentOS == OS .WINDOWS ) {
335+ return ! (
336+ file.absolutePath.endsWith(" win32-aarch64\\ jnidispatch.dll" ) ||
337+ file.absolutePath.endsWith(" win32-x86\\ jnidispatch.dll" )
338+ )
339+ } else {
340+ throw Exception (" Unsupported OS: $currentOS " )
341+ }
314342}
315343
316344private fun codesignInJar (jarFile : File , nativeLibPath : File ) {
317- val tmpDir = createTempDirectory(" MacosCodesignLibsInJarsTask " ).toFile()
345+ val tmpDir = createTempDirectory(" codesignLibsInJarsTask " ).toFile()
318346 runCmd(" unzip" , " -q" , jarFile.absolutePath, " -d" , tmpDir.absolutePath)
319347
320348 tmpDir.walk()
321349 .filter { it.isFile && isCodesignable(it) }
322350 .forEach { libFile ->
323- println (" " )
324- codesign(libFile)
325-
326- if (
327- libFile.absolutePath.contains(" darwin-x86-64" ) || // for libjnidispatch.jnilib
328- libFile.absolutePath.contains(" x86_64" ) // for liblz4-java.dylib
329- ) {
330- // Skip the jna's x86-64 lib
331- } else {
351+
352+ if (isValidLibFile(libFile)) {
353+ println (" " )
354+ codesign(libFile)
332355 runCmd(" cp" , libFile.absolutePath, nativeLibPath.absolutePath)
333356 }
334357
@@ -344,7 +367,7 @@ private fun codesignInJar(jarFile: File, nativeLibPath: File) {
344367 tmpDir.deleteRecursively()
345368}
346369
347- tasks.register(" macosCodesignLibsInJars " ) {
370+ tasks.register(" codesignLibsInJars " ) {
348371 dependsOn(" copyDependencies" , " copyJar" )
349372 inputs.files(tasks.named(" copyJar" ).get().outputs.files)
350373
@@ -383,6 +406,7 @@ private fun removeQuarantine(file: File) {
383406}
384407
385408tasks.register(" macosCodesignProvisionprofile" ) {
409+ onlyIf { currentOS == OS .MAC }
386410 doLast {
387411 removeQuarantine(provisionprofileDir.file(" embedded.provisionprofile" ).asFile)
388412 codesign(provisionprofileDir.file(" embedded.provisionprofile" ).asFile)
@@ -393,7 +417,7 @@ tasks.register("macosCodesignProvisionprofile") {
393417}
394418
395419tasks.register<Exec >(" jlink" ) {
396- dependsOn(" assemble" , " macosCodesignLibsInJars " , " macosCodesignProvisionprofile" )
420+ dependsOn(" assemble" , " codesignLibsInJars " , " macosCodesignProvisionprofile" )
397421 val jlinkBin = Paths .get(System .getProperty(" java.home" ), " bin" , " jlink" )
398422
399423 inputs.files(tasks.named(" copyJar" ).get().outputs.files)
@@ -412,6 +436,7 @@ tasks.register<Exec>("jlink") {
412436}
413437
414438tasks.register(" prepareInfoPlist" ) {
439+ onlyIf { currentOS == OS .MAC }
415440 doLast {
416441 val template = layout.projectDirectory.file(" mac-resources/Info.plist.template" ).asFile.readText()
417442 val content = template
@@ -435,45 +460,78 @@ tasks.register("bareJpackage") {
435460 inputs.files(runtimeImage, modulePath)
436461
437462 val outputDir = layout.buildDirectory.dir(" bare-jpackage" )
438- val outputFile = outputDir.get().asFile.resolve(" ${appName} -$version .dmg" )
463+ val outputFile = if (currentOS == OS .MAC ) {
464+ outputDir.get().asFile.resolve(" ${appName} -$version .dmg" )
465+ } else if (currentOS == OS .WINDOWS ) {
466+ outputDir.get().asFile.resolve(" ${appName} -$version .msi" )
467+ } else {
468+ throw Exception (" Unsupported OS: $currentOS " )
469+ }
439470
440471 outputs.file(outputFile)
441472 outputDir.get().asFile.deleteRecursively()
442473
443- // -XstartOnFirstThread is required for MacOS
444- val maybeStartOnFirstThread = if (currentOS == OS .MAC ) {
445- " -XstartOnFirstThread"
446- } else {
447- " "
448- }
449-
450474 doLast {
451- runCmd(
452- jpackageBin.absolutePathString(),
475+ // -XstartOnFirstThread is required for MacOS
476+ val maybeStartOnFirstThread = if (currentOS == OS .MAC ) {
477+ " -XstartOnFirstThread"
478+ } else {
479+ " "
480+ }
481+
482+ val javaOptionsArg = listOf (
483+ " --java-options" ,
484+ // -Djava.library.path=$APPDIR/resources is needed because we put the needed dylibs, jnilibs, and dlls there.
485+ " $maybeStartOnFirstThread -Djava.electron.packaged=true -Djava.library.path=\$ APPDIR/resources --add-exports java.base/sun.security.x509=ALL-UNNAMED --add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED"
486+ )
487+
488+ val baseArgs = listOf (
453489 " --name" , appName,
454490 " --app-version" , version.toString(),
455491 " --main-jar" , modulePath.resolve(" ${project.name} -$version .jar" ).absolutePath,
456492 " --main-class" , mainClassName,
457493 " --runtime-image" , runtimeImage.absolutePath,
458494 " --input" , modulePath.absolutePath,
459495 " --dest" , outputDir.get().asFile.absolutePath,
460- " --mac-package-identifier" , packageIdentifier,
461- " --mac-package-name" , appName,
462- " --mac-sign" ,
463- " --mac-app-store" ,
464- " --mac-signing-key-user-name" , macDeveloperApplicationCertName,
465- " --mac-entitlements" , " entitlements.plist" ,
466- " --resource-dir" , layout.projectDirectory.dir(" mac-resources" ).asFile.absolutePath,
467- " --app-content" , provisionprofileDir.file(" embedded.provisionprofile" ).asFile.absolutePath,
468496 " --app-content" , layout.buildDirectory.file(" resources-native" ).get().asFile.resolve(" app" ).absolutePath,
469- " --java-options" ,
470- // -Djava.library.path=$APPDIR/resources is needed because we put all dylibs there.
471- " $maybeStartOnFirstThread -Djava.library.path=\$ APPDIR/resources --add-exports java.base/sun.security.x509=ALL-UNNAMED --add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED"
497+ ) + javaOptionsArg
498+
499+ val platformSpecificArgs = if (currentOS == OS .MAC ) {
500+ listOf (
501+ " --mac-package-identifier" ,
502+ packageIdentifier,
503+ " --mac-package-name" ,
504+ appName,
505+ " --mac-sign" ,
506+ " --mac-app-store" ,
507+ " --mac-signing-key-user-name" ,
508+ macDeveloperApplicationCertName,
509+ " --mac-entitlements" ,
510+ " entitlements.plist" ,
511+ " --resource-dir" ,
512+ layout.projectDirectory.dir(" mac-resources" ).asFile.absolutePath,
513+ " --app-content" ,
514+ provisionprofileDir.file(" embedded.provisionprofile" ).asFile.absolutePath,
515+ )
516+ } else if (currentOS == OS .WINDOWS ) {
517+ listOf (
518+ " --type" , " msi" ,
519+ " --win-menu" ,
520+ " --win-shortcut"
521+ )
522+ } else {
523+ throw Exception (" Unsupported OS: $currentOS " )
524+ }
525+
526+ runCmd(
527+ * ((listOf (jpackageBin.absolutePathString())
528+ + baseArgs + platformSpecificArgs).toTypedArray())
472529 )
473530 }
474531}
475532
476- tasks.register(" jpackage" ) {
533+ tasks.register(" jpackageForMac" ) {
534+ onlyIf { currentOS == OS .MAC }
477535 dependsOn(" bareJpackage" )
478536
479537 inputs.file(tasks.named(" bareJpackage" ).get().outputs.files.singleFile)
@@ -533,10 +591,43 @@ tasks.register("jpackage") {
533591 }
534592}
535593
594+
595+ tasks.register(" jpackageForWindows" ) {
596+ onlyIf { currentOS == OS .WINDOWS }
597+ dependsOn(" bareJpackage" )
598+
599+ inputs.file(tasks.named(" bareJpackage" ).get().outputs.files.singleFile)
600+
601+ val outputAppDir = layout.buildDirectory.dir(" msi" ).get().asFile
602+
603+ outputs.dir(outputAppDir)
604+
605+ doLast {
606+ outputAppDir.deleteRecursively()
607+ outputAppDir.mkdirs()
608+
609+ runCmd(
610+ File (" c:\\ Users\\ tanin\\ projects\\ CodeSignTool-v1.3.2-windows" ),
611+ " CodeSignTool.bat" ,
612+ " sign" ,
613+ " -input_file_path=${inputs.files.singleFile.absolutePath} " ,
614+ " -output_dir_path=${outputAppDir.absolutePath} " ,
615+ " -program_name=JavaElectron" ,
616+ " -username=${System .getenv(" SSL_COM_USERNAME" )} " ,
617+ " -password=${System .getenv(" SSL_COM_PASSWORD" )} " ,
618+ " -totp_secret=${System .getenv(" SSL_COM_TOTP_SECRET" )} "
619+ )
620+ }
621+ }
622+
623+ tasks.register(" jpackage" ) {
624+ dependsOn(" bareJpackage" , " jpackageForMac" , " jpackageForWindows" )
625+ }
626+
536627tasks.register<Exec >(" notarize" ) {
537- dependsOn(" jpackage " )
628+ dependsOn(" jpackageForMac " )
538629
539- inputs.file(tasks.named(" jpackage " ).get().outputs.files.filter { it.extension == " dmg" }.first())
630+ inputs.file(tasks.named(" jpackageForMac " ).get().outputs.files.filter { it.extension == " dmg" }.first())
540631
541632 commandLine(
542633 " /usr/bin/xcrun" ,
@@ -554,7 +645,7 @@ tasks.register<Exec>("notarize") {
554645tasks.register<Exec >(" staple" ) {
555646 dependsOn(" notarize" )
556647
557- inputs.file(tasks.named(" jpackage " ).get().outputs.files.filter { it.extension == " dmg" }.first())
648+ inputs.file(tasks.named(" jpackageForMac " ).get().outputs.files.filter { it.extension == " dmg" }.first())
558649
559650 commandLine(
560651 " /usr/bin/xcrun" ,
@@ -566,8 +657,8 @@ tasks.register<Exec>("staple") {
566657}
567658
568659tasks.register<Exec >(" convertToPkg" ) {
569- dependsOn(" jpackage " )
570- val app = tasks.named(" jpackage " ).get().outputs.files.filter { it.extension == " app" }.first()
660+ dependsOn(" jpackageForMac " )
661+ val app = tasks.named(" jpackageForMac " ).get().outputs.files.filter { it.extension == " app" }.first()
571662 inputs.dir(app)
572663 outputs.file(layout.buildDirectory.dir(" pkg" ).get().file(" Backdoor.pkg" ))
573664 commandLine(
0 commit comments