Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ abstract class AbstractDistributions {
var description: String? = null
var vendor: String? = null
val appResourcesRootDir: DirectoryProperty = objects.directoryProperty()

/**
* Root directory for files passed to the underlying packaging tool (jpackage)
* via `--resource-dir`, used to override the tool's own packaging resources (e.g.
* a `<package-name>-volume.icns` DMG volume icon, a DMG background, Linux
* `preinst`/`postinst` scripts, or WiX templates). See
* https://docs.oracle.com/en/java/javase/21/jpackage/override-jpackage-resources.html
*
* Files are resolved from `common`, `<os>` and `<os>-<arch>` subdirectories, the
* same layout as [appResourcesRootDir]. The generated `Info.plist` and
* `product-def.plist` are managed by Compose and always take precedence.
*/
val packagingResourcesRootDir: DirectoryProperty = objects.directoryProperty()

val licenseFile: RegularFileProperty = objects.fileProperty()

var targetFormats: Set<TargetFormat> = EnumSet.noneOf(TargetFormat::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ private fun JvmApplicationContext.configurePackageTask(
packageTask.packageVendor.set(packageTask.provider { executables.vendor })
packageTask.packageVersion.set(packageVersionFor(packageTask.targetFormat))
packageTask.licenseFile.set(executables.licenseFile)
packageTask.packagingResourcesRootDir.set(executables.packagingResourcesRootDir)
}

packageTask.destinationDir.set(app.nativeDistributions.outputBaseDir.map {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,11 @@ abstract class AbstractJPackageTask @Inject constructor(
@get:Internal
val appResourcesDir: DirectoryProperty = objects.directoryProperty()

@get:InputDirectory
@get:Optional
@get:PathSensitive(PathSensitivity.RELATIVE)
val packagingResourcesRootDir: DirectoryProperty = objects.directoryProperty()

@get:Internal
private val libsMappingFile: Provider<RegularFile> = workingDir.map {
it.file("libs-mapping.txt")
Expand Down Expand Up @@ -607,6 +612,7 @@ abstract class AbstractJPackageTask @Inject constructor(
}

fileOperations.clearDirs(jpackageResources)
copyUserPackagingResources()
if (currentOS == OS.MacOS) {
InfoPlistBuilder(macExtraPlistKeysRawXml.orNull)
.also { setInfoPlistValues(it) }
Expand All @@ -626,6 +632,33 @@ abstract class AbstractJPackageTask @Inject constructor(
}
}

/**
* Copies user-supplied packaging override resources into [jpackageResources]
* (the `--resource-dir` passed to jpackage). Files are taken from the `common`,
* `<os>` and `<os>-<arch>` subdirectories of [packagingResourcesRootDir], mirroring
* the layout of `appResourcesRootDir`. Called after [jpackageResources] is cleared
* but before the generated `Info.plist`/`product-def.plist` are written, so those
* Compose-managed files always win over anything the user drops in.
*/
private fun copyUserPackagingResources() {
val rootDir = packagingResourcesRootDir.ioFileOrNull ?: return
val destDir = jpackageResources.ioFile
for (subDirName in listOf("common", currentOS.id, currentTarget.id)) {
val sourceDir = rootDir.resolve(subDirName)
if (!sourceDir.isDirectory) continue
for (file in sourceDir.walk()) {
val relPath = file.relativeTo(sourceDir).path
if (relPath.isEmpty()) continue
val destFile = destDir.resolve(relPath)
if (file.isDirectory) {
fileOperations.mkdirs(destFile)
} else {
file.copyTo(destFile, overwrite = true)
}
}
}
}

override fun jvmToolEnvironment(): MutableMap<String, String> =
super.jvmToolEnvironment().apply {
if (currentOS == OS.Windows) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,19 @@ class DesktopApplicationTest : GradlePluginTestBase() {
}
}

@Test
fun packagingResources() = with(testProject("application/packagingResources")) {
gradle(":createDistributable").checks {
check.taskSuccessful(":createDistributable")

// Files from packagingResourcesRootDir must be copied into the
// directory passed to jpackage via --resource-dir, for both the
// `common` and the current-OS subdirectories.
file("build/compose/tmp/resources/common-packaging-resource.txt").checkExists()
file("build/compose/tmp/resources/os-specific-packaging-resource.txt").checkExists()
}
}

@Test
fun testWixUnzip() {
Assumptions.assumeTrue(currentOS == OS.Windows) { "The test is only relevant for Windows" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat

plugins {
id "org.jetbrains.kotlin.jvm"
id "org.jetbrains.kotlin.plugin.compose"
id "org.jetbrains.compose"
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib"
implementation compose.desktop.currentOs
}

compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageVersion = "1.0.0"

packagingResourcesRootDir.set(project.layout.projectDirectory.dir("packaging-resources"))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
common packaging resource
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
linux only packaging resource
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
macos only packaging resource
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
windows only packaging resource
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
pluginManagement {
plugins {
id 'org.jetbrains.kotlin.jvm' version 'KOTLIN_VERSION_PLACEHOLDER'
id 'org.jetbrains.kotlin.plugin.compose' version 'KOTLIN_VERSION_PLACEHOLDER'
id 'org.jetbrains.compose' version 'COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER'
}
repositories {
mavenLocal()
gradlePluginPortal()
mavenCentral()
google()
maven {
url 'https://packages.jetbrains.team/maven/p/cmp/dev'
}
}
}
dependencyResolutionManagement {
repositories {
mavenCentral()
google()
maven {
url 'https://packages.jetbrains.team/maven/p/cmp/dev'
}
mavenLocal()
}
}
rootProject.name = "packagingResources"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fun main() {
println("Hello, world!")
}