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. 18
      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. 18
      examples/issues/desktop/build.gradle.kts
  10. 15
      examples/todoapp/README.md
  11. 4
      examples/todoapp/buildSrc/build.gradle.kts
  12. 18
      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. 113
      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. 1
      gradle-plugins/settings.gradle.kts
  37. 3
      templates/desktop-template/README.md
  38. 11
      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. 12
      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. MPP Code Viewer example for desktop/android written in Multiplatform Compose library.
To run desktop application execute in a terminal: ### Running desktop application
`./gradlew desktop:run` ```
./gradlew :desktop:run
```
To install android application on device/emulator: ### Building native desktop distribution
'./gradlew installDebug' ```
./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 { buildscript {
repositories { repositories {
// TODO: remove after new build is published
mavenLocal()
google() google()
jcenter() jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
@ -16,6 +18,8 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
// TODO: remove after new build is published
mavenLocal()
google() google()
jcenter() jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")

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

@ -1,10 +1,9 @@
import org.jetbrains.compose.compose import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins { plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22) 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")
java
application
} }
kotlin { kotlin {
@ -22,6 +21,19 @@ kotlin {
} }
} }
compose.desktop {
application { application {
mainClassName = "org.jetbrains.codeviewer.MainKt" 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). 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 ### Running desktop application
To run android application you will need to open project in Intellij IDEA or Android Studio and run "android" configuration ```
./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 { buildscript {
repositories { repositories {
// TODO: remove after new build is published
mavenLocal().mavenContent {
includeModule("org.jetbrains.compose", "compose-gradle-plugin")
}
google() google()
jcenter() jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
@ -7,7 +11,6 @@ buildscript {
dependencies { dependencies {
classpath("org.jetbrains.compose:compose-gradle-plugin:0.1.0-m1-build57") 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("com.android.tools.build:gradle:4.0.1")
classpath(kotlin("gradle-plugin", version = "1.4.0")) 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 { plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22) 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")
id("org.jetbrains.compose.desktop.application")
} }
kotlin { kotlin {

13
examples/issues/README.md

@ -1,4 +1,13 @@
Github Issues viewer example written in Jetpack Compose UI library. 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 { buildscript {
repositories { repositories {
// TODO: remove after new build is published
mavenLocal()
google() google()
jcenter() jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")

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

@ -1,10 +1,9 @@
import org.jetbrains.compose.compose import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins { plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22) 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")
java
application
} }
kotlin { kotlin {
@ -21,6 +20,19 @@ kotlin {
} }
} }
compose.desktop {
application { application {
mainClassName = "androidx.ui.examples.jetissues.MainKt" 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. - View state is preserved when navigating between screens, Android configuration change, etc.
- Model-View-Intent (aka MVI) architectural pattern - 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 { repositories {
// TODO: remove after new build is published
mavenLocal()
google() google()
jcenter() jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
@ -11,6 +13,8 @@ repositories {
buildscript { buildscript {
repositories { repositories {
// TODO: remove after new build is published
mavenLocal()
google() google()
jcenter() jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")

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

@ -1,10 +1,9 @@
import org.jetbrains.compose.compose import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins { plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22) 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")
java
application
} }
kotlin { kotlin {
@ -29,6 +28,19 @@ kotlin {
} }
} }
compose.desktop {
application { application {
mainClassName = "example.todo.desktop.MainKt" 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 { subprojects {
group = BuildProperties.group group = BuildProperties.group
version = BuildProperties.version version = BuildProperties.deployVersion(project)
repositories { repositories {
maven("https://dl.bintray.com/kotlin/kotlin-dev") 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 // "Global" properties
object BuildProperties { object BuildProperties {
const val name = "JetBrains Compose Plugin" const val name = "JetBrains Compose Plugin"
const val group = "org.jetbrains.compose" const val group = "org.jetbrains.compose"
const val website = "https://jetbrains.org/compose" const val website = "https://jetbrains.org/compose"
const val vcs = "https://github.com/JetBrains/compose-jb" const val vcs = "https://github.com/JetBrains/compose-jb"
val composeVersion: String fun composeVersion(project: Project): String =
get() = System.getenv("COMPOSE_GRADLE_PLUGIN_COMPOSE_VERSION") ?: "0.1.0-SNAPSHOT" project.findProperty("compose.version") as? String
val version: String ?: System.getenv("COMPOSE_GRADLE_PLUGIN_COMPOSE_VERSION")
get() = System.getenv("COMPOSE_GRADLE_PLUGIN_VERSION") ?: composeVersion ?: "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 { plugins {
kotlin("jvm") kotlin("jvm")
id("de.fuerstenau.buildconfig") id("de.fuerstenau.buildconfig")
id("com.gradle.plugin-publish") id("com.gradle.plugin-publish")
id("java-gradle-plugin") id("java-gradle-plugin")
id("maven-publish") id("maven-publish")
id("com.github.johnrengelman.shadow") version "6.1.0"
} }
gradlePluginConfig { gradlePluginConfig {
@ -17,12 +20,37 @@ gradlePluginConfig {
buildConfig { buildConfig {
packageName = "org.jetbrains.compose" packageName = "org.jetbrains.compose"
clsName = "ComposeBuildConfig" clsName = "ComposeBuildConfig"
buildConfigField("String", "composeVersion", BuildProperties.composeVersion) buildConfigField("String", "composeVersion", BuildProperties.composeVersion(project))
} }
val embedded by configurations.creating
dependencies { dependencies {
compileOnly(gradleApi()) compileOnly(gradleApi())
compileOnly(localGroovy()) compileOnly(localGroovy())
compileOnly("org.jetbrains.kotlin:kotlin-gradle-plugin") compileOnly(kotlin("gradle-plugin-api"))
compileOnly(kotlin("gradle-plugin"))
testImplementation(gradleTestKit()) 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.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.dsl.DependencyHandler 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.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@ -12,7 +14,16 @@ private val composeVersion get() = ComposeBuildConfig.composeVersion
class ComposePlugin : Plugin<Project> { class ComposePlugin : Plugin<Project> {
override fun apply(project: 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 { 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( project.dependencies.add(
"kotlinCompilerPluginClasspath", "kotlinCompilerPluginClasspath",
"org.jetbrains.compose.compiler:compiler:$composeVersion" "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 objects: ObjectFactory
) { ) {
internal var _configurationSource: ConfigurationSource? = null internal var _configurationSource: ConfigurationSource? = null
private set
internal var _isDefaultConfigurationEnabled = true
private set
internal val _fromFiles = objects.fileCollection() internal val _fromFiles = objects.fileCollection()
internal val _dependenciesTaskNames = ArrayList<String>() internal val _dependenciesTaskNames = ArrayList<String>()
@ -28,7 +31,7 @@ open class Application @Inject constructor(
_configurationSource = ConfigurationSource.KotlinMppTarget(from) _configurationSource = ConfigurationSource.KotlinMppTarget(from)
} }
fun disableDefaultConfiguration() { fun disableDefaultConfiguration() {
_configurationSource = null _isDefaultConfigurationEnabled = false
} }
fun fromFiles(vararg files: Any) { 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

113
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,55 +1,35 @@
package org.jetbrains.compose.desktop.application package org.jetbrains.compose.desktop.application.internal
import org.gradle.api.* import org.gradle.api.*
import org.gradle.api.file.FileCollection
import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.TaskProvider 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.Application
import org.jetbrains.compose.desktop.application.dsl.ConfigurationSource import org.jetbrains.compose.desktop.application.dsl.TargetFormat
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.tasks.AbstractJPackageTask import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension 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.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import java.io.File import java.io.File
import java.util.* import java.util.*
private const val PLUGIN_ID = "org.jetbrains.compose.desktop.application"
// todo: multiple launchers // todo: multiple launchers
// todo: file associations // todo: file associations
// todo: use workers // todo: use workers
@Suppress("unused") // Gradle plugin entry point fun configureApplicationImpl(project: Project, app: Application) {
open class ApplicationPlugin : Plugin<Project> { project.afterEvaluate {
override fun apply(project: Project) { if (app._isDefaultConfigurationEnabled) {
project.plugins.apply(DesktopBasePlugin::class.java) if (project.plugins.hasPlugin("org.jetbrains.kotlin.multiplatform")) {
val composeExt = project.extensions.getByType(ComposeExtension::class.java) project.configureFromMppPlugin(app)
val desktopExt = composeExt.extensions.getByType(DesktopExtension::class.java) } else if (project.plugins.hasPlugin("org.jetbrains.kotlin.jvm")) {
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") val mainSourceSet = project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets.getByName("main")
mainApplication.from(mainSourceSet) app.from(mainSourceSet)
} }
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
project.configureFromMppPlugin(mainApplication)
} }
project.afterEvaluate { project.configurePackagingTasks(listOf(app))
project.configurePackagingTasks(listOf(mainApplication))
project.configureWix() project.configureWix()
} }
} }
}
internal fun Project.configureFromMppPlugin(mainApplication: Application) { internal fun Project.configureFromMppPlugin(mainApplication: Application) {
val kotlinExt = extensions.getByType(KotlinMultiplatformExtension::class.java) val kotlinExt = extensions.getByType(KotlinMultiplatformExtension::class.java)
@ -60,7 +40,7 @@ internal fun Project.configureFromMppPlugin(mainApplication: Application) {
mainApplication.from(target) mainApplication.from(target)
isJvmTargetConfigured = true isJvmTargetConfigured = true
} else { } 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. " + "multiple Kotlin JVM targets definitions are detected. " +
"Specify, which target to use by using `compose.desktop.application.from(kotlinMppTarget)`") "Specify, which target to use by using `compose.desktop.application.from(kotlinMppTarget)`")
mainApplication.disableDefaultConfiguration() mainApplication.disableDefaultConfiguration()
@ -91,9 +71,44 @@ internal fun Project.configurePackagingTasks(app: Application): TaskProvider<Def
} }
internal fun AbstractJPackageTask.configurePackagingTask(app: Application) { 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 -> { OS.Linux -> {
app.nativeDistributions.linux.also { linux -> app.nativeDistributions.linux.also { linux ->
linuxShortcut.set(provider { linux.shortcut }) 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) { private fun Project.configureRunTask(app: Application) {
project.tasks.composeTask<JavaExec>(taskName("run", app)) { project.tasks.composeTask<JavaExec>(taskName("run", app)) {
mainClass.set(provider { app.mainClass }) 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) { private fun Project.eachWindowsPackageTask(fn: AbstractJPackageTask.() -> Unit) {
tasks.withType(AbstractJPackageTask::class.java).configureEach { packageTask -> tasks.withType(AbstractJPackageTask::class.java).configureEach { packageTask ->
if (packageTask.targetOS == OS.Windows) { if (packageTask.targetFormat.isCompatibleWith(OS.Windows)) {
packageTask.fn() 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, objects: ObjectFactory,
providers: ProviderFactory providers: ProviderFactory
) : DefaultTask() { ) : DefaultTask() {
@get:Input
internal val targetOS: OS
get() = targetFormat.os
@get:InputFiles @get:InputFiles
val files: ConfigurableFileCollection = objects.fileCollection() val files: ConfigurableFileCollection = objects.fileCollection()
@ -296,6 +292,13 @@ abstract class AbstractJPackageTask @Inject constructor(
exec.executable = jpackage.absolutePath exec.executable = jpackage.absolutePath
exec.setArgs(listOf("@${argsFile.absolutePath}")) exec.setArgs(listOf("@${argsFile.absolutePath}"))
}.assertNormalExitValue() }.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 { } finally {
tmpDir.deleteRecursively() tmpDir.deleteRecursively()
} }

2
gradle-plugins/gradle.properties

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

1
gradle-plugins/settings.gradle.kts

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

3
templates/desktop-template/README.md

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

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

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

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

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

3
templates/multiplatform-template/README.md

@ -2,8 +2,7 @@ Compose Multiplatform Application
**Desktop** **Desktop**
- `./gradlew run` - run application - `./gradlew run` - run application
- `./gradlew install` - build application into `desktop/build/install` - `./gradlew package` - package native distribution into `build/compose/binaries`
- `./gradlew distZip` - build and create archive ready for distribution in `desktop/build/distributions/desktop.zip`
**Android** **Android**
- `./gradlew installDebug` - install Android application on an Android device (on a real device or on an emulator) - `./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" val composeVersion = System.getenv("COMPOSE_TEMPLATE_COMPOSE_VERSION") ?: "0.1.0-m1-build57"
repositories { repositories {
// TODO: remove after new build is published
mavenLocal()
google() google()
jcenter() jcenter()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")

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

@ -1,10 +1,9 @@
import org.jetbrains.compose.compose import org.jetbrains.compose.compose
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins { plugins {
kotlin("multiplatform") // kotlin("jvm") doesn't work well in IDEA/AndroidStudio (https://github.com/JetBrains/compose-jb/issues/22) 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")
java
application
} }
kotlin { kotlin {
@ -21,6 +20,13 @@ kotlin {
} }
} }
compose.desktop {
application { application {
mainClassName = "MainKt" 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. 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. 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` `org.jetbrains.compose` Gradle plugin simplifies the packaging of applications into native distributions and running an application locally.
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. Currently, the plugin uses [jpackage](https://openjdk.java.net/jeps/343) for packaging self-contained applications.
## Basic usage ## Basic usage
@ -26,7 +25,6 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins { plugins {
kotlin("jvm") kotlin("jvm")
id("org.jetbrains.compose") id("org.jetbrains.compose")
id("org.jetbrains.compose.desktop.application")
} }
dependencies { dependencies {
@ -54,6 +52,8 @@ 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, * `run` is used to run an app locally. You need to define a `mainClass` — an fq-name of a class,
containing the `main` function. 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`. After a build, output binaries can be found in `${project.buildDir}/compose/binaries`.
## Available formats ## Available formats
@ -144,7 +144,7 @@ If the default configuration is ambiguous or not sufficient, the plugin can be c
```kotlin ```kotlin
plugins { plugins {
kotlin("jvm") kotlin("jvm")
id("org.jetbrains.compose.desktop.application") id("org.jetbrains.compose")
} }
val customSourceSet = sourceSets.create("customSourceSet") val customSourceSet = sourceSets.create("customSourceSet")
@ -158,7 +158,7 @@ compose.desktop {
```kotlin ```kotlin
plugins { plugins {
kotlin("multiplatform") kotlin("multiplatform")
id("org.jetbrains.compose.desktop.application") id("org.jetbrains.compose")
} }
kotlin { kotlin {

Loading…
Cancel
Save