11 Commits

Author SHA1 Message Date
Dan Chao
d097341abd Prepare 0.26.2 release 2024-07-18 09:13:58 -07:00
Daniel Chao
0eab5fb552 Add release notes for 0.26.2 (#586) 2024-07-18 09:13:11 -07:00
Daniel Chao
7c3787396e Fix race condition when concurrently downloading packages (#584)
This fixes a possible race condition where multiple processes download
the same package into the same temp dir.
2024-07-18 09:12:03 -07:00
Dan Chao
57df7995fd Prepare 0.26.1 release 2024-06-28 09:28:36 -07:00
Daniel Chao
6c97b09c29 Add notes for 0.26.1 (#556) 2024-06-28 09:28:23 -07:00
Daniel Chao
da19c3971e Do not enable TLS certificate revocation checks by default (#553)
This addresses an issue where network requests may fail if cert revocation checks
error, which may occur due to availability issues, or due to lack of internet access.

Revocation checking can still be enabled by setting JVM property com.sun.net.ssl.checkRevocation if on the JVM.

Also:
* Load built-in certs from resources, and move them to pkl-commons-cli
* Fix an issue where HttpInitException is not caught when loading a module
2024-06-28 09:02:44 -07:00
Daniel Chao
efad356b7b Only run Gradle compatibility tests against releases in CI (#554)
This fixes our CI tests on main. It mitigates an issue where the current RC is borked right now.
2024-06-28 09:02:37 -07:00
Daniel Chao
261a2260a1 Use compatible architecture in native executables (#551)
Use the most compatible architecture; for example, x86-64 instead of
x86-64-v3.
2024-06-28 09:02:25 -07:00
Philip K.F. Hölzenspies
204c6b16c3 Resolve project dirs from working dir by default 2024-06-28 09:02:02 -07:00
Daniel Chao
f91f91fd30 docs: add contributor for 0.26 release (#546)
Add a contributor name who was missing from acknowledgements.
2024-06-24 08:52:23 -07:00
Philip K.F. Hölzenspies
309fb49fa1 Prepare 0.26.0 release 2024-06-17 18:49:29 +01:00
36 changed files with 112 additions and 119 deletions

View File

@@ -132,8 +132,7 @@ jobs {
name = "gradle compatibility" name = "gradle compatibility"
command = #""" command = #"""
:pkl-gradle:build \ :pkl-gradle:build \
:pkl-gradle:compatibilityTestReleases \ :pkl-gradle:compatibilityTestReleases
:pkl-gradle:compatibilityTestCandidate
"""# """#
}.job }.job
["deploy-snapshot"] = new DeployJob { command = "publishToSonatype" }.job ["deploy-snapshot"] = new DeployJob { command = "publishToSonatype" }.job

View File

@@ -610,8 +610,7 @@ jobs:
- run: - run:
command: |- command: |-
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results :pkl-gradle:build \ ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results :pkl-gradle:build \
:pkl-gradle:compatibilityTestReleases \ :pkl-gradle:compatibilityTestReleases
:pkl-gradle:compatibilityTestCandidate
name: gradle compatibility name: gradle compatibility
- store_test_results: - store_test_results:
path: ~/test-results path: ~/test-results

View File

@@ -1,6 +1,6 @@
name: main name: main
title: Main Project title: Main Project
version: 0.26.0-dev version: 0.26.2
prerelease: true prerelease: false
nav: nav:
- nav.adoc - nav.adoc

View File

@@ -3,10 +3,10 @@
// the following attributes must be updated immediately before a release // the following attributes must be updated immediately before a release
// pkl version corresponding to current git commit without -dev suffix or git hash // pkl version corresponding to current git commit without -dev suffix or git hash
:pkl-version-no-suffix: 0.26.0 :pkl-version-no-suffix: 0.26.2
// tells whether pkl version corresponding to current git commit // tells whether pkl version corresponding to current git commit
// is a release version (:is-release-version: '') or dev version (:!is-release-version:) // is a release version (:is-release-version: '') or dev version (:!is-release-version:)
:!is-release-version: :is-release-version: ''
// the remaining attributes do not need to be updated regularly // the remaining attributes do not need to be updated regularly

View File

@@ -1,6 +1,6 @@
= Pkl 0.26 Release Notes = Pkl 0.26 Release Notes
:version: 0.26 :version: 0.26
:version-minor: 0.26.0 :version-minor: 0.26.2
:release-date: June 17th, 2024 :release-date: June 17th, 2024
include::ROOT:partial$component-attributes.adoc[] include::ROOT:partial$component-attributes.adoc[]
@@ -508,6 +508,7 @@ We would like to thank the contributors to this release (in alphabetical order):
* https://github.com/MarkSRobinson[@MarkSRobinson] * https://github.com/MarkSRobinson[@MarkSRobinson]
* https://github.com/mitchcapper[@mitchcapper] * https://github.com/mitchcapper[@mitchcapper]
* https://github.com/mrs1669[@mrs1669] * https://github.com/mrs1669[@mrs1669]
* https://github.com/netvl[@netvl]
* https://github.com/nirinchev[@nirinchev] * https://github.com/nirinchev[@nirinchev]
* https://github.com/raj-j-shah[@raj-j-shah] * https://github.com/raj-j-shah[@raj-j-shah]
* https://github.com/sgammon[@sgammon] * https://github.com/sgammon[@sgammon]

View File

@@ -1,6 +1,34 @@
= Changelog = Changelog
include::ROOT:partial$component-attributes.adoc[] include::ROOT:partial$component-attributes.adoc[]
[[release-0.26.2]]
== 0.26.2 (2024-07-18)
=== Fixes
* Fixes a possible race condition where multiple concurrent Pkl evaluations results in a thrown exception when downloading packages (https://github.com/apple/pkl/pull/584[#584]).
[[release-0.26.1]]
== 0.26.1 (2024-06-28)
=== Fixes
* Fixes a regression where native executables fail to run on some environments that don't support newer CPU features (https://github.com/apple/pkl/pull/551[#551]).
* Fixes a `PklBugException` when passing `.` as a project directory to `pkl project resolve` and `pkl project package` (https://github.com/apple/pkl/pull/544[#544]).
=== Changes
* Disable revocation checking of TLS certificates (https://github.com/apple/pkl/pull/553[#553]).
+
As part of HTTP improvements in 0.26, we unwittingly fixed a bug where Pkl does not actually perform cert revocation checks when making HTTPS requests.
This fix, unfortunately, caused a regression in some cases.
For example, this happens when connecting to a server that bears a public trust certificate, while in an environment with no internet access.
This is because the HTTP client needs to check the revocation status of all certificates in the chain.
+
Revocation checks are a nuanced topic with some benefits, and also with its own problem areas.
For this reason, revocation checking is disabled for Pkl's native CLIs.
Users of Pkl's Java APIs will respect the revocation settings set in the JVM.
[[release-0.26.0]] [[release-0.26.0]]
== 0.26.0 (2024-06-17) == 0.26.0 (2024-06-17)

View File

@@ -1,7 +1,7 @@
# suppress inspection "UnusedProperty" for whole file # suppress inspection "UnusedProperty" for whole file
group=org.pkl-lang group=org.pkl-lang
version=0.26.0 version=0.26.2
# google-java-format requires jdk.compiler exports # google-java-format requires jdk.compiler exports
org.gradle.jvmargs= \ org.gradle.jvmargs= \

View File

@@ -1,6 +1,3 @@
import java.security.KeyStore
import java.security.cert.CertificateFactory
plugins { plugins {
pklAllProjects pklAllProjects
pklKotlinLibrary pklKotlinLibrary
@@ -38,8 +35,6 @@ val stagedLinuxAarch64Executable: Configuration by configurations.creating
val stagedAlpineLinuxAmd64Executable: Configuration by configurations.creating val stagedAlpineLinuxAmd64Executable: Configuration by configurations.creating
val stagedWindowsAmd64Executable: Configuration by configurations.creating val stagedWindowsAmd64Executable: Configuration by configurations.creating
val certs: SourceSet by sourceSets.creating
dependencies { dependencies {
compileOnly(libs.svm) compileOnly(libs.svm)
@@ -148,38 +143,11 @@ tasks.check {
dependsOn(testStartJavaExecutable) dependsOn(testStartJavaExecutable)
} }
val trustStore = layout.buildDirectory.dir("generateTrustStore/PklCARoots.p12")
val trustStorePassword = "password" // no sensitive data to protect
// generate a trust store for Pkl's built-in CA certificates
val generateTrustStore by tasks.registering {
inputs.file(certs.resources.singleFile)
outputs.file(trustStore)
doLast {
val certificates = certs.resources.singleFile.inputStream().use { stream ->
CertificateFactory.getInstance("X.509").generateCertificates(stream)
}
KeyStore.getInstance("PKCS12").apply {
load(null, trustStorePassword.toCharArray()) // initialize empty trust store
for ((index, certificate) in certificates.withIndex()) {
setCertificateEntry("cert-$index", certificate)
}
val trustStoreFile = trustStore.get().asFile
trustStoreFile.parentFile.mkdirs()
trustStoreFile.outputStream().use { stream ->
store(stream, trustStorePassword.toCharArray())
}
}
}
}
fun Exec.configureExecutable( fun Exec.configureExecutable(
graalVm: BuildInfo.GraalVm, graalVm: BuildInfo.GraalVm,
outputFile: Provider<RegularFile>, outputFile: Provider<RegularFile>,
extraArgs: List<String> = listOf() extraArgs: List<String> = listOf()
) { ) {
dependsOn(generateTrustStore)
inputs.files(sourceSets.main.map { it.output }) inputs.files(sourceSets.main.map { it.output })
.withPropertyName("mainSourceSets") .withPropertyName("mainSourceSets")
.withPathSensitivity(PathSensitivity.RELATIVE) .withPathSensitivity(PathSensitivity.RELATIVE)
@@ -210,14 +178,10 @@ fun Exec.configureExecutable(
// needed for messagepack-java (see https://github.com/msgpack/msgpack-java/issues/600) // needed for messagepack-java (see https://github.com/msgpack/msgpack-java/issues/600)
add("--initialize-at-run-time=org.msgpack.core.buffer.DirectBufferAccess") add("--initialize-at-run-time=org.msgpack.core.buffer.DirectBufferAccess")
add("--no-fallback") add("--no-fallback")
add("-Djavax.net.ssl.trustStore=${trustStore.get().asFile}")
add("-Djavax.net.ssl.trustStorePassword=$trustStorePassword")
add("-Djavax.net.ssl.trustStoreType=PKCS12")
// security property "ocsp.enable=true" is set in Main.kt
add("-Dcom.sun.net.ssl.checkRevocation=true")
add("-H:IncludeResources=org/pkl/core/stdlib/.*\\.pkl") add("-H:IncludeResources=org/pkl/core/stdlib/.*\\.pkl")
add("-H:IncludeResources=org/jline/utils/.*") add("-H:IncludeResources=org/jline/utils/.*")
add("-H:IncludeResourceBundles=org.pkl.core.errorMessages") add("-H:IncludeResourceBundles=org.pkl.core.errorMessages")
add("-H:IncludeResources=org/pkl/commons/cli/PklCARoots.pem")
add("--macro:truffle") add("--macro:truffle")
add("-H:Class=org.pkl.cli.Main") add("-H:Class=org.pkl.cli.Main")
add("-H:Name=${outputFile.get().asFile.name}") add("-H:Name=${outputFile.get().asFile.name}")
@@ -232,6 +196,7 @@ fun Exec.configureExecutable(
if (!buildInfo.isReleaseBuild) { if (!buildInfo.isReleaseBuild) {
add("-Ob") add("-Ob")
} }
add("-march=compatibility")
// native-image rejects non-existing class path entries -> filter // native-image rejects non-existing class path entries -> filter
add("--class-path") add("--class-path")
val pathInput = sourceSets.main.get().output + configurations.runtimeClasspath.get() val pathInput = sourceSets.main.get().output + configurations.runtimeClasspath.get()
@@ -316,7 +281,7 @@ val windowsExecutableAmd64: TaskProvider<Exec> by tasks.registering(Exec::class)
configureExecutable( configureExecutable(
buildInfo.graalVmAmd64, buildInfo.graalVmAmd64,
layout.buildDirectory.file("executable/pkl-windows-amd64"), layout.buildDirectory.file("executable/pkl-windows-amd64"),
listOf("-Dfile.encoding=UTF-8", "-march=compatibility") listOf("-Dfile.encoding=UTF-8")
) )
} }

View File

@@ -35,7 +35,7 @@ abstract class CliProjectCommand(cliOptions: CliBaseOptions, private val project
) )
return@lazy listOf(projectFile.normalize()) return@lazy listOf(projectFile.normalize())
} }
projectDirs.map { dir -> projectDirs.map(cliOptions.normalizedWorkingDir::resolve).map { dir ->
val projectFile = dir.resolve(PKL_PROJECT_FILENAME) val projectFile = dir.resolve(PKL_PROJECT_FILENAME)
if (!Files.exists(projectFile)) { if (!Files.exists(projectFile)) {
throw CliException("Directory $dir does not contain a PklProject file.") throw CliException("Directory $dir does not contain a PklProject file.")

View File

@@ -171,8 +171,20 @@ abstract class CliCommand(protected val cliOptions: CliBaseOptions) {
private fun HttpClient.Builder.addDefaultCliCertificates() { private fun HttpClient.Builder.addDefaultCliCertificates() {
val caCertsDir = IoUtils.getPklHomeDir().resolve("cacerts") val caCertsDir = IoUtils.getPklHomeDir().resolve("cacerts")
var certsAdded = false
if (Files.isDirectory(caCertsDir)) { if (Files.isDirectory(caCertsDir)) {
Files.list(caCertsDir).filter { it.isRegularFile() }.forEach { addCertificates(it) } Files.list(caCertsDir)
.filter { it.isRegularFile() }
.forEach { cert ->
certsAdded = true
addCertificates(cert)
}
}
if (!certsAdded) {
val defaultCerts =
javaClass.classLoader.getResourceAsStream("org/pkl/commons/cli/PklCARoots.pem")
?: throw CliException("Could not find bundled certificates")
addCertificates(defaultCerts.readAllBytes())
} }
} }

View File

@@ -16,7 +16,6 @@
package org.pkl.commons.cli package org.pkl.commons.cli
import java.io.PrintStream import java.io.PrintStream
import java.security.Security
import kotlin.system.exitProcess import kotlin.system.exitProcess
/** Building block for CLIs. Intended to be called from a `main` method. */ /** Building block for CLIs. Intended to be called from a `main` method. */
@@ -30,9 +29,6 @@ fun cliMain(block: () -> Unit) {
// Force `native-image` to use system proxies (which does not happen with `-D`). // Force `native-image` to use system proxies (which does not happen with `-D`).
System.setProperty("java.net.useSystemProxies", "true") System.setProperty("java.net.useSystemProxies", "true")
// enable OCSP for default SSL context
Security.setProperty("ocsp.enable", "true")
try { try {
block() block()
} catch (e: CliTestException) { } catch (e: CliTestException) {

View File

@@ -31,22 +31,17 @@ import java.nio.file.Files;
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.cert.CertPathBuilder; import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import javax.net.ssl.CertPathTrustManagerParameters;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLHandshakeException;
@@ -130,43 +125,36 @@ final class JdkHttpClient implements HttpClient {
List<Path> certificateFiles, List<ByteBuffer> certificateBytes) { List<Path> certificateFiles, List<ByteBuffer> certificateBytes) {
try { try {
if (certificateFiles.isEmpty() && certificateBytes.isEmpty()) { if (certificateFiles.isEmpty() && certificateBytes.isEmpty()) {
// use Pkl native executable's or JVM's built-in CA certificates // use JVM's built-in CA certificates
return SSLContext.getDefault(); return SSLContext.getDefault();
} }
var certPathBuilder = CertPathBuilder.getInstance("PKIX");
// create a non-legacy revocation checker that is configured via setOptions() instead of
// security property "ocsp.enabled"
var revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();
revocationChecker.setOptions(Set.of()); // prefer OCSP, fall back to CRLs
var certFactory = CertificateFactory.getInstance("X.509"); var certFactory = CertificateFactory.getInstance("X.509");
Set<TrustAnchor> trustAnchors = List<Certificate> certs = gatherCertificates(certFactory, certificateFiles, certificateBytes);
createTrustAnchors(certFactory, certificateFiles, certificateBytes); var keystore = KeyStore.getInstance(KeyStore.getDefaultType());
var pkixParameters = new PKIXBuilderParameters(trustAnchors, new X509CertSelector()); keystore.load(null);
// equivalent of "com.sun.net.ssl.checkRevocation=true" for (var i = 0; i < certs.size(); i++) {
pkixParameters.setRevocationEnabled(true); keystore.setCertificateEntry("Certificate" + i, certs.get(i));
pkixParameters.addCertPathChecker(revocationChecker); }
var trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); var trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
trustManagerFactory.init(new CertPathTrustManagerParameters(pkixParameters)); trustManagerFactory.init(keystore);
var sslContext = SSLContext.getInstance("TLS"); var sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom()); sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
return sslContext; return sslContext;
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException | IOException e) {
throw new HttpClientInitException( throw new HttpClientInitException(
ErrorMessages.create("cannotInitHttpClient", Exceptions.getRootReason(e)), e); ErrorMessages.create("cannotInitHttpClient", Exceptions.getRootReason(e)), e);
} }
} }
private static Set<TrustAnchor> createTrustAnchors( private static List<Certificate> gatherCertificates(
CertificateFactory factory, List<Path> certificateFiles, List<ByteBuffer> certificateBytes) { CertificateFactory factory, List<Path> certificateFiles, List<ByteBuffer> certificateBytes) {
var anchors = new HashSet<TrustAnchor>(); var certificates = new ArrayList<Certificate>();
for (var file : certificateFiles) { for (var file : certificateFiles) {
try (var stream = Files.newInputStream(file)) { try (var stream = Files.newInputStream(file)) {
collectTrustAnchors(anchors, factory, stream, file); collectCertificates(certificates, factory, stream, file);
} catch (NoSuchFileException e) { } catch (NoSuchFileException e) {
throw new HttpClientInitException(ErrorMessages.create("cannotFindCertFile", file)); throw new HttpClientInitException(ErrorMessages.create("cannotFindCertFile", file));
} catch (IOException e) { } catch (IOException e) {
@@ -176,13 +164,13 @@ final class JdkHttpClient implements HttpClient {
} }
for (var byteBuffer : certificateBytes) { for (var byteBuffer : certificateBytes) {
var stream = new ByteArrayInputStream(byteBuffer.array()); var stream = new ByteArrayInputStream(byteBuffer.array());
collectTrustAnchors(anchors, factory, stream, "<unavailable>"); collectCertificates(certificates, factory, stream, "<unavailable>");
} }
return anchors; return certificates;
} }
private static void collectTrustAnchors( private static void collectCertificates(
Collection<TrustAnchor> anchors, ArrayList<Certificate> anchors,
CertificateFactory factory, CertificateFactory factory,
InputStream stream, InputStream stream,
Object source) { Object source) {
@@ -197,8 +185,6 @@ final class JdkHttpClient implements HttpClient {
if (certificates.isEmpty()) { if (certificates.isEmpty()) {
throw new HttpClientInitException(ErrorMessages.create("emptyCertFile", source)); throw new HttpClientInitException(ErrorMessages.create("emptyCertFile", source));
} }
for (var certificate : certificates) { anchors.addAll(certificates);
anchors.add(new TrustAnchor(certificate, null));
}
} }
} }

View File

@@ -455,10 +455,9 @@ final class PackageResolvers {
private byte[] downloadUriToPathAndComputeChecksum(URI downloadUri, Path path) private byte[] downloadUriToPathAndComputeChecksum(URI downloadUri, Path path)
throws IOException, SecurityManagerException { throws IOException, SecurityManagerException {
Files.createDirectories(path.getParent());
var inputStream = openExternalUri(downloadUri); var inputStream = openExternalUri(downloadUri);
try (var digestInputStream = newDigestInputStream(inputStream)) { try (var digestInputStream = newDigestInputStream(inputStream)) {
Files.copy(digestInputStream, path); Files.copy(digestInputStream, path, StandardCopyOption.REPLACE_EXISTING);
return digestInputStream.getMessageDigest().digest(); return digestInputStream.getMessageDigest().digest();
} }
} }
@@ -472,7 +471,7 @@ final class PackageResolvers {
} }
try (var in = inputStream) { try (var in = inputStream) {
Files.createDirectories(path.getParent()); Files.createDirectories(path.getParent());
Files.copy(in, path); Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING);
if (checksums != null) { if (checksums != null) {
var digestInputStream = (DigestInputStream) inputStream; var digestInputStream = (DigestInputStream) inputStream;
var checksumBytes = digestInputStream.getMessageDigest().digest(); var checksumBytes = digestInputStream.getMessageDigest().digest();
@@ -490,7 +489,10 @@ final class PackageResolvers {
if (Files.exists(cachePath)) { if (Files.exists(cachePath)) {
return cachePath; return cachePath;
} }
var tmpPath = tmpDir.resolve(metadataRelativePath); Files.createDirectories(tmpDir);
var tmpPath =
Files.createTempFile(
tmpDir, IoUtils.encodePath(packageUri.toString().replaceAll("/", "-")), ".json");
try { try {
downloadMetadata(packageUri, requestUri, tmpPath, checksums); downloadMetadata(packageUri, requestUri, tmpPath, checksums);
Files.createDirectories(cachePath.getParent()); Files.createDirectories(cachePath.getParent());
@@ -539,7 +541,10 @@ final class PackageResolvers {
if (Files.exists(cachePath)) { if (Files.exists(cachePath)) {
return cachePath; return cachePath;
} }
var tmpPath = tmpDir.resolve(relativePath); Files.createDirectories(tmpDir);
var tmpPath =
Files.createTempFile(
tmpDir, IoUtils.encodePath(packageUri.toString().replaceAll("/", "-")), ".zip");
try { try {
var checksumBytes = var checksumBytes =
downloadUriToPathAndComputeChecksum(dependencyMetadata.getPackageZipUrl(), tmpPath); downloadUriToPathAndComputeChecksum(dependencyMetadata.getPackageZipUrl(), tmpPath);

View File

@@ -30,6 +30,7 @@ import java.util.stream.Collectors;
import org.pkl.core.Release; import org.pkl.core.Release;
import org.pkl.core.SecurityManager; import org.pkl.core.SecurityManager;
import org.pkl.core.SecurityManagerException; import org.pkl.core.SecurityManagerException;
import org.pkl.core.http.HttpClientInitException;
import org.pkl.core.module.ModuleKey; import org.pkl.core.module.ModuleKey;
import org.pkl.core.module.ModuleKeys; import org.pkl.core.module.ModuleKeys;
import org.pkl.core.module.ResolvedModuleKey; import org.pkl.core.module.ResolvedModuleKey;
@@ -191,7 +192,7 @@ public final class ModuleCache {
ModuleKey module, SecurityManager securityManager, @Nullable Node importNode) { ModuleKey module, SecurityManager securityManager, @Nullable Node importNode) {
try { try {
return module.resolve(securityManager); return module.resolve(securityManager);
} catch (SecurityManagerException | PackageLoadError e) { } catch (SecurityManagerException | PackageLoadError | HttpClientInitException e) {
throw new VmExceptionBuilder().withOptionalLocation(importNode).withCause(e).build(); throw new VmExceptionBuilder().withOptionalLocation(importNode).withCause(e).build();
} catch (FileNotFoundException | NoSuchFileException e) { } catch (FileNotFoundException | NoSuchFileException e) {
var exceptionBuilder = var exceptionBuilder =

View File

@@ -33,7 +33,7 @@ import org.pkl.core.util.Nullable;
@TruffleLanguage.Registration( @TruffleLanguage.Registration(
id = "pkl", id = "pkl",
name = "Pkl", name = "Pkl",
version = "0.26.0-dev", version = "0.26.2",
characterMimeTypes = VmLanguage.MIME_TYPE, characterMimeTypes = VmLanguage.MIME_TYPE,
contextPolicy = ContextPolicy.SHARED) contextPolicy = ContextPolicy.SHARED)
public final class VmLanguage extends TruffleLanguage<VmContext> { public final class VmLanguage extends TruffleLanguage<VmContext> {

View File

@@ -2,10 +2,9 @@ package org.pkl.core.packages
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatCode import org.assertj.core.api.Assertions.assertThatCode
import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.*
import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.Test import org.junit.jupiter.api.parallel.ExecutionMode
import org.junit.jupiter.api.assertThrows
import org.pkl.commons.deleteRecursively import org.pkl.commons.deleteRecursively
import org.pkl.commons.readString import org.pkl.commons.readString
import org.pkl.commons.test.FileTestUtils import org.pkl.commons.test.FileTestUtils
@@ -44,7 +43,9 @@ class PackageResolversTest {
} }
} }
@Test // execute test 3 times to check concurrent writes
@RepeatedTest(3)
@Execution(ExecutionMode.CONCURRENT)
fun `get module bytes`() { fun `get module bytes`() {
val expectedBirdModule = packageRoot.resolve("birds@0.5.0/package/Bird.pkl").readString(StandardCharsets.UTF_8) val expectedBirdModule = packageRoot.resolve("birds@0.5.0/package/Bird.pkl").readString(StandardCharsets.UTF_8)
val assetUri = PackageAssetUri("package://localhost:0/birds@0.5.0#/Bird.pkl") val assetUri = PackageAssetUri("package://localhost:0/birds@0.5.0#/Bird.pkl")

View File

@@ -36,7 +36,7 @@
/// ///
/// Warning: Although this module is ready for initial use, /// Warning: Although this module is ready for initial use,
/// benchmark results may be inaccurate or inconsistent. /// benchmark results may be inaccurate or inconsistent.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.Benchmark module pkl.Benchmark
import "pkl:platform" as _platform import "pkl:platform" as _platform

View File

@@ -63,7 +63,7 @@
/// @Deprecated { message = "Use `com.example.Birds.Parrot` instead" } /// @Deprecated { message = "Use `com.example.Birds.Parrot` instead" }
/// amends "pkl:PackageInfo" /// amends "pkl:PackageInfo"
/// ``` /// ```
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.DocPackageInfo module pkl.DocPackageInfo
import "pkl:reflect" import "pkl:reflect"

View File

@@ -31,7 +31,7 @@
/// ///
/// title = "Title displayed in the header of each page" /// title = "Title displayed in the header of each page"
/// ``` /// ```
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.DocsiteInfo module pkl.DocsiteInfo
import "pkl:reflect" import "pkl:reflect"

View File

@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Common settings for Pkl's own evaluator. /// Common settings for Pkl's own evaluator.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
@Since { version = "0.26.0" } @Since { version = "0.26.0" }
module pkl.EvaluatorSettings module pkl.EvaluatorSettings

View File

@@ -64,7 +64,7 @@
/// value = project /// value = project
/// } /// }
/// ``` /// ```
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.Project module pkl.Project
import "pkl:EvaluatorSettings" as EvaluatorSettingsModule import "pkl:EvaluatorSettings" as EvaluatorSettingsModule

View File

@@ -17,7 +17,7 @@
/// Fundamental properties, methods, and classes for writing Pkl programs. /// Fundamental properties, methods, and classes for writing Pkl programs.
/// ///
/// Members of this module are automatically available in every Pkl module. /// Members of this module are automatically available in every Pkl module.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.base module pkl.base
import "pkl:jsonnet" import "pkl:jsonnet"

View File

@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// A JSON parser. /// A JSON parser.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.json module pkl.json
/// A JSON parser. /// A JSON parser.

View File

@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// A [Jsonnet](https://jsonnet.org) renderer. /// A [Jsonnet](https://jsonnet.org) renderer.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.jsonnet module pkl.jsonnet
/// Constructs an [ImportStr]. /// Constructs an [ImportStr].

View File

@@ -18,7 +18,7 @@
/// ///
/// Note that some mathematical functions, such as `sign()`, `abs()`, and `round()`, /// Note that some mathematical functions, such as `sign()`, `abs()`, and `round()`,
/// are directly defined in classes [Number], [Int], and [Float]. /// are directly defined in classes [Number], [Int], and [Float].
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.math module pkl.math
/// The minimum [Int] value: `-9223372036854775808`. /// The minimum [Int] value: `-9223372036854775808`.

View File

@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Information about the platform that the current program runs on. /// Information about the platform that the current program runs on.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.platform module pkl.platform
/// The platform that the current program runs on. /// The platform that the current program runs on.

View File

@@ -16,7 +16,7 @@
/// A renderer for [Protocol Buffers](https://developers.google.com/protocol-buffers). /// A renderer for [Protocol Buffers](https://developers.google.com/protocol-buffers).
/// Note: This module is _experimental_ and not ready for production use. /// Note: This module is _experimental_ and not ready for production use.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.protobuf module pkl.protobuf
import "pkl:reflect" import "pkl:reflect"

View File

@@ -26,7 +26,7 @@
/// - Documentation generators (such as *Pkldoc*) /// - Documentation generators (such as *Pkldoc*)
/// - Code generators (such as *pkl-codegen-java* and *pkl-codegen-kotlin*) /// - Code generators (such as *pkl-codegen-java* and *pkl-codegen-kotlin*)
/// - Domain-specific schema validators /// - Domain-specific schema validators
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.reflect module pkl.reflect
import "pkl:base" import "pkl:base"

View File

@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Information about the Pkl release that the current program runs on. /// Information about the Pkl release that the current program runs on.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.release module pkl.release
import "pkl:semver" import "pkl:semver"

View File

@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Parsing, comparison, and manipulation of [semantic version](https://semver.org/spec/v2.0.0.html) numbers. /// Parsing, comparison, and manipulation of [semantic version](https://semver.org/spec/v2.0.0.html) numbers.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.semver module pkl.semver
/// Tells whether [version] is a valid semantic version number. /// Tells whether [version] is a valid semantic version number.

View File

@@ -19,7 +19,7 @@
/// Every settings file must amend this module. /// Every settings file must amend this module.
/// Unless CLI commands and build tool plugins are explicitly configured with a settings file, /// Unless CLI commands and build tool plugins are explicitly configured with a settings file,
/// they will use `~/.pkl/settings.pkl` or the defaults specified in this module. /// they will use `~/.pkl/settings.pkl` or the defaults specified in this module.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.settings module pkl.settings
import "pkl:EvaluatorSettings" import "pkl:EvaluatorSettings"

View File

@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// Utilities for generating shell scripts. /// Utilities for generating shell scripts.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.shell module pkl.shell
/// Escapes [str] by enclosing it in single quotes. /// Escapes [str] by enclosing it in single quotes.

View File

@@ -18,7 +18,7 @@
/// ///
/// To write tests, amend this module and define [facts] or [examples] (or both). /// To write tests, amend this module and define [facts] or [examples] (or both).
/// To run tests, evaluate the amended module. /// To run tests, evaluate the amended module.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
open module pkl.test open module pkl.test
/// Named groups of boolean expressions that are expected to evaluate to [true]. /// Named groups of boolean expressions that are expected to evaluate to [true].

View File

@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// An XML renderer. /// An XML renderer.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.xml module pkl.xml
/// Renders values as XML. /// Renders values as XML.

View File

@@ -15,7 +15,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// A YAML 1.2 compliant YAML parser. /// A YAML 1.2 compliant YAML parser.
@ModuleInfo { minPklVersion = "0.26.0" } @ModuleInfo { minPklVersion = "0.26.1" }
module pkl.yaml module pkl.yaml
/// A YAML parser. /// A YAML parser.