mirror of
https://github.com/apple/pkl.git
synced 2026-03-30 13:51:57 +02:00
Initial commit
This commit is contained in:
144
buildSrc/src/main/kotlin/BuildInfo.kt
Normal file
144
buildSrc/src/main/kotlin/BuildInfo.kt
Normal file
@@ -0,0 +1,144 @@
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
import java.io.File
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.VersionCatalog
|
||||
import org.gradle.api.artifacts.VersionCatalogsExtension
|
||||
import org.gradle.api.artifacts.VersionConstraint
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
|
||||
// `buildInfo` in main build scripts
|
||||
// `project.extensions.getByType<BuildInfo>()` in precompiled script plugins
|
||||
open class BuildInfo(project: Project) {
|
||||
val self = this
|
||||
|
||||
inner class GraalVm {
|
||||
val homeDir: String by lazy {
|
||||
System.getenv("GRAALVM_HOME") ?: "${System.getProperty("user.home")}/.graalvm"
|
||||
}
|
||||
|
||||
val version: String by lazy {
|
||||
libs.findVersion("graalVm").get().toString()
|
||||
}
|
||||
|
||||
val isGraal22: Boolean by lazy {
|
||||
version.startsWith("22")
|
||||
}
|
||||
|
||||
val arch by lazy {
|
||||
if (os.isMacOsX && isGraal22) {
|
||||
"amd64"
|
||||
} else {
|
||||
self.arch
|
||||
}
|
||||
}
|
||||
|
||||
val osName: String by lazy {
|
||||
when {
|
||||
os.isMacOsX && isGraal22 -> "darwin"
|
||||
os.isMacOsX -> "macos"
|
||||
os.isLinux -> "linux"
|
||||
else -> throw RuntimeException("${os.familyName} is not supported.")
|
||||
}
|
||||
}
|
||||
|
||||
val baseName: String by lazy {
|
||||
if (graalVm.isGraal22) {
|
||||
"graalvm-ce-java11-${osName}-${arch}-${version}"
|
||||
} else {
|
||||
"graalvm-jdk-${graalVM23JdkVersion}_${osName}-${arch}_bin"
|
||||
}
|
||||
}
|
||||
|
||||
val graalVM23JdkVersion: String by lazy {
|
||||
libs.findVersion("graalVM23JdkVersion").get().requiredVersion
|
||||
}
|
||||
|
||||
val downloadUrl: String by lazy {
|
||||
if (isGraal22) {
|
||||
"https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-" +
|
||||
"${version}/$baseName.tar.gz"
|
||||
} else {
|
||||
val jdkMajor = graalVM23JdkVersion.takeWhile { it != '.' }
|
||||
"https://download.oracle.com/graalvm/$jdkMajor/archive/$baseName.tar.gz"
|
||||
}
|
||||
}
|
||||
|
||||
val installDir: File by lazy {
|
||||
File(homeDir, baseName)
|
||||
}
|
||||
|
||||
val baseDir: String by lazy {
|
||||
if (os.isMacOsX) "$installDir/Contents/Home" else installDir.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same logic as [org.gradle.internal.os.OperatingSystem#arch], which is protected.
|
||||
*/
|
||||
val arch: String by lazy {
|
||||
when (val arch = System.getProperty("os.arch")) {
|
||||
"x86" -> "i386"
|
||||
"x86_64" -> "amd64"
|
||||
"powerpc" -> "ppc"
|
||||
else -> arch
|
||||
}
|
||||
}
|
||||
|
||||
val graalVm: GraalVm = GraalVm()
|
||||
|
||||
val isCiBuild: Boolean by lazy {
|
||||
System.getenv("CI") != null
|
||||
}
|
||||
|
||||
val isReleaseBuild: Boolean by lazy {
|
||||
java.lang.Boolean.getBoolean("releaseBuild")
|
||||
}
|
||||
|
||||
val os: org.gradle.internal.os.OperatingSystem by lazy {
|
||||
org.gradle.internal.os.OperatingSystem.current()
|
||||
}
|
||||
|
||||
// could be `commitId: Provider<String> = project.provider { ... }`
|
||||
val commitId: String by lazy {
|
||||
// only run command once per build invocation
|
||||
if (project === project.rootProject) {
|
||||
Runtime.getRuntime()
|
||||
.exec("git rev-parse --short HEAD", arrayOf(), project.rootDir)
|
||||
.inputStream.reader().readText().trim()
|
||||
} else {
|
||||
project.rootProject.extensions.getByType(BuildInfo::class.java).commitId
|
||||
}
|
||||
}
|
||||
|
||||
val commitish: String by lazy {
|
||||
if (isReleaseBuild) project.version.toString() else commitId
|
||||
}
|
||||
|
||||
val pklVersion: String by lazy {
|
||||
if (isReleaseBuild) {
|
||||
project.version.toString()
|
||||
} else {
|
||||
project.version.toString().replace("-SNAPSHOT", "-dev+$commitId")
|
||||
}
|
||||
}
|
||||
|
||||
val pklVersionNonUnique: String by lazy {
|
||||
if (isReleaseBuild) {
|
||||
project.version.toString()
|
||||
} else {
|
||||
project.version.toString().replace("-SNAPSHOT", "-dev")
|
||||
}
|
||||
}
|
||||
|
||||
// https://melix.github.io/blog/2021/03/version-catalogs-faq.html#_but_how_can_i_use_the_catalog_in_em_plugins_em_defined_in_code_buildsrc_code
|
||||
val libs: VersionCatalog by lazy {
|
||||
project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
}
|
||||
|
||||
init {
|
||||
if (!isReleaseBuild) {
|
||||
project.version = "${project.version}-SNAPSHOT"
|
||||
}
|
||||
}
|
||||
}
|
||||
47
buildSrc/src/main/kotlin/ExecutableJar.kt
Normal file
47
buildSrc/src/main/kotlin/ExecutableJar.kt
Normal file
@@ -0,0 +1,47 @@
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.kotlin.dsl.listProperty
|
||||
|
||||
/**
|
||||
* Builds a self-contained Pkl CLI Jar that is directly executable on *nix
|
||||
* and executable with `java -jar` on Windows.
|
||||
*
|
||||
* For direct execution, the `java` command must be on the PATH.
|
||||
*
|
||||
* https://skife.org/java/unix/2011/06/20/really_executable_jars.html
|
||||
*/
|
||||
open class ExecutableJar : DefaultTask() {
|
||||
@get:InputFile
|
||||
val inJar: RegularFileProperty = project.objects.fileProperty()
|
||||
|
||||
@get:OutputFile
|
||||
val outJar: RegularFileProperty = project.objects.fileProperty()
|
||||
|
||||
@get:Input
|
||||
val jvmArgs: ListProperty<String> = project.objects.listProperty()
|
||||
|
||||
@TaskAction
|
||||
fun buildJar() {
|
||||
val inFile = inJar.get().asFile
|
||||
val outFile = outJar.get().asFile
|
||||
val escapedJvmArgs = jvmArgs.get().joinToString(separator = " ") { "\"$it\"" }
|
||||
|
||||
val startScript = """
|
||||
#!/bin/sh
|
||||
exec java $escapedJvmArgs -jar $0 "$@"
|
||||
""".trim().trimMargin() + "\n\n\n"
|
||||
|
||||
outFile.outputStream().use { outStream ->
|
||||
startScript.byteInputStream().use { it.copyTo(outStream) }
|
||||
inFile.inputStream().use { it.copyTo(outStream) }
|
||||
}
|
||||
|
||||
// chmod a+x
|
||||
outFile.setExecutable(true, false)
|
||||
}
|
||||
}
|
||||
7
buildSrc/src/main/kotlin/GradlePluginTests.kt
Normal file
7
buildSrc/src/main/kotlin/GradlePluginTests.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
open class GradlePluginTests {
|
||||
lateinit var minGradleVersion: GradleVersion
|
||||
lateinit var maxGradleVersion: GradleVersion
|
||||
var skippedGradleVersions: List<GradleVersion> = listOf()
|
||||
}
|
||||
68
buildSrc/src/main/kotlin/GradleVersionInfo.kt
Normal file
68
buildSrc/src/main/kotlin/GradleVersionInfo.kt
Normal file
@@ -0,0 +1,68 @@
|
||||
import java.net.URL
|
||||
import org.gradle.util.GradleVersion
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
@Suppress("unused")
|
||||
class GradleVersionInfo(json: Map<String, Any>) {
|
||||
val version: String by json
|
||||
|
||||
val gradleVersion: GradleVersion by lazy { GradleVersion.version(version) }
|
||||
|
||||
val isReleaseVersion: Boolean by lazy {
|
||||
// for some reason, `gradleVersion == gradleVersion.baseVersion` is a compile error
|
||||
gradleVersion.version == gradleVersion.baseVersion.version
|
||||
}
|
||||
|
||||
val buildTime: String by json
|
||||
|
||||
val current: Boolean by json
|
||||
|
||||
val snapshot: Boolean by json
|
||||
|
||||
val nightly: Boolean by json
|
||||
|
||||
val releaseNightly: Boolean by json
|
||||
|
||||
val activeRc: Boolean by json
|
||||
|
||||
val rcFor: String by json
|
||||
|
||||
val milestoneFor: String by json
|
||||
|
||||
val broken: Boolean by json
|
||||
|
||||
val downloadUrl: String by json
|
||||
|
||||
val checksumUrl: String by json
|
||||
|
||||
val wrapperChecksumUrl: String by json
|
||||
|
||||
companion object {
|
||||
private fun fetchAll(): List<GradleVersionInfo> = fetchMultiple("https://services.gradle.org/versions/all")
|
||||
|
||||
fun fetchReleases(): List<GradleVersionInfo> = fetchAll().filter { it.isReleaseVersion }
|
||||
|
||||
fun fetchCurrent(): GradleVersionInfo = fetchSingle("https://services.gradle.org/versions/current")
|
||||
|
||||
fun fetchRc(): GradleVersionInfo? = fetchSingleOrNull("https://services.gradle.org/versions/release-candidate")
|
||||
|
||||
fun fetchNightly(): GradleVersionInfo = fetchSingle("https://services.gradle.org/versions/nightly")
|
||||
|
||||
private fun fetchSingle(url: String): GradleVersionInfo {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return GradleVersionInfo(JsonSlurper().parse(URL(url)) as Map<String, Any>)
|
||||
}
|
||||
|
||||
private fun fetchSingleOrNull(url: String): GradleVersionInfo? {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val json = JsonSlurper().parse(URL(url)) as Map<String, Any>
|
||||
return if (json.isEmpty()) null else GradleVersionInfo(json)
|
||||
}
|
||||
|
||||
private fun fetchMultiple(url: String): List<GradleVersionInfo> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return (JsonSlurper().parse(URL(url)) as List<Map<String, Any>>)
|
||||
.map { GradleVersionInfo(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
6
buildSrc/src/main/kotlin/HtmlValidator.kt
Normal file
6
buildSrc/src/main/kotlin/HtmlValidator.kt
Normal file
@@ -0,0 +1,6 @@
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.FileCollection
|
||||
|
||||
open class HtmlValidator(project: Project) {
|
||||
var sources: FileCollection = project.files()
|
||||
}
|
||||
115
buildSrc/src/main/kotlin/MergeSourcesJars.kt
Normal file
115
buildSrc/src/main/kotlin/MergeSourcesJars.kt
Normal file
@@ -0,0 +1,115 @@
|
||||
import java.io.File
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.FileVisitDetails
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.kotlin.dsl.listProperty
|
||||
import org.gradle.kotlin.dsl.mapProperty
|
||||
|
||||
open class MergeSourcesJars : DefaultTask() {
|
||||
@get:InputFiles
|
||||
val inputJars: ConfigurableFileCollection = project.objects.fileCollection()
|
||||
|
||||
@get:InputFiles
|
||||
val mergedBinaryJars: ConfigurableFileCollection = project.objects.fileCollection()
|
||||
|
||||
@get:Input
|
||||
val relocatedPackages: MapProperty<String, String> = project.objects.mapProperty()
|
||||
|
||||
@get:Input
|
||||
var sourceFileExtensions: ListProperty<String> = project.objects.listProperty<String>()
|
||||
.convention(listOf(".java", ".kt"))
|
||||
|
||||
@get:OutputFile
|
||||
val outputJar: RegularFileProperty = project.objects.fileProperty()
|
||||
|
||||
@TaskAction
|
||||
@Suppress("unused")
|
||||
fun merge() {
|
||||
val binaryPaths = collectBinaryPaths()
|
||||
|
||||
val relocatedPkgs = relocatedPackages.get()
|
||||
|
||||
val relocatedPaths = relocatedPkgs.entries.associate { (key, value) -> toPath(key) to toPath(value) }
|
||||
|
||||
// use negative lookbehind to match any that don't precede with
|
||||
// a word or a period character. should catch most cases.
|
||||
val importPattern = Pattern.compile("(?<!(\\w|\\.))(" +
|
||||
relocatedPkgs.keys.joinToString("|") { it.replace(".", "\\.") } + ")")
|
||||
|
||||
val sourceFileExts = sourceFileExtensions.get()
|
||||
|
||||
val outDir = this.temporaryDir
|
||||
|
||||
for (jar in inputJars) {
|
||||
// as of Gradle 2.4, doesn't visit dirs despite the claims
|
||||
project.zipTree(jar).visit {
|
||||
val details = this
|
||||
if (details.isDirectory) return@visit
|
||||
|
||||
var path = details.relativePath.parent.pathString
|
||||
val relocatedPath = relocatedPaths.keys.find { path.startsWith(it) }
|
||||
if (relocatedPath != null) {
|
||||
path = path.replace(relocatedPath, relocatedPaths.getValue(relocatedPath))
|
||||
}
|
||||
// conservative shrinking
|
||||
if (!binaryPaths.contains(path)) return@visit
|
||||
|
||||
val outFile = File("$outDir/$path/${details.file.name}")
|
||||
outFile.parentFile.mkdirs()
|
||||
|
||||
if (sourceFileExts.any { details.file.name.endsWith(it) }) {
|
||||
val oldContents = details.file.readText(Charsets.UTF_8)
|
||||
val newContents = fixImports(relocatedPkgs, details, oldContents, importPattern)
|
||||
outFile.writeText(newContents, Charsets.UTF_8)
|
||||
} else {
|
||||
details.copyTo(outFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.ant.invokeMethod("jar", mapOf("basedir" to outDir, "destfile" to outputJar.get()))
|
||||
}
|
||||
|
||||
private fun collectBinaryPaths(): Set<String> {
|
||||
val result = mutableSetOf<String>()
|
||||
for (jar in mergedBinaryJars) {
|
||||
// as of Gradle 2.4 doesn't visit dirs despite the claims
|
||||
project.zipTree(jar).visit {
|
||||
val details = this
|
||||
if (details.isDirectory) return@visit // avoid adding empty dirs
|
||||
result.add(details.relativePath.parent.pathString)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun fixImports(
|
||||
relocatedPkgs: Map<String, String>,
|
||||
details: FileVisitDetails,
|
||||
sourceText: String,
|
||||
importPattern: Pattern
|
||||
): String {
|
||||
val matcher = importPattern.matcher(sourceText)
|
||||
val buffer = StringBuffer()
|
||||
logger.debug("Inspecting file: {}", details.relativePath)
|
||||
while (matcher.find()) {
|
||||
val newStat = relocatedPkgs[matcher.group(2)]
|
||||
logger.debug("Old: {}", matcher.group())
|
||||
logger.debug("New: {}", newStat)
|
||||
matcher.appendReplacement(buffer, Matcher.quoteReplacement(newStat))
|
||||
}
|
||||
matcher.appendTail(buffer)
|
||||
return buffer.toString()
|
||||
}
|
||||
|
||||
private fun toPath(packageName: String): String = packageName.replace(".", "/")
|
||||
}
|
||||
43
buildSrc/src/main/kotlin/ResolveSourcesJars.kt
Normal file
43
buildSrc/src/main/kotlin/ResolveSourcesJars.kt
Normal file
@@ -0,0 +1,43 @@
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.result.ResolvedArtifactResult
|
||||
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.jvm.JvmLibrary
|
||||
import org.gradle.kotlin.dsl.property
|
||||
import org.gradle.language.base.artifact.SourcesArtifact
|
||||
|
||||
open class ResolveSourcesJars : DefaultTask() {
|
||||
@get:InputFiles
|
||||
val configuration: Property<Configuration> = project.objects.property()
|
||||
|
||||
@get:OutputDirectory
|
||||
val outputDir: DirectoryProperty = project.objects.directoryProperty()
|
||||
|
||||
@TaskAction
|
||||
@Suppress("UnstableApiUsage", "unused")
|
||||
fun resolve() {
|
||||
val componentIds = configuration.get().incoming.resolutionResult.allDependencies.map {
|
||||
(it as ResolvedDependencyResult).selected.id
|
||||
}
|
||||
|
||||
val resolutionResult = project.dependencies.createArtifactResolutionQuery()
|
||||
.forComponents(componentIds)
|
||||
.withArtifacts(JvmLibrary::class.java, SourcesArtifact::class.java)
|
||||
.execute()
|
||||
|
||||
val resolvedJars = resolutionResult.resolvedComponents
|
||||
.flatMap { it.getArtifacts(SourcesArtifact::class.java) }
|
||||
.map { (it as ResolvedArtifactResult).file }
|
||||
|
||||
// copying to an output dir because I don't know how else to describe task outputs
|
||||
project.sync {
|
||||
from(resolvedJars)
|
||||
into(outputDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
95
buildSrc/src/main/kotlin/pklAllProjects.gradle.kts
Normal file
95
buildSrc/src/main/kotlin/pklAllProjects.gradle.kts
Normal file
@@ -0,0 +1,95 @@
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
val buildInfo = extensions.create<BuildInfo>("buildInfo", project)
|
||||
|
||||
dependencyLocking {
|
||||
lockAllConfigurations()
|
||||
}
|
||||
|
||||
configurations {
|
||||
val rejectedVersionSuffix = Regex("-alpha|-beta|-eap|-m|-rc|-snapshot", RegexOption.IGNORE_CASE)
|
||||
configureEach {
|
||||
resolutionStrategy {
|
||||
componentSelection {
|
||||
all {
|
||||
if (rejectedVersionSuffix.containsMatchIn(candidate.version)) {
|
||||
reject("Rejected dependency $candidate " +
|
||||
"because it has a prelease version suffix matching `$rejectedVersionSuffix`.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins.withType(JavaPlugin::class).configureEach {
|
||||
val java = project.extensions.getByType<JavaPluginExtension>()
|
||||
java.sourceCompatibility = JavaVersion.VERSION_11
|
||||
java.targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
freeCompilerArgs = freeCompilerArgs + listOf("-Xjsr305=strict", "-Xjvm-default=all")
|
||||
}
|
||||
}
|
||||
|
||||
plugins.withType(IdeaPlugin::class).configureEach {
|
||||
val errorMessage = "Use IntelliJ Gradle import instead of running the `idea` task. See README for more information."
|
||||
|
||||
tasks.named("idea") {
|
||||
doFirst {
|
||||
throw GradleException(errorMessage)
|
||||
}
|
||||
}
|
||||
tasks.named("ideaModule") {
|
||||
doFirst {
|
||||
throw GradleException(errorMessage)
|
||||
}
|
||||
}
|
||||
if (project == rootProject) {
|
||||
tasks.named("ideaProject") {
|
||||
doFirst {
|
||||
throw GradleException(errorMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins.withType(MavenPublishPlugin::class).configureEach {
|
||||
configure<PublishingExtension> {
|
||||
// CI builds pick up artifacts from this repo.
|
||||
// It's important that this repo is only declared once per project.
|
||||
repositories {
|
||||
maven {
|
||||
name = "projectLocal" // affects task names
|
||||
url = uri("file:///$rootDir/build/m2")
|
||||
}
|
||||
}
|
||||
// use resolved/locked (e.g., `1.15`)
|
||||
// instead of declared (e.g., `1.+`)
|
||||
// dependency versions in generated POMs
|
||||
publications {
|
||||
withType(MavenPublication::class.java) {
|
||||
versionMapping {
|
||||
allVariants {
|
||||
fromResolutionResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// settings.gradle.kts sets `--write-locks`
|
||||
// if Gradle command line contains this task name
|
||||
val updateDependencyLocks by tasks.registering {
|
||||
doLast {
|
||||
configurations
|
||||
.filter { it.isCanBeResolved }
|
||||
.forEach { it.resolve() }
|
||||
}
|
||||
}
|
||||
|
||||
val allDependencies by tasks.registering(DependencyReportTask::class)
|
||||
183
buildSrc/src/main/kotlin/pklFatJar.gradle.kts
Normal file
183
buildSrc/src/main/kotlin/pklFatJar.gradle.kts
Normal file
@@ -0,0 +1,183 @@
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.component.AdhocComponentWithVariants
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.kotlin.dsl.*
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
id("com.github.johnrengelman.shadow")
|
||||
}
|
||||
|
||||
// make fat Jar available to other subprojects
|
||||
val fatJarConfiguration: Configuration = configurations.create("fatJar")
|
||||
|
||||
val fatJarPublication: MavenPublication = publishing.publications.create<MavenPublication>("fatJar")
|
||||
|
||||
// ideally we'd configure this automatically based on project dependencies
|
||||
val firstPartySourcesJarsConfiguration: Configuration = configurations.create("firstPartySourcesJars")
|
||||
|
||||
val relocations = mapOf(
|
||||
// pkl-core dependencies
|
||||
"org.antlr.v4." to "org.pkl.thirdparty.antlr.v4.",
|
||||
// https://github.com/oracle/graal/issues/1644 has been fixed,
|
||||
// but native-image still fails when shading com.oracle.truffle
|
||||
//"com.oracle.truffle" to "org.pkl.thirdparty.truffle",
|
||||
"org.graalvm." to "org.pkl.thirdparty.graalvm.",
|
||||
"org.organicdesign.fp." to "org.pkl.thirdparty.paguro.",
|
||||
"org.snakeyaml.engine." to "org.pkl.thirdparty.snakeyaml.engine.",
|
||||
"org.msgpack." to "org.pkl.thirdparty.msgpack.",
|
||||
"org.w3c.dom." to "org.pkl.thirdparty.w3c.dom",
|
||||
"com.oracle.svm.core." to "org.pkl.thirdparty.svm.",
|
||||
|
||||
// pkl-cli dependencies
|
||||
"org.jline." to "org.pkl.thirdparty.jline.",
|
||||
"com.github.ajalt.clikt." to "org.pkl.thirdparty.clikt.",
|
||||
"kotlin." to "org.pkl.thirdparty.kotlin.",
|
||||
"kotlinx." to "org.pkl.thirdparty.kotlinx.",
|
||||
"org.intellij." to "org.pkl.thirdparty.intellij.",
|
||||
"org.fusesource.jansi." to "org.pkl.thirdparty.jansi",
|
||||
"org.fusesource.hawtjni." to "org.pkl.thirdparty.hawtjni",
|
||||
|
||||
// pkl-doc dependencies
|
||||
"org.commonmark." to "org.pkl.thirdparty.commonmark.",
|
||||
"org.jetbrains." to "org.pkl.thirdparty.jetbrains.",
|
||||
|
||||
// pkl-config-java dependencies
|
||||
"io.leangen.geantyref." to "org.pkl.thirdparty.geantyref.",
|
||||
|
||||
// pkl-codegen-java dependencies
|
||||
"com.squareup.javapoet." to "org.pkl.thirdparty.javapoet.",
|
||||
|
||||
// pkl-codegen-kotlin dependencies
|
||||
"com.squareup.kotlinpoet." to "org.pkl.thirdparty.kotlinpoet.",
|
||||
)
|
||||
|
||||
val nonRelocations = listOf("com/oracle/truffle/")
|
||||
|
||||
tasks.shadowJar {
|
||||
inputs.property("relocations", relocations)
|
||||
|
||||
archiveClassifier.set(null as String?)
|
||||
|
||||
configurations = listOf(project.configurations.runtimeClasspath.get())
|
||||
|
||||
exclude("META-INF/maven/**")
|
||||
exclude("META-INF/upgrade/**")
|
||||
exclude("META-INF/versions/19/**")
|
||||
|
||||
// org.antlr.v4.runtime.misc.RuleDependencyProcessor
|
||||
exclude("META-INF/services/javax.annotation.processing.Processor")
|
||||
|
||||
exclude("module-info.*")
|
||||
|
||||
for ((from, to) in relocations) {
|
||||
relocate(from, to)
|
||||
}
|
||||
|
||||
// necessary for service files to be adapted to relocation
|
||||
mergeServiceFiles()
|
||||
}
|
||||
|
||||
// workaround for https://github.com/johnrengelman/shadow/issues/651
|
||||
components.withType(AdhocComponentWithVariants::class.java).forEach { c ->
|
||||
c.withVariantsFromConfiguration(project.configurations.shadowRuntimeElements.get()) {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
|
||||
val testFatJar by tasks.registering(Test::class) {
|
||||
testClassesDirs = files(tasks.test.get().testClassesDirs)
|
||||
classpath =
|
||||
// compiled test classes
|
||||
sourceSets.test.get().output +
|
||||
// fat Jar
|
||||
tasks.shadowJar.get().outputs.files +
|
||||
// test-only dependencies
|
||||
// (test dependencies that are also main dependencies must already be contained in fat Jar;
|
||||
// to verify that, we don't want to include them here)
|
||||
(configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get())
|
||||
}
|
||||
|
||||
tasks.check {
|
||||
dependsOn(testFatJar)
|
||||
}
|
||||
|
||||
val validateFatJar by tasks.registering {
|
||||
val outputFile = file("$buildDir/validateFatJar/result.txt")
|
||||
inputs.files(tasks.shadowJar)
|
||||
inputs.property("nonRelocations", nonRelocations)
|
||||
outputs.file(outputFile)
|
||||
|
||||
doLast {
|
||||
val unshadowedFiles = mutableListOf<String>()
|
||||
zipTree(tasks.shadowJar.get().outputs.files.singleFile).visit {
|
||||
val fileDetails = this
|
||||
val path = fileDetails.relativePath.pathString
|
||||
if (!(fileDetails.isDirectory ||
|
||||
path.startsWith("org/pkl/") ||
|
||||
path.startsWith("META-INF/") ||
|
||||
nonRelocations.any { path.startsWith(it) })) {
|
||||
// don't throw exception inside `visit`
|
||||
// as this gives a misleading "Could not expand ZIP" error message
|
||||
unshadowedFiles.add(path)
|
||||
}
|
||||
}
|
||||
if (unshadowedFiles.isEmpty()) {
|
||||
outputFile.writeText("SUCCESS")
|
||||
} else {
|
||||
outputFile.writeText("FAILURE")
|
||||
throw GradleException("Found unshadowed files:\n" + unshadowedFiles.joinToString("\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.check {
|
||||
dependsOn(validateFatJar)
|
||||
}
|
||||
|
||||
val resolveSourcesJars by tasks.registering(ResolveSourcesJars::class) {
|
||||
configuration.set(configurations.runtimeClasspath)
|
||||
outputDir.set(project.file("$buildDir/resolveSourcesJars"))
|
||||
}
|
||||
|
||||
val fatSourcesJar by tasks.registering(MergeSourcesJars::class) {
|
||||
plugins.withId("pklJavaLibrary") {
|
||||
inputJars.from(tasks.named("sourcesJar"))
|
||||
}
|
||||
inputJars.from(firstPartySourcesJarsConfiguration)
|
||||
inputJars.from(resolveSourcesJars.map { fileTree(it.outputDir) })
|
||||
|
||||
mergedBinaryJars.from(tasks.shadowJar)
|
||||
relocatedPackages.set(relocations)
|
||||
outputJar.fileProvider(provider {
|
||||
file(tasks.shadowJar.get().archiveFile.get().asFile.path.replace(".jar", "-sources.jar"))
|
||||
})
|
||||
}
|
||||
|
||||
artifacts {
|
||||
add("fatJar", tasks.shadowJar)
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
named<MavenPublication>("fatJar") {
|
||||
project.shadow.component(this)
|
||||
|
||||
// sources Jar is fat
|
||||
artifact(fatSourcesJar.flatMap { it.outputJar.asFile }) {
|
||||
classifier = "sources"
|
||||
}
|
||||
|
||||
plugins.withId("pklJavaLibrary") {
|
||||
val javadocJar by tasks.existing(Jar::class)
|
||||
// Javadoc Jar is not fat (didn't invest effort)
|
||||
artifact(javadocJar.flatMap { it.archiveFile }) {
|
||||
classifier = "javadoc"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
buildSrc/src/main/kotlin/pklGraalVm.gradle.kts
Normal file
85
buildSrc/src/main/kotlin/pklGraalVm.gradle.kts
Normal file
@@ -0,0 +1,85 @@
|
||||
import java.nio.file.*
|
||||
import java.util.UUID
|
||||
import de.undercouch.gradle.tasks.download.Download
|
||||
import de.undercouch.gradle.tasks.download.Verify
|
||||
|
||||
plugins {
|
||||
id("de.undercouch.download")
|
||||
}
|
||||
|
||||
val buildInfo = project.extensions.getByType<BuildInfo>()
|
||||
|
||||
val homeDir = buildInfo.graalVm.homeDir
|
||||
val baseName = buildInfo.graalVm.baseName
|
||||
val installDir = buildInfo.graalVm.installDir
|
||||
val downloadUrl = buildInfo.graalVm.downloadUrl
|
||||
val downloadFile = file(homeDir).resolve("$baseName.tar.gz")
|
||||
|
||||
// tries to minimize chance of corruption by download-to-temp-file-and-move
|
||||
val downloadGraalVm by tasks.registering(Download::class) {
|
||||
onlyIf {
|
||||
!installDir.exists()
|
||||
}
|
||||
|
||||
src(downloadUrl)
|
||||
dest(downloadFile)
|
||||
overwrite(false)
|
||||
tempAndMove(true)
|
||||
}
|
||||
|
||||
val verifyGraalVm by tasks.registering(Verify::class) {
|
||||
onlyIf {
|
||||
!installDir.exists()
|
||||
}
|
||||
|
||||
dependsOn(downloadGraalVm)
|
||||
src(downloadFile)
|
||||
checksum(buildInfo.libs.findVersion("graalVmSha256-${buildInfo.graalVm.osName}-${buildInfo.graalVm.arch}").get().toString())
|
||||
algorithm("SHA-256")
|
||||
}
|
||||
|
||||
// minimize chance of corruption by extract-to-random-dir-and-flip-symlink
|
||||
val installGraalVm by tasks.registering {
|
||||
dependsOn(verifyGraalVm)
|
||||
|
||||
onlyIf {
|
||||
!installDir.exists()
|
||||
}
|
||||
|
||||
doLast {
|
||||
val distroDir = "$homeDir/${UUID.randomUUID()}"
|
||||
|
||||
try {
|
||||
mkdir(distroDir)
|
||||
|
||||
println("Extracting $downloadFile into $distroDir")
|
||||
// faster and more reliable than Gradle's `copy { from tarTree() }`
|
||||
exec {
|
||||
workingDir = file(distroDir)
|
||||
executable = "tar"
|
||||
args("--strip-components=1", "-xzf", downloadFile)
|
||||
}
|
||||
|
||||
val distroBinDir = if (buildInfo.os.isMacOsX) "$distroDir/Contents/Home/bin" else "$distroDir/bin"
|
||||
|
||||
println("Installing native-image into $distroDir")
|
||||
exec {
|
||||
executable = "$distroBinDir/gu"
|
||||
args("install", "--no-progress", "native-image")
|
||||
}
|
||||
|
||||
println("Creating symlink $installDir for $distroDir")
|
||||
val tempLink = Paths.get("$homeDir/${UUID.randomUUID()}")
|
||||
Files.createSymbolicLink(tempLink, Paths.get(distroDir))
|
||||
try {
|
||||
Files.move(tempLink, installDir.toPath(), StandardCopyOption.ATOMIC_MOVE)
|
||||
} catch (e: Exception) {
|
||||
try { delete(tempLink.toFile()) } catch (ignored: Exception) {}
|
||||
throw e
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
try { delete(distroDir) } catch (ignored: Exception) {}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
103
buildSrc/src/main/kotlin/pklGradlePluginTest.gradle.kts
Normal file
103
buildSrc/src/main/kotlin/pklGradlePluginTest.gradle.kts
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Allows to run Gradle plugin tests against different Gradle versions.
|
||||
*
|
||||
* Adds a `compatibilityTestX` task for every Gradle version X
|
||||
* between `ext.minSupportedGradleVersion` and `ext.maxSupportedGradleVersion`
|
||||
* that is not in `ext.gradleVersionsExcludedFromTesting`.
|
||||
* The list of available Gradle versions is obtained from services.gradle.org.
|
||||
* Adds lifecycle tasks to test against multiple Gradle versions at once, for example all Gradle release versions.
|
||||
* Compatibility test tasks run the same tests and use the same task configuration as the project's `test` task.
|
||||
* They set system properties for the Gradle version and distribution URL to be used.
|
||||
* These properties are consumed by the `AbstractTest` class.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
java
|
||||
}
|
||||
|
||||
val gradlePluginTests = extensions.create<GradlePluginTests>("gradlePluginTests")
|
||||
|
||||
tasks.addRule("Pattern: compatibilityTest[All|Releases|Latest|Candidate|Nightly|<GradleVersion>]") {
|
||||
val taskName = this
|
||||
val matchResult = Regex("compatibilityTest(.+)").matchEntire(taskName) ?: return@addRule
|
||||
|
||||
when (val taskNameSuffix = matchResult.groupValues[1]) {
|
||||
"All" ->
|
||||
task("compatibilityTestAll") {
|
||||
dependsOn("compatibilityTestReleases", "compatibilityTestCandidate", "compatibilityTestNightly")
|
||||
}
|
||||
// releases in configured range
|
||||
"Releases" ->
|
||||
task("compatibilityTestReleases") {
|
||||
val versionInfos = GradleVersionInfo.fetchReleases()
|
||||
val versionsToTestAgainst = versionInfos.filter { versionInfo ->
|
||||
val v = versionInfo.gradleVersion
|
||||
!versionInfo.broken &&
|
||||
v in gradlePluginTests.minGradleVersion..gradlePluginTests.maxGradleVersion &&
|
||||
v !in gradlePluginTests.skippedGradleVersions
|
||||
}
|
||||
|
||||
dependsOn(versionsToTestAgainst.map { createCompatibilityTestTask(it) })
|
||||
}
|
||||
// latest release (if not developing against latest)
|
||||
"Latest" ->
|
||||
task("compatibilityTestLatest") {
|
||||
val versionInfo = GradleVersionInfo.fetchCurrent()
|
||||
if (versionInfo.version == gradle.gradleVersion) {
|
||||
doLast {
|
||||
println("No new Gradle release available. " +
|
||||
"(Run `gradlew test` to test against ${versionInfo.version}.)")
|
||||
}
|
||||
} else {
|
||||
dependsOn(createCompatibilityTestTask(versionInfo))
|
||||
}
|
||||
}
|
||||
// active release candidate (if any)
|
||||
"Candidate" ->
|
||||
task("compatibilityTestCandidate") {
|
||||
val versionInfo = GradleVersionInfo.fetchRc()
|
||||
if (versionInfo?.activeRc == true) {
|
||||
dependsOn(createCompatibilityTestTask(versionInfo))
|
||||
} else {
|
||||
doLast {
|
||||
println("No active Gradle release candidate available.")
|
||||
}
|
||||
}
|
||||
}
|
||||
// latest nightly
|
||||
"Nightly" ->
|
||||
task("compatibilityTestNightly") {
|
||||
val versionInfo = GradleVersionInfo.fetchNightly()
|
||||
dependsOn(createCompatibilityTestTask(versionInfo))
|
||||
}
|
||||
// explicit version
|
||||
else ->
|
||||
createCompatibilityTestTask(
|
||||
taskNameSuffix,
|
||||
"https://services.gradle.org/distributions-snapshots/gradle-$taskNameSuffix-bin.zip"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun createCompatibilityTestTask(versionInfo: GradleVersionInfo): Task =
|
||||
createCompatibilityTestTask(versionInfo.version, versionInfo.downloadUrl)
|
||||
|
||||
fun createCompatibilityTestTask(version: String, downloadUrl: String): Task {
|
||||
return tasks.create("compatibilityTest$version", Test::class.java) {
|
||||
mustRunAfter(tasks.test)
|
||||
|
||||
maxHeapSize = tasks.test.get().maxHeapSize
|
||||
jvmArgs = tasks.test.get().jvmArgs
|
||||
classpath = tasks.test.get().classpath
|
||||
systemProperty("testGradleVersion", version)
|
||||
systemProperty("testGradleDistributionUrl", downloadUrl)
|
||||
|
||||
doFirst {
|
||||
if (version == gradle.gradleVersion && gradle.taskGraph.hasTask(tasks.test.get())) {
|
||||
// don't test same version twice
|
||||
println("This version has already been tested by the `test` task.")
|
||||
throw StopExecutionException()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
buildSrc/src/main/kotlin/pklHtmlValidator.gradle.kts
Normal file
58
buildSrc/src/main/kotlin/pklHtmlValidator.gradle.kts
Normal file
@@ -0,0 +1,58 @@
|
||||
plugins {
|
||||
base
|
||||
}
|
||||
|
||||
val htmlValidator = extensions.create<HtmlValidator>("htmlValidator", project)
|
||||
|
||||
val buildInfo = project.extensions.getByType<BuildInfo>()
|
||||
|
||||
val validatorConfiguration: Configuration = configurations.create("validator") {
|
||||
resolutionStrategy.eachDependency {
|
||||
if (requested.group == "log4j" && requested.name == "log4j") {
|
||||
@Suppress("UnstableApiUsage")
|
||||
useTarget(buildInfo.libs.findLibrary("log4j12Api").get())
|
||||
because("mitigate critical security vulnerabilities")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@Suppress("UnstableApiUsage")
|
||||
validatorConfiguration(buildInfo.libs.findLibrary("nuValidator").get()) {
|
||||
// we only want jetty-util and jetty-util-ajax (with the right version)
|
||||
// couldn't find a more robust way to express this
|
||||
exclude(group = "org.eclipse.jetty", module = "jetty-continuation")
|
||||
exclude(group = "org.eclipse.jetty", module = "jetty-http")
|
||||
exclude(group = "org.eclipse.jetty", module = "jetty-io")
|
||||
exclude(group = "org.eclipse.jetty", module = "jetty-security")
|
||||
exclude(group = "org.eclipse.jetty", module = "jetty-server")
|
||||
exclude(group = "org.eclipse.jetty", module = "jetty-servlets")
|
||||
exclude(group = "javax.servlet")
|
||||
exclude(group = "commons-fileupload")
|
||||
}
|
||||
}
|
||||
|
||||
val validateHtml by tasks.registering(JavaExec::class) {
|
||||
val resultFile = file("$buildDir/validateHtml/result.txt")
|
||||
inputs.files(htmlValidator.sources)
|
||||
outputs.file(resultFile)
|
||||
|
||||
classpath = validatorConfiguration
|
||||
mainClass.set("nu.validator.client.SimpleCommandLineValidator")
|
||||
args("--skip-non-html") // --also-check-css doesn't work (still checks css as html), so limit to html files
|
||||
args("--filterpattern", "(.*)Consider adding “lang=(.*)")
|
||||
args("--filterpattern", "(.*)Consider adding a “lang” attribute(.*)")
|
||||
args("--filterpattern", "(.*)unrecognized media “amzn-kf8”(.*)") // kindle
|
||||
// for debugging
|
||||
// args "--verbose"
|
||||
args(htmlValidator.sources)
|
||||
|
||||
// write a basic result file s.t. gradle can consider task up-to-date
|
||||
// writing a result file in case validation fails is not easily possible with JavaExec, but also not strictly necessary
|
||||
doFirst { project.delete(resultFile) }
|
||||
doLast { resultFile.writeText("Success.") }
|
||||
}
|
||||
|
||||
tasks.check {
|
||||
dependsOn(validateHtml)
|
||||
}
|
||||
59
buildSrc/src/main/kotlin/pklJavaLibrary.gradle.kts
Normal file
59
buildSrc/src/main/kotlin/pklJavaLibrary.gradle.kts
Normal file
@@ -0,0 +1,59 @@
|
||||
@file:Suppress("HttpUrlsUsage")
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
id("pklKotlinTest")
|
||||
id("com.diffplug.spotless")
|
||||
}
|
||||
|
||||
// make sources Jar available to other subprojects
|
||||
val sourcesJarConfiguration = configurations.register("sourcesJar")
|
||||
|
||||
java {
|
||||
withSourcesJar() // creates `sourcesJar` task
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
artifacts {
|
||||
// make sources Jar available to other subprojects
|
||||
add("sourcesJar", tasks["sourcesJar"])
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
googleJavaFormat("1.15.0")
|
||||
targetExclude("**/generated/**", "**/build/**")
|
||||
licenseHeaderFile(rootProject.file("buildSrc/src/main/resources/license-header.star-block.txt"))
|
||||
}
|
||||
}
|
||||
|
||||
tasks.compileKotlin {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
manifest {
|
||||
attributes += mapOf("Automatic-Module-Name" to "org.${project.name.replace("-", ".")}")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.javadoc {
|
||||
classpath = sourceSets.main.get().output + sourceSets.main.get().compileClasspath
|
||||
source = sourceSets.main.get().allJava
|
||||
title = "${project.name} ${project.version} API"
|
||||
(options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet")
|
||||
}
|
||||
|
||||
val workAroundKotlinGradlePluginBug by tasks.registering {
|
||||
doLast {
|
||||
// Works around this problem, which sporadically appears and disappears in different subprojects:
|
||||
// A problem was found with the configuration of task ':pkl-executor:compileJava' (type 'JavaCompile').
|
||||
// > Directory '[...]/pkl/pkl-executor/build/classes/kotlin/main'
|
||||
// specified for property 'compileKotlinOutputClasses' does not exist.
|
||||
file("$buildDir/classes/kotlin/main").mkdirs()
|
||||
}
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
dependsOn(workAroundKotlinGradlePluginBug)
|
||||
}
|
||||
28
buildSrc/src/main/kotlin/pklKotlinLibrary.gradle.kts
Normal file
28
buildSrc/src/main/kotlin/pklKotlinLibrary.gradle.kts
Normal file
@@ -0,0 +1,28 @@
|
||||
plugins {
|
||||
id("pklJavaLibrary")
|
||||
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
val buildInfo = project.extensions.getByType<BuildInfo>()
|
||||
|
||||
dependencies {
|
||||
// At least some of our kotlin APIs contain Kotlin stdlib types
|
||||
// that aren't compiled away by kotlinc (e.g., `kotlin.Function`).
|
||||
// So let's be conservative and default to `api` for now.
|
||||
// For Kotlin APIs that only target Kotlin users (e.g., pkl-config-kotlin),
|
||||
// it won't make a difference.
|
||||
api(buildInfo.libs.findLibrary("kotlinStdLib").get())
|
||||
}
|
||||
|
||||
tasks.compileKotlin {
|
||||
enabled = true // disabled by pklJavaLibrary
|
||||
}
|
||||
|
||||
spotless {
|
||||
kotlin {
|
||||
ktfmt("0.44").googleStyle()
|
||||
targetExclude("**/generated/**", "**/build/**")
|
||||
licenseHeaderFile(rootProject.file("buildSrc/src/main/resources/license-header.star-block.txt"))
|
||||
}
|
||||
}
|
||||
57
buildSrc/src/main/kotlin/pklKotlinTest.gradle.kts
Normal file
57
buildSrc/src/main/kotlin/pklKotlinTest.gradle.kts
Normal file
@@ -0,0 +1,57 @@
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
import java.net.URI
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
val buildInfo = project.extensions.getByType<BuildInfo>()
|
||||
|
||||
dependencies {
|
||||
testImplementation(buildInfo.libs.findLibrary("assertj").get())
|
||||
testImplementation(buildInfo.libs.findLibrary("junitApi").get())
|
||||
testImplementation(buildInfo.libs.findLibrary("junitParams").get())
|
||||
testImplementation(buildInfo.libs.findLibrary("kotlinStdLib").get())
|
||||
|
||||
testRuntimeOnly(buildInfo.libs.findLibrary("junitEngine").get())
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
val testTask = this
|
||||
|
||||
useJUnitPlatform()
|
||||
|
||||
// enable checking of stdlib return types
|
||||
systemProperty("org.pkl.testMode", "true")
|
||||
|
||||
reports.named("html") {
|
||||
enabled = true
|
||||
}
|
||||
|
||||
testLogging {
|
||||
exceptionFormat = TestExceptionFormat.FULL
|
||||
}
|
||||
|
||||
addTestListener(object : TestListener {
|
||||
override fun beforeSuite(suite: TestDescriptor) {}
|
||||
override fun beforeTest(testDescriptor: TestDescriptor) {}
|
||||
override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) {}
|
||||
|
||||
// print report link at end of task, not just at end of build
|
||||
override fun afterSuite(descriptor: TestDescriptor, result: TestResult) {
|
||||
if (descriptor.parent != null) return // only interested in overall result
|
||||
|
||||
if (result.resultType == TestResult.ResultType.FAILURE) {
|
||||
println("\nThere were failing tests. See the report at: ${fixFileUri(testTask.reports.html.entryPoint.toURI())}")
|
||||
}
|
||||
}
|
||||
|
||||
// makes links clickable on macOS
|
||||
private fun fixFileUri(uri: URI): URI {
|
||||
if ("file" == uri.scheme && !uri.schemeSpecificPart.startsWith("//")) {
|
||||
return URI.create("file://" + uri.schemeSpecificPart)
|
||||
}
|
||||
return uri
|
||||
}
|
||||
})
|
||||
}
|
||||
7
buildSrc/src/main/kotlin/pklNativeBuild.gradle.kts
Normal file
7
buildSrc/src/main/kotlin/pklNativeBuild.gradle.kts
Normal file
@@ -0,0 +1,7 @@
|
||||
val assembleNative by tasks.registering {}
|
||||
|
||||
val checkNative by tasks.registering {}
|
||||
|
||||
val buildNative by tasks.registering {
|
||||
dependsOn(assembleNative, checkNative)
|
||||
}
|
||||
118
buildSrc/src/main/kotlin/pklPublishLibrary.gradle.kts
Normal file
118
buildSrc/src/main/kotlin/pklPublishLibrary.gradle.kts
Normal file
@@ -0,0 +1,118 @@
|
||||
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.Base64
|
||||
|
||||
plugins {
|
||||
`maven-publish`
|
||||
signing
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
components.findByName("java")?.let { javaComponent ->
|
||||
create<MavenPublication>("library") {
|
||||
from(javaComponent)
|
||||
}
|
||||
}
|
||||
withType<MavenPublication>().configureEach {
|
||||
pom {
|
||||
name.set(artifactId)
|
||||
licenses {
|
||||
license {
|
||||
name.set("The Apache Software License, Version 2.0")
|
||||
url.set("https://github.com/apple/pkl/blob/main/LICENSE.txt")
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id.set("pkl-authors")
|
||||
name.set("The Pkl Authors")
|
||||
email.set("pkl-oss@group.apple.com")
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection.set("scm:git:git://github.com/apple/pkl.git")
|
||||
developerConnection.set("scm:git:ssh://github.com/apple/pkl.git")
|
||||
val buildInfo = project.extensions.getByType<BuildInfo>()
|
||||
url.set("https://github.com/apple/pkl/tree/${buildInfo.commitish}")
|
||||
}
|
||||
issueManagement {
|
||||
system.set("GitHub Issues")
|
||||
url.set("https://github.com/apple/pkl/issues")
|
||||
}
|
||||
ciManagement {
|
||||
system.set("Circle CI")
|
||||
url.set("https://app.circleci.com/pipelines/github/apple/pkl")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val validatePom by tasks.registering {
|
||||
val generatePomFileForLibraryPublication by tasks.existing(GenerateMavenPom::class)
|
||||
val outputFile = file("$buildDir/validatePom") // dummy output to satisfy up-to-date check
|
||||
|
||||
dependsOn(generatePomFileForLibraryPublication)
|
||||
inputs.file(generatePomFileForLibraryPublication.get().destination)
|
||||
outputs.file(outputFile)
|
||||
|
||||
doLast {
|
||||
outputFile.delete()
|
||||
|
||||
val pomFile = generatePomFileForLibraryPublication.get().destination
|
||||
assert(pomFile.exists())
|
||||
|
||||
val text = pomFile.readText()
|
||||
|
||||
run {
|
||||
val unresolvedVersion = Regex("<version>.*[+,()\\[\\]].*</version>")
|
||||
val matches = unresolvedVersion.findAll(text).toList()
|
||||
if (matches.isNotEmpty()) {
|
||||
throw GradleException(
|
||||
"""
|
||||
Found unresolved version selector(s) in generated POM:
|
||||
${matches.joinToString("\n") { it.groupValues[0] }}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val buildInfo = project.extensions.getByType<BuildInfo>()
|
||||
if (buildInfo.isReleaseBuild) {
|
||||
val snapshotVersion = Regex("<version>.*-SNAPSHOT</version>")
|
||||
val matches = snapshotVersion.findAll(text).toList()
|
||||
if (matches.isNotEmpty()) {
|
||||
throw GradleException(
|
||||
"""
|
||||
Found snapshot version(s) in generated POM of Pkl release version:
|
||||
${matches.joinToString("\n") { it.groupValues[0] }}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
outputFile.writeText("OK")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.publish {
|
||||
dependsOn(validatePom)
|
||||
}
|
||||
|
||||
signing {
|
||||
// provided as env vars `ORG_GRADLE_PROJECT_signingKey` and `ORG_GRADLE_PROJECT_signingPassword`
|
||||
// in CI.
|
||||
val signingKey = (findProperty("signingKey") as String?)
|
||||
?.let { Base64.getDecoder().decode(it).toString(StandardCharsets.US_ASCII) }
|
||||
val signingPassword = findProperty("signingPassword") as String?
|
||||
if (signingKey != null && signingPassword != null) {
|
||||
useInMemoryPgpKeys(signingKey, signingPassword)
|
||||
}
|
||||
publishing.publications.findByName("library")?.let { sign(it) }
|
||||
}
|
||||
|
||||
artifacts {
|
||||
project.tasks.findByName("javadocJar")?.let { archives(it) }
|
||||
project.tasks.findByName("sourcesJar")?.let { archives(it) }
|
||||
}
|
||||
16
buildSrc/src/main/resources/license-header.line-comment.txt
Normal file
16
buildSrc/src/main/resources/license-header.line-comment.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
15
buildSrc/src/main/resources/license-header.star-block.txt
Normal file
15
buildSrc/src/main/resources/license-header.star-block.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Reference in New Issue
Block a user