Initial commit

This commit is contained in:
Peter Niederwieser
2016-01-19 14:51:19 +01:00
committed by Dan Chao
commit ecad035dca
2972 changed files with 211653 additions and 0 deletions

154
.circleci/config.pkl Normal file
View File

@@ -0,0 +1,154 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
// File gets rendered to .circleci/config.yml via git hook.
amends ".../pkl-project-commons/packages/pkl.impl.circleci/PklCI.pkl"
import "jobs/BuildNativeJob.pkl"
import "jobs/GradleCheckJob.pkl"
import "jobs/DeployJob.pkl"
import "jobs/SimpleGradleJob.pkl"
local prbJobs: Listing<String> = gradleCheckJobs.keys.toListing()
local buildAndTestJobs = (prbJobs) {
"bench"
// "gradle-compatibility"
...buildNativeJobs.keys.filter((it) -> it.endsWith("snapshot"))
}
local releaseJobs = (prbJobs) {
"bench"
// "gradle-compatibility"
...buildNativeJobs.keys.filter((it) -> it.endsWith("release"))
}
prb {
jobs = prbJobs
}
main {
jobs {
...buildAndTestJobs
new {
["deploy-snapshot"] {
requires = buildAndTestJobs
context = "pkl-maven-release"
}
}
}
}
release {
jobs {
...releaseJobs
// do GitHub release first because we can overwrite the tag.
// publishing to Maven Central is final.
new {
["github-release"] {
requires = releaseJobs
context = "pkl-github-release"
}
}
new {
["deploy-release"] {
requires { "github-release" }
context = "pkl-maven-release"
}
}
}
}
triggerDocsBuild = "both"
triggerPackageDocsBuild = "release"
local buildNativeJobs: Mapping<String, BuildNativeJob> = new {
for (_dist in List("release", "snapshot")) {
for (_arch in List("amd64", "aarch64")) {
for (_os in List("macOS", "linux")) {
["pkl-cli-\(_os)-\(_arch)-\(_dist)"] {
arch = _arch
os = _os
isRelease = _dist == "release"
}
}
}
["pkl-cli-linux-alpine-amd64-\(_dist)"] {
arch = "amd64"
os = "linux"
musl = true
isRelease = _dist == "release"
}
}
}
local gradleCheckJobs: Mapping<String, GradleCheckJob> = new {
["gradle-check-jdk11"] {
javaVersion = "11.0"
isRelease = false
}
["gradle-check-jdk17"] {
javaVersion = "17.0"
isRelease = false
}
}
jobs {
for (jobName, job in buildNativeJobs) {
[jobName] = job.job
}
for (jobName, job in gradleCheckJobs) {
[jobName] = job.job
}
["bench"] = new SimpleGradleJob { command = "bench:jmh" }.job
["gradle-compatibility"] = new SimpleGradleJob {
name = "gradle compatibility"
command = #"""
:pkl-gradle:build \
:pkl-gradle:compatibilityTestReleases \
:pkl-gradle:compatibilityTestCandidate
"""#
}.job
["deploy-snapshot"] = new DeployJob {
command = "publishToSonatype"
}.job
["deploy-release"] = new DeployJob {
isRelease = true
command = "publishToSonatype closeAndReleaseSonatypeStagingRepository"
}.job
["github-release"] {
docker {
new {
image = "maniator/gh:v2.40.1"
}
}
steps {
new AttachWorkspaceStep { at = "." }
new RunStep {
name = "Publish release on GitHub"
command = #"""
gh release create "${CIRCLE_TAG}" \
--title "${CIRCLE_TAG}" \
--target "${CIRCLE_SHA1}" \
--verify-tag \
--notes "Release notes: https://pkl-lang.org/main/current/release-notes/changelog.html#release-${CIRCLE_TAG}" \
--repo "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \
pkl-cli/build/executable/*
"""#
}
}
}
}

870
.circleci/config.yml Normal file
View File

@@ -0,0 +1,870 @@
# Generated from CircleCI.pkl. DO NOT EDIT.
version: '2.1'
orbs:
pr-approval: apple/pr-approval@0.1.0
jobs:
pkl-cli-macOS-amd64-release:
steps:
- checkout
- run:
command: /usr/sbin/softwareupdate --install-rosetta --agree-to-license
name: Installing Rosetta 2
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DreleaseBuild=true pkl-cli:macExecutableAmd64 pkl-core:testMacExecutableAmd64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
resource_class: macos.m1.large.gen1
macos:
xcode: 15.2.0
pkl-cli-linux-amd64-release:
steps:
- checkout
- restore_cache:
key: staticdeps-amd64
name: Restore static deps from cache
- run:
command: |-
sed -ie '/\[ol8_codeready_builder\]/,/^$/s/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-linux-ol8.repo \
&& microdnf -y install util-linux tree coreutils-single findutils curl tar gzip git zlib-devel gcc-c++ make openssl glibc-langpack-en libstdc++-static \
&& microdnf clean all \
&& rm -rf /var/cache/dnf
# install jdk
curl -L \
https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.20.1_1.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \
&& cd /jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
mkdir -p ~/staticdeps/bin
cp /usr/lib/gcc/x86_64-redhat-linux/8/libstdc++.a ~/staticdeps
# install zlib
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
mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \
&& cat /tmp/zlib.tar.gz | tar --strip-components=1 -xzC . \
&& echo "zlib-1.2.13: configure..." && ./configure --static --prefix="$HOME"/staticdeps > /dev/null \
&& echo "zlib-1.2.13: make..." && make -s -j4 \
&& echo "zlib-1.2.13: make install..." && make -s install \
&& rm -rf /tmp/dep_zlib-1.2.13
fi
# install musl
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
mkdir -p /tmp/dep_musl-1.2.2 \
&& cd /tmp/dep_musl-1.2.2 \
&& cat /tmp/musl.tar.gz | tar --strip-components=1 -xzC . \
&& echo "musl-1.2.2: configure..." && ./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null \
&& echo "musl-1.2.2: make..." && make -s -j4 \
&& echo "musl-1.2.2: make install..." && make -s install \
&& rm -rf /tmp/dep_musl-1.2.2
# native-image expects to find an executable at this path.
ln -s ~/staticdeps/bin/musl-gcc ~/staticdeps/bin/x86_64-linux-musl-gcc
fi
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- save_cache:
paths:
- ~/staticdeps
key: staticdeps-amd64
name: Save statics deps to cache
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DreleaseBuild=true pkl-cli:linuxExecutableAmd64 pkl-core:testLinuxExecutableAmd64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
JAVA_HOME: /jdk
resource_class: xlarge
docker:
- image: oraclelinux:8-slim
pkl-cli-macOS-aarch64-release:
steps:
- checkout
- run:
command: git apply patches/graalVm23.patch
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DreleaseBuild=true pkl-cli:macExecutableAarch64 pkl-core:testMacExecutableAarch64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
resource_class: macos.m1.large.gen1
macos:
xcode: 15.2.0
pkl-cli-linux-aarch64-release:
steps:
- checkout
- restore_cache:
key: staticdeps-aarch64
name: Restore static deps from cache
- run:
command: |-
sed -ie '/\[ol8_codeready_builder\]/,/^$/s/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-linux-ol8.repo \
&& microdnf -y install util-linux tree coreutils-single findutils curl tar gzip git zlib-devel gcc-c++ make openssl glibc-langpack-en libstdc++-static \
&& microdnf clean all \
&& rm -rf /var/cache/dnf
# install jdk
curl -L \
https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20.1%2B1/OpenJDK11U-jdk_aarch64_linux_hotspot_11.0.20.1_1.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \
&& cd /jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
mkdir -p ~/staticdeps/bin
cp /usr/lib/gcc/aarch64-redhat-linux/8/libstdc++.a ~/staticdeps
# install zlib
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
mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \
&& cat /tmp/zlib.tar.gz | tar --strip-components=1 -xzC . \
&& echo "zlib-1.2.13: configure..." && ./configure --static --prefix="$HOME"/staticdeps > /dev/null \
&& echo "zlib-1.2.13: make..." && make -s -j4 \
&& echo "zlib-1.2.13: make install..." && make -s install \
&& rm -rf /tmp/dep_zlib-1.2.13
fi
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- save_cache:
paths:
- ~/staticdeps
key: staticdeps-aarch64
name: Save statics deps to cache
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DreleaseBuild=true pkl-cli:linuxExecutableAarch64 pkl-core:testLinuxExecutableAarch64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
JAVA_HOME: /jdk
resource_class: arm.xlarge
docker:
- image: arm64v8/oraclelinux:8-slim
pkl-cli-linux-alpine-amd64-release:
steps:
- checkout
- restore_cache:
key: staticdeps-amd64
name: Restore static deps from cache
- run:
command: |-
sed -ie '/\[ol8_codeready_builder\]/,/^$/s/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-linux-ol8.repo \
&& microdnf -y install util-linux tree coreutils-single findutils curl tar gzip git zlib-devel gcc-c++ make openssl glibc-langpack-en libstdc++-static \
&& microdnf clean all \
&& rm -rf /var/cache/dnf
# install jdk
curl -L \
https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.20.1_1.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \
&& cd /jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
mkdir -p ~/staticdeps/bin
cp /usr/lib/gcc/x86_64-redhat-linux/8/libstdc++.a ~/staticdeps
# install zlib
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
mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \
&& cat /tmp/zlib.tar.gz | tar --strip-components=1 -xzC . \
&& echo "zlib-1.2.13: configure..." && ./configure --static --prefix="$HOME"/staticdeps > /dev/null \
&& echo "zlib-1.2.13: make..." && make -s -j4 \
&& echo "zlib-1.2.13: make install..." && make -s install \
&& rm -rf /tmp/dep_zlib-1.2.13
fi
# install musl
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
mkdir -p /tmp/dep_musl-1.2.2 \
&& cd /tmp/dep_musl-1.2.2 \
&& cat /tmp/musl.tar.gz | tar --strip-components=1 -xzC . \
&& echo "musl-1.2.2: configure..." && ./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null \
&& echo "musl-1.2.2: make..." && make -s -j4 \
&& echo "musl-1.2.2: make install..." && make -s install \
&& rm -rf /tmp/dep_musl-1.2.2
# native-image expects to find an executable at this path.
ln -s ~/staticdeps/bin/musl-gcc ~/staticdeps/bin/x86_64-linux-musl-gcc
fi
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- save_cache:
paths:
- ~/staticdeps
key: staticdeps-amd64
name: Save statics deps to cache
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace -DreleaseBuild=true pkl-cli:alpineExecutableAmd64 pkl-core:testAlpineExecutableAmd64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
JAVA_HOME: /jdk
resource_class: xlarge
docker:
- image: oraclelinux:8-slim
pkl-cli-macOS-amd64-snapshot:
steps:
- checkout
- run:
command: /usr/sbin/softwareupdate --install-rosetta --agree-to-license
name: Installing Rosetta 2
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace pkl-cli:macExecutableAmd64 pkl-core:testMacExecutableAmd64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
resource_class: macos.m1.large.gen1
macos:
xcode: 15.2.0
pkl-cli-linux-amd64-snapshot:
steps:
- checkout
- restore_cache:
key: staticdeps-amd64
name: Restore static deps from cache
- run:
command: |-
sed -ie '/\[ol8_codeready_builder\]/,/^$/s/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-linux-ol8.repo \
&& microdnf -y install util-linux tree coreutils-single findutils curl tar gzip git zlib-devel gcc-c++ make openssl glibc-langpack-en libstdc++-static \
&& microdnf clean all \
&& rm -rf /var/cache/dnf
# install jdk
curl -L \
https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.20.1_1.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \
&& cd /jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
mkdir -p ~/staticdeps/bin
cp /usr/lib/gcc/x86_64-redhat-linux/8/libstdc++.a ~/staticdeps
# install zlib
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
mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \
&& cat /tmp/zlib.tar.gz | tar --strip-components=1 -xzC . \
&& echo "zlib-1.2.13: configure..." && ./configure --static --prefix="$HOME"/staticdeps > /dev/null \
&& echo "zlib-1.2.13: make..." && make -s -j4 \
&& echo "zlib-1.2.13: make install..." && make -s install \
&& rm -rf /tmp/dep_zlib-1.2.13
fi
# install musl
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
mkdir -p /tmp/dep_musl-1.2.2 \
&& cd /tmp/dep_musl-1.2.2 \
&& cat /tmp/musl.tar.gz | tar --strip-components=1 -xzC . \
&& echo "musl-1.2.2: configure..." && ./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null \
&& echo "musl-1.2.2: make..." && make -s -j4 \
&& echo "musl-1.2.2: make install..." && make -s install \
&& rm -rf /tmp/dep_musl-1.2.2
# native-image expects to find an executable at this path.
ln -s ~/staticdeps/bin/musl-gcc ~/staticdeps/bin/x86_64-linux-musl-gcc
fi
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- save_cache:
paths:
- ~/staticdeps
key: staticdeps-amd64
name: Save statics deps to cache
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace pkl-cli:linuxExecutableAmd64 pkl-core:testLinuxExecutableAmd64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
JAVA_HOME: /jdk
resource_class: xlarge
docker:
- image: oraclelinux:8-slim
pkl-cli-macOS-aarch64-snapshot:
steps:
- checkout
- run:
command: git apply patches/graalVm23.patch
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace pkl-cli:macExecutableAarch64 pkl-core:testMacExecutableAarch64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
resource_class: macos.m1.large.gen1
macos:
xcode: 15.2.0
pkl-cli-linux-aarch64-snapshot:
steps:
- checkout
- restore_cache:
key: staticdeps-aarch64
name: Restore static deps from cache
- run:
command: |-
sed -ie '/\[ol8_codeready_builder\]/,/^$/s/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-linux-ol8.repo \
&& microdnf -y install util-linux tree coreutils-single findutils curl tar gzip git zlib-devel gcc-c++ make openssl glibc-langpack-en libstdc++-static \
&& microdnf clean all \
&& rm -rf /var/cache/dnf
# install jdk
curl -L \
https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20.1%2B1/OpenJDK11U-jdk_aarch64_linux_hotspot_11.0.20.1_1.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \
&& cd /jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
mkdir -p ~/staticdeps/bin
cp /usr/lib/gcc/aarch64-redhat-linux/8/libstdc++.a ~/staticdeps
# install zlib
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
mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \
&& cat /tmp/zlib.tar.gz | tar --strip-components=1 -xzC . \
&& echo "zlib-1.2.13: configure..." && ./configure --static --prefix="$HOME"/staticdeps > /dev/null \
&& echo "zlib-1.2.13: make..." && make -s -j4 \
&& echo "zlib-1.2.13: make install..." && make -s install \
&& rm -rf /tmp/dep_zlib-1.2.13
fi
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- save_cache:
paths:
- ~/staticdeps
key: staticdeps-aarch64
name: Save statics deps to cache
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace pkl-cli:linuxExecutableAarch64 pkl-core:testLinuxExecutableAarch64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
JAVA_HOME: /jdk
resource_class: arm.xlarge
docker:
- image: arm64v8/oraclelinux:8-slim
pkl-cli-linux-alpine-amd64-snapshot:
steps:
- checkout
- restore_cache:
key: staticdeps-amd64
name: Restore static deps from cache
- run:
command: |-
sed -ie '/\[ol8_codeready_builder\]/,/^$/s/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-linux-ol8.repo \
&& microdnf -y install util-linux tree coreutils-single findutils curl tar gzip git zlib-devel gcc-c++ make openssl glibc-langpack-en libstdc++-static \
&& microdnf clean all \
&& rm -rf /var/cache/dnf
# install jdk
curl -L \
https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.20.1_1.tar.gz -o /tmp/jdk.tar.gz
mkdir /jdk \
&& cd /jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
mkdir -p ~/staticdeps/bin
cp /usr/lib/gcc/x86_64-redhat-linux/8/libstdc++.a ~/staticdeps
# install zlib
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
mkdir -p /tmp/dep_zlib-1.2.13 \
&& cd /tmp/dep_zlib-1.2.13 \
&& cat /tmp/zlib.tar.gz | tar --strip-components=1 -xzC . \
&& echo "zlib-1.2.13: configure..." && ./configure --static --prefix="$HOME"/staticdeps > /dev/null \
&& echo "zlib-1.2.13: make..." && make -s -j4 \
&& echo "zlib-1.2.13: make install..." && make -s install \
&& rm -rf /tmp/dep_zlib-1.2.13
fi
# install musl
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
mkdir -p /tmp/dep_musl-1.2.2 \
&& cd /tmp/dep_musl-1.2.2 \
&& cat /tmp/musl.tar.gz | tar --strip-components=1 -xzC . \
&& echo "musl-1.2.2: configure..." && ./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null \
&& echo "musl-1.2.2: make..." && make -s -j4 \
&& echo "musl-1.2.2: make install..." && make -s install \
&& rm -rf /tmp/dep_musl-1.2.2
# native-image expects to find an executable at this path.
ln -s ~/staticdeps/bin/musl-gcc ~/staticdeps/bin/x86_64-linux-musl-gcc
fi
name: Set up environment
shell: '#!/bin/bash -exo pipefail'
- save_cache:
paths:
- ~/staticdeps
key: staticdeps-amd64
name: Save statics deps to cache
- run:
command: |-
export PATH=~/staticdeps/bin:$PATH
./gradlew --info --stacktrace pkl-cli:alpineExecutableAmd64 pkl-core:testAlpineExecutableAmd64
name: gradle buildNative
- persist_to_workspace:
root: '.'
paths:
- pkl-cli/build/executable/
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
JAVA_HOME: /jdk
resource_class: xlarge
docker:
- image: oraclelinux:8-slim
gradle-check-jdk11:
steps:
- checkout
- run:
command: ./gradlew --info --stacktrace check
name: gradle check
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
docker:
- image: cimg/openjdk:11.0
gradle-check-jdk17:
steps:
- checkout
- run:
command: ./gradlew --info --stacktrace check
name: gradle check
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
docker:
- image: cimg/openjdk:17.0
bench:
steps:
- checkout
- run:
command: ./gradlew --info --stacktrace bench:jmh
name: bench:jmh
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
docker:
- image: cimg/openjdk:11.0
gradle-compatibility:
steps:
- checkout
- run:
command: |-
./gradlew --info --stacktrace :pkl-gradle:build \
:pkl-gradle:compatibilityTestReleases \
:pkl-gradle:compatibilityTestCandidate
name: gradle compatibility
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
docker:
- image: cimg/openjdk:11.0
deploy-snapshot:
steps:
- checkout
- attach_workspace:
at: '.'
- run:
command: ./gradlew --info --stacktrace publishToSonatype
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
docker:
- image: cimg/openjdk:11.0
deploy-release:
steps:
- checkout
- attach_workspace:
at: '.'
- run:
command: ./gradlew --info --stacktrace -DreleaseBuild=true publishToSonatype closeAndReleaseSonatypeStagingRepository
- run:
command: |-
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \;
name: Gather test results
when: always
- store_test_results:
path: ~/test-results
environment:
LANG: en_US.UTF-8
docker:
- image: cimg/openjdk:11.0
github-release:
steps:
- attach_workspace:
at: '.'
- run:
command: |-
gh release create "${CIRCLE_TAG}" \
--title "${CIRCLE_TAG}" \
--target "${CIRCLE_SHA1}" \
--verify-tag \
--notes "Release notes: https://pkl-lang.org/main/current/release-notes/changelog.html#release-${CIRCLE_TAG}" \
--repo "${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" \
pkl-cli/build/executable/*
name: Publish release on GitHub
docker:
- image: maniator/gh:v2.40.1
trigger-docsite-build:
steps:
- run:
command: |-
curl --location \
--request POST \
--header "Content-Type: application/json" \
-u "${CIRCLE_TOKEN}:" \
--data '{ "branch": "main" }' \
"https://circleci.com/api/v2/project/github/apple/pkl-lang.org/pipeline"
name: Triggering docsite build
docker:
- image: cimg/base:current
trigger-package-docs-build:
steps:
- run:
command: |-
curl --location \
--request POST \
--header "Content-Type: application/json" \
-u "${CIRCLE_TOKEN}:" \
--data '{ "branch": "main" }' \
"https://circleci.com/api/v2/project/github/apple/pkl-package-docs/pipeline"
name: Triggering docsite build
docker:
- image: cimg/base:current
workflows:
prb:
jobs:
- hold:
type: approval
- pr-approval/authenticate:
context: pkl-pr-approval
- gradle-check-jdk11:
requires:
- hold
- pr-approval/authenticate
- gradle-check-jdk17:
requires:
- hold
- pr-approval/authenticate
when:
matches:
value: << pipeline.git.branch >>
pattern: ^pull/\d+(/head)?$
main:
jobs:
- gradle-check-jdk11
- gradle-check-jdk17
- bench
- pkl-cli-macOS-amd64-snapshot
- pkl-cli-linux-amd64-snapshot
- pkl-cli-macOS-aarch64-snapshot
- pkl-cli-linux-aarch64-snapshot
- pkl-cli-linux-alpine-amd64-snapshot
- deploy-snapshot:
requires:
- gradle-check-jdk11
- gradle-check-jdk17
- bench
- pkl-cli-macOS-amd64-snapshot
- pkl-cli-linux-amd64-snapshot
- pkl-cli-macOS-aarch64-snapshot
- pkl-cli-linux-aarch64-snapshot
- pkl-cli-linux-alpine-amd64-snapshot
context: pkl-maven-release
- trigger-docsite-build:
requires:
- deploy-snapshot
context:
- pkl-pr-approval
when:
equal:
- main
- << pipeline.git.branch >>
release:
jobs:
- gradle-check-jdk11:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- gradle-check-jdk17:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- bench:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- pkl-cli-macOS-amd64-release:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- pkl-cli-linux-amd64-release:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- pkl-cli-macOS-aarch64-release:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- pkl-cli-linux-aarch64-release:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- pkl-cli-linux-alpine-amd64-release:
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- github-release:
requires:
- gradle-check-jdk11
- gradle-check-jdk17
- bench
- pkl-cli-macOS-amd64-release
- pkl-cli-linux-amd64-release
- pkl-cli-macOS-aarch64-release
- pkl-cli-linux-aarch64-release
- pkl-cli-linux-alpine-amd64-release
context: pkl-github-release
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- deploy-release:
requires:
- github-release
context: pkl-maven-release
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/
- trigger-package-docs-build:
requires:
- deploy-release
context:
- pkl-pr-approval
filters:
branches:
ignore: /.*/
tags:
only: /^v?\d+\.\d+\.\d+$/

View File

@@ -0,0 +1,167 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
/// Builds the native `pkl` CLI
extends "GradleJob.pkl"
// TODO(oss) replace these with package imports
import ".../pkl-pantry/packages/com.circleci.v2/CircleCI.pkl"
import ".../pkl-pantry/packages/pkl.experimental.uri/URI.pkl"
/// The OS to run on
os: "macOS"|"linux"
/// The architecture to use
arch: "amd64"|"aarch64"
/// Whether to link to musl. Otherwise, links to glibc.
musl: Boolean = false
local setupLinuxEnvironment: CircleCI.RunStep =
let (jdkVersion = "11.0.20.1+1")
let (muslVersion = "1.2.2")
let (zlibVersion = "1.2.13")
let (jdkVersionEncoded = URI.encodeComponent(jdkVersion))
let (jdkVersionAlt = jdkVersion.replaceLast("+", "_"))
let (majorJdkVersion = jdkVersion.split(".").first)
new {
name = "Set up environment"
shell = "#!/bin/bash -exo pipefail"
command = new Listing {
#"""
sed -ie '/\[ol8_codeready_builder\]/,/^$/s/enabled=0/enabled=1/g' /etc/yum.repos.d/oracle-linux-ol8.repo \
&& microdnf -y install util-linux tree coreutils-single findutils curl tar gzip git zlib-devel gcc-c++ make openssl glibc-langpack-en libstdc++-static \
&& microdnf clean all \
&& rm -rf /var/cache/dnf
# install jdk
curl -L \
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
mkdir /jdk \
&& cd /jdk \
&& cat /tmp/jdk.tar.gz | tar --strip-components=1 -xzC .
mkdir -p ~/staticdeps/bin
cp /usr/lib/gcc/\#(if (arch == "amd64") "x86_64" else "aarch64")-redhat-linux/8/libstdc++.a ~/staticdeps
# install zlib
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
mkdir -p /tmp/dep_zlib-\#(zlibVersion) \
&& cd /tmp/dep_zlib-\#(zlibVersion) \
&& cat /tmp/zlib.tar.gz | tar --strip-components=1 -xzC . \
&& echo "zlib-\#(zlibVersion): configure..." && ./configure --static --prefix="$HOME"/staticdeps > /dev/null \
&& echo "zlib-\#(zlibVersion): make..." && make -s -j4 \
&& echo "zlib-\#(zlibVersion): make install..." && make -s install \
&& rm -rf /tmp/dep_zlib-\#(zlibVersion)
fi
"""#
// don't need musl on aarch because GraalVM only supports musl builds on x86
when (arch == "amd64") {
#"""
# install musl
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
mkdir -p /tmp/dep_musl-\#(muslVersion) \
&& cd /tmp/dep_musl-\#(muslVersion) \
&& cat /tmp/musl.tar.gz | tar --strip-components=1 -xzC . \
&& echo "musl-\#(muslVersion): configure..." && ./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null \
&& echo "musl-\#(muslVersion): make..." && make -s -j4 \
&& echo "musl-\#(muslVersion): make install..." && make -s install \
&& rm -rf /tmp/dep_musl-\#(muslVersion)
# native-image expects to find an executable at this path.
ln -s ~/staticdeps/bin/musl-gcc ~/staticdeps/bin/x86_64-linux-musl-gcc
fi
"""#
}
}.join("\n\n")
}
steps {
when (os == "linux") {
new CircleCI.RestoreCacheStep {
name = "Restore static deps from cache"
key = "staticdeps-\(arch)"
}
setupLinuxEnvironment
new CircleCI.SaveCacheStep {
name = "Save statics deps to cache"
key = "staticdeps-\(arch)"
paths {
"~/staticdeps"
}
}
}
when (os == "macOS" && arch == "amd64") {
new CircleCI.RunStep {
name = "Installing Rosetta 2"
command = """
/usr/sbin/softwareupdate --install-rosetta --agree-to-license
"""
}
}
// If building macOS/aarch64, we need to use GraalVM 23.
// We can't use GraalVM 23 for any other build because we need to support Java 11, which was
// dropped in GraalVM 23.
when (os == "macOS" && arch == "aarch64") {
new CircleCI.RunStep {
command = "git apply patches/graalVm23.patch"
}
}
new CircleCI.RunStep {
name = "gradle buildNative"
local _os =
if (os == "macOS") "mac"
else if (musl) "alpine"
else "linux"
local jobName = "\(_os)Executable\(arch.capitalize())"
command = #"""
export PATH=~/staticdeps/bin:$PATH
./gradlew \#(module.gradleArgs) pkl-cli:\#(jobName) pkl-core:test\#(jobName.capitalize())
"""#
}
new CircleCI.PersistToWorkspaceStep {
root = "."
paths {
"pkl-cli/build/executable/"
}
}
}
job {
when (os == "macOS") {
macos {
xcode = "15.2.0"
}
// Use M1 for all architectures. We build amd64/aarch64 based on the GraalVM version,
// which gets patched in via `git apply patches/graalVm23.patch`.
resource_class = "macos.m1.large.gen1"
} else {
docker {
new {
image = if (arch == "aarch64") "arm64v8/oraclelinux:8-slim" else "oraclelinux:8-slim"
}
}
environment {
["JAVA_HOME"] = "/jdk"
}
resource_class = if (arch == "aarch64") "arm.xlarge" else "xlarge"
}
}

View File

@@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
extends "GradleJob.pkl"
import ".../pkl-pantry/packages/com.circleci.v2/CircleCI.pkl"
local self = this
command: String
job {
docker {
new { image = "cimg/openjdk:11.0" }
}
}
steps {
new CircleCI.AttachWorkspaceStep { at = "." }
new CircleCI.RunStep {
command = "./gradlew \(self.gradleArgs) \(module.command)"
}
}

View File

@@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
extends "GradleJob.pkl"
import ".../pkl-pantry/packages/com.circleci.v2/CircleCI.pkl"
javaVersion: "11.0"|"17.0"
steps {
new CircleCI.RunStep {
name = "gradle check"
command = "./gradlew \(module.gradleArgs) check"
}
}
job {
docker {
new {
image = "cimg/openjdk:\(javaVersion)"
}
}
}

View File

@@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
abstract module GradleJob
import ".../pkl-pantry/packages/com.circleci.v2/CircleCI.pkl"
/// Whether this is a release build or not.
isRelease: Boolean = false
fixed gradleArgs = new Listing {
"--info"
"--stacktrace"
when (isRelease) {
"-DreleaseBuild=true"
}
}.join(" ")
steps: Listing<CircleCI.Step>
job: CircleCI.Job = new {
environment {
["LANG"] = "en_US.UTF-8"
}
steps {
"checkout"
...module.steps
new CircleCI.RunStep {
// find all test results and write them to the home dir
name = "Gather test results"
command = """
mkdir ~/test-results/
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/test-results/ \\;
"""
`when` = "always"
}
new CircleCI.StoreTestResults {
path = "~/test-results"
}
}
}

View File

@@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
extends "GradleJob.pkl"
import ".../pkl-pantry/packages/com.circleci.v2/CircleCI.pkl"
name: String = command
command: String
steps {
new CircleCI.RunStep {
name = module.name
command = """
./gradlew \(module.gradleArgs) \(module.command)
"""
}
}
job {
docker {
new { image = "cimg/openjdk:11.0" }
}
}

10
.editorconfig Normal file
View File

@@ -0,0 +1,10 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
# don't trim whitespace within (say) a Pkl multiline string
trim_trailing_whitespace = false
insert_final_newline = true
max_line_length = 100

6
.gitattributes vendored Normal file
View File

@@ -0,0 +1,6 @@
# linguist-generated would suppress files in diffs
**/src/test/files/** linguist-vendored
/docs/** linguist-documentation
*.pkl linguist-language=Groovy

8
.githooks/pre-commit Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
files=`git diff --cached --name-status`
if [[ $files =~ .circleci/config.pkl ]]; then
pkl eval .circleci/config.pkl -o .circleci/config.yml
git add .circleci/config.yml
fi

19
.gitignore vendored Normal file
View File

@@ -0,0 +1,19 @@
# macOS
.DS_STORE
# Gradle
.gradle/
build/
generated/
# IntelliJ
.idea/
!.idea/codestyles/
!.idea/inspectionProfiles/
!.idea/runConfigurations/
!.idea/scopes/
!.idea/vcs.xml
# :pkl-core:makeIntelliJAntlrPluginHappy
gen/
PklLexer.tokens

600
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,600 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="OTHER_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</value>
</option>
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
<option name="LAYOUT_SETTINGS">
<value>
<option name="INSERT_BLANK_LINE_BEFORE_TAG" value="false" />
</value>
</option>
</AndroidXmlCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="INDENT_CHAINED_CALLS" value="false" />
</JSCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
</JavaCodeStyleSettings>
<Objective-C>
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
<option name="INDENT_C_STRUCT_MEMBERS" value="2" />
<option name="INDENT_CLASS_MEMBERS" value="2" />
<option name="INDENT_VISIBILITY_KEYWORDS" value="1" />
<option name="INDENT_INSIDE_CODE_BLOCK" value="2" />
<option name="KEEP_STRUCTURES_IN_ONE_LINE" value="true" />
<option name="FUNCTION_PARAMETERS_WRAP" value="5" />
<option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="5" />
<option name="TEMPLATE_CALL_ARGUMENTS_WRAP" value="5" />
<option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" />
<option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" />
<option name="SPACE_BEFORE_SUPERCLASS_COLON" value="false" />
</Objective-C>
<Objective-C-extensions>
<option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
<option name="RELEASE_STYLE" value="IVAR" />
<option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cc" header="h" />
<pair source="c" header="h" />
</extensions>
</Objective-C-extensions>
<Python>
<option name="USE_CONTINUATION_INDENT_FOR_ARGUMENTS" value="true" />
</Python>
<ScalaCodeStyleSettings>
<option name="MULTILINE_STRING_CLOSING_QUOTES_ON_NEW_LINE" value="true" />
</ScalaCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="INDENT_CHAINED_CALLS" value="false" />
</TypeScriptCodeStyleSettings>
<XML>
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
</XML>
<codeStyleSettings language="CSS">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="ECMA Script Level 4">
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
</codeStyleSettings>
<codeStyleSettings language="HTML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JAVA">
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_RESOURCES" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JSON">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="RIGHT_MARGIN" value="80" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="ObjectiveC">
<option name="RIGHT_MARGIN" value="80" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="1" />
<option name="BLANK_LINES_BEFORE_IMPORTS" value="0" />
<option name="BLANK_LINES_AFTER_IMPORTS" value="0" />
<option name="BLANK_LINES_AROUND_CLASS" value="0" />
<option name="BLANK_LINES_AROUND_METHOD" value="0" />
<option name="BLANK_LINES_AROUND_METHOD_IN_INTERFACE" value="0" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="false" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PROTO">
<option name="RIGHT_MARGIN" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Python">
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="RIGHT_MARGIN" value="80" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SASS">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SCSS">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:.*Style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_weight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_margin</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_marginRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:padding</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingTop</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingBottom</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingStart</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingEnd</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingLeft</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:paddingRight</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res-auto</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/tools</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="protobuf">
<option name="RIGHT_MARGIN" value="80" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@@ -0,0 +1,46 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="CanBeFinal" enabled="true" level="INFORMATION" enabled_by_default="false">
<scope name="AllExceptTruffleAst" level="WARNING" enabled="true">
<option name="REPORT_CLASSES" value="false" />
<option name="REPORT_METHODS" value="false" />
<option name="REPORT_FIELDS" value="true" />
</scope>
<option name="REPORT_CLASSES" value="false" />
<option name="REPORT_METHODS" value="false" />
<option name="REPORT_FIELDS" value="true" />
</inspection_tool>
<inspection_tool class="ClassCanBeRecord" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="FieldMayBeFinal" enabled="true" level="INFORMATION" enabled_by_default="true">
<scope name="AllExceptTruffleAst" level="WARNING" enabled="true" />
</inspection_tool>
<inspection_tool class="JavadocBlankLines" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NullableProblems" enabled="true" level="WARNING" enabled_by_default="false">
<scope name="AllExceptGenerated" level="WARNING" enabled="true">
<option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true" />
<option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOT_ANNOTATED_GETTER" value="true" />
<option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true" />
<option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="true" />
<option name="REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD" value="true" />
</scope>
<option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true" />
<option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOT_ANNOTATED_GETTER" value="true" />
<option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true" />
<option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="true" />
<option name="REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD" value="true" />
</inspection_tool>
<inspection_tool class="SameParameterValue" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>

3
.idea/scopes/AllExceptTruffleAst.xml generated Normal file
View File

@@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="AllExceptTruffleAst" pattern="(src:*..*||test:*..*||lib:*..*)&amp;&amp;!src[pkl.pkl-core.main]:com.apple.pkl.core.ast..*&amp;&amp;!src[pkl.pkl-core.main]:com.apple.pkl.core.stdlib..*Nodes" />
</component>

3
.idea/scopes/AllProjects.xml generated Normal file
View File

@@ -0,0 +1,3 @@
<component name="DependencyValidationManager">
<scope name="AllProjects" pattern="!file[pkl.pkl-core.test]:files//*&amp;&amp;!file[pkl.pkl-doc.test]:files//*&amp;&amp;!file[pkl.pkl-core.main]:antlr//*&amp;&amp;!file[pkl.pkl-core.main]:truffle//*&amp;&amp;!file[pkl.buildSrc.main]:*/" />
</component>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

1
.java-version Normal file
View File

@@ -0,0 +1 @@
17.0

78
CODE_OF_CONDUCT.adoc Normal file
View File

@@ -0,0 +1,78 @@
== Code of Conduct
=== Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our
project and our community a harassment-free experience for everyone,
regardless of age, body size, disability, ethnicity, sex
characteristics, gender identity and expression, level of experience,
education, socio-economic status, nationality, personal appearance,
race, religion, or sexual identity and orientation.
=== Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual
attention or advances
* Trolling, insulting/derogatory comments, and personal or political
attacks
* Public or private harassment
* Publishing others private information, such as a physical or
electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
=== Our Responsibilities
Project maintainers are responsible for clarifying the standards of
acceptable behavior and are expected to take appropriate and fair
corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit,
or reject comments, commits, code, wiki edits, issues, and other
contributions that are not aligned to this Code of Conduct, or to ban
temporarily or permanently any contributor for other behaviors that they
deem inappropriate, threatening, offensive, or harmful.
=== Scope
This Code of Conduct applies within all project spaces, and it also
applies when an individual is representing the project or its community
in public spaces. Examples of representing a project or community
include using an official project e-mail address, posting via an
official social media account, or acting as an appointed representative
at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
=== Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may
be reported by contacting the open source team at
opensource-conduct@group.apple.com. All complaints will be reviewed and
investigated and will result in a response that is deemed necessary and
appropriate to the circumstances. The project team is obligated to
maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted
separately.
Project maintainers who do not follow or enforce the Code of Conduct in
good faith may face temporary or permanent repercussions as determined
by other members of the projects leadership.
=== Attribution
This Code of Conduct is adapted from the
https://www.contributor-covenant.org[Contributor Covenant], version 1.4,
available at
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

58
CONTRIBUTING.adoc Normal file
View File

@@ -0,0 +1,58 @@
:uri-github-discussion: https://github.com/apple/pkl/discussions
:uri-github-issue-pkl: https://github.com/apple/pkl/issues/new
:uri-seven-rules: https://cbea.ms/git-commit/#seven-rules
= Pkl Contributor's Guide
Welcome to the Pkl community, and thank you for contributing!
This guide explains how to get involved.
* <<Licensing>>
* <<Issue Tracking>>
* <<Pull Requests>>
== Licensing
Pkl is released under the Apache 2.0 license.
This is why we require that, by submitting a pull request, you acknowledge that you have the right to license your contribution to Apple and the community, and agree that your contribution is licensed under the Apache 2.0 license.
== Issue Tracking
To file a bug or feature request, use {uri-github-issue-pkl}[GitHub].
Be sure to include the following information:
* Context
** What are/were you trying to achieve?
** What's the impact of this bug/feature?
For bug reports, additionally include the following information:
* The output of `pkl --version`.
* The complete error message.
* The simplest possible steps to reproduce.
== Pull Requests
When preparing a pull request, follow this checklist:
* Imitate the conventions of surrounding code.
* Format code with `./gradlew spotlessApply` (otherwise the build will fail).
* Verify that both the JVM build (`./gradlew build`) and native build (`./gradlew buildNative`) succeed.
* Follow the {uri-seven-rules}[seven rules] of great Git commit messages:
** Separate subject from body with a blank line.
** Limit the subject line to 50 characters.footnote:not-enforced[This rule is not enforced in the Pkl project.]
** Capitalize the subject line.
** Do not end the subject line with a period.
** Use the imperative mood in the subject line.
** Wrap the body at 72 characters.footnote:not-enforced[]
** Use the body to explain what and why vs. how.
IMPORTANT: If you plan to make substantial changes or add new features,
we encourage you to first discuss them with the wider Pkl developer community.
You can do this by filing a {uri-github-issue-pkl}[GitHub Issue] or by starting
{uri-github-discussion}[GitHub Discussion].
This will save time and increases the chance of your pull request being accepted.
== Maintainers
The projects maintainers (those with write access to the upstream repository) are listed in link:MAINTAINERS.adoc[].

101
DEVELOPMENT.adoc Normal file
View File

@@ -0,0 +1,101 @@
= Development
:uri-gng: https://gng.dsun.org
:uri-jenv: https://www.jenv.be
:uri-intellij: https://www.jetbrains.com/idea/download/
:uri-jdk: https://adoptopenjdk.net/releases.html
== Setup
. (mandatory) Install {uri-jdk}[OpenJDK 11 HotSpot] (as long as we support JDK11)
. (mandatory) Setup Gradle on your system
. (recommended) Install {uri-intellij}[IntelliJ IDEA 2023.x] +
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
and click its "Import Gradle Project" link.
. (recommended) Install {uri-gng}[gng] +
_gng_ enables to run Gradle commands with `gw` (instead of `./gradlew`) from any subdirectory.
. (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. +
Enable _jenv_ plugins for better handling by `gradle`:
+
[source,shell]
----
jenv enable-plugin gradle
jenv enable-plugin export
----
== Common Build Commands
[source,shell]
----
gw clean
gw test
gw build # build everything except native executables
gw buildNative # build macOS executable on macOS,
# Linux and Alpine executables on Linux
gw pkldoc # generate standard library docs
pkl-cli/build/executable/jpkl # run Java executable
pkl-cli/build/executable/pkl-macos-amd64 # run Mac executable
----
== Update Gradle
. Go to https://gradle.org/release-checksums/ and copy the checksum for the new Gradle version
. Run the following command *twice* (until it prints UP-TO-DATE):
+
[source,shell]
----
gw wrapper --gradle-version [version] --gradle-distribution-sha256-sum [sha]
----
. Commit the updated wrapper files
== Update Dependencies
. (optional) Update _gradle/libs.version.toml_
based on version information from https://search.maven.org, https://plugins.gradle.org, and GitHub repos
. Run `gw updateDependencyLocks`
. Validate changes with `gw build buildNative`
. Review and commit the updated dependency lock files
== Code Generation
* Truffle code generation is performed by Truffle's annotation processor, which runs as part of task `:pkl-core:compileJava`
** Output dir is `generated/truffle/`
* ANTLR code generation is performed by task `:pkl-core:generateGrammarSource`
** Output dir is `generated/antlr/`
== Resources
=== ANTLR
* https://github.com/antlr/antlr4/blob/main/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
* http://ssw.jku.at/Research/Projects/JVM/Truffle.html[Homepage]
* https://github.com/graalvm/truffle[GitHub]
* http://lafo.ssw.uni-linz.ac.at/javadoc/truffle/latest/[Javadoc]
* http://mail.openjdk.java.net/pipermail/graal-dev/[Mailing List]
* https://medium.com/@octskyward/graal-truffle-134d8f28fb69#.2db370y2g[Graal & Truffle (Article)]
* https://comserv.cs.ut.ee/home/files/Pool_ComputerScience_2016.pdf?study=ATILoputoo&reference=6319668E7151D556131810BC3F4A627D7FEF5F3B[Truffle Overview (see chapter 1)]
* https://gist.github.com/smarr/d1f8f2101b5cc8e14e12[Truffle: Languages and Material]
* https://github.com/smarr/truffle-notes[Truffle Notes]
* https://wiki.openjdk.java.net/display/Graal/Truffle+FAQ+and+Guidelines[Truffle FAQ]
=== Other Config Languages
* https://github.com/google/jsonnet[Jsonnet]
* https://github.com/dhall-lang/dhall-lang[Dhall]
* https://cuelang.org[CUE]
* https://nickel-lang.org[Nickel]
* https://kcl-lang.io[KCL]
* https://github.com/google/skylark[Skylark]
* https://github.com/typesafehub/config[Typesafe Config]
* https://www.flabbergast.org[Flabbergast]
(defunct, http://artefacts.masella.name/2015-srecon-andre_masella.pdf[paper])
* https://medium.com/@MrJamesFisher/nix-by-example-a0063a1a4c55[Nix by example: The Nix expression language]
* http://lethalman.blogspot.co.at/2014/07/nix-pill-4-basics-of-language.html[Nix pill 4: the basics of the language]
* https://docs.puppetlabs.com/puppet/latest/reference/lang_summary.html[Puppet Configuration Language]

202
LICENSE.txt Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

11
MAINTAINERS.adoc Normal file
View File

@@ -0,0 +1,11 @@
= MAINTAINERS
This page lists all active Maintainers of this repository.
See link:CONTRIBUTING.adoc[] for general contribution guidelines.
== Maintainers (in alphabetical order)
* https://github.com/bioball[Daniel Chao]
* https://github.com/stackoverflow[Islon Scherer]
* https://github.com/holzensp[Philip Hölzenspies]

106
NOTICE.txt Normal file
View File

@@ -0,0 +1,106 @@
Copyright © 2024 Apple Inc. and the Pkl project authors
Portions of this software were originally based on 'SnakeYAML' developed by Andrey Somov.
(https://bitbucket.org/asomov/snakeyaml-engine/)
The Apache License
Copyright © 2008-2010 Andrey Somov
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.
Portions of this software were originally based on 'jline3' developed by the JLine authors.
(https://github.com/jline/jline3)
Copyright (c) 2002-2023, the original author(s)
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 JLine 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.
Portions of this software were originally based on 'minimal-json' developed by EclipseSource.
(https://github.com/ralfstx/minimal-json)
Copyright (c) 2015, 2016 EclipseSource.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Portions of this software were originally based on 'gson' developed by the Google Inc.
(https://github.com/google/gson)
The Apache License
Copyright © 2008 Google 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
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.
Portions of this software were originally based on 'guava' developed by Google Inc.
(https://github.com/google/guava)
The Apache License
Copyright © 2009 The Guava Authors
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.
Portions of this software were originally based on 'java-string-similarity' developed by Thibault Debatty.
(https://github.com/tdebatty/java-string-similarity)
Copyright 2015 Thibault Debatty
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Portions of this software were originally based on 'xerxes2-j' developed by the Apache Software Foundation.
(https://github.com/apache/xerces2-j)
The Apache License
Copyright © 1999-2018 The Apache Software Foundation
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.
Portions of this software were originally based on 'scroll-into-view-if-needed' developed by Cody Olsen.
(https://github.com/scroll-into-view/scroll-into-view-if-needed)
Copyright (c) 2023 Cody Olsen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This product ships with third party licenses that may be distributed under a different license.
This information is detailed in THIRD-PARTY-NOTICES.txt.
Portions of this software includes code from "Gradle" by Gradle, Inc.
Copyright 2015 the original author or authors.
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.

36
README.adoc Normal file
View File

@@ -0,0 +1,36 @@
= Pkl
:uri-homepage: https://pkl-lang.org
:uri-docs: {uri-homepage}/main/current
:uri-docs-introduction: {uri-docs}/introduction
:uri-docs-release-notes: {uri-docs}/release-notes
:uri-docs-language: {uri-docs}/language
:uri-docs-tools: {uri-docs}/tools
:uri-github-issue: https://github.com/apple/pkl/issues
:uri-github-discussions: https://github.com/apple/pkl/discussions
:uri-pkl-examples: https://pkl-lang.org/main/current/examples.html
:uri-installation: https://pkl-lang.org/main/current/pkl-cli/index.html#installation
:uri-lang-reference: https://pkl-lang.org/main/current/language-reference/index.html
A configuration as code language with rich validation and tooling.
== Quick Links
* {uri-installation}[Installation]
* {uri-lang-reference}[Language Reference]
== Documentation
* {uri-homepage}[Home Page]
** {uri-docs-introduction}[Introduction]
** {uri-docs-language}[Language]
** {uri-docs-tools}[Tools]
** {uri-pkl-examples}[Examples]
** {uri-docs-release-notes}[Release Notes]
== Community
We'd love to hear from you!
* Create an {uri-github-issue}[issue]
* Ask a question on {uri-github-discussions}[GitHub Discussions]

13
SECURITY.adoc Normal file
View File

@@ -0,0 +1,13 @@
= Security
For the protection of our community, the Pkl team does not disclose, discuss, or confirm security issues until our investigation is complete and any necessary updates are generally available.
== Reporting a security vulnerability
If you have discovered a security vulnerability within the Pkl project, please report it to us.
We welcome reports from everyone, including security researchers, developers, and users.
Security vulnerabilities may be reported on the link:https://security.apple.com/submit[Report a vulnerability] form.
When submitting a vulnerability, select "Apple Devices and Software" as the affected platform, and "Open Source" as the affected area.
For more information, see https://pkl-lang.org/security.html.

376
THIRD-PARTY-NOTICES.txt Normal file
View File

@@ -0,0 +1,376 @@
Pkl ships with third-party libraries that may be distributed under a different license than
Pkl's own license.
These libraries and their licenses are listed below:
1) Clikt (https://github.com/ajalt/clikt)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
Copyright © 2018 AJ Alt
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.
2) JavaPoet (http://github.com/square/javapoet/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
Copyright © 2015 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
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.
3) KotlinPoet (https://github.com/square/kotlinpoet)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
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
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)
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
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
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
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
POM License: The 2-Clause BSD License - https://opensource.org/licenses/BSD-2-Clause
Embedded license:
****************************************
Copyright (c) 2015, Atlassian Pty Ltd
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.
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 HOLDER 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.
7) commonmark-java extension for tables
POM License: The 2-Clause BSD License - https://opensource.org/licenses/BSD-2-Clause
Embedded license:
****************************************
Copyright (c) 2015, Atlassian Pty Ltd
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.
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 HOLDER 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.
8) jansi (http://fusesource.com/)
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
The Apache License
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
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)
POM License: Universal Permissive License, Version 1.0 - http://opensource.org/licenses/UPL
10) Truffle API (http://openjdk.java.net/projects/graal)
POM License: Universal Permissive License, Version 1.0 - http://opensource.org/licenses/UPL
11) IntelliJ IDEA Annotations (http://www.jetbrains.org)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
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
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/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
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
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/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
Copyright © 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributor
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.
14) kotlin-stdlib-common (https://kotlinlang.org/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
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
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/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
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
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/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
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
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)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
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
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)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
2017-2019 JetBrains s.r.o and respective authors and developers
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.
19) kotlinx-serialization-json (https://github.com/Kotlin/kotlinx.serialization)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
2017-2019 JetBrains s.r.o and respective authors and developers
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.
20) JLine Reader
Manifest license URL: https://opensource.org/licenses/BSD-3-Clause
POM License: The 3-Clause BSD License - https://opensource.org/licenses/BSD-3-Clause
Copyright (c) 2002-2023, the original author(s)
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 JLine 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.
21) JLine Terminal
Manifest license URL: https://opensource.org/licenses/BSD-3-Clause
POM License: The 3-Clause BSD License - https://opensource.org/licenses/BSD-3-Clause
Copyright (c) 2002-2023, the original author(s)
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 JLine 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.
22) JLine JANSI Terminal
Manifest license URL: https://opensource.org/licenses/BSD-3-Clause
POM License: The 3-Clause BSD License - https://opensource.org/licenses/BSD-3-Clause
Copyright (c) 2002-2023, the original author(s)
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 JLine 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.
23) msgpack-core (https://msgpack.org/)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
Copyright © 2016 Sadayuki Furuhashi, Muga Nishizawa, Taro L. Saito, Mitsunori Komatsu, Ozawa Tsuyoshi
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.
24) Paguro (https://github.com/GlenKPeterson/Paguro)
POM License: Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0
The Apache License
Copyright © 2021 Glen K. Peterson
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.
POM License: Eclipse Public License - v 1.0 - http://www.eclipse.org/legal/epl-v10.html
NOTE: The files in this project that came from Clojure (Persistent...) MUST only be used under the Eclipse 1.0 license.
At the user's choice, any other files in this project can be used under Eclipse 1.0 or the Apache 2.0 license.
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT").
ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
1. DEFINITIONS
"Contribution" means:
a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.
"Contributor" means any person or entity that distributes the Program.
"Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.
"Program" means the Contributions distributed in accordance with this Agreement.
"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.
b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:
a) it complies with the terms and conditions of this Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
iii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and
iv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright notices contained within the Program.
Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.
For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement , including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.
All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.
Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved.
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)
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
The Apache License
Copyright © 2008-2010 Andrey Somov
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.

48
bench/bench.gradle.kts Normal file
View File

@@ -0,0 +1,48 @@
plugins {
pklAllProjects
pklJavaLibrary
pklGraalVm
id("me.champeau.jmh")
}
val truffle: Configuration by configurations.creating
val graal: Configuration by configurations.creating
@Suppress("UnstableApiUsage")
dependencies {
jmh(project(":pkl-core"))
// necessary because antlr4-runtime is declared as implementation dependency in pkl-core.gradle
jmh(libs.antlrRuntime)
truffle(libs.truffleApi)
graal(libs.graalCompiler)
}
jmh {
//include = ["fib_class_java"]
//include = ["fib_class_constrained1", "fib_class_constrained2"]
jmhVersion.set(libs.versions.jmh)
// jvmArgsAppend = "-Dgraal.TruffleCompilationExceptionsAreFatal=true " +
// "-Dgraal.Dump=Truffle,TruffleTree -Dgraal.TraceTruffleCompilation=true " +
// "-Dgraal.TruffleFunctionInlining=false"
jvm.set("${buildInfo.graalVm.baseDir}/bin/java")
// see: https://docs.oracle.com/en/graalvm/enterprise/20/docs/graalvm-as-a-platform/implement-language/#disable-class-path-separation
jvmArgs.set(
listOf(
// one JVM arg per list element doesn't work, but the following does
"-Dgraalvm.locatorDisabled=true --module-path=${truffle.asPath} --upgrade-module-path=${graal.asPath}"
)
)
includeTests.set(false)
//threads = Runtime.runtime.availableProcessors() / 2 + 1
//synchronizeIterations = false
}
tasks.named("jmh") {
dependsOn(":installGraalVm")
}
// Prevent this error which occurs when building in IntelliJ:
// "Entry org/pkl/core/fib_class_typed.pkl is a duplicate but no duplicate handling strategy has been set."
tasks.processJmhResources {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

43
bench/gradle.lockfile Normal file
View File

@@ -0,0 +1,43 @@
# 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.
com.tunnelvisionlabs:antlr4-runtime:4.9.0=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
net.bytebuddy:byte-buddy:1.12.21=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
org.apache.commons:commons-math3:3.2=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata
org.assertj:assertj-core:3.24.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.compiler:compiler:22.3.1=graal
org.graalvm.sdk:graal-sdk:22.3.1=graal,jmh,jmhRuntimeClasspath,truffle
org.graalvm.truffle:truffle-api:22.3.1=graal,jmh,jmhRuntimeClasspath,truffle
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,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath
org.jetbrains.kotlin:kotlin-scripting-common:1.7.10=kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.7.10=kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.7.10=kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-scripting-jvm:1.7.10=kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest
org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10=kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,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,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jetbrains:annotations:13.0=kotlinCompilerClasspath,kotlinCompilerPluginClasspathJmh,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-engine:5.9.3=testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-params:5.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-engine:1.9.3=testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit:junit-bom:5.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.openjdk.jmh:jmh-core:1.36=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.openjdk.jmh:jmh-generator-asm:1.36=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.openjdk.jmh:jmh-generator-bytecode:1.36=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.openjdk.jmh:jmh-generator-reflection:1.36=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.organicdesign:Paguro:3.10.3=jmh,jmhRuntimeClasspath
org.ow2.asm:asm:9.0=jmh,jmhCompileClasspath,jmhImplementationDependenciesMetadata,jmhRuntimeClasspath
org.snakeyaml:snakeyaml-engine:2.5=jmh,jmhRuntimeClasspath
empty=annotationProcessor,apiDependenciesMetadata,archives,compile,compileClasspath,compileOnly,compileOnlyDependenciesMetadata,default,implementationDependenciesMetadata,intransitiveDependenciesMetadata,jmhAnnotationProcessor,jmhApiDependenciesMetadata,jmhCompile,jmhCompileOnly,jmhCompileOnlyDependenciesMetadata,jmhIntransitiveDependenciesMetadata,jmhKotlinScriptDef,jmhKotlinScriptDefExtensions,jmhRuntime,jmhRuntimeOnlyDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtime,runtimeClasspath,runtimeOnlyDependenciesMetadata,sourcesJar,testAnnotationProcessor,testApiDependenciesMetadata,testCompile,testCompileOnly,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions,testRuntime

View File

@@ -0,0 +1,104 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core;
import static org.pkl.core.ModuleSource.modulePath;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;
@SuppressWarnings("unused")
@Warmup(iterations = 5, time = 2)
@Measurement(iterations = 5, time = 2)
@OutputTimeUnit(TimeUnit.SECONDS)
@Fork(1)
public class Fibonacci {
@Benchmark
public long fib_class_java() {
return new FibJavaImpl().fib(35);
}
@Benchmark
public long fib_class() {
try (var evaluator = Evaluator.preconfigured()) {
var module = evaluator.evaluate(modulePath("org/pkl/core/fib_class.pkl"));
return (long) module.getProperties().get("result");
}
}
@Benchmark
public long fib_class_explicitThis() {
try (var evaluator = Evaluator.preconfigured()) {
var module = evaluator.evaluate(modulePath("org/pkl/core/fib_class_explicitThis.pkl"));
return (long) module.getProperties().get("result");
}
}
@Benchmark
public long fib_class_typed() {
try (var evaluator = Evaluator.preconfigured()) {
var module = evaluator.evaluate(modulePath("org/pkl/core/fib_class_typed.pkl"));
return (long) module.getProperties().get("result");
}
}
@Benchmark
public long fib_class_constrained1() {
try (var evaluator = Evaluator.preconfigured()) {
var module = evaluator.evaluate(modulePath("org/pkl/core/fib_class_constrained1.pkl"));
return (long) module.getProperties().get("result");
}
}
@Benchmark
public long fib_class_constrained2() {
try (var evaluator = Evaluator.preconfigured()) {
var module = evaluator.evaluate(modulePath("org/pkl/core/fib_class_constrained2.pkl"));
return (long) module.getProperties().get("result");
}
}
@Benchmark
public long fib_module() {
try (var evaluator = Evaluator.preconfigured()) {
var module = evaluator.evaluate(modulePath("org/pkl/core/fib_module.pkl"));
return (long) module.getProperties().get("result");
}
}
@Benchmark
public long fib_module_explicitThis() {
try (var evaluator = Evaluator.preconfigured()) {
var module = evaluator.evaluate(modulePath("org/pkl/core/fib_module_explicitThis.pkl"));
return (long) module.getProperties().get("result");
}
}
@Benchmark
public long fib_lambda() {
try (var evaluator = Evaluator.preconfigured()) {
var module = evaluator.evaluate(modulePath("org/pkl/core/fib_lambda.pkl"));
return (long) module.getProperties().get("result");
}
}
}
// kept similar to pkl code (class, instance method, long argument)
class FibJavaImpl {
long fib(long n) {
return n < 2 ? n : fib(n - 1) + fib(n - 2);
}
}

View File

@@ -0,0 +1,143 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.util.TempFile;
import org.openjdk.jmh.util.TempFileManager;
import org.pkl.core.module.ModuleKeyFactories;
import org.pkl.core.repl.ReplRequest;
import org.pkl.core.repl.ReplResponse;
import org.pkl.core.repl.ReplServer;
import org.pkl.core.resource.ResourceReaders;
import org.pkl.core.util.IoUtils;
@Warmup(iterations = 5, time = 2)
@Measurement(iterations = 5, time = 2)
@OutputTimeUnit(TimeUnit.SECONDS)
@Fork(1)
@SuppressWarnings("unused")
public class ListSort {
private static final ReplServer repl =
new ReplServer(
SecurityManagers.defaultManager,
Loggers.stdErr(),
List.of(ModuleKeyFactories.standardLibrary),
List.of(ResourceReaders.file()),
Map.of(),
Map.of(),
null,
null,
null,
IoUtils.getCurrentWorkingDir(),
StackFrameTransformers.defaultTransformer);
private static final List<Object> list = new ArrayList<>(100000);
static {
var random = new Random(2786433088656064171L);
for (var i = 0; i < 100000; i++) {
list.add(random.nextLong());
}
TempFile tempFile;
try {
tempFile = new TempFileManager().create("bench-nums.txt");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
try (var fw = new FileWriter(tempFile.getAbsolutePath())) {
for (var elem : list) {
fw.append(elem.toString()).append('\n');
}
fw.flush();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
var responses =
repl.handleRequest(
new ReplRequest.Eval(
"setup",
"import \"pkl:test\"\n"
+ "random = test.random\n"
+ "nums = read(\"file://"
+ tempFile.getAbsolutePath()
+ "\").text.split(\"\\n\").dropLast(1).map((it) -> it.toInt())\n"
+ "cmp = (x, y) -> if (x < y) -1 else if (x == y) 0 else 1",
false,
false));
if (!responses.isEmpty()) {
throw new AssertionError(responses.get(0));
}
}
@Benchmark
public String sortPkl() {
var response =
repl.handleRequest(
// append `.length` to avoid rendering the list
new ReplRequest.Eval("sort", "nums.sort().length", false, false))
.get(0);
if (!(response instanceof ReplResponse.EvalSuccess)) {
throw new AssertionError(response);
}
return ((ReplResponse.EvalSuccess) response).getResult();
}
@Benchmark
public String sortWithPkl() {
var response =
repl.handleRequest(
// append `.length` to avoid rendering the list
new ReplRequest.Eval("sort", "nums.sortWith(cmp).length", false, false))
.get(0);
if (!(response instanceof ReplResponse.EvalSuccess)) {
throw new AssertionError(response);
}
return ((ReplResponse.EvalSuccess) response).getResult();
}
// note that this is an uneven comparison
// (timsort vs. merge sort, java.util.ArrayList vs. persistent vector
@Benchmark
public List<Object> sortJava() {
return sort(list);
}
private List<Object> sort(List<Object> self) {
var array = self.toArray();
Arrays.sort(array);
return Arrays.asList(array);
}
// note that this is an uneven comparison
// (timsort vs. merge sort, java.util.ArrayList vs. persistent vector
@Benchmark
public List<Object> sortWithJava() {
return sortWith(list, Comparator.comparingLong(x -> (long) x));
}
private List<Object> sortWith(List<Object> self, Comparator<Object> comparator) {
var array = self.toArray();
Arrays.sort(array, comparator);
return Arrays.asList(array);
}
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core.parser;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.*;
@SuppressWarnings("unused")
@Warmup(iterations = 5, time = 2)
@Measurement(iterations = 5, time = 2)
@OutputTimeUnit(TimeUnit.SECONDS)
@Fork(1)
public class ParserBenchmark {
// One-time execution of this code took ~10s until moving rule alternative
// for parenthesized expression after alternative for anonymous function.
@Benchmark
public void run() {
new Parser()
.parseModule(
"a1 {\n"
+ " a2 {\n"
+ " a3 {\n"
+ " a4 {\n"
+ " a5 {\n"
+ " a6 {\n"
+ " a7 {\n"
+ " a8 {\n"
+ " a9 {\n"
+ " a10 {\n"
+ " a11 {\n"
+ " a12 {\n"
+ " a13 = map(map(map((x) -> 1)))\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}");
}
}

View File

@@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
class Fibonacci {
function fib(n) = if (n < 2) n else fib(n - 1) + fib(n - 2)
}
result = new Fibonacci {}.fib(35)

View File

@@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
class Fibonacci {
function fib(n: Int(this >= 0)): Int(this >= 0) = if (n < 2) n else fib(n - 1) + fib(n - 2)
}
result = new Fibonacci {}.fib(35)

View File

@@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
class Fibonacci {
function fib(n: Int(isPositive)): Int(isPositive) = if (n < 2) n else fib(n - 1) + fib(n - 2)
}
result = new Fibonacci {}.fib(35)

View File

@@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
class Fibonacci {
function fib(n) = if (n < 2) n else this.fib(n - 1) + this.fib(n - 2)
}
result = new Fibonacci {}.fib(35)

View File

@@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
class Fibonacci {
function fib(n: Int): Int = if (n < 2) n else fib(n - 1) + fib(n - 2)
}
result = new Fibonacci {}.fib(35)

View File

@@ -0,0 +1,19 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
hidden fib = (n) -> if (n < 2) n else fib.apply(n - 1) + fib.apply(n - 2)
result = fib.apply(35)

View File

@@ -0,0 +1,18 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
function fib(n) = if (n < 2) n else fib(n - 1) + fib(n - 2)
result = fib(35)

View File

@@ -0,0 +1,18 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
function fib(n) = if (n < 2) n else this.fib(n - 1) + this.fib(n - 2)
result = fib(35)

67
build.gradle.kts Normal file
View File

@@ -0,0 +1,67 @@
// https://youtrack.jetbrains.com/issue/KTIJ-19369
@file:Suppress("DSL_SCOPE_VIOLATION")
import org.jetbrains.gradle.ext.ActionDelegationConfig
import org.jetbrains.gradle.ext.ActionDelegationConfig.TestRunner.PLATFORM
import org.jetbrains.gradle.ext.ProjectSettings
import org.jetbrains.gradle.ext.TaskTriggersConfig
plugins {
pklAllProjects
pklGraalVm
alias(libs.plugins.ideaExt)
alias(libs.plugins.jmh) apply false
alias(libs.plugins.nexusPublish)
}
nexusPublishing {
repositories {
sonatype {
nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
}
}
}
idea {
project {
this as ExtensionAware
configure<ProjectSettings> {
this as ExtensionAware
configure<ActionDelegationConfig> {
delegateBuildRunToGradle = true
testRunner = PLATFORM
}
configure<TaskTriggersConfig> {
afterSync(provider { project(":pkl-core").tasks.named("makeIntelliJAntlrPluginHappy") })
}
}
}
}
val clean by tasks.registering(Delete::class) {
delete(buildDir)
}
val printVersion by tasks.registering {
doFirst { println(buildInfo.pklVersion) }
}
val message = """
====
Gradle version : ${gradle.gradleVersion}
Java version : ${System.getProperty("java.version")}
isParallel : ${gradle.startParameter.isParallelProjectExecutionEnabled}
maxWorkerCount : ${gradle.startParameter.maxWorkerCount}
Architecture : ${buildInfo.arch}
Project Version : ${project.version}
Pkl Version : ${buildInfo.pklVersion}
Pkl Non-Unique Version : ${buildInfo.pklVersionNonUnique}
Git Commit ID : ${buildInfo.commitId}
====
"""
val formattedMessage = message.replace("\n====", "\n" + "=".repeat(message.lines().maxByOrNull { it.length }!!.length))
logger.info(formattedMessage)

17
buildSrc/build.gradle.kts Normal file
View File

@@ -0,0 +1,17 @@
plugins {
`kotlin-dsl`
}
dependencies {
implementation(libs.downloadTaskPlugin)
implementation(libs.spotlessPlugin)
implementation(libs.kotlinPlugin) {
exclude(module = "kotlin-android-extensions")
}
implementation(libs.shadowPlugin)
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

View File

@@ -0,0 +1,24 @@
@file:Suppress("UnstableApiUsage")
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}
// makes ~/.gradle/init.gradle unnecessary and ~/.gradle/gradle.properties optional
dependencyResolutionManagement {
// use same version catalog as main build
versionCatalogs {
register("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
repositories {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
mavenCentral()
gradlePluginPortal()
}
}

View File

@@ -0,0 +1,144 @@
@file:Suppress("MemberVisibilityCanBePrivate")
import java.io.File
import org.gradle.api.Project
import org.gradle.api.artifacts.VersionCatalog
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.api.artifacts.VersionConstraint
import org.gradle.kotlin.dsl.getByType
// `buildInfo` in main build scripts
// `project.extensions.getByType<BuildInfo>()` in precompiled script plugins
open class BuildInfo(project: Project) {
val self = this
inner class GraalVm {
val homeDir: String by lazy {
System.getenv("GRAALVM_HOME") ?: "${System.getProperty("user.home")}/.graalvm"
}
val version: String by lazy {
libs.findVersion("graalVm").get().toString()
}
val isGraal22: Boolean by lazy {
version.startsWith("22")
}
val arch by lazy {
if (os.isMacOsX && isGraal22) {
"amd64"
} else {
self.arch
}
}
val osName: String by lazy {
when {
os.isMacOsX && isGraal22 -> "darwin"
os.isMacOsX -> "macos"
os.isLinux -> "linux"
else -> throw RuntimeException("${os.familyName} is not supported.")
}
}
val baseName: String by lazy {
if (graalVm.isGraal22) {
"graalvm-ce-java11-${osName}-${arch}-${version}"
} else {
"graalvm-jdk-${graalVM23JdkVersion}_${osName}-${arch}_bin"
}
}
val graalVM23JdkVersion: String by lazy {
libs.findVersion("graalVM23JdkVersion").get().requiredVersion
}
val downloadUrl: String by lazy {
if (isGraal22) {
"https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-" +
"${version}/$baseName.tar.gz"
} else {
val jdkMajor = graalVM23JdkVersion.takeWhile { it != '.' }
"https://download.oracle.com/graalvm/$jdkMajor/archive/$baseName.tar.gz"
}
}
val installDir: File by lazy {
File(homeDir, baseName)
}
val baseDir: String by lazy {
if (os.isMacOsX) "$installDir/Contents/Home" else installDir.toString()
}
}
/**
* Same logic as [org.gradle.internal.os.OperatingSystem#arch], which is protected.
*/
val arch: String by lazy {
when (val arch = System.getProperty("os.arch")) {
"x86" -> "i386"
"x86_64" -> "amd64"
"powerpc" -> "ppc"
else -> arch
}
}
val graalVm: GraalVm = GraalVm()
val isCiBuild: Boolean by lazy {
System.getenv("CI") != null
}
val isReleaseBuild: Boolean by lazy {
java.lang.Boolean.getBoolean("releaseBuild")
}
val os: org.gradle.internal.os.OperatingSystem by lazy {
org.gradle.internal.os.OperatingSystem.current()
}
// could be `commitId: Provider<String> = project.provider { ... }`
val commitId: String by lazy {
// only run command once per build invocation
if (project === project.rootProject) {
Runtime.getRuntime()
.exec("git rev-parse --short HEAD", arrayOf(), project.rootDir)
.inputStream.reader().readText().trim()
} else {
project.rootProject.extensions.getByType(BuildInfo::class.java).commitId
}
}
val commitish: String by lazy {
if (isReleaseBuild) project.version.toString() else commitId
}
val pklVersion: String by lazy {
if (isReleaseBuild) {
project.version.toString()
} else {
project.version.toString().replace("-SNAPSHOT", "-dev+$commitId")
}
}
val pklVersionNonUnique: String by lazy {
if (isReleaseBuild) {
project.version.toString()
} else {
project.version.toString().replace("-SNAPSHOT", "-dev")
}
}
// https://melix.github.io/blog/2021/03/version-catalogs-faq.html#_but_how_can_i_use_the_catalog_in_em_plugins_em_defined_in_code_buildsrc_code
val libs: VersionCatalog by lazy {
project.extensions.getByType<VersionCatalogsExtension>().named("libs")
}
init {
if (!isReleaseBuild) {
project.version = "${project.version}-SNAPSHOT"
}
}
}

View File

@@ -0,0 +1,47 @@
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.listProperty
/**
* Builds a self-contained Pkl CLI Jar that is directly executable on *nix
* and executable with `java -jar` on Windows.
*
* For direct execution, the `java` command must be on the PATH.
*
* https://skife.org/java/unix/2011/06/20/really_executable_jars.html
*/
open class ExecutableJar : DefaultTask() {
@get:InputFile
val inJar: RegularFileProperty = project.objects.fileProperty()
@get:OutputFile
val outJar: RegularFileProperty = project.objects.fileProperty()
@get:Input
val jvmArgs: ListProperty<String> = project.objects.listProperty()
@TaskAction
fun buildJar() {
val inFile = inJar.get().asFile
val outFile = outJar.get().asFile
val escapedJvmArgs = jvmArgs.get().joinToString(separator = " ") { "\"$it\"" }
val startScript = """
#!/bin/sh
exec java $escapedJvmArgs -jar $0 "$@"
""".trim().trimMargin() + "\n\n\n"
outFile.outputStream().use { outStream ->
startScript.byteInputStream().use { it.copyTo(outStream) }
inFile.inputStream().use { it.copyTo(outStream) }
}
// chmod a+x
outFile.setExecutable(true, false)
}
}

View File

@@ -0,0 +1,7 @@
import org.gradle.util.GradleVersion
open class GradlePluginTests {
lateinit var minGradleVersion: GradleVersion
lateinit var maxGradleVersion: GradleVersion
var skippedGradleVersions: List<GradleVersion> = listOf()
}

View File

@@ -0,0 +1,68 @@
import java.net.URL
import org.gradle.util.GradleVersion
import groovy.json.JsonSlurper
@Suppress("unused")
class GradleVersionInfo(json: Map<String, Any>) {
val version: String by json
val gradleVersion: GradleVersion by lazy { GradleVersion.version(version) }
val isReleaseVersion: Boolean by lazy {
// for some reason, `gradleVersion == gradleVersion.baseVersion` is a compile error
gradleVersion.version == gradleVersion.baseVersion.version
}
val buildTime: String by json
val current: Boolean by json
val snapshot: Boolean by json
val nightly: Boolean by json
val releaseNightly: Boolean by json
val activeRc: Boolean by json
val rcFor: String by json
val milestoneFor: String by json
val broken: Boolean by json
val downloadUrl: String by json
val checksumUrl: String by json
val wrapperChecksumUrl: String by json
companion object {
private fun fetchAll(): List<GradleVersionInfo> = fetchMultiple("https://services.gradle.org/versions/all")
fun fetchReleases(): List<GradleVersionInfo> = fetchAll().filter { it.isReleaseVersion }
fun fetchCurrent(): GradleVersionInfo = fetchSingle("https://services.gradle.org/versions/current")
fun fetchRc(): GradleVersionInfo? = fetchSingleOrNull("https://services.gradle.org/versions/release-candidate")
fun fetchNightly(): GradleVersionInfo = fetchSingle("https://services.gradle.org/versions/nightly")
private fun fetchSingle(url: String): GradleVersionInfo {
@Suppress("UNCHECKED_CAST")
return GradleVersionInfo(JsonSlurper().parse(URL(url)) as Map<String, Any>)
}
private fun fetchSingleOrNull(url: String): GradleVersionInfo? {
@Suppress("UNCHECKED_CAST")
val json = JsonSlurper().parse(URL(url)) as Map<String, Any>
return if (json.isEmpty()) null else GradleVersionInfo(json)
}
private fun fetchMultiple(url: String): List<GradleVersionInfo> {
@Suppress("UNCHECKED_CAST")
return (JsonSlurper().parse(URL(url)) as List<Map<String, Any>>)
.map { GradleVersionInfo(it) }
}
}
}

View File

@@ -0,0 +1,6 @@
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
open class HtmlValidator(project: Project) {
var sources: FileCollection = project.files()
}

View File

@@ -0,0 +1,115 @@
import java.io.File
import java.util.regex.Matcher
import java.util.regex.Pattern
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileVisitDetails
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.listProperty
import org.gradle.kotlin.dsl.mapProperty
open class MergeSourcesJars : DefaultTask() {
@get:InputFiles
val inputJars: ConfigurableFileCollection = project.objects.fileCollection()
@get:InputFiles
val mergedBinaryJars: ConfigurableFileCollection = project.objects.fileCollection()
@get:Input
val relocatedPackages: MapProperty<String, String> = project.objects.mapProperty()
@get:Input
var sourceFileExtensions: ListProperty<String> = project.objects.listProperty<String>()
.convention(listOf(".java", ".kt"))
@get:OutputFile
val outputJar: RegularFileProperty = project.objects.fileProperty()
@TaskAction
@Suppress("unused")
fun merge() {
val binaryPaths = collectBinaryPaths()
val relocatedPkgs = relocatedPackages.get()
val relocatedPaths = relocatedPkgs.entries.associate { (key, value) -> toPath(key) to toPath(value) }
// use negative lookbehind to match any that don't precede with
// a word or a period character. should catch most cases.
val importPattern = Pattern.compile("(?<!(\\w|\\.))(" +
relocatedPkgs.keys.joinToString("|") { it.replace(".", "\\.") } + ")")
val sourceFileExts = sourceFileExtensions.get()
val outDir = this.temporaryDir
for (jar in inputJars) {
// as of Gradle 2.4, doesn't visit dirs despite the claims
project.zipTree(jar).visit {
val details = this
if (details.isDirectory) return@visit
var path = details.relativePath.parent.pathString
val relocatedPath = relocatedPaths.keys.find { path.startsWith(it) }
if (relocatedPath != null) {
path = path.replace(relocatedPath, relocatedPaths.getValue(relocatedPath))
}
// conservative shrinking
if (!binaryPaths.contains(path)) return@visit
val outFile = File("$outDir/$path/${details.file.name}")
outFile.parentFile.mkdirs()
if (sourceFileExts.any { details.file.name.endsWith(it) }) {
val oldContents = details.file.readText(Charsets.UTF_8)
val newContents = fixImports(relocatedPkgs, details, oldContents, importPattern)
outFile.writeText(newContents, Charsets.UTF_8)
} else {
details.copyTo(outFile)
}
}
}
project.ant.invokeMethod("jar", mapOf("basedir" to outDir, "destfile" to outputJar.get()))
}
private fun collectBinaryPaths(): Set<String> {
val result = mutableSetOf<String>()
for (jar in mergedBinaryJars) {
// as of Gradle 2.4 doesn't visit dirs despite the claims
project.zipTree(jar).visit {
val details = this
if (details.isDirectory) return@visit // avoid adding empty dirs
result.add(details.relativePath.parent.pathString)
}
}
return result
}
private fun fixImports(
relocatedPkgs: Map<String, String>,
details: FileVisitDetails,
sourceText: String,
importPattern: Pattern
): String {
val matcher = importPattern.matcher(sourceText)
val buffer = StringBuffer()
logger.debug("Inspecting file: {}", details.relativePath)
while (matcher.find()) {
val newStat = relocatedPkgs[matcher.group(2)]
logger.debug("Old: {}", matcher.group())
logger.debug("New: {}", newStat)
matcher.appendReplacement(buffer, Matcher.quoteReplacement(newStat))
}
matcher.appendTail(buffer)
return buffer.toString()
}
private fun toPath(packageName: String): String = packageName.replace(".", "/")
}

View File

@@ -0,0 +1,43 @@
import org.gradle.api.DefaultTask
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.jvm.JvmLibrary
import org.gradle.kotlin.dsl.property
import org.gradle.language.base.artifact.SourcesArtifact
open class ResolveSourcesJars : DefaultTask() {
@get:InputFiles
val configuration: Property<Configuration> = project.objects.property()
@get:OutputDirectory
val outputDir: DirectoryProperty = project.objects.directoryProperty()
@TaskAction
@Suppress("UnstableApiUsage", "unused")
fun resolve() {
val componentIds = configuration.get().incoming.resolutionResult.allDependencies.map {
(it as ResolvedDependencyResult).selected.id
}
val resolutionResult = project.dependencies.createArtifactResolutionQuery()
.forComponents(componentIds)
.withArtifacts(JvmLibrary::class.java, SourcesArtifact::class.java)
.execute()
val resolvedJars = resolutionResult.resolvedComponents
.flatMap { it.getArtifacts(SourcesArtifact::class.java) }
.map { (it as ResolvedArtifactResult).file }
// copying to an output dir because I don't know how else to describe task outputs
project.sync {
from(resolvedJars)
into(outputDir)
}
}
}

View File

@@ -0,0 +1,95 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
val buildInfo = extensions.create<BuildInfo>("buildInfo", project)
dependencyLocking {
lockAllConfigurations()
}
configurations {
val rejectedVersionSuffix = Regex("-alpha|-beta|-eap|-m|-rc|-snapshot", RegexOption.IGNORE_CASE)
configureEach {
resolutionStrategy {
componentSelection {
all {
if (rejectedVersionSuffix.containsMatchIn(candidate.version)) {
reject("Rejected dependency $candidate " +
"because it has a prelease version suffix matching `$rejectedVersionSuffix`.")
}
}
}
}
}
}
plugins.withType(JavaPlugin::class).configureEach {
val java = project.extensions.getByType<JavaPluginExtension>()
java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "11"
freeCompilerArgs = freeCompilerArgs + listOf("-Xjsr305=strict", "-Xjvm-default=all")
}
}
plugins.withType(IdeaPlugin::class).configureEach {
val errorMessage = "Use IntelliJ Gradle import instead of running the `idea` task. See README for more information."
tasks.named("idea") {
doFirst {
throw GradleException(errorMessage)
}
}
tasks.named("ideaModule") {
doFirst {
throw GradleException(errorMessage)
}
}
if (project == rootProject) {
tasks.named("ideaProject") {
doFirst {
throw GradleException(errorMessage)
}
}
}
}
plugins.withType(MavenPublishPlugin::class).configureEach {
configure<PublishingExtension> {
// CI builds pick up artifacts from this repo.
// It's important that this repo is only declared once per project.
repositories {
maven {
name = "projectLocal" // affects task names
url = uri("file:///$rootDir/build/m2")
}
}
// use resolved/locked (e.g., `1.15`)
// instead of declared (e.g., `1.+`)
// dependency versions in generated POMs
publications {
withType(MavenPublication::class.java) {
versionMapping {
allVariants {
fromResolutionResult()
}
}
}
}
}
}
// settings.gradle.kts sets `--write-locks`
// if Gradle command line contains this task name
val updateDependencyLocks by tasks.registering {
doLast {
configurations
.filter { it.isCanBeResolved }
.forEach { it.resolve() }
}
}
val allDependencies by tasks.registering(DependencyReportTask::class)

View File

@@ -0,0 +1,183 @@
import org.gradle.api.GradleException
import org.gradle.api.artifacts.Configuration
import org.gradle.api.component.AdhocComponentWithVariants
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.*
plugins {
`java-library`
`maven-publish`
id("com.github.johnrengelman.shadow")
}
// make fat Jar available to other subprojects
val fatJarConfiguration: Configuration = configurations.create("fatJar")
val fatJarPublication: MavenPublication = publishing.publications.create<MavenPublication>("fatJar")
// ideally we'd configure this automatically based on project dependencies
val firstPartySourcesJarsConfiguration: Configuration = configurations.create("firstPartySourcesJars")
val relocations = mapOf(
// pkl-core dependencies
"org.antlr.v4." to "org.pkl.thirdparty.antlr.v4.",
// https://github.com/oracle/graal/issues/1644 has been fixed,
// but native-image still fails when shading com.oracle.truffle
//"com.oracle.truffle" to "org.pkl.thirdparty.truffle",
"org.graalvm." to "org.pkl.thirdparty.graalvm.",
"org.organicdesign.fp." to "org.pkl.thirdparty.paguro.",
"org.snakeyaml.engine." to "org.pkl.thirdparty.snakeyaml.engine.",
"org.msgpack." to "org.pkl.thirdparty.msgpack.",
"org.w3c.dom." to "org.pkl.thirdparty.w3c.dom",
"com.oracle.svm.core." to "org.pkl.thirdparty.svm.",
// pkl-cli dependencies
"org.jline." to "org.pkl.thirdparty.jline.",
"com.github.ajalt.clikt." to "org.pkl.thirdparty.clikt.",
"kotlin." to "org.pkl.thirdparty.kotlin.",
"kotlinx." to "org.pkl.thirdparty.kotlinx.",
"org.intellij." to "org.pkl.thirdparty.intellij.",
"org.fusesource.jansi." to "org.pkl.thirdparty.jansi",
"org.fusesource.hawtjni." to "org.pkl.thirdparty.hawtjni",
// pkl-doc dependencies
"org.commonmark." to "org.pkl.thirdparty.commonmark.",
"org.jetbrains." to "org.pkl.thirdparty.jetbrains.",
// pkl-config-java dependencies
"io.leangen.geantyref." to "org.pkl.thirdparty.geantyref.",
// pkl-codegen-java dependencies
"com.squareup.javapoet." to "org.pkl.thirdparty.javapoet.",
// pkl-codegen-kotlin dependencies
"com.squareup.kotlinpoet." to "org.pkl.thirdparty.kotlinpoet.",
)
val nonRelocations = listOf("com/oracle/truffle/")
tasks.shadowJar {
inputs.property("relocations", relocations)
archiveClassifier.set(null as String?)
configurations = listOf(project.configurations.runtimeClasspath.get())
exclude("META-INF/maven/**")
exclude("META-INF/upgrade/**")
exclude("META-INF/versions/19/**")
// org.antlr.v4.runtime.misc.RuleDependencyProcessor
exclude("META-INF/services/javax.annotation.processing.Processor")
exclude("module-info.*")
for ((from, to) in relocations) {
relocate(from, to)
}
// necessary for service files to be adapted to relocation
mergeServiceFiles()
}
// workaround for https://github.com/johnrengelman/shadow/issues/651
components.withType(AdhocComponentWithVariants::class.java).forEach { c ->
c.withVariantsFromConfiguration(project.configurations.shadowRuntimeElements.get()) {
skip()
}
}
val testFatJar by tasks.registering(Test::class) {
testClassesDirs = files(tasks.test.get().testClassesDirs)
classpath =
// compiled test classes
sourceSets.test.get().output +
// fat Jar
tasks.shadowJar.get().outputs.files +
// test-only dependencies
// (test dependencies that are also main dependencies must already be contained in fat Jar;
// to verify that, we don't want to include them here)
(configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get())
}
tasks.check {
dependsOn(testFatJar)
}
val validateFatJar by tasks.registering {
val outputFile = file("$buildDir/validateFatJar/result.txt")
inputs.files(tasks.shadowJar)
inputs.property("nonRelocations", nonRelocations)
outputs.file(outputFile)
doLast {
val unshadowedFiles = mutableListOf<String>()
zipTree(tasks.shadowJar.get().outputs.files.singleFile).visit {
val fileDetails = this
val path = fileDetails.relativePath.pathString
if (!(fileDetails.isDirectory ||
path.startsWith("org/pkl/") ||
path.startsWith("META-INF/") ||
nonRelocations.any { path.startsWith(it) })) {
// don't throw exception inside `visit`
// as this gives a misleading "Could not expand ZIP" error message
unshadowedFiles.add(path)
}
}
if (unshadowedFiles.isEmpty()) {
outputFile.writeText("SUCCESS")
} else {
outputFile.writeText("FAILURE")
throw GradleException("Found unshadowed files:\n" + unshadowedFiles.joinToString("\n"))
}
}
}
tasks.check {
dependsOn(validateFatJar)
}
val resolveSourcesJars by tasks.registering(ResolveSourcesJars::class) {
configuration.set(configurations.runtimeClasspath)
outputDir.set(project.file("$buildDir/resolveSourcesJars"))
}
val fatSourcesJar by tasks.registering(MergeSourcesJars::class) {
plugins.withId("pklJavaLibrary") {
inputJars.from(tasks.named("sourcesJar"))
}
inputJars.from(firstPartySourcesJarsConfiguration)
inputJars.from(resolveSourcesJars.map { fileTree(it.outputDir) })
mergedBinaryJars.from(tasks.shadowJar)
relocatedPackages.set(relocations)
outputJar.fileProvider(provider {
file(tasks.shadowJar.get().archiveFile.get().asFile.path.replace(".jar", "-sources.jar"))
})
}
artifacts {
add("fatJar", tasks.shadowJar)
}
publishing {
publications {
named<MavenPublication>("fatJar") {
project.shadow.component(this)
// sources Jar is fat
artifact(fatSourcesJar.flatMap { it.outputJar.asFile }) {
classifier = "sources"
}
plugins.withId("pklJavaLibrary") {
val javadocJar by tasks.existing(Jar::class)
// Javadoc Jar is not fat (didn't invest effort)
artifact(javadocJar.flatMap { it.archiveFile }) {
classifier = "javadoc"
}
}
}
}
}

View File

@@ -0,0 +1,85 @@
import java.nio.file.*
import java.util.UUID
import de.undercouch.gradle.tasks.download.Download
import de.undercouch.gradle.tasks.download.Verify
plugins {
id("de.undercouch.download")
}
val buildInfo = project.extensions.getByType<BuildInfo>()
val homeDir = buildInfo.graalVm.homeDir
val baseName = buildInfo.graalVm.baseName
val installDir = buildInfo.graalVm.installDir
val downloadUrl = buildInfo.graalVm.downloadUrl
val downloadFile = file(homeDir).resolve("$baseName.tar.gz")
// tries to minimize chance of corruption by download-to-temp-file-and-move
val downloadGraalVm by tasks.registering(Download::class) {
onlyIf {
!installDir.exists()
}
src(downloadUrl)
dest(downloadFile)
overwrite(false)
tempAndMove(true)
}
val verifyGraalVm by tasks.registering(Verify::class) {
onlyIf {
!installDir.exists()
}
dependsOn(downloadGraalVm)
src(downloadFile)
checksum(buildInfo.libs.findVersion("graalVmSha256-${buildInfo.graalVm.osName}-${buildInfo.graalVm.arch}").get().toString())
algorithm("SHA-256")
}
// minimize chance of corruption by extract-to-random-dir-and-flip-symlink
val installGraalVm by tasks.registering {
dependsOn(verifyGraalVm)
onlyIf {
!installDir.exists()
}
doLast {
val distroDir = "$homeDir/${UUID.randomUUID()}"
try {
mkdir(distroDir)
println("Extracting $downloadFile into $distroDir")
// faster and more reliable than Gradle's `copy { from tarTree() }`
exec {
workingDir = file(distroDir)
executable = "tar"
args("--strip-components=1", "-xzf", downloadFile)
}
val distroBinDir = if (buildInfo.os.isMacOsX) "$distroDir/Contents/Home/bin" else "$distroDir/bin"
println("Installing native-image into $distroDir")
exec {
executable = "$distroBinDir/gu"
args("install", "--no-progress", "native-image")
}
println("Creating symlink $installDir for $distroDir")
val tempLink = Paths.get("$homeDir/${UUID.randomUUID()}")
Files.createSymbolicLink(tempLink, Paths.get(distroDir))
try {
Files.move(tempLink, installDir.toPath(), StandardCopyOption.ATOMIC_MOVE)
} catch (e: Exception) {
try { delete(tempLink.toFile()) } catch (ignored: Exception) {}
throw e
}
} catch (e: Exception) {
try { delete(distroDir) } catch (ignored: Exception) {}
throw e
}
}
}

View File

@@ -0,0 +1,103 @@
/**
* Allows to run Gradle plugin tests against different Gradle versions.
*
* Adds a `compatibilityTestX` task for every Gradle version X
* between `ext.minSupportedGradleVersion` and `ext.maxSupportedGradleVersion`
* that is not in `ext.gradleVersionsExcludedFromTesting`.
* The list of available Gradle versions is obtained from services.gradle.org.
* Adds lifecycle tasks to test against multiple Gradle versions at once, for example all Gradle release versions.
* Compatibility test tasks run the same tests and use the same task configuration as the project's `test` task.
* They set system properties for the Gradle version and distribution URL to be used.
* These properties are consumed by the `AbstractTest` class.
*/
plugins {
java
}
val gradlePluginTests = extensions.create<GradlePluginTests>("gradlePluginTests")
tasks.addRule("Pattern: compatibilityTest[All|Releases|Latest|Candidate|Nightly|<GradleVersion>]") {
val taskName = this
val matchResult = Regex("compatibilityTest(.+)").matchEntire(taskName) ?: return@addRule
when (val taskNameSuffix = matchResult.groupValues[1]) {
"All" ->
task("compatibilityTestAll") {
dependsOn("compatibilityTestReleases", "compatibilityTestCandidate", "compatibilityTestNightly")
}
// releases in configured range
"Releases" ->
task("compatibilityTestReleases") {
val versionInfos = GradleVersionInfo.fetchReleases()
val versionsToTestAgainst = versionInfos.filter { versionInfo ->
val v = versionInfo.gradleVersion
!versionInfo.broken &&
v in gradlePluginTests.minGradleVersion..gradlePluginTests.maxGradleVersion &&
v !in gradlePluginTests.skippedGradleVersions
}
dependsOn(versionsToTestAgainst.map { createCompatibilityTestTask(it) })
}
// latest release (if not developing against latest)
"Latest" ->
task("compatibilityTestLatest") {
val versionInfo = GradleVersionInfo.fetchCurrent()
if (versionInfo.version == gradle.gradleVersion) {
doLast {
println("No new Gradle release available. " +
"(Run `gradlew test` to test against ${versionInfo.version}.)")
}
} else {
dependsOn(createCompatibilityTestTask(versionInfo))
}
}
// active release candidate (if any)
"Candidate" ->
task("compatibilityTestCandidate") {
val versionInfo = GradleVersionInfo.fetchRc()
if (versionInfo?.activeRc == true) {
dependsOn(createCompatibilityTestTask(versionInfo))
} else {
doLast {
println("No active Gradle release candidate available.")
}
}
}
// latest nightly
"Nightly" ->
task("compatibilityTestNightly") {
val versionInfo = GradleVersionInfo.fetchNightly()
dependsOn(createCompatibilityTestTask(versionInfo))
}
// explicit version
else ->
createCompatibilityTestTask(
taskNameSuffix,
"https://services.gradle.org/distributions-snapshots/gradle-$taskNameSuffix-bin.zip"
)
}
}
fun createCompatibilityTestTask(versionInfo: GradleVersionInfo): Task =
createCompatibilityTestTask(versionInfo.version, versionInfo.downloadUrl)
fun createCompatibilityTestTask(version: String, downloadUrl: String): Task {
return tasks.create("compatibilityTest$version", Test::class.java) {
mustRunAfter(tasks.test)
maxHeapSize = tasks.test.get().maxHeapSize
jvmArgs = tasks.test.get().jvmArgs
classpath = tasks.test.get().classpath
systemProperty("testGradleVersion", version)
systemProperty("testGradleDistributionUrl", downloadUrl)
doFirst {
if (version == gradle.gradleVersion && gradle.taskGraph.hasTask(tasks.test.get())) {
// don't test same version twice
println("This version has already been tested by the `test` task.")
throw StopExecutionException()
}
}
}
}

View File

@@ -0,0 +1,58 @@
plugins {
base
}
val htmlValidator = extensions.create<HtmlValidator>("htmlValidator", project)
val buildInfo = project.extensions.getByType<BuildInfo>()
val validatorConfiguration: Configuration = configurations.create("validator") {
resolutionStrategy.eachDependency {
if (requested.group == "log4j" && requested.name == "log4j") {
@Suppress("UnstableApiUsage")
useTarget(buildInfo.libs.findLibrary("log4j12Api").get())
because("mitigate critical security vulnerabilities")
}
}
}
dependencies {
@Suppress("UnstableApiUsage")
validatorConfiguration(buildInfo.libs.findLibrary("nuValidator").get()) {
// we only want jetty-util and jetty-util-ajax (with the right version)
// couldn't find a more robust way to express this
exclude(group = "org.eclipse.jetty", module = "jetty-continuation")
exclude(group = "org.eclipse.jetty", module = "jetty-http")
exclude(group = "org.eclipse.jetty", module = "jetty-io")
exclude(group = "org.eclipse.jetty", module = "jetty-security")
exclude(group = "org.eclipse.jetty", module = "jetty-server")
exclude(group = "org.eclipse.jetty", module = "jetty-servlets")
exclude(group = "javax.servlet")
exclude(group = "commons-fileupload")
}
}
val validateHtml by tasks.registering(JavaExec::class) {
val resultFile = file("$buildDir/validateHtml/result.txt")
inputs.files(htmlValidator.sources)
outputs.file(resultFile)
classpath = validatorConfiguration
mainClass.set("nu.validator.client.SimpleCommandLineValidator")
args("--skip-non-html") // --also-check-css doesn't work (still checks css as html), so limit to html files
args("--filterpattern", "(.*)Consider adding “lang=(.*)")
args("--filterpattern", "(.*)Consider adding a “lang” attribute(.*)")
args("--filterpattern", "(.*)unrecognized media “amzn-kf8”(.*)") // kindle
// for debugging
// args "--verbose"
args(htmlValidator.sources)
// write a basic result file s.t. gradle can consider task up-to-date
// writing a result file in case validation fails is not easily possible with JavaExec, but also not strictly necessary
doFirst { project.delete(resultFile) }
doLast { resultFile.writeText("Success.") }
}
tasks.check {
dependsOn(validateHtml)
}

View File

@@ -0,0 +1,59 @@
@file:Suppress("HttpUrlsUsage")
plugins {
`java-library`
id("pklKotlinTest")
id("com.diffplug.spotless")
}
// make sources Jar available to other subprojects
val sourcesJarConfiguration = configurations.register("sourcesJar")
java {
withSourcesJar() // creates `sourcesJar` task
withJavadocJar()
}
artifacts {
// make sources Jar available to other subprojects
add("sourcesJar", tasks["sourcesJar"])
}
spotless {
java {
googleJavaFormat("1.15.0")
targetExclude("**/generated/**", "**/build/**")
licenseHeaderFile(rootProject.file("buildSrc/src/main/resources/license-header.star-block.txt"))
}
}
tasks.compileKotlin {
enabled = false
}
tasks.jar {
manifest {
attributes += mapOf("Automatic-Module-Name" to "org.${project.name.replace("-", ".")}")
}
}
tasks.javadoc {
classpath = sourceSets.main.get().output + sourceSets.main.get().compileClasspath
source = sourceSets.main.get().allJava
title = "${project.name} ${project.version} API"
(options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet")
}
val workAroundKotlinGradlePluginBug by tasks.registering {
doLast {
// Works around this problem, which sporadically appears and disappears in different subprojects:
// A problem was found with the configuration of task ':pkl-executor:compileJava' (type 'JavaCompile').
// > Directory '[...]/pkl/pkl-executor/build/classes/kotlin/main'
// specified for property 'compileKotlinOutputClasses' does not exist.
file("$buildDir/classes/kotlin/main").mkdirs()
}
}
tasks.compileJava {
dependsOn(workAroundKotlinGradlePluginBug)
}

View File

@@ -0,0 +1,28 @@
plugins {
id("pklJavaLibrary")
kotlin("jvm")
}
val buildInfo = project.extensions.getByType<BuildInfo>()
dependencies {
// At least some of our kotlin APIs contain Kotlin stdlib types
// that aren't compiled away by kotlinc (e.g., `kotlin.Function`).
// So let's be conservative and default to `api` for now.
// For Kotlin APIs that only target Kotlin users (e.g., pkl-config-kotlin),
// it won't make a difference.
api(buildInfo.libs.findLibrary("kotlinStdLib").get())
}
tasks.compileKotlin {
enabled = true // disabled by pklJavaLibrary
}
spotless {
kotlin {
ktfmt("0.44").googleStyle()
targetExclude("**/generated/**", "**/build/**")
licenseHeaderFile(rootProject.file("buildSrc/src/main/resources/license-header.star-block.txt"))
}
}

View File

@@ -0,0 +1,57 @@
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import java.net.URI
plugins {
kotlin("jvm")
}
val buildInfo = project.extensions.getByType<BuildInfo>()
dependencies {
testImplementation(buildInfo.libs.findLibrary("assertj").get())
testImplementation(buildInfo.libs.findLibrary("junitApi").get())
testImplementation(buildInfo.libs.findLibrary("junitParams").get())
testImplementation(buildInfo.libs.findLibrary("kotlinStdLib").get())
testRuntimeOnly(buildInfo.libs.findLibrary("junitEngine").get())
}
tasks.withType<Test>().configureEach {
val testTask = this
useJUnitPlatform()
// enable checking of stdlib return types
systemProperty("org.pkl.testMode", "true")
reports.named("html") {
enabled = true
}
testLogging {
exceptionFormat = TestExceptionFormat.FULL
}
addTestListener(object : TestListener {
override fun beforeSuite(suite: TestDescriptor) {}
override fun beforeTest(testDescriptor: TestDescriptor) {}
override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) {}
// print report link at end of task, not just at end of build
override fun afterSuite(descriptor: TestDescriptor, result: TestResult) {
if (descriptor.parent != null) return // only interested in overall result
if (result.resultType == TestResult.ResultType.FAILURE) {
println("\nThere were failing tests. See the report at: ${fixFileUri(testTask.reports.html.entryPoint.toURI())}")
}
}
// makes links clickable on macOS
private fun fixFileUri(uri: URI): URI {
if ("file" == uri.scheme && !uri.schemeSpecificPart.startsWith("//")) {
return URI.create("file://" + uri.schemeSpecificPart)
}
return uri
}
})
}

View File

@@ -0,0 +1,7 @@
val assembleNative by tasks.registering {}
val checkNative by tasks.registering {}
val buildNative by tasks.registering {
dependsOn(assembleNative, checkNative)
}

View File

@@ -0,0 +1,118 @@
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
import java.nio.charset.StandardCharsets
import java.util.Base64
plugins {
`maven-publish`
signing
}
publishing {
publications {
components.findByName("java")?.let { javaComponent ->
create<MavenPublication>("library") {
from(javaComponent)
}
}
withType<MavenPublication>().configureEach {
pom {
name.set(artifactId)
licenses {
license {
name.set("The Apache Software License, Version 2.0")
url.set("https://github.com/apple/pkl/blob/main/LICENSE.txt")
}
}
developers {
developer {
id.set("pkl-authors")
name.set("The Pkl Authors")
email.set("pkl-oss@group.apple.com")
}
}
scm {
connection.set("scm:git:git://github.com/apple/pkl.git")
developerConnection.set("scm:git:ssh://github.com/apple/pkl.git")
val buildInfo = project.extensions.getByType<BuildInfo>()
url.set("https://github.com/apple/pkl/tree/${buildInfo.commitish}")
}
issueManagement {
system.set("GitHub Issues")
url.set("https://github.com/apple/pkl/issues")
}
ciManagement {
system.set("Circle CI")
url.set("https://app.circleci.com/pipelines/github/apple/pkl")
}
}
}
}
}
val validatePom by tasks.registering {
val generatePomFileForLibraryPublication by tasks.existing(GenerateMavenPom::class)
val outputFile = file("$buildDir/validatePom") // dummy output to satisfy up-to-date check
dependsOn(generatePomFileForLibraryPublication)
inputs.file(generatePomFileForLibraryPublication.get().destination)
outputs.file(outputFile)
doLast {
outputFile.delete()
val pomFile = generatePomFileForLibraryPublication.get().destination
assert(pomFile.exists())
val text = pomFile.readText()
run {
val unresolvedVersion = Regex("<version>.*[+,()\\[\\]].*</version>")
val matches = unresolvedVersion.findAll(text).toList()
if (matches.isNotEmpty()) {
throw GradleException(
"""
Found unresolved version selector(s) in generated POM:
${matches.joinToString("\n") { it.groupValues[0] }}
""".trimIndent()
)
}
}
val buildInfo = project.extensions.getByType<BuildInfo>()
if (buildInfo.isReleaseBuild) {
val snapshotVersion = Regex("<version>.*-SNAPSHOT</version>")
val matches = snapshotVersion.findAll(text).toList()
if (matches.isNotEmpty()) {
throw GradleException(
"""
Found snapshot version(s) in generated POM of Pkl release version:
${matches.joinToString("\n") { it.groupValues[0] }}
""".trimIndent()
)
}
}
outputFile.writeText("OK")
}
}
tasks.publish {
dependsOn(validatePom)
}
signing {
// provided as env vars `ORG_GRADLE_PROJECT_signingKey` and `ORG_GRADLE_PROJECT_signingPassword`
// in CI.
val signingKey = (findProperty("signingKey") as String?)
?.let { Base64.getDecoder().decode(it).toString(StandardCharsets.US_ASCII) }
val signingPassword = findProperty("signingPassword") as String?
if (signingKey != null && signingPassword != null) {
useInMemoryPgpKeys(signingKey, signingPassword)
}
publishing.publications.findByName("library")?.let { sign(it) }
}
artifacts {
project.tasks.findByName("javadocJar")?.let { archives(it) }
project.tasks.findByName("sourcesJar")?.let { archives(it) }
}

View File

@@ -0,0 +1,16 @@
//===----------------------------------------------------------------------===//
// Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//

View File

@@ -0,0 +1,15 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

6
docs/antora.yml Normal file
View File

@@ -0,0 +1,6 @@
name: main
title: Main Project
version: 0.25.0-dev
prerelease: true
nav:
- nav.adoc

35
docs/docs.gradle.kts Normal file
View File

@@ -0,0 +1,35 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
plugins {
pklAllProjects
pklKotlinTest
}
sourceSets {
test {
java {
srcDir(file("modules/pkl-core/examples"))
srcDir(file("modules/pkl-config-java/examples"))
}
val kotlin = project.extensions
.getByType<KotlinJvmProjectExtension>()
.sourceSets[name]
.kotlin
kotlin.srcDir(file("modules/pkl-config-kotlin/examples"))
}
}
dependencies {
testImplementation(project(":pkl-core"))
testImplementation(project(":pkl-config-java"))
testImplementation(project(":pkl-config-kotlin"))
testImplementation(project(":pkl-commons-test"))
testImplementation(libs.junitEngine)
testImplementation(libs.antlrRuntime)
}
tasks.test {
inputs.files(fileTree("modules").matching {
include("**/pages/*.adoc")
})
}

36
docs/gradle.lockfile Normal file
View File

@@ -0,0 +1,36 @@
# 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.
com.tunnelvisionlabs:antlr4-runtime:4.9.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.leangen.geantyref:geantyref:1.3.14=testRuntimeClasspath
net.bytebuddy:byte-buddy:1.12.21=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.24.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.sdk:graal-sdk:22.3.1=testRuntimeClasspath
org.graalvm.truffle:truffle-api:22.3.1=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,testRuntimeClasspath
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.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-engine:5.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.jupiter:junit-jupiter-params:5.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit.platform:junit-platform-engine:1.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.junit:junit-bom:5.9.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath,testRuntimeOnlyDependenciesMetadata
org.organicdesign:Paguro:3.10.3=testRuntimeClasspath
org.snakeyaml:snakeyaml-engine:2.5=testRuntimeClasspath
empty=annotationProcessor,apiDependenciesMetadata,archives,compile,compileClasspath,compileOnly,compileOnlyDependenciesMetadata,default,implementationDependenciesMetadata,intransitiveDependenciesMetadata,kotlinCompilerPluginClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,runtime,runtimeClasspath,runtimeOnlyDependenciesMetadata,testAnnotationProcessor,testApiDependenciesMetadata,testCompile,testCompileOnly,testCompileOnlyDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions,testRuntime

View File

@@ -0,0 +1,8 @@
= Community
:uri-github-issue: https://github.com/apple/pkl/issues
:uri-github-discussions: https://github.com/apple/pkl/discussions
We'd love to hear from you!
* Create an {uri-github-issue}[issue]
* Ask questions on {uri-github-discussions}[GitHub Discussions]

View File

@@ -0,0 +1,14 @@
= Examples
:uri-github-apple: https://github.com/apple
:uri-jvm-examples: {uri-github-apple}/pkl-jvm-examples
:uri-go-examples: {uri-github-apple}/pkl-go-examples
:uri-swift-examples: {uri-github-apple}/pkl-swift-examples
:uri-k8s-examples: {uri-github-apple}/pkl-k8s-examples
For ready-to-go examples with full source code, see the various repositories that are available for you.
* {uri-jvm-examples}[pkl-jvm-examples] -- for using Pkl within the JVM
* {uri-swift-examples}[pkl-swift-examples] -- for using Pkl with Swift
* {uri-go-examples}[pkl-go-examples] -- for using Pkl with Go
* {uri-k8s-examples}[pkl-k8s-examples] -- for using Pkl with Kubernetes

View File

@@ -0,0 +1,15 @@
= User Manual
include::../partials/component-attributes.adoc[]
Quick Links: xref:pkl-cli:index.adoc#installation[Installation] | xref:language-reference:index.adoc[Language Reference]
Pkl -- pronounced _Pickle_ -- is an embeddable configuration language which provides rich support for data templating and validation.
It can be used from the command line, integrated in a build pipeline, or embedded in a program.
Pkl scales from small to large, simple to complex, ad-hoc to repetitive configuration tasks.
xref:introduction:index.adoc[Introduction]:: Why we created Pkl and what it can do for you.
xref:language.adoc[Language]:: Get to know the language and standard library.
xref:language-bindings.adoc[Bindings]:: Libraries for embedding Pkl into general-purpose languages.
xref:tools.adoc[Tools]:: CLI, Gradle plugin, code generators, and other tools.
link:{uri-pkl-examples-repo}[Examples]:: Ready-to-go examples with full source code.
xref:release-notes:index.adoc[Release Notes]:: What's new in each release.

View File

@@ -0,0 +1,3 @@
= Framework Integrations
* xref:spring:ROOT:index.adoc[Spring (Boot) Integration]

View File

@@ -0,0 +1,6 @@
= Language Bindings
* xref:java-binding:index.adoc[Java]
* xref:kotlin-binding:index.adoc[Kotlin]
* xref:swift:ROOT:index.adoc[Swift]
* xref:go:ROOT:index.adoc[Go]

View File

@@ -0,0 +1,5 @@
= Language
* xref:language-tutorial:index.adoc[Tutorial]
* xref:language-reference:index.adoc[Language Reference]
* xref:standard-library.adoc[Standard Library]

View File

@@ -0,0 +1,7 @@
= Resources
include::../partials/component-attributes.adoc[]
There's more to explore!
* Visit Pkl's repositories on https://github.com/apple?q=pkl[GitHub]
* Browse the standard library's https://pkl-lang.org/package-docs/pkl/{pkl-version}/[API Docs]

View File

@@ -0,0 +1,13 @@
= Standard Library
include::../partials/component-attributes.adoc[]
The standard library is a set of Pkl modules, versioned and distributed together with the language.
It is documented in the link:{uri-pkl-stdlib-docs-index}[API Docs].
To import a standard library module, use `import "pkl:<identifier>"`.
For example, `import "pkl:json"` imports the `pkl.json` module.
The `pkl.base` module defines the most fundamental properties, methods, and classes for using Pkl.
Its members are automatically available in every module and hence, it does not need to be imported.
The default module allowlist (`--allowed-modules`) grants access to all standard library modules.

View File

@@ -0,0 +1,10 @@
= Tools
include::ROOT:partial$component-attributes.adoc[]
* xref:pkl-cli:index.adoc[CLI]
* xref:pkl-doc:index.adoc[Pkldoc]
* xref:pkl-gradle:index.adoc[Gradle Plugin]
* Editor support
** xref:intellij:ROOT:index.adoc[IntelliJ]
** xref:vscode:ROOT:index.adoc[VSCode]
** xref:neovim:ROOT:index.adoc[Neovim]

View File

@@ -0,0 +1,64 @@
// TODO: move to antora.yml once supported
// 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-no-suffix: 0.25.0
// tells whether pkl version corresponding to current git commit
// is a release version (:is-release-version: '') or dev version (:!is-release-version:)
:!is-release-version:
// the remaining attributes do not need to be updated regularly
:pkl-version: {pkl-version-no-suffix}-dev
ifdef::is-release-version[]
:pkl-version: {pkl-version-no-suffix}
endif::[]
// use non-unique snapshot version because we have no way to determine unique snapshot version here
:pkl-artifact-version: {pkl-version-no-suffix}-SNAPSHOT
ifdef::is-release-version[]
:pkl-artifact-version: {pkl-version}
endif::[]
:uri-maven-docsite: https://central.sonatype.com/
:uri-sonatype: https://s01.oss.sonatype.org/service/local/repositories/snapshots/content/
:symbolic-version-name: latest
ifdef::is-release-version[]
:symbolic-version-name: current
endif::[]
:uri-pkl-docs-base: https://pkl-lang.org/package-docs
:uri-pkl-stdlib-docs-base: {uri-pkl-docs-base}/pkl
:uri-pkl-stdlib-docs: {uri-pkl-stdlib-docs-base}/{pkl-version}
:uri-pkl-stdlib-docs-index: {uri-pkl-stdlib-docs}/
// TODO(oss): check these links when we have tags
:github-branch: main
ifdef::is-release-version[]
:github-branch: v{pkl-version-no-suffix}
endif::[]
:uri-github-tree: https://github.com/apple/pkl/tree/{github-branch}
:uri-pkl-stdlib-sources: {uri-github-tree}/stdlib
:github-releases-base: https://github.com/apple/pkl/releases
:github-releases: {github-releases-base}/download/{pkl-artifact-version}
:uri-pkl-core-main-sources: {uri-github-tree}/pkl-core/src/main/java/org/pkl/core
:uri-pkl-cli-main-sources: {uri-github-tree}/pkl-cli/src/main/kotlin/org/pkl/cli
:uri-pkl-doc-main-sources: {uri-github-tree}/pkl-doc/src/main/kotlin/org/pkl/doc
// This attribute is used as language for Pkl code blocks.
// It can then be mapped to different languages in different environments (e.g., IntelliJ vs. Antora).
:pkl: pkl
:pkl-expr: pkl expression
:uri-pkl-examples-repo: https://github.com/apple/pkl-jvm-examples
:uri-pkl-examples-tree: {uri-pkl-examples-repo}/tree/main
:uri-build-eval-example: {uri-pkl-examples-tree}/build-eval
:uri-codegen-java-example: {uri-pkl-examples-tree}/codegen-java
:uri-codegen-kotlin-example: {uri-pkl-examples-tree}/codegen-kotlin
:uri-config-java-example: {uri-pkl-examples-tree}/config-java
:uri-config-kotlin-example: {uri-pkl-examples-tree}/config-kotlin
:uri-pkldoc-example: {uri-pkl-examples-tree}/pkldoc

View File

@@ -0,0 +1,93 @@
= Comparison
include::ROOT:partial$component-attributes.adoc[]
:uri-jsonnet: https://jsonnet.org
:uri-hcl: https://github.com/hashicorp/hcl
:uri-dhall: https://dhall-lang.org
:uri-pkl-spring: https://github.com/apple/pkl-spring
:uri-graalvm: https://www.graalvm.org
Configuration is often described in a static configuration format or is generated with a general-purpose programming language.
This page lists shortcomings of these approaches and explains how Pkl addresses them.
Also, Pkl's strong and weak points in comparison to other configuration languages are discussed in this document.
[[static-config-formats]]
== Pkl vs. Static Config Formats
Static configuration formats such as JSON, YAML, and XML work reasonably well for simple configuration needs.
However, they do have some shortcomings, including:
. They are not very human-friendly to read and write. (JSON, XML)
. They do not provide a way to split a large file into multiple smaller ones. (JSON, YAML)
. They offer no way or very limited ways to abstract over repetitive configuration. (JSON, YAML, XML)
. They do not offer standardized or widely available schema validators. (JSON, YAML)
. They offer little or no schema-aware tooling. (JSON, YAML)
Pkl addresses these shortcomings as follows:
. It has a clutter-free and familiar syntax with nestable comments.
. Modules can import other modules from local and remote locations.
. Every object can act as a template for other objects.
The standard library offers strong support for data manipulation.
. It has strong built-in support for describing and validating configuration schemas.
. It is designed to enable schema-aware tooling, such as REPLs and editors with code completion support.
[[general-purpose-langs]]
== Pkl vs. General-purpose Languages
When configuration needs outgrow the capabilities of static configuration formats,
projects often turn to generate configuration with a general-purpose programming language such as Python.
Given enough effort, this approach can satisfy complex configuration needs.
However, expressing configuration in a full-blown programming language does have some shortcomings, including:
. Reading, writing, and debugging configuration can become as challenging as reading, writing, and debugging application code.
. The host language may not be a good fit for describing, manipulating, and abstracting over hierarchical configuration.
. Configuration code may not visually resemble the configuration it generates.
. The host language may not be a good fit for defining and validating configuration schemas.
. Development environments may offer little help for developing and validating configuration written in the host language.
. General-purpose languages are powerful and often difficult to sandbox.
Are you certain your configuration script isn't erasing your hard disk or launching a rocket?
Pkl addresses these shortcomings as follows:
. As an expression-oriented and side-effect free language, it eliminates many potential sources of errors.
. It is specifically designed for describing, manipulating, and abstracting over hierarchical configuration.
. Pkl code often resembles the configuration it generates.
. It has strong built-in support for defining and validating configuration schemas.
. It is designed to enable advanced and schema-aware tooling.
. It is comparatively powerless and strictly sandboxed, making fatal configuration mistakes and exploits less likely.
Till now, we haven't spotted any Pkl script capable of erasing your hard disk.
[[other-config-langs]]
== Pkl vs. Other Config Languages
Compared to open-source configuration languages such as link:{uri-jsonnet}[Jsonnet],
link:{uri-hcl}[HCL], and link:{uri-dhall}[Dhall], Pkl's strong points are:
General::
+
* Pkl has a clean and familiar syntax, which makes it easier to read and learn.
* Pkl supports writing sophisticated schemas, which enables config validation, code and documentation generation, and advanced IDE support.
This is Pkl's most significant differentiator, and is the main reason why we created it.
* Pkl has stronger templating capabilities than other config languages, reducing user code to the absolute minimum.
Embedding::
+
* Pkl is great for embedding into JVM applications.
* Pkl offers modern xref:java-binding:pkl-config-java.adoc[JVM libraries] for runtime application configuration.
* Pkl supports xref:java-binding:codegen.adoc[code generation] to enable statically typed access to configuration from programming languages.
* Pkl integrates with third-party (link:{uri-pkl-spring}[Spring Boot]) JVM libraries and frameworks.
Tooling::
+
* Pkl has a polished xref:pkl-doc:index.adoc[documentation generator] that produces highly navigable and searchable documentation.
* Pkl offers a xref:pkl-gradle:index.adoc[Gradle plugin] to easily integrate code evaluation, documentation generation, and code generation into your builds.
* Pkl's native executables have a link:{uri-graalvm}[JIT compiler] that can speed up evaluation up to hundred times.
On the other hand, we believe that Pkl's weak points are:
* Pkl's native binaries are larger than those of other config languages.
* Pkl is less known and has a smaller community than some other config languages.
We are working towards making Pkl overcome these weakness. Please support us in reaching this goal!
We hope that you will enjoy Pkl, and that you trust us to gradually improve its weak points.

View File

@@ -0,0 +1,97 @@
= Concepts
include::ROOT:partial$component-attributes.adoc[]
:uri-property-list: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/PropertyLists/UnderstandXMLPlist/UnderstandXMLPlist.html
Let's get to know Pkl by discussing some of its concepts and features.
[[abstraction]]
== Abstraction
Configuration tends to grow larger and more complex over time, making it increasingly difficult to understand and maintain.
Pkl can reduce the size and complexity of configuration by
* describing similar configuration elements in terms of their differences
* introducing abstractions for common configuration elements
* separating configuration structure from configuration data
* computing instead of enumerating configuration
[[evaluation]]
== Evaluation
Pkl code lives in _modules_, a more fancy and general term for _files_.
Evaluating a module produces an in-memory _data model_ that is roughly comparable to a JSON data model.
If evaluation completes successfully, the Pkl evaluator converts the data model to an external representation and terminates with the status code zero.
Otherwise, the evaluator prints an error message and terminates with a non-zero status code.
[[immutability]]
== Immutability
All Pkl data is immutable.
Manipulating a value always returns a new value, leaving the original value unchanged.
Immutability eliminates many potential sources of errors.
[[isolation]]
== Isolation
Evaluation of Pkl code is strictly sandboxed.
Except for a few well-defined and well-controlled exceptions, Pkl code cannot interact with the outside world.
Leaving aside bugs in the language implementation, the worst thing that buggy or malicious Pkl code can do is to consume CPU and memory resources until the evaluator gets killed.
Over time, sandboxing will be further strengthened to cover fine-grained CPU and memory boxing.
[[rendering]]
== Rendering
Converting a data model to an external representation is called _rendering_ the model.
Pkl ships with renderers for the following data formats:
* JSON
* Jsonnet
* Pcf (a static subset of Pkl)
* (Java) Properties
* {uri-property-list}[Property List]
* XML
* YAML
Support for other formats can be added by writing a custom renderer in Pkl or Java.
See xref:language-reference:index.adoc#module-output[Module Output] and xref:pkl-core:index.adoc#value-visitor[Value Visitor] for more information.
[[resemblance]]
== Resemblance
By design, Pkl code tends to structurally and visually resemble the configuration it generates.
This makes the code easier to read and write.
[[reuse]]
== Reuse
Modules can reuse other modules by xref:language-reference:index.adoc#import-module[importing] them from local or remote locations.
Imports can also be used to split up one large module into multiple smaller ones, increasing maintainability.
A configurable security policy helps to keep imports under control.
[[schema]]
== Schema
Configuration is structured data.
Pkl supports -- but does not require -- to express this structure as a _configuration schema_, a set of classes defining configuration properties, their defaults, types, and constraints.
Writing and maintaining a configuration schema takes some effort but, in return, provides these benefits:
* Independent evolution of configuration schema and configuration data, often by different teams (for example service providers and service consumers).
* Automatic xref:pkl-doc:index.adoc[documentation generation].
* Strong validation of configuration, both during development time and runtime.
* Statically typed access to configuration from xref:java-binding:codegen.adoc[Java] and other languages through code generation.
* Schema-aware development tools, for example REPLs and editors with code completion support.
[[template]]
== Templating
Pkl supports writing templates for objects and entire modules.
Templates can be repeatedly turned into concrete configuration by filling in the blanks, and -- when necessary -- overriding defaults.
Sharing template modules over the network can streamline complex configuration tasks for entire teams, organizations, and communities.
[[usability]]
== Usability
Everybody needs a configuration solution, but nobody wants to spend a lot of time learning it.
To reflect this reality, Pkl has a strong focus on usability.
For example, error messages explain causes and possible solutions and object properties maintain definition order to avoid surprises.
We hope that this focus on usability will make Pkl accessible to a wide audience of occasional users, while still leaving room for expert users and advanced use cases.

View File

@@ -0,0 +1,13 @@
= Introduction
include::ROOT:partial$component-attributes.adoc[]
Pkl -- pronounced _Pickle_ -- is a configuration-as-code language with rich validation and tooling.
It can be used as a command line tool, software library, or build plugin.
Pkl scales from small to large, simple to complex, ad-hoc to recurring configuration tasks.
We created Pkl because we believe that configuration is best expressed in a special-purpose configuration language;
a blend between a static configuration format, and a general-purpose programming language.
* xref:use-cases.adoc[Use Cases]
* xref:concepts.adoc[Concepts]
* xref:comparison.adoc[Comparison]

View File

@@ -0,0 +1,35 @@
= Use Cases
include::ROOT:partial$component-attributes.adoc[]
:uri-kotlin-homepage: https://kotlinlang.org
:uri-xml-property-lists: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/PropertyLists/UnderstandXMLPlist/UnderstandXMLPlist.html
Pkl is a good fit for:
Generating Static Configuration::
Are you using a tool, service, or application that is configured with JSON, YAML, or any other static configuration format?
+
By generating this configuration with Pkl, you can reduce verbosity and increase maintainability through xref:concepts.adoc#reuse[reuse], xref:concepts.adoc#template[templating], and xref:concepts.adoc#abstraction[abstraction].
JSON, YAML, and {uri-xml-property-lists}[XML property lists] are supported out of the box; xref:concepts.adoc#rendering[renderers] for other configuration formats can be developed and shared by anyone.
Automatic defaults, strong validation, and sensible error messages come in reach with configuration xref:concepts.adoc#schema[schemas].
+
Generation can be triggered manually, by an automation pipeline, or by the target application.
Application Runtime Configuration::
Are you the author of a tool, service, or application that consumes configuration?
+
By adopting Pkl as your "native" configuration solution (rather than, say, using it to generate JSON files), you benefit from a modern xref:java-binding:pkl-config-java.adoc[configuration library] that is safe, easy, and enjoyable to use.
At the same time, anyone configuring your application -- whether that's your users, site reliability engineers (SREs), or yourself -- benefit from a well-defined, well-documented, and scalable configuration language.
+
At the time of writing, Pkl offers configuration libraries for the JVM runtime, Swift, and also for Golang.
+
We maintian the following libraries:
+
* xref:java-binding:pkl-config-java.adoc[pkl-config-java] for Java compatible languages
* xref:kotlin-binding:pkl-config-kotlin.adoc[pkl-config-kotlin] for the {uri-kotlin-homepage}[Kotlin] language.
* xref:swift:ROOT:index.adoc[pkl-swift] for the Swift language.
* xref:go:ROOT:index.adoc[pkl-go] for the Go language.
In the future, we hope to add support for other popular languages and platforms, realizing our vision of a polyglot config solution based on a single config language.
<Your Use Case Here>::
We are just getting started. Tell us about _your_ Pkl success story!

View File

@@ -0,0 +1,22 @@
import org.pkl.config.java.Config;
import org.pkl.config.java.ConfigEvaluator;
import org.pkl.config.java.JavaType;
import org.junit.jupiter.api.Test;
@SuppressWarnings("unused")
// the pkl/pkl-examples repo has a similar example
public class JavaConfigExample {
@Test
public void usage() {
// tag::usage[]
Config config;
try (var evaluator = ConfigEvaluator.preconfigured()) { // <1>
config = evaluator.evaluateText(
"pigeon { age = 5; diet = \"Seeds\" }"); // <2>
}
var pigeon = config.get("pigeon"); // <3>
var age = pigeon.get("age").as(int.class); // <4>
var diet = pigeon.get("diet").as(JavaType.listOf(String.class)); // <5>
// end::usage[]
}
}

View File

@@ -0,0 +1,180 @@
= Java Code Generator
include::ROOT:partial$component-attributes.adoc[]
:uri-pkl-codgen-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 benefits of code generation are:
* Configuration can be conveniently consumed as statically typed Java objects.
* The entire configuration tree can be code-completed in Java IDEs.
* Any drift between Java code and Pkl configuration structure is caught at compile time.
The generated classes are immutable and have component-wise implementations of `equals()`, `hashCode()`, and `toString()`.
== Installation
The code generator is offered as Gradle plugin, Java library, and CLI.
=== Gradle Plugin
See xref:pkl-gradle:index.adoc#installation[Installation] in the Gradle plugin chapter.
[[install-library]]
=== Java Library
The `pkl-codegen-java` library is available {uri-pkl-codgen-java-maven-module}[from Maven Central].
It requires Java 11 or higher.
ifndef::is-release-version[]
NOTE: Snapshots are published to repository `{uri-sonatype}`.
endif::[]
==== Gradle
To use the library in a Gradle project, declare the following dependency:
[tabs]
====
Groovy::
+
.build.gradle
[source,groovy,subs="+attributes"]
----
dependencies {
compile "org.pkl-lang:pkl-codegen-java:{pkl-artifact-version}"
}
ifndef::is-release-build[]
repositories {
maven { url "{uri-sonatype}" }
}
endif::[]
----
Kotlin::
+
.build.gradle.kts
[source,kotlin,subs="+attributes"]
----
dependencies {
compile("org.pkl-lang:pkl-codegen-java:{pkl-artifact-version}")
}
ifndef::is-release-build[]
repositories {
maven { url = uri("{uri-sonatype}") }
}
endif::[]
----
====
==== Maven
To use the library in a Maven project, declare the following dependency:
.pom.xml
[source,xml,subs="+attributes"]
----
<project>
<dependency>
<groupId>org.pkl-lang</groupId>
<artifactId>pkl-codegen-java</artifactId>
<version>{pkl-artifact-version}</version>
</dependency>
ifndef::is-release-build[]
<repositories>
<repository>
<id>sonatype-s01</id>
<name>Sonatype S01</name>
<url>{uri-sonatype}</url>
</repository>
</repositories>
endif::[]
</project>
----
[[install-cli]]
=== CLI
The CLI is bundled with the Java library.
As we do not currently ship the CLI as a self-contained Jar, we recommend to provision it with a Maven compatible build tool as shown in <<install-library>>.
[[codegen-java-usage]]
== Usage
The code generator is offered as Gradle plugin, Java library, and CLI.
=== Gradle Plugin
See xref:pkl-gradle:index.adoc#java-code-gen[Java Code Generation] in the Gradle plugin chapter.
=== Java Library
The Java library offers two APIs: a high-level API that corresponds to the CLI, and a lower-level API that provides additional features and control.
The entry points for these APIs are `org.pkl.codegen.java.CliJavaCodeGenerator` and `org.pkl.codegen.java.JavaCodeGenerator`, respectively.
For more information, refer to the Javadoc documentation.
=== CLI
As explained in <<install-cli,Installation>>, the CLI is bundled with the Java library.
To run the CLI, execute the library Jar or its `org.pkl.codegen.java.Main` main class.
*Synopsis:* `java -cp <classpath> -jar pkl-codegen-java.jar [<options>] <modules>`
`<modules>`::
The absolute or relative URIs of the modules to generate classes for.
Relative URIs are resolved against the working directory.
==== Options
.--generate-getters
[%collapsible]
====
Default: (flag not set) +
Flag that indicates to generate private final fields and public getter methods instead of public final fields.
====
.--generate-javadoc
[%collapsible]
====
Default: (flag not set) +
Flag that indicates to generate Javadoc based on doc comments for Pkl modules, classes, and properties.
====
.--params-annotation
[%collapsible]
====
Default: `org.pkl.config.java.mapper.Named` +
Fully qualified name of the annotation to use on constructor parameters.
====
.--non-null-annotation
[%collapsible]
====
Default: `org.pkl.config.java.mapper.NonNull` +
Fully qualified named of the annotation class to use for non-null types. +
This annotation is required to have `java.lang.annotation.ElementType.TYPE_USE` as a `@Target`
or it may generate code that does not compile.
====
.--implement-serializable
[%collapsible]
====
Default: (flag not set) +
Whether to make generated classes implement `java.io.Serializable`.
====
Common code generator options:
include::{partialsdir}/cli-codegen-options.adoc[]
Common CLI options:
include::../../pkl-cli/partials/cli-common-options.adoc[]
[[full-example]]
== Full Example
For a ready-to-go example with full source code,
see link:{uri-codegen-java-example}[codegen-java] in the _pkl/pkl-examples_ repository.

View File

@@ -0,0 +1,4 @@
= Integration with Java
Pkl provides rich integration with Java. Our integration allows you to embed the Pkl runtime into your Java program, and also provides code generation from Pkl source files.

View File

@@ -0,0 +1,212 @@
= pkl-config-java Library
include::ROOT:partial$component-attributes.adoc[]
:uri-pkl-core-EvalException: {uri-pkl-core-main-sources}/EvalException.java
:uri-pkl-config-java-maven-module: {uri-maven-docsite}/artifact/org.pkl-lang/pkl-config-java-all
:uri-pkl-config-java-main-sources: {uri-github-tree}/pkl-config-java/src/main/java/org/pkl/config/java
:uri-pkl-config-java-test-sources: {uri-github-tree}/pkl-config-java/src/test/java/org/pkl/config/java
:uri-pkl-config-java-test-resources: {uri-github-tree}/pkl-config-java/src/test/resources/org/pkl/config/java
:uri-pkl-config-java-ConfigEvaluator: {uri-pkl-config-java-main-sources}/ConfigEvaluator.java
:uri-pkl-config-java-Config: {uri-pkl-config-java-main-sources}/Config.java
:uri-pkl-config-java-ValueMapper: {uri-pkl-config-java-main-sources}/mapper/ValueMapper.java
:uri-pkl-config-java-Named: {uri-pkl-config-java-main-sources}/mapper/Named.java
:uri-pkl-config-java-Conversion: {uri-pkl-config-java-main-sources}/mapper/Conversion.java
:uri-pkl-config-java-Conversions: {uri-pkl-config-java-main-sources}/mapper/Conversions.java
:uri-pkl-config-java-ConverterFactories: {uri-pkl-config-java-main-sources}/mapper/ConverterFactories.java
:uri-pkl-config-java-Converter: {uri-pkl-config-java-main-sources}/mapper/Converter.java
:uri-pkl-config-java-ConverterFactory: {uri-pkl-config-java-main-sources}/mapper/ConverterFactory.java
:uri-pkl-config-java-PObjectToObjectByCtorTestJava: {uri-pkl-config-java-test-sources}/mapper/PObjectToObjectByCtorTest.java
:uri-pkl-config-java-PObjectToObjectByCtorTestPkl: {uri-pkl-config-java-test-resources}/mapper/PObjectToObjectByCtorTest.pkl
The _pkl-config-java_ library builds upon xref:pkl-core:index.adoc[pkl-core].
It offers a higher-level API specifically designed for consuming application runtime configuration.
== Installation
The _pkl-config-java_ library is available {uri-pkl-config-java-maven-module}[from Maven Central].
It requires Java 11 or higher.
=== Gradle
To use the library in a Gradle project, declare the following dependency:
[tabs]
====
Groovy::
+
.build.gradle
[source,groovy,subs="+attributes"]
----
dependencies {
compile "org.pkl-lang:pkl-config-java:{pkl-artifact-version}"
}
ifndef::is-release-build[]
repositories {
maven { url "{uri-sonatype}" }
}
endif::[]
----
Kotlin::
+
.build.gradle.kts
[source,kotlin,subs="+attributes"]
----
dependencies {
compile("org.pkl-lang:pkl-config-java:{pkl-artifact-version}")
}
ifndef::is-release-build[]
repositories {
maven { url = uri("{uri-sonatype}") }
}
endif::[]
----
====
Unlike `pkl-config-java`, `pkl-config-java__-all__` is a fat Jar with renamed third-party packages to avoid version conflicts.
=== Maven
To use the library in a Maven project, declare the following dependency:
.pom.xml
[source,xml,subs="+attributes"]
----
<project>
<dependency>
<groupId>org.pkl-lang</groupId>
<artifactId>pkl-config-java</artifactId>
<version>{pkl-artifact-version}</version>
</dependency>
ifndef::is-release-build[]
<repositories>
<repository>
<id>sonatype-s01</id>
<name>Sonatype S01</name>
<url>{uri-sonatype}</url>
</repository>
</repositories>
endif::[]
</project>
----
Unlike `pkl-config-java`, `pkl-config-java__-all__` is a fat Jar with renamed third-party packages to avoid version conflicts.
== Usage
=== Consuming Configuration
The {uri-pkl-config-java-ConfigEvaluator}[`ConfigEvaluator`] class loads and evaluates Pkl modules.
If evaluation succeeds, a {uri-pkl-config-java-Config}[`Config`] object is returned.
Otherwise, an {uri-pkl-core-EvalException}[`EvalException`] with error details is thrown.
The returned `Config` object represents the root of the Pkl configuration tree.
Intermediate and leaf nodes are also represented as `Config` objects.
`Config` objects offer methods to
* convert their Pkl value to a Java value of the specified type.
* navigate to child nodes.
Let's see this in action:
[[config-evaluator-java-example]]
[source,java,indent=0]
----
include::{examplesdir}/JavaConfigExample.java[tags=usage]
----
<1> Create a preconfigured `ConfigEvaluator`.
To create a customized evaluator, start from `ConfigEvaluatorBuilder.preconfigured()` or `ConfigEvaluatorBuilder.unconfigured()`.
The evaluator should be closed once it is no longer needed.
In this example, this is done with a try-with-resources statement.
Note that objects returned by the evaluator remain valid after calling `close()`.
<2> Evaluate the given text.
Other `evaluate` methods read from files, URLs, and other sources.
If evaluation fails, an {uri-pkl-core-EvalException}[`EvalException`] is thrown.
<3> Navigate from the config root to its `"pigeon"` child.
<4> Navigate from `"pigeon"` to `"age"` and get the latter's value as an `int`.
If conversion to the requested type fails, a `ConversionException` is thrown.
<5> Navigate from `"pigeon"` to `"diet"` and get the latter's value as a `List<String>`.
Note the use of `JavaType.listOf()` for creating a parameterized type literal.
Similar methods exist for sets, maps, and other generic types.
A `ConfigEvaluator` caches module sources and evaluation results.
To clear the cache, for example to evaluate the same module again, close the evaluator and create a new one.
For a ready-to-go example with full source code,
see link:{uri-config-java-example}[config-java] in the _pkl/pkl-examples_ repository.
[[object-mapping]]
=== Object Mapping
When a `Config` object needs to convert its Pkl value to a Java value, it delegates the conversion to {uri-pkl-config-java-ValueMapper}[`ValueMapper`].
`ValueMapper` can convert an entire `PModule` or any part thereof.
A `ValueMapper` instance can be configured with many different Pkl-to-Java value conversions.
`ValueMapper.preconfigured()` creates an instance configured with conversions from Pkl values to:
* Number types
* Strings
* Enums
* Collections
* Arrays
* `java.util.Optional`
* `java.time.Duration`
* `java.net.URI/URL`
* etc.
Additionally, a preconfigured `ValueMapper` instance can convert Pkl objects to Java objects with equally named properties that are settable through a constructor.
This conversion works as follows:
. Find the Java class constructor with the highest number of parameters.
. Match constructor parameters with Pkl object properties by name.
+
Unmatched constructor parameters result in a conversion error.
Unmatched Pkl object properties are ignored.
+
. Convert each Pkl property value to the corresponding constructor parameter's type.
. Invoke the constructor.
The Pkl object's runtime type is irrelevant to this conversion.
Hence, typed and dynamic Pkl objects are equally supported.
To perform this conversion, `ValueMapper` needs a way to obtain the Java constructor's parameter names.
They need to be provided in one of the following ways:
* Annotate constructor with `java.beans.ConstructorProperties`.
* Annotate parameters with {uri-pkl-config-java-Named}[`Named`].
* Annotate parameters with `javax.inject.Named`.
* Set the Java compiler flag `-parameters`.
For a complete object mapping example, see:
* {uri-pkl-config-java-PObjectToObjectByCtorTestJava}[`PObjectToObjectByCtorTest.java`]
TIP: Together with xref:java-binding:codegen.adoc[code generation], object mapping provides a complete solution for consuming Pkl configuration as statically typed Java objects.
Java code never drifts from the configuration structure defined in Pkl, and the entire configuration tree can be code-completed in Java IDEs.
==== Value Conversions
The Pkl-to-Java value conversions that ship with the library are defined in {uri-pkl-config-java-Conversions}[`Conversions`] (for individual conversions) and {uri-pkl-config-java-ConverterFactories}[`ConverterFactories`] (for families of conversions).
To implement and register your own conversions, follow these steps:
. For conversions from a single source type to a single target type, implement a {uri-pkl-config-java-Conversion}[`Conversion`].
+
Example: `Conversions.pStringToCharacter` converts a single-character `pkl.base#String` to `java.lang.Character`.
. For conversions from one or multiple source types to one or multiple target types, implement a {uri-pkl-config-java-ConverterFactory}[`ConverterFactory`].
+
Example: `ConverterFactories.pCollectionToCollection` converts any `pkl.base#Collection` to any implementation of `java.util.Collection<E>`, for any `E`.
+
Converter factories are called once per combination of source type and (possibly parameterized) target type.
The returned `Converter`s are cached.
. Create a `ValueMapperBuilder`, add all desired conversions, and build a `ValueMapper`.
. Either use the `ValueMapper` directly, or connect it to a `ConfigEvaluator` through `ConfigEvaluatorBuilder`.
== Further Information
Refer to the Javadoc and sources published with the library, or browse the library's {uri-pkl-config-java-main-sources}[main] and {uri-pkl-config-java-test-sources}[test] sources.

View File

@@ -0,0 +1,23 @@
.--indent
[%collapsible]
====
Default: `" "` (two spaces) +
Example: `"\t"` (one tab) +
The characters to use for indenting generated source code.
====
.-o, --output-dir
[%collapsible]
====
Default: (not set) +
Example: `generated/` +
The directory where generated source code is placed.
Relative paths are resolved against the working directory.
====
.--generate-spring-boot
[%collapsible]
====
Default: (not set) +
Flag that indicates to generate config classes for use with Spring Boot.
====

View File

@@ -0,0 +1,33 @@
@file:Suppress("UNUSED_VARIABLE")
import org.pkl.config.java.ConfigEvaluator
import org.pkl.config.kotlin.forKotlin
import org.pkl.config.kotlin.to
import org.junit.jupiter.api.Test
// the pkl/pkl-examples repo has a similar example
class KotlinConfigExample {
@Test
fun usage() {
// tag::usage[]
val evaluator = ConfigEvaluator.preconfigured().forKotlin() // <1>
val config = evaluator.use { // <2>
it.evaluateText("""pigeon { age = 5; diet = "Seeds" }""")
}
val pigeon = config["pigeon"] // <3>
val age = pigeon["age"].to<Int>() // <4>
val hobbies = pigeon["diet"].to<List<String>>() // <5>
// end::usage[]
}
@Test
fun nullable() {
// tag::nullable[]
val evaluator = ConfigEvaluator.preconfigured().forKotlin()
val config = evaluator.use {
it.evaluateText("name = null") // <1>
}
val name = config["name"].to<String?>() // <2>
// end::nullable[]
}
}

View File

@@ -0,0 +1,130 @@
= Kotlin Code Generator
include::ROOT:partial$component-attributes.adoc[]
:uri-pkl-codegen-kotlin-maven-module: {uri-maven-docsite}/artifact/org.pkl-lang/pkl-codegen-kotlin
The Kotlin source code generator reads Pkl classes and generates corresponding Kotlin classes with equally named properties.
Together with xref:java-binding:pkl-config-java.adoc#object-mapping[Object Mapping], code generation provides a complete solution for consuming Pkl configuration as statically typed Kotlin objects.
Kotlin code never drifts from the configuration structure defined in Pkl, and the entire configuration tree can be code-completed in Kotlin IDEs.
== Installation
The code generator is offered as Gradle plugin, Java library, and CLI.
=== Gradle Plugin
See xref:pkl-gradle:index.adoc#installation[Installation] in the Gradle plugin chapter.
[[install-library]]
=== Java Library
The `pkl-codegen-kotlin` library is available {uri-pkl-codegen-kotlin-maven-module}[from Maven Central].
It requires Java 8 or higher and Kotlin 1.3 or higher.
==== Gradle
To use the library in a Gradle project, declare the following dependency:
[tabs]
====
Groovy::
+
.build.gradle
[source,groovy,subs="+attributes"]
----
dependencies {
compile "org.pkl-lang:pkl-config-kotlin:{pkl-artifact-version}"
}
ifndef::is-release-build[]
repositories {
maven { url "{uri-sonatype}" }
}
endif::[]
----
Kotlin::
+
.build.gradle.kts
[source,kotlin,subs="+attributes"]
----
dependencies {
compile("org.pkl-lang:pkl-config-kotlin:{pkl-artifact-version}")
}
ifndef::is-release-build[]
repositories {
maven { url = uri("{uri-sonatype}") }
}
endif::[]
----
====
==== Maven
To use the library in a Maven project, declare the following dependency:
.pom.xml
[source,xml,subs="+attributes"]
----
<dependency>
<groupId>org.pkl-lang</groupId>
<artifactId>pkl-codegen-kotlin</artifactId>
<version>{pkl-artifact-version}</version>
</dependency>
----
[[install-cli]]
=== CLI
The CLI is bundled with the library.
As we do not currently ship the CLI as a self-contained Jar, we recommend to provision it with a Maven compatible build tool as shown in <<install-library>>.
[[usage]]
== Usage
The code generator is offered as Gradle plugin, Java library, and CLI.
=== Gradle Plugin
See xref:pkl-gradle:index.adoc#kotlin-code-gen[Kotlin Code Generation] in the Gradle plugin chapter.
=== Java Library
The library offers two APIs: a high-level API that corresponds to the CLI, and a lower-level API that provides additional features and control.
The entry points for these APIs are `org.pkl.codegen.kotlin.CliKotlinCodeGenerator` and `org.pkl.codegen.kotlin.KotlinCodeGenerator`, respectively.
For more information, refer to the KDoc documentation.
=== CLI
As mentioned in <<install-cli,Installation>>, the CLI is bundled with the library.
To run the CLI, execute the library Jar or its `org.pkl.codegen.kotlin.Main` main class.
*Synopsis:* `java -cp <classpath> -jar pkl-codegen-kotlin.jar [<options>] <modules>`
`<modules>`::
The absolute or relative URIs of the modules to generate classe for.
Relative URIs are resolved against the working directory.
==== Options
.--generate-kdoc
[%collapsible]
====
Default: (flag not set) +
Flag that indicates to generate Kdoc based on doc comments for Pkl modules, classes, and properties.
====
Common code generator options:
include::../../java-binding/partials/cli-codegen-options.adoc[]
Common CLI options:
include::../../pkl-cli/partials/cli-common-options.adoc[]
[[full-example]]
== Full Example
For a ready-to-go example with full source code,
see link:{uri-codegen-kotlin-example}[codegen-kotlin] in the _pkl/pkl-examples_ repository.

View File

@@ -0,0 +1,3 @@
= Integration with Kotlin
Pkl provides rich integration with Kotlin. Our integration allows you to embed the Pkl runtime into your Kotlin application, and also provides code generation for from Pkl source code.

View File

@@ -0,0 +1,117 @@
= pkl-config-kotlin Library
include::ROOT:partial$component-attributes.adoc[]
:uri-pkl-config-kotlin-maven-module: {uri-maven-docsite}/artifact/org.pkl-lang/pkl-config-kotlin
:uri-pkl-config-kotlin-main-sources: {uri-github-tree}/pkl-config-kotlin/src/main/kotlin/org/pkl/kotlin
:uri-pkl-config-kotlin-test-sources: {uri-github-tree}/pkl-config-kotlin/src/test/kotlin/org/pkl/kotlin
:uri-pkl-config-kotlin-ConverterFactories: {uri-pkl-config-kotlin-main-sources}/ConverterFactories.kt
:uri-pkl-config-kotlin-ConfigExtensions: {uri-pkl-config-kotlin-main-sources}/ConfigExtensions.kt
The _pkl-config-kotlin_ library extends xref:java-binding:pkl-config-java.adoc[pkl-config-java] with Kotlin specific extension methods and object converters.
We recommend that Kotlin projects depend on this library instead of _pkl-config-java_.
== Installation
The _pkl-config-kotlin_ library is available {uri-pkl-config-kotlin-maven-module}[from Maven Central].
It requires Java 11 or higher and Kotlin 1.5 or higher.
=== Gradle
To use the library in a Gradle project, declare the following dependency:
[tabs]
====
Groovy::
+
.build.gradle
[source,groovy,subs="+attributes"]
----
dependencies {
compile "org.pkl-lang:pkl-config-kotlin:{pkl-artifact-version}"
}
ifndef::is-release-build[]
repositories {
maven { url "{uri-sonatype}" }
}
endif::[]
----
Kotlin::
+
.build.gradle.kts
[source,kotlin,subs="+attributes"]
----
dependencies {
compile("org.pkl-lang:pkl-config-kotlin:{pkl-artifact-version}")
}
ifndef::is-release-build[]
repositories {
maven { url = uri("{uri-sonatype}") }
}
endif::[]
----
====
=== Maven
To use the library in a Maven project, declare the following dependency:
.pom.xml
[source,xml,subs="+attributes"]
----
<project>
<dependency>
<groupId>org.pkl-lang</groupId>
<artifactId>pkl-config-kotlin</artifactId>
<version>{pkl-artifact-version}</version>
</dependency>
ifndef::is-release-build[]
<repositories>
<repository>
<id>sonatype-s01</id>
<name>Sonatype S01</name>
<url>{uri-sonatype}</url>
</repository>
</repositories>
endif::[]
</project>
----
== Usage
Below is the Kotlin version of the Java xref:java-binding:pkl-config-java.adoc#config-evaluator-java-example[ConfigEvaluator] example.
Differences to the Java version are called out.
[source,kotlin,indent=0]
----
include::{examplesdir}/KotlinConfigExample.kt[tags=usage]
----
<1> Use the `forKotlin()` method to preconfigure the builder with Kotlin specific conversions.
In particular, `forKotlin()` eliminates the need to annotate constructor parameters of Kotlin classes and Kotlin data classes with `@Named`.
<2> The evaluator should be closed once it is no longer needed.
Here this is done with a Kotlin `use {}` expression.
Any data returned by the evaluator before calling `close()` remains valid.
<3> Navigate to the `"pigeon"` child.
The subscript notation is shorthand for `config.get("pigeon")`.
<4> Convert `"age"` to `Int` with the `Config.to()` extension method.
The target type is provided as a type argument.
Always use `Config.to()` instead of `Config.as()` in Kotlin.
<5> `Config.to()` makes conversions to parameterized types straightforward:
`to<List<String>>()` instead of `as(JavaType.listOf(String::class.java))`.
For properties that are allowed to be `null`, convert to a nullable type:
[source,kotlin,indent=0]
----
include::{examplesdir}/KotlinConfigExample.kt[tags=nullable]
----
<1> To indicate that `null` is an allowed value, convert to the nullable type `String?`.
Converting to `String` would result in a `ConversionException`.
For a ready-to-go example with full source code,
see link:{uri-config-kotlin-example}[config-kotlin] in the _pkl/pkl-examples_ repository.
== Further Information
Refer to the Javadoc and sources published with the library, or browse the library's {uri-pkl-config-kotlin-main-sources}[main] and {uri-pkl-config-kotlin-test-sources}[test] sources.

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View File

@@ -0,0 +1,317 @@
= Basic Configuration
include::ROOT:partial$component-attributes.adoc[]
In this first part of xref:index.adoc[the Pkl tutorial], you build familiarity with Pkl syntax and basic structure.
You also learn different ways to invoke Pkl to produce different formats.
== Basic values
Consider the following example Pkl file.
[source,{pkl}]
.intro.pkl
----
name = "Pkl: Configure your Systems in New Ways"
attendants = 100
isInteractive = true
amountLearned = 13.37
----
Running Pkl on this file gives
[source,shell]
----
$ pkl eval /Users/me/tutorial/intro.pkl
name = "Pkl: Configure your Systems in New Ways"
attendants = 100
isInteractive = true
amountLearned = 13.37
----
It may seem nothing happened.
However, Pkl tells you that it _accepts the input_.
In other words, you now know that `intro.pkl` does not contain any errors.
You can ask Pkl to print this configuration in a different format, using the `-f` option.
For example, JSON:
[source,shell]
----
$ pkl eval -f json /Users/me/tutorial/intro.pkl
{
"name": "Pkl: Configure your Systems in New Ways",
"attendants": 100,
"isInteractive": true,
"amountLearned": 13.37
}
----
Or _PropertyList_ format:
[source,shell]
----
$ pkl eval -f plist /Users/me/tutorial/intro.pkl
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>Pkl: Configure your Systems in New Ways</string>
<key>attendants</key>
<integer>100</integer>
<key>isInteractive</key>
<true/>
<key>amountLearned</key>
<real>13.37</real>
</dict>
</plist>
----
Notice that Pkl generated `<string>`, `<integer>`, `<true/>` and `<real>` for the values in your configuration.
This means it has _both_ correctly derived the types of the literal values _and_ translated those types to the corresponding elements in the PropertyList.
xref:03_writing_a_template.adoc[Part III] goes into types in more detail.
== Structure: Classes, objects, modules
A configuration often requires more than just basic values.
Typically, you need some kind of (hierarchical) structure.
Pkl provides _immutable objects_ for this.
Objects have three kinds of members: properties, elements and entries.
First, look at the syntax for objects and their members.
=== Properties
[source,{pkl}]
.simpleObjectWithProperties.pkl
----
bird { // <1>
name = "Common wood pigeon" // <2>
diet = "Seeds"
taxonomy { // <3>
species = "Columba palumbus"
}
}
----
<1> This _defines_ `bird` to be an object
<2> For primitive values, Pkl has the `=` syntax (more on this later).
<3> Just like `bird {`, but to show that objects can be nested.
This defines an object called `bird` with three _named properties_: `name`, `diet`, and `taxonomy`.
The first two of these are strings, but `taxonomy` is another object.
This means properties in an object can have different types and objects can be nested.
=== Elements
Of course, you don't always have names for every individual structure in your configuration.
What if you want "just a bunch of things" without knowing how many?
Pkl offers _elements_ for this purpose.
Elements are object members, just like properties.
Where you index properties by their name, you index elements by an integer.
You can think of an object that only contains elements as _array_.
Much like arrays in many languages, you can use square brackets to access an element, for example, `myObject[42]`.
You write an element, by writing only an expression.
Pkl derives the index from the number of elements already in the object.
For example:
[source,{pkl}]
.simpleObjectsWithElements.pkl
----
exampleObjectWithJustIntElements {
100 // <1>
42
}
exampleObjectWithMixedElements {
"Bird Breeder Conference"
(2000 + 23) // <2>
exampleObjectWithJustIntElements // <3>
}
----
<1> When you write only the value (without a name), you describe an _element_.
<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.
=== Entries
Objects can have one more kind of member; _entries_.
Like a _property_, an _entry_ is "named" (technically _keyed_).
Unlike a property, the name does not need to be known at declaration time.
Of course, we need a syntax to tell entries apart from properties.
You write entry "names" by enclosing them in square brackets ("names" is quoted, because the names do not need to be strings; any value can index entries).
[source,{pkl}]
.simpleObjectsWithEntries.pkl
----
pigeonShelter {
["bird"] { // <1>
name = "Common wood pigeon"
diet = "Seeds"
taxonomy {
species = "Columba palumbus"
}
}
["address"] = "355 Bird St." // <2>
}
birdCount {
[pigeonShelter] = 42 // <3>
}
----
<1> The difference with properties is the notation of the key: `[<expression>]`.
<2> As with properties, entries can be primitive values or objects.
<3> Any object can be used as a key for an entry.
=== Mixed members
In the examples so far, you have seen objects with properties, object with elements and object with entries.
These object members can be freely mixed.
[source,{pkl}]
.mixedObject.pkl
----
mixedObject {
name = "Pigeon"
lifespan = 8
"wing"
"claw"
["wing"] = "Not related to the _element_ \"wing\""
42
extinct = false
[false] {
description = "Construed object example"
}
}
----
Notice, how properties (`name`, `lifespan` and `extinct`), elements (`"wing"`, `"claw"`, `42`) and entries (`"wing"`, `false`) are mixed together in this one object.
You don't have to order them by kind, and you don't require (other) special syntax.
=== Collections
This free-for-all mixing of object members can become confusing.
Also, target formats are often considerably more restrictive.
In the following example, you see what happens when you try to produce JSON from `mixedObject`:
[source,shell]
----
$ pkl eval -f json /Users/me/tutorial/mixedObject.pkl
Pkl Error
Cannot render object with both properties/entries and elements as JSON.
Object: "Pigeon"
89 | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L90)
----
This is why Pkl has two special types of object, namely _listings_, which contain _exclusively_ elements, and _mappings_, which contain _exclusively_ entries.
Both listings and mappings _are_ "just objects," so, they don't require syntax besides that of objects:
[source,{pkl}]
.collections.pkl
----
birds { // <1>
"Pigeon"
"Parrot"
"Barn owl"
"Falcon"
}
habitats { // <2>
["Pigeon"] = "Streets"
["Parrot"] = "Parks"
["Barn owl"] = "Forests"
["Falcon"] = "Mountains"
}
----
<1> A listing containing four elements.
<2> A mapping containing four entries.
[NOTE]
====
_Technically_, the correct way to define `birds` and `habitats` is by using `new Listing {...}` and `new Mapping {...}` explicitly.
You will see what these mean in part xref:03_writing_a_template.adoc[three] of this tutorial.
====
When you render _this_ configuration as JSON, everything works:
[source,json]
----
{
"birds": [
"Pigeon",
"Parrot",
"Barn owl",
"Falcon"
],
"habitats": {
"Pigeon": "Streets",
"Parrot": "Parks",
"Barn owl": "Forests",
"Falcon": "Mountains"
}
}
----
Notice particularly, that you rendered the listing as a JSON _array_.
When you index the listing with an integer, you're referring to the element inside the listing at the corresponding position (starting from `0`).
For example:
[source,{pkl}]
.indexedListing.pkl
----
birds {
"Pigeon"
"Parrot"
"Barn owl"
"Falcon"
}
relatedToSnowOwl = birds[2]
----
results in
[source,{pkl}]
----
birds {
"Pigeon"
"Parrot"
"Barn owl"
"Falcon"
}
relatedToSnowOwl = "Barn owl"
----
== Exercises
1. Given the following JSON snippet (taken from W3C examples), write the `.pkl` file that produces this JSON:
+
[source,json]
----
{
"name": "Common wood pigeon",
"lifespan": 8,
"friends": {
"bird1": "Parrot",
"bird2": "Albatross",
"bird3": "Falcon"
}
}
----
2. For some reason, we decide we no longer need the birdX names of the different birds; we just need them as an array.
Change your solution to the previous question to produce the following JSON result:
+
[source,json]
----
{
"name": "Common wood pigeon",
"lifespan": 8,
"birds": ["Parrot", "Barn owl", "Falcon"]
}
----

View File

@@ -0,0 +1,438 @@
= Filling out a Template
include::ROOT:partial$component-attributes.adoc[]
In this second part of xref:index.adoc[the Pkl tutorial], you will learn how to write one (part of a) configuration in terms of another.
You will also find and fill out an existing _template_.
== Composing configurations
=== Amending
The central mechanism in Pkl for expressing one (part of a) configuration in terms of another is _amending_.
Consider the following example.
[source,{pkl}]
.amendingObjects.pkl
----
bird {
name = "Pigeon"
diet = "Seeds"
taxonomy {
kingdom = "Animalia"
clade = "Dinosauria"
order = "Columbiformes"
}
}
parrot = (bird) {
name = "Parrot"
diet = "Berries"
taxonomy {
order = "Psittaciformes"
}
}
----
Parrot and Pigeon have nearly identical properties.
They only differ in their name and taxonomy, so if you have already written out `bird`, you can say that `parrot` is just like `pigeon` except `name` is `"Parrot"`, diet is `"Berries"` the `taxonomy.order` is `"Psittaciformes"`.
When you run this, Pkl expands everything fully.
[source,{pkl}]
----
bird {
name = "Common wood pigeon"
diet = "Seeds"
taxonomy {
kingdom = "Animalia"
clade = "Dinosauria"
order = "Columbiformes"
}
}
parrot {
name = "Parrot"
diet = "Berries"
taxonomy {
kingdom = "Animalia"
clade = "Dinosauria"
order = "Psittaciformes"
}
}
----
[IMPORTANT]
====
_Amending_ does not allow us to _add_ properties to the (typed) object we are amending.
The xref:03_writing_a_template.adoc[next part of the tutorial] discusses types in more detail.
There, you see that amending _never changes the type_ of the object.
====
You can also amend nested objects.
This allows you to only describe the difference with the outermost object for arbitrarily deeply nested structures.
Consider the following example.
[source,{pkl}]
.nestedAmends.pkl
----
woodPigeon {
name = "Common wood pigeon"
diet = "Seeds"
taxonomy {
species = "Columba palumbus"
}
}
stockPigeon = (woodPigeon) {
name = "Stock pigeon"
taxonomy { // <1>
species = "Columba oenas"
}
}
dodo = (stockPigeon) { // <2>
name = "Dodo"
extinct = true // <3>
taxonomy {
species = "Raphus cucullatus"
}
}
----
<1> This amends `species`, _as it occurs in_ `stockPigeon`.
<2> Amended objects can, themselves, be amended.
<3> New fields can be added to objects when amending.
Notice how you only have to change `taxonomy.species`.
In this example, `bird.taxonomy` has `kingdom`, `clade`, `order` and `species`.
You are amending `stockPigeon`, to define `woodPigeon`.
They have the same `taxonomy`, except for `species`.
This notation says that everything in `taxonomy` should be what it is in the object you are amending (`stockPigeon`), except for `species`, which should be `"Columba palumbus"` .
For the input above, Pkl produces the following output.
[source,{pkl}]
----
woodPigeon {
name = "Common wood pigeon"
diet = "Seeds"
taxonomy {
species = "Columba palumbus"
}
}
stockPigeon {
name = "Stock pigeon"
diet = "Seeds"
taxonomy {
species = "Columba oenas"
}
}
dodo {
name = "Dodo"
diet = "Seeds"
extinct = true
taxonomy {
species = "Raphus cucullatus"
}
}
----
So far, you have only amended _properties_.
Since you refer to them by name, it makes sense that you "overwrite" the value from the object you're amending.
What if you include _elements_ or _entries_ in an amends expression?
[source,{pkl}]
.amendElementsAndEntries.pkl
----
favoriteFoods {
"red berries"
"blue berries"
["Barn owl"] {
"mice"
}
}
adultBirdFoods = (favoriteFoods) {
[1] = "pebbles" // <1>
"worms" // <2>
["Falcon"] { // <3>
"insects"
"amphibians"
}
["Barn owl"] { // <4>
"fish"
}
}
----
<1> Explicitly amending _by index_ replaces the element at that index.
<2> Without explicit indices, Pkl can't know which element to overwrite, so, instead, it _adds_ an element to the object you're amending.
<3> When you write "new" entries (using a key that does not occur in the object you're amending), Pkl also _adds_ them.
<4> When you write an entry using a key that exists, this notation amends its value.
Pkl can't know which of the `favoriteFoods` to overwrite only by their _value_.
When you want to _replace_ an element, you have to explicitly amend the element at a specific index.
This is why a "plain" element in an amends expression is _added_ to the object being amended.
Result:
[source,{pkl}]
----
favoriteFoods {
["Barn owl"] {
"mice"
}
"red berries"
"blue berries"
}
adultBirdFoods {
["Barn owl"] {
"mice"
"fish"
}
"red berries"
"pebbles"
["Falcon"] {
"insects"
"amphibians"
}
"worms"
}
----
=== Modules
A `.pkl` file describes a _module_.
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.
[source,{pkl}]
.pigeon.pkl
----
name = "Common wood pigeon"
diet = "Seeds"
taxonomy {
species = "Columba palumbus"
}
----
You can `import` this module and express `parrot` like you did before.
[source,{pkl}]
.parrot.pkl
----
import "pigeon.pkl" // <1>
parrot = (pigeon) {
name = "Great green macaw"
diet = "Berries"
species {
species = "Ara ambiguus"
}
}
----
<1> Importing `foo.pkl` creates the object `foo`, so you can refer to `pigeon` in this code, like you did before.
If you run Pkl on both, you will see that it works.
Looking at the result, however, you see a (possibly) unexpected difference.
[source,{pkl}]
----
$ pkl eval /Users/me/tutorial/pigeon.pkl
name = "Common wood pigeon""
diet = "Seeds"
taxonomy {
species = "Columba palumbus"
}
$ pkl eval /Users/me/tutorial/parrot.pkl
parrot {
name = "Great green macaw"
diet = "Berries"
taxonomy {
species = "Ara ambiguus"
}
}
----
The object `pigeon` is "spread" in the top-level, while `parrot` is a nested and named object.
This is because writing `parrot {...}` defines an object property _in_ the "current" module.
In order to say that "this module is an object, amended from the `pigeon` module," you use an _amends clause_.
[source,{pkl}]
.parrot.pkl
----
amends "pigeon.pkl" // <1>
name = "Great green macaw"
----
<1> "This" module is the same as `"pigeon.pkl"`, except for what is in the remainder of the file.
[NOTE]
====
As a first intuition, think of "amending a module" as "filling out a form."
====
== Amending templates
A Pkl file can be either a _template_ or a _"normal" module_.
This terminology describes the _intended use_ of the module and doesn't imply anything about its structure.
In other words: just by looking at Pkl code, you can't tell whether it is a template or a "normal" module.
[source,{pkl}]
.acmecicd.pkl
----
module acmecicd
class Pipeline {
name: String(nameRequiresBranchName)?
hidden nameRequiresBranchName = (_) ->
if (branchName == null)
throw("Pipelines that set a 'name' must also set a 'branchName'.")
else true
branchName: String?
}
timeout: Int(this >= 3)
pipelines: Listing<Pipeline>
output {
renderer = new YamlRenderer {}
}
----
Remember that amending is like filling out a form.
That's exactly what you're doing here; you're filling out "work order forms".
Next, add a time-out of one minute for your job.
[source,{pkl}]
.cicd.pkl
----
amends "acmecicd.pkl"
timeout = 1
----
Unfortunately, Pkl does not accept this configuration and provides a rather elaborate error message:
[source,plain]
----
Pkl Error // <1>
Type constraint `this >= 3` violated. // <2>
Value: 1 // <3>
225 | timeout: Int(this >= 3)? // <4>
^^^^^^^^^
at acmecicd#timeout (file:///Users/me/tutorial/acmecicd.pkl, line 8)
3 | timeout = 1 // <5>
^
at cicd#timeout (file:///Users/me/tutorial/cicd.pkl, line 3)
90 | text = renderer.renderDocument(value) // <6>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (https://github.com/apple/pkl/blob/e4d8c882d/stdlib/base.pkl#L90)
----
<1> Pkl found an error.
<2> Which error Pkl found.
<3> What the offending value is.
<4> Where Pkl found its expectation (line 8 of the amended module).
<5> Where Pkl found the offending value (line 3 of the input module).
<6> What Pkl evaluated to discover the error.
When Pkl prints source locations, it also prints clickable links for easy access.
For local files, it generates a link for your development environment (https://pkl-lang.org/main/current/pkl-cli/index.html#settings-file[configurable in `+~/.pkl/settings.pkl+`]).
For packages imported from elsewhere, if available, Pkl produces `https://` links to their repository.
Pkl complains about a _type constraint_.
Pkl's type system doesn't just protect you from providing a `String` where you expected an `Int`, it even checks which _values_ are allowed.
In this case, the minimum time-out is _three_ minutes.
If you change the value to `3`, Pkl accepts your configuration.
[source, shell]
----
$ pkl eval cicd.pkl
timeout: 3
pipelines: []
----
You can now define a pipeline.
Start off by specifying the name of the pipeline and nothing else.
[source,{pkl}]
.cicd.pkl
----
amends "acmecicd.pkl"
timeout = 3
pipelines {
new { // <1>
name = "prb"
}
}
----
<1> There is no pipeline object to amend. The `new` keyword gives you an object to amend.
So far, you've defined objects the same way you amended them.
When the name `foo` didn't occur before, `foo { ... }` _creates_ a property called `foo` and assigns to it the object specified on the `...`.
If `foo` is an existing object, this notation is an _amend expression_; resulting in a new _object_ (value), but _not_ a new (named) property.
Since `pipelines` is a listing, you can _add_ elements by writing expressions in an amend expression.
In this case, though, there is no object to amend. Writing `myNewPipeline { ... }` defines a _property_, but listings may only include _elements_.
This is where you can use the keyword `new`.
`new` gives you an object to amend.
Pkl derives from the context in which `new` is used and what the object to amend should look like.
This is called the _default value_ for the context.
xref:03_writing_a_template.adoc[The next part] goes into detail about how Pkl does this.
Running Pkl on your new configuration produces a verbose error.
[source,plain]
.cicd.pkl
----
Pkl Error
Pipelines that set a 'name' must also set a 'branchName'.
8 | throw("Pipelines that set a 'name' must also set a 'branchName'.")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at acmecicd#Pipeline.nameRequiresBranchName.<function#1> (file:///Users/me/tutorial/acmecicd.pkl, line 8)
6 | name = "prb"
^^^^^
at cicd#pipelines[#1].name (file:///Users/me/tutorial/cicd.pkl, line 6)
90 | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (https://github.com/apple/pkl/blob/e4d8c882d/stdlib/base.pkl#L90)
----
You have hit another type constraint, like `timeout: Int(this >= 3)` before.
In this case, the error message consists of an English language sentence, instead of Pkl code.
When constraints are complicated or very application specific, template authors can `throw` a more descriptive error message like this.
The message is quite instructive, so you can fix the error by adding a `branchName`.
[source,{pkl}]
.cicd.pkl
----
amends "acmecicd.pkl"
timeout = 3
pipelines {
new {
name = "prb"
branchName = "main"
}
}
----
and indeed
[source,{pkl}]
----
$ pkl eval -f yml /Users/me/tutorial/cicd.pkl
timeout: 3
pipelines:
- name: prb
branchName: main
----

View File

@@ -0,0 +1,441 @@
= Writing a Template
include::ROOT:partial$component-attributes.adoc[]
In parts xref:01_basic_config.adoc[one] and xref:02_filling_out_a_template.adoc[two], you saw that Pkl provides _validation_ of our configurations.
It checks syntax, types and constraints.
As you saw in the `acmecicd` example xref:02_filling_out_a_template.adoc#amending-templates[here], the template can provide informative error messages when an amending module violates a type constraint.
In this final part, you will see some of Pkl's techniques that are particularly relevant for writing a template.
== Basic types
Pkl always checks the _syntax_ of its input.
As it evaluates your configuration, it also checks _types_.
You've seen objects, listings, and mappings already.
These provide ways to write structured configuration.
Before you can write types for them, you need to know how to write the types for the simplest (unstructured) values.
These are all Pkl's _basic_ types:
[source,{pkl}]
.pklTutorialPart3.pkl
----
name: String = "Writing a Template"
part: Int = 3
hasExercises: Boolean = true
amountLearned: Float = 13.37
duration: Duration = 30.min
bandwidthRequirementPerSecond: DataSize = 50.mb
----
In the above, you've explicitly annotated the code with type signatures.
The default output of Pkl is actually `pcf`, which is a subset of Pkl.
Since `pcf` does not have type signatures, running Pkl on this example removes them.
[source,shell]
----
$ pkl eval pklTutorialPart3.pkl
name = "Writing a Template"
part = 3
hasExercises = true
amountLearned = 13.37
duration = 30.min
bandwidthRequirementPerSecond = 50.mb
----
Note how `Duration` and `DataSize` help you prevent https://en.wikipedia.org/wiki/Mars_Climate_Orbiter[unit errors] in these common (for configuration) domains.
== Typed objects, properties and amending
Having a notation for basic types, you can now write _typed objects_.
[source,{pkl}]
.simpleClass.pkl
----
class Language { // <1>
name: String
}
bestForConfig: Language = new { // <2>
name = "Pkl"
}
----
<1> A class definition.
<2> A property definition, using the `Language` class.
[NOTE]
====
Although not required (or enforced), it's customary to name properties starting with a lower-case letter. Class names, by that same convention, start with an upper-case letter.
====
You can type objects with _classes_.
In this example, you define a class called `Language`.
You can now be certain that every instance of `Language` has a property `name` with type `String`.
Types and values are different things in Pkl.
Pkl does not render types in its output,footnote:[Although, some output formats can contain their own form of type annotation. This may be derived from the Pkl type. Type definitions (`class` and `typealias`) themselves are never rendered.] so when you run Pkl on this, you don't see the class _definition_ at all.
[source,{pkl}]
----
$ pkl eval simpleClass.pkl
bestForConfig {
name = "Pkl"
}
----
Did you notice that the output doesn't just omit the type signature, but also the `= new`?
We will discuss this further in the next section.
When your configuration describes a few different parts like this, you can define one instance and amend it for every other instance.
For example:
[source,{pkl}]
.pklTutorialParts.pkl
----
class TutorialPart {
name: String
part: Int
hasExercises: Boolean
amountLearned: Float
duration: Duration
bandwidthRequirementPerSecond: DataSize
}
pklTutorialPart1: TutorialPart = new {
name = "Basic Configuration"
part = 1
hasExercises = true
amountLearned = 13.37
duration = 30.min
bandwidthRequirementPerSecond = 50.mib.toUnit("mb")
}
pklTutorialPart2: TutorialPart = (pklTutorialPart1) {
name = "Filling out a Template"
part = 2
}
pklTutorialPart3: TutorialPart = (pklTutorialPart1) {
name = "Writing a Template"
part = 3
}
----
You can read this as saying "``pklTutorialPart2`` & `pklTutorialPart3` are exactly like `pklTutorialPart1`, except for their `name` and `part`."
Running Pkl confirms this:
[source,shell]
----
$ pkl eval pklTutorialParts.pkl
pklTutorialPart1 {
name = "Basic Configuration"
part = 1
hasExercises = true
amountLearned = 13.37
duration = 30.min
bandwidthRequirementPerSecond = 50.mb
}
pklTutorialPart2 {
name = "Filling out a Template"
part = 2
hasExercises = true
amountLearned = 13.37
duration = 30.min
bandwidthRequirementPerSecond = 50.mb
}
pklTutorialPart3 {
name = "Writing a Template"
part = 3
hasExercises = true
amountLearned = 13.37
duration = 30.min
bandwidthRequirementPerSecond = 50.mb
}
----
Sadly, `pklTutorialParts.pkl` is a _rewrite_ of `pklTutorial.pkl`.
It creates a separate `class TutorialPart` and instantiates three properties with it (`pklTutorialPart1`, `pklTutorialPart2` and `pklTutorialPart3`).
In doing so, it implicitly moves everything "down" one level (`pklTutorialPart3` is now a property in the module `pklTutorialParts`, whereas above, in `pklTutorialPart3.pkl` it was its own module).
This is not very DRY.
As a matter of fact, you don't need this rewrite.
Any `.pkl` file defines a _module_ in Pkl.
Any module is represented by a _module class_, which is an actual Pkl `class`.
A module is not quite the same as any other class, because Pkl never renders class definitions on the output.
However, when you ran Pkl on `pklTutorialPart3.pkl`, it _did_ produce an output.
This is because a module also defines an _instance_ of the module class.
The values given to properties in a module (or in any "normal" class) are called _default values_.
When you instantiate a class, all the properties for which you _don't_ provide a value are populated from the class' default values.
In our examples of tutorial parts, only the `name` and `part` varied across instances.
You can express this by adding default values to the (module) class definition.
Instead of starting from a particular tutorial part, you can define the module `tutorialPart` as follows:
[source,{pkl}]
.TutorialPart.pkl
----
name: String // <1>
part: Int // <1>
hasExercises: Boolean = true // <2>
amountLearned: Float = 13.37 // <2>
duration: Duration = 30.min // <2>
bandwidthRequirementPerSecond: DataSize = 50.mb // <2>
----
<1> No default value given.
<2> Default value given.
Running this through Pkl gives an error, or course, because of the missing values:
[source, shell]
----
$ pkl eval TutorialPart.pkl
Pkl Error
Tried to read property `name` but its value is undefined.
1 | name: String
^^^^
...
----
An individual part now only has to fill in the missing fields, so you can change `pklTutorialPart3.pkl` to amend this:
[source,{pkl}]
.pklTutorialPart3.pkl
----
amends "TutorialPart.pkl"
name = "Writing a Template"
part = 3
----
This results in
[source, shell]
----
$ pkl eval pklTutorialPart3.pkl
name = "Writing a Template"
part = 3
hasExercises = true
amountLearned = 13.37
duration = 30.min
bandwidthRequirementPerSecond = 50.mb
----
This now behaves exactly like our `pklTutorialPart3: TutorialPart = (pklTutorialPart1) {...` before.
`pklTutorialPart3` is now defined as the value we get by amending `tutorialPart` and giving it a `name` and a `part`.
[IMPORTANT]
====
Amending anything _never changes its type_.
When we amend an object of type `Foo`, the result will always be precisely of type `Foo`.
By "precisely" we mean, that amending an object also can't "turn it into" an instance of a sub-class of the class of the object being amended.
====
== A new template
Now that you know about types, you can start writing your first template.
So far, you've written configurations with Pkl, either without a template, or using a template on Pkl Hub.
It is often easiest to first write a (typical) configuration for which you want to create a template.
Suppose you want to define what a live workshop for this tutorial looks like.
Consider this example:
[source,{pkl}]
.workshop2023.pkl
----
title = "Pkl: Configure your Systems in New Ways"
interactive = true
seats = 100
occupancy = 0.85
duration = 1.5.h
`abstract` = """
With more systems to configure, the software industry is drowning in repetitive and brittle configuration files.
YAML and other configuration formats have been turned into programming languages against their will.
Unsurprisingly, they dont live up to the task.
Pkl puts you back in control.
"""
event {
name = "Migrating Birds between hemispheres"
year = 2023
}
instructors {
"Kate Sparrow"
"Jerome Owl"
}
sessions {
new {
date = "8/14/2023"
time = 30.min
}
new {
date = "8/15/2023"
time = 30.min
}
}
assistants {
["kevin"] = "Kevin Parrot"
["betty"] = "Betty Harrier"
}
agenda {
["beginners"] {
title = "Basic Configuration"
part = 1
duration = 45.min
}
["intermediates"] {
title = "Filling out a Template"
part = 2
duration = 45.min
}
["experts"] {
title = "Writing a Template"
part = 3
duration = 45.min
}
}
----
Call your new template `Workshop.pkl`.
Although not required, it's good practice to always name your template with a `module`-clause.
Defining the first few properties are like you saw in the previous section:
[source,{pkl}]
----
module Workshop
title: String
interactive: Boolean
seats: Int
occupancy: Float
duration: Duration
`abstract`: String
----
Unlike these first few properties, `event` is an object with multiple properties.
To be able to type `event`, you need a `class`.
You've seen before how to define this:
[source,{pkl}]
----
class Event {
name: String
year: Int
}
event: Event
----
Next, `instructors` isn't an object with properties, but a list of unnamed values.
Pkl offers the `Listing` type for this:
[source,{pkl}]
----
instructors: Listing<String>
----
`sessions` is a `Listing` of objects, so you need a `Session` class.
[source,{pkl}]
----
class Session {
time: Duration
date: String
}
sessions: Listing<Session>
----
`assistants` has a structure like an object, in that all the values are named, but the set of names is not fixed for all possible workshops (and some workshops may have more assistants than others). The Pkl type for this is a `Mapping`:
[source,{pkl}]
----
assistants: Mapping<String, String>
----
Finally, for every workshop session, there is an `agenda`, which describes which ``TutorialPart``s are covered.
You already defined `TutorialPart.pkl` as its own module, so you should not define a separate class, but rather `import` that module and reuse it here:
[source,{pkl}]
----
import "TutorialPart.pkl" // <1>
agenda: Mapping<String, TutorialPart>
----
<1> This `import` clause brings the name `TutorialPart` into scope, which is the module class as discussed above. Note that import clauses must appear before property definitions.
Putting it all together, your `Workshop.pkl` template looks like this:
[source,{pkl}]
.Workshop.pkl
----
module Workshop
import "TutorialPart.pkl"
title: String
interactive: Boolean
seats: Int
occupancy: Float
duration: Duration
`abstract`: String
class Event {
name: String
year: Int
}
event: Event
instructors: Listing<String>
class Session {
time: Duration
date: String
}
sessions: Listing<Session>
assistants: Mapping<String, String>
agenda: Mapping<String, TutorialPart>
----

View File

@@ -0,0 +1,17 @@
= Tutorial
include::ROOT:partial$component-attributes.adoc[]
Welcome to the Pkl tutorial. We will get you up and running quickly!
If you are new to Pkl, we recommend that you follow along with the code examples.
This tutorial describes interactions with the xref:pkl-cli:index.adoc#repl[REPL].
For an even more interactive experience, follow along using a xref:main:ROOT:tools.adoc[supported editor].
For more comprehensive documentation, see xref:language-reference:index.adoc[Language Reference].
For ready-to-go examples with full source code, see xref:ROOT:examples.adoc[].
For API documentation, see xref:ROOT:standard-library.adoc[Standard Library].
Pick a tutorial by topic:
1. xref:01_basic_config.adoc[Basic Configuration]
2. xref:02_filling_out_a_template.adoc[Filling out a Template]
3. xref:03_writing_a_template.adoc[Writing a Template]

View File

@@ -0,0 +1,782 @@
= CLI
include::ROOT:partial$component-attributes.adoc[]
:uri-homebrew: https://brew.sh
:uri-pkl-macos-download: {github-releases}/pkl-cli-macos-{pkl-artifact-version}.bin
:uri-pkl-linux-amd64-download: {github-releases}/pkl-cli-linux-amd64-{pkl-artifact-version}.bin
:uri-pkl-linux-aarch64-download: {github-releases}/pkl-cli-linux-aarch64-{pkl-artifact-version}.bin
:uri-pkl-alpine-download: {github-releases}/pkl-cli-alpine-amd64-{pkl-artifact-version}.bin
:uri-pkl-java-download: {github-releases}/pkl-cli-java-{pkl-artifact-version}.jar
:uri-pkl-stdlib-docs-settings: {uri-pkl-stdlib-docs}/settings/
:uri-pkl-cli-main-sources: {uri-github-tree}/pkl-cli/src/main/kotlin/org/pkl/cli
:uri-pkl-cli-CliEvaluatorOptions: {uri-pkl-cli-main-sources}/CliEvaluatorOptions.kt
:uri-certificates: {uri-github-tree}/pkl-commons-cli/src/main/resources/org/pkl/commons/cli/commands
The `pkl` command-line interface (CLI) evaluates Pkl modules and writes their output to the console or a file.
For interactive development, the CLI includes a Read-Eval-Print Loop (REPL).
[[installation]]
== Installation
The CLI comes in multiple flavors:
* Native macOS executable for amd64 (tested on macOS 10.15)
* Native Linux executable for amd64 (tested on Oracle Linux 8)
* Native Linux executable for aarch64 (tested on Oracle Linux 8)
* Native Alpine Linux executable for amd64 (cross-compiled and tested on Oracle Linux 8)
* Java executable (tested with Java 8/11/14 on macOS and Oracle Linux)
On macOS and Linux, we recommend using the native executables.
They are self-contained, start up instantly, and run complex Pkl code much faster than the Java executable.
.What is the Difference Between the Linux and Alpine Linux Executables?
[NOTE]
====
The Linux executable is dynamically linked against _glibc_ and _libstdc{plus}{plus}_,
whereas, the Alpine Linux executable is statically linked against _musl libc_ and _libstdc{plus}{plus}_.
====
The Java executable works on multiple platforms and has a smaller binary size than the native executables.
However, it requires a Java 8 (or higher) runtime on the system path, 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.
Except where noted otherwise, the rest of this page discusses the native executables.
//TODO uncomment this after brew formula is merged and available
// [[homebrew]]
// === Homebrew
//
// Release versions can be installed with {uri-homebrew}[Homebrew].
//
// ifdef::is-release-version[]
// To install Pkl, run:
//
// [source,shell]
// ----
// brew install pkl
// ----
//
// To update Pkl, run:
//
// [source,shell]
// ----
// brew update
// brew upgrade pkl # or just `brew upgrade`
// ----
// endif::[]
//
// ifndef::is-release-version[]
// For instructions, switch to a release version of this page.
// endif::[]
[[download]]
=== Download
Development and release versions can be downloaded and installed manually.
=== macOS Executable
[source,shell]
[subs="+attributes"]
----
curl -o pkl {uri-pkl-macos-download}
chmod +x pkl
./pkl --version
----
This should print something similar to:
[source,shell]
[subs="+attributes"]
----
Pkl {pkl-version} (macOS, native)
----
[[linux-executable]]
=== Linux Executable
The Linux executable is dynamically linked against _glibc_ and _libstdc{plus}{plus}_ for the amd64 and aarch64 architectures.
For a statically linked executable, see <<Alpine Linux Executable>>.
On amd64:
[source,shell]
[subs="+attributes"]
----
# on amd64
curl -o pkl {uri-pkl-linux-amd64-download}
chmod +x pkl
./pkl --version
----
On aarch64:
[source,shell]
[subs="+attributes"]
----
curl -o pkl {uri-pkl-linux-aarch64-download}
chmod +x pkl
./pkl --version
----
This should print something similar to:
[source,shell]
[subs="+attributes"]
----
Pkl {pkl-version} (Linux, native)
----
[[alpine-linux-executable]]
=== Alpine Linux Executable
The Alpine Linux executable is statically linked against _musl libc_ and _libstdc{plus}{plus}_.
For a dynamically linked executable, see <<Linux Executable>>.
[source,shell]
[subs="+attributes"]
----
curl -o pkl {uri-pkl-alpine-download}
chmod +x pkl
./pkl --version
----
This should print something similar to:
[source,shell]
[subs="+attributes"]
----
Pkl {pkl-version} (Linux, native)
----
NOTE: We currently do not support the aarch64 architecture for Alpine Linux.
=== Java Executable
[source,shell]
[subs="+attributes"]
----
curl -o jpkl {uri-pkl-java-download}
chmod +x jpkl
./jpkl --version
----
This should print something similar to:
[source,shell]
[subs="+attributes"]
----
Pkl {pkl-version} (macOS 10.16, Java 11.0.9)
----
[[usage]]
== Usage
*Synopsis:* `pkl <subcommand> [<options>] [<args>]`
For a brief description of available options, run `pkl -h`.
NOTE: The Java executable is named `jpkl`.
[[command-eval]]
=== `pkl eval`
*Synopsis:* `pkl eval [<options>] [<modules>]`
Evaluate the given Pkl `<modules>` and produce their rendering results.
<modules>::
The absolute or relative URIs of the modules to evaluate.
Relative URIs are resolved against the working directory.
==== Options
[[format]]
.-f, --format
[%collapsible]
====
Default: (none) +
Example: `yaml` +
The output format to generate.
The default output renderer for a module supports the following formats:
* `json`
* `jsonnet`
* `pcf`
* `plist`
* `properties`
* `textproto`
* `xml`
* `yaml`
If no format is set, the default renderer chooses `pcf`.
====
[[output-path]]
.-o, --output-path
[%collapsible]
====
Default: (none) +
Example: "config.yaml" +
The file path where the output file is placed.
Relative paths are resolved against the project directory.
// suppress inspection "AsciiDocLinkResolve"
This option is mutually exclusive with link:#multiple-file-output-path[`--multiple-file-output-path`].
If neither option is set, each module's `output.text` is written to standard output.
If multiple source modules are given, placeholders can be used to map them to different output files.
The following placeholders are supported:
`%\{moduleDir}`:::
The directory path of the module, relative to the working directory.
Only available when evaluating file-based modules.
`%\{moduleName}`:::
The simple module name as inferred from the module URI.
For hierarchical URIs such as `+file:///foo/bar/baz.pkl+`, this is the last path segment without file extension.
`%\{outputFormat}`:::
The requested output format.
Only available if `--format` is set.
If multiple source modules are mapped to the same output file, their outputs are concatenated.
By default, module outputs are separated with `---`, as in a YAML stream.
// suppress inspection "AsciiDocLinkResolve"
The separator can be customized using the link:#module-output-separator[`--module-output-separator`] option.
====
[[module-output-separator]]
.--module-output-separator
[%collapsible]
====
Default: `---` (as in a YAML stream) +
The separator to use when multiple module outputs are written to the same file, or to standard output.
====
[[multiple-file-output-path]]
.-m, --multiple-file-output-path
[%collapsible]
====
Default: (none) +
Example: "output/" +
The directory where a module's output files are placed.
Setting this option causes Pkl to evaluate a module's `output.files` property
and write the files specified therein.
Within `output.files`, a key determines a file's path relative to `--multiple-file-output-path`,
and a value determines the file's contents.
// suppress inspection "AsciiDocLinkResolve"
This option cannot be used together with any of the following:
* xref:output-path[`--output-path`]
* xref:expression[`--expression`]
// suppress inspection "AsciiDocLinkResolve"
This option supports the same placeholders as link:#output-path[`--output-path`].
Examples:
[source,shell]
----
# Write files to `output/`
pkl eval -m output/ myFiles.pkl
# Write files to the current working directory
pkl eval -m . myFiles.pkl
# Write foo.pkl's files to the `foo` directory, and bar.pkl's files
# to the `bar` directory
pkl eval -m "%{moduleName}" foo.pkl bar.pkl
----
For additional details, see xref:language-reference:index.adoc#multiple-file-output[Multiple File Output]
in the language reference.
====
[[expression]]
.-x, --expression
[%collapsible]
====
Default: (none) +
The expression to be evaluated within the module.
This option causes Pkl to evaluate the provided expression instead of the module's `output.text` or `output.files` properties.
The resulting value is then stringified, and written to either standard out, or the designated output file.
For example, consider the following Pkl module:
.pigeon.pkl
[source%tested,{pkl}]
----
metadata {
species = "Pigeon"
}
----
The following command prints `Pigeon` to the console:
[source,shell]
----
pkl -x metadata.name pigeon.pkl
# => Pigeon
----
Setting an `--expression` flag can be thought of as substituting the expression in place of a module's `output.text` property.
Running the previous command is conceptually the same as if the below module were evaluated without the `--expression` flag:
[source,pkl]
----
metadata {
species = "Pigeon"
}
output {
text = metadata.name.toString()
}
----
====
This command also takes <<common-options, common options>>.
[[command-server]]
=== `pkl server`
*Synopsys:* `pkl server`
Run as a server that communicates over standard input/output.
This option is used for embedding Pkl in an external client, such as xref:swift:ROOT:index.adoc[pkl-swift] or xref:go:ROOT:index.adoc[pkl-go].
[[command-test]]
=== `pkl test`
*Synopsys:* `pkl test [<options>] [<modules>]`
Evaluate the given `<modules>` as _tests_, producing a test report and appropriate exit code.
Renderers defined in test files will be ignored by the `test` command.
<modules>::
The absolute or relative URIs of the modules to test. Relative URIs are resolved against the working directory.
==== Options
[[junit-reports]]
.--junit-reports
[%collapsible]
====
Default: (none) +
Example: `./build/test-results` +
Directory where to store JUnit reports.
No JUnit reports will be generated if this option is not present.
====
[[overwrite]]
.--overwrite
[%collapsible]
====
Force generation of expected examples. +
The old expected files will be deleted if present.
====
This command also takes <<common-options, common options>>.
[[command-repl]]
=== `pkl repl`
*Synopsys:* `pkl repl [<options>]`
Start a REPL session.
This command takes <<common-options, common options>>.
[[command-project-package]]
=== `pkl project package`
*Synopsis:* `pkl project package <project-dir>`
This command prepares a project to be published as a package.
Given a project directory, it creates the following artifacts:
* `<name>@<version>` - the package metadata file
* `<name>@<version>.sha256` - the dependency metadata file's SHA-256 checksum
* `<name>@<version>.zip` - the package archive
* `<name>@<version>.zip.sha256` - the package archive's SHA-256 checksum
These artifacts are expected to be published to an HTTPS server, such that the metadata and zip files can be fetched at their expected locations.
The package ZIP should be available at the `packageZipUrl` location specified in the `PklProject` file
The package metadata should be available at the package URI's derived HTTPS URL.
For example, given package `package://example.com/mypackage@1.0.0`, the metadata file should be published to `+https://example.com/mypackage@1.0.0+`.
During packaging, this command runs these additional steps:
1. Run the package's API tests, if any are defined.
2. Validates that if the package has already been published, that the package's metadata is identical. This step can be skipped using the `--skip-publish-check` flag.
Examples:
[source,shell]
----
# Search the current working directory for a project, and package it.
pkl project package
# Package all projects within the `packages/` directory to `.out`, writing each package's artifacts to its own directory.
pkl project package --output-path ".out/%{name}@%{version}/" packages/*/
----
==== Options
.--output-path
[%collapsible]
====
Default: `.out`
The directory to write artifacts to.
Accepts the following placeholders:
`%\{name}`:: The name of the package
`%\{version}`:: The version of the package
====
.--skip-publish-check
[%collapsible]
====
Skips checking whether a package has already been published with different contents.
By default, the packager will check whether a package at the same version has already been published.
If the package has been published, it validates that the package's metadata is identical to the locally generated metadata.
====
.--junit-reports
[%collapsible]
====
Default: (none) +
Example: `./build/test-results` +
Directory where to store JUnit reports.
No JUnit reports will be generated if this option is not present.
====
.--overwrite
[%collapsible]
====
Force generation of expected examples. +
The old expected files will be deleted if present.
====
This command also takes <<common-options,common options>>.
[[command-project-resolve]]
=== `pkl project resolve`
*Synopsis:* `pkl project resolve <project-dir>`
This command takes the dependencies of a project, and writes the resolved versions a file at path `PklProject.deps.json`.
It builds a dependency list, taking the latest minor version in case of version conflicts.
For more details, see the xref:language-reference:index.adoc#resolving-dependencies[resolving dependencies] section of the language reference.
Examples:
[source,shell]
----
# Search the current working directory for a project, and resolve its dependencies.
pkl project resolve
# Resolve dependencies for all projects within the `packages/` directory.
pkl project resolve packages/*/
----
==== Options
This command accepts <<common-options,common options>>.
[[command-download-package]]
=== `pkl download-package`
*Synopsis*: `pkl download-package <package-uri>`
This command downloads the specified packages to the cache directory.
If the
package already exists in the cache directory, this command is a no-op.
==== Options
This command accepts <<common-options,common options>>.
[[common-options]]
=== Common options
The <<command-eval>>, <<command-test>>, <<command-repl>>, <<command-project-resolve>>, <<command-project-package>>, and <<command-download-package>> commands support the following common options:
include::../../pkl-cli/partials/cli-common-options.adoc[]
The <<command-eval>>, <<command-test>>, <<command-repl>>, and <<command-download-package>> commands also take the following options:
include::../../pkl-cli/partials/cli-project-options.adoc[]
== Evaluating Modules
Say we have the following module:
[[config.pkl]]
.config.pkl
[source,{pkl}]
----
bird {
species = "Pigeon"
diet = "Seeds"
}
parrot = (bird) {
species = "Parrot"
diet = "Berries"
}
----
To evaluate this module and write its output to standard output, run:
[source,shell]
----
pkl eval config.pkl
----
You should see the following output:
[source,{pkl}]
----
bird {
species = "Pigeon"
diet = "Seeds"
}
parrot {
species = "Parrot"
diet = "Berries"
}
----
To render output as JSON, YAML, XML property list, or Java properties,
use `--format json`, `--format yaml`, `--format plist`, or `--format properties`, respectively.
To control the output format from within Pkl code, see xref:language-reference:index.adoc#module-output[Module Output].
To read a source module from standard input rather than a file, use `-` as a module name:
[source,shell]
----
echo mod2.pkl | pkl eval mod1.pkl - mod3.pkl
----
This is especially useful in environments that don't support `/dev/stdin`.
To write output to a file rather than standard output, use `--output-path some/file.ext`.
[[batch-evaluation]]
=== Batch Evaluation
Multiple modules can be evaluated at once:
[source,shell]
----
pkl eval config1.pkl config2.pkl config3.pkl
----
To write module outputs to separate output files, `--output-path` supports the following placeholders:
`%\{moduleDir}`:: the directory path of the source module, relative to the working directory (only available for file based modules)
`%\{moduleName}`:: the last path segment of the module URI, without file extension
`%\{outputFormat}`:: the target format (only available if `--format` is set)
The following run produces three JSON files placed next to the given source modules:
[source,shell]
----
pkl eval --format=json --output-path=%{moduleDir}/%{moduleName}.json config1.pkl config2.pkl config3.pkl
----
If multiple module outputs are written to the same file, or to standard output, their outputs are concatenated.
By default, module outputs are separated with `---`, as in a YAML stream.
The separator can be customized using the `--module-output-separator` option.
[[repl]]
== Working with the REPL
To start a REPL session, run `pkl repl`:
[source,shell]
[subs="+attributes"]
----
$ pkl repl
Welcome to Pkl {pkl-version}.
Type an expression to have it evaluated.
Type :help or :examples for more information.
pkl>
----
NOTE: The Java executable is named `jpkl`.
=== Loading Modules
To load <<config.pkl,`config.pkl`>> into the REPL, run:
[source,shell]
----
pkl> :load config.pkl
----
To evaluate the `bird.name` property, run:
[source,shell]
----
pkl> bird.name
"Pigeon"
----
To evaluate the entire module, force-evaluate `this`:
[source,shell]
----
pkl> :force this
----
=== REPL Commands
Commands start with `:` and can be tab-completed:
[source,shell]
[subs="+attributes,+macros"]
----
pkl> :{empty}kbd:[Tab]
clear examples force help load quit reset
pkl> :q{empty}kbd:[Tab]
pkl> :quit{empty}kbd:[Return]
$
----
Commands can be abbreviated with any unique name prefix:
[source,shell]
[subs="+attributes,+macros"]
----
pkl> :q{empty}kbd:[Return]
$
----
To learn more about each command, run the `:help` command.
Some commands support further command-specific tab completion.
For example, the `:load` command supports completing file paths.
With commands out of the way, let's move on to evaluating code.
=== Evaluating Code
To evaluate an expression, type the expression and hit kbd:[Return].
[source,shell]
----
pkl> 2 + 4
6
----
Apart from expressions, the REPL also accepts property, function, and class definitions.
(See the xref:language-reference:index.adoc[Language Reference] to learn more about these language concepts.)
[source,shell]
----
pkl> hello = "Hello, World!"
pkl> hello
"Hello, World!"
pkl> function double(n) = 2 * n
pkl> double(5)
10
pkl> class Bird { name: String }
pkl> new Bird { species = "Pigeon" }
{
name = ?
}
----
Top-level expressions are only supported in the REPL.
In a regular module, every expression is contained in a definition, and only definitions exist at the top level.
=== Redefining Members
Existing members can be redefined:
[source,shell]
----
pkl> species = "Pigeon"
pkl> species
"Pigeon"
pkl> species = "Barn"
pkl> species
"Barn"
pkl> species += " Owl"
pkl> species
"Barn owl"
----
Due to Pkl's late binding semantics, redefining a member affects dependent members:
[source,shell]
----
pkl> name = "Barn"
pkl> species = "$name Owl"
pkl> species
"Barn owl"
pkl> name = "Elf"
pkl> species
"Elf Owl"
----
Redefining members is only supported in the REPL. Under the hood,
it works as follows:
* The REPL environment is represented as a synthetic Pkl module.
* When a new member is defined, it is added to the current REPL module.
* When an existing member is redefined, it is added to a new REPL module that xref:language-reference:index.adoc#module-amend[amends] the previous REPL module.
[[settings-file]]
== Settings File
The Pkl settings file allows to customize the CLI experience.
A settings file is a Pkl module amending the `pkl.settings` standard library module.
Its default location is `~/.pkl/settings.pkl`.
To use a different settings file, set the `--settings` command line option, for example `--settings mysettings.pkl`.
To enforce default settings, use `--settings pkl:settings`.
The settings file is also honored by (and configurable through) the Gradle plugin and `CliEvaluator` API.
Here is a typical settings file:
.~/.pkl/settings.pkl
[source%parsed,{pkl}]
----
amends "pkl:settings" // <1>
editor = Idea // <2>
----
<1> A settings file should amend the `pkl.settings` standard library module.
<2> Configures IntelliJ IDEA as the preferred editor.
Other supported values are `System`, `GoLand`, `TextMate`, `Sublime`, `Atom`, and `VsCode`.
With the above settings file in place, kbd:[Cmd]+Double-clicking a source code link in a stack trace opens the corresponding file in IntelliJ IDEA at the correct location.
To learn more about available settings, see link:{uri-pkl-stdlib-docs-settings}[pkl.settings].
[[ca-certs]]
== CA Certificates
When making TLS requests, Pkl comes with its own set of {uri-certificates}[CA certificates].
These certificates can be overridden via either of the two options:
- Set them directly via the CLI option `--ca-certificates <path>`.
- Add them to a directory at path `~/.pkl/cacerts/`.
Both these options will *replace* the default CA certificates bundled with Pkl. +
The CLI option takes precedence over the certificates in `~/.pkl/cacerts/`. +
Certificates need to be X.509 certificates in PEM format.

View File

@@ -0,0 +1,124 @@
[[allowed-modules]]
.--allowed-modules
[%collapsible]
====
Default: `pkl:,file:,modulepath:,https:,repl:,package:,projectpackage:` +
Comma-separated list of URI patterns that determine which modules can be loaded and evaluated.
Patterns are matched against the beginning of module URIs.
(File paths have been converted to `file:` URLs at this stage.)
At least one pattern needs to match for a module to be loadable.
Both source modules and transitive modules are subject to this check.
====
[[allowed-resources]]
.--allowed-resources
[%collapsible]
====
Default: `env:,prop:,package:,projectpackage:` +
Comma-separated list of URI patterns that determine which external resources can be read.
Patterns are matched against the beginning of resource URIs.
At least one pattern needs to match for a resource to be readable.
====
[[cache-dir]]
.--cache-dir
[%collapsible]
====
Default: `~/.pkl/cache` +
Example: `/path/to/module/cache/` +
The cache directory for storing packages.
====
.--no-cache
[%collapsible]
====
Disable cacheing of packages.
====
.-e, --env-var
[%collapsible]
====
Default: OS environment variables for the current process +
Example: `MY_VAR=myValue` +
Sets an environment variable that can be read by Pkl code with `read("env:<envVarName>")`.
Repeat this option to set multiple environment variables.
====
.-h, --help
[%collapsible]
====
Display help information.
====
.--module-path
[%collapsible]
====
Default: (empty) +
Example: `dir1:zip1.zip:jar1.jar` +
Directories, ZIP archives, or JAR archives to search when resolving `modulepath:` URIs.
Paths are separated by the platform-specific path separator (`:` on *nix, `;` on Windows).
Relative paths are resolved against the working directory.
====
.-p, --property
[%collapsible]
====
Default: (none) +
Example: `myProp=myValue` +
Sets an external property that can be read by Pkl code with `read("prop:<propertyName>")`.
Repeat this option to set multiple external properties.
====
.--root-dir
[%collapsible]
====
Default: (none) +
Example: `/some/path` +
Root directory for `file:` modules and resources.
If set, access to file-based modules and resources is restricted to those located under the specified root directory.
Any symlinks are resolved before this check is performed.
====
.--settings
[%collapsible]
====
Default: (none) +
Example: `mySettings.pkl` +
File path of the Pkl settings file to use.
If not set, `~/.pkl/settings.pkl` or defaults specified in the `pkl.settings` standard library module are used.
====
.-t, --timeout
[%collapsible]
====
Default: (none) +
Example: `30` +
Duration, in seconds, after which evaluation of a source module will be timed out.
Note that a timeout is treated the same as a program error in that any subsequent source modules will not be evaluated.
====
.-v, --version
[%collapsible]
====
Display version information.
====
.-w, --working-dir
[%collapsible]
====
Base path that relative module paths passed as command-line arguments are resolved against.
Defaults to the current working directory.
====
.--ca-certificates
[%collapsible]
====
Default: (none) +
Example: `/some/path/certificates.pem` +
Path to a file containing CA certificates to be used for TLS connections.
Setting this option replaces the existing set of CA certificates bundled into the CLI.
Certificates need to be X.509 certificates in PEM format.
For other methods of configuring certificates, see xref:pkl-cli:index.adoc#ca-certs[CA Certificates].
====

View File

@@ -0,0 +1,26 @@
[[project-dir]]
.--project-dir
[%collapsible]
====
Default: (none) +
Example: `/some/path` +
Directory where the project lives.
A project is a directory that contains a `PklProject` file, which is used to declare package dependencies, as well as common evaluator settings to be applied in the project.
If omitted, this is determined by searching up from the working directory for a directory that contains a `PklProject` file, until `--root-dir` or the file system root is reached.
====
[[omit-project-settings]]
.--omit-project-settings
[%collapsible]
====
Disables loading evaluator settings from the PklProject file.
====
[[no-project]]
.--no-project
[%collapsible]
====
Disables all behavior related to projects.
====

View File

@@ -0,0 +1,26 @@
import org.pkl.core.Evaluator;
import org.pkl.core.ModuleSource;
import java.util.List;
import org.pkl.core.PModule;
import org.pkl.core.PObject;
import org.junit.jupiter.api.Test;
// the pkl/pkl-examples repo has a similar example
@SuppressWarnings({"unchecked", "unused", "ConstantConditions"})
public class CoreEvaluatorExample {
@Test
public void usage() {
// tag::usage[]
PModule module;
try (var evaluator =
Evaluator.preconfigured()) { // <1>
module = evaluator.evaluate(
ModuleSource.text("pigeon { age = 30; hobbies = List(\"swimming\", \"surfing\") }")); // <2>
}
var pigeon = (PObject) module.get("pigeon"); // <3>
var className = pigeon.getClassInfo().getQualifiedName(); // <4>
var hobbies = (List<String>) pigeon.get("hobbies"); // <5>
// end::usage[]
}
}

View File

@@ -0,0 +1,127 @@
= pkl-core Library
include::ROOT:partial$component-attributes.adoc[]
:uri-pkl-core-maven-module: {uri-maven-docsite}/artifact/org.pkl-lang/pkl-core
:uri-pkl-core-main-sources: {uri-github-tree}/pkl-core/src/main/java/org/pkl/core
:uri-pkl-core-test-sources: {uri-github-tree}/pkl-core/src/test/java/org/pkl/core
:uri-pkl-core-Evaluator: {uri-pkl-core-main-sources}/Evaluator.java
:uri-pkl-core-PModule: {uri-pkl-core-main-sources}/PModule.java
:uri-pkl-core-PklException: {uri-pkl-core-main-sources}/PklException.java
:uri-pkl-core-ValueVisitor: {uri-pkl-core-main-sources}/ValueVisitor.java
:uri-pkl-core-JsonRenderer: {uri-pkl-core-main-sources}/JsonRenderer.java
:uri-pkl-core-PcfRenderer: {uri-pkl-core-main-sources}/PcfRenderer.java
:uri-pkl-core-PListRenderer: {uri-pkl-core-main-sources}/PListRenderer.java
:uri-pkl-core-YamlRenderer: {uri-pkl-core-main-sources}/YamlRenderer.java
:uri-pkl-core-SecurityManagers: {uri-pkl-core-main-sources}/SecurityManagers.java
:uri-pkl-core-ModuleKeyFactories: {uri-pkl-core-main-sources}/module/ModuleKeyFactories.java
The _pkl-core_ library contains the Pkl parser, evaluator, REPL server, and xref:ROOT:standard-library.adoc[Standard Library].
It is the foundation for most of Pkl's other libraries and tools.
The library can also be used to embed Pkl in Java libraries and applications.
[[pkl-core-installation]]
== Installation
The _pkl-core_ library is available {uri-pkl-core-maven-module}[from Maven Central].
It requires Java 11 or higher.
=== Gradle
To use the library in a Gradle project, declare the following dependency:
[tabs]
====
Groovy::
+
.build.gradle
[source,groovy,subs="+attributes"]
----
dependencies {
compile "org.pkl-lang:pkl-core:{pkl-artifact-version}"
}
ifndef::is-release-build[]
repositories {
maven { url "{uri-sonatype}" }
}
endif::[]
----
Kotlin::
+
.build.gradle.kts
[source,kotlin,subs="+attributes"]
----
dependencies {
compile("org.pkl-lang:pkl-core:{pkl-artifact-version}")
}
ifndef::is-release-build[]
repositories {
maven { url = uri("{uri-sonatype}") }
}
endif::[]
----
====
=== Maven
To use the library in a Maven project, declare the following dependency:
.pom.xml
[source,xml,subs="+attributes"]
----
<project>
<dependency>
<groupId>org.pkl-lang</groupId>
<artifactId>pkl-core</artifactId>
<version>{pkl-artifact-version}</version>
</dependency>
ifndef::is-release-build[]
<repositories>
<repository>
<id>sonatype-s01</id>
<name>Sonatype S01</name>
<url>{uri-sonatype}</url>
</repository>
</repositories>
endif::[]
</project>
----
== Usage
{uri-pkl-core-Evaluator}[`Evaluator`] is the core evaluator that exposes multiple methods of evaluation.
The main evaluation method is `evaluate`, which returns a Java representation of the Pkl module object.
If evaluation succeeds, a {uri-pkl-core-PModule}[`PModule`] object representing the fully evaluated module is returned.
Otherwise, an {uri-pkl-core-PklException}[`PklException`] with error details is thrown.
Let's look at an example:
[[config-evaluator-core-example]]
[source,java,indent=0]
----
include::{examplesdir}/CoreEvaluatorExample.java[tags=usage]
----
<1> Build an `Evaluator` with default configuration.
The evaluator should be closed once it is no longer needed.
In this example, this is done with a try-with-resources statement.
Note that objects returned by the evaluator remain valid after calling `close()`.
<2> Build a `ModuleSource` using the given text as the module's contents. Evaluate the given module source. Alternatively, it's possible to build a `ModuleSource` from a file, path, uri, and other sources.
<3> Get the module's `"pigeon"` property, which is represented as `PObject` in Java.
<4> Get the class name for this object. In this example, the class name is `pkl.base#Dynamic`.
<5> Get pigeon's `"diet"` property, which is represented as `List<String>` in Java.
[[value-visitor]]
Often, {uri-pkl-core-ValueVisitor}[`ValueVisitor`] is a better way to process a module.
See {uri-pkl-core-PcfRenderer}[`PcfRenderer`], {uri-pkl-core-JsonRenderer}[`JsonRenderer`], {uri-pkl-core-YamlRenderer}[`YamlRenderer`] and {uri-pkl-core-PListRenderer}[`PListRenderer`] for examples.
[[security-manager-spi]]
The (Pkl, not Java) security manager can be configured and customized using {uri-pkl-core-SecurityManagers}[`SecurityManagers`] and related classes.
[[module-loader-spi]]
Module loaders can be configured and customized using {uri-pkl-core-ModuleKeyFactories}[`ModuleKeyFactories`] and related classes.
== Further Information
Refer to the Javadoc and sources published with the library, or browse the library's {uri-pkl-core-main-sources}[main] and {uri-pkl-core-test-sources}[test] sources.

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 KiB

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