mirror of
https://github.com/apple/pkl.git
synced 2026-03-23 17:41:10 +01:00
Moving to java.net.http.HttpClient brings many benefits, including HTTP/2 support and the ability to make asynchronous requests. Major additions and changes: - Introduce a lightweight org.pkl.core.http.HttpClient API. This keeps some flexibility and allows to enforce behavior such as setting the User-Agent header. - Provide an implementation that delegates to java.net.http.HttpClient. - Use HttpClient for all HTTP(s) requests across the codebase. This required adding an HttpClient parameter to constructors and factory methods of multiple classes, some of which are public APIs. - Manage CA certificates per HTTP client instead of per JVM. This makes it unnecessary to set JVM-wide system/security properties and default SSLSocketFactory's. - Add executor v2 options to the executor SPI - Add pkl-certs as a new artifact, and remove certs from pkl-commons-cli artifact Each HTTP client maintains its own connection pool and SSLContext. For efficiency reasons, It's best to reuse clients whenever feasible. To avoid memory leaks, clients are not stored in static fields. HTTP clients are expensive to create. For this reason, EvaluatorBuilder defaults to a "lazy" client that creates the underlying java.net.http.HttpClient on the first send (which may never happen).
381 lines
13 KiB
Kotlin
381 lines
13 KiB
Kotlin
plugins {
|
|
pklAllProjects
|
|
pklKotlinLibrary
|
|
pklPublishLibrary
|
|
pklNativeBuild
|
|
`maven-publish`
|
|
|
|
// already on build script class path (see buildSrc/build.gradle.kts),
|
|
// hence must only specify plugin ID here
|
|
@Suppress("DSL_SCOPE_VIOLATION")
|
|
id(libs.plugins.shadow.get().pluginId)
|
|
|
|
@Suppress("DSL_SCOPE_VIOLATION")
|
|
alias(libs.plugins.checksum)
|
|
}
|
|
|
|
// make Java executable available to other subprojects
|
|
val javaExecutableConfiguration: Configuration = configurations.create("javaExecutable")
|
|
|
|
publishing {
|
|
publications {
|
|
named<MavenPublication>("library") {
|
|
pom {
|
|
url.set("https://github.com/apple/pkl/tree/main/pkl-cli")
|
|
description.set("Pkl CLI Java library.")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
val stagedMacAmd64Executable: Configuration by configurations.creating
|
|
val stagedMacAarch64Executable: Configuration by configurations.creating
|
|
val stagedLinuxAmd64Executable: Configuration by configurations.creating
|
|
val stagedLinuxAarch64Executable: Configuration by configurations.creating
|
|
val stagedAlpineLinuxAmd64Executable: Configuration by configurations.creating
|
|
|
|
dependencies {
|
|
compileOnly(libs.svm)
|
|
|
|
// CliEvaluator exposes PClass
|
|
api(projects.pklCore)
|
|
// CliEvaluatorOptions exposes CliBaseOptions
|
|
api(projects.pklCommonsCli)
|
|
|
|
implementation(projects.pklCommons)
|
|
implementation(libs.jansi)
|
|
implementation(libs.jlineReader)
|
|
implementation(libs.jlineTerminal)
|
|
implementation(libs.jlineTerminalJansi)
|
|
implementation(projects.pklServer)
|
|
implementation(libs.clikt) {
|
|
// force clikt to use our version of the kotlin stdlib
|
|
exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib-jdk8")
|
|
exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib-common")
|
|
}
|
|
|
|
testImplementation(projects.pklCommonsTest)
|
|
|
|
stagedMacAmd64Executable(files("$buildDir/executable/pkl-macos-amd64"))
|
|
stagedMacAarch64Executable(files("$buildDir/executable/pkl-macos-aarch64"))
|
|
stagedLinuxAmd64Executable(files("$buildDir/executable/pkl-linux-amd64"))
|
|
stagedLinuxAarch64Executable(files("$buildDir/executable/pkl-linux-aarch64"))
|
|
stagedAlpineLinuxAmd64Executable(files("$buildDir/executable/pkl-alpine-linux-amd64"))
|
|
}
|
|
|
|
tasks.jar {
|
|
manifest {
|
|
attributes += mapOf("Main-Class" to "org.pkl.cli.Main")
|
|
}
|
|
|
|
// not required at runtime
|
|
exclude("org/pkl/cli/svm/**")
|
|
}
|
|
|
|
tasks.javadoc {
|
|
enabled = false
|
|
}
|
|
|
|
tasks.shadowJar {
|
|
archiveFileName.set("jpkl")
|
|
|
|
exclude("META-INF/maven/**")
|
|
exclude("META-INF/upgrade/**")
|
|
|
|
// org.antlr.v4.runtime.misc.RuleDependencyProcessor
|
|
exclude("META-INF/services/javax.annotation.processing.Processor")
|
|
|
|
exclude("module-info.*")
|
|
}
|
|
|
|
val javaExecutable by tasks.registering(ExecutableJar::class) {
|
|
inJar.set(tasks.shadowJar.flatMap { it.archiveFile })
|
|
outJar.set(file("$buildDir/executable/jpkl"))
|
|
|
|
// uncomment for debugging
|
|
//jvmArgs.addAll("-ea", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005")
|
|
}
|
|
|
|
val testJavaExecutable by tasks.registering(Test::class) {
|
|
testClassesDirs = tasks.test.get().testClassesDirs
|
|
classpath =
|
|
// compiled test classes
|
|
sourceSets.test.get().output +
|
|
// java executable
|
|
javaExecutable.get().outputs.files +
|
|
// test-only dependencies
|
|
// (test dependencies that are also main dependencies must already be contained in java executable;
|
|
// to verify that, we don't want to include them here)
|
|
(configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get())
|
|
}
|
|
|
|
tasks.check {
|
|
dependsOn(testJavaExecutable)
|
|
}
|
|
|
|
// 0.14 Java executable was broken because javaExecutable.jvmArgs wasn't commented out.
|
|
// To catch this and similar problems, test that Java executable starts successfully.
|
|
val testStartJavaExecutable by tasks.registering(Exec::class) {
|
|
dependsOn(javaExecutable)
|
|
val outputFile = file("$buildDir/testStartJavaExecutable") // dummy output to satisfy up-to-date check
|
|
outputs.file(outputFile)
|
|
|
|
executable = javaExecutable.get().outputs.files.singleFile.toString()
|
|
args("--version")
|
|
|
|
doFirst { outputFile.delete() }
|
|
|
|
doLast { outputFile.writeText("OK") }
|
|
}
|
|
|
|
tasks.check {
|
|
dependsOn(testStartJavaExecutable)
|
|
}
|
|
|
|
fun Exec.configureExecutable(isEnabled: Boolean, outputFile: File, extraArgs: List<String> = listOf()) {
|
|
enabled = isEnabled
|
|
dependsOn(":installGraalVm")
|
|
|
|
inputs.files(sourceSets.main.map { it.output })
|
|
inputs.files(configurations.runtimeClasspath)
|
|
outputs.file(outputFile)
|
|
|
|
workingDir = outputFile.parentFile
|
|
executable = "${buildInfo.graalVm.baseDir}/bin/native-image"
|
|
|
|
// JARs to exclude from the class path for the native-image build.
|
|
val exclusions =
|
|
if (buildInfo.graalVm.isGraal22) emptyList()
|
|
else listOf(libs.truffleApi, libs.graalSdk).map { it.get().module.name }
|
|
// https://www.graalvm.org/22.0/reference-manual/native-image/Options/
|
|
argumentProviders.add(CommandLineArgumentProvider {
|
|
listOf(
|
|
// currently gives a deprecation warning, but we've been told
|
|
// that the "initialize everything at build time" *CLI* option is likely here to stay
|
|
"--initialize-at-build-time="
|
|
,"--no-fallback"
|
|
,"-H:IncludeResources=org/pkl/core/stdlib/.*\\.pkl"
|
|
,"-H:IncludeResources=org/jline/utils/.*"
|
|
,"-H:IncludeResources=org/pkl/certs/PklCARoots.pem"
|
|
//,"-H:IncludeResources=org/pkl/core/Release.properties"
|
|
,"-H:IncludeResourceBundles=org.pkl.core.errorMessages"
|
|
,"--macro:truffle"
|
|
,"-H:Class=org.pkl.cli.Main"
|
|
,"-H:Name=${outputFile.name}"
|
|
//,"--native-image-info"
|
|
//,"-Dpolyglot.image-build-time.PreinitializeContexts=pkl"
|
|
// the actual limit (currently) used by native-image is this number + 1400 (idea is to compensate for Truffle's own nodes)
|
|
,"-H:MaxRuntimeCompileMethods=1800"
|
|
,"-H:+EnforceMaxRuntimeCompileMethods"
|
|
,"--enable-url-protocols=http,https"
|
|
//,"--install-exit-handlers"
|
|
,"-H:+ReportExceptionStackTraces"
|
|
,"-H:-ParseRuntimeOptions" // disable automatic support for JVM CLI options (puts our main class in full control of argument parsing)
|
|
//,"-H:+PrintAnalysisCallTree"
|
|
//,"-H:PrintAnalysisCallTreeType=CSV"
|
|
//,"-H:+PrintImageObjectTree"
|
|
//,"--features=org.pkl.cli.svm.InitFeature"
|
|
//,"-H:Dump=:2"
|
|
//,"-H:MethodFilter=ModuleCache.getOrLoad*,VmLanguage.loadModule"
|
|
//,"-g"
|
|
//,"-verbose"
|
|
//,"--debug-attach"
|
|
//,"-H:+AllowVMInspection"
|
|
//,"-H:+PrintHeapHistogram"
|
|
//,"-H:+ReportDeletedElementsAtRuntime"
|
|
//,"-H:+PrintMethodHistogram"
|
|
//,"-H:+PrintRuntimeCompileMethods"
|
|
//,"-H:NumberOfThreads=1"
|
|
//,"-J-Dtruffle.TruffleRuntime=com.oracle.truffle.api.impl.DefaultTruffleRuntime"
|
|
//,"-J-Dcom.oracle.truffle.aot=true"
|
|
//,"-J:-ea"
|
|
//,"-J:-esa"
|
|
// for use with https://www.graalvm.org/docs/tools/dashboard/
|
|
//,"-H:DashboardDump=dashboard.dump", "-H:+DashboardAll"
|
|
// native-image rejects non-existing class path entries -> filter
|
|
,"--class-path"
|
|
,((sourceSets.main.get().output + configurations.runtimeClasspath.get())
|
|
.filter { it.exists() && !exclusions.any { exclude -> it.name.contains(exclude) }})
|
|
.asPath
|
|
// make sure dev machine stays responsive (15% slowdown on my laptop)
|
|
,"-J-XX:ActiveProcessorCount=${
|
|
Runtime.getRuntime().availableProcessors() / (if (buildInfo.os.isMacOsX && !buildInfo.isCiBuild) 4 else 1)
|
|
}"
|
|
) + extraArgs
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Builds the pkl CLI for macOS/amd64.
|
|
*/
|
|
val macExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class) {
|
|
configureExecutable(buildInfo.os.isMacOsX && buildInfo.graalVm.isGraal22, file("$buildDir/executable/pkl-macos-amd64"))
|
|
}
|
|
|
|
/**
|
|
* Builds the pkl CLI for macOS/aarch64.
|
|
*
|
|
* This requires that GraalVM be set to version 23.0 or greater, because 22.x does not support this
|
|
* os/arch pair.
|
|
*/
|
|
val macExecutableAarch64: TaskProvider<Exec> by tasks.registering(Exec::class) {
|
|
configureExecutable(
|
|
buildInfo.os.isMacOsX && !buildInfo.graalVm.isGraal22,
|
|
file("$buildDir/executable/pkl-macos-aarch64"),
|
|
listOf(
|
|
"--initialize-at-run-time=org.msgpack.core.buffer.DirectBufferAccess",
|
|
"-H:+AllowDeprecatedBuilderClassesOnImageClasspath"
|
|
)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Builds the pkl CLI for linux/amd64.
|
|
*/
|
|
val linuxExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class) {
|
|
configureExecutable(buildInfo.os.isLinux && buildInfo.arch == "amd64", file("$buildDir/executable/pkl-linux-amd64"))
|
|
}
|
|
|
|
/**
|
|
* Builds the pkl CLI for linux/aarch64.
|
|
*
|
|
* Right now, this is built within a container on Mac using emulation because CI does not have
|
|
* ARM instances.
|
|
*/
|
|
val linuxExecutableAarch64: TaskProvider<Exec> by tasks.registering(Exec::class) {
|
|
configureExecutable(buildInfo.os.isLinux && buildInfo.arch == "aarch64", file("$buildDir/executable/pkl-linux-aarch64"))
|
|
}
|
|
|
|
/**
|
|
* Builds a statically linked CLI for linux/amd64.
|
|
*
|
|
* Note: we don't publish the same for linux/aarch64 because native-image doesn't support this.
|
|
* Details: https://www.graalvm.org/22.0/reference-manual/native-image/ARM64/
|
|
*/
|
|
val alpineExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class) {
|
|
configureExecutable(
|
|
buildInfo.os.isLinux && buildInfo.arch == "amd64" && buildInfo.hasMuslToolchain,
|
|
file("$buildDir/executable/pkl-alpine-linux-amd64"),
|
|
listOf(
|
|
"--static",
|
|
"--libc=musl",
|
|
"-H:CCompilerOption=-Wl,-z,stack-size=10485760",
|
|
"-Dorg.pkl.compat=alpine"
|
|
)
|
|
)
|
|
}
|
|
|
|
tasks.assembleNative {
|
|
dependsOn(macExecutableAmd64, macExecutableAarch64, linuxExecutableAmd64, linuxExecutableAarch64, alpineExecutableAmd64)
|
|
}
|
|
|
|
// make Java executable available to other subprojects
|
|
// (we don't do the same for native executables because we don't want tasks assemble/build to build them)
|
|
artifacts {
|
|
add("javaExecutable", javaExecutable.map { it.outputs.files.singleFile }) {
|
|
name = "pkl-cli-java"
|
|
classifier = null
|
|
extension = "jar"
|
|
builtBy(javaExecutable)
|
|
}
|
|
}
|
|
|
|
//region Maven Publishing
|
|
publishing {
|
|
publications {
|
|
register<MavenPublication>("javaExecutable") {
|
|
artifactId = "pkl-cli-java"
|
|
|
|
artifact(javaExecutable.map { it.outputs.files.singleFile }) {
|
|
classifier = null
|
|
extension = "jar"
|
|
builtBy(javaExecutable)
|
|
}
|
|
|
|
pom {
|
|
url.set("https://github.com/apple/pkl/tree/main/pkl-cli")
|
|
description.set("""
|
|
Pkl CLI executable for Java.
|
|
Can be executed directly on *nix (if the `java` command is found on the PATH) and with `java -jar` otherwise.
|
|
Requires Java 11 or higher.
|
|
""".trimIndent())
|
|
}
|
|
}
|
|
create<MavenPublication>("macExecutableAmd64") {
|
|
artifactId = "pkl-cli-macos-amd64"
|
|
artifact(stagedMacAmd64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedMacAmd64Executable)
|
|
}
|
|
pom {
|
|
name.set("pkl-cli-macos-amd64")
|
|
url.set("https://github.com/apple/pkl/tree/main/pkl-cli")
|
|
description.set("Native Pkl CLI executable for macOS/amd64.")
|
|
}
|
|
}
|
|
create<MavenPublication>("macExecutableAarch64") {
|
|
artifactId = "pkl-cli-macos-aarch64"
|
|
artifact(stagedMacAarch64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedMacAarch64Executable)
|
|
}
|
|
pom {
|
|
name.set("pkl-cli-macos-aarch64")
|
|
url.set("https://github.com/apple/pkl/tree/main/pkl-cli")
|
|
description.set("Native Pkl CLI executable for macOS/aarch64.")
|
|
}
|
|
}
|
|
create<MavenPublication>("linuxExecutableAmd64") {
|
|
artifactId = "pkl-cli-linux-amd64"
|
|
artifact(stagedLinuxAmd64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedLinuxAmd64Executable)
|
|
}
|
|
pom {
|
|
name.set("pkl-cli-linux-amd64")
|
|
url.set("https://github.com/apple/pkl/tree/main/pkl-cli")
|
|
description.set("Native Pkl CLI executable for linux/amd64.")
|
|
}
|
|
}
|
|
create<MavenPublication>("linuxExecutableAarch64") {
|
|
artifactId = "pkl-cli-linux-aarch64"
|
|
artifact(stagedLinuxAarch64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedLinuxAarch64Executable)
|
|
}
|
|
pom {
|
|
name.set("pkl-cli-linux-aarch64")
|
|
url.set("https://github.com/apple/pkl/tree/main/pkl-cli")
|
|
description.set("Native Pkl CLI executable for linux/aarch64.")
|
|
}
|
|
}
|
|
create<MavenPublication>("alpineLinuxExecutableAmd64") {
|
|
artifactId = "pkl-cli-alpine-linux-amd64"
|
|
artifact(stagedAlpineLinuxAmd64Executable.singleFile) {
|
|
classifier = null
|
|
extension = "bin"
|
|
builtBy(stagedAlpineLinuxAmd64Executable)
|
|
}
|
|
pom {
|
|
name.set("pkl-cli-alpine-linux-amd64")
|
|
url.set("https://github.com/apple/pkl/tree/main/pkl-cli")
|
|
description.set("Native Pkl CLI executable for linux/amd64 and statically linked to musl.")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
signing {
|
|
sign(publishing.publications["javaExecutable"])
|
|
sign(publishing.publications["linuxExecutableAarch64"])
|
|
sign(publishing.publications["linuxExecutableAmd64"])
|
|
sign(publishing.publications["macExecutableAarch64"])
|
|
sign(publishing.publications["macExecutableAmd64"])
|
|
sign(publishing.publications["alpineLinuxExecutableAmd64"])
|
|
}
|
|
//endregion
|