Browse Source

Merge pull request #45 from JetBrains/application-plugin-fixes

Application plugin fixes
pull/49/head
Igor Demin 4 years ago committed by GitHub
parent
commit
6f6577a1ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      examples/codeviewer/README.md
  2. 4
      examples/codeviewer/build.gradle.kts
  3. 20
      examples/codeviewer/desktop/build.gradle.kts
  4. 16
      examples/imageviewer/README.md
  5. 5
      examples/imageviewer/build.gradle.kts
  6. 1
      examples/imageviewer/desktop/build.gradle.kts
  7. 13
      examples/issues/README.md
  8. 2
      examples/issues/build.gradle.kts
  9. 22
      examples/issues/desktop/build.gradle.kts
  10. 15
      examples/todoapp/README.md
  11. 4
      examples/todoapp/buildSrc/build.gradle.kts
  12. 20
      examples/todoapp/desktop/build.gradle.kts
  13. 2
      gradle-plugins/build.gradle.kts
  14. 11
      gradle-plugins/buildSrc/src/main/kotlin/BuildProperties.kt
  15. 47
      gradle-plugins/compose-desktop-application/build.gradle.kts
  16. 10
      gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/ComposeBasePlugin.kt
  17. 14
      gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/DesktopBasePlugin.kt
  18. 5
      gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/DesktopExtension.kt
  19. 16
      gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/TargetFormat.kt
  20. 32
      gradle-plugins/compose/build.gradle.kts
  21. 0
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposeExtension.kt
  22. 11
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt
  23. 20
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/DesktopExtension.kt
  24. 5
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/Application.kt
  25. 0
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/ConfigurationSource.kt
  26. 0
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/NativeDistributions.kt
  27. 0
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/PlatformSettings.kt
  28. 27
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/TargetFormat.kt
  29. 0
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/cliArgUtils.kt
  30. 119
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureApplication.kt
  31. 0
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/dslUtils.kt
  32. 0
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/osUtils.kt
  33. 2
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/wixToolset.kt
  34. 11
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/tasks/AbstractJPackageTask.kt
  35. 2
      gradle-plugins/gradle.properties
  36. 3
      gradle-plugins/settings.gradle.kts
  37. 3
      templates/desktop-template/README.md
  38. 15
      templates/desktop-template/build.gradle.kts
  39. 2
      templates/desktop-template/settings.gradle.kts
  40. 3
      templates/multiplatform-template/README.md
  41. 2
      templates/multiplatform-template/build.gradle.kts
  42. 16
      templates/multiplatform-template/desktop/build.gradle.kts
  43. 12
      tutorials/Native_distributions_and_local_execution/README.md

18
examples/codeviewer/README.md

@ -1,7 +1,17 @@
MPP Code Viewer example for desktop/android written in Multiplatform Compose library.
To run desktop application execute in a terminal:
`./gradlew desktop:run`
### Running desktop application
```
./gradlew :desktop:run
```
To install android application on device/emulator:
'./gradlew installDebug'
### Building native desktop distribution
```
./gradlew :desktop:package
# outputs are written to desktop/build/compose/binaries
```
### Installing Android application on device/emulator
```
./gradlew installDebug
```

4
examples/codeviewer/build.gradle.kts

