Skip to content

Commit

Permalink
1.18: extract JBR with tar -xzf on Mac and Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
sergej-koscejev committed Aug 7, 2023
1 parent 74e1bb3 commit 90f1a8c
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 83 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 1.18

### Changed

- `extractJbr` task is no longer a `Sync` but will use platform-specific tools (`tar`) to make sure symlinks in the JBR
are extracted properly. Native libraries rely on symlinks and do not function unless properly extracted.

## 1.17

### Added
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,8 @@ to your build, you need to make sure that it is available in your dependency rep
the scripts located in mbeddr/build.publish.jdk

For easy consumption and incremental build support the plugin creates a task `downloadJbr` which exposes the location of
the java executable via the `javaExecutable` property. See the tests in src/test/kotlin/JBRDownloadTest.kt for an example
how to use it.
the java executable via the `javaExecutable` property. See
[the tests](src/test/kotlin/test/de/itemis/mps/gradle/JBRDownloadTest.kt) for an example of how to use it.

### Usage

Expand Down Expand Up @@ -493,8 +493,8 @@ downloadJbr {
using wildcards like `*` or `+` in there for reproducible builds.
* `distributionType` - optional distribution type for the JBR to use. Will default to `jbr_jcef` if omitted.
* `downloadDir` - optional directory where the downloaded JBR is downloaded and extracted to. The plugin defaults to
`build/jbrDownload`
`build/jbrDownload`.

## Custom MPS Distribution

Features that perform an action inside an MPS project, like the `modelcheck` or `generate-models` plugin, require
Expand Down Expand Up @@ -540,4 +540,4 @@ tasks.getByName("resolveMpsForModelcheck").dependsOn(downloadAndExtractCustomMPS
Since plugin version 1.10, the `environmentKind` parameter allows to choose between MPS or IDEA environment for
generation or model check. The default is to use the IDEA environment because that was the case in earlier versions, but
the MPS environment is lighter and likely to be more performant. On the other hand, the MPS environment does not load
some plugins or extensions and may lead to different results.
plugins (only extensions) and may lead to different results.
4 changes: 1 addition & 3 deletions api/mps-gradle-plugin.api
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ public class de/itemis/mps/gradle/TestLanguages : de/itemis/mps/gradle/RunAntScr

public class de/itemis/mps/gradle/downloadJBR/DownloadJbrConfiguration {
public field jbrVersion Ljava/lang/String;
public fun <init> ()V
public fun <init> (Lorg/gradle/api/model/ObjectFactory;)V
public final fun getDistributionType ()Ljava/lang/String;
public final fun getDownloadDir ()Ljava/io/File;
public final fun getJbrVersion ()Ljava/lang/String;
Expand All @@ -214,8 +214,6 @@ public class de/itemis/mps/gradle/downloadJBR/DownloadJbrConfiguration {
}

public class de/itemis/mps/gradle/downloadJBR/DownloadJbrForPlatform : org/gradle/api/DefaultTask {
public field javaExecutable Ljava/io/File;
public field jbrDir Ljava/io/File;
public fun <init> ()V
public final fun getJavaExecutable ()Ljava/io/File;
public final fun getJbrDir ()Ljava/io/File;
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ plugins {
}

val versionMajor = 1
val versionMinor = 17
val versionMinor = 18

group = "de.itemis.mps"

Expand Down
167 changes: 100 additions & 67 deletions src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Plugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,94 +4,127 @@ import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.Sync
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.model.ObjectFactory
import java.io.File
import javax.inject.Inject

open class DownloadJbrConfiguration {
open class DownloadJbrConfiguration @Inject constructor(objects: ObjectFactory) {
lateinit var jbrVersion: String
var distributionType : String? = null
var downloadDir: File? = null
internal val downloadDirProperty: DirectoryProperty = objects.directoryProperty()

var downloadDir: File?
get() = downloadDirProperty.get().asFile
set(value) {
downloadDirProperty.set(value)
}
}

open class DownloadJbrProjectPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.run {

val extension = extensions.create("downloadJbr", DownloadJbrConfiguration::class.java)
val extractJbr = tasks.register("extractJbr", Sync::class.java)
extension.downloadDirProperty.convention(layout.buildDirectory.dir("jbrDownload"))

val downloadJbr = tasks.register("downloadJbr", DownloadJbrForPlatform::class.java) {
dependsOn(extractJbr)
group = "Build"
description = "Downloads the JetBrains Runtime for the current platform and extracts it."
}
val configuration = configurations.detachedConfiguration()
configuration.dependencies.addLater(provider { project.dependencies.create(dependencyString(extension)) })

afterEvaluate {
val downloadDir = extension.downloadDir ?: File(buildDir, "jbrDownload")
val version = extension.jbrVersion
// from version 10 on the jbr distribution type is replaced with jbr_jcef
// jbr_jcef is the distribution used to start a normal desktop ide and should include everything
// required for running tests. While a little bit larger than jbr_nomod it should cause the least
// surprises when using it as a default.
// see https://github.com/mbeddr/build.publish.jdk/commit/10bbf7d177336179ca189fc8bb4c1262029c69da
val distributionType = if(extension.distributionType == null &&
Regex("""11_0_[0-9][^0-9]""").find(version) != null) {
"jbr"
} else {
"jbr_jcef"
}

val cpuArch = when(System.getProperty ("os.arch")) {
"aarch64" -> "aarch64"
"amd64" -> "x64"
"x86_64" -> "x64"
else -> throw GradleException("Unsupported CPU Architecture: ${System.getProperty ("os.arch")}! Please open a bug at https://github.com/mbeddr/mps-gradle-plugin with details about your operating system and CPU.")
val extractJbr = tasks.register("extractJbr") {
inputs.files(configuration).skipWhenEmpty()
outputs.dir(extension.downloadDirProperty)

}
val dependencyString = when {
Os.isFamily(Os.FAMILY_MAC) -> {
"com.jetbrains.jdk:$distributionType:$version:osx-$cpuArch@tgz"
}
Os.isFamily(Os.FAMILY_WINDOWS) -> {
"com.jetbrains.jdk:$distributionType:$version:windows-$cpuArch@tgz"
}
Os.isFamily(Os.FAMILY_UNIX) -> {
"com.jetbrains.jdk:$distributionType:$version:linux-$cpuArch@tgz"
}
else -> {
throw GradleException("Unsupported platform! Please open a bug at https://github.com/mbeddr/mps-gradle-plugin with details about your operating system.")
}
}
doLast {
if (Os.isFamily(Os.FAMILY_UNIX)) {
// Use Unix utilities to properly deal with symlinks
delete(extension.downloadDirProperty)
val downloadDir = mkdir(extension.downloadDirProperty)

val dependency = project.dependencies.create(dependencyString)
val configuration = configurations.detachedConfiguration(dependency)
exec {
commandLine("tar", "-xzf", configuration.singleFile.absolutePath)
workingDir = downloadDir
}

extractJbr.configure {
from({ configuration.resolve().map { tarTree(it) } })
into(downloadDir)
includeEmptyDirs = false
eachFile {
mode = mode or Integer.parseInt("600", 8)
}
filesMatching("jbr_*/**") {
path = path.replace("jbr_(.*?)/(.*)".toRegex(), "jbr/$2")
}
}
if (downloadDir.listFiles { _, name -> name.startsWith("jbr_") }!!.any()) {
exec {
commandLine("sh", "-c", "mv jbr_* jbr")
workingDir = downloadDir
}
}

val jbrSubdir = when {
Os.isFamily(Os.FAMILY_MAC) -> {
File(downloadDir, "jbr/Contents/Home")
}
else -> {
File(downloadDir, "jbr")
exec {
commandLine("chmod", "-R", "u+w", ".")
workingDir = downloadDir
}
} else {
// On Windows we don't worry about symlinks nor file modes.
sync {
from({ tarTree(configuration.singleFile) })
into(extension.downloadDirProperty)
includeEmptyDirs = false
eachFile {
mode = mode or Integer.parseInt("600", 8)
}
filesMatching("jbr_*/**") {
path = path.replace("jbr_(.*?)/(.*)".toRegex(), "jbr/$2")
}
}
}
}
}

downloadJbr.configure {
jbrDir = jbrSubdir
javaExecutable = if (Os.isFamily(Os.FAMILY_WINDOWS)) File(jbrSubdir, "bin/java.exe") else File(jbrSubdir, "bin/java")
}
tasks.register("downloadJbr", DownloadJbrForPlatform::class.java) {
dependsOn(extractJbr)
group = "Build"
description = "Downloads the JetBrains Runtime for the current platform and extracts it."

jbrDirProperty.set(extension.downloadDirProperty.dir(
if (Os.isFamily(Os.FAMILY_MAC)) "jbr/Contents/Home"
else "jbr"
))
javaExecutableProperty.set(jbrDirProperty.file(if (Os.isFamily(Os.FAMILY_WINDOWS)) "bin/java.exe" else "bin/java"))
}
}
}

private fun dependencyString(extension: DownloadJbrConfiguration): String {
val version = extension.jbrVersion
// from version 10 on the jbr distribution type is replaced with jbr_jcef
// jbr_jcef is the distribution used to start a normal desktop ide and should include everything
// required for running tests. While a little bit larger than jbr_nomod it should cause the least
// surprises when using it as a default.
// see https://github.com/mbeddr/build.publish.jdk/commit/10bbf7d177336179ca189fc8bb4c1262029c69da
val distributionType = if(extension.distributionType == null &&
Regex("""11_0_[0-9][^0-9]""").find(version) != null) {
"jbr"
} else {
"jbr_jcef"
}

val cpuArch = when(System.getProperty ("os.arch")) {
"aarch64" -> "aarch64"
"amd64" -> "x64"
"x86_64" -> "x64"
else -> throw GradleException("Unsupported CPU Architecture: ${System.getProperty ("os.arch")}! Please open a bug at https://github.com/mbeddr/mps-gradle-plugin with details about your operating system and CPU.")

}

val dependencyString = when {
Os.isFamily(Os.FAMILY_MAC) -> {
"com.jetbrains.jdk:$distributionType:$version:osx-$cpuArch@tgz"
}
Os.isFamily(Os.FAMILY_WINDOWS) -> {
"com.jetbrains.jdk:$distributionType:$version:windows-$cpuArch@tgz"
}
Os.isFamily(Os.FAMILY_UNIX) -> {
"com.jetbrains.jdk:$distributionType:$version:linux-$cpuArch@tgz"
}
else -> {
throw GradleException("Unsupported platform! Please open a bug at https://github.com/mbeddr/mps-gradle-plugin with details about your operating system.")
}
}

return dependencyString
}
}
28 changes: 21 additions & 7 deletions src/main/kotlin/de/itemis/mps/gradle/downloadJBR/Tasks.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
package de.itemis.mps.gradle.downloadJBR

import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.DefaultTask
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.*
import java.io.File

open class DownloadJbrForPlatform : DefaultTask() {

@OutputDirectory
lateinit var jbrDir : File
@get:Internal
internal val jbrDirProperty: DirectoryProperty = project.objects.directoryProperty()

@OutputFile
lateinit var javaExecutable: File
}
@get:Internal
var jbrDir : File
get() = jbrDirProperty.get().asFile
set(value) {
jbrDirProperty.set(value)
}

@get:Internal
internal val javaExecutableProperty: RegularFileProperty = project.objects.fileProperty()

@get:Internal
var javaExecutable: File
get() = javaExecutableProperty.get().asFile
set(value) {
javaExecutableProperty.set(value)
}
}

0 comments on commit 90f1a8c

Please sign in to comment.