mirror of
https://github.com/processing/processing4.git
synced 2026-01-29 11:21:06 +01:00
531 lines
18 KiB
Kotlin
531 lines
18 KiB
Kotlin
import org.gradle.internal.jvm.Jvm
|
|
import org.gradle.internal.os.OperatingSystem
|
|
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
|
|
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
|
import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask
|
|
import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download
|
|
import java.io.FileOutputStream
|
|
import java.util.zip.ZipEntry
|
|
import java.util.zip.ZipOutputStream
|
|
|
|
// TODO: Update to 2.10.20 and add hot-reloading: https://github.com/JetBrains/compose-hot-reload
|
|
|
|
plugins{
|
|
id("java")
|
|
kotlin("jvm") version libs.versions.kotlin
|
|
|
|
alias(libs.plugins.compose.compiler)
|
|
alias(libs.plugins.jetbrainsCompose)
|
|
alias(libs.plugins.serialization)
|
|
alias(libs.plugins.download)
|
|
}
|
|
|
|
repositories{
|
|
mavenCentral()
|
|
google()
|
|
maven { url = uri("https://jogamp.org/deployment/maven") }
|
|
}
|
|
|
|
sourceSets{
|
|
main{
|
|
java{
|
|
srcDirs("src")
|
|
}
|
|
kotlin{
|
|
srcDirs("src")
|
|
}
|
|
resources{
|
|
srcDirs("resources", listOf("languages", "fonts", "theme").map { "../build/shared/lib/$it" })
|
|
}
|
|
}
|
|
test{
|
|
kotlin{
|
|
srcDirs("test")
|
|
}
|
|
}
|
|
}
|
|
|
|
compose.desktop {
|
|
application {
|
|
mainClass = "processing.app.ProcessingKt"
|
|
|
|
jvmArgs(*listOf(
|
|
Pair("processing.version", rootProject.version),
|
|
Pair("processing.revision", findProperty("revision") ?: Int.MAX_VALUE),
|
|
Pair("processing.contributions.source", "https://contributions.processing.org/contribs"),
|
|
Pair("processing.download.page", "https://processing.org/download/"),
|
|
Pair("processing.download.latest", "https://processing.org/download/latest.txt"),
|
|
Pair("processing.tutorials", "https://processing.org/tutorials/"),
|
|
).map { "-D${it.first}=${it.second}" }.toTypedArray())
|
|
|
|
nativeDistributions{
|
|
modules("jdk.jdi", "java.compiler", "jdk.accessibility", "java.management.rmi", "java.scripting", "jdk.httpserver")
|
|
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
|
|
packageName = "Processing"
|
|
|
|
macOS{
|
|
bundleID = "${rootProject.group}.app"
|
|
iconFile = rootProject.file("build/macos/processing.icns")
|
|
infoPlist{
|
|
extraKeysRawXml = file("macos/info.plist").readText()
|
|
}
|
|
entitlementsFile.set(file("macos/entitlements.plist"))
|
|
runtimeEntitlementsFile.set(file("macos/entitlements.plist"))
|
|
appStore = true
|
|
jvmArgs("-Dsun.java2d.metal=true")
|
|
}
|
|
windows{
|
|
iconFile = rootProject.file("build/windows/processing.ico")
|
|
menuGroup = "Processing"
|
|
upgradeUuid = "89d8d7fe-5602-4b12-ba10-0fe78efbd602"
|
|
}
|
|
linux {
|
|
appCategory = "Programming"
|
|
menuGroup = "Development;Programming;"
|
|
iconFile = rootProject.file("build/linux/processing.png")
|
|
// Fix fonts on some Linux distributions
|
|
jvmArgs("-Dawt.useSystemAAFontSettings=on")
|
|
|
|
fileAssociation("pde", "Processing Source Code", "application/x-processing")
|
|
fileAssociation("pyde", "Processing Python Source Code", "application/x-processing")
|
|
fileAssociation("pdez", "Processing Sketch Bundle", "application/x-processing")
|
|
fileAssociation("pdex", "Processing Contribution Bundle", "application/x-processing")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
implementation(project(":core"))
|
|
runtimeOnly(project(":java"))
|
|
implementation(project(":app:utils"))
|
|
|
|
implementation(libs.flatlaf)
|
|
|
|
implementation(libs.jna)
|
|
implementation(libs.jnaplatform)
|
|
|
|
implementation(compose.runtime)
|
|
implementation(compose.foundation)
|
|
implementation(compose.material)
|
|
implementation(compose.ui)
|
|
implementation(compose.components.resources)
|
|
implementation(compose.components.uiToolingPreview)
|
|
|
|
implementation(compose.desktop.currentOs)
|
|
|
|
implementation(libs.compottie)
|
|
implementation(libs.kaml)
|
|
implementation(libs.markdown)
|
|
implementation(libs.markdownJVM)
|
|
|
|
testImplementation(kotlin("test"))
|
|
testImplementation(libs.mockitoKotlin)
|
|
testImplementation(libs.junitJupiter)
|
|
testImplementation(libs.junitJupiterParams)
|
|
|
|
implementation(libs.clikt)
|
|
implementation(libs.kotlinxSerializationJson)
|
|
}
|
|
|
|
tasks.test {
|
|
useJUnitPlatform()
|
|
workingDir = file("build/test")
|
|
workingDir.mkdirs()
|
|
}
|
|
|
|
tasks.compileJava{
|
|
options.encoding = "UTF-8"
|
|
}
|
|
|
|
tasks.register("lsp-develop"){
|
|
group = "processing"
|
|
// This task is used to run the LSP server when developing the LSP server itself
|
|
// to run the LSP server for end-users use `processing lsp` instead
|
|
dependencies.add("runtimeOnly", project(":java"))
|
|
|
|
// Usage: ./gradlew lsp-develop
|
|
// Make sure the cwd is set to the project directory
|
|
// or use -p to set the project directory
|
|
|
|
// Modify run configuration to start the LSP server rather than the Processing IDE
|
|
val run = tasks.named<JavaExec>("run").get()
|
|
run.standardInput = System.`in`
|
|
run.standardOutput = System.out
|
|
dependsOn(run)
|
|
|
|
// TODO: Remove after command line is integrated, then add the `lsp` argument instead, `lsp-develop` can't be removed because we still need to pipe the input and output
|
|
run.jvmArgs("-Djava.awt.headless=true")
|
|
compose.desktop.application.mainClass = "processing.mode.java.lsp.PdeLanguageServer"
|
|
}
|
|
|
|
val version = if(project.version == "unspecified") "1.0.0" else project.version
|
|
|
|
tasks.register<Exec>("installCreateDmg") {
|
|
onlyIf { OperatingSystem.current().isMacOsX }
|
|
commandLine("arch", "-arm64", "brew", "install", "--quiet", "create-dmg")
|
|
}
|
|
tasks.register<Exec>("packageCustomDmg"){
|
|
onlyIf { OperatingSystem.current().isMacOsX }
|
|
group = "compose desktop"
|
|
|
|
val distributable = tasks.named<AbstractJPackageTask>("createDistributable").get()
|
|
dependsOn(distributable, "installCreateDmg")
|
|
|
|
val packageName = distributable.packageName.get()
|
|
val dir = distributable.destinationDir.get()
|
|
val dmg = dir.file("../dmg/$packageName-$version.dmg").asFile
|
|
val app = dir.file("$packageName.app").asFile
|
|
|
|
dmg.parentFile.deleteRecursively()
|
|
dmg.parentFile.mkdirs()
|
|
|
|
val extra = mutableListOf<String>()
|
|
val isSigned = compose.desktop.application.nativeDistributions.macOS.signing.sign.get()
|
|
|
|
if(!isSigned) {
|
|
val content = """
|
|
run 'xattr -d com.apple.quarantine Processing-${version}.dmg' to remove the quarantine flag
|
|
""".trimIndent()
|
|
val instructions = dmg.parentFile.resolve("INSTRUCTIONS.txt")
|
|
instructions.writeText(content)
|
|
extra.add("--add-file")
|
|
extra.add("INSTRUCTIONS.txt")
|
|
extra.add(instructions.path)
|
|
extra.add("200")
|
|
extra.add("25")
|
|
}
|
|
|
|
commandLine("create-dmg",
|
|
"--volname", packageName,
|
|
"--volicon", file("macos/volume.icns"),
|
|
"--background", file("macos/background.png"),
|
|
"--icon", "$packageName.app", "190", "185",
|
|
"--window-pos", "200", "200",
|
|
"--window-size", "658", "422",
|
|
"--app-drop-link", "466", "185",
|
|
"--hide-extension", "$packageName.app",
|
|
*extra.toTypedArray(),
|
|
dmg,
|
|
app
|
|
)
|
|
}
|
|
|
|
tasks.register<Exec>("packageCustomMsi"){
|
|
onlyIf { OperatingSystem.current().isWindows }
|
|
dependsOn("createDistributable")
|
|
workingDir = file("windows")
|
|
group = "compose desktop"
|
|
|
|
val version = if(version == "unspecified") "1.0.0" else version
|
|
|
|
commandLine(
|
|
"dotnet",
|
|
"build",
|
|
"/p:Platform=x64",
|
|
"/p:Version=$version",
|
|
"/p:DefineConstants=\"Version=$version;\""
|
|
)
|
|
}
|
|
|
|
|
|
tasks.register("generateSnapConfiguration"){
|
|
onlyIf { OperatingSystem.current().isLinux }
|
|
|
|
val distributable = tasks.named<AbstractJPackageTask>("createDistributable").get()
|
|
dependsOn(distributable)
|
|
|
|
val name = findProperty("snapname") as String? ?: rootProject.name
|
|
val arch = when (System.getProperty("os.arch")) {
|
|
"amd64", "x86_64" -> "amd64"
|
|
"aarch64" -> "arm64"
|
|
else -> System.getProperty("os.arch")
|
|
}
|
|
val confinement = findProperty("snapconfinement") as String? ?: "strict"
|
|
val dir = distributable.destinationDir.get()
|
|
val base = layout.projectDirectory.file("linux/snapcraft.base.yml")
|
|
|
|
doFirst {
|
|
|
|
var content = base
|
|
.asFile
|
|
.readText()
|
|
.replace("\$name", name)
|
|
.replace("\$arch", arch)
|
|
.replace("\$version", version as String)
|
|
.replace("\$confinement", confinement)
|
|
.let {
|
|
if (confinement != "classic") return@let it
|
|
// If confinement is not strict, remove the PLUGS section
|
|
val start = it.indexOf("# PLUGS START")
|
|
val end = it.indexOf("# PLUGS END")
|
|
if (start != -1 && end != -1) {
|
|
val before = it.substring(0, start)
|
|
val after = it.substring(end + "# PLUGS END".length)
|
|
return@let before + after
|
|
}
|
|
return@let it
|
|
}
|
|
dir.file("../snapcraft.yaml").asFile.writeText(content)
|
|
}
|
|
}
|
|
|
|
tasks.register<Exec>("packageSnap"){
|
|
onlyIf { OperatingSystem.current().isLinux }
|
|
dependsOn("packageDeb", "generateSnapConfiguration")
|
|
group = "compose desktop"
|
|
|
|
val distributable = tasks.named<AbstractJPackageTask>("createDistributable").get()
|
|
workingDir = distributable.destinationDir.dir("../").get().asFile
|
|
commandLine("snapcraft")
|
|
}
|
|
tasks.register<Zip>("zipDistributable"){
|
|
dependsOn("createDistributable", "setExecutablePermissions")
|
|
group = "compose desktop"
|
|
|
|
val distributable = tasks.named<AbstractJPackageTask>("createDistributable").get()
|
|
val dir = distributable.destinationDir.get()
|
|
val packageName = distributable.packageName.get()
|
|
|
|
from(dir){ eachFile{ permissions{ unix("755") } } }
|
|
archiveBaseName.set(packageName)
|
|
destinationDirectory.set(dir.file("../").asFile)
|
|
}
|
|
|
|
afterEvaluate{
|
|
// Override the default DMG task to use our custom one
|
|
tasks.named("packageDmg").configure{
|
|
dependsOn("packageCustomDmg")
|
|
group = "compose desktop"
|
|
actions = emptyList()
|
|
}
|
|
// Override the default MSI task to use our custom one
|
|
tasks.named("packageMsi").configure{
|
|
dependsOn("packageCustomMsi")
|
|
group = "compose desktop"
|
|
actions = emptyList()
|
|
}
|
|
tasks.named("packageDistributionForCurrentOS").configure {
|
|
if(OperatingSystem.current().isMacOsX
|
|
&& compose.desktop.application.nativeDistributions.macOS.notarization.appleID.isPresent
|
|
){
|
|
dependsOn("notarizeDmg")
|
|
}
|
|
dependsOn("packageSnap", "zipDistributable")
|
|
}
|
|
}
|
|
|
|
|
|
// LEGACY TASKS
|
|
// Most of these are shims to be compatible with the old build system
|
|
// They should be removed in the future, as we work towards making things more Gradle-native
|
|
val composeResources = { subPath: String -> layout.buildDirectory.dir("resources-bundled/common/$subPath") }
|
|
compose.desktop.application.nativeDistributions.appResourcesRootDir.set(composeResources("../"))
|
|
|
|
tasks.register<Copy>("includeCore"){
|
|
val core = project(":core")
|
|
dependsOn(core.tasks.jar)
|
|
from(core.layout.buildDirectory.dir("libs"))
|
|
from(core.configurations.runtimeClasspath)
|
|
into(composeResources("core/library"))
|
|
}
|
|
tasks.register<Copy>("includeJavaMode") {
|
|
val java = project(":java")
|
|
dependsOn(java.tasks.jar)
|
|
from(java.layout.buildDirectory.dir("libs"))
|
|
from(java.configurations.runtimeClasspath)
|
|
into(composeResources("modes/java/mode"))
|
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
}
|
|
tasks.register<Copy>("includeJdk") {
|
|
from(Jvm.current().javaHome.absolutePath)
|
|
destinationDir = composeResources("jdk").get().asFile
|
|
|
|
fileTree(destinationDir).files.forEach { file ->
|
|
file.setWritable(true, false)
|
|
file.setReadable(true, false)
|
|
}
|
|
}
|
|
tasks.register<Copy>("includeSharedAssets"){
|
|
from("../build/shared/")
|
|
into(composeResources(""))
|
|
}
|
|
tasks.register<Download>("includeProcessingExamples") {
|
|
val examples = layout.buildDirectory.file("tmp/processing-examples.zip")
|
|
src("https://github.com/processing/processing-examples/archive/refs/heads/main.zip")
|
|
dest(examples)
|
|
overwrite(false)
|
|
doLast{
|
|
copy{
|
|
from(zipTree(examples)){ // remove top level directory
|
|
exclude("processing-examples-main/README.md")
|
|
exclude("processing-examples-main/.github/**")
|
|
eachFile { relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray()) }
|
|
includeEmptyDirs = false
|
|
}
|
|
into(composeResources("/modes/java/examples"))
|
|
}
|
|
}
|
|
}
|
|
tasks.register<Download>("includeProcessingWebsiteExamples") {
|
|
val examples = layout.buildDirectory.file("tmp/processing-website.zip")
|
|
src("https://github.com/processing/processing-website/archive/refs/heads/main.zip")
|
|
dest(examples)
|
|
overwrite(false)
|
|
doLast{
|
|
copy{
|
|
from(zipTree(examples)){
|
|
include("processing-website-main/content/examples/**")
|
|
eachFile { relativePath = RelativePath(true, *relativePath.segments.drop(3).toTypedArray()) }
|
|
includeEmptyDirs = false
|
|
exclude { it.name.contains(".es.") || it.name == "liveSketch.js" }
|
|
}
|
|
into(composeResources("modes/java/examples"))
|
|
}
|
|
}
|
|
}
|
|
tasks.register<Copy>("includeJavaModeResources") {
|
|
val java = project(":java")
|
|
dependsOn(java.tasks.named("extraResources"))
|
|
from(java.layout.buildDirectory.dir("resources-bundled"))
|
|
into(composeResources("../"))
|
|
}
|
|
// TODO: Move to java mode
|
|
tasks.register<Copy>("renameWindres") {
|
|
dependsOn("includeSharedAssets","includeJavaModeResources")
|
|
val dir = composeResources("modes/java/application/launch4j/bin/")
|
|
val os = DefaultNativePlatform.getCurrentOperatingSystem()
|
|
val platform = when {
|
|
os.isWindows -> "windows"
|
|
os.isMacOsX -> "macos"
|
|
else -> "linux"
|
|
}
|
|
from(dir) {
|
|
include("*-$platform*")
|
|
rename("(.*)-$platform(.*)", "$1$2")
|
|
}
|
|
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
|
into(dir)
|
|
}
|
|
tasks.register("includeProcessingResources"){
|
|
dependsOn(
|
|
"includeCore",
|
|
"includeJavaMode",
|
|
"includeSharedAssets",
|
|
"includeProcessingExamples",
|
|
"includeProcessingWebsiteExamples",
|
|
"includeJavaModeResources",
|
|
"renameWindres"
|
|
)
|
|
mustRunAfter("includeJdk")
|
|
finalizedBy("signResources")
|
|
}
|
|
|
|
tasks.register("signResources"){
|
|
onlyIf {
|
|
OperatingSystem.current().isMacOsX
|
|
&&
|
|
compose.desktop.application.nativeDistributions.macOS.signing.sign.get()
|
|
}
|
|
group = "compose desktop"
|
|
val resourcesPath = composeResources("")
|
|
|
|
// find jars in the resources directory
|
|
val jars = mutableListOf<File>()
|
|
doFirst{
|
|
fileTree(resourcesPath)
|
|
.matching { include("**/Info.plist") }
|
|
.singleOrNull()
|
|
?.let { file ->
|
|
copy {
|
|
from(file)
|
|
into(resourcesPath)
|
|
}
|
|
}
|
|
fileTree(resourcesPath) {
|
|
include("**/*.jar")
|
|
exclude("**/*.jar.tmp/**")
|
|
}.forEach { file ->
|
|
val tempDir = file.parentFile.resolve("${file.name}.tmp")
|
|
copy {
|
|
from(zipTree(file))
|
|
into(tempDir)
|
|
}
|
|
file.delete()
|
|
jars.add(tempDir)
|
|
}
|
|
fileTree(resourcesPath){
|
|
include("**/bin/**")
|
|
include("**/*.jnilib")
|
|
include("**/*.dylib")
|
|
include("**/*aarch64*")
|
|
include("**/*x86_64*")
|
|
include("**/*ffmpeg*")
|
|
include("**/ffmpeg*/**")
|
|
exclude("jdk/**")
|
|
exclude("*.jar")
|
|
exclude("*.so")
|
|
exclude("*.dll")
|
|
}.forEach{ file ->
|
|
exec {
|
|
commandLine("codesign", "--timestamp", "--force", "--deep","--options=runtime", "--sign", "Developer ID Application", file)
|
|
}
|
|
}
|
|
jars.forEach { file ->
|
|
FileOutputStream(File(file.parentFile, file.nameWithoutExtension)).use { fos ->
|
|
ZipOutputStream(fos).use { zos ->
|
|
file.walkTopDown().forEach { fileEntry ->
|
|
if (fileEntry.isFile) {
|
|
// Calculate the relative path for the zip entry
|
|
val zipEntryPath = fileEntry.relativeTo(file).path
|
|
val entry = ZipEntry(zipEntryPath)
|
|
zos.putNextEntry(entry)
|
|
|
|
// Copy file contents to the zip
|
|
fileEntry.inputStream().use { input ->
|
|
input.copyTo(zos)
|
|
}
|
|
zos.closeEntry()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
file.deleteRecursively()
|
|
}
|
|
file(composeResources("Info.plist")).delete()
|
|
}
|
|
|
|
|
|
}
|
|
tasks.register("setExecutablePermissions") {
|
|
description = "Sets executable permissions on binaries in Processing.app resources"
|
|
group = "compose desktop"
|
|
|
|
doLast {
|
|
val resourcesPath = layout.buildDirectory.dir("compose/binaries")
|
|
fileTree(resourcesPath) {
|
|
include("**/resources/**/bin/**")
|
|
include("**/resources/**/lib/**")
|
|
include("**/resources/**/*.sh")
|
|
include("**/resources/**/*.dylib")
|
|
include("**/resources/**/*.so")
|
|
include("**/resources/**/*.exe")
|
|
}.forEach { file ->
|
|
if (file.isFile) {
|
|
file.setExecutable(true, false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
afterEvaluate {
|
|
tasks.named("prepareAppResources").configure {
|
|
dependsOn("includeProcessingResources")
|
|
}
|
|
tasks.named("createDistributable").configure {
|
|
dependsOn("includeJdk")
|
|
finalizedBy("setExecutablePermissions")
|
|
}
|
|
}
|