Compare commits

..

94 Commits

Author SHA1 Message Date
Islon Scherer 842c46e358 remove folders from build executable dir 2025-02-26 17:52:27 +01:00
Islon Scherer 52c2b29a04 change version to 0.28.0 2025-02-26 17:09:14 +01:00
Daniel Chao cf889246fd Add release notes for 0.28 (#978)
Co-authored-by: Islon Scherer <islonscherer@gmail.com>
2025-02-26 07:52:21 -08:00
Daniel Chao fcce5c7e11 Replace dead links to ANTLR parser grammar (#973) 2025-02-21 08:26:49 -08:00
odenix 52a86d3f32 Untangle external reader code (#776)
- move the following classes into package externalreader:
  - ExternalModuleResolver
  - ExternalResourceResolver
  - MessageTransportModuleResolver (renamed to ExternalModuleResolverImpl, made package-private)
  - MessageTransportResourceResolver (renamed to ExternalResourceResolverImpl, made package-private)
- replace interface ExternalModuleResolver.Spec with record ExternalModuleReaderSpec
- replace interface ExternalResourceResolver.Spec with record ExternalResourceReaderSpec
- translate between messaging.ResourceReaderSpec and ExternalResourceReaderSpec (eliminates dependency from messaging on higher layer)
- translate between messaging.ResourceResolverSpec and ExternalResourceResolverSpec (eliminates dependency from messaging on higher layer)
- add ServerMessages.ExternalReader and translate between this message component and the PklEvaluatorSettings.ExternalReader API
- add ServerMessages.Proxy and translate between this message component and the PklEvaluatorSettings.Proxy API
- change type of CreateEvaluatorRequest.allowedModules/allowedResources from List<Pattern>? to List<String>?
  - removes a lot of code
  - should not need to create a Pattern object to send a message
- deprecate method evaluatorSettings.PklEvaluatorSettings.Proxy.create()
  - only seems useful internally, inlined

Co-authored-by: Dan Chao <dan.chao@apple.com>
2025-02-20 22:38:51 -08:00
Daniel Chao 31c80e792e Ensure findOrAddAuxiliarySlot is not called during compilation (#969)
Fixes an issue that is preventing the native executable from building
2025-02-20 08:09:22 -08:00
Artem Yarmoliuk 50cfb1c962 Bump clikt to 5.0.3 (#947)
This bumps Clikt from version 3 to version 5, which, among other things, improves
the help text formatting with colors.

Also: 
* Add `--version` flag to pkldoc, pkl-codegen-java, pkl-codegen-kotlin
* Add help text to pkldoc, pkl-codegen-java, pkl-codegen-kotlin
2025-02-19 15:18:02 -08:00
Daniel Chao 643c6f5a76 Execute typechecks eagerly when within a constraint (#964)
This changes the language to check all types eagerly when within a type constraint.

This addresses two regressions in the language:

1. Type constraints are too relaxed (listing/mapping parameters may not be checked)
2. Failing type constraints hide members that were forced during execution of the constraint
2025-02-19 12:51:52 -08:00
Daniel Chao 227f0637fc Rename package ast to syntax (#968) 2025-02-19 10:57:41 -08:00
Vladimir Matveev baa34a6dd1 Added support for an alternative current dir mode in pkldoc (#824)
Some systems have trouble with handling symlinks, which breaks the current directory links created by Pkldoc. In this PR, we add an alternative mode which creates a full copy of the latest published version contents in the current directory instead.

Co-authored-by: Dan Chao <dan.chao@apple.com>
2025-02-19 08:52:32 -08:00
Islon Scherer 2ffd201172 move handling of strings to parser (#962) 2025-02-19 17:19:48 +01:00
Daniel Chao ee23a8c3f4 Make CliktCommands classes (#963)
Missed these three classes.

This prevents the AOT compiler from statically initializing CLI argument
default values (like working dir).
2025-02-18 08:29:59 -08:00
Daniel Chao 28b128f86f Run spotless formatting (#958)
When we updated spotless's Java and Kotlin formatter, we changed the underlying
formatting rules.
However, due to spotless ratcheting, these formatting changes don't get applied unless a file
gets touched in a commit.

To avoid future PRs introducing lines of change that aren't related to the intention of the PR,
this is a one-time format of all files.
2025-02-17 07:36:43 -08:00
Islon Scherer d270829ed3 fix calculation of spans in parser (#957) 2025-02-15 12:11:55 +01:00
Michael Case 350b71a634 Fix incorrect glob example (#956)
Correct glob docs and use realistic file extensions.
2025-02-14 13:31:04 -08:00
Daniel Chao 28df90527b Add docs for various keywords (#955) 2025-02-14 13:30:22 -08:00
Daniel Chao eabfcdd333 Allow -DcommitId flag when building Pkl (#954)
This is to allow building Pkl in environments that don't have access
to git.
2025-02-14 09:36:47 -08:00
Daniel Chao 1a4f9ee72e Improve handling of errors when analysis fails (#948)
Modules that cannot be loaded for one reason or another now cause a Pkl Exception,
with the offending import highlighted as part of the stack trace.
2025-02-13 14:00:48 -08:00
Daniel Chao 65cf3237b7 Add parser benchmarks (#953)
The current benchmark is not too useful now that we have a linear parser.

This changes the benchmarks to parse the standard library, and also the language snippet tests.

Co-authored-by: Islon Scherer <islonscherer@gmail.com>
2025-02-13 11:22:31 -08:00
Daniel Chao d00d0ba79f Update dependencies (#938) 2025-02-13 10:19:24 -08:00
Josh B f56b1bb84f Test and document supercalls using the same method/property name (#943) 2025-02-12 21:10:37 -08:00
Islon Scherer b526902bf0 Replace ANTLR with hand-rolled parser (#917)
Co-authored-by: Kushal Pisavadia <kushi.p@gmail.com>
Co-authored-by: Daniel Chao <daniel.h.chao@gmail.com>
2025-02-12 18:11:00 +01:00
Daniel Chao 7c3f8ad261 Improve documentation about Set/Map ordering (#944)
The language reference and stdlib are both slightly incorrect;
maps and sets are ordered when iterated on, but unordered in terms of
equality.
2025-02-12 06:43:51 -08:00
Daniel Chao 7ed710c226 Make commands classes instead of objects (#946)
Making these classes caused native-image to statically initialize
them at build time, which included CLI argument default values
(like working dir).

This turns them back into classes.

Co-authored-by: Islon Scherer <islonscherer@gmail.com>
2025-02-11 06:38:19 -08:00
Josh B ad99e4a7f7 Correctly set allowed modules/resoures when external reader scheme contain regex control characters (#941) 2025-02-07 14:03:40 -08:00
Daniel Chao e85e888f92 [docs] Add documetation about release/evolution/roadmap (#937) 2025-02-05 11:24:41 -08:00
Daniel Chao 3b6fbdff15 Remove usages of VmFunction#apply(Object) (#936)
These call sites should use `ApplyVmFunction1Node` instead.
2025-02-05 09:18:42 -08:00
Daniel Chao 9784cd7265 Turn CLI commands into objects, self register subcommands (#935)
Usages of `RootCommand` no longer need to initialize a new instance, nor register subcommands.
2025-02-05 09:18:23 -08:00
Daniel Chao aadcccd0fc Run a simple eval script (#928)
Execute `1 + 1` instead of eval'ing `circleci.pkl` (might cause
spurious failures due to requirement on network connection).
2025-02-04 07:21:57 -08:00
Daniel Chao 9075ca0729 Fix native gvm ci (#930)
* Update GraalVM checksum
* Fix: download JDK on macOS

Signed-off-by: Sam Gammon <sam@elide.dev>
Co-authored-by: Sam Gammon <sam@elide.dev>
2025-02-04 07:21:42 -08:00
Sam Gammon 5e12dfb200 fix: upgrade ci jobs to jdk 21 (#926)
Signed-off-by: Sam Gammon <sam@elide.dev>
2025-02-03 17:17:07 -08:00
Sam Gammon 408242a44c Upgrade GraalVM and Truffle, set up multi-JDK testing, bump development Java to 21 (#876)
This updates the GraalVM and Truffle libraries to 2024.1.2.

This also updates the build logic to compile Java sources using Java 21, due to some compile-only dependencies within GraalVM/Truffle using class file version 65. However, the produced artifact is still compatible with Java 17.

This also changes the Gradle build logic to use toolchains, and to test the Java libraries with JDK 17 and 21.

One consequence of this change is that Truffle is no longer shaded within the fat jars.

feat: support for jvm21+ toolchain
feat: support for gradle toolchains
feat: pass -PnativeArch=native to build with -march=native
test: multi-jdk testing support
test: support for jvm-test-suite plugin
test: add tasks to run jpkl eval on multiple jdks
test: make jdk exec tests respect multi-jdk flags and ranges
fix: remove mrjar classes at >jvm17 from fatjars
fix: use jdk21 to run the tests (needed for Unsafe.ensureInitialized)
fix: truffle svm dependency is required after graalvm 24.0.0
fix: warnings for gvm flag usage, renamed truffle svm macro
fix: build with --add-modules=jdk.unsupported where needed
fix: don't use gu tool for modern graalvm versions
fix: catch Throwable instead of deprecated-for-removal ThreadDeath
chore: buildinfo changes for JVM targets, toolchains
chore: enforce testing at exactly jdk21
chore: enforce build tooling at jdk21+
chore: bump graalvm/truffle libs → 24.1.2
chore: toolchains for buildSrc

Signed-off-by: Sam Gammon <sam@elide.dev>
2025-02-03 14:57:40 -08:00
Stanley Cheung 8cfd2357c6 Fix typo in tutorial part 2 (#921) 2025-01-31 07:53:22 -08:00
Sam Gammon 3fa935b390 fix: downstream native-image builds (#914)
SVM (SubstrateVM) compile configuration classes
must be included within the `cli` jar to prevent
downstream `native-image` builds from failing.

Fat JARs cannot be used with `native-image`, so
these classes can still safely be excluded here.

Fixes and closes apple/pkl#907

Signed-off-by: Sam Gammon <sam@elide.dev>
2025-01-29 20:31:05 -08:00
Kushal Pisavadia aa8a0f18e8 Simplify inputs for javadocJar (#916)
Also, rename `dummy` to `placeholder`
2025-01-29 09:46:39 -08:00
Daniel Chao 3815a0206b Optimization: execute const object bodies and typechecks only once (#915)
If the object member is const, it only needs to be executed once, and all children in the prototype chain can use its cached value.

There is a possible other optimization here, not included in this PR: we can avoid adding these values to the child object's cachedMembers.
2025-01-29 07:19:55 -08:00
odenix 90df0662af Overhaul implementation of for-generators (#844)
Motivation:
* fix known bugs and limitations of for-generators
* improve code health by removing complex workarounds

Changes:
* simplify AstBuilder code related to for-generators
  * track for-generators via `SymbolTable.enterForGenerator()`
  * add `RestoreForBindingsNode` during initial AST construction
    instead of calling `MemberNode.replaceBody()` later on
  * simplify some unnecessarily complex code
* remove workarounds and band-aids such as:
  * `isInIterable`
  * `executeAndSetEagerly`
  * adding dummy slots in `AmendFunctionNode`
* overhaul implementation of for-generators
  * store keys and values of for-generator iterations in regular instead of auxiliary frame slots
    * set them via `TypeNode.executeAndSet()`
    * `ResolveVariableNode` no longer needs to search auxiliary slots
    * `Read(Enclosing)AuxiliarySlot` is no longer needed
  * at the start of each for-generator iteration, create a new `VirtualFrame`
    that is a copy of the current frame (arguments + slots)
    and stores the iteration key and value in additional slots.
  * execute for-generator iteration with the newly created frame
    * `childNode.execute(newFrame)`
    * Pkl objects created during the iteration will materialize this frame
  * store newly created frames in `owner.extraStorage`
    if their for-generator slots may be accessed when a generated member is executed
    * resolving variable names to for-generator variables at parse time would make this analysis more precise
  * when a generated member is executed,
	  * retrieve the corresponding frame stored in `owner.extraStorage`
	  * copy the retrieved frame's for-generator slots into slots of the current frame

Result:
* for-generators are implemented in a correct, reasonably simple, and reasonably efficient way
  * complexity is fully contained within package `generator` and `AstBuilder`
* for-generator keys and values can be accessed from all nested scopes:
  * key and value expressions of generated members
  * condition expressions of nested when-generators
  * iterable expressions of nested for-generators
* for-generator keys and values can be accessed from within objects created by the expressions listed above
* sibling for-generators can use the same key/value variable names
* parent/child for-generators can use the same key/value variable names
* fixes https://github.com/apple/pkl/issues/741
2025-01-28 14:06:42 -08:00
Kushal Pisavadia 11169d6691 Upgrade gradle to 8.12.1 (from 8.12) and fix some build warnings (#910)
Build warning fixes:

* Return `tasks.register` as `tasks.create` is deprecated
* Use property accessor `.files` instead of function `.files()`
2025-01-27 15:01:19 -08:00
Daniel Chao 5dc672731d Bump minimum Gradle version to 8.2 (#901)
The Kotlin 2.0 version upgrade made us incompatible with Gradle 8.1.

Given that it is now over 1.5 years old, this drops support for it, and
raises the minimum version to 8.2.
2025-01-27 10:04:31 -08:00
odenix 258eda8630 Update Kotlin to 2.0 (#900)
- update Kotlin from 1.7.10 to 2.0.21
  - Kotlin 1.6 dependencies in Gradle lock files are expected because kotlinc,
    which is also used by some tests, internally uses some 1.6 dependencies
    for backwards compatibility reasons.
- update kotlinx-html and kotlinx-serialization
- adapt Kotlin code where necessary
- use Kotlin stdlib Path APIs where possible
- fix IntelliJ Kotlin inspection warnings
- reformat code with `./gradlew spotlessApply`
  - ktfmt adds lots of trailing commas
- Add workaround to fix IntelliJ "unresolved reference" errors
2025-01-23 14:41:59 -08:00
Daniel Chao cdd6d52642 Only run Gradle compatibility tests against minimum and maximum release (#898)
Currently, we run against every release version, which is taking 20
minutes to run in CI, and this will grow as Gradle creates more
releases.

This limits the amount of Gradle versions being tested against;
theoretically, only testing against the minimum version and the maximum
version should ensure that we are compatible with every version in the
range.
2025-01-22 14:08:45 -08:00
Daniel Chao 29049ac437 Import release notes for 0.27.2 (#897) 2025-01-22 09:36:48 -08:00
Daniel Chao 2a9b10097d Revert "Upgrade Kotlin to 1.7.21 (#887)" (#896)
This reverts commit 273d1219a6.
2025-01-22 08:33:06 -08:00
Daniel Chao 257bd6f699 Allow jar:nested: URIs in default security manager (#895)
Nested jars built by spring boot can possibly represent classpath
resource URIs as "jar:nested:".

This changes Pkl to by default trust them with the same level as
modulepath URIs.
2025-01-22 06:42:47 -08:00
Vic 75bd21420b Document where to find all keywords (#892) 2025-01-21 13:03:43 -08:00
Kushal Pisavadia 273d1219a6 Upgrade Kotlin to 1.7.21 (#887)
What's new: https://kotlinlang.org/docs/whatsnew1720.html

Releases
--------

- https://github.com/JetBrains/kotlin/releases/tag/v1.7.20
- https://github.com/JetBrains/kotlin/releases/tag/v1.7.21
2025-01-17 14:12:31 +00:00
Daniel Chao ec7d7267dc Update dependencies (#883)
Most of these dependencies are test dependencies.
2025-01-15 05:39:14 -08:00
Daniel Chao 3096da1920 Update gradle to 8.12 (#884) 2025-01-15 05:38:51 -08:00
Daniel Chao 100dd0560e Support jpkl executable for Windows (#872)
This updates the script used to start the executable to support
Windows as well.

For Windows support, the executable needs to be named `jpkl.bat`.
2025-01-14 05:16:59 -08:00
Josh B 3296dd8a89 Fix NPE when handling ExternalReader specs with null arguments (#882) 2025-01-14 04:51:09 -08:00
Josh B 160e4a5636 YamlRenderer: allow all primitive scalar types as map keys (#879) 2025-01-13 16:22:52 -08:00
Josh B 267de3c789 Fix page size for Linux AArch64 native executables (#875)
Graal Native Image is assuming 4k page size here, which is a naughty assumption to make in the modern Linux-on-ARM landscape.
Two very common hardware configurations require 16k minumum page size: the Raspberry Pi 5 and Asahi Linux (running on Apple Silicon hardware).

This change forces 64k pages for Linux/AArch64 native executables to guarantee compatibility with these platforms.
DEVELOPMENT.adoc is also updated to cover the additional dependencies required for building native executables on Linux.
2025-01-07 15:55:27 +00:00
Daniel Chao f6c74e90a8 Update license year (#871)
* Update license header file spec to use placeholder year
* Update spotless to use ratchet formatting (only format files that have changed)
2025-01-07 10:15:07 +00:00
Stefan M. 467e64f98e Make Test Report locale independent (#868)
Format numbers with `.` decimals
2025-01-02 09:29:48 -08:00
Josh Soref d9c65d484a Fix spelling errors (#846)
Also: change checksums due to filename and content changes, and fix language snippet test output to produce correct error messages
2024-12-23 12:49:56 -08:00
Daniel Chao a014e8d1d1 Add comment about const check (#859) 2024-12-23 11:38:33 -08:00
Daniel Chao 6fd82a5bb8 Clarify terminology on renderer converters (#860) 2024-12-20 10:36:51 -08:00
Daniel Chao 29fb99ffea Update JDK version in dev docs (#848) 2024-12-20 10:36:35 -08:00
Daniel Chao efe1608bd6 Fix compile error (#857)
PRs https://github.com/apple/pkl/pull/789 and https://github.com/apple/pkl/pull/837 being merged caused a compile error; this fixes them.
2024-12-19 12:15:30 -08:00
Josh B 6cab47067b Fix CreateEvaluatorRequest decoding (#853)
Handle case when request specifies external reader with null arguments
2024-12-19 09:59:22 -08:00
odenix 17f431370a Fix exception handling of PklRootNode's (#837)
Motivation:
- Perform same exception handling for every implementation of PklRootNode.execute().
- Avoid code duplication.

Changes:
- Change PklRootNode.execute() to be a final method that performs exception handling
  and calls abstract method executeImpl(), which is implemented by subclasses.
- Remove executeBody() methods, which served a similar purpose but were more limited.
- Remove duplicate exception handling code.

Result:
- More reliable exception handling.
  This should fix known problems such as misclassifying stack overflows
  as internal errors and displaying errors without a stack trace.
- Less code duplication.
2024-12-19 09:58:44 -08:00
Daniel Chao 9982511513 Download JDK for windows build (#851)
Don't use the system Java on Windows builds, instead download them from Adoptium.

Also:

* Fail job if curl returns a 4xx status code
* Add java version to `GradleJob`
2024-12-19 09:23:04 -08:00
Kushal Pisavadia 6bd8e288ef Convert org.pkl.executor.Version.Identifier POJO to record class (#836) 2024-12-16 14:36:41 -08:00
odenix 01bf844a96 codegen-java: Support not annotating constructor parameters (#792)
Motivation:
Spring Boot configuration classes neither require nor benefit from annotating constructor parameters with their name.
The same is true for pkl-config-java configuration classes compiled with `-parameter`.

Changes:
- Change CLI parameter `--params-annotation` to accept a `none` value.
  This is recommended in https://clig.dev/#arguments-and-flags and is how the `-F` parameter of the `ssh` command works.
- Change `paramsAnnotation` property in Gradle plugin, CliJavaCodeGeneratorOptions, and JavaCodegenOptions as follows:
  - Change meaning of `null` from "generate org.pkl.java.config.mapper.Named annotations" to "do not generate annotations".
    This is a breaking change (only) affecting users who explicitly set the property to `null` instead of omitting it.
  - Change property default from `null` to:
    `null` if `generateSpringBootConfig` is `true` and `org.pkl.java.config.mapper.Named` otherwise
- add tests
- update docs of this and other codegen options

Result:
Generated code does not contain unnecessary annotations.
2024-12-13 14:29:18 -08:00
Islon Scherer 70aaa6322e Add release notes for 0.27.1 (#840)
Co-authored-by: Philip K.F. Hölzenspies <holzensp@gmail.com>
2024-12-06 16:24:49 +01:00
odenix 1bc473ba54 Improve lazy type checking of listings and mappings (#789)
Motivation:
- simplify implementation of lazy type checking
- fix correctness issues of lazy type checking (#785)

Changes:
- implement listing/mapping type cast via amendment (`parent`) instead of delegation (`delegate`)
- handle type checking of *computed* elements/entries in the same way as type checking of computed properties
  - ElementOrEntryNode is the equivalent of TypeCheckedPropertyNode
- remove fields VmListingOrMapping.delegate/typeNodeFrame/cachedMembers/checkedMembers
- fix #785 by executing all type casts between a member's owner and receiver
- fix #823 by storing owner and receiver directly
  instead of storing the mutable frame containing them (typeNodeFrame)
- remove overrides of VmObject methods that are no longer required
  - good for Truffle partial evaluation and JVM inlining
- revert a85a173faa except for added tests
- move `VmUtils.setOwner` and `VmUtils.setReceiver` and make them private
  - these methods aren't generally safe to use

Result:
- simpler code with greater optimization potential
  - VmListingOrMapping can now have both a type node and new members
- fewer changes to surrounding code
- smaller memory footprint
- better performance in some cases
- fixes https://github.com/apple/pkl/issues/785
- fixes https://github.com/apple/pkl/issues/823

Potential future optimizations:
- avoid lazy type checking overhead for untyped listings/mappings
- improve efficiency of forcing a typed listing/mapping
  - currently, lazy type checking will traverse the parent chain once per member,
    reducing the performance benefit of shallow-forcing
	  a listing/mapping over evaluating each member individually
- avoid creating an intermediate untyped listing/mapping in the following cases:
  - `new Listing<X> {...}`
  - amendment of `property: Listing<X>`
2024-12-06 13:41:33 +01:00
translatenix ad06a96a8a Update Gradle to 8.11 (#800)
Changes:
- Update wrapper by running the following command:
  ./gradlew wrapper --gradle-version 8.11 --gradle-distribution-sha256-sum
  57dafb5c2622c6cc08b993c85b7c06956a2f53536432a30ead46166dbca0f1e9
- Verify wrapper JAR integrity according to:
  https://docs.gradle.org/current/userguide/gradle_wrapper.html#
  manually_verifying_the_gradle_wrapper_jar
- Replace usages of deprecated method `Project.exec` with `ExecOperations.exec`
- Convert extension function `Task.configureInstallGraalVm` to task class `InstallGraalVm`
  - a task class is the cleanest way to get hold of `ExecOperations`
- Move extension property `BuildInfo.GraalVm.downloadFile` into class `GraalVm`
- Don't apply plugin `pklGraalVm` in project `bench` (unnecessary, now causes error)
2024-11-22 11:16:04 -08:00
Islon Scherer 1abd174d77 Fix possible stack overflow in Listing/Mapping type checking (#826) 2024-11-22 09:39:52 +01:00
translatenix 45302c8a00 Switch from com.squareup.javapoet to com.palantir.javapoet (#790)
Motivation:
com.squareup.javapoet is EOL.
com.palantir.javapoet is an actively maintained fork that supports generating record classes.
2024-11-20 16:16:51 -08:00
translatenix e6c1e1411b Update SnakeYAML Engine to 2.8 (#813)
Changes:
- update version selector and lock files
- adapt code to breaking changes
2024-11-20 15:21:12 -08:00
Artem Yarmoliuk cc579f8fd6 Add math.atan2 (#819) 2024-11-18 14:11:19 -08:00
Daniel Chao b93cb9b322 Exclude non file-based modules from synthesized *GatherImports task (#821)
This fixes an issue where certain modules tasks fail due to the plugin
attempting to analyze their imports, but the arguments may not actually be
Pkl modules.

For example, the pkldoc task accepts entire packages in its "sourceMoules" property.

This changes the gather imports logic to only analyze file-based modules.
This is also a performance improvement; non file-based modules are unlikely to import
files due to insufficient trust levels.

Also: fix a bug when generating pkldoc on Windows
2024-11-18 11:14:17 -08:00
translatenix 7c1604b264 Delete obsolete file pkl-certs/gradle.lockfile (#820) 2024-11-17 12:38:13 -08:00
translatenix 0c6808566f codegen-kotlin: Deprecate method toKotlinCodegenOptions without replacement (#810)
Motivation:
`CliKotlinCodeGeneratorOptions.toKotlinCodegenOptions` is an internal method that isn't useful to clients.
2024-11-14 12:21:07 -08:00
translatenix 51df2f3aa4 Convert org.pkl.core.Release into a record (#812)
Also, add doc comments to some methods.
2024-11-14 12:20:37 -08:00
Kushal Pisavadia 09bc09d058 Join concatenated String constants in test into single String (#814) 2024-11-14 08:09:25 -08:00
Kushal Pisavadia 16af6b7bcc Use text block to improve readability of test (#815) 2024-11-14 07:14:04 -08:00
Kushal Pisavadia 2a7eec592d Delete unused PclLexer.tokens file (#818) 2024-11-14 14:35:58 +01:00
Kushal Pisavadia dda457aa8e Delete unused Resource.pcl-expected.pcf input file (#817) 2024-11-14 14:34:50 +01:00
Kushal Pisavadia 696a325511 Rename snippet tests to match content: minPklVersion (#816) 2024-11-14 14:33:46 +01:00
Kushal Pisavadia 9a27616956 Convert org.pkl.core POJOs to record classes (#808) 2024-11-13 15:54:41 -08:00
translatenix 406fa4cf40 Rename JavaCodegenOptions to JavaCodeGeneratorOptions (#801)
The new name is consistent with existing names JavaCodeGenerator and CliJavaCodeGeneratorOptions.
Backward compatibility is ensured by turning JavaCodegenOptions into a (deprecated) type alias.

Also: deprecate `CliJavaCodeGeneratorOptions.toJavaCodegenOptions()`
2024-11-13 15:43:33 -08:00
translatenix df38011c9e codegen-java/kotlin: Fix generation of hashCode methods (#802)
codegen-java:
- use `pattern.pattern()` instead of `pattern` in hashCode method
  (consistent with equals method)

codegen-kotlin:
- use `regex.pattern` instead of `regex` in hashCode method
  (consistent with equals method)
- if a data class has a Regex property, generate not only
  an equals method but also a hashCode method
2024-11-13 15:42:45 -08:00
translatenix b8d90eddec codegen-kotlin: Generate toString() methods consistent with data classes (#793)
Motivation:
codegen-kotlin generates a mix of data classes and regular classes.
For regular classes, toString() methods are also generated.
However, the output of generated toString() methods
differs from the output of default toString() methods of data classes.

Changes:
Generate toString() methods that produce the same output
as default toString() methods of data classes.

Also: rename KotlinCodegenOptions to KotlinCodeGeneratorOptions

The new name is consistent with existing names KotlinCodeGenerator and CliKotlinCodeGeneratorOptions.
Backward compatibility is ensured by turning KotlinCodegenOptions into a (deprecated) type alias.
2024-11-13 15:22:11 -08:00
translatenix 9faff5e551 Fix length of listings with computed index (#797)
Motivation:
The following expression evaluates to 2 instead of 1:
new Listing { "value" } { [0 + 0] = "override" }.length

Changes:
- fix length computation in EntriesLiteralNode
- improve `api/listing` tests
- make snippet test failures diffable in IntelliJ

Result:
- fixes https://github.com/apple/pkl/issues/780
- improved dev experience in IntelliJ
2024-11-13 18:29:37 +00:00
Kushal Pisavadia 3f91824dc2 Convert org.pkl.core.runtime POJOs to record classes (#807) 2024-11-13 13:09:21 +00:00
Kushal Pisavadia dddbb27143 Convert org.pkl.core.project POJOs to record classes (#749) 2024-11-12 17:08:01 -08:00
Kushal Pisavadia 3246a0e449 Convert org.pkl.core.resource POJOs to record classes (#748) 2024-11-12 17:07:52 -08:00
translatenix a22a8a8127 Fix Javadoc warning emitted by Gradle build (#798) 2024-11-11 11:37:14 -08:00
Kushal Pisavadia ff60f61cbb Convert org.pkl.core.util POJOs to record classes (#750) 2024-11-11 10:00:33 -08:00
Josh B 0d199892b8 Fix a possible deadlock during external reader process close (#786)
* Fix a possible deadlock during external reader process close

* Apply spotless

---------

Co-authored-by: Philip K.F. Hölzenspies <holzensp@gmail.com>
2024-11-07 11:24:16 +00:00
Nick Muerdter a533e53838 Fix broken link to documentation site in release notes (#784) 2024-11-05 12:56:40 -08:00
Dan Chao 44fd680e43 Start next dev iteration 2024-11-05 10:34:31 -08:00
Dan Chao 33bffbe158 Prepare 0.27.0 release 2024-11-05 10:34:31 -08:00
639 changed files with 19716 additions and 9078 deletions
+6 -7
View File
@@ -105,16 +105,13 @@ local buildNativeJobs: Mapping<String, BuildNativeJob> = new {
} }
local gradleCheckJobs: Mapping<String, GradleCheckJob> = new { local gradleCheckJobs: Mapping<String, GradleCheckJob> = new {
["gradle-check-jdk17"] { ["gradle-check"] {
javaVersion = "17.0"
isRelease = false
}
["gradle-check-jdk21"] {
javaVersion = "21.0" javaVersion = "21.0"
isRelease = false isRelease = false
os = "linux"
} }
["gradle-check-jdk17-windows"] { ["gradle-check-windows"] {
javaVersion = "17.0" javaVersion = "21.0"
isRelease = false isRelease = false
os = "windows" os = "windows"
} }
@@ -151,6 +148,8 @@ jobs {
command = #""" command = #"""
# exclude build_artifacts.txt from publish # exclude build_artifacts.txt from publish
rm -f pkl-cli/build/executable/*.build_artifacts.txt rm -f pkl-cli/build/executable/*.build_artifacts.txt
find pkl-cli/build/executable/* -type d | xargs rm -rf
rm -f pkl-cli/build/executable/resources
gh release create "${CIRCLE_TAG}" \ gh release create "${CIRCLE_TAG}" \
--title "${CIRCLE_TAG}" \ --title "${CIRCLE_TAG}" \
--target "${CIRCLE_SHA1}" \ --target "${CIRCLE_SHA1}" \
+147 -83
View File
@@ -9,10 +9,21 @@ jobs:
- run: - run:
command: /usr/sbin/softwareupdate --install-rosetta --agree-to-license command: /usr/sbin/softwareupdate --install-rosetta --agree-to-license
name: Installing Rosetta 2 name: Installing Rosetta 2
- run:
command: |-
# install jdk
curl -Lf \
https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_x64_mac_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir $HOME/jdk \
&& cd $HOME/jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DreleaseBuild=true pkl-cli:macExecutableAmd64 pkl-core:testMacExecutableAmd64 pkl-server:testMacExecutableAmd64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true -DreleaseBuild=true pkl-cli:macExecutableAmd64 pkl-core:testMacExecutableAmd64 pkl-server:testMacExecutableAmd64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -22,6 +33,7 @@ jobs:
path: ~/test-results path: ~/test-results
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
JAVA_HOME: /Users/distiller/jdk/Contents/Home
resource_class: macos.m1.large.gen1 resource_class: macos.m1.large.gen1
macos: macos:
xcode: 15.3.0 xcode: 15.3.0
@@ -39,8 +51,8 @@ jobs:
&& rm -rf /var/cache/dnf && rm -rf /var/cache/dnf
# install jdk # install jdk
curl -L \ curl -Lf \
https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz -o /tmp/jdk.tar.gz https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_x64_linux_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \ mkdir /jdk \
&& cd /jdk \ && cd /jdk \
@@ -52,7 +64,7 @@ jobs:
# install zlib # install zlib
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
curl -L https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz curl -Lf https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz
mkdir -p /tmp/dep_zlib-1.2.13 \ mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \ && cd /tmp/dep_zlib-1.2.13 \
@@ -65,7 +77,7 @@ jobs:
# install musl # install musl
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
curl -L https://musl.libc.org/releases/musl-1.2.2.tar.gz -o /tmp/musl.tar.gz curl -Lf https://musl.libc.org/releases/musl-1.2.2.tar.gz -o /tmp/musl.tar.gz
mkdir -p /tmp/dep_musl-1.2.2 \ mkdir -p /tmp/dep_musl-1.2.2 \
&& cd /tmp/dep_musl-1.2.2 \ && cd /tmp/dep_musl-1.2.2 \
@@ -88,7 +100,7 @@ jobs:
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DreleaseBuild=true pkl-cli:linuxExecutableAmd64 pkl-core:testLinuxExecutableAmd64 pkl-server:testLinuxExecutableAmd64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true -DreleaseBuild=true pkl-cli:linuxExecutableAmd64 pkl-core:testLinuxExecutableAmd64 pkl-server:testLinuxExecutableAmd64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -105,10 +117,21 @@ jobs:
pkl-cli-macOS-aarch64-release: pkl-cli-macOS-aarch64-release:
steps: steps:
- checkout - checkout
- run:
command: |-
# install jdk
curl -Lf \
https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_aarch64_mac_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir $HOME/jdk \
&& cd $HOME/jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DreleaseBuild=true pkl-cli:macExecutableAarch64 pkl-core:testMacExecutableAarch64 pkl-server:testMacExecutableAarch64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true -DreleaseBuild=true pkl-cli:macExecutableAarch64 pkl-core:testMacExecutableAarch64 pkl-server:testMacExecutableAarch64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -118,6 +141,7 @@ jobs:
path: ~/test-results path: ~/test-results
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
JAVA_HOME: /Users/distiller/jdk/Contents/Home
resource_class: macos.m1.large.gen1 resource_class: macos.m1.large.gen1
macos: macos:
xcode: 15.3.0 xcode: 15.3.0
@@ -135,8 +159,8 @@ jobs:
&& rm -rf /var/cache/dnf && rm -rf /var/cache/dnf
# install jdk # install jdk
curl -L \ curl -Lf \
https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.9_9.tar.gz -o /tmp/jdk.tar.gz https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \ mkdir /jdk \
&& cd /jdk \ && cd /jdk \
@@ -148,7 +172,7 @@ jobs:
# install zlib # install zlib
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
curl -L https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz curl -Lf https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz
mkdir -p /tmp/dep_zlib-1.2.13 \ mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \ && cd /tmp/dep_zlib-1.2.13 \
@@ -168,7 +192,7 @@ jobs:
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DreleaseBuild=true pkl-cli:linuxExecutableAarch64 pkl-core:testLinuxExecutableAarch64 pkl-server:testLinuxExecutableAarch64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true -DreleaseBuild=true pkl-cli:linuxExecutableAarch64 pkl-core:testLinuxExecutableAarch64 pkl-server:testLinuxExecutableAarch64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -196,8 +220,8 @@ jobs:
&& rm -rf /var/cache/dnf && rm -rf /var/cache/dnf
# install jdk # install jdk
curl -L \ curl -Lf \
https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz -o /tmp/jdk.tar.gz https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_x64_linux_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \ mkdir /jdk \
&& cd /jdk \ && cd /jdk \
@@ -209,7 +233,7 @@ jobs:
# install zlib # install zlib
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
curl -L https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz curl -Lf https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz
mkdir -p /tmp/dep_zlib-1.2.13 \ mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \ && cd /tmp/dep_zlib-1.2.13 \
@@ -222,7 +246,7 @@ jobs:
# install musl # install musl
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
curl -L https://musl.libc.org/releases/musl-1.2.2.tar.gz -o /tmp/musl.tar.gz curl -Lf https://musl.libc.org/releases/musl-1.2.2.tar.gz -o /tmp/musl.tar.gz
mkdir -p /tmp/dep_musl-1.2.2 \ mkdir -p /tmp/dep_musl-1.2.2 \
&& cd /tmp/dep_musl-1.2.2 \ && cd /tmp/dep_musl-1.2.2 \
@@ -245,7 +269,7 @@ jobs:
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DreleaseBuild=true pkl-cli:alpineExecutableAmd64 pkl-core:testAlpineExecutableAmd64 pkl-server:testAlpineExecutableAmd64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true -DreleaseBuild=true pkl-cli:alpineExecutableAmd64 pkl-core:testAlpineExecutableAmd64 pkl-server:testAlpineExecutableAmd64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -262,10 +286,22 @@ jobs:
pkl-cli-windows-amd64-release: pkl-cli-windows-amd64-release:
steps: steps:
- checkout - checkout
- run:
command: |-
# install jdk
curl -Lf \
https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_x64_windows_hotspot_21.0.5_11.zip -o /tmp/jdk.zip
unzip /tmp/jdk.zip -d /tmp/jdk \
&& cd /tmp/jdk/jdk-* \
&& mkdir /jdk \
&& cp -r . /jdk
name: Set up environment
shell: bash.exe
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DreleaseBuild=true pkl-cli:windowsExecutableAmd64 pkl-core:testWindowsExecutableAmd64 pkl-server:testWindowsExecutableAmd64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true -DreleaseBuild=true pkl-cli:windowsExecutableAmd64 pkl-core:testWindowsExecutableAmd64 pkl-server:testWindowsExecutableAmd64
name: gradle buildNative name: gradle buildNative
shell: bash.exe shell: bash.exe
- persist_to_workspace: - persist_to_workspace:
@@ -276,6 +312,7 @@ jobs:
path: ~/test-results path: ~/test-results
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
JAVA_HOME: /jdk
resource_class: windows.large resource_class: windows.large
machine: machine:
image: windows-server-2022-gui:current image: windows-server-2022-gui:current
@@ -285,10 +322,21 @@ jobs:
- run: - run:
command: /usr/sbin/softwareupdate --install-rosetta --agree-to-license command: /usr/sbin/softwareupdate --install-rosetta --agree-to-license
name: Installing Rosetta 2 name: Installing Rosetta 2
- run:
command: |-
# install jdk
curl -Lf \
https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_x64_mac_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir $HOME/jdk \
&& cd $HOME/jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results pkl-cli:macExecutableAmd64 pkl-core:testMacExecutableAmd64 pkl-server:testMacExecutableAmd64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true pkl-cli:macExecutableAmd64 pkl-core:testMacExecutableAmd64 pkl-server:testMacExecutableAmd64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -298,6 +346,7 @@ jobs:
path: ~/test-results path: ~/test-results
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
JAVA_HOME: /Users/distiller/jdk/Contents/Home
resource_class: macos.m1.large.gen1 resource_class: macos.m1.large.gen1
macos: macos:
xcode: 15.3.0 xcode: 15.3.0
@@ -315,8 +364,8 @@ jobs:
&& rm -rf /var/cache/dnf && rm -rf /var/cache/dnf
# install jdk # install jdk
curl -L \ curl -Lf \
https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz -o /tmp/jdk.tar.gz https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_x64_linux_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \ mkdir /jdk \
&& cd /jdk \ && cd /jdk \
@@ -328,7 +377,7 @@ jobs:
# install zlib # install zlib
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
curl -L https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz curl -Lf https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz
mkdir -p /tmp/dep_zlib-1.2.13 \ mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \ && cd /tmp/dep_zlib-1.2.13 \
@@ -341,7 +390,7 @@ jobs:
# install musl # install musl
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
curl -L https://musl.libc.org/releases/musl-1.2.2.tar.gz -o /tmp/musl.tar.gz curl -Lf https://musl.libc.org/releases/musl-1.2.2.tar.gz -o /tmp/musl.tar.gz
mkdir -p /tmp/dep_musl-1.2.2 \ mkdir -p /tmp/dep_musl-1.2.2 \
&& cd /tmp/dep_musl-1.2.2 \ && cd /tmp/dep_musl-1.2.2 \
@@ -364,7 +413,7 @@ jobs:
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results pkl-cli:linuxExecutableAmd64 pkl-core:testLinuxExecutableAmd64 pkl-server:testLinuxExecutableAmd64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true pkl-cli:linuxExecutableAmd64 pkl-core:testLinuxExecutableAmd64 pkl-server:testLinuxExecutableAmd64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -381,10 +430,21 @@ jobs:
pkl-cli-macOS-aarch64-snapshot: pkl-cli-macOS-aarch64-snapshot:
steps: steps:
- checkout - checkout
- run:
command: |-
# install jdk
curl -Lf \
https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_aarch64_mac_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir $HOME/jdk \
&& cd $HOME/jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results pkl-cli:macExecutableAarch64 pkl-core:testMacExecutableAarch64 pkl-server:testMacExecutableAarch64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true pkl-cli:macExecutableAarch64 pkl-core:testMacExecutableAarch64 pkl-server:testMacExecutableAarch64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -394,6 +454,7 @@ jobs:
path: ~/test-results path: ~/test-results
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
JAVA_HOME: /Users/distiller/jdk/Contents/Home
resource_class: macos.m1.large.gen1 resource_class: macos.m1.large.gen1
macos: macos:
xcode: 15.3.0 xcode: 15.3.0
@@ -411,8 +472,8 @@ jobs:
&& rm -rf /var/cache/dnf && rm -rf /var/cache/dnf
# install jdk # install jdk
curl -L \ curl -Lf \
https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.9_9.tar.gz -o /tmp/jdk.tar.gz https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \ mkdir /jdk \
&& cd /jdk \ && cd /jdk \
@@ -424,7 +485,7 @@ jobs:
# install zlib # install zlib
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
curl -L https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz curl -Lf https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz
mkdir -p /tmp/dep_zlib-1.2.13 \ mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \ && cd /tmp/dep_zlib-1.2.13 \
@@ -444,7 +505,7 @@ jobs:
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results pkl-cli:linuxExecutableAarch64 pkl-core:testLinuxExecutableAarch64 pkl-server:testLinuxExecutableAarch64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true pkl-cli:linuxExecutableAarch64 pkl-core:testLinuxExecutableAarch64 pkl-server:testLinuxExecutableAarch64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -472,8 +533,8 @@ jobs:
&& rm -rf /var/cache/dnf && rm -rf /var/cache/dnf
# install jdk # install jdk
curl -L \ curl -Lf \
https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz -o /tmp/jdk.tar.gz https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_x64_linux_hotspot_21.0.5_11.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \ mkdir /jdk \
&& cd /jdk \ && cd /jdk \
@@ -485,7 +546,7 @@ jobs:
# install zlib # install zlib
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
curl -L https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz curl -Lf https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz -o /tmp/zlib.tar.gz
mkdir -p /tmp/dep_zlib-1.2.13 \ mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \ && cd /tmp/dep_zlib-1.2.13 \
@@ -498,7 +559,7 @@ jobs:
# install musl # install musl
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
curl -L https://musl.libc.org/releases/musl-1.2.2.tar.gz -o /tmp/musl.tar.gz curl -Lf https://musl.libc.org/releases/musl-1.2.2.tar.gz -o /tmp/musl.tar.gz
mkdir -p /tmp/dep_musl-1.2.2 \ mkdir -p /tmp/dep_musl-1.2.2 \
&& cd /tmp/dep_musl-1.2.2 \ && cd /tmp/dep_musl-1.2.2 \
@@ -521,7 +582,7 @@ jobs:
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results pkl-cli:alpineExecutableAmd64 pkl-core:testAlpineExecutableAmd64 pkl-server:testAlpineExecutableAmd64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true pkl-cli:alpineExecutableAmd64 pkl-core:testAlpineExecutableAmd64 pkl-server:testAlpineExecutableAmd64
name: gradle buildNative name: gradle buildNative
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
@@ -538,10 +599,22 @@ jobs:
pkl-cli-windows-amd64-snapshot: pkl-cli-windows-amd64-snapshot:
steps: steps:
- checkout - checkout
- run:
command: |-
# install jdk
curl -Lf \
https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_x64_windows_hotspot_21.0.5_11.zip -o /tmp/jdk.zip
unzip /tmp/jdk.zip -d /tmp/jdk \
&& cd /tmp/jdk/jdk-* \
&& mkdir /jdk \
&& cp -r . /jdk
name: Set up environment
shell: bash.exe
- run: - run:
command: |- command: |-
export PATH=~/staticdeps/bin:$PATH export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results pkl-cli:windowsExecutableAmd64 pkl-core:testWindowsExecutableAmd64 pkl-server:testWindowsExecutableAmd64 ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true pkl-cli:windowsExecutableAmd64 pkl-core:testWindowsExecutableAmd64 pkl-server:testWindowsExecutableAmd64
name: gradle buildNative name: gradle buildNative
shell: bash.exe shell: bash.exe
- persist_to_workspace: - persist_to_workspace:
@@ -552,26 +625,15 @@ jobs:
path: ~/test-results path: ~/test-results
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
JAVA_HOME: /jdk
resource_class: windows.large resource_class: windows.large
machine: machine:
image: windows-server-2022-gui:current image: windows-server-2022-gui:current
gradle-check-jdk17: gradle-check:
steps: steps:
- checkout - checkout
- run: - run:
command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results check command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true check
name: gradle check
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
docker:
- image: cimg/openjdk:17.0
gradle-check-jdk21:
steps:
- checkout
- run:
command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results check
name: gradle check name: gradle check
- store_test_results: - store_test_results:
path: ~/test-results path: ~/test-results
@@ -579,16 +641,29 @@ jobs:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
docker: docker:
- image: cimg/openjdk:21.0 - image: cimg/openjdk:21.0
gradle-check-jdk17-windows: gradle-check-windows:
steps: steps:
- checkout - checkout
- run: - run:
command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results check command: |-
# install jdk
curl -Lf \
https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.5%2B11/OpenJDK21U-jdk_x64_windows_hotspot_21.0.5_11.zip -o /tmp/jdk.zip
unzip /tmp/jdk.zip -d /tmp/jdk \
&& cd /tmp/jdk/jdk-* \
&& mkdir /jdk \
&& cp -r . /jdk
name: Set up environment
shell: bash.exe
- run:
command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true check
name: gradle check name: gradle check
- store_test_results: - store_test_results:
path: ~/test-results path: ~/test-results
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
JAVA_HOME: /jdk
resource_class: windows.large resource_class: windows.large
machine: machine:
image: windows-server-2022-gui:current image: windows-server-2022-gui:current
@@ -596,20 +671,20 @@ jobs:
steps: steps:
- checkout - checkout
- run: - run:
command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results bench:jmh command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true bench:jmh
name: bench:jmh name: bench:jmh
- store_test_results: - store_test_results:
path: ~/test-results path: ~/test-results
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
docker: docker:
- image: cimg/openjdk:17.0 - image: cimg/openjdk:21.0
gradle-compatibility: gradle-compatibility:
steps: steps:
- checkout - checkout
- run: - run:
command: |- command: |-
./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results :pkl-gradle:build \ ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true :pkl-gradle:build \
:pkl-gradle:compatibilityTestReleases :pkl-gradle:compatibilityTestReleases
name: gradle compatibility name: gradle compatibility
- store_test_results: - store_test_results:
@@ -617,14 +692,14 @@ jobs:
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
docker: docker:
- image: cimg/openjdk:17.0 - image: cimg/openjdk:21.0
deploy-snapshot: deploy-snapshot:
steps: steps:
- checkout - checkout
- attach_workspace: - attach_workspace:
at: '.' at: '.'
- run: - run:
command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results publishToSonatype command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true publishToSonatype
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
paths: paths:
@@ -634,14 +709,14 @@ jobs:
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
docker: docker:
- image: cimg/openjdk:17.0 - image: cimg/openjdk:21.0
deploy-release: deploy-release:
steps: steps:
- checkout - checkout
- attach_workspace: - attach_workspace:
at: '.' at: '.'
- run: - run:
command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DreleaseBuild=true publishToSonatype closeAndReleaseSonatypeStagingRepository command: ./gradlew --info --stacktrace -DtestReportsDir=${HOME}/test-results -DpklMultiJdkTesting=true -DreleaseBuild=true publishToSonatype closeAndReleaseSonatypeStagingRepository
- persist_to_workspace: - persist_to_workspace:
root: '.' root: '.'
paths: paths:
@@ -651,7 +726,7 @@ jobs:
environment: environment:
LANG: en_US.UTF-8 LANG: en_US.UTF-8
docker: docker:
- image: cimg/openjdk:17.0 - image: cimg/openjdk:21.0
github-release: github-release:
steps: steps:
- attach_workspace: - attach_workspace:
@@ -660,6 +735,8 @@ jobs:
command: |- command: |-
# exclude build_artifacts.txt from publish # exclude build_artifacts.txt from publish
rm -f pkl-cli/build/executable/*.build_artifacts.txt rm -f pkl-cli/build/executable/*.build_artifacts.txt
find pkl-cli/build/executable/* -type d | xargs rm -rf
rm -f pkl-cli/build/executable/resources
gh release create "${CIRCLE_TAG}" \ gh release create "${CIRCLE_TAG}" \
--title "${CIRCLE_TAG}" \ --title "${CIRCLE_TAG}" \
--target "${CIRCLE_SHA1}" \ --target "${CIRCLE_SHA1}" \
@@ -703,13 +780,10 @@ workflows:
type: approval type: approval
- pr-approval/authenticate: - pr-approval/authenticate:
context: pkl-pr-approval context: pkl-pr-approval
- gradle-check-jdk17: - gradle-check:
requires: requires:
- hold - hold
- gradle-check-jdk21: - gradle-check-windows:
requires:
- hold
- gradle-check-jdk17-windows:
requires: requires:
- hold - hold
when: when:
@@ -718,9 +792,8 @@ workflows:
pattern: ^pull/\d+(/head)?$ pattern: ^pull/\d+(/head)?$
main: main:
jobs: jobs:
- gradle-check-jdk17 - gradle-check
- gradle-check-jdk21 - gradle-check-windows
- gradle-check-jdk17-windows
- bench - bench
- gradle-compatibility - gradle-compatibility
- pkl-cli-macOS-amd64-snapshot - pkl-cli-macOS-amd64-snapshot
@@ -731,9 +804,8 @@ workflows:
- pkl-cli-windows-amd64-snapshot - pkl-cli-windows-amd64-snapshot
- deploy-snapshot: - deploy-snapshot:
requires: requires:
- gradle-check-jdk17 - gradle-check
- gradle-check-jdk21 - gradle-check-windows
- gradle-check-jdk17-windows
- bench - bench
- gradle-compatibility - gradle-compatibility
- pkl-cli-macOS-amd64-snapshot - pkl-cli-macOS-amd64-snapshot
@@ -754,19 +826,13 @@ workflows:
- << pipeline.git.branch >> - << pipeline.git.branch >>
release: release:
jobs: jobs:
- gradle-check-jdk17: - gradle-check:
filters: filters:
branches: branches:
ignore: /.*/ ignore: /.*/
tags: tags:
only: /^v?\d+\.\d+\.\d+$/ only: /^v?\d+\.\d+\.\d+$/
- gradle-check-jdk21: - gradle-check-windows:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- gradle-check-jdk17-windows:
filters: filters:
branches: branches:
ignore: /.*/ ignore: /.*/
@@ -822,9 +888,8 @@ workflows:
only: /^v?\d+\.\d+\.\d+$/ only: /^v?\d+\.\d+\.\d+$/
- github-release: - github-release:
requires: requires:
- gradle-check-jdk17 - gradle-check
- gradle-check-jdk21 - gradle-check-windows
- gradle-check-jdk17-windows
- bench - bench
- gradle-compatibility - gradle-compatibility
- pkl-cli-macOS-amd64-release - pkl-cli-macOS-amd64-release
@@ -860,9 +925,8 @@ workflows:
only: /^v?\d+\.\d+\.\d+$/ only: /^v?\d+\.\d+\.\d+$/
release-branch: release-branch:
jobs: jobs:
- gradle-check-jdk17 - gradle-check
- gradle-check-jdk21 - gradle-check-windows
- gradle-check-jdk17-windows
- bench - bench
- gradle-compatibility - gradle-compatibility
- pkl-cli-macOS-amd64-release - pkl-cli-macOS-amd64-release
+33 -11
View File
@@ -17,7 +17,6 @@
extends "GradleJob.pkl" extends "GradleJob.pkl"
import "package://pkg.pkl-lang.org/pkl-pantry/com.circleci.v2@1.1.2#/Config.pkl" import "package://pkg.pkl-lang.org/pkl-pantry/com.circleci.v2@1.1.2#/Config.pkl"
import "package://pkg.pkl-lang.org/pkl-pantry/pkl.experimental.uri@1.0.0#/URI.pkl"
/// The architecture to use /// The architecture to use
arch: "amd64"|"aarch64" arch: "amd64"|"aarch64"
@@ -25,13 +24,11 @@ arch: "amd64"|"aarch64"
/// Whether to link to musl. Otherwise, links to glibc. /// Whether to link to musl. Otherwise, links to glibc.
musl: Boolean = false musl: Boolean = false
javaVersion = "21.0"
local setupLinuxEnvironment: Config.RunStep = local setupLinuxEnvironment: Config.RunStep =
let (jdkVersion = "17.0.9+9")
let (muslVersion = "1.2.2") let (muslVersion = "1.2.2")
let (zlibVersion = "1.2.13") let (zlibVersion = "1.2.13")
let (jdkVersionEncoded = URI.encodeComponent(jdkVersion))
let (jdkVersionAlt = jdkVersion.replaceLast("+", "_"))
let (majorJdkVersion = jdkVersion.split(".").first)
new { new {
name = "Set up environment" name = "Set up environment"
shell = "#!/bin/bash -exo pipefail" shell = "#!/bin/bash -exo pipefail"
@@ -43,8 +40,8 @@ local setupLinuxEnvironment: Config.RunStep =
&& rm -rf /var/cache/dnf && rm -rf /var/cache/dnf
# install jdk # install jdk
curl -L \ curl -Lf \
https://github.com/adoptium/temurin\#(majorJdkVersion)-binaries/releases/download/jdk-\#(jdkVersionEncoded)/OpenJDK\#(majorJdkVersion)U-jdk_\#(if (arch == "amd64") "x64" else "aarch64")_linux_hotspot_\#(jdkVersionAlt).tar.gz -o /tmp/jdk.tar.gz https://github.com/adoptium/temurin\#(module.majorJdkVersion)-binaries/releases/download/\#(module.jdkGitHubReleaseName)/OpenJDK\#(module.majorJdkVersion)U-jdk_\#(if (arch == "amd64") "x64" else "aarch64")_linux_hotspot_\#(module.jdkVersionAlt).tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \ mkdir /jdk \
&& cd /jdk \ && cd /jdk \
@@ -56,7 +53,7 @@ local setupLinuxEnvironment: Config.RunStep =
# install zlib # install zlib
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
curl -L https://github.com/madler/zlib/releases/download/v\#(zlibVersion)/zlib-\#(zlibVersion).tar.gz -o /tmp/zlib.tar.gz curl -Lf https://github.com/madler/zlib/releases/download/v\#(zlibVersion)/zlib-\#(zlibVersion).tar.gz -o /tmp/zlib.tar.gz
mkdir -p /tmp/dep_zlib-\#(zlibVersion) \ mkdir -p /tmp/dep_zlib-\#(zlibVersion) \
&& cd /tmp/dep_zlib-\#(zlibVersion) \ && cd /tmp/dep_zlib-\#(zlibVersion) \
@@ -72,7 +69,7 @@ local setupLinuxEnvironment: Config.RunStep =
#""" #"""
# install musl # install musl
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
curl -L https://musl.libc.org/releases/musl-\#(muslVersion).tar.gz -o /tmp/musl.tar.gz curl -Lf https://musl.libc.org/releases/musl-\#(muslVersion).tar.gz -o /tmp/musl.tar.gz
mkdir -p /tmp/dep_musl-\#(muslVersion) \ mkdir -p /tmp/dep_musl-\#(muslVersion) \
&& cd /tmp/dep_musl-\#(muslVersion) \ && cd /tmp/dep_musl-\#(muslVersion) \
@@ -90,6 +87,22 @@ local setupLinuxEnvironment: Config.RunStep =
}.join("\n\n") }.join("\n\n")
} }
local setupMacEnvironment: Config.RunStep =
new {
name = "Set up environment"
shell = "#!/bin/bash -exo pipefail"
command =
#"""
# install jdk
curl -Lf \
https://github.com/adoptium/temurin\#(module.majorJdkVersion)-binaries/releases/download/\#(module.jdkGitHubReleaseName)/OpenJDK\#(module.majorJdkVersion)U-jdk_\#(if (arch == "amd64") "x64" else "aarch64")_mac_hotspot_\#(module.jdkVersionAlt).tar.gz -o /tmp/jdk.tar.gz
mkdir $HOME/jdk \
&& cd $HOME/jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
"""#
}
steps { steps {
when (os == "linux") { when (os == "linux") {
new Config.RestoreCacheStep { new Config.RestoreCacheStep {
@@ -105,7 +118,8 @@ steps {
} }
} }
} }
when (os == "macOS" && arch == "amd64") { when (os == "macOS") {
when (arch == "amd64") {
new Config.RunStep { new Config.RunStep {
name = "Installing Rosetta 2" name = "Installing Rosetta 2"
command = """ command = """
@@ -113,6 +127,8 @@ steps {
""" """
} }
} }
setupMacEnvironment
}
new Config.RunStep { new Config.RunStep {
name = "gradle buildNative" name = "gradle buildNative"
local _os = local _os =
@@ -143,9 +159,12 @@ job {
xcode = "15.3.0" xcode = "15.3.0"
} }
resource_class = "macos.m1.large.gen1" resource_class = "macos.m1.large.gen1"
environment {
["JAVA_HOME"] = "/Users/distiller/jdk/Contents/Home"
}
} }
when (os == "linux") { when (os == "linux") {
docker { docker = new Listing<Config.DockerImage> {
new { new {
image = if (arch == "aarch64") "arm64v8/oraclelinux:8-slim" else "oraclelinux:8-slim" image = if (arch == "aarch64") "arm64v8/oraclelinux:8-slim" else "oraclelinux:8-slim"
} }
@@ -160,5 +179,8 @@ job {
image = "windows-server-2022-gui:current" image = "windows-server-2022-gui:current"
} }
resource_class = "windows.large" resource_class = "windows.large"
environment {
["JAVA_HOME"] = "/jdk"
}
} }
} }
+2 -6
View File
@@ -19,13 +19,9 @@ import "package://pkg.pkl-lang.org/pkl-pantry/com.circleci.v2@1.1.2#/Config.pkl"
local self = this local self = this
command: String javaVersion = "21.0"
job { command: String
docker {
new { image = "cimg/openjdk:17.0" }
}
}
os = "linux" os = "linux"
-20
View File
@@ -17,29 +17,9 @@ extends "GradleJob.pkl"
import "package://pkg.pkl-lang.org/pkl-pantry/com.circleci.v2@1.1.2#/Config.pkl" import "package://pkg.pkl-lang.org/pkl-pantry/com.circleci.v2@1.1.2#/Config.pkl"
javaVersion: "17.0"|"21.0"
os = "linux"
steps { steps {
new Config.RunStep { new Config.RunStep {
name = "gradle check" name = "gradle check"
command = "./gradlew \(module.gradleArgs) check" command = "./gradlew \(module.gradleArgs) check"
} }
} }
job {
when (os == "linux") {
docker {
new {
image = "cimg/openjdk:\(javaVersion)"
}
}
}
when (os == "windows") {
machine {
image = "windows-server-2022-gui:current"
}
resource_class = "windows.large"
}
}
+53
View File
@@ -16,6 +16,7 @@
abstract module GradleJob abstract module GradleJob
import "package://pkg.pkl-lang.org/pkl-pantry/com.circleci.v2@1.1.2#/Config.pkl" import "package://pkg.pkl-lang.org/pkl-pantry/com.circleci.v2@1.1.2#/Config.pkl"
import "package://pkg.pkl-lang.org/pkl-pantry/pkl.experimental.uri@1.0.3#/URI.pkl"
/// Whether this is a release build or not. /// Whether this is a release build or not.
isRelease: Boolean = false isRelease: Boolean = false
@@ -23,10 +24,30 @@ isRelease: Boolean = false
/// The OS to run on /// The OS to run on
os: "macOS"|"linux"|"windows" os: "macOS"|"linux"|"windows"
/// The version of Java to use.
javaVersion: "17.0"|"21.0"
fixed javaVersionFull =
if (javaVersion == "17.0") "17.0.9+9"
else "21.0.5+11"
fixed jdkVersionAlt = javaVersionFull.replaceLast("+", "_")
fixed majorJdkVersion = javaVersionFull.split(".").first
fixed jdkGitHubReleaseName =
let (ver =
// 17.0.9+9 is missing some binaries (see https://github.com/adoptium/adoptium-support/issues/994)
if (javaVersionFull == "17.0.9+9" && os == "windows") "jdk-17.0.9+9.1"
else "jdk-\(javaVersionFull)"
)
URI.encodeComponent(ver)
fixed gradleArgs = new Listing { fixed gradleArgs = new Listing {
"--info" "--info"
"--stacktrace" "--stacktrace"
"-DtestReportsDir=${HOME}/test-results" "-DtestReportsDir=${HOME}/test-results"
"-DpklMultiJdkTesting=true"
when (isRelease) { when (isRelease) {
"-DreleaseBuild=true" "-DreleaseBuild=true"
} }
@@ -37,9 +58,41 @@ steps: Listing<Config.Step>
job: Config.Job = new { job: Config.Job = new {
environment { environment {
["LANG"] = "en_US.UTF-8" ["LANG"] = "en_US.UTF-8"
when (os == "windows") {
["JAVA_HOME"] = "/jdk"
}
}
when (os == "linux") {
docker {
new {
image = "cimg/openjdk:\(javaVersion)"
}
}
}
when (os == "windows") {
machine {
image = "windows-server-2022-gui:current"
}
resource_class = "windows.large"
} }
steps { steps {
"checkout" "checkout"
when (os == "windows") {
new Config.RunStep {
name = "Set up environment"
shell = "bash.exe"
command = #"""
# install jdk
curl -Lf \
https://github.com/adoptium/temurin\#(majorJdkVersion)-binaries/releases/download/\#(jdkGitHubReleaseName)/OpenJDK\#(majorJdkVersion)U-jdk_x64_windows_hotspot_\#(jdkVersionAlt).zip -o /tmp/jdk.zip
unzip /tmp/jdk.zip -d /tmp/jdk \
&& cd /tmp/jdk/jdk-* \
&& mkdir /jdk \
&& cp -r . /jdk
"""#
}
}
...module.steps ...module.steps
new Config.StoreTestResults { new Config.StoreTestResults {
path = "~/test-results" path = "~/test-results"
+2 -6
View File
@@ -23,6 +23,8 @@ command: String
os = "linux" os = "linux"
javaVersion = "21.0"
steps { steps {
new Config.RunStep { new Config.RunStep {
name = module.name name = module.name
@@ -31,9 +33,3 @@ steps {
""" """
} }
} }
job {
docker {
new { image = "cimg/openjdk:17.0" }
}
}
+3
View File
@@ -5,6 +5,7 @@
.gradle/ .gradle/
build/ build/
generated/ generated/
testgenerated/
# IntelliJ # IntelliJ
.idea/ .idea/
@@ -22,3 +23,5 @@ generated/
# :pkl-core:makeIntelliJAntlrPluginHappy # :pkl-core:makeIntelliJAntlrPluginHappy
gen/ gen/
PklLexer.tokens PklLexer.tokens
.kotlin/
+1 -1
View File
@@ -1 +1 @@
17.0 21
+15 -13
View File
@@ -2,12 +2,12 @@
:uri-gng: https://gng.dsun.org :uri-gng: https://gng.dsun.org
:uri-jenv: https://www.jenv.be :uri-jenv: https://www.jenv.be
:uri-intellij: https://www.jetbrains.com/idea/download/ :uri-intellij: https://www.jetbrains.com/idea/download/
:uri-jdk: https://adoptopenjdk.net/releases.html?variant=openjdk17 :uri-native-prerequisites-linux: https://www.graalvm.org/latest/getting-started/linux/#prerequisites-for-native-image-on-linux
:uri-native-prerequisites: https://www.graalvm.org/latest/getting-started/windows/#prerequisites-for-native-image-on-windows :uri-native-prerequisites-windows: https://www.graalvm.org/latest/getting-started/windows/#prerequisites-for-native-image-on-windows
== Setup == Setup
. (mandatory) Install {uri-jdk}[OpenJDK 17] or higher . (mandatory) Install a JDK (JDK 21+ required).
. (recommended) Install {uri-intellij}[IntelliJ IDEA] + . (recommended) Install {uri-intellij}[IntelliJ IDEA] +
To import the project into IntelliJ, go to File->Open and select the project's root directory. To import the project into IntelliJ, go to File->Open and select the project's root directory.
If the project is opened but not imported, look for a popup in the lower right corner If the project is opened but not imported, look for a popup in the lower right corner
@@ -17,7 +17,7 @@ _gng_ enables to run Gradle commands with `gw` (instead of `./gradlew`) from any
. (recommended) Set up Git ignore-revs + . (recommended) Set up Git ignore-revs +
`git config blame.ignoreRevsFile .git-blame-ignore-revs` `git config blame.ignoreRevsFile .git-blame-ignore-revs`
. (recommended) Install {uri-jenv}[jenv] and plugins + . (recommended) Install {uri-jenv}[jenv] and plugins +
_jenv_ use specific JDK versions in certain subdirectories. _Pkl_ comes with a `.java-version` file specifying JDK 17. + _jenv_ use specific JDK versions in certain subdirectories. _Pkl_ comes with a `.java-version` file specifying JDK 21. +
Enable _jenv_ plugins for better handling by `gradle`: Enable _jenv_ plugins for better handling by `gradle`:
+ +
[source,shell] [source,shell]
@@ -25,12 +25,20 @@ Enable _jenv_ plugins for better handling by `gradle`:
jenv enable-plugin gradle jenv enable-plugin gradle
jenv enable-plugin export jenv enable-plugin export
---- ----
. (optional) If you've named the original apple/pkl git repository something other than `origin`, set env var `PKL_ORIGINAL_REMOTE_NAME` to that name in your `.bashrc`, `.zshrc`, `config.fish` or however you manage your local environment.
+
This will allow spotless to pick the correct starting branch when formatting source code files.
Otherwise, you might see that _every_ file has its copyright year updated.
=== Additional Linux Setup
. (optional) To build the native executable (`./gradlew buildNative`),
install {uri-native-prerequisites-linux}[Prerequisites For Native Image on Linux].
=== Additional Windows Setup === Additional Windows Setup
. (optional) Go to `System->For developers` and enable `Developer Mode`. . (optional) Go to `System->For developers` and enable `Developer Mode`.
Otherwise, some tests may fail due to insufficient file system privileges. Otherwise, some tests may fail due to insufficient file system privileges.
. (optional) To build the native executable (`./gradlew buildNative`), . (optional) To build the native executable (`./gradlew buildNative`),
install {uri-native-prerequisites}[Prerequisites For Native Image on Windows]. install {uri-native-prerequisites-windows}[Prerequisites For Native Image on Windows].
== Common Build Commands == Common Build Commands
@@ -75,8 +83,8 @@ based on version information from https://search.maven.org, https://plugins.grad
* Truffle code generation is performed by Truffle's annotation processor, which runs as part of task `:pkl-core:compileJava` * Truffle code generation is performed by Truffle's annotation processor, which runs as part of task `:pkl-core:compileJava`
** Output dir is `generated/truffle/` ** Output dir is `generated/truffle/`
* ANTLR code generation is performed by task `:pkl-core:generateGrammarSource` * ANTLR code generation is performed by task `:pkl-core:generateTestGrammarSource`
** Output dir is `generated/antlr/` ** Output dir is `testgenerated/antlr/`
== Remote JVM Debugging == Remote JVM Debugging
@@ -88,12 +96,6 @@ Example: `./gradlew test -Djvmdebug=true`
== Resources == Resources
For automated build setup examples see our https://github.com/apple/pkl/blob/main/.circleci/[CircleCI] jobs like our https://github.com/apple/pkl/blob/main/.circleci/jobs/BuildNativeJob.pkl[BuildNativeJob.pkl], where we build Pkl automatically. For automated build setup examples see our https://github.com/apple/pkl/blob/main/.circleci/[CircleCI] jobs like our https://github.com/apple/pkl/blob/main/.circleci/jobs/BuildNativeJob.pkl[BuildNativeJob.pkl], where we build Pkl automatically.
=== ANTLR
* https://github.com/antlr/antlr4/blob/master/doc/index.md[Documentation]
* https://groups.google.com/forum/#!forum/antlr-discussion[Forums]
* https://github.com/mobileink/lab.clj.antlr/tree/main/doc[Some third-party docs]
=== Truffle === Truffle
* http://ssw.jku.at/Research/Projects/JVM/Truffle.html[Homepage] * http://ssw.jku.at/Research/Projects/JVM/Truffle.html[Homepage]
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright © 2024 Apple Inc. and the Pkl project authors Copyright © 2024-2025 Apple Inc. and the Pkl project authors
Portions of this software were originally based on 'SnakeYAML' developed by Andrey Somov. Portions of this software were originally based on 'SnakeYAML' developed by Andrey Somov.
+21 -32
View File
@@ -26,18 +26,7 @@ Copyright © 2017 Square, Inc.
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
4) ANTLR 4 Runtime (Optimized) (http://tunnelvisionlabs.com) 4) GeantyRef (https://github.com/leangen/geantyref)
POM License: The BSD License - http://www.antlr.org/license.html
Copyright (c) 2012 Terence Parr and Sam Harwell
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5) GeantyRef (https://github.com/leangen/geantyref)
Manifest license URL: https://www.apache.org/licenses/LICENSE-2.0 Manifest license URL: https://www.apache.org/licenses/LICENSE-2.0
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
@@ -47,7 +36,7 @@ Copyright © 2017 Kaqqao
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
6) commonmark-java core 5) commonmark-java core
POM License: The 2-Clause BSD License - https://opensource.org/licenses/BSD-2-Clause POM License: The 2-Clause BSD License - https://opensource.org/licenses/BSD-2-Clause
Embedded license: Embedded license:
@@ -78,7 +67,7 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7) commonmark-java extension for tables 6) commonmark-java extension for tables
POM License: The 2-Clause BSD License - https://opensource.org/licenses/BSD-2-Clause POM License: The 2-Clause BSD License - https://opensource.org/licenses/BSD-2-Clause
Embedded license: Embedded license:
@@ -109,7 +98,7 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8) jansi (http://fusesource.com/) 7) jansi (http://fusesource.com/)
Manifest license URL: https://www.apache.org/licenses/LICENSE-2.0 Manifest license URL: https://www.apache.org/licenses/LICENSE-2.0
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
@@ -119,13 +108,13 @@ Copyright © Fusesource 2023
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
9) Graal Sdk (https://github.com/oracle/graal) 8) Graal Sdk (https://github.com/oracle/graal)
POM License: Universal Permissive License, Version 1.0 - http://opensource.org/licenses/UPL POM License: Universal Permissive License, Version 1.0 - http://opensource.org/licenses/UPL
10) Truffle API (http://openjdk.java.net/projects/graal) 9) Truffle API (http://openjdk.java.net/projects/graal)
POM License: Universal Permissive License, Version 1.0 - http://opensource.org/licenses/UPL POM License: Universal Permissive License, Version 1.0 - http://opensource.org/licenses/UPL
11) IntelliJ IDEA Annotations (http://www.jetbrains.org) 10) IntelliJ IDEA Annotations (http://www.jetbrains.org)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -133,7 +122,7 @@ Copyright © Jetbrains 2023
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
12) kotlin-reflect (https://kotlinlang.org/) 11) kotlin-reflect (https://kotlinlang.org/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -141,7 +130,7 @@ Copyright © Wuseal 2018
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
13) kotlin-stdlib (https://kotlinlang.org/) 12) kotlin-stdlib (https://kotlinlang.org/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -149,7 +138,7 @@ Copyright © 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contribu
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
14) kotlin-stdlib-common (https://kotlinlang.org/) 13) kotlin-stdlib-common (https://kotlinlang.org/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -157,7 +146,7 @@ Copyright © 2023 Kotlin Team
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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) kotlin-stdlib-jdk7 (https://kotlinlang.org/) 14) kotlin-stdlib-jdk7 (https://kotlinlang.org/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -165,7 +154,7 @@ Copyright © 2023 Kotlin Team
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
16) kotlin-stdlib-jdk8 (https://kotlinlang.org/) 15) kotlin-stdlib-jdk8 (https://kotlinlang.org/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -173,7 +162,7 @@ Copyright © 2023 Kotlin Team
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
17) kotlinx.html (https://github.com/Kotlin/kotlinx.html) 16) kotlinx.html (https://github.com/Kotlin/kotlinx.html)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -181,7 +170,7 @@ Copyright © 2017 Yole
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
18) kotlinx-serialization-core (https://github.com/Kotlin/kotlinx.serialization) 17) kotlinx-serialization-core (https://github.com/Kotlin/kotlinx.serialization)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -189,7 +178,7 @@ The Apache License
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
19) kotlinx-serialization-json (https://github.com/Kotlin/kotlinx.serialization) 18) kotlinx-serialization-json (https://github.com/Kotlin/kotlinx.serialization)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -197,7 +186,7 @@ The Apache License
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
20) JLine Reader 19) JLine Reader
Manifest license URL: https://opensource.org/licenses/BSD-3-Clause Manifest license URL: https://opensource.org/licenses/BSD-3-Clause
POM License: The 3-Clause BSD License - https://opensource.org/licenses/BSD-3-Clause POM License: The 3-Clause BSD License - https://opensource.org/licenses/BSD-3-Clause
@@ -216,7 +205,7 @@ software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21) JLine Terminal 20) JLine Terminal
Manifest license URL: https://opensource.org/licenses/BSD-3-Clause Manifest license URL: https://opensource.org/licenses/BSD-3-Clause
POM License: The 3-Clause BSD License - https://opensource.org/licenses/BSD-3-Clause POM License: The 3-Clause BSD License - https://opensource.org/licenses/BSD-3-Clause
@@ -235,7 +224,7 @@ software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22) JLine JANSI Terminal 21) JLine JANSI Terminal
Manifest license URL: https://opensource.org/licenses/BSD-3-Clause Manifest license URL: https://opensource.org/licenses/BSD-3-Clause
POM License: The 3-Clause BSD License - https://opensource.org/licenses/BSD-3-Clause POM License: The 3-Clause BSD License - https://opensource.org/licenses/BSD-3-Clause
@@ -254,7 +243,7 @@ software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23) msgpack-core (https://msgpack.org/) 22) msgpack-core (https://msgpack.org/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -262,7 +251,7 @@ Copyright © 2016 Sadayuki Furuhashi, Muga Nishizawa, Taro L. Saito, Mitsunori K
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 http://www.apache.org/licenses/LICENSE-2.0 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 http://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. 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.
24) Paguro (https://github.com/GlenKPeterson/Paguro) 23) Paguro (https://github.com/GlenKPeterson/Paguro)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License The Apache License
@@ -364,7 +353,7 @@ Everyone is permitted to copy and distribute copies of this Agreement, but in or
This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation. This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose. Each party waives its rights to a jury trial in any resulting litigation.
25) SnakeYAML Engine (http://www.snakeyaml.org) 24) SnakeYAML Engine (http://www.snakeyaml.org)
Manifest license URL: https://www.apache.org/licenses/LICENSE-2.0 Manifest license URL: https://www.apache.org/licenses/LICENSE-2.0
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
+2 -5
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,18 +16,15 @@
plugins { plugins {
pklAllProjects pklAllProjects
pklJavaLibrary pklJavaLibrary
pklGraalVm
id("me.champeau.jmh") id("me.champeau.jmh")
} }
val truffle: Configuration by configurations.creating val truffle: Configuration by configurations.creating
val graal: Configuration by configurations.creating val graal: Configuration by configurations.creating
@Suppress("UnstableApiUsage")
dependencies { dependencies {
jmh(projects.pklCore) jmh(projects.pklCore)
// necessary because antlr4-runtime is declared as implementation dependency in pkl-core.gradle jmh(projects.pklCommonsTest)
jmh(libs.antlrRuntime)
truffle(libs.truffleApi) truffle(libs.truffleApi)
graal(libs.graalCompiler) graal(libs.graalCompiler)
} }
+50 -32
View File
@@ -1,44 +1,62 @@
# This is a Gradle generated file for dependency locking. # This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised. # Manual edits can break the build and are not advised.
# This file is expected to be part of source control. # This file is expected to be part of source control.
com.tunnelvisionlabs:antlr4-runtime:4.9.0=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath net.bytebuddy:byte-buddy:1.15.11=jmh,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.14.18=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.6.0=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
net.sf.jopt-simple:jopt-simple:5.0.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath net.sf.jopt-simple:jopt-simple:5.0.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.apache.commons:commons-math3:3.6.1=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath org.apache.commons:commons-math3:3.6.1=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata org.apiguardian:apiguardian-api:1.1.2=jmhCompileClasspath,jmhImplementationDependenciesMetadata,testCompileClasspath,testImplementationDependenciesMetadata,testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata
org.assertj:assertj-core:3.26.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.assertj:assertj-core:3.27.3=jmh,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.compiler:compiler:23.0.6=graal org.graalvm.compiler:compiler:24.1.2=graal
org.graalvm.sdk:graal-sdk:23.0.6=graal,jmh,jmhRuntimeClasspath,truffle org.graalvm.polyglot:polyglot:24.1.2=jmh,jmhRuntimeClasspath,truffle
org.graalvm.truffle:truffle-api:23.0.6=graal,jmh,jmhRuntimeClasspath,truffle org.graalvm.sdk:collections:24.1.2=graal,jmh,jmhRuntimeClasspath,truffle
org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.sdk:graal-sdk:24.1.2=jmh,jmhRuntimeClasspath
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.sdk:nativeimage:24.1.2=jmh,jmhRuntimeClasspath,truffle
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.sdk:word:24.1.2=graal,jmh,jmhRuntimeClasspath,truffle
org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.7.10=kotlinKlibCommonizerClasspath org.graalvm.truffle:truffle-api:24.1.2=jmh,jmhRuntimeClasspath,truffle
org.jetbrains.kotlin:kotlin-reflect:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.truffle:truffle-compiler:24.1.2=graal
org.jetbrains.kotlin:kotlin-script-runtime:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-common:1.7.10=kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.7.10=kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.7.10=kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-build-tools-impl:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-jvm:1.7.10=kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-stdlib:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.0.21=kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-native-prebuilt:2.0.21=kotlinNativeBundleConfiguration
org.junit.jupiter:junit-jupiter-api:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-reflect:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.junit.jupiter:junit-jupiter-engine:5.11.3=testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-script-runtime:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17,kotlinKlibCommonizerClasspath
org.junit.jupiter:junit-jupiter-params:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-scripting-common:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.junit.platform:junit-platform-commons:1.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.junit.platform:junit-platform-engine:1.11.3=testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.junit:junit-bom:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-scripting-jvm:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.21=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.11.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-api:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.11.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-engine:5.8.2=testJdk17RuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.11.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.jupiter:junit-jupiter:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.platform:junit-platform-commons:1.11.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-commons:1.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.platform:junit-platform-engine:1.11.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-engine:1.8.2=testJdk17RuntimeClasspath
org.junit.platform:junit-platform-launcher:1.8.2=testJdk17RuntimeClasspath
org.junit:junit-bom:5.11.4=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit:junit-bom:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.msgpack:msgpack-core:0.9.8=jmh,jmhRuntimeClasspath org.msgpack:msgpack-core:0.9.8=jmh,jmhRuntimeClasspath
org.openjdk.jmh:jmh-core:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath org.openjdk.jmh:jmh-core:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.openjdk.jmh:jmh-generator-asm:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath org.openjdk.jmh:jmh-generator-asm:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.openjdk.jmh:jmh-generator-bytecode:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath org.openjdk.jmh:jmh-generator-bytecode:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.openjdk.jmh:jmh-generator-reflection:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath org.openjdk.jmh:jmh-generator-reflection:1.37=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.opentest4j:opentest4j:1.2.0=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.opentest4j:opentest4j:1.3.0=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.organicdesign:Paguro:3.10.3=jmh,jmhRuntimeClasspath org.organicdesign:Paguro:3.10.3=jmh,jmhRuntimeClasspath
org.ow2.asm:asm:9.0=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath org.ow2.asm:asm:9.0=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.snakeyaml:snakeyaml-engine:2.5=jmh,jmhRuntimeClasspath org.snakeyaml:snakeyaml-engine:2.9=jmh,jmhRuntimeClasspath
empty=annotationProcessor,apiDependenciesMetadata,compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,jmhAnnotationProcessor,jmhApiDependenciesMetadata,jmhCompileOnlyDependenciesMetadata,jmhIntransitiveDependenciesMetadata,jmhKotlinScriptDef,jmhKotlinScriptDefExtensions,jmhRuntimeOnlyDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtimeClasspath,runtimeOnlyDependenciesMetadata,sourcesJar,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions empty=annotationProcessor,apiDependenciesMetadata,compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,jmhAnnotationProcessor,jmhApiDependenciesMetadata,jmhCompileOnlyDependenciesMetadata,jmhIntransitiveDependenciesMetadata,jmhKotlinScriptDef,jmhKotlinScriptDefExtensions,jmhRuntimeOnlyDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtimeClasspath,runtimeOnlyDependenciesMetadata,sourcesJar,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testJdk17AnnotationProcessor,testJdk17ApiDependenciesMetadata,testJdk17CompileOnlyDependenciesMetadata,testJdk17IntransitiveDependenciesMetadata,testJdk17KotlinScriptDefExtensions,testKotlinScriptDef,testKotlinScriptDefExtensions
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,8 +15,15 @@
*/ */
package org.pkl.core.parser; package org.pkl.core.parser;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.annotations.*;
import org.pkl.commons.test.FileTestUtils;
import org.pkl.commons.test.FileTestUtilsKt;
import org.pkl.core.Release;
import org.pkl.core.util.IoUtils;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Warmup(iterations = 5, time = 2) @Warmup(iterations = 5, time = 2)
@@ -24,37 +31,33 @@ import org.openjdk.jmh.annotations.*;
@OutputTimeUnit(TimeUnit.SECONDS) @OutputTimeUnit(TimeUnit.SECONDS)
@Fork(1) @Fork(1)
public class ParserBenchmark { public class ParserBenchmark {
// One-time execution of this code took ~10s until moving rule alternative
// for parenthesized expression after alternative for anonymous function.
@Benchmark @Benchmark
public void run() { public void parseStdlib() {
new Parser() for (var stdlibModule : Release.current().standardLibrary().modules()) {
.parseModule( try {
""" var moduleSource =
a1 { IoUtils.readClassPathResourceAsString(
a2 { getClass(), "/org/pkl/core/stdlib/%s.pkl".formatted(stdlibModule.substring(4)));
a3 { new Parser().parseModule(moduleSource);
a4 { } catch (IOException e) {
a5 { throw new UncheckedIOException(e);
a6 { }
a7 { }
a8 { }
a9 {
a10 { @Benchmark
a11 { public void parseSnippetTests() {
a12 { var snippetTestDir =
a13 = map(map(map((x) -> 1))) FileTestUtils.getRootProjectDir()
.resolve("pkl-core/src/test/files/LanguageSnippetTests/input");
for (var snippet : FileTestUtilsKt.listFilesRecursively(snippetTestDir)) {
try {
var moduleSource = Files.readString(snippet);
new Parser().parseModule(moduleSource);
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (ParserError ignore) {
} }
} }
} }
} }
}
}
}
}
}
}
}
}""");
}
}
+21 -5
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,7 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
plugins { `kotlin-dsl` } import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
`kotlin-dsl`
`jvm-toolchains`
}
// Keep this in sync with the constants in `BuildInfo.kt` (those are not addressable here).
val toolchainVersion = 21
dependencies { dependencies {
implementation(libs.downloadTaskPlugin) implementation(libs.downloadTaskPlugin)
@@ -27,8 +35,16 @@ dependencies {
} }
java { java {
sourceCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.toVersion(toolchainVersion)
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.toVersion(toolchainVersion)
toolchain {
languageVersion = JavaLanguageVersion.of(toolchainVersion)
vendor = JvmVendorSpec.ADOPTIUM
}
} }
kotlin { target { compilations.configureEach { kotlinOptions { jvmTarget = "17" } } } } kotlin {
jvmToolchain(toolchainVersion)
compilerOptions { jvmTarget = JvmTarget.fromTarget(toolchainVersion.toString()) }
}
+3 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@ pluginManagement {
} }
} }
plugins { id("org.gradle.toolchains.foojay-resolver-convention") }
// makes ~/.gradle/init.gradle unnecessary and ~/.gradle/gradle.properties optional // makes ~/.gradle/init.gradle unnecessary and ~/.gradle/gradle.properties optional
dependencyResolutionManagement { dependencyResolutionManagement {
// use same version catalog as main build // use same version catalog as main build
+273 -3
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -19,11 +19,56 @@ import java.io.File
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalog import org.gradle.api.artifacts.VersionCatalog
import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.kotlin.dsl.getByType import org.gradle.api.attributes.Category
import org.gradle.api.plugins.JvmTestSuitePlugin
import org.gradle.api.plugins.jvm.JvmTestSuite
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.testing.Test
import org.gradle.internal.extensions.stdlib.capitalized
import org.gradle.jvm.toolchain.*
import org.gradle.kotlin.dsl.*
import org.gradle.kotlin.dsl.support.serviceOf
import org.gradle.process.CommandLineArgumentProvider
import org.gradle.testing.base.TestingExtension
/**
* JVM bytecode target; this is pinned at a reasonable version, because downstream JVM projects
* which consume Pkl will need a minimum Bytecode level at or above this one.
*
* Kotlin and Java need matching bytecode targets, so this is expressed as a build setting and
* constant default. To override, pass `-DpklJdkToolchain=X` to the Gradle command line, where X is
* a major Java version.
*/
const val PKL_JVM_TARGET_DEFAULT_MAXIMUM = 17
/**
* The Pkl build requires JDK 21+ to build, because JDK 17 is no longer within the default set of
* supported JDKs for GraalVM. This is a build-time requirement, not a runtime requirement.
*/
const val PKL_JDK_VERSION_MIN = 21
/**
* The JDK minimum is set to match the bytecode minimum, to guarantee that fat JARs work against the
* earliest supported bytecode target.
*/
const val PKL_TEST_JDK_MINIMUM = PKL_JVM_TARGET_DEFAULT_MAXIMUM
/**
* Maximum JDK version which Pkl is tested with; this should be bumped when new JDK stable releases
* are issued. At the time of this writing, JDK 23 is the latest available release.
*/
const val PKL_TEST_JDK_MAXIMUM = 23
/**
* Test the full suite of JDKs between [PKL_TEST_JDK_MINIMUM] and [PKL_TEST_JDK_MAXIMUM]; if this is
* set to `false` (or overridden on the command line), only LTS releases are tested by default.
*/
const val PKL_TEST_ALL_JDKS = false
// `buildInfo` in main build scripts // `buildInfo` in main build scripts
// `project.extensions.getByType<BuildInfo>()` in precompiled script plugins // `project.extensions.getByType<BuildInfo>()` in precompiled script plugins
open class BuildInfo(project: Project) { open class BuildInfo(private val project: Project) {
inner class GraalVm(val arch: String) { inner class GraalVm(val arch: String) {
val homeDir: String by lazy { val homeDir: String by lazy {
System.getenv("GRAALVM_HOME") ?: "${System.getProperty("user.home")}/.graalvm" System.getenv("GRAALVM_HOME") ?: "${System.getProperty("user.home")}/.graalvm"
@@ -50,6 +95,11 @@ open class BuildInfo(project: Project) {
"https://download.oracle.com/graalvm/$jdkMajor/archive/$baseName.$extension" "https://download.oracle.com/graalvm/$jdkMajor/archive/$baseName.$extension"
} }
val downloadFile: File by lazy {
val extension = if (os.isWindows) "zip" else "tar.gz"
File(homeDir, "${baseName}.$extension")
}
val installDir: File by lazy { File(homeDir, baseName) } val installDir: File by lazy { File(homeDir, baseName) }
val baseDir: String by lazy { val baseDir: String by lazy {
@@ -75,6 +125,220 @@ open class BuildInfo(project: Project) {
val isReleaseBuild: Boolean by lazy { java.lang.Boolean.getBoolean("releaseBuild") } val isReleaseBuild: Boolean by lazy { java.lang.Boolean.getBoolean("releaseBuild") }
val isNativeArch: Boolean by lazy { java.lang.Boolean.getBoolean("nativeArch") }
val jvmTarget: Int by lazy {
System.getProperty("pklJvmTarget")?.toInt() ?: PKL_JVM_TARGET_DEFAULT_MAXIMUM
}
// JPMS exports for Truffle; needed on some versions of Java, and transitively within some JARs.
private val jpmsExports =
arrayOf(
"org.graalvm.truffle/com.oracle.truffle.api.exception=ALL-UNNAMED",
"org.graalvm.truffle/com.oracle.truffle.api=ALL-UNNAMED",
"org.graalvm.truffle/com.oracle.truffle.api.nodes=ALL-UNNAMED",
"org.graalvm.truffle/com.oracle.truffle.api.source=ALL-UNNAMED",
)
// Extra JPMS modules forced onto the module path via `--add-modules` in some cases.
private val jpmsAddModules = arrayOf("jdk.unsupported")
// Formats `jpmsExports` for use in JAR manifest attributes.
val jpmsExportsForJarManifest: String by lazy {
jpmsExports.joinToString(" ") { it.substringBefore("=") }
}
// Formats `jpmsExports` for use on the command line with `--add-exports`.
val jpmsExportsForAddExportsFlags: Collection<String> by lazy {
jpmsExports.map { "--add-exports=$it" }
}
// Formats `jpmsAddModules` for use on the command line with `--add-modules`.
val jpmsAddModulesFlags: Collection<String> by lazy { jpmsAddModules.map { "--add-modules=$it" } }
// JVM properties to set during testing.
val testProperties =
mapOf<String, Any>(
// @TODO: this should be removed once pkl supports JPMS as a true Java Module.
"polyglotimpl.DisableClassPathIsolation" to true
)
val jdkVendor: JvmVendorSpec = JvmVendorSpec.ADOPTIUM
val jdkToolchainVersion: JavaLanguageVersion by lazy {
JavaLanguageVersion.of(System.getProperty("pklJdkToolchain")?.toInt() ?: PKL_JDK_VERSION_MIN)
}
val jdkTestFloor: JavaLanguageVersion by lazy { JavaLanguageVersion.of(PKL_TEST_JDK_MINIMUM) }
val jdkTestCeiling: JavaLanguageVersion by lazy { JavaLanguageVersion.of(PKL_TEST_JDK_MAXIMUM) }
val testAllJdks: Boolean by lazy {
// By default, Pkl is tested against LTS JDK releases within the bounds of `PKL_TEST_JDK_TARGET`
// and `PKL_TEST_JDK_MAXIMUM`. To test against the full suite of JDK versions, past and present,
// set `-DpklTestAllJdks=true` on the Gradle command line. This results in non-LTS releases, old
// releases, and "experimental releases" (newer than the toolchain version) being included in
// the default `check` suite.
System.getProperty("pklTestAllJdks")?.toBoolean() ?: PKL_TEST_ALL_JDKS
}
val testExperimentalJdks: Boolean by lazy {
System.getProperty("pklTestFutureJdks")?.toBoolean() ?: false
}
val testJdkVendors: Sequence<JvmVendorSpec> by lazy {
// By default, only OpenJDK is tested during multi-JDK testing. Flip `-DpklTestAllVendors=true`
// to additionally test against a suite of JDK vendors, including Azul, Oracle, and GraalVM.
when (System.getProperty("pklTestAllVendors")?.toBoolean()) {
true -> sequenceOf(JvmVendorSpec.ADOPTIUM, JvmVendorSpec.GRAAL_VM, JvmVendorSpec.ORACLE)
else -> sequenceOf(JvmVendorSpec.ADOPTIUM)
}
}
// Assembles a collection of JDK versions which tests can be run against, considering ancillary
// parameters like `testAllJdks` and `testExperimentalJdks`.
val jdkTestRange: Collection<JavaLanguageVersion> by lazy {
JavaVersionRange.inclusive(jdkTestFloor, jdkTestCeiling).filter { version ->
// unless we are instructed to test all JDKs, tests only include LTS releases and
// versions above the toolchain version.
testAllJdks || (JavaVersionRange.isLTS(version) || version >= jdkToolchainVersion)
}
}
private fun JavaToolchainSpec.pklJdkToolchain() {
languageVersion.set(jdkToolchainVersion)
vendor.set(jdkVendor)
}
private fun labelForVendor(vendor: JvmVendorSpec): String =
when (vendor) {
JvmVendorSpec.AZUL -> "Zulu"
JvmVendorSpec.GRAAL_VM -> "GraalVm"
JvmVendorSpec.ORACLE -> "Oracle"
JvmVendorSpec.ADOPTIUM -> "Adoptium"
else -> error("Unrecognized JDK vendor: $vendor")
}
private fun testNamer(baseName: () -> String): (JavaLanguageVersion, JvmVendorSpec?) -> String =
{ jdkTarget, vendor ->
val targetToken =
when (vendor) {
null -> "Jdk${jdkTarget.asInt()}"
else -> "Jdk${jdkTarget.asInt()}${labelForVendor(vendor).capitalized()}"
}
if (jdkTarget > jdkToolchainVersion) {
// test targets above the toolchain target are considered "experimental".
"${baseName()}${targetToken}Experimental"
} else {
"${baseName()}${targetToken}"
}
}
@Suppress("UnstableApiUsage")
fun multiJdkTestingWith(
templateTask: TaskProvider<out Test>,
configurator: MultiJdkTestConfigurator = {},
): Iterable<Provider<out Any>> =
with(project) {
// force the `jvm-test-suite` plugin to apply first
project.pluginManager.apply(JvmTestSuitePlugin::class.java)
val isMultiVendor = testJdkVendors.count() > 1
val baseNameProvider = { templateTask.get().name }
val namer = testNamer(baseNameProvider)
val applyConfig: MultiJdkTestConfigurator = { (version, jdk) ->
// 1) copy configurations from the template task
dependsOn(templateTask)
templateTask.get().let { template ->
classpath = template.classpath
testClassesDirs = template.testClassesDirs
jvmArgs.addAll(template.jvmArgs)
jvmArgumentProviders.addAll(template.jvmArgumentProviders)
forkEvery = template.forkEvery
maxParallelForks = template.maxParallelForks
minHeapSize = template.minHeapSize
maxHeapSize = template.maxHeapSize
exclude(template.excludes)
template.systemProperties.forEach { prop -> systemProperty(prop.key, prop.value) }
}
// 2) assign launcher
javaLauncher = jdk
// 3) dispatch the user's configurator
configurator(version to jdk)
}
serviceOf<JavaToolchainService>().let { toolchains ->
jdkTestRange
.flatMap { targetVersion ->
// multiply out by jdk vendor
testJdkVendors.map { vendor -> (targetVersion to vendor) }
}
.filter { (jdkTarget, vendor) ->
// only include experimental tasks in the return suite if the flag is set. if the task
// is withheld from the returned list, it will not be executed by default with `gradle
// check`.
testExperimentalJdks ||
(!namer(jdkTarget, vendor.takeIf { isMultiVendor }).contains("Experimental"))
}
.map { (jdkTarget, vendor) ->
if (jdkToolchainVersion == jdkTarget)
tasks.register(namer(jdkTarget, vendor)) {
// alias to `test`
dependsOn(templateTask)
group = Category.VERIFICATION
description =
"Alias for regular '${baseNameProvider()}' task, on JDK ${jdkTarget.asInt()}"
}
else
the<TestingExtension>().suites.register(
namer(jdkTarget, vendor.takeIf { isMultiVendor }),
JvmTestSuite::class,
) {
targets.all {
testTask.configure {
group = Category.VERIFICATION
description = "Run tests against JDK ${jdkTarget.asInt()}"
applyConfig(jdkTarget to toolchains.launcherFor { languageVersion = jdkTarget })
// fix: on jdk17, we must force the polyglot module on to the modulepath
if (jdkTarget.asInt() == 17)
jvmArgumentProviders.add(
CommandLineArgumentProvider {
buildList { listOf("--add-modules=org.graalvm.polyglot") }
}
)
}
}
}
}
.toList()
}
}
val javaCompiler: Provider<JavaCompiler> by lazy {
project.serviceOf<JavaToolchainService>().let { toolchainService ->
toolchainService.compilerFor { pklJdkToolchain() }
}
}
val javaTestLauncher: Provider<JavaLauncher> by lazy {
project.serviceOf<JavaToolchainService>().let { toolchainService ->
toolchainService.launcherFor { pklJdkToolchain() }
}
}
val multiJdkTesting: Boolean by lazy {
// By default, Pkl is tested against a full range of JDK versions, past and present, within the
// supported bounds of `PKL_TEST_JDK_TARGET` and `PKL_TEST_JDK_MAXIMUM`. To opt-out of this
// behavior, set `-DpklMultiJdkTesting=false` on the Gradle command line.
//
// In CI, this defaults to `true` to catch potential cross-JDK compat regressions or other bugs.
// In local dev, this defaults to `false` to speed up the build and reduce contributor load.
System.getProperty("pklMultiJdkTesting")?.toBoolean() ?: isCiBuild
}
val hasMuslToolchain: Boolean by lazy { val hasMuslToolchain: Boolean by lazy {
// see "install musl" in .circleci/jobs/BuildNativeJob.pkl // see "install musl" in .circleci/jobs/BuildNativeJob.pkl
File(System.getProperty("user.home"), "staticdeps/bin/x86_64-linux-musl-gcc").exists() File(System.getProperty("user.home"), "staticdeps/bin/x86_64-linux-musl-gcc").exists()
@@ -86,6 +350,8 @@ open class BuildInfo(project: Project) {
// could be `commitId: Provider<String> = project.provider { ... }` // could be `commitId: Provider<String> = project.provider { ... }`
val commitId: String by lazy { val commitId: String by lazy {
// allow -DcommitId=abc123 for build environments that don't have git.
System.getProperty("commitId").let { if (it != null) return@lazy it }
// only run command once per build invocation // only run command once per build invocation
if (project === project.rootProject) { if (project === project.rootProject) {
val process = val process =
@@ -131,3 +397,7 @@ open class BuildInfo(project: Project) {
} }
} }
} }
// Shape of a function which is applied to configure multi-JDK testing.
private typealias MultiJdkTestConfigurator =
Test.(Pair<JavaLanguageVersion, Provider<JavaLauncher>>) -> Unit
+22 -8
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -22,12 +22,11 @@ import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
/** /**
* Builds a self-contained Pkl CLI Jar that is directly executable on *nix and executable with `java * Builds a self-contained Pkl CLI Jar that is directly executable on Windows, macOS, and Linux.
* -jar` on Windows.
* *
* For direct execution, the `java` command must be on the PATH. * For direct execution, the `java` command must be on the PATH.
* *
* https://skife.org/java/unix/2011/06/20/really_executable_jars.html * Technique borrowed from [Mill](https://mill-build.org/blog/5-executable-jars.html).
*/ */
abstract class ExecutableJar : DefaultTask() { abstract class ExecutableJar : DefaultTask() {
@get:InputFile abstract val inJar: RegularFileProperty @get:InputFile abstract val inJar: RegularFileProperty
@@ -41,12 +40,27 @@ abstract class ExecutableJar : DefaultTask() {
val inFile = inJar.get().asFile val inFile = inJar.get().asFile
val outFile = outJar.get().asFile val outFile = outJar.get().asFile
val escapedJvmArgs = jvmArgs.get().joinToString(separator = " ") { "\"$it\"" } val escapedJvmArgs = jvmArgs.get().joinToString(separator = " ") { "\"$it\"" }
val startScript = val unixStartScript =
""" """
#!/bin/sh @ 2>/dev/null # 2>nul & echo off & goto BOF
exec java $escapedJvmArgs -jar $0 "$@" :
exec java $escapedJvmArgs -jar "$0" "$@"
exit
""" """
.trimIndent() + "\n\n\n" .trimIndent()
val windowsStartScript =
"""
:BOF
setlocal
@echo off
java $escapedJvmArgs -jar "%~dpnx0" %*
endlocal
exit /B %errorlevel%
"""
.trimIndent()
// need crlf endings for Windows portion of script
.replace("\n", "\r\n")
val startScript = unixStartScript + "\r\n" + windowsStartScript + "\r\n".repeat(3)
outFile.outputStream().use { outStream -> outFile.outputStream().use { outStream ->
startScript.byteInputStream().use { it.copyTo(outStream) } startScript.byteInputStream().use { it.copyTo(outStream) }
inFile.inputStream().use { it.copyTo(outStream) } inFile.inputStream().use { it.copyTo(outStream) }
@@ -0,0 +1,91 @@
/*
* Copyright © 2024-2025 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.
*/
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
import java.util.*
import javax.inject.Inject
import kotlin.io.path.createDirectories
import org.gradle.api.DefaultTask
import org.gradle.api.internal.file.FileOperations
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import org.gradle.process.ExecOperations
abstract class InstallGraalVm
@Inject
constructor(
private val fileOperations: FileOperations,
private val execOperations: ExecOperations,
) : DefaultTask() {
@get:Input abstract val graalVm: Property<BuildInfo.GraalVm>
init {
@Suppress("LeakingThis") onlyIf("GraalVM not installed") { !graalVm.get().installDir.exists() }
}
@TaskAction
@Suppress("unused")
fun run() {
// minimize chance of corruption by extract-to-random-dir-and-flip-symlink
val distroDir = Paths.get(graalVm.get().homeDir, UUID.randomUUID().toString())
try {
distroDir.createDirectories()
println("Extracting ${graalVm.get().downloadFile} into $distroDir")
// faster and more reliable than Gradle's `copy { from tarTree() }`
execOperations.exec {
workingDir = distroDir.toFile()
executable = "tar"
args("--strip-components=1", "-xzf", graalVm.get().downloadFile)
}
val os = org.gradle.internal.os.OperatingSystem.current()
val distroBinDir =
if (os.isMacOsX) distroDir.resolve("Contents/Home/bin") else distroDir.resolve("bin")
println("Installing native-image into $distroDir")
val gvmVersionMajor =
requireNotNull(graalVm.get().version.split(".").first().toIntOrNull()) {
"Invalid GraalVM JDK version: ${graalVm.get().graalVmJdkVersion}"
}
if (gvmVersionMajor < 24) {
execOperations.exec {
val executableName = if (os.isWindows) "gu.cmd" else "gu"
executable = distroBinDir.resolve(executableName).toString()
args("install", "--no-progress", "native-image")
}
}
println("Creating symlink ${graalVm.get().installDir} for $distroDir")
val tempLink = Paths.get(graalVm.get().homeDir, UUID.randomUUID().toString())
Files.createSymbolicLink(tempLink, distroDir)
try {
Files.move(tempLink, graalVm.get().installDir.toPath(), StandardCopyOption.ATOMIC_MOVE)
} catch (e: Exception) {
try {
fileOperations.delete(tempLink.toFile())
} catch (ignored: Exception) {}
throw e
}
} catch (e: Exception) {
try {
fileOperations.delete(distroDir)
} catch (ignored: Exception) {}
throw e
}
}
}
@@ -0,0 +1,64 @@
/*
* Copyright © 2024-2025 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.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
import java.util.*
import org.gradle.jvm.toolchain.JavaLanguageVersion
typealias JavaVersionPair = Pair<JavaLanguageVersion, JavaLanguageVersion>
// All LTS releases.
private val ltsReleases =
sortedSetOf(
JavaLanguageVersion.of(8),
JavaLanguageVersion.of(11),
JavaLanguageVersion.of(17),
JavaLanguageVersion.of(21),
)
/** Describes an inclusive range of JVM versions, based on the [JavaLanguageVersion] type. */
@JvmInline
value class JavaVersionRange private constructor(private val bounds: JavaVersionPair) :
Iterable<JavaLanguageVersion> {
@Suppress("unused")
companion object {
fun isLTS(version: JavaLanguageVersion): Boolean = version in ltsReleases
fun inclusive(floor: JavaLanguageVersion, ceiling: JavaLanguageVersion): JavaVersionRange =
JavaVersionRange(floor to ceiling)
fun startingAt(floor: JavaLanguageVersion): JavaVersionRange =
inclusive(floor, JavaLanguageVersion.of(PKL_TEST_JDK_MAXIMUM))
fun upTo(ceiling: JavaLanguageVersion): JavaVersionRange =
inclusive(JavaLanguageVersion.of(PKL_TEST_JDK_MINIMUM), ceiling)
}
operator fun contains(version: JavaLanguageVersion): Boolean =
version >= bounds.first && version <= bounds.second
fun asSequence(): Sequence<JavaLanguageVersion> = sequence {
var current = bounds.first
while (current <= bounds.second) {
yield(current)
current = JavaLanguageVersion.of(current.asInt() + 1)
}
}
fun asSortedSet(): SortedSet<JavaLanguageVersion> = asSequence().toSortedSet()
override fun iterator(): Iterator<JavaLanguageVersion> = asSortedSet().iterator()
}
+2 -2
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -111,7 +111,7 @@ open class MergeSourcesJars : DefaultTask() {
relocatedPkgs: Map<String, String>, relocatedPkgs: Map<String, String>,
details: FileVisitDetails, details: FileVisitDetails,
sourceText: String, sourceText: String,
importPattern: Pattern importPattern: Pattern,
): String { ): String {
val matcher = importPattern.matcher(sourceText) val matcher = importPattern.matcher(sourceText)
val buffer = StringBuffer() val buffer = StringBuffer()
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/ */
import com.diffplug.gradle.spotless.KotlinGradleExtension import com.diffplug.gradle.spotless.KotlinGradleExtension
import org.gradle.accessors.dm.LibrariesForLibs import org.gradle.accessors.dm.LibrariesForLibs
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { id("com.diffplug.spotless") } plugins { id("com.diffplug.spotless") }
@@ -41,6 +42,15 @@ configurations {
} }
} }
configurations.all {
resolutionStrategy.eachDependency {
if (requested.group == "org.jetbrains.kotlin") {
// prevent transitive deps from bumping Koltin version
useVersion(libs.versions.kotlin.get())
}
}
}
plugins.withType(JavaPlugin::class).configureEach { plugins.withType(JavaPlugin::class).configureEach {
val java = project.extensions.getByType<JavaPluginExtension>() val java = project.extensions.getByType<JavaPluginExtension>()
java.sourceCompatibility = JavaVersion.VERSION_17 java.sourceCompatibility = JavaVersion.VERSION_17
@@ -48,9 +58,9 @@ plugins.withType(JavaPlugin::class).configureEach {
} }
tasks.withType<KotlinCompile>().configureEach { tasks.withType<KotlinCompile>().configureEach {
kotlinOptions { compilerOptions {
jvmTarget = "17" jvmTarget = JvmTarget.JVM_17
freeCompilerArgs = freeCompilerArgs + listOf("-Xjsr305=strict", "-Xjvm-default=all") freeCompilerArgs.addAll("-Xjsr305=strict", "-Xjvm-default=all")
} }
} }
@@ -132,7 +142,11 @@ private fun KotlinGradleExtension.configureFormatter() {
licenseHeaderFile(licenseHeaderFile, "([a-zA-Z]|@file|//)") licenseHeaderFile(licenseHeaderFile, "([a-zA-Z]|@file|//)")
} }
val originalRemoteName = System.getenv("PKL_ORIGINAL_REMOTE_NAME") ?: "origin"
spotless { spotless {
ratchetFrom = "$originalRemoteName/main"
// When building root project, format buildSrc files too. // When building root project, format buildSrc files too.
// We need this because buildSrc is not a subproject of the root project, so a top-level // We need this because buildSrc is not a subproject of the root project, so a top-level
// `spotlessApply` will not trigger `buildSrc:spotlessApply`. // `spotlessApply` will not trigger `buildSrc:spotlessApply`.
+26 -7
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -39,9 +39,6 @@ val firstPartySourcesJarsConfiguration: Configuration =
val relocations = val relocations =
mapOf( mapOf(
// pkl-core dependencies // pkl-core dependencies
"org.antlr.v4." to "org.pkl.thirdparty.antlr.v4.",
"com.oracle.truffle" to "org.pkl.thirdparty.truffle",
"org.graalvm." to "org.pkl.thirdparty.graalvm.",
"org.organicdesign.fp." to "org.pkl.thirdparty.paguro.", "org.organicdesign.fp." to "org.pkl.thirdparty.paguro.",
"org.snakeyaml.engine." to "org.pkl.thirdparty.snakeyaml.engine.", "org.snakeyaml.engine." to "org.pkl.thirdparty.snakeyaml.engine.",
"org.msgpack." to "org.pkl.thirdparty.msgpack.", "org.msgpack." to "org.pkl.thirdparty.msgpack.",
@@ -51,6 +48,9 @@ val relocations =
// pkl-cli dependencies // pkl-cli dependencies
"org.jline." to "org.pkl.thirdparty.jline.", "org.jline." to "org.pkl.thirdparty.jline.",
"com.github.ajalt.clikt." to "org.pkl.thirdparty.clikt.", "com.github.ajalt.clikt." to "org.pkl.thirdparty.clikt.",
"com.github.ajalt.colormath" to "org.pkl.thirdparty.colormath.",
"com.github.ajalt.mordant" to "org.pkl.thirdparty.mordant",
"com.sun.jna" to "org.pkl.thirdparty.jna",
"kotlin." to "org.pkl.thirdparty.kotlin.", "kotlin." to "org.pkl.thirdparty.kotlin.",
"kotlinx." to "org.pkl.thirdparty.kotlinx.", "kotlinx." to "org.pkl.thirdparty.kotlinx.",
"org.intellij." to "org.pkl.thirdparty.intellij.", "org.intellij." to "org.pkl.thirdparty.intellij.",
@@ -65,13 +65,13 @@ val relocations =
"io.leangen.geantyref." to "org.pkl.thirdparty.geantyref.", "io.leangen.geantyref." to "org.pkl.thirdparty.geantyref.",
// pkl-codegen-java dependencies // pkl-codegen-java dependencies
"com.squareup.javapoet." to "org.pkl.thirdparty.javapoet.", "com.palantir.javapoet." to "org.pkl.thirdparty.javapoet.",
// pkl-codegen-kotlin dependencies // pkl-codegen-kotlin dependencies
"com.squareup.kotlinpoet." to "org.pkl.thirdparty.kotlinpoet.", "com.squareup.kotlinpoet." to "org.pkl.thirdparty.kotlinpoet.",
) )
val nonRelocations = listOf("com/oracle/truffle/") val nonRelocations = listOf("com/oracle/truffle/", "org/graalvm/")
tasks.shadowJar { tasks.shadowJar {
inputs.property("relocations", relocations) inputs.property("relocations", relocations)
@@ -80,9 +80,28 @@ tasks.shadowJar {
configurations = listOf(project.configurations.runtimeClasspath.get()) configurations = listOf(project.configurations.runtimeClasspath.get())
// not required at runtime / fat JARs can't be used in native-image builds anyway
exclude("org/pkl/cli/svm/**")
exclude("META-INF/maven/**") exclude("META-INF/maven/**")
exclude("META-INF/upgrade/**") exclude("META-INF/upgrade/**")
exclude("META-INF/versions/19/**")
val info = project.extensions.getByType<BuildInfo>()
val minimumJvmTarget = JavaVersion.toVersion(info.jvmTarget)
manifest.attributes(
// Certain exports need to be added to the Java modulepath for Java 17 to work properly with
// shaded JARs. See the following link for an explanation of this syntax:
// https://bugs.openjdk.org/browse/JDK-8335225
"Add-Exports" to info.jpmsExportsForJarManifest
)
// effectively, this results in calls excluding:
// `META-INF/versions/{18-25}/**`
// at the time of this writing; multi-release JARs beyond JDK 21 break the current
// version of the Shadow plugin, and aren't needed for Truffle's use by Pkl.
JavaVersionRange.startingAt(JavaLanguageVersion.of(minimumJvmTarget.majorVersion.toInt() + 1))
.forEach { exclude("META-INF/versions/${it.asInt()}/**") }
// org.antlr.v4.runtime.misc.RuleDependencyProcessor // org.antlr.v4.runtime.misc.RuleDependencyProcessor
exclude("META-INF/services/javax.annotation.processing.Processor") exclude("META-INF/services/javax.annotation.processing.Processor")
+6 -62
View File
@@ -15,20 +15,11 @@
*/ */
import de.undercouch.gradle.tasks.download.Download import de.undercouch.gradle.tasks.download.Download
import de.undercouch.gradle.tasks.download.Verify import de.undercouch.gradle.tasks.download.Verify
import java.nio.file.*
import java.util.UUID
import kotlin.io.path.createDirectories
plugins { id("de.undercouch.download") } plugins { id("de.undercouch.download") }
val buildInfo = project.extensions.getByType<BuildInfo>() val buildInfo = project.extensions.getByType<BuildInfo>()
val BuildInfo.GraalVm.downloadFile
get(): File {
val extension = if (buildInfo.os.isWindows) "zip" else "tar.gz"
return file(homeDir).resolve("${baseName}.$extension")
}
// tries to minimize chance of corruption by download-to-temp-file-and-move // tries to minimize chance of corruption by download-to-temp-file-and-move
val downloadGraalVmAarch64 by val downloadGraalVmAarch64 by
tasks.registering(Download::class) { configureDownloadGraalVm(buildInfo.graalVmAarch64) } tasks.registering(Download::class) { configureDownloadGraalVm(buildInfo.graalVmAarch64) }
@@ -68,63 +59,16 @@ fun Verify.configureVerifyGraalVm(graalvm: BuildInfo.GraalVm) {
algorithm("SHA-256") algorithm("SHA-256")
} }
// minimize chance of corruption by extract-to-random-dir-and-flip-symlink @Suppress("unused")
val installGraalVmAarch64 by val installGraalVmAarch64 by
tasks.registering { tasks.registering(InstallGraalVm::class) {
dependsOn(verifyGraalVmAarch64) dependsOn(verifyGraalVmAarch64)
configureInstallGraalVm(buildInfo.graalVmAarch64) graalVm = buildInfo.graalVmAarch64
} }
// minimize chance of corruption by extract-to-random-dir-and-flip-symlink @Suppress("unused")
val installGraalVmAmd64 by val installGraalVmAmd64 by
tasks.registering { tasks.registering(InstallGraalVm::class) {
dependsOn(verifyGraalVmAmd64) dependsOn(verifyGraalVmAmd64)
configureInstallGraalVm(buildInfo.graalVmAmd64) graalVm = buildInfo.graalVmAmd64
}
fun Task.configureInstallGraalVm(graalVm: BuildInfo.GraalVm) {
onlyIf { !graalVm.installDir.exists() }
doLast {
val distroDir = Paths.get(graalVm.homeDir, UUID.randomUUID().toString())
try {
distroDir.createDirectories()
println("Extracting ${graalVm.downloadFile} into $distroDir")
// faster and more reliable than Gradle's `copy { from tarTree() }`
exec {
workingDir = file(distroDir)
executable = "tar"
args("--strip-components=1", "-xzf", graalVm.downloadFile)
}
val distroBinDir =
if (buildInfo.os.isMacOsX) distroDir.resolve("Contents/Home/bin")
else distroDir.resolve("bin")
println("Installing native-image into $distroDir")
exec {
val executableName = if (buildInfo.os.isWindows) "gu.cmd" else "gu"
executable = distroBinDir.resolve(executableName).toString()
args("install", "--no-progress", "native-image")
}
println("Creating symlink ${graalVm.installDir} for $distroDir")
val tempLink = Paths.get(graalVm.homeDir, UUID.randomUUID().toString())
Files.createSymbolicLink(tempLink, distroDir)
try {
Files.move(tempLink, graalVm.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
}
}
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,20 +27,23 @@ tasks.addRule("Pattern: compatibilityTest[All|Releases|Latest|Candidate|Nightly|
dependsOn( dependsOn(
"compatibilityTestReleases", "compatibilityTestReleases",
"compatibilityTestCandidate", "compatibilityTestCandidate",
"compatibilityTestNightly" "compatibilityTestNightly",
) )
} }
// releases in configured range // releases in configured range
"Releases" -> "Releases" ->
task("compatibilityTestReleases") { task("compatibilityTestReleases") {
val versionInfos = GradleVersionInfo.fetchReleases() val versionInfos = GradleVersionInfo.fetchReleases()
val versionsToTestAgainst = val allVersions =
versionInfos.filter { versionInfo -> versionInfos
.filter { versionInfo ->
val v = versionInfo.gradleVersion val v = versionInfo.gradleVersion
!versionInfo.broken && !versionInfo.broken &&
v in gradlePluginTests.minGradleVersion..gradlePluginTests.maxGradleVersion && v in gradlePluginTests.minGradleVersion..gradlePluginTests.maxGradleVersion &&
v !in gradlePluginTests.skippedGradleVersions v !in gradlePluginTests.skippedGradleVersions
} }
.sortedBy { it.gradleVersion }
val versionsToTestAgainst = listOf(allVersions.first(), allVersions.last())
dependsOn(versionsToTestAgainst.map { createCompatibilityTestTask(it) }) dependsOn(versionsToTestAgainst.map { createCompatibilityTestTask(it) })
} }
@@ -79,16 +82,16 @@ tasks.addRule("Pattern: compatibilityTest[All|Releases|Latest|Candidate|Nightly|
else -> else ->
createCompatibilityTestTask( createCompatibilityTestTask(
taskNameSuffix, taskNameSuffix,
"https://services.gradle.org/distributions-snapshots/gradle-$taskNameSuffix-bin.zip" "https://services.gradle.org/distributions-snapshots/gradle-$taskNameSuffix-bin.zip",
) )
} }
} }
fun createCompatibilityTestTask(versionInfo: GradleVersionInfo): Task = fun createCompatibilityTestTask(versionInfo: GradleVersionInfo): TaskProvider<Test> =
createCompatibilityTestTask(versionInfo.version, versionInfo.downloadUrl) createCompatibilityTestTask(versionInfo.version, versionInfo.downloadUrl)
fun createCompatibilityTestTask(version: String, downloadUrl: String): Task { fun createCompatibilityTestTask(version: String, downloadUrl: String): TaskProvider<Test> {
return tasks.create("compatibilityTest$version", Test::class.java) { return tasks.register("compatibilityTest$version", Test::class.java) {
mustRunAfter(tasks.test) mustRunAfter(tasks.test)
maxHeapSize = tasks.test.get().maxHeapSize maxHeapSize = tasks.test.get().maxHeapSize
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,25 +13,39 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
@file:Suppress("HttpUrlsUsage") @file:Suppress("HttpUrlsUsage", "unused")
import org.gradle.accessors.dm.LibrariesForLibs import org.gradle.accessors.dm.LibrariesForLibs
plugins { plugins {
`java-library` `java-library`
`jvm-toolchains`
id("pklKotlinTest") id("pklKotlinTest")
id("com.diffplug.spotless") id("com.diffplug.spotless")
} }
// make sources Jar available to other subprojects // make sources Jar available to other subprojects
val sourcesJarConfiguration = configurations.register("sourcesJar") val sourcesJarConfiguration: Provider<Configuration> = configurations.register("sourcesJar")
// Version Catalog library symbols. // Version Catalog library symbols.
val libs = the<LibrariesForLibs>() val libs = the<LibrariesForLibs>()
// Build configuration.
val info = project.extensions.getByType<BuildInfo>()
java { java {
val jvmTarget = JavaVersion.toVersion(info.jvmTarget)
withSourcesJar() // creates `sourcesJar` task withSourcesJar() // creates `sourcesJar` task
withJavadocJar() withJavadocJar()
sourceCompatibility = jvmTarget
targetCompatibility = jvmTarget
toolchain {
languageVersion = info.jdkToolchainVersion
vendor = info.jdkVendor
}
} }
artifacts { artifacts {
@@ -56,7 +70,11 @@ tasks.compileKotlin { enabled = false }
tasks.jar { tasks.jar {
manifest { manifest {
attributes += mapOf("Automatic-Module-Name" to "org.${project.name.replace("-", ".")}") attributes +=
mapOf(
"Automatic-Module-Name" to "org.${project.name.replace("-", ".")}",
"Add-Exports" to info.jpmsExportsForJarManifest,
)
} }
} }
@@ -80,9 +98,48 @@ val workAroundKotlinGradlePluginBug by
} }
} }
tasks.compileJava { val truffleJavacArgs =
dependsOn(workAroundKotlinGradlePluginBug) listOf(
// TODO: determine correct limits for Truffle specializations // TODO: determine correct limits for Truffle specializations
// (see https://graalvm.slack.com/archives/CNQSB2DHD/p1712380902746829) // (see https://graalvm.slack.com/archives/CNQSB2DHD/p1712380902746829)
options.compilerArgs.add("-Atruffle.dsl.SuppressWarnings=truffle-limit") "-Atruffle.dsl.SuppressWarnings=truffle-limit"
)
tasks.compileJava {
javaCompiler = info.javaCompiler
dependsOn(workAroundKotlinGradlePluginBug)
options.compilerArgs.addAll(truffleJavacArgs + info.jpmsAddModulesFlags)
} }
tasks.withType<JavaCompile>().configureEach {
val jvmTarget = JavaVersion.toVersion(info.jvmTarget)
javaCompiler = info.javaCompiler
sourceCompatibility = jvmTarget.majorVersion
targetCompatibility = jvmTarget.majorVersion
}
tasks.withType<JavaExec>().configureEach { jvmArgs(info.jpmsAddModulesFlags) }
fun Test.configureJdkTestTask(launcher: Provider<JavaLauncher>) {
useJUnitPlatform()
javaLauncher = launcher
systemProperties.putAll(info.testProperties)
jvmArgs.addAll(info.jpmsAddModulesFlags)
}
tasks.test { configureJdkTestTask(info.javaTestLauncher) }
// Prepare test tasks for each JDK version which is within the test target suite for Pkl. Each task
// uses a pinned JDK toolchain version, and is named for the major version which is tested.
//
// Test tasks configured in this manner are executed manually by name, e.g. `./gradlew testJdk11`,
// and automatically as dependencies of `check`.
//
// We omit the current JDK from this list because it is already tested, in effect, by the default
// `test` task.
//
// Pkl subprojects may elect to further configure these tasks as needed; by default, each task
// inherits the configuration of the default `test` task (aside from an overridden launcher).
val jdkTestTasks = info.multiJdkTestingWith(tasks.test) { (_, jdk) -> configureJdkTestTask(jdk) }
if (info.multiJdkTesting) tasks.check { dependsOn(jdkTestTasks) }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -14,13 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */
import org.gradle.accessors.dm.LibrariesForLibs import org.gradle.accessors.dm.LibrariesForLibs
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
plugins { plugins {
id("pklJavaLibrary") id("pklJavaLibrary")
kotlin("jvm") kotlin("jvm")
} }
// Build configuration.
val buildInfo = project.extensions.getByType<BuildInfo>() val buildInfo = project.extensions.getByType<BuildInfo>()
// Version Catalog library symbols. // Version Catalog library symbols.
@@ -38,3 +40,7 @@ dependencies {
tasks.compileKotlin { tasks.compileKotlin {
enabled = true // disabled by pklJavaLibrary enabled = true // disabled by pklJavaLibrary
} }
tasks.withType<KotlinJvmCompile>().configureEach {
compilerOptions { jvmTarget = JvmTarget.fromTarget(buildInfo.jvmTarget.toString()) }
}
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,7 +16,10 @@
import java.net.URI import java.net.URI
import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestExceptionFormat
plugins { kotlin("jvm") } plugins {
`jvm-test-suite`
kotlin("jvm")
}
val buildInfo = project.extensions.getByType<BuildInfo>() val buildInfo = project.extensions.getByType<BuildInfo>()
@@ -1,5 +1,5 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. // Copyright © $YEAR Apple Inc. and the Pkl project authors. All rights reserved.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © $YEAR Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+1 -1
View File
@@ -1,6 +1,6 @@
name: main name: main
title: Main Project title: Main Project
version: 0.27.1 version: 0.28.0
prerelease: false prerelease: false
nav: nav:
- nav.adoc - nav.adoc
+36 -27
View File
@@ -3,35 +3,44 @@
# This file is expected to be part of source control. # This file is expected to be part of source control.
com.tunnelvisionlabs:antlr4-runtime:4.9.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.tunnelvisionlabs:antlr4-runtime:4.9.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
net.bytebuddy:byte-buddy:1.14.18=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.6.0=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata
org.assertj:assertj-core:3.26.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:23.0.6=testRuntimeClasspath org.graalvm.polyglot:polyglot:24.1.2=testRuntimeClasspath
org.graalvm.truffle:truffle-api:23.0.6=testRuntimeClasspath org.graalvm.sdk:collections:24.1.2=testRuntimeClasspath
org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.sdk:graal-sdk:24.1.2=testRuntimeClasspath
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.sdk:nativeimage:24.1.2=testRuntimeClasspath
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.sdk:word:24.1.2=testRuntimeClasspath
org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.7.10=kotlinKlibCommonizerClasspath org.graalvm.truffle:truffle-api:24.1.2=testRuntimeClasspath
org.jetbrains.kotlin:kotlin-reflect:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,testRuntimeClasspath org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-script-runtime:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-common:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-build-tools-impl:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-jvm:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.0.21=kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-stdlib:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-native-prebuilt:2.0.21=kotlinNativeBundleConfiguration
org.jetbrains:annotations:13.0=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-script-runtime:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath
org.junit.jupiter:junit-jupiter-engine:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-scripting-common:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.junit.jupiter:junit-jupiter-params:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.junit.platform:junit-platform-commons:1.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.junit.platform:junit-platform-engine:1.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-scripting-jvm:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.junit:junit-bom:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.21=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-engine:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-params:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-engine:1.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit:junit-bom:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.msgpack:msgpack-core:0.9.8=testRuntimeClasspath org.msgpack:msgpack-core:0.9.8=testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.organicdesign:Paguro:3.10.3=testRuntimeClasspath org.organicdesign:Paguro:3.10.3=testRuntimeClasspath
org.snakeyaml:snakeyaml-engine:2.5=testRuntimeClasspath org.snakeyaml:snakeyaml-engine:2.9=testRuntimeClasspath
empty=annotationProcessor,apiDependenciesMetadata,compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtimeClasspath,runtimeOnlyDependenciesMetadata,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions empty=annotationProcessor,apiDependenciesMetadata,compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtimeClasspath,runtimeOnlyDependenciesMetadata,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions
@@ -0,0 +1,20 @@
= Evolution and Roadmap
:uri-pkl-roadmap: https://github.com/orgs/apple/projects/12/views/1
:uri-pkl-evolution: https://github.com/apple/pkl-evolution
== Evolution
Sometimes, a change to Pkl is large enough that it makes sense to create a proposal for the change so that it can be discussed in detail and vetted.
Pkl has a process for managing such designs in a repository called {uri-pkl-evolution}[Pkl Evolutiuon].
== Roadmap
To discover what might be coming in future versions, reference the {uri-pkl-roadmap}[Pkl Roadmap] project on GitHub.
The roadmap describes estimates.
The Pkl team aims to cut a release in February, June, and October of each year.
If an item is not complete by the release cutoff date, the roadmap item may be bumped to the next release.
Additionally, as priorities change, it is possible that items can be moved around, or backlogged.
@@ -3,7 +3,7 @@
// 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.27.1 :pkl-version-no-suffix: 0.28.0
// 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: ''
@@ -71,6 +71,7 @@ endif::[]
:uri-stdlib-analyzeModule: {uri-pkl-stdlib-docs}/analyze :uri-stdlib-analyzeModule: {uri-pkl-stdlib-docs}/analyze
:uri-stdlib-jsonnetModule: {uri-pkl-stdlib-docs}/jsonnet :uri-stdlib-jsonnetModule: {uri-pkl-stdlib-docs}/jsonnet
:uri-stdlib-reflectModule: {uri-pkl-stdlib-docs}/reflect :uri-stdlib-reflectModule: {uri-pkl-stdlib-docs}/reflect
:uri-stdlib-mathModule: {uri-pkl-stdlib-docs}/math
:uri-stdlib-xmlModule: {uri-pkl-stdlib-docs}/xml :uri-stdlib-xmlModule: {uri-pkl-stdlib-docs}/xml
:uri-stdlib-protobufModule: {uri-pkl-stdlib-docs}/protobuf :uri-stdlib-protobufModule: {uri-pkl-stdlib-docs}/protobuf
:uri-stdlib-evaluatorSettingsModule: {uri-pkl-stdlib-docs}/EvaluatorSettings :uri-stdlib-evaluatorSettingsModule: {uri-pkl-stdlib-docs}/EvaluatorSettings
@@ -142,3 +143,5 @@ endif::[]
:uri-messagepack: https://msgpack.org/index.html :uri-messagepack: https://msgpack.org/index.html
:uri-messagepack-spec: https://github.com/msgpack/msgpack/blob/master/spec.md :uri-messagepack-spec: https://github.com/msgpack/msgpack/blob/master/spec.md
:uri-pkl-roadmap: https://github.com/orgs/apple/projects/12/views/1
@@ -75,7 +75,7 @@ requestId: Int
/// API version of the CLI's `--allowed-modules` flag /// API version of the CLI's `--allowed-modules` flag
allowedModules: Listing<String>? allowedModules: Listing<String>?
/// Regex patterns to dettermine which resources are allowed to be read. /// Regex patterns to determine which resources are allowed to be read.
/// ///
/// API version of the CLI's `--allowed-resources` flag /// API version of the CLI's `--allowed-resources` flag
allowedResources: Listing<String>? allowedResources: Listing<String>?
@@ -130,7 +130,7 @@ class ClientResourceReader {
/// The URI scheme this reader is responsible for reading. /// The URI scheme this reader is responsible for reading.
scheme: String scheme: String
/// Tells whether the path part of ths URI has a /// Tells whether the path part of this URI has a
/// [hier-part](https://datatracker.ietf.org/doc/html/rfc3986#section-3). /// [hier-part](https://datatracker.ietf.org/doc/html/rfc3986#section-3).
/// ///
/// An example of a hierarchical URI is `file:///path/to/my/file`, where /// An example of a hierarchical URI is `file:///path/to/my/file`, where
@@ -148,7 +148,7 @@ class ClientModuleReader {
/// The URI scheme this reader is responsible for reading. /// The URI scheme this reader is responsible for reading.
scheme: String scheme: String
/// Tells whether the path part of ths URI has a /// Tells whether the path part of this URI has a
/// [hier-part](https://datatracker.ietf.org/doc/html/rfc3986#section-3). /// [hier-part](https://datatracker.ietf.org/doc/html/rfc3986#section-3).
/// ///
/// An example of a hierarchical URI is `file:///path/to/my/file`, where /// An example of a hierarchical URI is `file:///path/to/my/file`, where
@@ -427,7 +427,7 @@ evaluatorId: Int
/// The contents of the resource. /// The contents of the resource.
contents: Binary? // <1> contents: Binary? // <1>
/// The description of the error that occured when reading this resource. /// The description of the error that occurred when reading this resource.
error: String? error: String?
typealias Binary = Any // <1> typealias Binary = Any // <1>
@@ -478,7 +478,7 @@ evaluatorId: Int
/// The string contents of the module. /// The string contents of the module.
contents: String? contents: String?
/// The description of the error that occured when reading this resource. /// The description of the error that occurred when reading this resource.
error: String? error: String?
---- ----
@@ -528,7 +528,7 @@ evaluatorId: Int
/// The elements at the provided base path. /// The elements at the provided base path.
pathElements: Listing<PathElement>? pathElements: Listing<PathElement>?
/// The description of the error that occured when listing elements. /// The description of the error that occurred when listing elements.
error: String? error: String?
class PathElement { class PathElement {
@@ -586,7 +586,7 @@ evaluatorId: Int
/// The elements at the provided base path. /// The elements at the provided base path.
pathElements: Listing<PathElement>? pathElements: Listing<PathElement>?
/// The description of the error that occured when listing elements. /// The description of the error that occurred when listing elements.
error: String? error: String?
class PathElement { class PathElement {
+12 -8
View File
@@ -1,6 +1,6 @@
= Java Code Generator = Java Code Generator
include::ROOT:partial$component-attributes.adoc[] include::ROOT:partial$component-attributes.adoc[]
:uri-pkl-codgen-java-maven-module: {uri-maven-docsite}/artifact/org.pkl-lang/pkl-codegen-java :uri-pkl-codegen-java-maven-module: {uri-maven-docsite}/artifact/org.pkl-lang/pkl-codegen-java
The Java source code generator takes Pkl class definitions as an input, and generates corresponding Java classes with equally named properties. The Java source code generator takes Pkl class definitions as an input, and generates corresponding Java classes with equally named properties.
@@ -23,7 +23,7 @@ See xref:pkl-gradle:index.adoc#installation[Installation] in the Gradle plugin c
[[install-library]] [[install-library]]
=== Java Library === Java Library
The `pkl-codegen-java` library is available {uri-pkl-codgen-java-maven-module}[from Maven Central]. The `pkl-codegen-java` library is available {uri-pkl-codegen-java-maven-module}[from Maven Central].
It requires Java 17 or higher. It requires Java 17 or higher.
ifndef::is-release-version[] ifndef::is-release-version[]
@@ -145,23 +145,27 @@ Flag that indicates to generate private final fields and public getter methods i
[%collapsible] [%collapsible]
==== ====
Default: (flag not set) + Default: (flag not set) +
Flag that indicates to generate Javadoc based on doc comments for Pkl modules, classes, and properties. Flag that indicates to preserve Pkl doc comments by generating corresponding Javadoc comments.
==== ====
.--params-annotation .--params-annotation
[%collapsible] [%collapsible]
==== ====
Default: `org.pkl.config.java.mapper.Named` + Default: `none` if `--generate-spring-boot` is set, `org.pkl.config.java.mapper.Named` otherwise +
Fully qualified name of the annotation to use on constructor parameters. Fully qualified name of the annotation type to use for annotating constructor parameters with their name. +
The specified annotation type must have a `value` parameter of type `String` or the generated code may not compile.
If set to `none`, constructor parameters are not annotated.
Whether and how constructor parameters should be annotated depends on the library that instantiates the generated classes.
For Spring Boot applications, and for users of `pkl-config-java` compiling the generated classes with `-parameters`, no annotation is required.
==== ====
.--non-null-annotation .--non-null-annotation
[%collapsible] [%collapsible]
==== ====
Default: `org.pkl.config.java.mapper.NonNull` + Default: `org.pkl.config.java.mapper.NonNull` +
Fully qualified named of the annotation class to use for non-null types. + Fully qualified name of the annotation type to use for annotating non-null types. +
This annotation is required to have `java.lang.annotation.ElementType.TYPE_USE` as a `@Target` The specified annotation type must be annotated with `@java.lang.annotation.Target(ElementType.TYPE_USE)`
or it may generate code that does not compile. or the generated code may not compile.
==== ====
Common code generator options: Common code generator options:
@@ -26,7 +26,7 @@ Flag that indicates to generate config classes for use with Spring Boot.
[%collapsible] [%collapsible]
==== ====
Default: (not set) + Default: (not set) +
Whether to make generated classes implement `java.io.Serializable`. Flag that indicates to generate classes that implement `java.io.Serializable`.
==== ====
.--rename .--rename
@@ -118,7 +118,7 @@ Relative URIs are resolved against the working directory.
[%collapsible] [%collapsible]
==== ====
Default: (flag not set) + Default: (flag not set) +
Flag that indicates to generate Kdoc based on doc comments for Pkl modules, classes, and properties. Flag that indicates to preserve Pkl doc comments by generating corresponding KDoc comments.
==== ====
Common code generator options: Common code generator options:
+202 -20
View File
@@ -2,13 +2,11 @@
include::ROOT:partial$component-attributes.adoc[] include::ROOT:partial$component-attributes.adoc[]
:uri-common-mark: https://commonmark.org/ :uri-common-mark: https://commonmark.org/
:uri-newspeak: https://newspeaklanguage.org :uri-newspeak: https://newspeaklanguage.org
:uri-antlr4: https://www.antlr.org
:uri-prototypical-inheritance: https://en.wikipedia.org/wiki/Prototype-based_programming :uri-prototypical-inheritance: https://en.wikipedia.org/wiki/Prototype-based_programming
:uri-double-precision: https://en.wikipedia.org/wiki/Double-precision_floating-point_format :uri-double-precision: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
:uri-progressive-disclosure: https://en.wikipedia.org/wiki/Progressive_disclosure :uri-progressive-disclosure: https://en.wikipedia.org/wiki/Progressive_disclosure
:uri-javadoc-Pattern: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html :uri-javadoc-Pattern: https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
:uri-github-PklLexer: {uri-github-tree}/pkl-core/src/main/antlr/PklLexer.g4 :uri-github-PklLexer: {uri-github-tree}/pkl-core/src/main/java/org/pkl/core/parser/Lexer.java
:uri-github-PklParser: {uri-github-tree}/pkl-core/src/main/antlr/PklParser.g4
:uri-pkl-core-ModuleSchema: {uri-pkl-core-main-sources}/ModuleSchema.java :uri-pkl-core-ModuleSchema: {uri-pkl-core-main-sources}/ModuleSchema.java
:uri-pkl-core-SecurityManager: {uri-pkl-core-main-sources}/SecurityManager.java :uri-pkl-core-SecurityManager: {uri-pkl-core-main-sources}/SecurityManager.java
:uri-pkl-core-ResourceReader: {uri-pkl-core-main-sources}/resource/ResourceReader.java :uri-pkl-core-ResourceReader: {uri-pkl-core-main-sources}/resource/ResourceReader.java
@@ -2036,6 +2034,9 @@ greeting2 = greetPigeon(parrot) // <4>
<3> Call instance method on `pigeon`. <3> Call instance method on `pigeon`.
<4> Call module method (on `this`). <4> Call module method (on `this`).
Like other object-oriented languages, methods defined on extended classes and modules may be overridden.
The parent type's method may be called via the <<super-keyword,`super` keyword>>.
NOTE: Methods do not support named parameters or default parameter values. NOTE: Methods do not support named parameters or default parameter values.
The xref:blog:ROOT:class-as-a-function.adoc[Class-as-a-function] pattern may be a suitable replacement. The xref:blog:ROOT:class-as-a-function.adoc[Class-as-a-function] pattern may be a suitable replacement.
@@ -2573,7 +2574,7 @@ the following security checks are performed:
* The target module URI is checked against the module allowlist (`--allowed-modules`). * The target module URI is checked against the module allowlist (`--allowed-modules`).
* The source and target modules' _trust levels_ are determined and compared. * The source and target modules' _trust levels_ are determined and compared.
For access to be granted, the source module's trust level must be higher than or equal to the target module's trust level. For access to be granted, the source module's trust level must be greater than or equal to the target module's trust level.
By default, there are five trust levels, listed from highest to lowest: By default, there are five trust levels, listed from highest to lowest:
. `repl:` modules (code evaluated in the REPL) . `repl:` modules (code evaluated in the REPL)
@@ -2716,7 +2717,7 @@ quota:
disk: 20 GB disk: 20 GB
---- ----
In addition to _type_ based converters, renderers also support _path_ based converters: In addition to _class_-based converters, renderers also support _path_-based converters:
[source%parsed,{pkl}] [source%parsed,{pkl}]
---- ----
@@ -3193,10 +3194,13 @@ This section discusses language features that are generally more relevant to tem
<<for-generators,For Generators>> + <<for-generators,For Generators>> +
<<spread-syntax,Spread Syntax>> + <<spread-syntax,Spread Syntax>> +
<<member-predicates,Member Predicates (`[[...]]`)>> + <<member-predicates,Member Predicates (`[[...]]`)>> +
<<this-keyword,`this` Keyword>> +
<<outer-keyword,`outer` Keyword>> +
<<super-keyword,`super` Keyword>> +
<<module-keyword,`module` Keyword>> +
<<glob-patterns,Glob Patterns>> + <<glob-patterns,Glob Patterns>> +
<<doc-comments,Doc Comments>> + <<doc-comments,Doc Comments>> +
<<name-resolution,Name Resolution>> + <<name-resolution,Name Resolution>> +
<<grammar-definition,Grammar Definition>> +
<<reserved-keywords,Reserved Keywords>> + <<reserved-keywords,Reserved Keywords>> +
<<blank-identifiers,Blank Identifiers>> + <<blank-identifiers,Blank Identifiers>> +
<<projects,Projects>> + <<projects,Projects>> +
@@ -3353,9 +3357,9 @@ swiftHatchlings = typedProperty.listHatchlings(new { "Poppy"; "Chirpy" }) // <8>
<2> Assignment to an undeclared property in module context, amending `new Dynamic {}`. <2> Assignment to an undeclared property in module context, amending `new Dynamic {}`.
<3> `Listing` element creation, amending implicit `default`, `new Bird {}`. <3> `Listing` element creation, amending implicit `default`, `new Bird {}`.
<4> `Listing` element creation, amending implicit `default`, `new Dynamic {}`. <4> `Listing` element creation, amending implicit `default`, `new Dynamic {}`.
<5> `Mapping` value assignment, amdending the result of applying `default` to `"Saltmarsh Sparrow"`, `new Bird { name = "Saltmarsh Sparrow" }`. <5> `Mapping` value assignment, amending the result of applying `default` to `"Saltmarsh Sparrow"`, `new Bird { name = "Saltmarsh Sparrow" }`.
<6> `Mapping` value assignment _replacing_ the parent's entry, amending the result of applying `default` to `"Saltmarsh Sparrow"`, `new Bird { name = "Saltmarsh Sparrow" }`. <6> `Mapping` value assignment _replacing_ the parent's entry, amending the result of applying `default` to `"Saltmarsh Sparrow"`, `new Bird { name = "Saltmarsh Sparrow" }`.
<7> Admending the property default value `new Listing { new Bird { name = "Osprey" } }`; the result contains both birds. <7> Amending the property default value `new Listing { new Bird { name = "Osprey" } }`; the result contains both birds.
<8> Error: Cannot tell which parent to amend. <8> Error: Cannot tell which parent to amend.
[[let-expressions]] [[let-expressions]]
@@ -3539,9 +3543,7 @@ res6 = list.map((n) -> n * 3) // <6>
[[sets]] [[sets]]
=== Sets === Sets
A value of type link:{uri-stdlib-Set}[Set] is an ordered collection of unique _elements_. A value of type link:{uri-stdlib-Set}[Set] is a collection of unique _elements_.
A set's elements are eagerly evaluated.
Sets are constructed with the `Set()` methodfootnote:soft-keyword[]: Sets are constructed with the `Set()` methodfootnote:soft-keyword[]:
@@ -3557,6 +3559,20 @@ res4 = Set(1, "x", 5.min, List(1, 2, 3)) // <4>
<3> result: same set of length 3 <3> result: same set of length 3
<4> result: heterogeneous set that contains a list as its last element <4> result: heterogeneous set that contains a list as its last element
Sets retain the order of elements when constructed, which impacts how they are iterated over.
However, this order is not considered when determining equality of two sets.
[source%tested,{pkl}]
----
res1 = Set(4, 3, 2)
res2 = res1.first // <1>
res3 = res1.toListing() // <2>
res4 = Set(2, 3, 4) == res1 // <3>
----
<1> result: `4`
<2> result: `new Listing { 4; 3; 2 }`
<3> result: `true`
To compute the union of sets, use the `+` operator: To compute the union of sets, use the `+` operator:
[source%tested,{pkl-expr}] [source%tested,{pkl-expr}]
@@ -3584,7 +3600,7 @@ res4 = set.intersect(Set(3, 9, 2)) // <4>
[[maps]] [[maps]]
=== Maps === Maps
A value of type link:{uri-stdlib-Map}[Map] is an ordered collection of _values_ indexed by _key_. A value of type link:{uri-stdlib-Map}[Map] is a collection of _values_ indexed by _key_.
A map's key-value pairs are called its _entries_. A map's key-value pairs are called its _entries_.
Keys and values are eagerly evaluated. Keys and values are eagerly evaluated.
@@ -3619,6 +3635,20 @@ Any Pkl value can be used as a map key:
Map(new Dynamic { name = "Pigeon" }, 10.gb) Map(new Dynamic { name = "Pigeon" }, 10.gb)
---- ----
Maps retain the order of entries when constructed, which impacts how they are iterated over.
However, this order is not considered when determining equality of two maps.
[source%tested,{pkl}]
----
res1 = Map(2, "hello", 1, "world")
res2 = res1.entries.first // <1>
res3 = res1.toMapping() // <2>
res4 = res1 == Map(1, "world", 2, "hello") // <3>
----
<1> result: `Pair(2, "hello")`
<2> result: `new Mapping { [2] = "hello"; [1] = "world" }`
<3> result: `true`
To merge maps, use the `+` operator: To merge maps, use the `+` operator:
[source%tested,{pkl}] [source%tested,{pkl}]
@@ -4803,6 +4833,161 @@ The predicate, enclosed in double brackets (`\[[...]]`), is matched against each
Within the predicate, `this` refers to the member that the predicate is matched against. Within the predicate, `this` refers to the member that the predicate is matched against.
Matching members are amended (`{ ... }`) or overridden (`= <new-value>`). Matching members are amended (`{ ... }`) or overridden (`= <new-value>`).
[[this-keyword]]
=== `this` keyword
Normally, the `this` keyword references the enclosing object's receiver.
Example:
[source,pkl]
----
bird {
eatsInsects = this is InsectavorousBird
}
----
When used inside a <<type-constraints,type constraint>>, `this` refers to the value being tested.
Example:
[source,pkl]
----
port: UInt16(this > 1000)
----
When used inside a <<member-predicates,member predicate>>, `this` refers to the value being matched against.
Example:
[source,pkl]
----
animals {
[[this is Bird]] {
canFly = true
}
}
----
[[receiver]]
==== Receiver
The receiver is the bottom-most object in the <<prototype-chain>>.
That means that, within the context of an amending object, the reciever is the amending object.
Example:
[source,pkl]
----
hidden lawyerBird {
title = "\(this.name), Esq."
}
polly = (lawyerBird) {
name = "Polly" // <1>
}
----
<1> Polly has title `"Polly, Esq."`.
[[outer-keyword]]
=== `outer` keyword
The `outer` keyword references the <<receiver,receiver>> of the immediately outer lexical object.
It can be useful to disambiguate a lookup that might otherwise resolve elsewhere.
Example:
[source%tested,pkl]
----
foo {
bar = "bar"
qux {
bar = outer.bar // <1>
}
}
----
<1> References `bar` one level higher.
Note that `outer` cannot be chained.
In order to reference a value more than one level higher, a typical pattern is to declare a local property at that level.
For example:
[source%parsed,pkl]
----
foo {
local self = this
bar {
baz {
qux = self.qux
}
}
}
----
[[super-keyword]]
=== `super` keyword
The `super` keyword references the parent object in the <<prototype-chain,prototype chain>>.
When used within a class, it refers to the superclass's prototype.
When used within an object, it refers to the parent object in the amends chain.
Example:
[source%tested,pkl]
----
bird = new { name = "Quail" }
bird2 = (bird) { name = "Ms. \(super.name)" } // <1>
abstract class Bird {
foods: Listing<String>
function canEat(food: String): Boolean = foods.contains(food)
}
class InsectavorousBird extends Bird {
function canEat(food: String) =
super.canEat(food) || food == "insect" // <2>
}
----
<1> Result: `"Ms. Quail"`
<2> Calls parent class method `canEat()`
The `super` keyword must be followed by property/method access, or subscript.
`super` by itself a syntax error; whereas `super.foo` and `super["foo"]` are valid expressions.
[[module-keyword]]
=== `module` keyword
The `module` keyword can be used as either a value, or as a type.
When used as a value, it refers to the <<receiver,receiver>> of the module itself.
[source%tested,pkl]
----
name = "Quail"
some {
deep {
object {
name = module.name // <1>
}
}
}
----
<1> Resolves to `"Quail"`
When used as a type, it is the module's class.
[source%parsed,pkl]
----
module Bird
friend: module // <1>
----
<1> Is class `Bird`
The `module` type is a _self type_.
If the module is extended by another module, the `module` type refers to the extending module when
in the context of that module.
[[glob-patterns]] [[glob-patterns]]
=== Glob Patterns === Glob Patterns
@@ -4889,8 +5074,8 @@ TIP: If incorporating escape characters into a glob pattern, use <<custom-string
|=== |===
|Pattern |Description |Pattern |Description
|`*.pc[lf]` |`*.pk[lg]`
|Anything suffixed by `.pkl`, or `.pcf`. |Anything suffixed by `.pkl`, or `.pkg`.
|`**.y{a,}ml` |`**.y{a,}ml`
|Anything suffixed by either `yml` or `yaml`, crossing directory boundaries. |Anything suffixed by either `yml` or `yaml`, crossing directory boundaries.
@@ -5248,11 +5433,6 @@ For example, the prototype chain of value `42` contains, now listed from top to
A prototype chain never contains a non-object value, such as `42`. A prototype chain never contains a non-object value, such as `42`.
[[grammar-definition]]
=== Grammar Definition
Pkl's link:{uri-antlr4}[ANTLR 4] grammar is defined in link:{uri-github-PklLexer}[PklLexer.g4] and link:{uri-github-PklParser}[PklParser.g4].
[[reserved-keywords]] [[reserved-keywords]]
=== Reserved keywords === Reserved keywords
@@ -5269,6 +5449,8 @@ They cannot be used as a regular identifier, and currently do not have any meani
To use these names in an identifier, <<quoted-identifiers, surround them with backticks>>. To use these names in an identifier, <<quoted-identifiers, surround them with backticks>>.
For a complete list of keywords, consult field `Lexer.KEYWORDS` in {uri-github-PklLexer}[Lexer.java].
[[blank-identifiers]] [[blank-identifiers]]
=== Blank Identifiers === Blank Identifiers
@@ -5475,7 +5657,7 @@ Readers are implemented as ordinary executables and use Pkl's xref:bindings-spec
The xref:swift:ROOT:index.adoc[Swift] and xref:go:ROOT:index.adoc[Go] language binding libraries provide an `ExternalReaderRuntime` type to facilitate implementing external readers. The xref:swift:ROOT:index.adoc[Swift] and xref:go:ROOT:index.adoc[Go] language binding libraries provide an `ExternalReaderRuntime` type to facilitate implementing external readers.
External readers are configured separately for modules and resources. External readers are configured separately for modules and resources.
They are registered by mapping their URI scheme to the executable to run and additonal arguments to pass. They are registered by mapping their URI scheme to the executable to run and additional arguments to pass.
This is done on the command line by passing `--external-resource-reader` and `--external-module-reader` flags, which may both be passed multiple times. This is done on the command line by passing `--external-resource-reader` and `--external-module-reader` flags, which may both be passed multiple times.
[source,text] [source,text]
@@ -134,6 +134,7 @@ exampleObjectWithMixedElements {
<2> Elements don't have to be literal values; they can be arbitrary _expressions_. <2> Elements don't have to be literal values; they can be arbitrary _expressions_.
<3> Elements can really be _any_ value, not just primitive values. <3> Elements can really be _any_ value, not just primitive values.
[[entries]]
=== Entries === Entries
Objects can have one more kind of member; _entries_. Objects can have one more kind of member; _entries_.
@@ -213,7 +213,7 @@ adultBirdFoods {
A `.pkl` file describes a _module_. A `.pkl` file describes a _module_.
Modules are objects that can be referred to from other modules. Modules are objects that can be referred to from other modules.
Going back to the example above, you can write `parrot` as a separate module. Going back to the example above, you can write `pigeon` as a separate module.
[source,{pkl}] [source,{pkl}]
.pigeon.pkl .pigeon.pkl
+20 -6
View File
@@ -53,8 +53,7 @@ whereas, the Alpine Linux executable is statically linked against _musl libc_ an
==== ====
The Java executable works on multiple platforms and has a smaller binary size than the native executables. The Java executable works on multiple platforms and has a smaller binary size than the native executables.
However, it requires a Java 17 (or higher) runtime on the system path, has a noticeable startup delay, However, it requires a Java 17 (or higher) runtime on the system path, and has a noticeable startup delay.
and runs complex Pkl code slower than the native executables.
All flavors are built from the same codebase and undergo the same automated testing. All flavors are built from the same codebase and undergo the same automated testing.
Except where noted otherwise, the rest of this page discusses the native executables. Except where noted otherwise, the rest of this page discusses the native executables.
@@ -201,6 +200,14 @@ NOTE: We currently do not support the aarch64 architecture for Windows.
[[java-executable]] [[java-executable]]
=== Java Executable === Java Executable
The Java executable is a jar that can be executed directly on macOS, Linux, and Windows.
It requires `java` to be installed, and available on `$PATH`.
[tabs]
====
macOS/Linux::
+
[source,shell] [source,shell]
[subs="+attributes"] [subs="+attributes"]
---- ----
@@ -209,6 +216,16 @@ chmod +x jpkl
./jpkl --version ./jpkl --version
---- ----
Windows::
+
[source,PowerShell]
[subs="+attributes"]
----
Invoke-WebRequest '{uri-pkl-java-download}' -OutFile jpkl.bat
.\jpkl --version
----
====
This should print something similar to: This should print something similar to:
[source,shell] [source,shell]
@@ -217,8 +234,7 @@ This should print something similar to:
Pkl {pkl-version} (macOS 14.2, Java 17.0.10) Pkl {pkl-version} (macOS 14.2, Java 17.0.10)
---- ----
NOTE: The Java executable does not work as an executable file on Windows. NOTE: The Java executable is named `jpkl`.
However, it will work as a jar, for example, with `java -jar jpkl`.
[[usage]] [[usage]]
== Usage == Usage
@@ -721,8 +737,6 @@ Type :help or :examples for more information.
pkl> pkl>
---- ----
NOTE: The Java executable is named `jpkl`.
=== Loading Modules === Loading Modules
To load <<config.pkl,`config.pkl`>> into the REPL, run: To load <<config.pkl,`config.pkl`>> into the REPL, run:
+9 -1
View File
@@ -232,10 +232,18 @@ Relative URIs are resolved against the working directory.
[%collapsible] [%collapsible]
==== ====
Default: (none) + Default: (none) +
Example: `pkldoc` Example: `pkldoc` +
The directory where generated documentation is placed. The directory where generated documentation is placed.
==== ====
.--no-symlinks
[%collapsible]
====
Create copies of files and directories instead of symbolic links.
In particular, this affects how the "current" directories containing documentation content for the last generated version should be created.
By default, a symbolic link is created pointing to the last generated version. If symlinks are disabled, a full copy of the last generated version is created.
====
Common CLI options: Common CLI options:
include::../../pkl-cli/partials/cli-common-options.adoc[] include::../../pkl-cli/partials/cli-common-options.adoc[]
+38 -8
View File
@@ -373,14 +373,26 @@ Example: `generateGetters = true` +
Whether to generate private final fields and public getter methods rather than public final fields. Whether to generate private final fields and public getter methods rather than public final fields.
==== ====
// TODO: fixme (paramsAnnotation, nonNullAnnotation) .paramsAnnotation: Property<String>
.preferJavaxInjectAnnotation: Boolean
[%collapsible] [%collapsible]
==== ====
Default: `false` + Default: `null` if `generateSpringBootConfig` is `true`, `"org.pkl.config.java.mapper.Named"` otherwise+
Example: `preferJavaxInjectAnnotation = true` + Example: `paramsAnnotation = "org.project.MyAnnotation"` +
Whether to annotate constructor parameters with `@javax.inject.Named` instead of `@org.pkl.config.java.mapper.Named`. Fully qualified name of the annotation type to use for annotating constructor parameters with their name. +
If `true`, the generated code will have a compile dependency on `javax.inject:javax.inject:1`. The specified annotation type must have a `value` parameter of type `String` or the generated code may not compile.
If set to `null`, constructor parameters are not annotated.
Whether and how constructor parameters should be annotated depends on the library that instantiates the generated classes.
For Spring Boot applications, and for users of `pkl-config-java` compiling the generated classes with `-parameters`, no annotation is required.
====
.nonNullAnnotation: Property<String>
[%collapsible]
====
Default: `"org.pkl.config.java.mapper.NonNull"` +
Example: `nonNullAnnotation = "org.project.MyAnnotation"` +
Fully qualified name of the annotation type to use for annotating non-null types. +
The specified annotation type must be annotated with `@java.lang.annotation.Target(ElementType.TYPE_USE)`
or the generated code may not compile.
==== ====
Common code generation properties: Common code generation properties:
@@ -443,8 +455,15 @@ see link:{uri-codegen-kotlin-example}[codegen-kotlin] in the _pkl/pkl-examples_
=== Configuration Options === Configuration Options
// TODO: fixme (generateKdoc) === Configuration Options
(None)
.generateKdoc: Property<Boolean>
[%collapsible]
====
Default: `false` +
Example: `generateKdoc = true` +
Whether to preserve Pkl doc comments by generating corresponding KDoc comments.
====
Common code generation properties: Common code generation properties:
@@ -515,6 +534,17 @@ Example: `outputDir = layout.projectDirectory.dir("pkl-docs")` +
The directory where generated documentation is placed. The directory where generated documentation is placed.
==== ====
.noSymlinks: Property<Boolean>
[%collapsible]
====
Default: `false` +
Example: `noSymlinks = true` +
Create copies of files and directories instead of symbolic links.
In particular, this affects how the "current" directories containing documentation content for the last generated version should be created.
By default, a symbolic link is created pointing to the last generated version.
If symlinks are disabled, a full copy of the last generated version is created.
====
Common properties: Common properties:
include::../partials/gradle-modules-properties.adoc[] include::../partials/gradle-modules-properties.adoc[]
@@ -36,6 +36,14 @@ Example: `generateSpringBootConfig = true` +
Whether to generate config classes for use with Spring Boot. Whether to generate config classes for use with Spring Boot.
==== ====
.implementSerializable: Property<Boolean>
[%collapsible]
====
Default: `false` +
Example: `implementSerializable = true` +
Whether to generate classes that implement `java.io.Serializable`.
====
.renames: MapProperty<String, String> .renames: MapProperty<String, String>
[%collapsible] [%collapsible]
==== ====
@@ -86,4 +94,3 @@ Keys in this mapping can be arbitrary strings, including an empty string.
Values must be valid dot-separated fully qualifed class name prefixes, possibly terminated by a dot. Values must be valid dot-separated fully qualifed class name prefixes, possibly terminated by a dot.
==== ====
// TODO: fixme (implementSerializable)
Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

+2 -2
View File
@@ -12,7 +12,7 @@ This release brings Windows support, improvements to controlling how Pkl talks o
The next release (0.27) is scheduled for October 10th, 2024. The next release (0.27) is scheduled for October 10th, 2024.
Please send feedback and questions to https://github.com/apple/pkl/discussions[GitHub Discussions], or submit an issue on https://github.com/apple/pkl/issues/new[Github]. + Please send feedback and questions to https://github.com/apple/pkl/discussions[GitHub Discussions], or submit an issue on https://github.com/apple/pkl/issues/new[GitHub]. +
[small]#Pkl is hosted on https://github.com/apple/pkl[GitHub]. [small]#Pkl is hosted on https://github.com/apple/pkl[GitHub].
To get started, follow xref:pkl-cli:index.adoc#installation[Installation].# To get started, follow xref:pkl-cli:index.adoc#installation[Installation].#
@@ -460,7 +460,7 @@ To mitigate, the package's version needs to be bumped, even if package contents
== Miscellaneous [small]#🐸# == Miscellaneous [small]#🐸#
The following changes have been made that are not new features, nor breaking changes. The following changes have been made that are neither new features nor breaking changes.
* Pkl's user-agent header for HTTP requests has been tweaked to add a semicolon (https://github.com/apple/pkl/pull/221[#221]). Here is an example difference: * Pkl's user-agent header for HTTP requests has been tweaked to add a semicolon (https://github.com/apple/pkl/pull/221[#221]). Here is an example difference:
+ +
+3 -3
View File
@@ -1,6 +1,6 @@
= Pkl 0.27 Release Notes = Pkl 0.27 Release Notes
:version: 0.27 :version: 0.27
:version-minor: 0.27.1 :version-minor: 0.27.2
:release-date: November 5th, 2024 :release-date: November 5th, 2024
include::ROOT:partial$component-attributes.adoc[] include::ROOT:partial$component-attributes.adoc[]
@@ -12,7 +12,7 @@ This release brings improvements in typechecking of `Listing` and `Mapping`, the
The next release (0.28) is scheduled for February 2025. The next release (0.28) is scheduled for February 2025.
Please send feedback and questions to https://github.com/apple/pkl/discussions[GitHub Discussions], or submit an issue on https://github.com/apple/pkl/issues/new[Github]. + Please send feedback and questions to https://github.com/apple/pkl/discussions[GitHub Discussions], or submit an issue on https://github.com/apple/pkl/issues/new[GitHub]. +
[small]#Pkl is hosted on https://github.com/apple/pkl[GitHub]. [small]#Pkl is hosted on https://github.com/apple/pkl[GitHub].
To get started, follow xref:pkl-cli:index.adoc#installation[Installation].# To get started, follow xref:pkl-cli:index.adoc#installation[Installation].#
@@ -121,7 +121,7 @@ A new API has been added to analyze the import graph of Pkl modules (https://git
This API comes in four forms: This API comes in four forms:
1. A standard library module: `pkl:analyze` 1. A standard library module: `pkl:analyze`
2. A CLI command: `pkl anaylze imports` 2. A CLI command: `pkl analyze imports`
3. A Java API: `org.pkl.core.Analyzer` 3. A Java API: `org.pkl.core.Analyzer`
4. A Gradle API: `org.pkl.gradle.task.AnalyzeImportsTask` 4. A Gradle API: `org.pkl.gradle.task.AnalyzeImportsTask`
+375
View File
@@ -0,0 +1,375 @@
= Pkl 0.28 Release Notes
:version: 0.28
:version-minor: 0.28.0
:release-date: February 26th, 2025
include::ROOT:partial$component-attributes.adoc[]
:uri-snippet-tests: {uri-github-tree}/pkl-core/src/test/files/LanguageSnippetTests/input
:uri-standard-library: {uri-github-tree}/stdlib/
:uri-antlr: https://www.antlr.org
:wbr: pass:[<wbr />]
Pkl {version} was released on {release-date}. +
[.small]#The latest bugfix release is {version-minor}. (xref:changelog.adoc[All Versions])#
The next release (0.29) is scheduled for June 2025.
To see what's coming in the future, follow the {uri-pkl-roadmap}[Pkl Roadmap].
Please send feedback and questions to https://github.com/apple/pkl/discussions[GitHub Discussions], or submit an issue on https://github.com/apple/pkl/issues/new[GitHub]. +
[small]#Pkl is hosted on https://github.com/apple/pkl[GitHub].
To get started, follow xref:pkl-cli:index.adoc#installation[Installation].#
== Highlights [small]#💖#
News you don't want to miss.
=== New parser
Pkl has new parser (https://github.com/apple/pkl/pull/917[#917], https://github.com/apple/pkl/pull/957[#957], https://github.com/apple/pkl/pull/962[#962])!
The first step to evaluating a program is to parse its source code into a parse tree.
Currently, Pkl uses link:{uri-antlr}[ANTLR] to generate parser code from grammar files.
Using this approach has allowed for rapidly iterating and changing the language's grammar.
However, Pkl's grammar has matured; it's not as likely that the grammar will change from one version to the next.
Additionally, the current parser's performance has become more painful as projects written in Pkl grow in size.
In many cases, parsing can take up most of the time spent during evaluation.
In 0.28, the ANTLR-generated parser is being replaced by a handwritten parser.
In benchmarking tests, this has shown to improve parsing speed by around two orders of magnitude.
Here are some quick comparisons between the two parsers, run on a MacBook Pro M4 Max machine, with 5 warmup iterations, and run for 10 iterations:
|===
||Old parser |New parser
|link:{uri-snippet-tests}[Language snippet tests]
|440.8ms
|5.9ms
|link:{uri-standard-library}[Standard library]
|136.7msfootnote:[In the `pkl` CLI, the standard library is parsed during compilation rather than during evaluation. As a result, there is no parsing overhead.]
|0.8ms
|All https://github.com/apple/pkl-pantry[pkl-pantry] modules
|1424.2ms
|7.0ms
|===
== Noteworthy [small]#🎶#
Ready when you need them.
=== CLI improvements
==== Colored help messages
The `pkl`, `pkldoc`, `pkl-codegen-java`, and `pkl-codegen-kotlin` CLIs now emits help text with colors (https://github.com/apple/pkl/pull/947[#947]).
Here is a sneak peek:
image::pkl-cli-help-new.png[new pkl cli help output]
Thanks to https://github.com/gordonbondon[@gordonbondon] for their contribution!
==== `jpkl` support on Windows
The `jpkl` executable is now supported on Windows (https://github.com/apple/pkl/pull/872[#872]).
`jpkl` is a fat jar that can be executed directly when on macOS and Linux, but current users of Windows are required to execute it with `java -jar <path/to/jpkl>`.
In 0.28, Windows users can also call execute this command directly.
To do so, the filename should be called `jpkl.bat`, and placed in `PATH`.
=== Type constraint changes
Type annotations that are executed as a result of calling a constraint expressions now perform an eager typecheck (https://github.com/apple/pkl/pull/964[#964]).
In Pkl 0.27, we changed how xref:0.27.adoc#typecheck-improvements[typechecks are executed for `Listing` and `Mapping`] types.
However, this had two unintended side effects:
For one, error messages from certain failing constraints show `?` in place of values that are failing.
The following snippet:
[source%parsed,pkl]
----
class Bird { name: String }
bird: Listing<Bird>(firstOneIsQuail) = new {
new { name = "Pigeon" }
new { name = "Quail" }
}
local firstOneIsQuail = (it: Listing<Bird>) -> it[0].name == "Quail"
----
Produces the following error message:
[source]
----
–– Pkl Error ––
Type constraint `firstOneIsQuail` violated.
Value: new Listing { ?; ? }
3 | bird: Listing<Bird>(firstOneIsQuail) = new {
^^^^^^^^^^^^^^^
----
:fn-typecheck-details: footnote:[See https://github.com/apple/pkl-evolution/blob/main/spices/SPICE-0010-overhauled-mapping-listing-typechecks.adoc#delegating-objects[delegating objects] in SPICE-0010 for more details on this behavior.]
This is happening because lazy typechecks of mappings and listings will return a _new_ listing. Because the lambda's argument is defined as ``it: Listing<Bird>``, the value being passed into the function body is this new listing{fn-typecheck-details}.
Secondly, some constraints became less strict, allowing more values to pass.
The following snippet fails in Pkl 0.26, but passes in Pkl 0.27:
[source%parsed,pkl]
----
class Bird { name: String }
local nonEmpty = (it: Listing<Bird>) -> !it.isEmpty
birds: Listing(nonEmpty) = new { 1; 2; 3 }
----
This is because the function parameter `it: Listing<Bird>` does not actually check members of the argument until they are accessed, and the function body `!it.isEmpty` does not access any members.
To address both of these issues, the rule for executing type constraints has changed.
When executing a type annotation, mapping and listing typechecks are always _eager_.
This means that Pkl will check that each member of the mapping/listing conforms to the type parameter.
=== Java 22+ support
Pkl's Java libraries now support Java 22 and higher (https://github.com/apple/pkl/pull/876[#876]).
Thanks to https://github.com/sgammon[@sgammon] for their contribution!
=== New standard library method
The `pkl:math` standard library module has a new method, called {uri-stdlib-mathModule}/index.html#atan2()[atan2] (https://github.com/apple/pkl/pull/819[#819]).
It computes the https://en.wikipedia.org/wiki/Atan2[2-argument arctangent].
Thanks to https://github.com/gordonbondon[@gordonbondon] for their contribution!
=== Overhauled for-generator implementation
The implementation of xref:language-reference:index.adoc#for-generators[for-generators] has been overhauled (https://github.com/apple/pkl/pull/844[#844]).
This fixes some known bugs with the current for-generator implementation, and also improves code health by reducing complexity and removing workarounds and band-aids.
Thanks to https://github.com/odenix[@odenix] for their contribution!
=== Java code generator improvements
Improvements have been made to the Java code generator (https://github.com/apple/pkl/pull/792[#792]).
In pkl-codegen-java, the `--params-annotation` flag now accepts `none` as a value, which causes the code generator to skip adding annotations to a constructor's parameters.
Additionally, the Kotlin API `org.pkl.codegen.java.JavaCodeGeneratorOptions.paramsAnnotation` is now nullable.
If null, this also skips adding annotations.
By default, this annotation is set to `org.pkl.config.java.mapper.Named`, or none if the `--generate-spring-boot-config` flag is set.
This is useful for those compiling Java code with the `-parameters` flag set, because the pkl-config-java library is able to map into these classes without any extra annotations.
Thanks to https://github.com/odenix[@odenix] for their contribution!
=== Kotlin code generator improvements
Improvements have been made to the Kotlin code generator (https://github.com/apple/pkl/pull/793[#793]).
Currently, the output of `toString()` on a generated Kotlin class differs depending on if it was generated as a data class or as a regular class.
In Pkl 0.28, this method produces the same format, and matches the format used by data classes.
Thanks to https://github.com/odenix[@odenix] for their contribution!
=== pkldoc improvements
pkldoc has a new flag to write real files instead of symlinks (https://github.com/apple/pkl/pull/824[#824]).
Currently, pkldoc creates a symlink called "current", which points to the latest non-prerelease version of a package.
However, these symlinks can be problematic for some systems.
A new flag, `--no-symlinks`, and a similarly named Gradle property, `noSymlinks`, instructs pkldoc to write real files instead of symlinks.
Thanks to https://github.com/netvl[@netvl] for their contributions!
=== `jar:nested:` URIs are accepted by default
To improve integration with Spring Boot, the Pkl evaluator by default now accepts module URIs starting with `jar:nested:` (https://github.com/apple/pkl/pull/895[#895]).
The `--allowed-modules` flag (and the equally named option in other APIs) can be used to configure the set of allowed modules.
== Breaking Changes [small]#💔#
Things to watch out for when upgrading.
=== Stricter grammar
As a result of implementing a new parser, the following previously accepted grammar is no longer valid (https://github.com/apple/pkl/pull/917[#917]).
==== Inline object entries
When declaring multiple xref:language-tutorial:01_basic_config.adoc#entries[entries] on the same line, a semicolon is now required to separate them.
The following code snippet is currently valid, and becomes a syntax error in 0.28.
[source,pkl]
----
obj { ["one"] = 1 ["two"] = 2 }
----
To fix, insert a semicolon between the two entries:
[source,diff]
----
-obj { ["one"] = 1 ["two"] = 2 }
+obj { ["one"] = 1; ["two"] = 2 }
----
==== String escapes
When using xref:language-reference:index.adoc#custom-string-delimiters[custom string delimiters], the escape sequence becomes backslash (`\`) plus the number of pounds used to delimit the string.
Due to a parser bug, any extra pounds after this escape sequence are also permitted.
In Pkl 0.28, this becomes a syntax error.
[source,pkl]
----
foo = "foo \#(bar)" // Invalid character escape sequence `\#`.
----
==== Whitespace between generator members
Inline object spreads, for generators, and when generators all now require either whitespace or a semicolon separator.
[source,pkl]
----
foo { ...bar...baz } // Syntax error
----
=== Minimum Gradle version bump
The minimum Gradle version for the xref:main:pkl-gradle:index.adoc[Gradle Plugin] has been bumped to 8.2 (https://github.com/apple/pkl/pull/901[#901]).
=== Java/Kotlin API breaking changes
Breaking changes have been made to the Java/Kotlin APIs (https://github.com/apple/pkl/pull/748[#748], https://github.com/apple/pkl/pull/749[#749], https://github.com/apple/pkl/pull/776[#776], https://github.com/apple/pkl/pull/793[#793], https://github.com/apple/pkl/pull/808[#808], https://github.com/apple/pkl/pull/810[#810]).
|===
|API |Breakage
| org.pkl.core.resource{wbr}.Resource
| Converted into a record; previous getter methods are deprecated.
| org.pkl.core.project{wbr}.Package
| Converted into a record; previous getter methods are deprecated.
| org.pkl.core.Member{wbr}.SourceLocation
| Converted into a record; previous getter methods are deprecated.
| org.pkl.core{wbr}.Release
| Converted into a record; previous getter methods are deprecated.
| org.pkl.core.Release{wbr}.SourceCode
| Converted into a record; previous getter methods are deprecated.
| org.pkl.core.Release{wbr}.Documentation
| Converted into a record; previous getter methods are deprecated.
| org.pkl.core.Release{wbr}.StandardLibrary
| Converted into a record; previous getter methods are deprecated.
| org.pkl.core.project{wbr}.DeclaredDependencies
| Converted into a record; previous getter methods are deprecated.
| org.pkl.core.evaluatorSettings{wbr}.PklEvaluatorSettings{wbr}.Proxy{wbr}.create
| Deprecated; use the constructor instead.
| org.pkl.core.module{wbr}.ExternalModuleResolver
| Moved into package org.pkl.core.externalreader
| org.pkl.core.resource{wbr}.ExternalResourceResolver
| Moved into package org.pkl.core.externalreader
| org.pkl.core.messaging{wbr}.MessageTransportModuleResolver
| Renamed to ExternalModuleResolverImpl, made package-private
| org.pkl.core.messaging{wbr}.MessageTransportResourceResolver
| Renamed to ExternalResourceResolverImpl, made package-private
| org.pkl.core.module{wbr}.ExternalModuleResolver{wbr}.Spec
| Replaced with record org.pkl.core.externalreader.ModuleReaderSpec
| org.pkl.core.resource{wbr}.ExternalResourceResolver{wbr}.Spec
| Replaced with record org.pkl.core.externalreader.ResourceReaderSpec
| org.pkl.core.messaging{wbr}.CreateEvaluatorRequest
| Changed properties `allowedModules` and `allowedResources` to be of type `List<String>` instead of `List<Pattern>`
| org.pkl.codegen.kotlin{wbr}.KotlinCodegenOptions
| Renamed to org.pkl.codegen.kotlin.KotlinCodeGeneratorOptions
| org.pkl.codegen.kotlin{wbr}.CliKotlinCodeGeneratorOptions{wbr}.toKotlinCodegenOptions
| Deprecated without replacement
| org.pkl.codegen.java{wbr}.JavaCodegenOptions
| Renamed to org.pkl.codegen.java.JavaCodeGeneratorOptions
| org.pkl.codegen.java{wbr}.CliJavaCodeGeneratorOptions{wbr}.toJavaCodegenOptions()
| Deprecated without replacement
|===
=== Fat jars no longer shade Truffle
Pkl publishes two fat jars to Maven Central: https://central.sonatype.com/artifact/org.pkl-lang/pkl-tools[pkl-tools], and https://central.sonatype.com/artifact/org.pkl-lang/pkl-config-java-all[pkl-config-java-all].
Due a version bump in the Truffle library, the package `com.oracle.truffle` can no longer be shaded.
For users that use both Pkl and other Truffle languages, this means that their version of Truffle should match Pkl's version.
== Miscellaneous [small]#🐸#
* Documentation improvements (https://github.com/apple/pkl/pull/792[#792], https://github.com/apple/pkl/pull/846[#846], https://github.com/apple/pkl/pull/860[#860], https://github.com/apple/pkl/pull/892[#892], https://github.com/apple/pkl/pull/921[#921], https://github.com/apple/pkl/pull/937[#937], https://github.com/apple/pkl/pull/943[#943], https://github.com/apple/pkl/pull/944[#944], https://github.com/apple/pkl/pull/955[#955], https://github.com/apple/pkl/pull/956[#956], https://github.com/apple/pkl/pull/973[#973]).
* The repository now requires Java 21 or higher to build (https://github.com/apple/pkl/pull/876[#876]).
* Enable multi-jdk testing via `-DmultiJdkTesting=true` flag when building Pkl (https://github.com/apple/pkl/pull/876[#876]).
* Pkl's version of Kotlin has been upgraded to 2.0 (https://github.com/apple/pkl/pull/900[#900]).
* Allow setting commit id via `-DcommitId` flag when building Pkl (https://github.com/apple/pkl/pull/954[#954]).
== Bugs fixed [small]#🐜#
The following bugs have been fixed.
[smaller]
* Optimization: `const` members should be cached for all children in the prototype chain (https://github.com/apple/pkl/issues/508[#508])
* codegen-kotlin: Use same toString() representation for data classes and regular classes (https://github.com/apple/pkl/issues/717[#717])
* Late-bound values of iteratees within nested for/spread fail to resolve for-generator variables (https://github.com/apple/pkl/issues/741[#741])
* codegen-java/kotlin: Fix generation of equals/hashCode methods (https://github.com/apple/pkl/pull/802[#802])
* Not possible to render mapping with Int keys in YAML (https://github.com/apple/pkl/issues/878[#878])
* Parser accepts wrong string escapes (https://github.com/apple/pkl/issues/888[#888])
* Downstream native-image embedders are broken (https://github.com/apple/pkl/issues/907[#907])
* Failed type constraint error messages do not show forced members (https://github.com/apple/pkl/issues/918[#918])
* ANTLR incompatibilities (https://github.com/apple/pkl/issues/927[#927])
* Doc comments with interleaving comments result in an error (https://github.com/apple/pkl/issues/931[#931])
* Spread elements inside an object body don't need separators (https://github.com/apple/pkl/issues/932[#932])
* Correctly set allowed modules/resoures when external reader scheme contain regex control characters (https://github.com/apple/pkl/pull/941[#941])
* Bad import analysis fails with "None (cause has no message)" (https://github.com/apple/pkl/issues/949[#949])
== Contributors [small]#🙏#
We would like to thank the contributors to this release (in alphabetical order):
* https://github.com/gordonbondon[@gordonbondon]
* https://github.com/HT154[@HT154]
* https://github.com/jsoref[@jsoref]
* https://github.com/KushalP[@KushalP]
* https://github.com/netvl[@netvl]
* https://github.com/odenix[@odenix]
* https://github.com/romacafe[@romacafe]
* https://github.com/sgammon[@sgammon]
* https://github.com/sorcix[@sorcix]
* https://github.com/stanleyycheung[@stanleyycheung]
@@ -1,6 +1,27 @@
= Changelog = Changelog
include::ROOT:partial$component-attributes.adoc[] include::ROOT:partial$component-attributes.adoc[]
[[release-0.28.0]]
== 0.28.0 (2025-02-26)
xref:0.28.adoc[Release notes]
[[release-0.27.2]]
== 0.27.2 (2025-01-22)
=== Fixes
* Fixes issues where server mode message decoding might result in null pointer exceptions (https://github.com/apple/pkl/pull/853[#853], https://github.com/apple/pkl/pull/882[#882]).
* Fixes an issue where the test report outputs decimal numbers using local-specific decimals (https://github.com/apple/pkl/pull/868[#868]).
* Fixes an issue where the native executables might not run on some environments, resulting in an error like "Fatal error: Failed to create the main Isolate" (https://github.com/apple/pkl/pull/875[#875]).
=== Contributors ❤️
Thank you to all the contributors for this release!
* link:https://github.com/HT154[@HT154]
* link:https://github.com/StefMa[@StefMa]
[[release-0.27.1]] [[release-0.27.1]]
== 0.27.1 (2024-12-06) == 0.27.1 (2024-12-06)
@@ -1,5 +1,8 @@
= Release Notes = Release Notes
The Pkl team aims to release a new version of Pkl in February, June, and October of each year.
* xref:0.28.adoc[0.28 Release Notes]
* xref:0.27.adoc[0.27 Release Notes] * xref:0.27.adoc[0.27 Release Notes]
* xref:0.26.adoc[0.26 Release Notes] * xref:0.26.adoc[0.26 Release Notes]
* xref:0.25.adoc[0.25 Release Notes] * xref:0.25.adoc[0.25 Release Notes]
+1 -1
View File
@@ -12,7 +12,7 @@ XXX
The next release (XXX) is scheduled for XXX (e.g., August 2, 2021). The next release (XXX) is scheduled for XXX (e.g., August 2, 2021).
Please send feedback and questions to https://github.com/apple/pkl/discussions[GitHub Discussions], or submit an issue on https://github.com/apple/pkl/issues/new[Github]. + Please send feedback and questions to https://github.com/apple/pkl/discussions[GitHub Discussions], or submit an issue on https://github.com/apple/pkl/issues/new[GitHub]. +
[small]#Pkl is hosted on https://github.com/apple/pkl[GitHub]. [small]#Pkl is hosted on https://github.com/apple/pkl[GitHub].
To get started, follow xref:pkl-cli:index.adoc#installation[Installation].# To get started, follow xref:pkl-cli:index.adoc#installation[Installation].#
+1 -1
View File
@@ -356,7 +356,7 @@ myString = #"foo \ bar \ baz"#
myString = "foo \\ bar \\ baz" myString = "foo \\ bar \\ baz"
---- ----
NOTE: Sometimes, using custom string delimiters makes source code harder to read. For example, the `+\#+` literal reads better using escapes (`"\\#"`) than using custom string delimimters (`+##"\#"##+`). NOTE: Sometimes, using custom string delimiters makes source code harder to read. For example, the `+\#+` literal reads better using escapes (`"\\#"`) than using custom string delimiters (`+##"\#"##+`).
=== Interpolation === Interpolation
+3
View File
@@ -38,7 +38,10 @@
* xref:ROOT:examples.adoc[Examples] * xref:ROOT:examples.adoc[Examples]
* xref:ROOT:evolution-and-roadmap.adoc[Evolution and Roadmap]
* xref:release-notes:index.adoc[Release Notes] * xref:release-notes:index.adoc[Release Notes]
** xref:release-notes:0.28.adoc[0.28 Release Notes]
** xref:release-notes:0.27.adoc[0.27 Release Notes] ** xref:release-notes:0.27.adoc[0.27 Release Notes]
** xref:release-notes:0.26.adoc[0.26 Release Notes] ** xref:release-notes:0.26.adoc[0.26 Release Notes]
** xref:release-notes:0.25.adoc[0.25 Release Notes] ** xref:release-notes:0.25.adoc[0.25 Release Notes]
+9 -9
View File
@@ -16,15 +16,14 @@ import org.pkl.core.Loggers
import org.pkl.core.SecurityManagers import org.pkl.core.SecurityManagers
import org.pkl.core.StackFrameTransformers import org.pkl.core.StackFrameTransformers
import org.pkl.core.module.ModuleKeyFactories import org.pkl.core.module.ModuleKeyFactories
import org.pkl.core.parser.LexParseException
import org.pkl.core.parser.Parser
import org.pkl.core.parser.antlr.PklParser
import org.pkl.core.repl.ReplRequest import org.pkl.core.repl.ReplRequest
import org.pkl.core.repl.ReplResponse import org.pkl.core.repl.ReplResponse
import org.pkl.core.repl.ReplServer import org.pkl.core.repl.ReplServer
import org.pkl.core.util.IoUtils import org.pkl.core.util.IoUtils
import org.antlr.v4.runtime.ParserRuleContext
import org.pkl.core.http.HttpClient import org.pkl.core.http.HttpClient
import org.pkl.core.parser.Parser
import org.pkl.core.parser.ParserError
import org.pkl.core.parser.syntax.ClassProperty
import org.pkl.core.resource.ResourceReaders import org.pkl.core.resource.ResourceReaders
import java.nio.file.Files import java.nio.file.Files
import kotlin.io.path.isDirectory import kotlin.io.path.isDirectory
@@ -38,7 +37,7 @@ class DocSnippetTestsEngine : HierarchicalTestEngine<DocSnippetTestsEngine.Execu
private val projectDir = rootProjectDir.resolve("docs") private val projectDir = rootProjectDir.resolve("docs")
private val docsDir = projectDir.resolve("modules") private val docsDir = projectDir.resolve("modules")
companion object { private companion object {
val headingRegex = Regex("""(?u)^\s*(=++)\s*(.+)""") val headingRegex = Regex("""(?u)^\s*(=++)\s*(.+)""")
val collapsibleBlockRegex = Regex("""(?u)^\s*\[%collapsible""") val collapsibleBlockRegex = Regex("""(?u)^\s*\[%collapsible""")
val codeBlockRegex = Regex("""(?u)^\s*\[source(?:%(tested|parsed)(%error)?)?(?:,\{?([a-zA-Z-_]+)}?)?""") val codeBlockRegex = Regex("""(?u)^\s*\[source(?:%(tested|parsed)(%error)?)?(?:,\{?([a-zA-Z-_]+)}?)?""")
@@ -150,6 +149,7 @@ class DocSnippetTestsEngine : HierarchicalTestEngine<DocSnippetTestsEngine.Execu
} }
} }
@Suppress("DEPRECATION")
private fun parseAsciidoc(docDescriptor: Descriptor.Path, selectors: List<UniqueIdSelector>) { private fun parseAsciidoc(docDescriptor: Descriptor.Path, selectors: List<UniqueIdSelector>) {
var line = "" var line = ""
var prevLine = "" var prevLine = ""
@@ -302,7 +302,7 @@ class DocSnippetTestsEngine : HierarchicalTestEngine<DocSnippetTestsEngine.Execu
override fun getType() = Type.TEST override fun getType() = Type.TEST
private val parsed: ParserRuleContext by lazy { private val parsed: org.pkl.core.parser.syntax.Node by lazy {
when (language) { when (language) {
"pkl" -> Parser().parseModule(code) "pkl" -> Parser().parseModule(code)
"pkl-expr" -> Parser().parseExpressionInput(code) "pkl-expr" -> Parser().parseExpressionInput(code)
@@ -317,7 +317,7 @@ class DocSnippetTestsEngine : HierarchicalTestEngine<DocSnippetTestsEngine.Execu
if (expectError) { if (expectError) {
throw AssertionError("Expected a parse error, but got none.") throw AssertionError("Expected a parse error, but got none.")
} }
} catch (e: LexParseException) { } catch (e: ParserError) {
if (!expectError) { if (!expectError) {
throw AssertionError(e.message) throw AssertionError(e.message)
} }
@@ -334,7 +334,7 @@ class DocSnippetTestsEngine : HierarchicalTestEngine<DocSnippetTestsEngine.Execu
) )
) )
val properties = parsed.children.filterIsInstance<PklParser.ClassPropertyContext>() val properties = parsed.children()?.filterIsInstance<ClassProperty>() ?: emptyList()
val responses = mutableListOf<ReplResponse>() val responses = mutableListOf<ReplResponse>()
@@ -343,7 +343,7 @@ class DocSnippetTestsEngine : HierarchicalTestEngine<DocSnippetTestsEngine.Execu
responses.addAll(context.replServer.handleRequest( responses.addAll(context.replServer.handleRequest(
ReplRequest.Eval( ReplRequest.Eval(
"snippet", "snippet",
prop.Identifier().text, prop.name.value,
false, false,
true true
) )
+3 -1
View File
@@ -1,10 +1,11 @@
# suppress inspection "UnusedProperty" for whole file # suppress inspection "UnusedProperty" for whole file
group=org.pkl-lang group=org.pkl-lang
version=0.27.1 version=0.28.0
# google-java-format requires jdk.compiler exports # google-java-format requires jdk.compiler exports
org.gradle.jvmargs= \ org.gradle.jvmargs= \
-XX:+UseParallelGC \
-Dfile.encoding=UTF-8 \ -Dfile.encoding=UTF-8 \
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
@@ -15,4 +16,5 @@ org.gradle.jvmargs= \
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.caching=true org.gradle.caching=true
kotlin.stdlib.default.dependency=false kotlin.stdlib.default.dependency=false
kotlin.daemon.jvmargs=-XX:+UseParallelGC
#org.gradle.workers.max=1 #org.gradle.workers.max=1
+20 -22
View File
@@ -2,23 +2,23 @@
antlr = "4.+" antlr = "4.+"
assertj = "3.+" assertj = "3.+"
checksumPlugin = "1.4.0" checksumPlugin = "1.4.0"
clikt = "3.+" clikt = "5.+"
commonMark = "0.+" commonMark = "0.+"
downloadTaskPlugin = "5.6.0" downloadTaskPlugin = "5.6.0"
geantyref = "1.+" geantyref = "1.+"
googleJavaFormat = "1.21.0" googleJavaFormat = "1.25.2"
# must not use `+` because used in download URL # must not use `+` because used in download URL
# 23.1.x requires JDK 20+ # 23.1.x requires JDK 20+
graalVm = "23.0.6" graalVm = "24.1.2"
graalVmJdkVersion = "17.0.12" graalVmJdkVersion = "21.0.5"
# slightly hacky but convenient place so we remember to update the checksum # slightly hacky but convenient place so we remember to update the checksum
graalVmSha256-macos-x64 = "3ecac1471f3fa95a56c5b75c65db9e60ac4551f56eda09eb9da95e6049ea77d7" graalVmSha256-macos-x64 = "2d9b09e28bc1bb6ff219bf62eacc4626c7740b4f1829ede9ea4450f33e9c0826"
graalVmSha256-macos-aarch64 = "4cdfdc6c9395f6773efcd191b6605f1b7c8e1b78ab900ab5cff34720a3feffc5" graalVmSha256-macos-aarch64 = "cb68cb2c796f42f37a56fcd1385d8b86cca12e0b46c5618a5ed3ec7dd2260f6f"
graalVmSha256-linux-x64 = "b6f3dace24cf1960ec790216f4c86f00d4f43df64e4e8b548f6382f04894713f" graalVmSha256-linux-x64 = "c1960d4f9d278458bde1cd15115ac2f0b3240cb427d51cfeceb79dab91a7f5c9"
graalVmSha256-linux-aarch64 = "bd991d486b92deb74337b881e0f13a764c9c1e90fc358819080f7321fa5175e8" graalVmSha256-linux-aarch64 = "3ad68fbb2d13da528dfa0aea9e9345383245ec9c31094dce3905cefba9aac01e"
graalVmSha256-windows-x64 = "8b978e56dddc0edc60db99794b56975740d9c52293b31549cfc3f7516fc18b43" graalVmSha256-windows-x64 = "d5784cbdc87f84b5cbd6c9d09c6f1d4611954f139fcfc795005c58dffd7f6b41"
ideaExtPlugin = "1.1.9" ideaExtPlugin = "1.1.9"
javaPoet = "1.+" javaPoet = "0.+"
javaxInject = "1" javaxInject = "1"
jansi = "2.+" jansi = "2.+"
jimfs = "1.+" jimfs = "1.+"
@@ -29,14 +29,12 @@ jmh = "1.+"
jmhPlugin = "0.7.2" jmhPlugin = "0.7.2"
jsr305 = "3.+" jsr305 = "3.+"
junit = "5.+" junit = "5.+"
kotlin = "1.7.10" kotlin = "2.0.21"
# 1.7+ generates much more verbose code # 1.7+ generates much more verbose code
kotlinPoet = "1.6.+" kotlinPoet = "1.6.+"
# freeze until updating Kotlin version kotlinxHtml = "0.11.0"
kotlinxHtml = "0.8.1" kotlinxSerialization = "1.8.0"
# freeze until updating Kotlin version ktfmt = "0.53"
kotlinxSerialization = "1.5.1"
ktfmt = "0.44"
# replaces nuValidator's log4j dependency # replaces nuValidator's log4j dependency
# something related to log4j-1.2-api is apparently broken in 2.17.2 # something related to log4j-1.2-api is apparently broken in 2.17.2
log4j = "2.17.1" log4j = "2.17.1"
@@ -46,9 +44,7 @@ nuValidator = "20.+"
paguro = "3.+" paguro = "3.+"
shadowPlugin = "8.1.1" shadowPlugin = "8.1.1"
slf4j = "1.+" slf4j = "1.+"
# snakeYaml 2.6 removed DumpSettingsBuilder::setScalarResolver, snakeYaml = "2.+"
# which is used by the external YAML renderer (org.pkl.core.YamlRenderer)
snakeYaml = "2.5"
spotlessPlugin = "6.25.0" spotlessPlugin = "6.25.0"
wiremock = "3.+" wiremock = "3.+"
@@ -57,6 +53,7 @@ antlr = { group = "com.tunnelvisionlabs", name = "antlr4", version.ref = "antlr"
antlrRuntime = { group = "com.tunnelvisionlabs", name = "antlr4-runtime", version.ref = "antlr" } antlrRuntime = { group = "com.tunnelvisionlabs", name = "antlr4-runtime", version.ref = "antlr" }
assertj = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" } assertj = { group = "org.assertj", name = "assertj-core", version.ref = "assertj" }
clikt = { group = "com.github.ajalt.clikt", name = "clikt", version.ref = "clikt" } clikt = { group = "com.github.ajalt.clikt", name = "clikt", version.ref = "clikt" }
cliktMarkdown = { group = "com.github.ajalt.clikt", name = "clikt-markdown", version.ref = "clikt" }
commonMark = { group = "org.commonmark", name = "commonmark", version.ref = "commonMark" } commonMark = { group = "org.commonmark", name = "commonmark", version.ref = "commonMark" }
commonMarkTables = { group = "org.commonmark", name = "commonmark-ext-gfm-tables", version.ref = "commonMark" } commonMarkTables = { group = "org.commonmark", name = "commonmark-ext-gfm-tables", version.ref = "commonMark" }
downloadTaskPlugin = { group = "de.undercouch", name = "gradle-download-task", version.ref = "downloadTaskPlugin" } downloadTaskPlugin = { group = "de.undercouch", name = "gradle-download-task", version.ref = "downloadTaskPlugin" }
@@ -64,7 +61,7 @@ geantyref = { group = "io.leangen.geantyref", name = "geantyref", version.ref =
graalCompiler = { group = "org.graalvm.compiler", name = "compiler", version.ref = "graalVm" } graalCompiler = { group = "org.graalvm.compiler", name = "compiler", version.ref = "graalVm" }
graalSdk = { group = "org.graalvm.sdk", name = "graal-sdk", version.ref = "graalVm" } graalSdk = { group = "org.graalvm.sdk", name = "graal-sdk", version.ref = "graalVm" }
graalJs = { group = "org.graalvm.js", name = "js", version.ref = "graalVm" } graalJs = { group = "org.graalvm.js", name = "js", version.ref = "graalVm" }
javaPoet = { group = "com.squareup", name = "javapoet", version.ref = "javaPoet" } javaPoet = { group = "com.palantir.javapoet", name = "javapoet", version.ref = "javaPoet" }
javaxInject = { group = "javax.inject", name = "javax.inject", version.ref = "javaxInject" } javaxInject = { group = "javax.inject", name = "javax.inject", version.ref = "javaxInject" }
jansi = { group = "org.fusesource.jansi", name = "jansi", version.ref = "jansi" } jansi = { group = "org.fusesource.jansi", name = "jansi", version.ref = "jansi" }
jimfs = { group = "com.google.jimfs", name = "jimfs", version.ref = "jimfs" } jimfs = { group = "com.google.jimfs", name = "jimfs", version.ref = "jimfs" }
@@ -79,8 +76,7 @@ kotlinCompilerEmbeddable = { group = "org.jetbrains.kotlin", name = "kotlin-comp
kotlinPlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } kotlinPlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
kotlinPoet = { group = "com.squareup", name = "kotlinpoet", version.ref = "kotlinPoet" } kotlinPoet = { group = "com.squareup", name = "kotlinpoet", version.ref = "kotlinPoet" }
kotlinReflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" } kotlinReflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }
kotlinScriptingCompilerEmbeddable = { group = "org.jetbrains.kotlin", name = "kotlin-scripting-compiler-embeddable", version.ref = "kotlin" } kotlinScripting = { group = "org.jetbrains.kotlin", name = "kotlin-scripting-jsr223", version.ref = "kotlin" }
kotlinScriptUtil = { group = "org.jetbrains.kotlin", name = "kotlin-script-util", version.ref = "kotlin" }
kotlinStdLib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" } kotlinStdLib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" }
kotlinxHtml = { group = "org.jetbrains.kotlinx", name = "kotlinx-html-jvm", version.ref = "kotlinxHtml" } kotlinxHtml = { group = "org.jetbrains.kotlinx", name = "kotlinx-html-jvm", version.ref = "kotlinxHtml" }
kotlinxSerializationJson = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" } kotlinxSerializationJson = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" }
@@ -98,6 +94,8 @@ spotlessPlugin = { group = "com.diffplug.spotless", name = "spotless-plugin-grad
svm = { group = "org.graalvm.nativeimage", name = "svm", version.ref = "graalVm" } svm = { group = "org.graalvm.nativeimage", name = "svm", version.ref = "graalVm" }
truffleApi = { group = "org.graalvm.truffle", name = "truffle-api", version.ref = "graalVm" } truffleApi = { group = "org.graalvm.truffle", name = "truffle-api", version.ref = "graalVm" }
truffleDslProcessor = { group = "org.graalvm.truffle", name = "truffle-dsl-processor", version.ref = "graalVm" } truffleDslProcessor = { group = "org.graalvm.truffle", name = "truffle-dsl-processor", version.ref = "graalVm" }
truffleSvm = { group = "org.graalvm.nativeimage", name = "truffle-runtime-svm", version.ref = "graalVm" }
truffleRuntime = { group = "org.graalvm.truffle", name = "truffle-runtime", version.ref = "graalVm" }
wiremock = { group = "org.wiremock", name = "wiremock", version.ref = "wiremock" } wiremock = { group = "org.wiremock", name = "wiremock", version.ref = "wiremock" }
[plugins] # ordered alphabetically [plugins] # ordered alphabetically
+2 -2
View File
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionSha256Sum=31c55713e40233a8303827ceb42ca48a47267a0ad4bab9177123121e71524c26 distributionSha256Sum=8d97a97984f6cbd2b85fe4c60a743440a347544bf18818048e611f5288d46c94
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
Vendored
+1 -2
View File
@@ -86,8 +86,7 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
+3 -3
View File
@@ -2,15 +2,15 @@
"catalogs": {}, "catalogs": {},
"aliases": { "aliases": {
"pkl": { "pkl": {
"script-ref": "org.pkl-lang:pkl-cli-java:0.27.1", "script-ref": "org.pkl-lang:pkl-cli-java:0.28.0",
"java-agents": [] "java-agents": []
}, },
"pkl-codegen-java": { "pkl-codegen-java": {
"script-ref": "org.pkl-lang:pkl-codegen-java:0.27.1", "script-ref": "org.pkl-lang:pkl-codegen-java:0.28.0",
"java-agents": [] "java-agents": []
}, },
"pkl-codegen-kotlin": { "pkl-codegen-kotlin": {
"script-ref": "org.pkl-lang:pkl-codegen-kotlin:0.27.1", "script-ref": "org.pkl-lang:pkl-codegen-kotlin:0.28.0",
"java-agents": [] "java-agents": []
} }
}, },
-30
View File
@@ -1,30 +0,0 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
net.bytebuddy:byte-buddy:1.14.16=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.6.0=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata
org.assertj:assertj-core:3.26.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.7.10=kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-reflect:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-script-runtime:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-common:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-jvm:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains:annotations:13.0=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.10.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-engine:5.10.2=testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-params:5.10.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.10.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-engine:1.10.2=testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit:junit-bom:5.10.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
empty=annotationProcessor,apiDependenciesMetadata,compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtimeClasspath,runtimeOnlyDependenciesMetadata,signatures,sourcesJar,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions
+95 -53
View File
@@ -1,38 +1,55 @@
# This is a Gradle generated file for dependency locking. # This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised. # Manual edits can break the build and are not advised.
# This file is expected to be part of source control. # This file is expected to be part of source control.
com.ethlo.time:itu:1.10.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.ethlo.time:itu:1.10.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-annotations:2.17.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.fasterxml.jackson.core:jackson-annotations:2.18.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-core:2.17.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.fasterxml.jackson.core:jackson-core:2.18.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-databind:2.17.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.fasterxml.jackson.core:jackson-databind:2.18.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.17.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.fasterxml.jackson:jackson-bom:2.17.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.fasterxml.jackson:jackson-bom:2.18.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.ajalt.clikt:clikt-jvm:3.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath com.github.ajalt.clikt:clikt-core-jvm:5.0.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ajalt.clikt:clikt:3.5.4=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.github.ajalt.clikt:clikt-core:5.0.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.ajalt.clikt:clikt-jvm:5.0.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ajalt.clikt:clikt-markdown-jvm:5.0.3=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.clikt:clikt-markdown:5.0.3=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.clikt:clikt:5.0.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.ajalt.colormath:colormath-jvm:3.6.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ajalt.colormath:colormath:3.6.0=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.ajalt.mordant:mordant-core-jvm:3.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-core:3.0.1=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-ffm-jvm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-ffm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-graal-ffi-jvm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-graal-ffi:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-jna-jvm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-jna:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm:3.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-markdown-jvm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-markdown:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant:3.0.1=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.jknack:handlebars-helpers:4.3.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.github.jknack:handlebars-helpers:4.3.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.jknack:handlebars:4.3.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.github.jknack:handlebars:4.3.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.28.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.google.errorprone:error_prone_annotations:2.36.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.google.guava:failureaccess:1.0.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.google.guava:failureaccess:1.0.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.google.guava:guava:33.3.1-jre=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.google.guava:guava:33.4.0-jre=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.google.j2objc:j2objc-annotations:3.0.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.google.j2objc:j2objc-annotations:3.0.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.jayway.jsonpath:json-path:2.9.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.jayway.jsonpath:json-path:2.9.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.networknt:json-schema-validator:1.5.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.networknt:json-schema-validator:1.5.5=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.tunnelvisionlabs:antlr4-runtime:4.9.0=runtimeClasspath,testRuntimeClasspath
commons-fileupload:commons-fileupload:1.5=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath commons-fileupload:commons-fileupload:1.5=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
commons-io:commons-io:2.11.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath commons-io:commons-io:2.11.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.14.18=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.6.0=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath net.java.dev.jna:jna:5.14.0=runtimeClasspath,testRuntimeClasspath
net.javacrumbs.json-unit:json-unit-core:2.40.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath net.javacrumbs.json-unit:json-unit-core:2.40.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.minidev:accessors-smart:2.5.1=testRuntimeClasspath net.minidev:accessors-smart:2.5.1=testRuntimeClasspath
net.minidev:json-smart:2.5.1=testRuntimeClasspath net.minidev:json-smart:2.5.1=testRuntimeClasspath
net.sf.jopt-simple:jopt-simple:5.0.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath net.sf.jopt-simple:jopt-simple:5.0.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apache.httpcomponents.client5:httpclient5:5.3.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.apache.httpcomponents.client5:httpclient5:5.4.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apache.httpcomponents.core5:httpcore5-h2:5.2.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.apache.httpcomponents.core5:httpcore5-h2:5.3.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apache.httpcomponents.core5:httpcore5:5.2.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.apache.httpcomponents.core5:httpcore5:5.3.1=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata
org.assertj:assertj-core:3.26.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.checkerframework:checker-qual:3.43.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.checkerframework:checker-qual:3.43.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.jetty.http2:http2-common:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.eclipse.jetty.http2:http2-common:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.jetty.http2:http2-hpack:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.eclipse.jetty.http2:http2-hpack:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
@@ -55,48 +72,73 @@ org.eclipse.jetty:jetty-util:11.0.24=testCompileClasspath,testImplementationDepe
org.eclipse.jetty:jetty-webapp:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.eclipse.jetty:jetty-webapp:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.eclipse.jetty:jetty-xml:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.eclipse.jetty:jetty-xml:11.0.24=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.fusesource.jansi:jansi:2.4.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.fusesource.jansi:jansi:2.4.1=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.compiler:compiler:23.0.6=compileClasspath,compileOnlyDependenciesMetadata org.graalvm.compiler:compiler:24.1.2=compileClasspath,compileOnlyDependenciesMetadata
org.graalvm.nativeimage:native-image-base:23.0.6=compileClasspath,compileOnlyDependenciesMetadata org.graalvm.nativeimage:native-image-base:24.1.2=compileClasspath,compileOnlyDependenciesMetadata
org.graalvm.nativeimage:objectfile:23.0.6=compileClasspath,compileOnlyDependenciesMetadata org.graalvm.nativeimage:objectfile:24.1.2=compileClasspath,compileOnlyDependenciesMetadata
org.graalvm.nativeimage:pointsto:23.0.6=compileClasspath,compileOnlyDependenciesMetadata org.graalvm.nativeimage:pointsto:24.1.2=compileClasspath,compileOnlyDependenciesMetadata
org.graalvm.nativeimage:svm:23.0.6=compileClasspath,compileOnlyDependenciesMetadata org.graalvm.nativeimage:svm:24.1.2=compileClasspath,compileOnlyDependenciesMetadata
org.graalvm.sdk:graal-sdk:23.0.6=compileClasspath,compileOnlyDependenciesMetadata,runtimeClasspath,testRuntimeClasspath org.graalvm.nativeimage:truffle-runtime-svm:24.1.2=compileClasspath,compileOnlyDependenciesMetadata
org.graalvm.truffle:truffle-api:23.0.6=compileClasspath,compileOnlyDependenciesMetadata,runtimeClasspath,testRuntimeClasspath org.graalvm.polyglot:polyglot:24.1.2=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:collections:24.1.2=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:24.1.2=compileClasspath,compileOnlyDependenciesMetadata,runtimeClasspath,testRuntimeClasspath
org.graalvm.sdk:jniutils:24.1.2=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:nativeimage:24.1.2=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:word:24.1.2=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.truffle:truffle-api:24.1.2=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.truffle:truffle-compiler:24.1.2=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.truffle:truffle-runtime:24.1.2=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.hamcrest:hamcrest-core:2.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.hamcrest:hamcrest-core:2.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.hamcrest:hamcrest:2.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.hamcrest:hamcrest:2.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.7.10=kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-build-tools-impl:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-reflect:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-script-runtime:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-common:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.0.21=kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-jvm:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-native-prebuilt:2.0.21=kotlinNativeBundleConfiguration
org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-script-runtime:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-scripting-common:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.jetbrains.kotlin:kotlin-stdlib:1.7.10=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.jetbrains:annotations:13.0=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.jetbrains.kotlin:kotlin-scripting-jvm:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains:markdown-jvm:0.7.3=runtimeClasspath,testRuntimeClasspath
org.jetbrains:markdown:0.7.3=runtimeClasspath,testRuntimeClasspath
org.jline:jline-native:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jline:jline-native:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jline:jline-reader:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jline:jline-reader:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jline:jline-terminal-jansi:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jline:jline-terminal-jansi:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jline:jline-terminal:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jline:jline-terminal:3.23.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.junit.jupiter:junit-jupiter-api:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-engine:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.junit.jupiter:junit-jupiter-api:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.junit.jupiter:junit-jupiter-engine:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-commons:1.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.junit.jupiter:junit-jupiter-engine:5.8.2=testJdk17RuntimeClasspath
org.junit.platform:junit-platform-engine:1.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.junit.jupiter:junit-jupiter-params:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit:junit-bom:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.junit.jupiter:junit-jupiter-params:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.jupiter:junit-jupiter:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.platform:junit-platform-commons:1.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-commons:1.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.platform:junit-platform-engine:1.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-engine:1.8.2=testJdk17RuntimeClasspath
org.junit.platform:junit-platform-launcher:1.8.2=testJdk17RuntimeClasspath
org.junit:junit-bom:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit:junit-bom:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.msgpack:msgpack-core:0.9.8=runtimeClasspath,testRuntimeClasspath org.msgpack:msgpack-core:0.9.8=runtimeClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.2.0=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.organicdesign:Paguro:3.10.3=runtimeClasspath,testRuntimeClasspath org.organicdesign:Paguro:3.10.3=runtimeClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:2.0.13=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.slf4j:slf4j-api:2.0.16=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.snakeyaml:snakeyaml-engine:2.5=runtimeClasspath,testRuntimeClasspath org.snakeyaml:snakeyaml-engine:2.9=runtimeClasspath,testRuntimeClasspath
org.wiremock:wiremock:3.9.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.wiremock:wiremock:3.11.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.xmlunit:xmlunit-core:2.10.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.xmlunit:xmlunit-core:2.10.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.xmlunit:xmlunit-legacy:2.10.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.xmlunit:xmlunit-legacy:2.10.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.xmlunit:xmlunit-placeholders:2.10.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.xmlunit:xmlunit-placeholders:2.10.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.yaml:snakeyaml:2.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.yaml:snakeyaml:2.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
empty=annotationProcessor,archives,compile,intransitiveDependenciesMetadata,javaExecutable,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtime,runtimeOnlyDependenciesMetadata,shadow,signatures,sourcesJar,stagedAlpineLinuxAmd64Executable,stagedLinuxAarch64Executable,stagedLinuxAmd64Executable,stagedMacAarch64Executable,stagedMacAmd64Executable,stagedWindowsAmd64Executable,testAnnotationProcessor,testApiDependenciesMetadata,testCompile,testCompileOnly,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions,testRuntime empty=annotationProcessor,archives,compile,intransitiveDependenciesMetadata,javaExecutable,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtime,runtimeOnlyDependenciesMetadata,shadow,signatures,sourcesJar,stagedAlpineLinuxAmd64Executable,stagedLinuxAarch64Executable,stagedLinuxAmd64Executable,stagedMacAarch64Executable,stagedMacAmd64Executable,stagedWindowsAmd64Executable,testAnnotationProcessor,testApiDependenciesMetadata,testCompile,testCompileOnly,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testJdk17AnnotationProcessor,testJdk17ApiDependenciesMetadata,testJdk17CompileOnlyDependenciesMetadata,testJdk17IntransitiveDependenciesMetadata,testJdk17KotlinScriptDefExtensions,testKotlinScriptDef,testKotlinScriptDefExtensions,testRuntime
+110 -40
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import java.io.ByteArrayOutputStream
import org.gradle.kotlin.dsl.support.serviceOf
plugins { plugins {
pklAllProjects pklAllProjects
pklKotlinLibrary pklKotlinLibrary
@@ -50,6 +53,9 @@ val stagedWindowsAmd64Executable: Configuration by configurations.creating
dependencies { dependencies {
compileOnly(libs.svm) compileOnly(libs.svm)
compileOnly(libs.truffleSvm)
implementation(libs.truffleRuntime)
compileOnly(libs.graalSdk)
// CliEvaluator exposes PClass // CliEvaluator exposes PClass
api(projects.pklCore) api(projects.pklCore)
@@ -62,11 +68,7 @@ dependencies {
implementation(libs.jlineTerminal) implementation(libs.jlineTerminal)
implementation(libs.jlineTerminalJansi) implementation(libs.jlineTerminalJansi)
implementation(projects.pklServer) implementation(projects.pklServer)
implementation(libs.clikt) { 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) testImplementation(projects.pklCommonsTest)
testImplementation(libs.wiremock) testImplementation(libs.wiremock)
@@ -82,10 +84,8 @@ dependencies {
} }
tasks.jar { tasks.jar {
manifest { attributes += mapOf("Main-Class" to "org.pkl.cli.Main") } manifest.attributes +=
mapOf("Main-Class" to "org.pkl.cli.Main", "Add-Exports" to buildInfo.jpmsExportsForJarManifest)
// not required at runtime
exclude("org/pkl/cli/svm/**")
} }
tasks.javadoc { enabled = false } tasks.javadoc { enabled = false }
@@ -96,9 +96,6 @@ tasks.shadowJar {
exclude("META-INF/maven/**") exclude("META-INF/maven/**")
exclude("META-INF/upgrade/**") exclude("META-INF/upgrade/**")
// org.antlr.v4.runtime.misc.RuleDependencyProcessor
exclude("META-INF/services/javax.annotation.processing.Processor")
exclude("module-info.*") exclude("module-info.*")
} }
@@ -126,38 +123,100 @@ val testJavaExecutable by
(configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get()) (configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get())
} }
tasks.check { dependsOn(testJavaExecutable) } // Setup `testJavaExecutable` tasks for multi-JDK testing.
val testJavaExecutableOnOtherJdks =
if (buildInfo.multiJdkTesting) {
buildInfo.multiJdkTestingWith(testJavaExecutable)
} else {
emptyList()
}
// 0.14 Java executable was broken because javaExecutable.jvmArgs wasn't commented out. // Prepare a run of the fat JAR, optionally with a specific Java launcher.
// To catch this and similar problems, test that Java executable starts successfully. private fun setupJavaExecutableRun(
val testStartJavaExecutable by name: String,
tasks.registering(Exec::class) { args: Array<String>,
launcher: Provider<JavaLauncher>? = null,
configurator: Exec.() -> Unit = {},
) =
tasks.register(name, Exec::class) {
dependsOn(javaExecutable) dependsOn(javaExecutable)
val outputFile = val outputFile = layout.buildDirectory.file(name) // dummy output to satisfy up-to-date check
layout.buildDirectory.file(
"testStartJavaExecutable"
) // dummy output to satisfy up-to-date check
outputs.file(outputFile) outputs.file(outputFile)
if (buildInfo.os.isWindows) { executable =
executable = "java" when (launcher) {
args("-jar", javaExecutable.get().outputs.files.singleFile.toString(), "--version") null -> "java"
} else { else -> launcher.get().executablePath.asFile.absolutePath
executable = javaExecutable.get().outputs.files.singleFile.toString()
args("--version")
} }
args("-jar", javaExecutable.get().outputs.files.singleFile.toString(), *args)
doFirst { outputFile.get().asFile.delete() } doFirst { outputFile.get().asFile.delete() }
doLast { outputFile.get().asFile.writeText("OK") } doLast { outputFile.get().asFile.writeText("OK") }
configurator()
} }
tasks.check { dependsOn(testStartJavaExecutable) } // 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
setupJavaExecutableRun("testStartJavaExecutable", arrayOf("--version"))
// Setup `testStartJavaExecutable` tasks for multi-JDK testing.
val testStartJavaExecutableOnOtherJdks =
if (buildInfo.multiJdkTesting) {
buildInfo.jdkTestRange.map { jdkTarget ->
setupJavaExecutableRun(
"testStartJavaExecutableJdk${jdkTarget.asInt()}",
arrayOf("--version"),
serviceOf<JavaToolchainService>().launcherFor { languageVersion = jdkTarget },
)
}
} else {
emptyList()
}
val evalTestFlags = arrayOf("eval", "-x", "1 + 1", "pkl:base")
fun Exec.useRootDirAndSuppressOutput() {
workingDir = rootProject.layout.projectDirectory.asFile
standardOutput = ByteArrayOutputStream() // we only care that this exec doesn't fail
}
// 0.28 Preparing for JDK21 toolchains revealed that `testStartJavaExecutable` may pass, even though
// the evaluator fails. To catch this, we need to test the evaluator. We render the CircleCI config
// as a realistic test of the fat JAR.
val testEvalJavaExecutable by
setupJavaExecutableRun("testEvalJavaExecutable", evalTestFlags) { useRootDirAndSuppressOutput() }
// Run the same evaluator tests on all configured JDK test versions.
val testEvalJavaExecutableOnOtherJdks =
buildInfo.jdkTestRange.map { jdkTarget ->
setupJavaExecutableRun(
"testEvalJavaExecutableJdk${jdkTarget.asInt()}",
evalTestFlags,
serviceOf<JavaToolchainService>().launcherFor { languageVersion = jdkTarget },
) {
useRootDirAndSuppressOutput()
}
}
tasks.check {
dependsOn(
testJavaExecutable,
testStartJavaExecutable,
testJavaExecutableOnOtherJdks,
testStartJavaExecutableOnOtherJdks,
testEvalJavaExecutable,
testEvalJavaExecutableOnOtherJdks,
)
}
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(),
) { ) {
inputs inputs
.files(sourceSets.main.map { it.output }) .files(sourceSets.main.map { it.output })
@@ -179,11 +238,13 @@ fun Exec.configureExecutable(
executable = "${graalVm.baseDir}/bin/$nativeImageCommandName" executable = "${graalVm.baseDir}/bin/$nativeImageCommandName"
// JARs to exclude from the class path for the native-image build. // JARs to exclude from the class path for the native-image build.
val exclusions = listOf(libs.truffleApi, libs.graalSdk).map { it.get().module.name } val exclusions = listOf(libs.graalSdk).map { it.get().module.name }
// https://www.graalvm.org/22.0/reference-manual/native-image/Options/ // https://www.graalvm.org/22.0/reference-manual/native-image/Options/
argumentProviders.add( argumentProviders.add(
CommandLineArgumentProvider { CommandLineArgumentProvider {
buildList { buildList {
// must be emitted before any experimental options are used
add("-H:+UnlockExperimentalVMOptions")
// currently gives a deprecation warning, but we've been told // currently gives a deprecation warning, but we've been told
// that the "initialize everything at build time" *CLI* option is likely here to stay // that the "initialize everything at build time" *CLI* option is likely here to stay
add("--initialize-at-build-time=") add("--initialize-at-build-time=")
@@ -194,9 +255,9 @@ fun Exec.configureExecutable(
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("-H:IncludeResources=org/pkl/commons/cli/PklCARoots.pem")
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("-o")
add(outputFile.get().asFile.name)
// the actual limit (currently) used by native-image is this number + 1400 (idea is to // the actual limit (currently) used by native-image is this number + 1400 (idea is to
// compensate for Truffle's own nodes) // compensate for Truffle's own nodes)
add("-H:MaxRuntimeCompileMethods=1800") add("-H:MaxRuntimeCompileMethods=1800")
@@ -211,7 +272,11 @@ fun Exec.configureExecutable(
if (!buildInfo.isReleaseBuild) { if (!buildInfo.isReleaseBuild) {
add("-Ob") add("-Ob")
} }
if (buildInfo.isNativeArch) {
add("-march=native")
} else {
add("-march=compatibility") 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 = val pathInput =
@@ -240,7 +305,7 @@ val macExecutableAmd64: TaskProvider<Exec> by
dependsOn(":installGraalVmAmd64") dependsOn(":installGraalVmAmd64")
configureExecutable( configureExecutable(
buildInfo.graalVmAmd64, buildInfo.graalVmAmd64,
layout.buildDirectory.file("executable/pkl-macos-amd64") layout.buildDirectory.file("executable/pkl-macos-amd64"),
) )
} }
@@ -251,7 +316,7 @@ val macExecutableAarch64: TaskProvider<Exec> by
configureExecutable( configureExecutable(
buildInfo.graalVmAarch64, buildInfo.graalVmAarch64,
layout.buildDirectory.file("executable/pkl-macos-aarch64"), layout.buildDirectory.file("executable/pkl-macos-aarch64"),
listOf("-H:+AllowDeprecatedBuilderClassesOnImageClasspath") listOf("-H:+AllowDeprecatedBuilderClassesOnImageClasspath"),
) )
} }
@@ -261,7 +326,7 @@ val linuxExecutableAmd64: TaskProvider<Exec> by
dependsOn(":installGraalVmAmd64") dependsOn(":installGraalVmAmd64")
configureExecutable( configureExecutable(
buildInfo.graalVmAmd64, buildInfo.graalVmAmd64,
layout.buildDirectory.file("executable/pkl-linux-amd64") layout.buildDirectory.file("executable/pkl-linux-amd64"),
) )
} }
@@ -276,7 +341,12 @@ val linuxExecutableAarch64: TaskProvider<Exec> by
dependsOn(":installGraalVmAarch64") dependsOn(":installGraalVmAarch64")
configureExecutable( configureExecutable(
buildInfo.graalVmAarch64, buildInfo.graalVmAarch64,
layout.buildDirectory.file("executable/pkl-linux-aarch64") layout.buildDirectory.file("executable/pkl-linux-aarch64"),
listOf(
// Ensure compatibility for kernels with page size set to 4k, 16k and 64k
// (e.g. Raspberry Pi 5, Asahi Linux)
"-H:PageSize=65536"
),
) )
} }
@@ -292,7 +362,7 @@ val alpineExecutableAmd64: TaskProvider<Exec> by
configureExecutable( configureExecutable(
buildInfo.graalVmAmd64, buildInfo.graalVmAmd64,
layout.buildDirectory.file("executable/pkl-alpine-linux-amd64"), layout.buildDirectory.file("executable/pkl-alpine-linux-amd64"),
listOf("--static", "--libc=musl") listOf("--static", "--libc=musl"),
) )
} }
@@ -302,7 +372,7 @@ val windowsExecutableAmd64: TaskProvider<Exec> by
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") listOf("-Dfile.encoding=UTF-8"),
) )
} }
@@ -358,7 +428,7 @@ publishing {
description.set( description.set(
""" """
Pkl CLI executable for Java. 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. Can be executed directly, or with `java -jar <path/to/jpkl>`.
Requires Java 17 or higher. Requires Java 17 or higher.
""" """
.trimIndent() .trimIndent()
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -21,15 +21,15 @@ import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.truffle.TruffleFeature; import com.oracle.svm.truffle.TruffleFeature;
import java.util.Map; import java.util.Map;
import org.pkl.core.ast.builder.AstBuilder;
/** /**
* Workaround to prevent the native-image build error "Detected a started Thread in the image * Workaround to prevent the native-image build error "Detected a started Thread in the image
* heap.". The cause of this error is the use of {@link org.graalvm.polyglot.Context} in the * heap.". The cause of this error is the use of {@link org.graalvm.polyglot.Context} in the
* (intentionally) statically reachable class {@link org.pkl.core.runtime.StdLibModule}. * (intentionally) statically reachable class {@link org.pkl.core.runtime.StdLibModule}.
* *
* <p>A cleaner solution would be to have a separate {@link org.pkl.core.ast.builder.AstBuilder} for * <p>A cleaner solution would be to have a separate {@link AstBuilder} for stdlib modules that
* stdlib modules that produces a fully initialized module object without executing any Truffle * produces a fully initialized module object without executing any Truffle nodes.
* nodes.
* *
* <p>This class is automatically discovered by native-image; no registration is required. * <p>This class is automatically discovered by native-image; no registration is required.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -21,11 +21,11 @@ import java.io.Writer
import java.net.URI import java.net.URI
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.StandardOpenOption import java.nio.file.StandardOpenOption
import kotlin.io.path.createParentDirectories
import kotlin.io.path.exists import kotlin.io.path.exists
import kotlin.io.path.isDirectory import kotlin.io.path.isDirectory
import org.pkl.commons.cli.CliCommand import org.pkl.commons.cli.CliCommand
import org.pkl.commons.cli.CliException import org.pkl.commons.cli.CliException
import org.pkl.commons.createParentDirectories
import org.pkl.commons.currentWorkingDir import org.pkl.commons.currentWorkingDir
import org.pkl.commons.writeString import org.pkl.commons.writeString
import org.pkl.core.Closeables import org.pkl.core.Closeables
@@ -165,13 +165,13 @@ constructor(
options.moduleOutputSeparator + '\n', options.moduleOutputSeparator + '\n',
Charsets.UTF_8, Charsets.UTF_8,
StandardOpenOption.WRITE, StandardOpenOption.WRITE,
StandardOpenOption.APPEND StandardOpenOption.APPEND,
) )
outputFile.writeString( outputFile.writeString(
output, output,
Charsets.UTF_8, Charsets.UTF_8,
StandardOpenOption.WRITE, StandardOpenOption.WRITE,
StandardOpenOption.APPEND StandardOpenOption.APPEND,
) )
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -80,6 +80,6 @@ data class CliEvaluatorOptions(
) { ) {
companion object { companion object {
val defaults = CliEvaluatorOptions(CliBaseOptions()) val defaults: CliEvaluatorOptions = CliEvaluatorOptions(CliBaseOptions())
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
package org.pkl.cli package org.pkl.cli
import java.io.Writer import java.io.Writer
import kotlin.io.path.createParentDirectories
import org.pkl.commons.cli.CliCommand import org.pkl.commons.cli.CliCommand
import org.pkl.commons.createParentDirectories
import org.pkl.commons.writeString import org.pkl.commons.writeString
import org.pkl.core.Closeables import org.pkl.core.Closeables
import org.pkl.core.ModuleSource import org.pkl.core.ModuleSource
@@ -26,7 +26,7 @@ class CliImportAnalyzer
@JvmOverloads @JvmOverloads
constructor( constructor(
private val options: CliImportAnalyzerOptions, private val options: CliImportAnalyzerOptions,
private val consoleWriter: Writer = System.out.writer() private val consoleWriter: Writer = System.out.writer(),
) : CliCommand(options.base) { ) : CliCommand(options.base) {
override fun doRun() { override fun doRun() {
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@ import org.pkl.core.packages.PackageUri
class CliPackageDownloader( class CliPackageDownloader(
baseOptions: CliBaseOptions, baseOptions: CliBaseOptions,
private val packageUris: List<PackageUri>, private val packageUris: List<PackageUri>,
private val noTransitive: Boolean private val noTransitive: Boolean,
) : CliCommand(baseOptions) { ) : CliCommand(baseOptions) {
override fun doRun() { override fun doRun() {
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -32,11 +32,11 @@ class CliProjectPackager(
private val outputPath: String, private val outputPath: String,
private val skipPublishCheck: Boolean, private val skipPublishCheck: Boolean,
private val consoleWriter: Writer = System.out.writer(), private val consoleWriter: Writer = System.out.writer(),
private val errWriter: Writer = System.err.writer() private val errWriter: Writer = System.err.writer(),
) : CliProjectCommand(baseOptions, projectDirs) { ) : CliProjectCommand(baseOptions, projectDirs) {
private fun runApiTests(project: Project) { private fun runApiTests(project: Project) {
val apiTests = project.`package`!!.apiTests val apiTests = project.`package`!!.apiTests()
if (apiTests.isEmpty()) return if (apiTests.isEmpty()) return
val normalizeApiTests = apiTests.map { project.projectDir.resolve(it).toUri() } val normalizeApiTests = apiTests.map { project.projectDir.resolve(it).toUri() }
val testRunner = val testRunner =
@@ -49,7 +49,7 @@ class CliProjectPackager(
try { try {
testRunner.run() testRunner.run()
} catch (e: CliTestException) { } catch (e: CliTestException) {
throw CliException(ErrorMessages.create("packageTestsFailed", project.`package`!!.uri)) throw CliException(ErrorMessages.create("packageTestsFailed", project.`package`!!.uri()))
} }
} }
@@ -67,8 +67,8 @@ class CliProjectPackager(
} }
// Require that all local projects are included // Require that all local projects are included
projects.forEach { proj -> projects.forEach { proj ->
proj.dependencies.localDependencies.values.forEach { localDep -> proj.dependencies.localDependencies().values.forEach { localDep ->
val projectDir = Path.of(localDep.projectFileUri).parent val projectDir = Path.of(localDep.projectFileUri()).parent
if (projects.none { it.projectDir == projectDir }) { if (projects.none { it.projectDir == projectDir }) {
throw CliException( throw CliException(
ErrorMessages.create("missingProjectInPackageCommand", proj.projectDir, projectDir) ErrorMessages.create("missingProjectInPackageCommand", proj.projectDir, projectDir)
@@ -85,7 +85,7 @@ class CliProjectPackager(
securityManager, securityManager,
httpClient, httpClient,
skipPublishCheck, skipPublishCheck,
consoleWriter consoleWriter,
) )
.createPackages() .createPackages()
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@ class CliProjectResolver(
baseOptions: CliBaseOptions, baseOptions: CliBaseOptions,
projectDirs: List<Path>, projectDirs: List<Path>,
private val consoleWriter: Writer = System.out.writer(), private val consoleWriter: Writer = System.out.writer(),
private val errWriter: Writer = System.err.writer() private val errWriter: Writer = System.err.writer(),
) : CliProjectCommand(baseOptions, projectDirs) { ) : CliProjectCommand(baseOptions, projectDirs) {
override fun doRun() { override fun doRun() {
for (projectFile in normalizedProjectFiles) { for (projectFile in normalizedProjectFiles) {
@@ -38,10 +38,10 @@ class CliProjectResolver(
allowedModules, allowedModules,
allowedResources, allowedResources,
SecurityManagers.defaultTrustLevels, SecurityManagers.defaultTrustLevels,
rootDir rootDir,
), ),
httpClient, httpClient,
moduleCacheDir moduleCacheDir,
) )
val dependencies = ProjectDependenciesResolver(project, packageResolver, errWriter).resolve() val dependencies = ProjectDependenciesResolver(project, packageResolver, errWriter).resolve()
val depsFile = val depsFile =
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -34,13 +34,13 @@ internal class CliRepl(private val options: CliEvaluatorOptions) : CliCommand(op
allowedModules, allowedModules,
allowedResources, allowedResources,
SecurityManagers.defaultTrustLevels, SecurityManagers.defaultTrustLevels,
rootDir rootDir,
), ),
httpClient, httpClient,
Loggers.stdErr(), Loggers.stdErr(),
listOf( listOf(
ModuleKeyFactories.standardLibrary, ModuleKeyFactories.standardLibrary,
ModuleKeyFactories.modulePath(modulePathResolver) ModuleKeyFactories.modulePath(modulePathResolver),
) + ) +
ModuleKeyFactories.fromServiceProviders() + ModuleKeyFactories.fromServiceProviders() +
listOf( listOf(
@@ -48,7 +48,7 @@ internal class CliRepl(private val options: CliEvaluatorOptions) : CliCommand(op
ModuleKeyFactories.http, ModuleKeyFactories.http,
ModuleKeyFactories.pkg, ModuleKeyFactories.pkg,
ModuleKeyFactories.projectpackage, ModuleKeyFactories.projectpackage,
ModuleKeyFactories.genericUrl ModuleKeyFactories.genericUrl,
), ),
listOf( listOf(
ResourceReaders.environmentVariable(), ResourceReaders.environmentVariable(),
@@ -58,7 +58,7 @@ internal class CliRepl(private val options: CliEvaluatorOptions) : CliCommand(op
ResourceReaders.http(), ResourceReaders.http(),
ResourceReaders.https(), ResourceReaders.https(),
ResourceReaders.pkg(), ResourceReaders.pkg(),
ResourceReaders.projectpackage() ResourceReaders.projectpackage(),
), ),
environmentVariables, environmentVariables,
externalProperties, externalProperties,
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import org.pkl.core.messaging.ProtocolException
import org.pkl.server.Server import org.pkl.server.Server
class CliServer(options: CliBaseOptions) : CliCommand(options) { class CliServer(options: CliBaseOptions) : CliCommand(options) {
override fun doRun() = override fun doRun(): Unit =
try { try {
val server = Server.stream(System.`in`, System.out) val server = Server.stream(System.`in`, System.out)
server.use { it.start() } server.use { it.start() }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ constructor(
private val options: CliBaseOptions, private val options: CliBaseOptions,
private val testOptions: CliTestOptions, private val testOptions: CliTestOptions,
private val consoleWriter: Writer = System.out.writer(), private val consoleWriter: Writer = System.out.writer(),
private val errWriter: Writer = System.err.writer() private val errWriter: Writer = System.err.writer(),
) : CliCommand(options) { ) : CliCommand(options) {
override fun doRun() { override fun doRun() {
@@ -51,9 +51,9 @@ constructor(
// keep in sync with error message thrown by clikt // keep in sync with error message thrown by clikt
throw CliException( throw CliException(
""" """
Usage: pkl test [OPTIONS] <modules>... Usage: pkl test [<options>] <modules>...
Error: Missing argument "<modules>" Error: missing argument <modules>
""" """
.trimIndent() .trimIndent()
) )
+3 -18
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,26 +17,11 @@
package org.pkl.cli package org.pkl.cli
import com.github.ajalt.clikt.core.subcommands import com.github.ajalt.clikt.core.main
import org.pkl.cli.commands.* import org.pkl.cli.commands.*
import org.pkl.commons.cli.cliMain import org.pkl.commons.cli.cliMain
import org.pkl.core.Release
/** Main method of the Pkl CLI (command-line evaluator and REPL). */ /** Main method of the Pkl CLI (command-line evaluator and REPL). */
internal fun main(args: Array<String>) { internal fun main(args: Array<String>) {
cliMain { cliMain { RootCommand().main(args) }
val version = Release.current().versionInfo()
val helpLink = "${Release.current().documentation().homepage()}pkl-cli/index.html#usage"
RootCommand("pkl", version, helpLink)
.subcommands(
EvalCommand(helpLink),
ReplCommand(helpLink),
ServerCommand(helpLink),
TestCommand(helpLink),
ProjectCommand(helpLink),
DownloadPackageCommand(helpLink),
AnalyzeCommand(helpLink),
)
.main(args)
}
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/ */
package org.pkl.cli.commands package org.pkl.cli.commands
import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.core.NoOpCliktCommand import com.github.ajalt.clikt.core.NoOpCliktCommand
import com.github.ajalt.clikt.core.subcommands import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.options.option
@@ -25,29 +26,24 @@ import org.pkl.cli.CliImportAnalyzerOptions
import org.pkl.commons.cli.commands.ModulesCommand import org.pkl.commons.cli.commands.ModulesCommand
import org.pkl.commons.cli.commands.single import org.pkl.commons.cli.commands.single
class AnalyzeCommand(helpLink: String) : class AnalyzeCommand : NoOpCliktCommand(name = "analyze") {
NoOpCliktCommand( override fun help(context: Context) = "Commands related to static analysis"
name = "analyze",
help = "Commands related to static analysis", override fun helpEpilog(context: Context) = "For more information, visit $helpLink"
epilog = "For more information, visit $helpLink"
) {
init { init {
subcommands(AnalyzeImportsCommand(helpLink)) subcommands(AnalyzeImportsCommand())
}
} }
companion object { class AnalyzeImportsCommand : ModulesCommand(name = "imports", helpLink = helpLink) {
class AnalyzeImportsCommand(helpLink: String) : override val helpString = "Prints the graph of modules imported by the input module(s)."
ModulesCommand(
name = "imports",
helpLink = helpLink,
help = "Prints the the graph of modules imported by the input module(s)."
) {
private val outputPath: Path? by private val outputPath: Path? by
option( option(
names = arrayOf("-o", "--output-path"), names = arrayOf("-o", "--output-path"),
metavar = "<path>", metavar = "path",
help = "File path where the output file is placed." help = "File path where the output file is placed.",
) )
.path() .path()
.single() .single()
@@ -57,10 +53,8 @@ class AnalyzeCommand(helpLink: String) :
CliImportAnalyzerOptions( CliImportAnalyzerOptions(
base = baseOptions.baseOptions(modules, projectOptions), base = baseOptions.baseOptions(modules, projectOptions),
outputFormat = baseOptions.format, outputFormat = baseOptions.format,
outputPath = outputPath outputPath = outputPath,
) )
CliImportAnalyzer(options).run() CliImportAnalyzer(options).run()
} }
} }
}
}
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,11 +27,8 @@ import org.pkl.commons.cli.commands.ProjectOptions
import org.pkl.commons.cli.commands.single import org.pkl.commons.cli.commands.single
import org.pkl.core.packages.PackageUri import org.pkl.core.packages.PackageUri
class DownloadPackageCommand(helpLink: String) : class DownloadPackageCommand : BaseCommand(name = "download-package", helpLink = helpLink) {
BaseCommand( override val helpString =
name = "download-package",
helpLink = helpLink,
help =
""" """
Download package(s) Download package(s)
@@ -39,24 +36,25 @@ class DownloadPackageCommand(helpLink: String) :
If the package already exists in the cache directory, this command is a no-op. If the package already exists in the cache directory, this command is a no-op.
Examples: Examples:
``` ```
# Download two packages # Download two packages
$ pkl download-package package://example.com/package1@1.0.0 package://example.com/package2@1.0.0 $ pkl download-package package://example.com/package1@1.0.0 package://example.com/package2@1.0.0
``` ```
""" """
.trimIndent() .trimIndent()
) {
private val projectOptions by ProjectOptions() private val projectOptions by ProjectOptions()
private val packageUris: List<PackageUri> by private val packageUris: List<PackageUri> by
argument("<package>", "The package URIs to download") argument("package", "The package URIs to download")
.convert { PackageUri(it) } .convert { PackageUri(it) }
.multiple(required = true) .multiple(required = true)
private val noTransitive: Boolean by private val noTransitive: Boolean by
option( option(
names = arrayOf("--no-transitive"), names = arrayOf("--no-transitive"),
help = "Skip downloading transitive dependencies of a package" help = "Skip downloading transitive dependencies of a package",
) )
.single() .single()
.flag() .flag()
@@ -65,7 +63,7 @@ class DownloadPackageCommand(helpLink: String) :
CliPackageDownloader( CliPackageDownloader(
baseOptions.baseOptions(emptyList(), projectOptions), baseOptions.baseOptions(emptyList(), projectOptions),
packageUris, packageUris,
noTransitive noTransitive,
) )
.run() .run()
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,26 +24,24 @@ import org.pkl.cli.CliEvaluatorOptions
import org.pkl.commons.cli.commands.ModulesCommand import org.pkl.commons.cli.commands.ModulesCommand
import org.pkl.commons.cli.commands.single import org.pkl.commons.cli.commands.single
class EvalCommand(helpLink: String) : class EvalCommand : ModulesCommand(name = "eval", helpLink = helpLink) {
ModulesCommand(
name = "eval", override val helpString = "Render pkl module(s)"
help = "Render pkl module(s)",
helpLink = helpLink,
) {
private val outputPath: String? by private val outputPath: String? by
option( option(
names = arrayOf("-o", "--output-path"), names = arrayOf("-o", "--output-path"),
metavar = "<path>", metavar = "path",
help = "File path where the output file is placed." help = "File path where the output file is placed.",
) )
.single() .single()
private val moduleOutputSeparator: String by private val moduleOutputSeparator: String by
option( option(
names = arrayOf("--module-output-separator"), names = arrayOf("--module-output-separator"),
metavar = "<string>", metavar = "string",
help = help =
"Separator to use when multiple module outputs are written to the same file. (default: ---)" "Separator to use when multiple module outputs are written to the same file. (default: ---)",
) )
.single() .single()
.default("---") .default("---")
@@ -51,16 +49,16 @@ class EvalCommand(helpLink: String) :
private val expression: String? by private val expression: String? by
option( option(
names = arrayOf("-x", "--expression"), names = arrayOf("-x", "--expression"),
metavar = "<expression>", metavar = "expression",
help = "Expression to be evaluated within the module." help = "Expression to be evaluated within the module.",
) )
.single() .single()
private val multipleFileOutputPath: String? by private val multipleFileOutputPath: String? by
option( option(
names = arrayOf("-m", "--multiple-file-output-path"), names = arrayOf("-m", "--multiple-file-output-path"),
metavar = "<path>", metavar = "path",
help = "Directory where a module's multiple file output is placed." help = "Directory where a module's multiple file output is placed.",
) )
.single() .single()
.validate { .validate {
@@ -81,7 +79,7 @@ class EvalCommand(helpLink: String) :
outputFormat = baseOptions.format, outputFormat = baseOptions.format,
moduleOutputSeparator = moduleOutputSeparator, moduleOutputSeparator = moduleOutputSeparator,
multipleFileOutputPath = multipleFileOutputPath, multipleFileOutputPath = multipleFileOutputPath,
expression = expression ?: CliEvaluatorOptions.defaults.expression expression = expression ?: CliEvaluatorOptions.defaults.expression,
) )
CliEvaluator(options).run() CliEvaluator(options).run()
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/ */
package org.pkl.cli.commands package org.pkl.cli.commands
import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.core.NoOpCliktCommand import com.github.ajalt.clikt.core.NoOpCliktCommand
import com.github.ajalt.clikt.core.subcommands import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.argument
@@ -31,22 +32,20 @@ import org.pkl.commons.cli.commands.BaseCommand
import org.pkl.commons.cli.commands.TestOptions import org.pkl.commons.cli.commands.TestOptions
import org.pkl.commons.cli.commands.single import org.pkl.commons.cli.commands.single
class ProjectCommand(helpLink: String) : private const val NEWLINE = '\u0085'
NoOpCliktCommand(
name = "project", class ProjectCommand : NoOpCliktCommand(name = "project") {
help = "Run commands related to projects", override fun help(context: Context) = "Run commands related to projects"
epilog = "For more information, visit $helpLink"
) { override fun helpEpilog(context: Context) = "For more information, visit $helpLink"
init { init {
subcommands(ResolveCommand(helpLink), PackageCommand(helpLink)) subcommands(ResolveCommand(), PackageCommand())
}
} }
companion object { class ResolveCommand : BaseCommand(name = "resolve", helpLink = helpLink) {
class ResolveCommand(helpLink: String) : override val helpString =
BaseCommand(
name = "resolve",
helpLink = helpLink,
help =
""" """
Resolve dependencies for project(s) Resolve dependencies for project(s)
@@ -62,23 +61,18 @@ class ProjectCommand(helpLink: String) :
# Resolve dependencies for all projects within the `packages/` directory. # Resolve dependencies for all projects within the `packages/` directory.
$ pkl project resolve packages/*/ $ pkl project resolve packages/*/
``` ```
""", """
) {
private val projectDirs: List<Path> by private val projectDirs: List<Path> by
argument("<dir>", "The project directories to resolve dependencies for").path().multiple() argument("dir", "The project directories to resolve dependencies for").path().multiple()
override fun run() { override fun run() {
CliProjectResolver(baseOptions.baseOptions(emptyList()), projectDirs).run() CliProjectResolver(baseOptions.baseOptions(emptyList()), projectDirs).run()
} }
} }
private const val NEWLINE = '\u0085' class PackageCommand : BaseCommand(name = "package", helpLink = helpLink) {
override val helpString =
class PackageCommand(helpLink: String) :
BaseCommand(
name = "package",
helpLink = helpLink,
help =
""" """
Verify package(s), and prepare package artifacts to be published. Verify package(s), and prepare package artifacts to be published.
@@ -110,18 +104,18 @@ class ProjectCommand(helpLink: String) :
$ pkl project package packages/*/ $ pkl project package packages/*/
``` ```
""" """
.trimIndent(), .trimIndent()
) {
private val testOptions by TestOptions() private val testOptions by TestOptions()
private val projectDirs: List<Path> by private val projectDirs: List<Path> by
argument("<dir>", "The project directories to package").path().multiple() argument("dir", "The project directories to package").path().multiple()
private val outputPath: String by private val outputPath: String by
option( option(
names = arrayOf("--output-path"), names = arrayOf("--output-path"),
help = "The directory to write artifacts to", help = "The directory to write artifacts to",
metavar = "<path>" metavar = "path",
) )
.single() .single()
.default(".out/%{name}@%{version}") .default(".out/%{name}@%{version}")
@@ -140,10 +134,8 @@ class ProjectCommand(helpLink: String) :
projectDirs, projectDirs,
testOptions.cliTestOptions, testOptions.cliTestOptions,
outputPath, outputPath,
skipPublishCheck skipPublishCheck,
) )
.run() .run()
} }
} }
}
}
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -21,12 +21,9 @@ import org.pkl.cli.CliRepl
import org.pkl.commons.cli.commands.BaseCommand import org.pkl.commons.cli.commands.BaseCommand
import org.pkl.commons.cli.commands.ProjectOptions import org.pkl.commons.cli.commands.ProjectOptions
class ReplCommand(helpLink: String) : class ReplCommand : BaseCommand(name = "repl", helpLink = helpLink) {
BaseCommand( override val helpString = "Start a REPL session"
name = "repl",
help = "Start a REPL session",
helpLink = helpLink,
) {
private val projectOptions by ProjectOptions() private val projectOptions by ProjectOptions()
override fun run() { override fun run() {
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,25 +15,39 @@
*/ */
package org.pkl.cli.commands package org.pkl.cli.commands
import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.core.NoOpCliktCommand import com.github.ajalt.clikt.core.NoOpCliktCommand
import com.github.ajalt.clikt.core.context import com.github.ajalt.clikt.core.context
import com.github.ajalt.clikt.parameters.options.versionOption import com.github.ajalt.clikt.core.subcommands
import org.pkl.commons.cli.commands.installCommonOptions
import org.pkl.core.Release
internal val helpLink = "${Release.current().documentation.homepage}pkl-cli/index.html#usage"
class RootCommand : NoOpCliktCommand(name = "pkl") {
override val printHelpOnEmptyArgs = true
override fun helpEpilog(context: Context) = "For more information, visit $helpLink"
class RootCommand(name: String, version: String, helpLink: String) :
NoOpCliktCommand(
name = name,
printHelpOnEmptyArgs = true,
epilog = "For more information, visit $helpLink",
) {
init { init {
versionOption(version, names = setOf("-v", "--version"), message = { it })
context { context {
correctionSuggestor = { given, possible -> suggestTypoCorrection = { given, possible ->
if (!given.startsWith("-")) { if (!given.startsWith("-")) {
registeredSubcommands().map { it.commandName } registeredSubcommands().map { it.commandName }
} else possible } else possible
} }
} }
installCommonOptions()
subcommands(
EvalCommand(),
ReplCommand(),
ServerCommand(),
TestCommand(),
ProjectCommand(),
DownloadPackageCommand(),
AnalyzeCommand(),
)
} }
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,15 +16,15 @@
package org.pkl.cli.commands package org.pkl.cli.commands
import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.Context
import org.pkl.cli.CliServer import org.pkl.cli.CliServer
import org.pkl.commons.cli.CliBaseOptions import org.pkl.commons.cli.CliBaseOptions
class ServerCommand(helpLink: String) : class ServerCommand : CliktCommand(name = "server") {
CliktCommand( override fun help(context: Context) =
name = "server", "Run as a server that communicates over standard input/output"
help = "Run as a server that communicates over standard input/output",
epilog = "For more information, visit $helpLink" override fun helpEpilog(context: Context) = "For more information, visit $helpLink"
) {
override fun run() { override fun run() {
CliServer(CliBaseOptions()).run() CliServer(CliBaseOptions()).run()
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -26,10 +26,11 @@ import org.pkl.commons.cli.commands.BaseOptions
import org.pkl.commons.cli.commands.ProjectOptions import org.pkl.commons.cli.commands.ProjectOptions
import org.pkl.commons.cli.commands.TestOptions import org.pkl.commons.cli.commands.TestOptions
class TestCommand(helpLink: String) : class TestCommand : BaseCommand(name = "test", helpLink = helpLink) {
BaseCommand(name = "test", help = "Run tests within the given module(s)", helpLink = helpLink) { override val helpString = "Run tests within the given module(s)"
val modules: List<URI> by val modules: List<URI> by
argument(name = "<modules>", help = "Module paths or URIs to evaluate.") argument(name = "modules", help = "Module paths or URIs to evaluate.")
.convert { BaseOptions.parseModuleName(it) } .convert { BaseOptions.parseModuleName(it) }
.multiple() .multiple()
@@ -40,7 +41,7 @@ class TestCommand(helpLink: String) :
override fun run() { override fun run() {
CliTestRunner( CliTestRunner(
options = baseOptions.baseOptions(modules, projectOptions), options = baseOptions.baseOptions(modules, projectOptions),
testOptions = testOptions.cliTestOptions testOptions = testOptions.cliTestOptions,
) )
.run() .run()
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@ internal class Repl(workingDir: Path, private val server: ReplServer) {
option(Option.DISABLE_EVENT_EXPANSION, true) option(Option.DISABLE_EVENT_EXPANSION, true)
variable( variable(
org.jline.reader.LineReader.HISTORY_FILE, org.jline.reader.LineReader.HISTORY_FILE,
(IoUtils.getPklHomeDir().resolve("repl-history")) (IoUtils.getPklHomeDir().resolve("repl-history")),
) )
} }
.build() .build()
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@ private val cmdRegex = Regex(":(\\p{Alpha}*)(\\p{Space}*)(.*)", RegexOption.DOT_
internal fun getMatchingCommands(input: String): List<ParsedCommand> { internal fun getMatchingCommands(input: String): List<ParsedCommand> {
val match = cmdRegex.matchEntire(input) ?: return listOf() val match = cmdRegex.matchEntire(input) ?: return listOf()
val (cmd, ws, arg) = match.destructured val (cmd, ws, arg) = match.destructured
return Command.values() return Command.entries
.filter { it.toString().lowercase().startsWith(cmd) } .filter { it.toString().lowercase().startsWith(cmd) }
.map { ParsedCommand(it, cmd, ws, arg) } .map { ParsedCommand(it, cmd, ws, arg) }
} }
@@ -29,7 +29,7 @@ internal data class ParsedCommand(
val type: Command, val type: Command,
val cmd: String, val cmd: String,
val ws: String, val ws: String,
val arg: String val arg: String,
) )
internal enum class Command { internal enum class Command {
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@ internal abstract class JLineFileNameCompleter : Completer {
override fun complete( override fun complete(
reader: LineReader, reader: LineReader,
commandLine: ParsedLine, commandLine: ParsedLine,
candidates: MutableList<Candidate> candidates: MutableList<Candidate>,
) { ) {
val buffer = commandLine.word().substring(0, commandLine.wordCursor()) val buffer = commandLine.word().substring(0, commandLine.wordCursor())
val current: Path val current: Path
@@ -78,7 +78,7 @@ internal abstract class JLineFileNameCompleter : Completer {
null, null,
if (reader.isSet(LineReader.Option.AUTO_REMOVE_SLASH)) sep else null, if (reader.isSet(LineReader.Option.AUTO_REMOVE_SLASH)) sep else null,
null, null,
false false,
) )
) )
} else { } else {
@@ -90,7 +90,7 @@ internal abstract class JLineFileNameCompleter : Completer {
null, null,
null, null,
null, null,
true true,
) )
) )
} }
@@ -122,7 +122,7 @@ internal abstract class JLineFileNameCompleter : Completer {
terminal: Terminal, terminal: Terminal,
path: Path, path: Path,
resolver: StyleResolver, resolver: StyleResolver,
separator: String separator: String,
): String { ): String {
val builder = AttributedStringBuilder() val builder = AttributedStringBuilder()
val name = path.fileName.toString() val name = path.fileName.toString()
@@ -162,7 +162,7 @@ internal class FileCompleter(override val userDir: Path) : JLineFileNameComplete
override fun complete( override fun complete(
reader: LineReader, reader: LineReader,
commandLine: ParsedLine, commandLine: ParsedLine,
candidates: MutableList<Candidate> candidates: MutableList<Candidate>,
) { ) {
val loadCmd = val loadCmd =
getMatchingCommands(commandLine.line()).find { it.type == Command.Load && it.ws.isNotEmpty() } getMatchingCommands(commandLine.line()).find { it.type == Command.Load && it.ws.isNotEmpty() }
@@ -174,7 +174,7 @@ internal class FileCompleter(override val userDir: Path) : JLineFileNameComplete
internal object CommandCompleter : Completer { internal object CommandCompleter : Completer {
private val commandCandidates: List<Candidate> = private val commandCandidates: List<Candidate> =
Command.values().map { Candidate(":" + it.toString().lowercase()) } Command.entries.map { Candidate(":" + it.toString().lowercase()) }
override fun complete(reader: LineReader, line: ParsedLine, candidates: MutableList<Candidate>) { override fun complete(reader: LineReader, line: ParsedLine, candidates: MutableList<Candidate>) {
if (line.wordIndex() == 0) candidates.addAll(commandCandidates) if (line.wordIndex() == 0) candidates.addAll(commandCandidates)
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@ import org.pkl.core.OutputFormat
import org.pkl.core.SecurityManagers import org.pkl.core.SecurityManagers
import org.pkl.core.util.IoUtils import org.pkl.core.util.IoUtils
@OptIn(ExperimentalPathApi::class)
@WireMockTest(httpsEnabled = true, proxyMode = true) @WireMockTest(httpsEnabled = true, proxyMode = true)
class CliEvaluatorTest { class CliEvaluatorTest {
companion object { companion object {
@@ -88,19 +89,20 @@ class CliEvaluatorTest {
val sourceFiles = listOf(writePklFile("test.pkl")) val sourceFiles = listOf(writePklFile("test.pkl"))
val outputFiles = val outputFiles =
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), outputFormat = "pcf")
CliBaseOptions(sourceModules = sourceFiles),
outputFormat = "pcf",
)
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
checkOutputFile(outputFiles[0], "test.pcf", """ checkOutputFile(
outputFiles[0],
"test.pcf",
"""
person { person {
name = "pigeon" name = "pigeon"
age = 30 age = 30
} }
""") """,
)
} }
@Test @Test
@@ -108,10 +110,7 @@ person {
val sourceFiles = listOf(writePklFile("test.pkl")) val sourceFiles = listOf(writePklFile("test.pkl"))
val outputFiles = val outputFiles =
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), outputFormat = "json")
CliBaseOptions(sourceModules = sourceFiles),
outputFormat = "json",
)
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
@@ -125,7 +124,7 @@ person {
"age": 30 "age": 30
} }
} }
""" """,
) )
} }
@@ -134,18 +133,19 @@ person {
val sourceFiles = listOf(writePklFile("test.pkl")) val sourceFiles = listOf(writePklFile("test.pkl"))
val outputFiles = val outputFiles =
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), outputFormat = "yaml")
CliBaseOptions(sourceModules = sourceFiles),
outputFormat = "yaml",
)
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
checkOutputFile(outputFiles[0], "test.yaml", """ checkOutputFile(
outputFiles[0],
"test.yaml",
"""
person: person:
name: pigeon name: pigeon
age: 30 age: 30
""") """,
)
} }
@Test @Test
@@ -153,10 +153,7 @@ person:
val sourceFiles = listOf(writePklFile("test.pkl")) val sourceFiles = listOf(writePklFile("test.pkl"))
val outputFiles = val outputFiles =
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), outputFormat = "plist")
CliBaseOptions(sourceModules = sourceFiles),
outputFormat = "plist",
)
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
@@ -178,7 +175,7 @@ person:
</dict> </dict>
</dict> </dict>
</plist> </plist>
""" """,
) )
} }
@@ -187,10 +184,7 @@ person:
val sourceFiles = listOf(writePklFile("test.pkl")) val sourceFiles = listOf(writePklFile("test.pkl"))
val outputFiles = val outputFiles =
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), outputFormat = "xml")
CliBaseOptions(sourceModules = sourceFiles),
outputFormat = "xml",
)
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
@@ -205,7 +199,7 @@ person:
<age>30</age> <age>30</age>
</person> </person>
</root> </root>
""" """,
) )
} }
@@ -229,14 +223,11 @@ person:
listOf( listOf(
writePklFile("file1.pkl", "x = 1 + 1"), writePklFile("file1.pkl", "x = 1 + 1"),
writePklFile("file2.pkl", "x = 2 + 2"), writePklFile("file2.pkl", "x = 2 + 2"),
writePklFile("file3.pkl", "x = 3 + 3") writePklFile("file3.pkl", "x = 3 + 3"),
) )
val outputFiles = val outputFiles =
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), outputFormat = "pcf")
CliBaseOptions(sourceModules = sourceFiles),
outputFormat = "pcf",
)
) )
assertThat(outputFiles).hasSize(3) assertThat(outputFiles).hasSize(3)
@@ -269,20 +260,24 @@ person:
CliBaseOptions( CliBaseOptions(
sourceModules = sourceModules =
listOf(URI("modulepath:/foo/bar/test.pkl"), URI("modulepath:/foo/bar/test2.pkl")), listOf(URI("modulepath:/foo/bar/test.pkl"), URI("modulepath:/foo/bar/test2.pkl")),
modulePath = listOf(tempDir) modulePath = listOf(tempDir),
), ),
outputFormat = "pcf", outputFormat = "pcf",
outputPath = "$tempDir/%{moduleName}.%{outputFormat}" outputPath = "$tempDir/%{moduleName}.%{outputFormat}",
) )
) )
assertThat(outputFiles).hasSize(2) assertThat(outputFiles).hasSize(2)
checkOutputFile(outputFiles[0], "test.pcf", """ checkOutputFile(
outputFiles[0],
"test.pcf",
"""
person { person {
name = "pigeon" name = "pigeon"
age = 30 age = 30
} }
""") """,
)
checkOutputFile( checkOutputFile(
outputFiles[1], outputFiles[1],
"test2.pcf", "test2.pcf",
@@ -291,7 +286,7 @@ person {
name = "barn owl" name = "barn owl"
age = 30 age = 30
} }
""" """,
) )
} }
@@ -306,7 +301,7 @@ person {
name = read("prop:name") name = read("prop:name")
age = read("prop:age").toInt() age = read("prop:age").toInt()
} }
""" """,
) )
) )
@@ -315,19 +310,23 @@ person {
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions( CliBaseOptions(
sourceModules = sourceFiles, sourceModules = sourceFiles,
externalProperties = mapOf("name" to "pigeon", "age" to "30") externalProperties = mapOf("name" to "pigeon", "age" to "30"),
), ),
outputFormat = "pcf", outputFormat = "pcf",
) )
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
checkOutputFile(outputFiles[0], "test.pcf", """ checkOutputFile(
outputFiles[0],
"test.pcf",
"""
person { person {
name = "pigeon" name = "pigeon"
age = 30 age = 30
} }
""") """,
)
} }
@Test @Test
@@ -351,21 +350,25 @@ person {
sourceModules = listOf(file.toUri()), sourceModules = listOf(file.toUri()),
workingDir = workingDir =
if (relativePath) IoUtils.getCurrentWorkingDir().relativize(dir.parent) if (relativePath) IoUtils.getCurrentWorkingDir().relativize(dir.parent)
else dir.parent else dir.parent,
), ),
outputFormat = "pcf", outputFormat = "pcf",
outputPath = "baz/%{moduleName}.pcf" outputPath = "baz/%{moduleName}.pcf",
) )
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
assertThat(outputFiles[0].normalize()).isEqualTo(dir.parent.resolve("baz/test.pcf")) assertThat(outputFiles[0].normalize()).isEqualTo(dir.parent.resolve("baz/test.pcf"))
checkOutputFile(outputFiles[0], "test.pcf", """ checkOutputFile(
outputFiles[0],
"test.pcf",
"""
person { person {
name = "pigeon" name = "pigeon"
age = 30 age = 30
} }
""") """,
)
} }
@Test @Test
@@ -377,17 +380,21 @@ person {
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(URI("foo/test.pkl")), workingDir = tempDir), CliBaseOptions(sourceModules = listOf(URI("foo/test.pkl")), workingDir = tempDir),
outputFormat = "pcf" outputFormat = "pcf",
) )
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
checkOutputFile(outputFiles[0], "test.pcf", """ checkOutputFile(
outputFiles[0],
"test.pcf",
"""
person { person {
name = "pigeon" name = "pigeon"
age = 30 age = 30
} }
""") """,
)
} }
@Test @Test
@@ -396,10 +403,13 @@ person {
libDir.resolve("someLib.pkl").writeString("x = 1") libDir.resolve("someLib.pkl").writeString("x = 1")
val pklScript = val pklScript =
writePklFile("test.pkl", """ writePklFile(
"test.pkl",
"""
import "modulepath:/foo/someLib.pkl" import "modulepath:/foo/someLib.pkl"
result = someLib.x result = someLib.x
""") """,
)
val outputFiles = val outputFiles =
evalToFiles( evalToFiles(
@@ -407,9 +417,9 @@ result = someLib.x
CliBaseOptions( CliBaseOptions(
sourceModules = listOf(pklScript), sourceModules = listOf(pklScript),
workingDir = tempDir, workingDir = tempDir,
modulePath = listOf("lib".toPath()) modulePath = listOf("lib".toPath()),
), ),
outputFormat = "pcf" outputFormat = "pcf",
) )
) )
@@ -427,7 +437,7 @@ result = someLib.x
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(file), workingDir = workingDir), CliBaseOptions(sourceModules = listOf(file), workingDir = workingDir),
outputPath = "%{moduleDir}/result.pcf", outputPath = "%{moduleDir}/result.pcf",
outputFormat = "pcf" outputFormat = "pcf",
) )
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
@@ -449,7 +459,7 @@ result = someLib.x
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(file), workingDir = workingDir), CliBaseOptions(sourceModules = listOf(file), workingDir = workingDir),
outputFormat = "pcf" outputFormat = "pcf",
) )
) )
assertThat(outputFiles).hasSize(1) assertThat(outputFiles).hasSize(1)
@@ -465,10 +475,10 @@ result = someLib.x
CliEvaluator( CliEvaluator(
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(URI("repl:text"))), CliBaseOptions(sourceModules = listOf(URI("repl:text"))),
outputFormat = "pcf" outputFormat = "pcf",
), ),
stdin, stdin,
stdout stdout,
) )
evaluator.run() evaluator.run()
assertThat(stdout.toString().trim()).isEqualTo(defaultContents.replace("20 + 10", "30").trim()) assertThat(stdout.toString().trim()).isEqualTo(defaultContents.replace("20 + 10", "30").trim())
@@ -480,11 +490,7 @@ result = someLib.x
val module2 = writePklFile("mod2.pkl", "y = 11 + 11") val module2 = writePklFile("mod2.pkl", "y = 11 + 11")
val output = val output =
evalToConsole( evalToConsole(CliEvaluatorOptions(CliBaseOptions(sourceModules = listOf(module1, module2))))
CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(module1, module2)),
)
)
assertThat(output).isEqualTo("x = 42\n---\ny = 22\n") assertThat(output).isEqualTo("x = 42\n---\ny = 22\n")
} }
@@ -498,7 +504,7 @@ result = someLib.x
""" """
function fib(n) = if (n < 2) 0 else fib(n - 1) + fib(n - 2) function fib(n) = if (n < 2) 0 else fib(n - 1) + fib(n - 2)
x = fib(100) x = fib(100)
""" """,
) )
) )
@@ -507,7 +513,7 @@ result = someLib.x
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = sourceFiles, timeout = Duration.ofMillis(100)), CliBaseOptions(sourceModules = sourceFiles, timeout = Duration.ofMillis(100)),
outputFormat = "pcf" outputFormat = "pcf",
) )
) )
} }
@@ -516,16 +522,20 @@ result = someLib.x
@Test @Test
fun `cannot import module located outside root dir`() { fun `cannot import module located outside root dir`() {
val sourceFiles = listOf(writePklFile("test.pkl", """ val sourceFiles =
listOf(
writePklFile(
"test.pkl",
"""
amends "/non/existing.pkl" amends "/non/existing.pkl"
""")) """,
)
)
val e = val e =
assertThrows<CliException> { assertThrows<CliException> {
evalToFiles( evalToFiles(
CliEvaluatorOptions( CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles, rootDir = tempDir))
CliBaseOptions(sourceModules = sourceFiles, rootDir = tempDir),
)
) )
} }
@@ -538,7 +548,7 @@ result = someLib.x
listOf( listOf(
writePklFile("test1.pkl", "x = 1"), writePklFile("test1.pkl", "x = 1"),
writePklFile("test2.pkl", "x = 2"), writePklFile("test2.pkl", "x = 2"),
writePklFile("test3.pkl", "x = 3") writePklFile("test3.pkl", "x = 3"),
) )
val outputFile = tempDir.resolve("output.yaml") val outputFile = tempDir.resolve("output.yaml")
@@ -547,7 +557,7 @@ result = someLib.x
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = sourceFiles), CliBaseOptions(sourceModules = sourceFiles),
outputFile.toString(), outputFile.toString(),
"yaml" "yaml",
) )
) )
@@ -560,18 +570,18 @@ result = someLib.x
listOf( listOf(
writePklFile( writePklFile(
"test0.pkl", "test0.pkl",
"output { value = List(); renderer = new YamlRenderer { isStream = true } }" "output { value = List(); renderer = new YamlRenderer { isStream = true } }",
), ),
writePklFile("test1.pkl", "x = 1"), writePklFile("test1.pkl", "x = 1"),
writePklFile( writePklFile(
"test2.pkl", "test2.pkl",
"output { value = List(); renderer = new YamlRenderer { isStream = true } }" "output { value = List(); renderer = new YamlRenderer { isStream = true } }",
), ),
writePklFile("test3.pkl", "x = 3"), writePklFile("test3.pkl", "x = 3"),
writePklFile( writePklFile(
"test4.pkl", "test4.pkl",
"output { value = List(); renderer = new YamlRenderer { isStream = true } }" "output { value = List(); renderer = new YamlRenderer { isStream = true } }",
) ),
) )
val outputFile = tempDir.resolve("output.yaml") val outputFile = tempDir.resolve("output.yaml")
@@ -580,7 +590,7 @@ result = someLib.x
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = sourceFiles), CliBaseOptions(sourceModules = sourceFiles),
outputFile.toString(), outputFile.toString(),
"yaml" "yaml",
) )
) )
@@ -593,7 +603,7 @@ result = someLib.x
listOf( listOf(
writePklFile("test1.pkl", "x = 1"), writePklFile("test1.pkl", "x = 1"),
writePklFile("test2.pkl", "x = 2"), writePklFile("test2.pkl", "x = 2"),
writePklFile("test3.pkl", "x = 3") writePklFile("test3.pkl", "x = 3"),
) )
val outputFile = tempDir.resolve("output.pcf") val outputFile = tempDir.resolve("output.pcf")
@@ -603,7 +613,7 @@ result = someLib.x
CliBaseOptions(sourceModules = sourceFiles), CliBaseOptions(sourceModules = sourceFiles),
outputFile.toString(), outputFile.toString(),
outputFormat = "pcf", outputFormat = "pcf",
moduleOutputSeparator = "// my module separator" moduleOutputSeparator = "// my module separator",
) )
) )
@@ -617,7 +627,7 @@ result = someLib.x
// my module separator // my module separator
x = 3 x = 3
""" """
.trimIndent() .trimIndent(),
) )
} }
@@ -627,7 +637,7 @@ result = someLib.x
listOf( listOf(
writePklFile("test1.pkl", "x = 1"), writePklFile("test1.pkl", "x = 1"),
writePklFile("test2.pkl", "y = 2"), writePklFile("test2.pkl", "y = 2"),
writePklFile("test3.pkl", "z = 3") writePklFile("test3.pkl", "z = 3"),
) )
val outputFile = tempDir.resolve("output.pcf") val outputFile = tempDir.resolve("output.pcf")
@@ -637,7 +647,7 @@ result = someLib.x
CliBaseOptions(sourceModules = sourceFiles), CliBaseOptions(sourceModules = sourceFiles),
outputFile.toString(), outputFile.toString(),
outputFormat = "pcf", outputFormat = "pcf",
moduleOutputSeparator = "" moduleOutputSeparator = "",
) )
) )
@@ -651,7 +661,7 @@ result = someLib.x
z = 3 z = 3
""" """
.trimIndent() .trimIndent(),
) )
} }
@@ -661,11 +671,13 @@ result = someLib.x
listOf( listOf(
writePklFile("test1.pkl", "x = 1"), writePklFile("test1.pkl", "x = 1"),
writePklFile("test2.pkl", "x = 2"), writePklFile("test2.pkl", "x = 2"),
writePklFile("test3.pkl", "x = 3") writePklFile("test3.pkl", "x = 3"),
) )
val output = val output =
evalToConsole(CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), null, "yaml")) evalToConsole(
CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), outputFormat = "yaml")
)
assertThat(output).isEqualTo("x: 1\n---\nx: 2\n---\nx: 3\n") assertThat(output).isEqualTo("x: 1\n---\nx: 2\n---\nx: 3\n")
} }
@@ -676,22 +688,24 @@ result = someLib.x
listOf( listOf(
writePklFile( writePklFile(
"test0.pkl", "test0.pkl",
"output { value = List(); renderer = new YamlRenderer { isStream = true } }" "output { value = List(); renderer = new YamlRenderer { isStream = true } }",
), ),
writePklFile("test1.pkl", "x = 1"), writePklFile("test1.pkl", "x = 1"),
writePklFile( writePklFile(
"test2.pkl", "test2.pkl",
"output { value = List(); renderer = new YamlRenderer { isStream = true } }" "output { value = List(); renderer = new YamlRenderer { isStream = true } }",
), ),
writePklFile("test3.pkl", "x = 3"), writePklFile("test3.pkl", "x = 3"),
writePklFile( writePklFile(
"test4.pkl", "test4.pkl",
"output { value = List(); renderer = new YamlRenderer { isStream = true } }" "output { value = List(); renderer = new YamlRenderer { isStream = true } }",
) ),
) )
val output = val output =
evalToConsole(CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), null, "yaml")) evalToConsole(
CliEvaluatorOptions(CliBaseOptions(sourceModules = sourceFiles), outputFormat = "yaml")
)
assertThat(output).isEqualTo("x: 1\n---\nx: 3\n") assertThat(output).isEqualTo("x: 1\n---\nx: 3\n")
} }
@@ -705,8 +719,7 @@ result = someLib.x
evalToConsole( evalToConsole(
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = sourceFiles), CliBaseOptions(sourceModules = sourceFiles),
null, outputFormat = outputFormat.toString(),
outputFormat.toString()
) )
) )
assertThat(output).endsWith("\n") assertThat(output).endsWith("\n")
@@ -750,7 +763,7 @@ result = someLib.x
""" """
["bar"] = "baz" ["bar"] = "baz"
""" """
.trimIndent() .trimIndent(),
) )
checkOutputFile( checkOutputFile(
tempDir.resolve(".my-output/bar/baz.pcf"), tempDir.resolve(".my-output/bar/baz.pcf"),
@@ -758,7 +771,7 @@ result = someLib.x
""" """
["baz"] = "biz" ["baz"] = "biz"
""" """
.trimIndent() .trimIndent(),
) )
checkOutputFile(tempDir.resolve(".my-output/buz.txt"), "buz.txt", "buz") checkOutputFile(tempDir.resolve(".my-output/buz.txt"), "buz.txt", "buz")
} }
@@ -796,7 +809,7 @@ result = someLib.x
} }
""" """
.trimIndent(), .trimIndent(),
) ),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
@@ -823,7 +836,7 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
), ),
writePklFile( writePklFile(
"foo.pkl", "foo.pkl",
@@ -836,7 +849,7 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
), ),
) )
val options = val options =
@@ -849,11 +862,7 @@ result = someLib.x
@Test @Test
fun `multiple file output writes nothing if output files is null`() { fun `multiple file output writes nothing if output files is null`() {
val moduleUri = val moduleUri = writePklFile("test.pkl", "")
writePklFile(
"test.pkl",
"",
)
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir), CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir),
@@ -878,12 +887,12 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir), CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir),
multipleFileOutputPath = ".output" multipleFileOutputPath = ".output",
) )
assertThatCode { evalToConsole(options) } assertThatCode { evalToConsole(options) }
.hasMessageStartingWith("Output file conflict:") .hasMessageStartingWith("Output file conflict:")
@@ -904,7 +913,7 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
), ),
writePklFile( writePklFile(
"test2.pkl", "test2.pkl",
@@ -915,14 +924,14 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) ),
) )
for (moduleUri in moduleUris) { for (moduleUri in moduleUris) {
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir), CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir),
multipleFileOutputPath = ".output" multipleFileOutputPath = ".output",
) )
assertThatCode { evalToConsole(options) } assertThatCode { evalToConsole(options) }
.hasMessageStartingWith("Output file conflict:") .hasMessageStartingWith("Output file conflict:")
@@ -943,7 +952,7 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
), ),
writePklFile( writePklFile(
"test2.pkl", "test2.pkl",
@@ -954,13 +963,13 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) ),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = moduleUris, workingDir = tempDir), CliBaseOptions(sourceModules = moduleUris, workingDir = tempDir),
multipleFileOutputPath = ".output" multipleFileOutputPath = ".output",
) )
assertThatCode { evalToConsole(options) } assertThatCode { evalToConsole(options) }
.hasMessageContaining("Output file conflict:") .hasMessageContaining("Output file conflict:")
@@ -980,12 +989,12 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir), CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir),
multipleFileOutputPath = ".output" multipleFileOutputPath = ".output",
) )
assertThatCode { evalToConsole(options) } assertThatCode { evalToConsole(options) }
.hasMessageContaining("Output file conflict:") .hasMessageContaining("Output file conflict:")
@@ -1005,13 +1014,13 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir), CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir),
multipleFileOutputPath = ".output" multipleFileOutputPath = ".output",
) )
assertThatCode { evalToConsole(options) } assertThatCode { evalToConsole(options) }
.hasMessageContaining("Path spec `foo:bar` contains illegal character `:`.") .hasMessageContaining("Path spec `foo:bar` contains illegal character `:`.")
@@ -1030,13 +1039,13 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir), CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir),
multipleFileOutputPath = ".output" multipleFileOutputPath = ".output",
) )
assertThatCode { evalToConsole(options) } assertThatCode { evalToConsole(options) }
.hasMessageContaining("Path spec `foo\\bar` contains illegal character `\\`.") .hasMessageContaining("Path spec `foo\\bar` contains illegal character `\\`.")
@@ -1052,7 +1061,7 @@ result = someLib.x
bar = 1 bar = 1
} }
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
@@ -1083,7 +1092,7 @@ result = someLib.x
} }
person: Person = new { name = "Frodo" } person: Person = new { name = "Frodo" }
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
@@ -1105,7 +1114,7 @@ result = someLib.x
friend { name = "Bilbo" } friend { name = "Bilbo" }
} }
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
@@ -1125,7 +1134,7 @@ result = someLib.x
""" """
res = 1 res = 1
""" """
.trimIndent() .trimIndent(),
) )
writePklFile( writePklFile(
"PklProject", "PklProject",
@@ -1134,11 +1143,11 @@ result = someLib.x
package = throw("invalid project package") package = throw("invalid project package")
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir, noProject = true), CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir, noProject = true)
) )
val buffer = StringWriter() val buffer = StringWriter()
CliEvaluator(options, consoleWriter = buffer).run() CliEvaluator(options, consoleWriter = buffer).run()
@@ -1154,7 +1163,7 @@ result = someLib.x
""" """
res = read*("env:**") res = read*("env:**")
""" """
.trimIndent() .trimIndent(),
) )
writePklFile( writePklFile(
"PklProject", "PklProject",
@@ -1169,12 +1178,10 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir))
CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir),
)
val buffer = StringWriter() val buffer = StringWriter()
CliEvaluator(options, consoleWriter = buffer).run() CliEvaluator(options, consoleWriter = buffer).run()
assertThat(buffer.toString()) assertThat(buffer.toString())
@@ -1200,7 +1207,7 @@ result = someLib.x
res = Swallow res = Swallow
""" """
.trimIndent() .trimIndent(),
) )
val buffer = StringWriter() val buffer = StringWriter()
val options = val options =
@@ -1211,8 +1218,8 @@ result = someLib.x
moduleCacheDir = tempDir, moduleCacheDir = tempDir,
noCache = true, noCache = true,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = packageServer.port testPort = packageServer.port,
), )
) )
CliEvaluator(options, consoleWriter = buffer).run() CliEvaluator(options, consoleWriter = buffer).run()
assertThat(buffer.toString()) assertThat(buffer.toString())
@@ -1242,7 +1249,7 @@ result = someLib.x
} }
@Test @Test
fun `gives decent error message if certificate file is emtpy`(@TempDir tempDir: Path) { fun `gives decent error message if certificate file is empty`(@TempDir tempDir: Path) {
val emptyCerts = tempDir.writeEmptyFile("empty.pem") val emptyCerts = tempDir.writeEmptyFile("empty.pem")
val err = assertThrows<CliException> { evalModuleThatImportsPackage(emptyCerts) } val err = assertThrows<CliException> { evalModuleThatImportsPackage(emptyCerts) }
assertThat(err).hasMessageContaining("CA certificate file `${emptyCerts.pathString}` is empty.") assertThat(err).hasMessageContaining("CA certificate file `${emptyCerts.pathString}` is empty.")
@@ -1278,7 +1285,7 @@ result = someLib.x
sourceModules = listOf(URI("http://not.a.valid.host/bar.pkl")), sourceModules = listOf(URI("http://not.a.valid.host/bar.pkl")),
httpProxy = URI("http://localhost:${wwRuntimeInfo.httpPort}"), httpProxy = URI("http://localhost:${wwRuntimeInfo.httpPort}"),
allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:"), allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:"),
), )
) )
val output = evalToConsole(options) val output = evalToConsole(options)
assertThat(output).isEqualTo("foo = 1\n") assertThat(output).isEqualTo("foo = 1\n")
@@ -1313,18 +1320,18 @@ result = someLib.x
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
CliBaseOptions( CliBaseOptions(
sourceModules = listOf(URI("package://localhost:1/birds@0.5.0#/catalog/Ostritch.pkl")), sourceModules = listOf(URI("package://localhost:1/birds@0.5.0#/catalog/Ostrich.pkl")),
noCache = true, noCache = true,
httpProxy = URI(wwRuntimeInfo.httpBaseUrl), httpProxy = URI(wwRuntimeInfo.httpBaseUrl),
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:") allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:"),
) )
) )
val output = evalToConsole(options) val output = evalToConsole(options)
assertThat(output) assertThat(output)
.isEqualTo( .isEqualTo(
""" """
name = "Ostritch" name = "Ostrich"
favoriteFruit { favoriteFruit {
name = "Orange" name = "Orange"
@@ -1340,7 +1347,7 @@ result = someLib.x
@Test @Test
fun `eval http module from proxy -- configured in settings`( fun `eval http module from proxy -- configured in settings`(
@TempDir tempDir: Path, @TempDir tempDir: Path,
wwRuntimeInfo: WireMockRuntimeInfo wwRuntimeInfo: WireMockRuntimeInfo,
) { ) {
val settingsModule = val settingsModule =
tempDir.writeFile( tempDir.writeFile(
@@ -1354,7 +1361,7 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
stubFor( stubFor(
@@ -1366,7 +1373,7 @@ result = someLib.x
sourceModules = listOf(URI("http://not.a.valid.host/bar.pkl")), sourceModules = listOf(URI("http://not.a.valid.host/bar.pkl")),
settings = settingsModule.toUri(), settings = settingsModule.toUri(),
allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:"), allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:"),
), )
) )
val output = evalToConsole(options) val output = evalToConsole(options)
assertThat(output).isEqualTo("foo = 1\n") assertThat(output).isEqualTo("foo = 1\n")
@@ -1375,7 +1382,7 @@ result = someLib.x
@Test @Test
fun `eval http module from proxy -- configured in PklProject`( fun `eval http module from proxy -- configured in PklProject`(
@TempDir tempDir: Path, @TempDir tempDir: Path,
wwRuntimeInfo: WireMockRuntimeInfo wwRuntimeInfo: WireMockRuntimeInfo,
) { ) {
tempDir.writeFile( tempDir.writeFile(
"PklProject", "PklProject",
@@ -1390,7 +1397,7 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
stubFor( stubFor(
@@ -1401,8 +1408,8 @@ result = someLib.x
CliBaseOptions( CliBaseOptions(
sourceModules = listOf(URI("http://not.a.valid.host/bar.pkl")), sourceModules = listOf(URI("http://not.a.valid.host/bar.pkl")),
allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:"), allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:"),
projectDir = tempDir projectDir = tempDir,
), )
) )
val output = evalToConsole(options) val output = evalToConsole(options)
assertThat(output).isEqualTo("foo = 1\n") assertThat(output).isEqualTo("foo = 1\n")
@@ -1411,7 +1418,7 @@ result = someLib.x
@Test @Test
fun `eval http module from proxy -- PklProject beats user settings`( fun `eval http module from proxy -- PklProject beats user settings`(
@TempDir tempDir: Path, @TempDir tempDir: Path,
wwRuntimeInfo: WireMockRuntimeInfo wwRuntimeInfo: WireMockRuntimeInfo,
) { ) {
val projectDir = tempDir.resolve("my-project") val projectDir = tempDir.resolve("my-project")
projectDir.writeFile( projectDir.writeFile(
@@ -1427,7 +1434,7 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
val homeDir = tempDir.resolve("my-home") val homeDir = tempDir.resolve("my-home")
homeDir.writeFile( homeDir.writeFile(
@@ -1441,7 +1448,7 @@ result = someLib.x
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
val options = val options =
CliEvaluatorOptions( CliEvaluatorOptions(
@@ -1449,8 +1456,8 @@ result = someLib.x
sourceModules = listOf(URI("http://not.a.valid.host/bar.pkl")), sourceModules = listOf(URI("http://not.a.valid.host/bar.pkl")),
allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:"), allowedModules = SecurityManagers.defaultAllowedModules + Pattern.compile("http:"),
projectDir = projectDir, projectDir = projectDir,
settings = homeDir.resolve("settings.pkl").toUri() settings = homeDir.resolve("settings.pkl").toUri(),
), )
) )
stubFor(get(anyUrl()).willReturn(ok("result = 1"))) stubFor(get(anyUrl()).willReturn(ok("result = 1")))
val output = evalToConsole(options) val output = evalToConsole(options)
@@ -1477,14 +1484,9 @@ result = someLib.x
importGlob = import*("./日*.pkl").keys importGlob = import*("./日*.pkl").keys
importGlobFile = import*("$tempDirUri**/*.pkl").keys.map((it) -> it.replaceAll("$tempDirUri".replaceAll("///", "/"), "")) importGlobFile = import*("$tempDirUri**/*.pkl").keys.map((it) -> it.replaceAll("$tempDirUri".replaceAll("///", "/"), ""))
""" """
.trimIndent() .trimIndent(),
)
val output =
evalToConsole(
CliEvaluatorOptions(
CliBaseOptions(sourceModules = listOf(file)),
)
) )
val output = evalToConsole(CliEvaluatorOptions(CliBaseOptions(sourceModules = listOf(file))))
val tripleQuote = "\"\"\"" val tripleQuote = "\"\"\""
assertThat(output) assertThat(output)
@@ -1521,7 +1523,7 @@ result = someLib.x
import "package://localhost:0/birds@0.5.0#/catalog/Swallow.pkl" import "package://localhost:0/birds@0.5.0#/catalog/Swallow.pkl"
res = Swallow res = Swallow
""" """,
) )
val options = val options =
@@ -1531,8 +1533,8 @@ result = someLib.x
caCertificates = buildList { if (certsFile != null) add(certsFile) }, caCertificates = buildList { if (certsFile != null) add(certsFile) },
workingDir = tempDir, workingDir = tempDir,
noCache = true, noCache = true,
testPort = testPort testPort = testPort,
), )
) )
CliEvaluator(options).run() CliEvaluator(options).run()
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -65,7 +65,7 @@ class CliImportAnalyzerTest {
val analyzer = val analyzer =
CliImportAnalyzer( CliImportAnalyzer(
CliImportAnalyzerOptions(baseOptions, outputFormat = OutputFormat.JSON.toString()), CliImportAnalyzerOptions(baseOptions, outputFormat = OutputFormat.JSON.toString()),
StringBuilderWriter(sb) StringBuilderWriter(sb),
) )
analyzer.run() analyzer.run()
assertThat(sb.toString()) assertThat(sb.toString())
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,7 +16,8 @@
package org.pkl.cli package org.pkl.cli
import com.github.ajalt.clikt.core.BadParameterValue import com.github.ajalt.clikt.core.BadParameterValue
import com.github.ajalt.clikt.core.subcommands import com.github.ajalt.clikt.core.CliktError
import com.github.ajalt.clikt.core.parse
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.path.createDirectory import kotlin.io.path.createDirectory
import kotlin.io.path.createSymbolicLinkPointingTo import kotlin.io.path.createSymbolicLinkPointingTo
@@ -27,35 +28,37 @@ import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.condition.DisabledOnOs import org.junit.jupiter.api.condition.DisabledOnOs
import org.junit.jupiter.api.condition.OS import org.junit.jupiter.api.condition.OS
import org.junit.jupiter.api.io.TempDir import org.junit.jupiter.api.io.TempDir
import org.pkl.cli.commands.AnalyzeCommand
import org.pkl.cli.commands.EvalCommand import org.pkl.cli.commands.EvalCommand
import org.pkl.cli.commands.RootCommand import org.pkl.cli.commands.RootCommand
import org.pkl.commons.writeString import org.pkl.commons.writeString
import org.pkl.core.Release
class CliMainTest { class CliMainTest {
private val rootCmd = RootCommand()
private val evalCmd = EvalCommand("")
private val analyzeCommand = AnalyzeCommand("")
private val cmd = RootCommand("pkl", "pkl version 1", "").subcommands(evalCmd, analyzeCommand)
@Test @Test
fun `duplicate CLI option produces meaningful error message`(@TempDir tempDir: Path) { fun `duplicate CLI option produces meaningful error message`(@TempDir tempDir: Path) {
val inputFile = tempDir.resolve("test.pkl").writeString("").toString() val inputFile = tempDir.resolve("test.pkl").writeString("").toString()
assertThatCode { assertThatCode {
cmd.parse(arrayOf("eval", "--output-path", "path1", "--output-path", "path2", inputFile)) rootCmd.parse(
arrayOf("eval", "--output-path", "path1", "--output-path", "path2", inputFile)
)
} }
.hasMessage("Invalid value for \"--output-path\": Option cannot be repeated") .hasMessage("Option cannot be repeated")
assertThatCode { assertThatCode {
cmd.parse(arrayOf("eval", "-o", "path1", "--output-path", "path2", inputFile)) rootCmd.parse(arrayOf("eval", "-o", "path1", "--output-path", "path2", inputFile))
} }
.hasMessage("Invalid value for \"--output-path\": Option cannot be repeated") .hasMessage("Option cannot be repeated")
} }
@Test @Test
fun `eval requires at least one file`() { fun `eval requires at least one file`() {
assertThatCode { cmd.parse(arrayOf("eval")) }.hasMessage("""Missing argument "<modules>"""") assertThatCode { rootCmd.parse(arrayOf("eval")) }
.isInstanceOf(CliktError::class.java)
.extracting("paramName")
.isEqualTo("modules")
} }
// Can't reliably create symlinks on Windows. // Can't reliably create symlinks on Windows.
@@ -76,7 +79,7 @@ class CliMainTest {
val inputFile = tempDir.resolve("test.pkl").writeString(code).toString() val inputFile = tempDir.resolve("test.pkl").writeString(code).toString()
val outputFile = makeSymdir(tempDir, "out", "linkOut").resolve("test.pkl").toString() val outputFile = makeSymdir(tempDir, "out", "linkOut").resolve("test.pkl").toString()
assertThatCode { cmd.parse(arrayOf("eval", inputFile, "-o", outputFile)) } assertThatCode { rootCmd.parse(arrayOf("eval", inputFile, "-o", outputFile)) }
.doesNotThrowAnyException() .doesNotThrowAnyException()
} }
@@ -84,25 +87,26 @@ class CliMainTest {
fun `cannot have multiple output with -o or -x`(@TempDir tempDir: Path) { fun `cannot have multiple output with -o or -x`(@TempDir tempDir: Path) {
val testIn = makeInput(tempDir) val testIn = makeInput(tempDir)
val testOut = tempDir.resolve("test").toString() val testOut = tempDir.resolve("test").toString()
val error = val error = """Option is mutually exclusive with -o, --output-path and -x, --expression."""
"""Invalid value for "--multiple-file-output-path": Option is mutually exclusive with -o, --output-path and -x, --expression."""
assertThatCode { cmd.parse(arrayOf("eval", "-m", testOut, "-x", "x", testIn)) } assertThatCode { rootCmd.parse(arrayOf("eval", "-m", testOut, "-x", "x", testIn)) }
.hasMessage(error) .hasMessage(error)
assertThatCode { cmd.parse(arrayOf("eval", "-m", testOut, "-o", "/tmp/test", testIn)) } assertThatCode { rootCmd.parse(arrayOf("eval", "-m", testOut, "-o", "/tmp/test", testIn)) }
.hasMessage(error) .hasMessage(error)
} }
@Test @Test
fun `showing version works`() { fun `showing version works`() {
assertThatCode { cmd.parse(arrayOf("--version")) }.hasMessage("pkl version 1") assertThatCode { rootCmd.parse(arrayOf("--version")) }.hasMessage(Release.current().versionInfo)
} }
@Test @Test
fun `file paths get parsed into URIs`(@TempDir tempDir: Path) { fun `file paths get parsed into URIs`(@TempDir tempDir: Path) {
val cmd = RootCommand()
cmd.parse(arrayOf("eval", makeInput(tempDir, "my file.txt"))) cmd.parse(arrayOf("eval", makeInput(tempDir, "my file.txt")))
val evalCmd = cmd.registeredSubcommands().filterIsInstance<EvalCommand>().first()
val modules = evalCmd.baseOptions.baseOptions(evalCmd.modules).normalizedSourceModules val modules = evalCmd.baseOptions.baseOptions(evalCmd.modules).normalizedSourceModules
assertThat(modules).hasSize(1) assertThat(modules).hasSize(1)
assertThat(modules[0].path).endsWith("my file.txt") assertThat(modules[0].path).endsWith("my file.txt")
@@ -110,7 +114,7 @@ class CliMainTest {
@Test @Test
fun `invalid URIs are not accepted`() { fun `invalid URIs are not accepted`() {
val ex = assertThrows<BadParameterValue> { cmd.parse(arrayOf("eval", "file:my file.txt")) } val ex = assertThrows<BadParameterValue> { rootCmd.parse(arrayOf("eval", "file:my file.txt")) }
assertThat(ex.message).contains("URI `file:my file.txt` has invalid syntax") assertThat(ex.message).contains("URI `file:my file.txt` has invalid syntax")
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import org.pkl.core.packages.PackageUri
class CliPackageDownloaderTest { class CliPackageDownloaderTest {
companion object { companion object {
val server = PackageServer() private val server = PackageServer()
@AfterAll @AfterAll
@JvmStatic @JvmStatic
@@ -45,15 +45,15 @@ class CliPackageDownloaderTest {
CliBaseOptions( CliBaseOptions(
moduleCacheDir = tempDir, moduleCacheDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = server.port testPort = server.port,
), ),
packageUris = packageUris =
listOf( listOf(
PackageUri("package://localhost:0/birds@0.5.0"), PackageUri("package://localhost:0/birds@0.5.0"),
PackageUri("package://localhost:0/fruit@1.0.5"), PackageUri("package://localhost:0/fruit@1.0.5"),
PackageUri("package://localhost:0/fruit@1.1.0") PackageUri("package://localhost:0/fruit@1.1.0"),
), ),
noTransitive = true noTransitive = true,
) )
cmd.run() cmd.run()
assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")).exists() assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")).exists()
@@ -75,7 +75,7 @@ class CliPackageDownloaderTest {
moduleCacheDir = ".my-cache" moduleCacheDir = ".my-cache"
} }
""" """
.trimIndent() .trimIndent(),
) )
val cmd = val cmd =
@@ -84,10 +84,10 @@ class CliPackageDownloaderTest {
CliBaseOptions( CliBaseOptions(
workingDir = tempDir, workingDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = server.port testPort = server.port,
), ),
packageUris = listOf(PackageUri("package://localhost:0/birds@0.5.0")), packageUris = listOf(PackageUri("package://localhost:0/birds@0.5.0")),
noTransitive = true noTransitive = true,
) )
cmd.run() cmd.run()
assertThat(tempDir.resolve(".my-cache/package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")) assertThat(tempDir.resolve(".my-cache/package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip"))
@@ -104,13 +104,13 @@ class CliPackageDownloaderTest {
CliBaseOptions( CliBaseOptions(
moduleCacheDir = tempDir, moduleCacheDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = server.port testPort = server.port,
), ),
packageUris = packageUris =
listOf( listOf(
PackageUri("package://localhost:0/birds@0.5.0::sha256:${PackageServer.BIRDS_SHA}"), PackageUri("package://localhost:0/birds@0.5.0::sha256:${PackageServer.BIRDS_SHA}")
), ),
noTransitive = true noTransitive = true,
) )
cmd.run() cmd.run()
assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")).exists() assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")).exists()
@@ -125,13 +125,13 @@ class CliPackageDownloaderTest {
CliBaseOptions( CliBaseOptions(
moduleCacheDir = tempDir, moduleCacheDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = server.port testPort = server.port,
), ),
packageUris = packageUris =
listOf( listOf(
PackageUri("package://localhost:0/birds@0.5.0::sha256:intentionallyBogusChecksum"), PackageUri("package://localhost:0/birds@0.5.0::sha256:intentionallyBogusChecksum")
), ),
noTransitive = true noTransitive = true,
) )
assertThatCode { cmd.run() } assertThatCode { cmd.run() }
.hasMessage( .hasMessage(
@@ -152,7 +152,7 @@ class CliPackageDownloaderTest {
CliPackageDownloader( CliPackageDownloader(
baseOptions = CliBaseOptions(workingDir = tempDir, noCache = true), baseOptions = CliBaseOptions(workingDir = tempDir, noCache = true),
packageUris = listOf(PackageUri("package://localhost:0/birds@0.5.0")), packageUris = listOf(PackageUri("package://localhost:0/birds@0.5.0")),
noTransitive = true noTransitive = true,
) )
assertThatCode { cmd.run() } assertThatCode { cmd.run() }
.hasMessage("Cannot download packages because no cache directory is specified.") .hasMessage("Cannot download packages because no cache directory is specified.")
@@ -166,10 +166,10 @@ class CliPackageDownloaderTest {
CliBaseOptions( CliBaseOptions(
moduleCacheDir = tempDir, moduleCacheDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = server.port testPort = server.port,
), ),
packageUris = listOf(PackageUri("package://localhost:0/badChecksum@1.0.0")), packageUris = listOf(PackageUri("package://localhost:0/badChecksum@1.0.0")),
noTransitive = true noTransitive = true,
) )
assertThatCode { cmd.run() } assertThatCode { cmd.run() }
.hasMessageStartingWith( .hasMessageStartingWith(
@@ -185,14 +185,14 @@ class CliPackageDownloaderTest {
CliBaseOptions( CliBaseOptions(
moduleCacheDir = tempDir, moduleCacheDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = server.port testPort = server.port,
), ),
packageUris = packageUris =
listOf( listOf(
PackageUri("package://localhost:0/badChecksum@1.0.0"), PackageUri("package://localhost:0/badChecksum@1.0.0"),
PackageUri("package://bogus.domain/notAPackage@1.0.0") PackageUri("package://bogus.domain/notAPackage@1.0.0"),
), ),
noTransitive = true noTransitive = true,
) )
assertThatCode { cmd.run() } assertThatCode { cmd.run() }
.hasMessage( .hasMessage(
@@ -222,10 +222,10 @@ class CliPackageDownloaderTest {
CliBaseOptions( CliBaseOptions(
moduleCacheDir = tempDir, moduleCacheDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = server.port testPort = server.port,
), ),
packageUris = listOf(PackageUri("package://localhost:0/birds@0.5.0")), packageUris = listOf(PackageUri("package://localhost:0/birds@0.5.0")),
noTransitive = false noTransitive = false,
) )
.run() .run()
assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")).exists() assertThat(tempDir.resolve("package-2/localhost(3a)0/birds@0.5.0/birds@0.5.0.zip")).exists()
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -115,7 +115,7 @@ class CliProjectPackagerTest {
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
tempDir.writeFile( tempDir.writeFile(
"PklProject", "PklProject",
@@ -130,7 +130,7 @@ class CliProjectPackagerTest {
apiTests { "myTest.pkl" } apiTests { "myTest.pkl" }
} }
""" """
.trimIndent() .trimIndent(),
) )
val buffer = StringWriter() val buffer = StringWriter()
val packager = val packager =
@@ -140,7 +140,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = buffer consoleWriter = buffer,
) )
val err = assertThrows<CliException> { packager.run() } val err = assertThrows<CliException> { packager.run() }
assertThat(err).hasMessageContaining("because its API tests are failing") assertThat(err).hasMessageContaining("because its API tests are failing")
@@ -187,7 +187,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = buffer consoleWriter = buffer,
) )
packager.run() packager.run()
} }
@@ -286,7 +286,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out", ".out",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = buffer consoleWriter = buffer,
) )
packager.run() packager.run()
} }
@@ -301,7 +301,7 @@ class CliProjectPackagerTest {
name: String name: String
""" """
.trimIndent() .trimIndent(),
) )
val fooTxt = val fooTxt =
@@ -312,7 +312,7 @@ class CliProjectPackagerTest {
bar bar
baz baz
""" """
.trimIndent() .trimIndent(),
) )
tempDir tempDir
@@ -337,7 +337,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
packager.run() packager.run()
val expectedMetadata = tempDir.resolve(".out/mypackage@1.0.0/mypackage@1.0.0") val expectedMetadata = tempDir.resolve(".out/mypackage@1.0.0/mypackage@1.0.0")
@@ -411,7 +411,7 @@ class CliProjectPackagerTest {
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
CliProjectPackager( CliProjectPackager(
CliBaseOptions(workingDir = tempDir), CliBaseOptions(workingDir = tempDir),
@@ -419,7 +419,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
.run() .run()
val expectedArchive = tempDir.resolve(".out/mypackage@1.0.0/mypackage@1.0.0.zip") val expectedArchive = tempDir.resolve(".out/mypackage@1.0.0/mypackage@1.0.0.zip")
@@ -432,7 +432,7 @@ class CliProjectPackagerTest {
"/input", "/input",
"/input/foo", "/input/foo",
"/input/foo/bar.txt", "/input/foo/bar.txt",
"/main.pkl" "/main.pkl",
) )
) )
} }
@@ -460,7 +460,7 @@ class CliProjectPackagerTest {
["project2"] = import("../project2/PklProject") ["project2"] = import("../project2/PklProject")
} }
""" """
.trimIndent() .trimIndent(),
) )
projectDir.writeFile( projectDir.writeFile(
"PklProject.deps.json", "PklProject.deps.json",
@@ -483,7 +483,7 @@ class CliProjectPackagerTest {
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
project2Dir.writeFile( project2Dir.writeFile(
@@ -498,7 +498,7 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com/project2.zip" packageZipUrl = "https://foo.com/project2.zip"
} }
""" """
.trimIndent() .trimIndent(),
) )
project2Dir.writeFile( project2Dir.writeFile(
"PklProject.deps.json", "PklProject.deps.json",
@@ -508,7 +508,7 @@ class CliProjectPackagerTest {
"resolvedDependencies": {} "resolvedDependencies": {}
} }
""" """
.trimIndent() .trimIndent(),
) )
CliProjectPackager( CliProjectPackager(
@@ -517,7 +517,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
.run() .run()
val expectedMetadata = tempDir.resolve(".out/mypackage@1.0.0/mypackage@1.0.0") val expectedMetadata = tempDir.resolve(".out/mypackage@1.0.0/mypackage@1.0.0")
@@ -598,7 +598,7 @@ class CliProjectPackagerTest {
["project2"] = import("../project2/PklProject") ["project2"] = import("../project2/PklProject")
} }
""" """
.trimIndent() .trimIndent(),
) )
projectDir.writeFile( projectDir.writeFile(
"PklProject.deps.json", "PklProject.deps.json",
@@ -621,7 +621,7 @@ class CliProjectPackagerTest {
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
project2Dir.writeFile( project2Dir.writeFile(
@@ -636,7 +636,7 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com/project2.zip" packageZipUrl = "https://foo.com/project2.zip"
} }
""" """
.trimIndent() .trimIndent(),
) )
project2Dir.writeFile( project2Dir.writeFile(
"PklProject.deps.json", "PklProject.deps.json",
@@ -646,7 +646,7 @@ class CliProjectPackagerTest {
"resolvedDependencies": {} "resolvedDependencies": {}
} }
""" """
.trimIndent() .trimIndent(),
) )
assertThatCode { assertThatCode {
CliProjectPackager( CliProjectPackager(
@@ -655,7 +655,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
.run() .run()
} }
@@ -671,7 +671,7 @@ class CliProjectPackagerTest {
res = foo res = foo
""" """
.trimIndent() .trimIndent(),
) )
tempDir.writeFile( tempDir.writeFile(
"PklProject", "PklProject",
@@ -685,7 +685,7 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com" packageZipUrl = "https://foo.com"
} }
""" """
.trimIndent() .trimIndent(),
) )
val e = val e =
assertThrows<CliException> { assertThrows<CliException> {
@@ -695,7 +695,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
.run() .run()
} }
@@ -725,7 +725,7 @@ class CliProjectPackagerTest {
res = foo res = foo
""" """
.trimIndent() .trimIndent(),
) )
tempDir.writeFile( tempDir.writeFile(
"PklProject", "PklProject",
@@ -739,7 +739,7 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com" packageZipUrl = "https://foo.com"
} }
""" """
.trimIndent() .trimIndent(),
) )
val e = val e =
assertThrows<CliException> { assertThrows<CliException> {
@@ -749,7 +749,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
.run() .run()
} }
@@ -771,7 +771,7 @@ class CliProjectPackagerTest {
""" """
res = read("$tempDir/foo.pkl") res = read("$tempDir/foo.pkl")
""" """
.trimIndent() .trimIndent(),
) )
tempDir.writeFile( tempDir.writeFile(
"PklProject", "PklProject",
@@ -785,7 +785,7 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com" packageZipUrl = "https://foo.com"
} }
""" """
.trimIndent() .trimIndent(),
) )
val e = val e =
assertThrows<CliException> { assertThrows<CliException> {
@@ -795,7 +795,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
.run() .run()
} }
@@ -816,7 +816,7 @@ class CliProjectPackagerTest {
""" """
import "baz.pkl" import "baz.pkl"
""" """
.trimIndent() .trimIndent(),
) )
tempDir.writeFile( tempDir.writeFile(
"PklProject", "PklProject",
@@ -830,7 +830,7 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com" packageZipUrl = "https://foo.com"
} }
""" """
.trimIndent() .trimIndent(),
) )
CliProjectPackager( CliProjectPackager(
CliBaseOptions(workingDir = tempDir), CliBaseOptions(workingDir = tempDir),
@@ -838,7 +838,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
.run() .run()
} }
@@ -858,7 +858,7 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com" packageZipUrl = "https://foo.com"
} }
""" """
.trimIndent() .trimIndent(),
) )
tempDir.writeFile("project2/main2.pkl", "res = 2") tempDir.writeFile("project2/main2.pkl", "res = 2")
tempDir.writeFile( tempDir.writeFile(
@@ -873,7 +873,7 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com" packageZipUrl = "https://foo.com"
} }
""" """
.trimIndent() .trimIndent(),
) )
val out = StringWriter() val out = StringWriter()
CliProjectPackager( CliProjectPackager(
@@ -882,7 +882,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = out consoleWriter = out,
) )
.run() .run()
val sep = File.separatorChar val sep = File.separatorChar
@@ -923,7 +923,7 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com" packageZipUrl = "https://foo.com"
} }
""" """
.trimIndent() .trimIndent(),
) )
val e = val e =
assertThrows<CliException> { assertThrows<CliException> {
@@ -931,13 +931,13 @@ class CliProjectPackagerTest {
CliBaseOptions( CliBaseOptions(
workingDir = tempDir, workingDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = packageServer.port testPort = packageServer.port,
), ),
listOf(tempDir.resolve("project")), listOf(tempDir.resolve("project")),
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = false, skipPublishCheck = false,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
.run() .run()
} }
@@ -968,20 +968,20 @@ class CliProjectPackagerTest {
packageZipUrl = "https://foo.com" packageZipUrl = "https://foo.com"
} }
""" """
.trimIndent() .trimIndent(),
) )
val out = StringWriter() val out = StringWriter()
CliProjectPackager( CliProjectPackager(
CliBaseOptions( CliBaseOptions(
workingDir = tempDir, workingDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = packageServer.port testPort = packageServer.port,
), ),
listOf(tempDir.resolve("project")), listOf(tempDir.resolve("project")),
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = false, skipPublishCheck = false,
consoleWriter = out consoleWriter = out,
) )
.run() .run()
val sep = File.separatorChar val sep = File.separatorChar
@@ -1025,7 +1025,7 @@ class CliProjectPackagerTest {
CliTestOptions(), CliTestOptions(),
".out/%{name}@%{version}", ".out/%{name}@%{version}",
skipPublishCheck = true, skipPublishCheck = true,
consoleWriter = StringWriter() consoleWriter = StringWriter(),
) )
packager.run() packager.run()
val expectedMetadata = tempDir.resolve(".out/mypackage@1.0.0/mypackage@1.0.0") val expectedMetadata = tempDir.resolve(".out/mypackage@1.0.0/mypackage@1.0.0")
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -47,7 +47,7 @@ class CliProjectResolverTest {
CliBaseOptions(workingDir = tempDir, noCache = true), CliBaseOptions(workingDir = tempDir, noCache = true),
emptyList(), emptyList(),
consoleWriter = StringWriter(), consoleWriter = StringWriter(),
errWriter = StringWriter() errWriter = StringWriter(),
) )
val err = assertThrows<CliException> { packager.run() } val err = assertThrows<CliException> { packager.run() }
assertThat(err).hasMessageStartingWith("No project visible to the working directory.") assertThat(err).hasMessageStartingWith("No project visible to the working directory.")
@@ -60,7 +60,7 @@ class CliProjectResolverTest {
CliBaseOptions(noCache = true), CliBaseOptions(noCache = true),
listOf(tempDir), listOf(tempDir),
consoleWriter = StringWriter(), consoleWriter = StringWriter(),
errWriter = StringWriter() errWriter = StringWriter(),
) )
val err = assertThrows<CliException> { packager.run() } val err = assertThrows<CliException> { packager.run() }
assertThat(err).hasMessageStartingWith("Directory $tempDir does not contain a PklProject file.") assertThat(err).hasMessageStartingWith("Directory $tempDir does not contain a PklProject file.")
@@ -79,18 +79,18 @@ class CliProjectResolverTest {
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
CliProjectResolver( CliProjectResolver(
CliBaseOptions( CliBaseOptions(
workingDir = tempDir, workingDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = packageServer.port, testPort = packageServer.port,
noCache = true noCache = true,
), ),
listOf(tempDir), listOf(tempDir),
consoleWriter = StringWriter(), consoleWriter = StringWriter(),
errWriter = StringWriter() errWriter = StringWriter(),
) )
.run() .run()
val expectedOutput = tempDir.resolve("PklProject.deps.json") val expectedOutput = tempDir.resolve("PklProject.deps.json")
@@ -134,18 +134,18 @@ class CliProjectResolverTest {
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
CliProjectResolver( CliProjectResolver(
CliBaseOptions( CliBaseOptions(
workingDir = tempDir, workingDir = tempDir,
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = packageServer.port, testPort = packageServer.port,
noCache = true noCache = true,
), ),
emptyList(), emptyList(),
consoleWriter = StringWriter(), consoleWriter = StringWriter(),
errWriter = StringWriter() errWriter = StringWriter(),
) )
.run() .run()
val expectedOutput = tempDir.resolve("PklProject.deps.json") val expectedOutput = tempDir.resolve("PklProject.deps.json")
@@ -191,7 +191,7 @@ class CliProjectResolverTest {
["project2"] = import("../project2/PklProject") ["project2"] = import("../project2/PklProject")
} }
""" """
.trimIndent() .trimIndent(),
) )
projectDir.writeFile( projectDir.writeFile(
"../project2/PklProject", "../project2/PklProject",
@@ -212,7 +212,7 @@ class CliProjectResolverTest {
["project3"] = import("../project3/PklProject") ["project3"] = import("../project3/PklProject")
} }
""" """
.trimIndent() .trimIndent(),
) )
projectDir.writeFile( projectDir.writeFile(
@@ -233,17 +233,17 @@ class CliProjectResolverTest {
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
CliProjectResolver( CliProjectResolver(
CliBaseOptions( CliBaseOptions(
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = packageServer.port, testPort = packageServer.port,
noCache = true noCache = true,
), ),
listOf(projectDir), listOf(projectDir),
consoleWriter = StringWriter(), consoleWriter = StringWriter(),
errWriter = StringWriter() errWriter = StringWriter(),
) )
.run() .run()
val expectedOutput = projectDir.resolve("PklProject.deps.json") val expectedOutput = projectDir.resolve("PklProject.deps.json")
@@ -299,7 +299,7 @@ class CliProjectResolverTest {
["fruit"] = import("../fruit/PklProject") ["fruit"] = import("../fruit/PklProject")
} }
""" """
.trimIndent() .trimIndent(),
) )
projectDir.writeFile( projectDir.writeFile(
"../fruit/PklProject", "../fruit/PklProject",
@@ -313,7 +313,7 @@ class CliProjectResolverTest {
packageZipUrl = "https://foo.com/fruit.zip" packageZipUrl = "https://foo.com/fruit.zip"
} }
""" """
.trimIndent() .trimIndent(),
) )
val consoleOut = StringWriter() val consoleOut = StringWriter()
val errOut = StringWriter() val errOut = StringWriter()
@@ -321,11 +321,11 @@ class CliProjectResolverTest {
CliBaseOptions( CliBaseOptions(
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = packageServer.port, testPort = packageServer.port,
noCache = true noCache = true,
), ),
listOf(projectDir), listOf(projectDir),
consoleWriter = consoleOut, consoleWriter = consoleOut,
errWriter = errOut errWriter = errOut,
) )
.run() .run()
val expectedOutput = projectDir.resolve("PklProject.deps.json") val expectedOutput = projectDir.resolve("PklProject.deps.json")
@@ -373,7 +373,7 @@ class CliProjectResolverTest {
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
tempDir.writeFile( tempDir.writeFile(
@@ -387,7 +387,7 @@ class CliProjectResolverTest {
} }
} }
""" """
.trimIndent() .trimIndent(),
) )
val consoleOut = StringWriter() val consoleOut = StringWriter()
@@ -396,11 +396,11 @@ class CliProjectResolverTest {
CliBaseOptions( CliBaseOptions(
caCertificates = listOf(FileTestUtils.selfSignedCertificate), caCertificates = listOf(FileTestUtils.selfSignedCertificate),
testPort = packageServer.port, testPort = packageServer.port,
noCache = true noCache = true,
), ),
listOf(tempDir.resolve("project1"), tempDir.resolve("project2")), listOf(tempDir.resolve("project1"), tempDir.resolve("project2")),
consoleWriter = consoleOut, consoleWriter = consoleOut,
errWriter = errOut errWriter = errOut,
) )
.run() .run()
val sep = File.separatorChar val sep = File.separatorChar
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,18 +15,17 @@
*/ */
package org.pkl.cli package org.pkl.cli
import com.github.ajalt.clikt.core.MissingArgument import com.github.ajalt.clikt.testing.test
import com.github.ajalt.clikt.core.subcommands
import java.io.StringWriter import java.io.StringWriter
import java.io.Writer import java.io.Writer
import java.net.URI import java.net.URI
import java.nio.file.Path import java.nio.file.Path
import java.util.*
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.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir import org.junit.jupiter.api.io.TempDir
import org.pkl.cli.commands.EvalCommand
import org.pkl.cli.commands.RootCommand import org.pkl.cli.commands.RootCommand
import org.pkl.commons.cli.CliBaseOptions import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.cli.CliException import org.pkl.commons.cli.CliException
@@ -34,7 +33,6 @@ import org.pkl.commons.cli.CliTestOptions
import org.pkl.commons.readString import org.pkl.commons.readString
import org.pkl.commons.toUri import org.pkl.commons.toUri
import org.pkl.commons.writeString import org.pkl.commons.writeString
import org.pkl.core.Release
class CliTestRunnerTest { class CliTestRunnerTest {
@Test @Test
@@ -380,7 +378,7 @@ class CliTestRunnerTest {
val opts = val opts =
CliBaseOptions( CliBaseOptions(
sourceModules = listOf(input.toUri(), input2.toUri()), sourceModules = listOf(input.toUri(), input2.toUri()),
settings = URI("pkl:settings") settings = URI("pkl:settings"),
) )
val testOpts = CliTestOptions(junitDir = tempDir) val testOpts = CliTestOptions(junitDir = tempDir)
val runner = CliTestRunner(opts, testOpts, noopWriter, noopWriter) val runner = CliTestRunner(opts, testOpts, noopWriter, noopWriter)
@@ -390,14 +388,9 @@ class CliTestRunnerTest {
@Test @Test
fun `no source modules specified has same message as pkl eval`() { fun `no source modules specified has same message as pkl eval`() {
val e1 = assertThrows<CliException> { CliTestRunner(CliBaseOptions(), CliTestOptions()).run() } val e1 = assertThrows<CliException> { CliTestRunner(CliBaseOptions(), CliTestOptions()).run() }
val e2 = val e2 = RootCommand().test("eval")
assertThrows<MissingArgument> { assertThat(e1).hasMessageContaining("missing argument <modules>")
val rootCommand = assertThat(e1.message!!.replace("test", "eval") + "\n").isEqualTo(e2.stderr)
RootCommand("pkl", Release.current().versionInfo(), "").subcommands(EvalCommand(""))
rootCommand.parse(listOf("eval"))
}
assertThat(e1).hasMessageContaining("Missing argument \"<modules>\"")
assertThat(e1.message!!.replace("test", "eval")).isEqualTo(e2.helpMessage())
} }
@Test @Test
@@ -487,6 +480,50 @@ class CliTestRunnerTest {
) )
} }
@Test
fun `CliTestRunner locale independence test`(@TempDir tempDir: Path) {
val originalLocale = Locale.getDefault()
Locale.setDefault(Locale.GERMANY)
try {
val code =
"""
amends "pkl:test"
facts {
["localeTest"] {
1 == 1
}
}
"""
.trimIndent()
val input = tempDir.resolve("test.pkl").writeString(code).toString()
val out = StringWriter()
val err = StringWriter()
val opts =
CliBaseOptions(sourceModules = listOf(input.toUri()), settings = URI("pkl:settings"))
val testOpts = CliTestOptions()
val runner = CliTestRunner(opts, testOpts, consoleWriter = out, errWriter = err)
runner.run()
assertThat(out.toString().stripFileAndLines(tempDir))
.isEqualTo(
"""
module test
facts
✔ localeTest
100.0% tests pass [1 passed], 100.0% asserts pass [1 passed]
"""
.trimIndent()
)
assertThat(err.toString()).isEqualTo("")
} finally {
Locale.setDefault(originalLocale)
}
}
private fun String.stripFileAndLines(tmpDir: Path): String { private fun String.stripFileAndLines(tmpDir: Path): String {
// handle platform differences in handling of file URIs // handle platform differences in handling of file URIs
// (file:/// on *nix vs. file:/ on Windows) // (file:/// on *nix vs. file:/ on Windows)
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@ package org.pkl.cli
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.nio.file.Path import java.nio.file.Path
import org.pkl.commons.createParentDirectories import kotlin.io.path.createParentDirectories
import org.pkl.commons.writeString import org.pkl.commons.writeString
fun Path.writeFile(fileName: String, contents: String): Path { fun Path.writeFile(fileName: String, contents: String): Path {
+71 -33
View File
@@ -1,40 +1,78 @@
# This is a Gradle generated file for dependency locking. # This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised. # Manual edits can break the build and are not advised.
# This file is expected to be part of source control. # This file is expected to be part of source control.
com.github.ajalt.clikt:clikt-jvm:3.5.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath com.github.ajalt.clikt:clikt-core-jvm:5.0.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ajalt.clikt:clikt:3.5.4=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.github.ajalt.clikt:clikt-core:5.0.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.squareup:javapoet:1.13.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath com.github.ajalt.clikt:clikt-jvm:5.0.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.tunnelvisionlabs:antlr4-runtime:4.9.0=runtimeClasspath,testRuntimeClasspath com.github.ajalt.clikt:clikt-markdown-jvm:5.0.3=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.clikt:clikt-markdown:5.0.3=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.clikt:clikt:5.0.3=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.ajalt.colormath:colormath-jvm:3.6.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ajalt.colormath:colormath:3.6.0=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.ajalt.mordant:mordant-core-jvm:3.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-core:3.0.1=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-ffm-jvm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-ffm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-graal-ffi-jvm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-graal-ffi:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-jna-jvm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm-jna:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-jvm:3.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-markdown-jvm:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant-markdown:3.0.1=runtimeClasspath,testRuntimeClasspath
com.github.ajalt.mordant:mordant:3.0.1=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.palantir.javapoet:javapoet:0.6.0=compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
net.bytebuddy:byte-buddy:1.14.18=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
net.java.dev.jna:jna:5.6.0=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath net.java.dev.jna:jna:5.14.0=runtimeClasspath,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata
org.assertj:assertj-core:3.26.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:23.0.6=runtimeClasspath,testRuntimeClasspath org.graalvm.polyglot:polyglot:24.1.2=runtimeClasspath,testRuntimeClasspath
org.graalvm.truffle:truffle-api:23.0.6=runtimeClasspath,testRuntimeClasspath org.graalvm.sdk:collections:24.1.2=runtimeClasspath,testRuntimeClasspath
org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.sdk:graal-sdk:24.1.2=runtimeClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-compiler-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.sdk:nativeimage:24.1.2=runtimeClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-daemon-embeddable:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.graalvm.sdk:word:24.1.2=runtimeClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.7.10=kotlinKlibCommonizerClasspath org.graalvm.truffle:truffle-api:24.1.2=runtimeClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-reflect:1.7.10=kotlinCompilerClasspath,kotlinKlibCommonizerClasspath org.jetbrains.intellij.deps:trove4j:1.0.20200330=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-script-runtime:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath org.jetbrains.kotlin:kotlin-build-common:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-common:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-build-tools-api:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-build-tools-impl:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-jvm:1.7.10=kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest org.jetbrains.kotlin:kotlin-compiler-runner:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-daemon-client:2.0.21=kotlinBuildToolsApiClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:2.0.21=kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-stdlib:1.7.10=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-native-prebuilt:2.0.21=kotlinNativeBundleConfiguration
org.jetbrains:annotations:13.0=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-reflect:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.junit.jupiter:junit-jupiter-api:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-script-runtime:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17,kotlinKlibCommonizerClasspath
org.junit.jupiter:junit-jupiter-engine:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-scripting-common:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.junit.jupiter:junit-jupiter-params:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.junit.platform:junit-platform-commons:1.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.junit.platform:junit-platform-engine:1.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-scripting-jvm:2.0.21=kotlinBuildToolsApiClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17
org.junit:junit-bom:5.11.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-stdlib:2.0.21=apiDependenciesMetadata,compileClasspath,implementationDependenciesMetadata,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinKlibCommonizerClasspath
org.jetbrains:annotations:13.0=compileClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinCompilerPluginClasspathTestJdk17,kotlinKlibCommonizerClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains:markdown-jvm:0.7.3=runtimeClasspath,testRuntimeClasspath
org.jetbrains:markdown:0.7.3=runtimeClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-api:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-engine:5.8.2=testJdk17RuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.jupiter:junit-jupiter:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.platform:junit-platform-commons:1.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-commons:1.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.junit.platform:junit-platform-engine:1.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-engine:1.8.2=testJdk17RuntimeClasspath
org.junit.platform:junit-platform-launcher:1.8.2=testJdk17RuntimeClasspath
org.junit:junit-bom:5.11.4=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit:junit-bom:5.8.2=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.msgpack:msgpack-core:0.9.8=runtimeClasspath,testRuntimeClasspath org.msgpack:msgpack-core:0.9.8=runtimeClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.2.0=testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testJdk17RuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.organicdesign:Paguro:3.10.3=runtimeClasspath,testRuntimeClasspath org.organicdesign:Paguro:3.10.3=runtimeClasspath,testRuntimeClasspath
org.snakeyaml:snakeyaml-engine:2.5=runtimeClasspath,testRuntimeClasspath org.snakeyaml:snakeyaml-engine:2.9=runtimeClasspath,testRuntimeClasspath
empty=annotationProcessor,compileOnlyDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtimeOnlyDependenciesMetadata,signatures,sourcesJar,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions empty=annotationProcessor,compileOnlyDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtimeOnlyDependenciesMetadata,signatures,sourcesJar,testAnnotationProcessor,testApiDependenciesMetadata,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testJdk17AnnotationProcessor,testJdk17ApiDependenciesMetadata,testJdk17CompileOnlyDependenciesMetadata,testJdk17IntransitiveDependenciesMetadata,testJdk17KotlinScriptDefExtensions,testKotlinScriptDef,testKotlinScriptDefExtensions
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@
package org.pkl.codegen.java package org.pkl.codegen.java
import java.io.IOException import java.io.IOException
import kotlin.io.path.createParentDirectories
import org.pkl.commons.cli.CliCommand import org.pkl.commons.cli.CliCommand
import org.pkl.commons.cli.CliException import org.pkl.commons.cli.CliException
import org.pkl.commons.createParentDirectories
import org.pkl.commons.writeString import org.pkl.commons.writeString
import org.pkl.core.Closeables import org.pkl.core.Closeables
import org.pkl.core.ModuleSource import org.pkl.core.ModuleSource
@@ -33,7 +33,7 @@ class CliJavaCodeGenerator(private val options: CliJavaCodeGeneratorOptions) :
builder.build().use { evaluator -> builder.build().use { evaluator ->
for (moduleUri in options.base.normalizedSourceModules) { for (moduleUri in options.base.normalizedSourceModules) {
val schema = evaluator.evaluateSchema(ModuleSource.uri(moduleUri)) val schema = evaluator.evaluateSchema(ModuleSource.uri(moduleUri))
val codeGenerator = JavaCodeGenerator(schema, options.toJavaCodegenOptions()) val codeGenerator = JavaCodeGenerator(schema, options.toJavaCodeGeneratorOptions())
try { try {
for ((fileName, fileContents) in codeGenerator.output) { for ((fileName, fileContents) in codeGenerator.output) {
val outputFile = options.outputDir.resolve(fileName) val outputFile = options.outputDir.resolve(fileName)
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -35,25 +35,35 @@ data class CliJavaCodeGeneratorOptions(
*/ */
val generateGetters: Boolean = false, val generateGetters: Boolean = false,
/** Whether to generate Javadoc based on doc comments for Pkl modules, classes, and properties. */ /** Whether to preserve Pkl doc comments by generating corresponding Javadoc comments. */
val generateJavadoc: Boolean = false, val generateJavadoc: Boolean = false,
/** Whether to generate config classes for use with Spring Boot. */ /** Whether to generate config classes for use with Spring Boot. */
val generateSpringBootConfig: Boolean = false, val generateSpringBootConfig: Boolean = false,
/** /**
* Fully qualified name of the annotation to use on constructor parameters. If this options is not * Fully qualified name of the annotation type to use for annotating constructor parameters with
* set, [org.pkl.config.java.mapper.Named] will be used. * their name.
*
* The specified annotation type must have a `value` parameter of type [java.lang.String] or the
* generated code may not compile.
*
* If set to `null`, constructor parameters are not annotated. The default value is `null` if
* [generateSpringBootConfig] is `true` and `"org.pkl.config.java.mapper.Named"` otherwise.
*/ */
val paramsAnnotation: String? = null, val paramsAnnotation: String? =
if (generateSpringBootConfig) null else "org.pkl.config.java.mapper.Named",
/** /**
* Fully qualified name of the annotation to use on non-null properties. If this option is not * Fully qualified name of the annotation type to use for annotating non-null types.
* set, [org.pkl.config.java.mapper.NonNull] will be used. *
* The specified annotation type must have a [java.lang.annotation.Target] of
* [java.lang.annotation.ElementType.TYPE_USE] or the generated code may not compile. If set to
* `null`, [org.pkl.config.java.mapper.NonNull] will be used.
*/ */
val nonNullAnnotation: String? = null, val nonNullAnnotation: String? = null,
/** Whether to make generated classes implement [java.io.Serializable] */ /** Whether to generate classes that implement [java.io.Serializable]. */
val implementSerializable: Boolean = false, val implementSerializable: Boolean = false,
/** /**
@@ -63,10 +73,14 @@ data class CliJavaCodeGeneratorOptions(
* Pkl module names, you can define a rename mapping, where the key is a prefix of the original * Pkl module names, you can define a rename mapping, where the key is a prefix of the original
* Pkl module name, and the value is the desired replacement. * Pkl module name, and the value is the desired replacement.
*/ */
val renames: Map<String, String> = emptyMap() val renames: Map<String, String> = emptyMap(),
) { ) {
fun toJavaCodegenOptions() = @Suppress("DeprecatedCallableAddReplaceWith")
JavaCodegenOptions( @Deprecated("deprecated without replacement")
fun toJavaCodegenOptions() = toJavaCodeGeneratorOptions()
internal fun toJavaCodeGeneratorOptions() =
JavaCodeGeneratorOptions(
indent, indent,
generateGetters, generateGetters,
generateJavadoc, generateJavadoc,
@@ -74,6 +88,6 @@ data class CliJavaCodeGeneratorOptions(
paramsAnnotation, paramsAnnotation,
nonNullAnnotation, nonNullAnnotation,
implementSerializable, implementSerializable,
renames renames,
) )
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,10 +15,9 @@
*/ */
package org.pkl.codegen.java package org.pkl.codegen.java
import com.squareup.javapoet.* import com.palantir.javapoet.*
import java.io.StringWriter import java.io.StringWriter
import java.lang.Deprecated import java.lang.Deprecated
import java.net.URI
import java.util.* import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
import javax.lang.model.element.Modifier import javax.lang.model.element.Modifier
@@ -41,7 +40,10 @@ import org.pkl.core.util.IoUtils
class JavaCodeGeneratorException(message: String) : RuntimeException(message) class JavaCodeGeneratorException(message: String) : RuntimeException(message)
data class JavaCodegenOptions( @kotlin.Deprecated("renamed to JavaCodeGeneratorOptions", ReplaceWith("JavaCodeGeneratorOptions"))
typealias JavaCodegenOptions = JavaCodeGeneratorOptions
data class JavaCodeGeneratorOptions(
/** The characters to use for indenting generated Java code. */ /** The characters to use for indenting generated Java code. */
val indent: String = " ", val indent: String = " ",
@@ -51,25 +53,35 @@ data class JavaCodegenOptions(
*/ */
val generateGetters: Boolean = false, val generateGetters: Boolean = false,
/** Whether to generate Javadoc based on doc comments for Pkl modules, classes, and properties. */ /** Whether to preserve Pkl doc comments by generating corresponding Javadoc comments. */
val generateJavadoc: Boolean = false, val generateJavadoc: Boolean = false,
/** Whether to generate config classes for use with Spring Boot. */ /** Whether to generate config classes for use with Spring Boot. */
val generateSpringBootConfig: Boolean = false, val generateSpringBootConfig: Boolean = false,
/** /**
* Fully qualified name of the annotation to use on constructor parameters. If this options is not * Fully qualified name of the annotation type to use for annotating constructor parameters with
* set, [org.pkl.config.java.mapper.Named] will be used. * their name.
*
* The specified annotation type must have a `value` parameter of type [java.lang.String] or the
* generated code may not compile.
*
* If set to `null`, constructor parameters are not annotated. The default value is `null` if
* [generateSpringBootConfig] is `true` and `"org.pkl.config.java.mapper.Named"` otherwise.
*/ */
val paramsAnnotation: String? = null, val paramsAnnotation: String? =
if (generateSpringBootConfig) null else "org.pkl.config.java.mapper.Named",
/** /**
* Fully qualified name of the annotation to use on non-null properties. If this option is not * Fully qualified name of the annotation type to use for annotating non-null types.
* set, [org.pkl.config.java.mapper.NonNull] will be used. *
* The specified annotation type must have a [java.lang.annotation.Target] of
* [java.lang.annotation.ElementType.TYPE_USE] or the generated code may not compile. If set to
* `null`, [org.pkl.config.java.mapper.NonNull] will be used.
*/ */
val nonNullAnnotation: String? = null, val nonNullAnnotation: String? = null,
/** Whether to make generated classes implement [java.io.Serializable] */ /** Whether to generate classes that implement [java.io.Serializable]. */
val implementSerializable: Boolean = false, val implementSerializable: Boolean = false,
/** /**
@@ -78,16 +90,17 @@ data class JavaCodegenOptions(
* Can be used when the class or package name in the generated source code should be different * Can be used when the class or package name in the generated source code should be different
* from the corresponding name derived from the Pkl module declaration . * from the corresponding name derived from the Pkl module declaration .
*/ */
val renames: Map<String, String> = emptyMap() val renames: Map<String, String> = emptyMap(),
) )
/** Entrypoint for the Java code generator API. */ /** Entrypoint for the Java code generator API. */
class JavaCodeGenerator( class JavaCodeGenerator(
private val schema: ModuleSchema, private val schema: ModuleSchema,
private val codegenOptions: JavaCodegenOptions private val codegenOptions: JavaCodeGeneratorOptions,
) { ) {
companion object { companion object {
private val OBJECT = ClassName.get(Object::class.java)
private val STRING = ClassName.get(String::class.java) private val STRING = ClassName.get(String::class.java)
private val DURATION = ClassName.get(Duration::class.java) private val DURATION = ClassName.get(Duration::class.java)
private val DURATION_UNIT = ClassName.get(DurationUnit::class.java) private val DURATION_UNIT = ClassName.get(DurationUnit::class.java)
@@ -101,7 +114,7 @@ class JavaCodeGenerator(
private val PMODULE = ClassName.get(PModule::class.java) private val PMODULE = ClassName.get(PModule::class.java)
private val PCLASS = ClassName.get(PClass::class.java) private val PCLASS = ClassName.get(PClass::class.java)
private val PATTERN = ClassName.get(Pattern::class.java) private val PATTERN = ClassName.get(Pattern::class.java)
private val URI = ClassName.get(URI::class.java) private val URI = ClassName.get(java.net.URI::class.java)
private val VERSION = ClassName.get(Version::class.java) private val VERSION = ClassName.get(Version::class.java)
private const val PROPERTY_PREFIX: String = "org.pkl.config.java.mapper." private const val PROPERTY_PREFIX: String = "org.pkl.config.java.mapper."
@@ -221,20 +234,23 @@ class JavaCodeGenerator(
val properties = renameIfReservedWord(pClass.properties).filterValues { !it.isHidden } val properties = renameIfReservedWord(pClass.properties).filterValues { !it.isHidden }
val allProperties = superProperties + properties val allProperties = superProperties + properties
fun PClass.Property.isRegex(): Boolean =
(this.type as? PType.Class)?.pClass?.info == PClassInfo.Regex
fun addCtorParameter( fun addCtorParameter(
builder: MethodSpec.Builder, builder: MethodSpec.Builder,
propJavaName: String, propJavaName: String,
property: PClass.Property property: PClass.Property,
) { ) {
builder.addParameter( val paramBuilder = ParameterSpec.builder(property.type.toJavaPoetName(), propJavaName)
ParameterSpec.builder(property.type.toJavaPoetName(), propJavaName) if (paramsAnnotationName != null) {
.addAnnotation( paramBuilder.addAnnotation(
AnnotationSpec.builder(namedAnnotationName) AnnotationSpec.builder(paramsAnnotationName)
.addMember("value", "\$S", property.simpleName) .addMember("value", "\$S", property.simpleName)
.build() .build()
) )
.build() }
) builder.addParameter(paramBuilder.build())
} }
fun generateConstructor(isInstantiable: Boolean): MethodSpec { fun generateConstructor(isInstantiable: Boolean): MethodSpec {
@@ -283,14 +299,12 @@ class JavaCodeGenerator(
.addStatement("\$T other = (\$T) obj", javaPoetClassName, javaPoetClassName) .addStatement("\$T other = (\$T) obj", javaPoetClassName, javaPoetClassName)
for ((propertyName, property) in allProperties) { for ((propertyName, property) in allProperties) {
val accessor = val accessor = if (property.isRegex()) "\$N.pattern()" else "\$N"
if ((property.type as? PType.Class)?.pClass?.info == PClassInfo.Regex) "\$N.pattern()"
else "\$N"
builder.addStatement( builder.addStatement(
"if (!\$T.equals(this.$accessor, other.$accessor)) return false", "if (!\$T.equals(this.$accessor, other.$accessor)) return false",
Objects::class.java, Objects::class.java,
propertyName, propertyName,
propertyName propertyName,
) )
} }
@@ -306,11 +320,12 @@ class JavaCodeGenerator(
.returns(Int::class.java) .returns(Int::class.java)
.addStatement("int result = 1") .addStatement("int result = 1")
for (propertyName in allProperties.keys) { for ((propertyName, property) in allProperties) {
val accessor = if (property.isRegex()) "this.\$N.pattern()" else "this.\$N"
builder.addStatement( builder.addStatement(
"result = 31 * result + \$T.hashCode(this.\$N)", "result = 31 * result + \$T.hashCode($accessor)",
Objects::class.java, Objects::class.java,
propertyName propertyName,
) )
} }
@@ -332,7 +347,7 @@ class JavaCodeGenerator(
appendBuilder.addStatement( appendBuilder.addStatement(
"appendProperty(builder, \$S, this.\$N)", "appendProperty(builder, \$S, this.\$N)",
propertyName, propertyName,
propertyName propertyName,
) )
} }
@@ -341,7 +356,7 @@ class JavaCodeGenerator(
"\$T builder = new \$T(\$L)", "\$T builder = new \$T(\$L)",
StringBuilder::class.java, StringBuilder::class.java,
StringBuilder::class.java, StringBuilder::class.java,
builderSize builderSize,
) )
.addStatement("builder.append(\$T.class.getSimpleName()).append(\" {\")", javaPoetClassName) .addStatement("builder.append(\$T.class.getSimpleName()).append(\" {\")", javaPoetClassName)
.addCode(appendBuilder.build()) .addCode(appendBuilder.build())
@@ -365,7 +380,7 @@ class JavaCodeGenerator(
annotations: Collection<PObject>, annotations: Collection<PObject>,
hasJavadoc: Boolean, hasJavadoc: Boolean,
addAnnotation: (Class<*>) -> Unit, addAnnotation: (Class<*>) -> Unit,
addJavadoc: (String) -> Unit addJavadoc: (String) -> Unit,
) { ) {
annotations annotations
.firstOrNull { it.classInfo == PClassInfo.Deprecated } .firstOrNull { it.classInfo == PClassInfo.Deprecated }
@@ -401,7 +416,7 @@ class JavaCodeGenerator(
property.annotations, property.annotations,
hasJavadoc, hasJavadoc,
{ builder.addAnnotation(it) }, { builder.addAnnotation(it) },
{ builder.addJavadoc(it) } { builder.addJavadoc(it) },
) )
builder.addModifiers(Modifier.PUBLIC) builder.addModifiers(Modifier.PUBLIC)
} }
@@ -414,7 +429,7 @@ class JavaCodeGenerator(
fun generateGetter( fun generateGetter(
propertyName: String, propertyName: String,
property: PClass.Property, property: PClass.Property,
isOverridden: Boolean isOverridden: Boolean,
): MethodSpec { ): MethodSpec {
val propertyType = property.type val propertyType = property.type
val isBooleanProperty = val isBooleanProperty =
@@ -444,7 +459,7 @@ class JavaCodeGenerator(
property.annotations, property.annotations,
hasJavadoc, hasJavadoc,
{ builder.addAnnotation(it) }, { builder.addAnnotation(it) },
{ builder.addJavadoc(it) } { builder.addJavadoc(it) },
) )
return builder.build() return builder.build()
@@ -463,7 +478,7 @@ class JavaCodeGenerator(
property.annotations, property.annotations,
false, false,
{ methodBuilder.addAnnotation(it) }, { methodBuilder.addAnnotation(it) },
{ methodBuilder.addJavadoc(it) } { methodBuilder.addJavadoc(it) },
) )
val codeBuilder = CodeBlock.builder() val codeBuilder = CodeBlock.builder()
@@ -519,7 +534,7 @@ class JavaCodeGenerator(
AnnotationSpec.builder( AnnotationSpec.builder(
ClassName.get( ClassName.get(
"org.springframework.boot.context.properties", "org.springframework.boot.context.properties",
"ConfigurationProperties" "ConfigurationProperties",
) )
) )
// use "value" instead of "prefix" to entice JavaPoet to generate a single-line // use "value" instead of "prefix" to entice JavaPoet to generate a single-line
@@ -556,7 +571,7 @@ class JavaCodeGenerator(
pClass.annotations, pClass.annotations,
hasJavadoc, hasJavadoc,
{ builder.addAnnotation(it) }, { builder.addAnnotation(it) },
{ builder.addJavadoc(it) } { builder.addJavadoc(it) },
) )
if (!isModuleClass) { if (!isModuleClass) {
@@ -616,7 +631,7 @@ class JavaCodeGenerator(
private fun generateEnumTypeSpec( private fun generateEnumTypeSpec(
typeAlias: TypeAlias, typeAlias: TypeAlias,
stringLiterals: Set<String> stringLiterals: Set<String>,
): TypeSpec.Builder { ): TypeSpec.Builder {
val enumConstantToPklNames = val enumConstantToPklNames =
stringLiterals stringLiterals
@@ -658,19 +673,15 @@ class JavaCodeGenerator(
for ((enumConstantName, pklName) in enumConstantToPklNames) { for ((enumConstantName, pklName) in enumConstantToPklNames) {
builder.addEnumConstant( builder.addEnumConstant(
enumConstantName, enumConstantName,
TypeSpec.anonymousClassBuilder("\$S", pklName).build() TypeSpec.anonymousClassBuilder("\$S", pklName).build(),
) )
} }
return builder return builder
} }
private val namedAnnotationName = private val paramsAnnotationName: ClassName? =
if (codegenOptions.paramsAnnotation != null) { codegenOptions.paramsAnnotation?.let { toClassName(it) }
toClassName(codegenOptions.paramsAnnotation)
} else {
ClassName.get("org.pkl.config.java.mapper", "Named")
}
private fun appendPropertyMethod() = private fun appendPropertyMethod() =
MethodSpec.methodBuilder("appendProperty") MethodSpec.methodBuilder("appendProperty")
@@ -682,7 +693,7 @@ class JavaCodeGenerator(
.addStatement( .addStatement(
"\$T lines = \$T.toString(value).split(\"\\n\")", "\$T lines = \$T.toString(value).split(\"\\n\")",
ArrayTypeName.of(String::class.java), ArrayTypeName.of(String::class.java),
Objects::class.java Objects::class.java,
) )
.addStatement("builder.append(lines[0])") .addStatement("builder.append(lines[0])")
.beginControlFlow("for (int i = 1; i < lines.length; i++)") .beginControlFlow("for (int i = 1; i < lines.length; i++)")
@@ -706,7 +717,7 @@ class JavaCodeGenerator(
/** Generate `List<? extends Foo>` if `Foo` is `abstract` or `open`, to allow subclassing. */ /** Generate `List<? extends Foo>` if `Foo` is `abstract` or `open`, to allow subclassing. */
private fun PType.toJavaPoetTypeArgumentName(): TypeName { private fun PType.toJavaPoetTypeArgumentName(): TypeName {
val baseName = toJavaPoetName(nullable = false, boxed = true) val baseName = toJavaPoetName(boxed = true)
return if (this is PType.Class && (pClass.isAbstract || pClass.isOpen)) { return if (this is PType.Class && (pClass.isAbstract || pClass.isOpen)) {
WildcardTypeName.subtypeOf(baseName) WildcardTypeName.subtypeOf(baseName)
} else { } else {
@@ -716,15 +727,15 @@ class JavaCodeGenerator(
private fun PType.toJavaPoetName(nullable: Boolean = false, boxed: Boolean = false): TypeName = private fun PType.toJavaPoetName(nullable: Boolean = false, boxed: Boolean = false): TypeName =
when (this) { when (this) {
PType.UNKNOWN -> TypeName.OBJECT.nullableIf(nullable) PType.UNKNOWN -> OBJECT.nullableIf(nullable)
PType.NOTHING -> TypeName.VOID PType.NOTHING -> TypeName.VOID
is PType.StringLiteral -> STRING.nullableIf(nullable) is PType.StringLiteral -> STRING.nullableIf(nullable)
is PType.Class -> { is PType.Class -> {
// if in doubt, spell it out // if in doubt, spell it out
when (val classInfo = pClass.info) { when (val classInfo = pClass.info) {
PClassInfo.Any -> TypeName.OBJECT PClassInfo.Any -> OBJECT
PClassInfo.Typed, PClassInfo.Typed,
PClassInfo.Dynamic -> TypeName.OBJECT.nullableIf(nullable) PClassInfo.Dynamic -> OBJECT.nullableIf(nullable)
PClassInfo.Boolean -> TypeName.BOOLEAN.boxIf(boxed).nullableIf(nullable) PClassInfo.Boolean -> TypeName.BOOLEAN.boxIf(boxed).nullableIf(nullable)
PClassInfo.String -> STRING.nullableIf(nullable) PClassInfo.String -> STRING.nullableIf(nullable)
// seems more useful to generate `double` than `java.lang.Number` // seems more useful to generate `double` than `java.lang.Number`
@@ -737,25 +748,25 @@ class JavaCodeGenerator(
ParameterizedTypeName.get( ParameterizedTypeName.get(
PAIR, PAIR,
if (typeArguments.isEmpty()) { if (typeArguments.isEmpty()) {
TypeName.OBJECT OBJECT
} else { } else {
typeArguments[0].toJavaPoetTypeArgumentName() typeArguments[0].toJavaPoetTypeArgumentName()
}, },
if (typeArguments.isEmpty()) { if (typeArguments.isEmpty()) {
TypeName.OBJECT OBJECT
} else { } else {
typeArguments[1].toJavaPoetTypeArgumentName() typeArguments[1].toJavaPoetTypeArgumentName()
} },
) )
.nullableIf(nullable) .nullableIf(nullable)
PClassInfo.Collection -> PClassInfo.Collection ->
ParameterizedTypeName.get( ParameterizedTypeName.get(
COLLECTION, COLLECTION,
if (typeArguments.isEmpty()) { if (typeArguments.isEmpty()) {
TypeName.OBJECT OBJECT
} else { } else {
typeArguments[0].toJavaPoetTypeArgumentName() typeArguments[0].toJavaPoetTypeArgumentName()
} },
) )
.nullableIf(nullable) .nullableIf(nullable)
PClassInfo.List, PClassInfo.List,
@@ -763,10 +774,10 @@ class JavaCodeGenerator(
ParameterizedTypeName.get( ParameterizedTypeName.get(
LIST, LIST,
if (typeArguments.isEmpty()) { if (typeArguments.isEmpty()) {
TypeName.OBJECT OBJECT
} else { } else {
typeArguments[0].toJavaPoetTypeArgumentName() typeArguments[0].toJavaPoetTypeArgumentName()
} },
) )
.nullableIf(nullable) .nullableIf(nullable)
} }
@@ -774,10 +785,10 @@ class JavaCodeGenerator(
ParameterizedTypeName.get( ParameterizedTypeName.get(
SET, SET,
if (typeArguments.isEmpty()) { if (typeArguments.isEmpty()) {
TypeName.OBJECT OBJECT
} else { } else {
typeArguments[0].toJavaPoetTypeArgumentName() typeArguments[0].toJavaPoetTypeArgumentName()
} },
) )
.nullableIf(nullable) .nullableIf(nullable)
PClassInfo.Map, PClassInfo.Map,
@@ -785,15 +796,15 @@ class JavaCodeGenerator(
ParameterizedTypeName.get( ParameterizedTypeName.get(
MAP, MAP,
if (typeArguments.isEmpty()) { if (typeArguments.isEmpty()) {
TypeName.OBJECT OBJECT
} else { } else {
typeArguments[0].toJavaPoetTypeArgumentName() typeArguments[0].toJavaPoetTypeArgumentName()
}, },
if (typeArguments.isEmpty()) { if (typeArguments.isEmpty()) {
TypeName.OBJECT OBJECT
} else { } else {
typeArguments[1].toJavaPoetTypeArgumentName() typeArguments[1].toJavaPoetTypeArgumentName()
} },
) )
.nullableIf(nullable) .nullableIf(nullable)
PClassInfo.Module -> PMODULE.nullableIf(nullable) PClassInfo.Module -> PMODULE.nullableIf(nullable)
@@ -815,7 +826,7 @@ class JavaCodeGenerator(
is PType.Constrained -> baseType.toJavaPoetName(nullable = nullable, boxed = boxed) is PType.Constrained -> baseType.toJavaPoetName(nullable = nullable, boxed = boxed)
is PType.Alias -> is PType.Alias ->
when (typeAlias.qualifiedName) { when (typeAlias.qualifiedName) {
"pkl.base#NonNull" -> TypeName.OBJECT.nullableIf(nullable) "pkl.base#NonNull" -> OBJECT.nullableIf(nullable)
"pkl.base#Int8" -> TypeName.BYTE.boxIf(boxed).nullableIf(nullable) "pkl.base#Int8" -> TypeName.BYTE.boxIf(boxed).nullableIf(nullable)
"pkl.base#Int16", "pkl.base#Int16",
"pkl.base#UInt8" -> TypeName.SHORT.boxIf(boxed).nullableIf(nullable) "pkl.base#UInt8" -> TypeName.SHORT.boxIf(boxed).nullableIf(nullable)
@@ -930,5 +941,5 @@ internal val javaReservedWords =
"try", "try",
"void", "void",
"volatile", "volatile",
"while" "while",
) )
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,15 +17,14 @@
package org.pkl.codegen.java package org.pkl.codegen.java
import com.github.ajalt.clikt.parameters.options.associate import com.github.ajalt.clikt.core.main
import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.*
import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.path import com.github.ajalt.clikt.parameters.types.path
import java.nio.file.Path import java.nio.file.Path
import org.pkl.commons.cli.CliBaseOptions import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.cli.cliMain import org.pkl.commons.cli.cliMain
import org.pkl.commons.cli.commands.ModulesCommand import org.pkl.commons.cli.commands.ModulesCommand
import org.pkl.commons.cli.commands.installCommonOptions
import org.pkl.commons.toPath import org.pkl.commons.toPath
import org.pkl.core.Release import org.pkl.core.Release
@@ -34,19 +33,16 @@ internal fun main(args: Array<String>) {
cliMain { PklJavaCodegenCommand().main(args) } cliMain { PklJavaCodegenCommand().main(args) }
} }
class PklJavaCodegenCommand : internal val helpLink = "${Release.current().documentation.homepage}java-binding/codegen.html#cli"
ModulesCommand(
name = "pkl-codegen-java",
helpLink = Release.current().documentation().homepage(),
) {
class PklJavaCodegenCommand : ModulesCommand(name = "pkl-codegen-java", helpLink) {
private val defaults = CliJavaCodeGeneratorOptions(CliBaseOptions(), "".toPath()) private val defaults = CliJavaCodeGeneratorOptions(CliBaseOptions(), "".toPath())
private val outputDir: Path by private val outputDir: Path by
option( option(
names = arrayOf("-o", "--output-dir"), names = arrayOf("-o", "--output-dir"),
metavar = "<path>", metavar = "path",
help = "The directory where generated source code is placed." help = "The directory where generated source code is placed.",
) )
.path() .path()
.default(defaults.outputDir) .default(defaults.outputDir)
@@ -54,8 +50,8 @@ class PklJavaCodegenCommand :
private val indent: String by private val indent: String by
option( option(
names = arrayOf("--indent"), names = arrayOf("--indent"),
metavar = "<chars>", metavar = "chars",
help = "The characters to use for indenting generated source code." help = "The characters to use for indenting generated source code.",
) )
.default(defaults.indent) .default(defaults.indent)
@@ -64,66 +60,72 @@ class PklJavaCodegenCommand :
names = arrayOf("--generate-getters"), names = arrayOf("--generate-getters"),
help = help =
"Whether to generate public getter methods and " + "Whether to generate public getter methods and " +
"private final fields instead of public final fields." "private final fields instead of public final fields.",
) )
.flag() .flag()
private val generateJavadoc: Boolean by private val generateJavadoc: Boolean by
option( option(
names = arrayOf("--generate-javadoc"), names = arrayOf("--generate-javadoc"),
help = help = "Whether to preserve Pkl doc comments by generating corresponding Javadoc comments.",
"Whether to generate Javadoc based on doc comments " +
"for Pkl modules, classes, and properties."
) )
.flag() .flag()
private val generateSpringboot: Boolean by private val generateSpringBoot: Boolean by
option( option(
names = arrayOf("--generate-spring-boot"), names = arrayOf("--generate-spring-boot"),
help = "Whether to generate config classes for use with Spring boot." help = "Whether to generate config classes for use with Spring Boot.",
) )
.flag() .flag()
private val paramsAnnotation: String? by private val paramsAnnotation: String by
option( option(
names = arrayOf("--params-annotation"), names = arrayOf("--params-annotation"),
help = "Fully qualified name of the annotation to use on constructor parameters." help =
"Fully qualified name of the annotation type to use for annotating constructor parameters with their name.",
) )
.defaultLazy(
"`none` if `--generate-spring-boot` is set, `org.pkl.config.java.mapper.Named` otherwise"
) {
if (generateSpringBoot) "none" else "org.pkl.config.java.mapper.Named"
}
private val nonNullAnnotation: String? by private val nonNullAnnotation: String? by
option( option(
names = arrayOf("--non-null-annotation"), names = arrayOf("--non-null-annotation"),
help = help =
""" """
Fully qualified named of the annotation class to use for non-null types. Fully qualified name of the annotation type to use for annotating non-null types.
This annotation is required to have `java.lang.annotation.ElementType.TYPE_USE` as a `@Target` The specified annotation type must be annotated with `@java.lang.annotation.Target(ElementType.TYPE_USE)`
or it may generate code that does not compile. or the generated code may not compile.
""" """
.trimIndent() .trimIndent(),
) )
private val implementSerializable: Boolean by private val implementSerializable: Boolean by
option( option(
names = arrayOf("--implement-serializable"), names = arrayOf("--implement-serializable"),
help = "Whether to make generated classes implement java.io.Serializable." help = "Whether to generate classes that implement java.io.Serializable.",
) )
.flag() .flag()
private val renames: Map<String, String> by private val renames: Map<String, String> by
option( option(
names = arrayOf("--rename"), names = arrayOf("--rename"),
metavar = "<old_name=new_name>", metavar = "old_name=new_name",
help = help =
""" """
Replace a prefix in the names of the generated Java classes (repeatable). Replace a prefix in the names of the generated Java classes (repeatable).
By default, the names of generated classes are derived from the Pkl module names. By default, the names of generated classes are derived from the Pkl module names.
With this option, you can override the modify the default names, renaming entire With this option, you can override or modify the default names, renaming entire
classes or just their packages. classes or just their packages.
""" """
.trimIndent() .trimIndent(),
) )
.associate() .associate()
override val helpString: String = "Generate Java classes and interfaces from Pkl module(s)"
override fun run() { override fun run() {
val options = val options =
CliJavaCodeGeneratorOptions( CliJavaCodeGeneratorOptions(
@@ -132,12 +134,16 @@ class PklJavaCodegenCommand :
indent = indent, indent = indent,
generateGetters = generateGetters, generateGetters = generateGetters,
generateJavadoc = generateJavadoc, generateJavadoc = generateJavadoc,
generateSpringBootConfig = generateSpringboot, generateSpringBootConfig = generateSpringBoot,
paramsAnnotation = paramsAnnotation, paramsAnnotation = if (paramsAnnotation == "none") null else paramsAnnotation,
nonNullAnnotation = nonNullAnnotation, nonNullAnnotation = nonNullAnnotation,
implementSerializable = implementSerializable, implementSerializable = implementSerializable,
renames = renames renames = renames,
) )
CliJavaCodeGenerator(options).run() CliJavaCodeGenerator(options).run()
} }
init {
installCommonOptions()
}
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ class CliJavaCodeGeneratorTest {
name: String name: String
age: Int age: Int
} }
""" """,
) )
val module2 = val module2 =
@@ -53,7 +53,7 @@ class CliJavaCodeGeneratorTest {
extends "mod1.pkl" extends "mod1.pkl"
parrot: Person parrot: Person
""" """,
) )
val module1File = module1.writeToDisk(tempDir.resolve("org/mod1.pkl")) val module1File = module1.writeToDisk(tempDir.resolve("org/mod1.pkl"))
@@ -64,7 +64,7 @@ class CliJavaCodeGeneratorTest {
CliJavaCodeGenerator( CliJavaCodeGenerator(
CliJavaCodeGeneratorOptions( CliJavaCodeGeneratorOptions(
CliBaseOptions(listOf(module1File.toUri(), module2File.toUri())), CliBaseOptions(listOf(module1File.toUri(), module2File.toUri())),
outputDir outputDir,
) )
) )
@@ -82,7 +82,7 @@ class CliJavaCodeGeneratorTest {
|public class Mod1 { |public class Mod1 {
| public final @NonNull Person pigeon; | public final @NonNull Person pigeon;
""", """,
module1JavaFile.readString() module1JavaFile.readString(),
) )
val module2JavaFile = javaDir.resolve("org/Mod2.java") val module2JavaFile = javaDir.resolve("org/Mod2.java")
@@ -91,7 +91,7 @@ class CliJavaCodeGeneratorTest {
|public final class Mod2 extends Mod1 { |public final class Mod2 extends Mod1 {
| public final Mod1. @NonNull Person parrot; | public final Mod1. @NonNull Person parrot;
""", """,
module2JavaFile.readString() module2JavaFile.readString(),
) )
val resourcesDir = outputDir.resolve("resources/META-INF/org/pkl/config/java/mapper/classes/") val resourcesDir = outputDir.resolve("resources/META-INF/org/pkl/config/java/mapper/classes/")
@@ -101,18 +101,18 @@ class CliJavaCodeGeneratorTest {
// use two assertions because java.util.Properties doesn't guarantee order // use two assertions because java.util.Properties doesn't guarantee order
assertContains( assertContains(
"""org.pkl.config.java.mapper.org.mod1\#Person=org.Mod1${dollar}Person""", """org.pkl.config.java.mapper.org.mod1\#Person=org.Mod1${dollar}Person""",
module1PropertiesString module1PropertiesString,
) )
assertContains( assertContains(
"""org.pkl.config.java.mapper.org.mod1\#ModuleClass=org.Mod1""", """org.pkl.config.java.mapper.org.mod1\#ModuleClass=org.Mod1""",
module1PropertiesString module1PropertiesString,
) )
val module2PropertiesFile = resourcesDir.resolve("org.mod2.properties") val module2PropertiesFile = resourcesDir.resolve("org.mod2.properties")
assertContains( assertContains(
"""org.pkl.config.java.mapper.org.mod2\#ModuleClass=org.Mod2""", """org.pkl.config.java.mapper.org.mod2\#ModuleClass=org.Mod2""",
module2PropertiesFile.readString() module2PropertiesFile.readString(),
) )
} }
@@ -127,7 +127,7 @@ class CliJavaCodeGeneratorTest {
class Person { class Person {
name: String name: String
} }
""" """,
) )
val module2 = val module2 =
@@ -144,7 +144,7 @@ class CliJavaCodeGeneratorTest {
class Person { class Person {
age: Int age: Int
} }
""" """,
) )
val module1PklFile = module1.writeToDisk(tempDir.resolve("org/mod1.pkl")) val module1PklFile = module1.writeToDisk(tempDir.resolve("org/mod1.pkl"))
@@ -155,7 +155,7 @@ class CliJavaCodeGeneratorTest {
CliJavaCodeGenerator( CliJavaCodeGenerator(
CliJavaCodeGeneratorOptions( CliJavaCodeGeneratorOptions(
CliBaseOptions(listOf(module1PklFile.toUri(), module2PklFile.toUri())), CliBaseOptions(listOf(module1PklFile.toUri(), module2PklFile.toUri())),
outputDir outputDir,
) )
) )
@@ -169,7 +169,7 @@ class CliJavaCodeGeneratorTest {
| |
| public final @NonNull Person person2; | public final @NonNull Person person2;
""", """,
module2JavaFile.readString() module2JavaFile.readString(),
) )
} }
@@ -184,7 +184,7 @@ class CliJavaCodeGeneratorTest {
class Person { class Person {
name: String name: String
} }
""" """,
) )
val module2 = val module2 =
@@ -199,7 +199,7 @@ class CliJavaCodeGeneratorTest {
owner: Module1.Person owner: Module1.Person
name: String name: String
} }
""" """,
) )
val module3 = val module3 =
@@ -213,7 +213,7 @@ class CliJavaCodeGeneratorTest {
class Supergroup { class Supergroup {
owner: Module2.Group owner: Module2.Group
} }
""" """,
) )
val module1PklFile = module1.writeToDisk(tempDir.resolve("org/foo/Module1.pkl")) val module1PklFile = module1.writeToDisk(tempDir.resolve("org/foo/Module1.pkl"))
@@ -226,7 +226,7 @@ class CliJavaCodeGeneratorTest {
CliJavaCodeGeneratorOptions( CliJavaCodeGeneratorOptions(
CliBaseOptions(listOf(module1PklFile, module2PklFile, module3PklFile).map { it.toUri() }), CliBaseOptions(listOf(module1PklFile, module2PklFile, module3PklFile).map { it.toUri() }),
outputDir, outputDir,
renames = mapOf("org.foo" to "com.foo.x", "org.baz" to "com.baz.a.b") renames = mapOf("org.foo" to "com.foo.x", "org.baz" to "com.baz.a.b"),
) )
) )
@@ -243,7 +243,7 @@ class CliJavaCodeGeneratorTest {
| public static final class Person { | public static final class Person {
| public final @NonNull String name; | public final @NonNull String name;
""", """,
it it,
) )
} }
@@ -260,7 +260,7 @@ class CliJavaCodeGeneratorTest {
| public static final class Group { | public static final class Group {
| public final Module1. @NonNull Person owner; | public final Module1. @NonNull Person owner;
""", """,
it it,
) )
} }
@@ -277,7 +277,7 @@ class CliJavaCodeGeneratorTest {
| public static final class Supergroup { | public static final class Supergroup {
| public final Module2. @NonNull Group owner; | public final Module2. @NonNull Group owner;
""", """,
it it,
) )
} }
} }

Some files were not shown because too many files have changed in this diff Show More