@ -1,5 +1,7 @@
buildscript {
repositories {
// TODO: remove after new build is published
mavenLocal()
google()
jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
@ -16,6 +18,8 @@ buildscript {
allprojects {
repositories {
// TODO: remove after new build is published
mavenLocal()
google()
jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")

20
examples/codeviewer/desktop/build.gradle.kts

@ -1,10 +1,9 @@
import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22)
id("org.jetbrains.compose")
java
application
}
kotlin {
@ -22,6 +21,19 @@ kotlin {
}
}
application {
mainClassName = "org.jetbrains.codeviewer.MainKt"
compose.desktop {
application {
mainClass = "org.jetbrains.codeviewer.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "ComposeCodeViewer"
windows {
menu = true
// see https://wixtoolset.org/documentation/manual/v3/howtos/general/generate_guids.html
upgradeUuid = "AF792DA6-2EA3-495A-95E5-C3C6CBCB9948"
}
}
}
}

16
examples/imageviewer/README.md

@ -1,4 +1,16 @@
An example of image gallery for remote server image viewing, based on Jetpack Compose UI library (desktop and android).
To run desktop application execute in terminal: ./gradlew desktop:run
To run android application you will need to open project in Intellij IDEA or Android Studio and run "android" configuration
### Running desktop application
```
./gradlew :desktop:run
```
### Building native desktop distribution
```
./gradlew :desktop:package
# outputs are written to desktop/build/compose/binaries
```
### Running Android application
Open project in IntelliJ IDEA or Android Studio and run "android" configuration.

5
examples/imageviewer/build.gradle.kts

@ -1,5 +1,9 @@
buildscript {
repositories {
// TODO: remove after new build is published
mavenLocal().mavenContent {
includeModule("org.jetbrains.compose", "compose-gradle-plugin")
}
google()
jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
@ -7,7 +11,6 @@ buildscript {
dependencies {
classpath("org.jetbrains.compose:compose-gradle-plugin:0.1.0-m1-build57")
classpath("org.jetbrains.compose:compose-desktop-application-gradle-plugin:0.1.0-m1-build57")
classpath("com.android.tools.build:gradle:4.0.1")
classpath(kotlin("gradle-plugin", version = "1.4.0"))
}

1
examples/imageviewer/desktop/build.gradle.kts

@ -4,7 +4,6 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22)
id("org.jetbrains.compose")
id("org.jetbrains.compose.desktop.application")
}
kotlin {

13
examples/issues/README.md

@ -1,4 +1,13 @@
Github Issues viewer example written in Jetpack Compose UI library.
To run desktop application execute in terminal:
`./gradlew run`
### Running desktop application
```
./gradlew :desktop:run
```
### Building native desktop distribution
```
./gradlew :desktop:package
# outputs are written to desktop/build/compose/binaries
```

2
examples/issues/build.gradle.kts

@ -1,5 +1,7 @@
buildscript {
repositories {
// TODO: remove after new build is published
mavenLocal()
google()
jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")

22
examples/issues/desktop/build.gradle.kts

@ -1,10 +1,9 @@
import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22)
id("org.jetbrains.compose")
java
application
}
kotlin {
@ -21,6 +20,19 @@ kotlin {
}
}
application {
mainClassName = "androidx.ui.examples.jetissues.MainKt"
}
compose.desktop {
application {
mainClass = "androidx.ui.examples.jetissues.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "IssuesViewer"
windows {
menu = true
// see https://wixtoolset.org/documentation/manual/v3/howtos/general/generate_guids.html
upgradeUuid = "6565BEAD-713A-4DE7-A469-6B10FC4A6861"
}
}
}
}

15
examples/todoapp/README.md

@ -23,6 +23,17 @@ Features:
- View state is preserved when navigating between screens, Android configuration change, etc.
- Model-View-Intent (aka MVI) architectural pattern
To run the desktop application execute the following command: `./gradlew desktop:run`.
### Running desktop application
```
./gradlew :desktop:run
```
To run the Android application you will need to open the project in Intellij IDEA or Android Studio and run "android" configuration.
### Building native desktop distribution
```
./gradlew :desktop:package
# outputs are written to desktop/build/compose/binaries
```
### Running Android application
Open project in Intellij IDEA or Android Studio and run "android" configuration.

4
examples/todoapp/buildSrc/build.gradle.kts

@ -4,6 +4,8 @@ plugins {
}
repositories {
// TODO: remove after new build is published
mavenLocal()
google()
jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
@ -11,6 +13,8 @@ repositories {
buildscript {
repositories {
// TODO: remove after new build is published
mavenLocal()
google()
jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")

20
examples/todoapp/desktop/build.gradle.kts

@ -1,10 +1,9 @@
import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22)
id("org.jetbrains.compose")
java
application
}
kotlin {
@ -29,6 +28,19 @@ kotlin {
}
}
application {
mainClassName = "example.todo.desktop.MainKt"
compose.desktop {
application {
mainClass = "example.todo.desktop.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "ComoseDesktopTodo"
windows {
menuGroup = "Compose Examples"
// see https://wixtoolset.org/documentation/manual/v3/howtos/general/generate_guids.html
upgradeUuid = "BF9CDA6A-1391-46D5-9ED5-383D6E68CCEB"
}
}
}
}

2
gradle-plugins/build.gradle.kts

@ -8,7 +8,7 @@ plugins {
subprojects {
group = BuildProperties.group
version = BuildProperties.version
version = BuildProperties.deployVersion(project)
repositories {
maven("https://dl.bintray.com/kotlin/kotlin-dev")

11
gradle-plugins/buildSrc/src/main/kotlin/BuildProperties.kt

@ -1,11 +1,14 @@
import org.gradle.api.Project
// "Global" properties
object BuildProperties {
const val name = "JetBrains Compose Plugin"
const val group = "org.jetbrains.compose"
const val website = "https://jetbrains.org/compose"
const val vcs = "https://github.com/JetBrains/compose-jb"
val composeVersion: String
get() = System.getenv("COMPOSE_GRADLE_PLUGIN_COMPOSE_VERSION") ?: "0.1.0-SNAPSHOT"
val version: String
get() = System.getenv("COMPOSE_GRADLE_PLUGIN_VERSION") ?: composeVersion
fun composeVersion(project: Project): String =
project.findProperty("compose.version") as? String
?: System.getenv("COMPOSE_GRADLE_PLUGIN_COMPOSE_VERSION")
?: "0.1.0-SNAPSHOT"
fun deployVersion(project: Project): String = System.getenv("COMPOSE_GRADLE_PLUGIN_VERSION") ?: composeVersion(project)
}

47
gradle-plugins/compose-desktop-application/build.gradle.kts

@ -1,47 +0,0 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
kotlin("jvm")
id("com.gradle.plugin-publish")
id("java-gradle-plugin")
id("maven-publish")
id("com.github.johnrengelman.shadow") version "6.1.0"
}
gradlePluginConfig {
pluginId = "org.jetbrains.compose.desktop.application"
artifactId = "compose-desktop-application-gradle-plugin"
displayName = "JetBrains Compose Desktop Application Plugin"
description = "Plugin for creating native distributions and run configurations"
implementationClass = "org.jetbrains.compose.desktop.application.ApplicationPlugin"
}
val embedded by configurations.creating
dependencies {
fun embeddedCompileOnly(dep: String) {
compileOnly(dep)
embedded(dep)
}
compileOnly(gradleApi())
compileOnly(kotlin("gradle-plugin-api"))
compileOnly(kotlin("gradle-plugin"))
// include relocated download task to avoid potential runtime conflicts
embeddedCompileOnly("de.undercouch:gradle-download-task:4.1.1")
}
val shadow = tasks.named<ShadowJar>("shadowJar") {
val fromPackage = "de.undercouch"
val toPackage = "org.jetbrains.compose.$fromPackage"
relocate(fromPackage, toPackage)
archiveClassifier.set("shadow")
configurations = listOf(embedded)
exclude("META-INF/gradle-plugins/de.undercouch.download.properties")
}
val jar = tasks.named<Jar>("jar") {
dependsOn(shadow)
from(zipTree(shadow.get().archiveFile))
this.duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

10
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/ComposeBasePlugin.kt

@ -1,10 +0,0 @@
package org.jetbrains.compose
import org.gradle.api.Plugin
import org.gradle.api.Project
open class ComposeBasePlugin : Plugin<Project> {
override fun apply(project: Project) {
project.extensions.create("compose", ComposeExtension::class.java)
}
}

14
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/DesktopBasePlugin.kt

@ -1,14 +0,0 @@
package org.jetbrains.compose.desktop
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.compose.ComposeBasePlugin
import org.jetbrains.compose.ComposeExtension
open class DesktopBasePlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.apply(ComposeBasePlugin::class.java)
val composeExt = project.extensions.getByType(ComposeExtension::class.java)
composeExt.extensions.create("desktop", DesktopExtension::class.java)
}
}

5
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/DesktopExtension.kt

@ -1,5 +0,0 @@
package org.jetbrains.compose.desktop
import org.gradle.api.plugins.ExtensionAware
abstract class DesktopExtension : ExtensionAware

16
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/TargetFormat.kt

@ -1,16 +0,0 @@
package org.jetbrains.compose.desktop.application.dsl
import org.jetbrains.compose.desktop.application.internal.OS
enum class TargetFormat(
internal val id: String,
internal val os: OS
) {
Deb("deb", OS.Linux),
Rpm("rpm", OS.Linux),
App("app-image", OS.MacOS),
Dmg("dmg", OS.MacOS),
Pkg("pkg", OS.MacOS),
Exe("exe", OS.Windows),
Msi("msi", OS.Windows)
}

32
gradle-plugins/compose/build.gradle.kts

@ -1,9 +1,12 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
kotlin("jvm")
id("de.fuerstenau.buildconfig")
id("com.gradle.plugin-publish")
id("java-gradle-plugin")
id("maven-publish")
id("com.github.johnrengelman.shadow") version "6.1.0"
}
gradlePluginConfig {
@ -17,12 +20,37 @@ gradlePluginConfig {
buildConfig {
packageName = "org.jetbrains.compose"
clsName = "ComposeBuildConfig"
buildConfigField("String", "composeVersion", BuildProperties.composeVersion)
buildConfigField("String", "composeVersion", BuildProperties.composeVersion(project))
}
val embedded by configurations.creating
dependencies {
compileOnly(gradleApi())
compileOnly(localGroovy())
compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin")
compileOnly(kotlin("gradle-plugin-api"))
compileOnly(kotlin("gradle-plugin"))
testImplementation(gradleTestKit())
fun embeddedCompileOnly(dep: String) {
compileOnly(dep)
embedded(dep)
}
// include relocated download task to avoid potential runtime conflicts
embeddedCompileOnly("de.undercouch:gradle-download-task:4.1.1")
}
val shadow = tasks.named<ShadowJar>("shadowJar") {
val fromPackage = "de.undercouch"
val toPackage = "org.jetbrains.compose.$fromPackage"
relocate(fromPackage, toPackage)
archiveClassifier.set("shadow")
configurations = listOf(embedded)
exclude("META-INF/gradle-plugins/de.undercouch.download.properties")
}
val jar = tasks.named<Jar>("jar") {
dependsOn(shadow)
from(zipTree(shadow.get().archiveFile))
this.duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

0
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/ComposeExtension.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposeExtension.kt

11
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt

@ -5,6 +5,8 @@ package org.jetbrains.compose
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.jetbrains.compose.desktop.DesktopExtension
import org.jetbrains.compose.desktop.application.internal.configureApplicationImpl
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@ -12,7 +14,16 @@ private val composeVersion get() = ComposeBuildConfig.composeVersion
class ComposePlugin : Plugin<Project> {
override fun apply(project: Project) {
val composeExtension = project.extensions.create("compose", ComposeExtension::class.java)
val desktopExtension = composeExtension.extensions.create("desktop", DesktopExtension::class.java)
project.afterEvaluate {
if (desktopExtension._isApplicationInitialized) {
// If application object was not accessed in a script,
// we want to avoid creating tasks like package, run, etc. to avoid conflicts with other plugins
configureApplicationImpl(project, desktopExtension.application)
}
project.dependencies.add(
"kotlinCompilerPluginClasspath",
"org.jetbrains.compose.compiler:compiler:$composeVersion"

20
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/DesktopExtension.kt

@ -0,0 +1,20 @@
package org.jetbrains.compose.desktop
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.ExtensionAware
import org.jetbrains.compose.desktop.application.dsl.Application
import javax.inject.Inject
abstract class DesktopExtension @Inject constructor(private val objectFactory: ObjectFactory) : ExtensionAware {
internal var _isApplicationInitialized = false
private set
val application: Application by lazy {
_isApplicationInitialized = true
objectFactory.newInstance(Application::class.java, "main")
}
fun application(fn: Application.() -> Unit) {
application.fn()
}
}

5
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/Application.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/Application.kt

@ -16,6 +16,9 @@ open class Application @Inject constructor(
objects: ObjectFactory
) {
internal var _configurationSource: ConfigurationSource? = null
private set
internal var _isDefaultConfigurationEnabled = true
private set
internal val _fromFiles = objects.fileCollection()
internal val _dependenciesTaskNames = ArrayList<String>()
@ -28,7 +31,7 @@ open class Application @Inject constructor(
_configurationSource = ConfigurationSource.KotlinMppTarget(from)
}
fun disableDefaultConfiguration() {
_configurationSource = null
_isDefaultConfigurationEnabled = false
}
fun fromFiles(vararg files: Any) {

0
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/ConfigurationSource.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/ConfigurationSource.kt

0
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/NativeDistributions.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/NativeDistributions.kt

0
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/PlatformSettings.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/PlatformSettings.kt

27
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/dsl/TargetFormat.kt

@ -0,0 +1,27 @@
package org.jetbrains.compose.desktop.application.dsl
import org.jetbrains.compose.desktop.application.internal.OS
import org.jetbrains.compose.desktop.application.internal.currentOS
enum class TargetFormat(
internal val id: String,
private vararg val compatibleOSs: OS
) {
AppImage("app-image", *OS.values()),
Deb("deb", OS.Linux),
Rpm("rpm", OS.Linux),
Dmg("dmg", OS.MacOS),
Pkg("pkg", OS.MacOS),
Exe("exe", OS.Windows),
Msi("msi", OS.Windows);
val isCompatibleWithCurrentOS: Boolean by lazy { isCompatibleWith(currentOS) }
internal fun isCompatibleWith(targetOS: OS): Boolean = targetOS in compatibleOSs
val fileExt: String
get() {
check(this != AppImage) { "$this cannot have a file extension" }
return ".$id"
}
}

0
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/cliArgUtils.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/cliArgUtils.kt

119
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/ApplicationPlugin.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureApplication.kt

@ -1,53 +1,33 @@
package org.jetbrains.compose.desktop.application
package org.jetbrains.compose.desktop.application.internal
import org.gradle.api.*
import org.gradle.api.file.FileCollection
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
import org.jetbrains.compose.ComposeExtension
import org.jetbrains.compose.desktop.DesktopBasePlugin
import org.jetbrains.compose.desktop.DesktopExtension
import org.jetbrains.compose.desktop.application.dsl.Application
import org.jetbrains.compose.desktop.application.dsl.ConfigurationSource
import org.jetbrains.compose.desktop.application.internal.OS
import org.jetbrains.compose.desktop.application.internal.configureWix
import org.jetbrains.compose.desktop.application.internal.currentOS
import org.jetbrains.compose.desktop.application.internal.provider
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import java.io.File
import java.util.*
private const val PLUGIN_ID = "org.jetbrains.compose.desktop.application"
// todo: multiple launchers
// todo: file associations
// todo: use workers
@Suppress("unused") // Gradle plugin entry point
open class ApplicationPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.apply(DesktopBasePlugin::class.java)
val composeExt = project.extensions.getByType(ComposeExtension::class.java)
val desktopExt = composeExt.extensions.getByType(DesktopExtension::class.java)
val mainApplication = project.objects.newInstance(Application::class.java, "main")
desktopExt.extensions.add("application", mainApplication)
project.plugins.withId("org.jetbrains.kotlin.jvm") {
val mainSourceSet = project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets.getByName("main")
mainApplication.from(mainSourceSet)
}
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
project.configureFromMppPlugin(mainApplication)
}
project.afterEvaluate {
project.configurePackagingTasks(listOf(mainApplication))
project.configureWix()
fun configureApplicationImpl(project: Project, app: Application) {
project.afterEvaluate {
if (app._isDefaultConfigurationEnabled) {
if (project.plugins.hasPlugin("org.jetbrains.kotlin.multiplatform")) {
project.configureFromMppPlugin(app)
} else if (project.plugins.hasPlugin("org.jetbrains.kotlin.jvm")) {
val mainSourceSet = project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets.getByName("main")
app.from(mainSourceSet)
}
}
project.configurePackagingTasks(listOf(app))
project.configureWix()
}
}
@ -60,7 +40,7 @@ internal fun Project.configureFromMppPlugin(mainApplication: Application) {
mainApplication.from(target)
isJvmTargetConfigured = true
} else {
logger.error("w: Default configuration for '$PLUGIN_ID' is disabled: " +
logger.error("w: Default configuration for Compose Desktop Application is disabled: " +
"multiple Kotlin JVM targets definitions are detected. " +
"Specify, which target to use by using `compose.desktop.application.from(kotlinMppTarget)`")
mainApplication.disableDefaultConfiguration()
@ -91,9 +71,44 @@ internal fun Project.configurePackagingTasks(app: Application): TaskProvider<Def
}
internal fun AbstractJPackageTask.configurePackagingTask(app: Application) {
enabled = (currentOS == targetOS)
enabled = targetFormat.isCompatibleWithCurrentOS
if (targetFormat != TargetFormat.AppImage) {
configurePlatformSettings(app)
}
app.nativeDistributions.let { executables ->
packageName.set(provider { executables.packageName ?: project.name })
packageDescription.set(provider { executables.description })
packageCopyright.set(provider { executables.copyright })
packageVendor.set(provider { executables.vendor })
packageVersion.set(provider {
executables.version
?: project.version.toString().takeIf { it != "unspecified" }
})
}
destinationDir.set(app.nativeDistributions.outputBaseDir.map { it.dir("${app.name}/${targetFormat.id}") })
javaHome.set(provider { app.javaHomeOrDefault() })
launcherMainJar.set(app.mainJar.orNull)
app._fromFiles.forEach { files.from(it) }
dependsOn(*app._dependenciesTaskNames.toTypedArray())
app._configurationSource?.let { configSource ->
dependsOn(configSource.jarTaskName)
files.from(configSource.runtimeClasspath)
launcherMainJar.set(app.mainJar.orElse(configSource.jarTask(project).flatMap { it.archiveFile }))
}
modules.set(provider { app.nativeDistributions.modules })
launcherMainClass.set(provider { app.mainClass })
launcherJvmArgs.set(provider { app.jvmArgs })
launcherArgs.set(provider { app.args })
}
val targetPlatformSettings = when (targetOS) {
internal fun AbstractJPackageTask.configurePlatformSettings(app: Application) {
when (currentOS) {
OS.Linux -> {
app.nativeDistributions.linux.also { linux ->
linuxShortcut.set(provider { linux.shortcut })
@ -130,40 +145,8 @@ internal fun AbstractJPackageTask.configurePackagingTask(app: Application) {
}
}
}
app.nativeDistributions.let { executables ->
packageName.set(provider { executables.packageName ?: project.name })
packageDescription.set(provider { executables.description })
packageCopyright.set(provider { executables.copyright })
packageVendor.set(provider { executables.vendor })
packageVersion.set(provider {
executables.version
?: project.version.toString().takeIf { it != "unspecified" }
})
}
destinationDir.set(app.nativeDistributions.outputBaseDir.map { it.dir("${app.name}/${targetFormat.id}") })
javaHome.set(provider { app.javaHomeOrDefault() })
launcherMainJar.set(app.mainJar.orNull)
app._fromFiles.forEach { files.from(it) }
dependsOn(*app._dependenciesTaskNames.toTypedArray())
app._configurationSource?.let { configSource ->
dependsOn(configSource.jarTaskName)
files.from(configSource.runtimeClasspath)
launcherMainJar.set(app.mainJar.orElse(configSource.jarTask(project).flatMap { it.archiveFile }))
}
modules.set(provider { app.nativeDistributions.modules })
launcherMainClass.set(provider { app.mainClass })
launcherJvmArgs.set(provider { app.jvmArgs })
launcherArgs.set(provider { app.args })
}
private fun AbstractJPackageTask.jarFromJarTaskByName(jarTaskName: String) =
project.tasks.named(jarTaskName).map { (it as Jar).archiveFile.get() }
private fun Project.configureRunTask(app: Application) {
project.tasks.composeTask<JavaExec>(taskName("run", app)) {
mainClass.set(provider { app.mainClass })

0
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/dslUtils.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/dslUtils.kt

0
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/osUtils.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/osUtils.kt

2
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/wixToolset.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/wixToolset.kt

@ -48,7 +48,7 @@ internal fun Project.configureWix() {
private fun Project.eachWindowsPackageTask(fn: AbstractJPackageTask.() -> Unit) {
tasks.withType(AbstractJPackageTask::class.java).configureEach { packageTask ->
if (packageTask.targetOS == OS.Windows) {
if (packageTask.targetFormat.isCompatibleWith(OS.Windows)) {
packageTask.fn()
}
}

11
gradle-plugins/compose-desktop-application/src/main/kotlin/org/jetbrains/compose/desktop/application/tasks/AbstractJPackageTask.kt → gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/tasks/AbstractJPackageTask.kt

@ -32,10 +32,6 @@ abstract class AbstractJPackageTask @Inject constructor(
objects: ObjectFactory,
providers: ProviderFactory
) : DefaultTask() {
@get:Input
internal val targetOS: OS
get() = targetFormat.os
@get:InputFiles
val files: ConfigurableFileCollection = objects.fileCollection()
@ -296,6 +292,13 @@ abstract class AbstractJPackageTask @Inject constructor(
exec.executable = jpackage.absolutePath
exec.setArgs(listOf("@${argsFile.absolutePath}"))
}.assertNormalExitValue()
val destinationDirFile = destinationDir.asFile.get()
val finalLocation = when (targetFormat) {
TargetFormat.AppImage -> destinationDirFile
else -> destinationDirFile.walk().first { it.isFile && it.name.endsWith(targetFormat.fileExt) }
}
logger.lifecycle("The distribution is written to ${finalLocation.canonicalPath}")
} finally {
tmpDir.deleteRecursively()
}

2
gradle-plugins/gradle.properties

@ -1,2 +1,4 @@
org.gradle.parallel=true
kotlin.code.style=official
#compose.version=0.1.0-m1-build57

3
gradle-plugins/settings.gradle.kts

@ -5,5 +5,4 @@ pluginManagement {
}
}
include(":compose")
include(":compose-desktop-application")
include(":compose")

3
templates/desktop-template/README.md

@ -1,5 +1,4 @@
Compose Desktop Application
- `./gradlew run` - run application
- `./gradlew install` - build application into `build/install`
- `./gradlew distZip` - build and create archive ready for distribution in `build/distributions/desktop.zip`
- `./gradlew package` - package native distribution into `build/compose/binaries`

15
templates/desktop-template/build.gradle.kts

@ -1,9 +1,9 @@
import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("jvm") version "1.4.0"
id("org.jetbrains.compose") version (System.getenv("COMPOSE_TEMPLATE_COMPOSE_VERSION") ?: "0.1.0-m1-build57")
application
}
repositories {
@ -15,6 +15,13 @@ dependencies {
implementation(compose.desktop.currentOs)
}
application {
mainClassName = "MainKt"
}
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "KotlinJvmComposeDesktopApplication"
}
}
}

2
templates/desktop-template/settings.gradle.kts

@ -1,5 +1,7 @@
pluginManagement {
repositories {
// TODO: remove after new build is published
mavenLocal()
gradlePluginPortal()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}

3
templates/multiplatform-template/README.md

@ -2,8 +2,7 @@ Compose Multiplatform Application
**Desktop**
- `./gradlew run` - run application
- `./gradlew install` - build application into `desktop/build/install`
- `./gradlew distZip` - build and create archive ready for distribution in `desktop/build/distributions/desktop.zip`
- `./gradlew package` - package native distribution into `build/compose/binaries`
**Android**
- `./gradlew installDebug` - install Android application on an Android device (on a real device or on an emulator)

2
templates/multiplatform-template/build.gradle.kts

@ -2,6 +2,8 @@ buildscript {
val composeVersion = System.getenv("COMPOSE_TEMPLATE_COMPOSE_VERSION") ?: "0.1.0-m1-build57"
repositories {
// TODO: remove after new build is published
mavenLocal()
google()
jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")

16
templates/multiplatform-template/desktop/build.gradle.kts

@ -1,10 +1,9 @@
import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22)
id("org.jetbrains.compose")
java
application
}
kotlin {
@ -21,6 +20,13 @@ kotlin {
}
}
application {
mainClassName = "MainKt"
}
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "KotlinMultiplatformComposeDesktopApplication"
}
}
}

12
tutorials/Native_distributions_and_local_execution/README.md

@ -5,10 +5,9 @@
In this tutorial, we'll show you how to create native distributions (installers/packages) for all the supported systems.
We will also demonstrate how to run an application locally with the same settings as for distributions.
## Desktop application Gradle plugin
## Gradle plugin
`org.jetbrains.compose.desktop.application`
simplifies the packaging of applications into native distributions and running an application locally.
`org.jetbrains.compose` Gradle plugin simplifies the packaging of applications into native distributions and running an application locally.
Currently, the plugin uses [jpackage](https://openjdk.java.net/jeps/343) for packaging self-contained applications.
## Basic usage
@ -26,7 +25,6 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("jvm")
id("org.jetbrains.compose")
id("org.jetbrains.compose.desktop.application")
}
dependencies {
@ -53,6 +51,8 @@ Tasks that are not compatible with the current OS are skipped by default.
aggregating all package tasks for an application.
* `run` is used to run an app locally. You need to define a `mainClass` — an fq-name of a class,
containing the `main` function.
Note, that the tasks are created only if the `application` block/property is used in a script.
After a build, output binaries can be found in `${project.buildDir}/compose/binaries`.
@ -144,7 +144,7 @@ If the default configuration is ambiguous or not sufficient, the plugin can be c
```kotlin
plugins {
kotlin("jvm")
id("org.jetbrains.compose.desktop.application")
id("org.jetbrains.compose")
}
val customSourceSet = sourceSets.create("customSourceSet")
@ -158,7 +158,7 @@ compose.desktop {
```kotlin
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose.desktop.application")
id("org.jetbrains.compose")
}
kotlin {

Loading…
Cancel
Save