Compare commits
69
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
975de92001 | ||
|
|
2d7a368b48 | ||
|
|
155fc5a867 | ||
|
|
5b53816463 | ||
|
|
095f064148 | ||
|
|
1c785a75af | ||
|
|
72b237e204 | ||
|
|
c43feddbac | ||
|
|
c39b1e7a59 | ||
|
|
3dccfe3d8b | ||
|
|
fc5d658aa3 | ||
|
|
85b4a4669a | ||
|
|
1f5c62ecef | ||
|
|
7e8e5f648d | ||
|
|
875fac857c | ||
|
|
7fa1ce7852 | ||
|
|
70947166a3 | ||
|
|
56e178934a | ||
|
|
ffd8a5d484 | ||
|
|
a9b7fe3a33 | ||
|
|
6ad50eb589 | ||
|
|
d54dda0d83 | ||
|
|
89cb6c98a1 | ||
|
|
5cb5d41a44 | ||
|
|
b1b36b09ac | ||
|
|
0b582b50b4 | ||
|
|
99c2d84c43 | ||
|
|
ec2d12a654 | ||
|
|
e0d727be60 | ||
|
|
ea68f7b258 | ||
|
|
434f699887 | ||
|
|
3e703995ca | ||
|
|
21d278eba5 | ||
|
|
939e844c03 | ||
|
|
0cb9843af7 | ||
|
|
05d8e88592 | ||
|
|
dd026c7023 | ||
|
|
dd83b9ab4f | ||
|
|
3f5797de6f | ||
|
|
ac0d9f1d31 | ||
|
|
95d7a4bcc9 | ||
|
|
23897fd8c3 | ||
|
|
f7adfceaeb | ||
|
|
a06684b2c0 | ||
|
|
ce977f1ffe | ||
|
|
08f0c3781b | ||
|
|
97c73e7c28 | ||
|
|
78c0ebce9d | ||
|
|
ef5e34c210 | ||
|
|
e18d962033 | ||
|
|
9f79fe47da | ||
|
|
b97abe13bc | ||
|
|
fe96e0b1b0 | ||
|
|
eff9a9e164 | ||
|
|
8399f11186 | ||
|
|
6811abf11c | ||
|
|
f96fba00e1 | ||
|
|
d062312df9 | ||
|
|
f4ad0da658 | ||
|
|
88a50d167e | ||
|
|
f973fd6717 | ||
|
|
66fb5c133b | ||
|
|
1a3d7a1a76 | ||
|
|
862c61f2e2 | ||
|
|
dbcecd9677 | ||
|
|
ba25f4820c | ||
|
|
adaafc4045 | ||
|
|
82fe176c69 | ||
|
|
6423b2add5 |
No files matched your search
+1
-1
@@ -227,7 +227,7 @@ release {
|
||||
needs = releaseJobs.keys.toListing()
|
||||
}
|
||||
["github-release"] = new GithubRelease {
|
||||
needs = "deploy-release"
|
||||
needs = releaseJobs.keys.toListing()
|
||||
}
|
||||
} |> toWorkflowJobs
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ local command =
|
||||
}.join(" ")
|
||||
|
||||
steps {
|
||||
catalog.`actions/checkout@v6`
|
||||
new {
|
||||
name = "gradle build java executables"
|
||||
shell = "bash"
|
||||
|
||||
@@ -68,6 +68,19 @@ steps {
|
||||
path = module.buildDir
|
||||
}
|
||||
}
|
||||
(catalog.`actions/upload-artifact@v5`) {
|
||||
name = "Upload compiled classes list"
|
||||
with {
|
||||
name =
|
||||
if (musl)
|
||||
"compiled-classes-\(project)-alpine-\(module.os)-\(module.arch)"
|
||||
else
|
||||
"compiled-classes-\(project)-\(module.os)-\(module.arch)"
|
||||
// Need to insert a wildcard to make actions/upload-artifact preserve the folder hierarchy.
|
||||
// See https://github.com/actions/upload-artifact/issues/206
|
||||
path = "\(project)*/build/compiled-classes/**/*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fixed job {
|
||||
|
||||
@@ -10,7 +10,7 @@ fixed job {
|
||||
permissions {
|
||||
contents = "write"
|
||||
}
|
||||
needs = "deploy-release"
|
||||
needs = module.needs
|
||||
steps {
|
||||
(catalog.`actions/download-artifact@v6`) {
|
||||
with {
|
||||
@@ -30,11 +30,12 @@ fixed job {
|
||||
run =
|
||||
#"""
|
||||
gh release create ${TAG_NAME} \
|
||||
--draft \
|
||||
--title "${TAG_NAME}" \
|
||||
--target "${GIT_SHA}" \
|
||||
--verify-tag \
|
||||
--notes "Release notes: https://pkl-lang.org/main/current/release-notes/changelog.html#release-${TAG_NAME}" \
|
||||
*/build/executable/* */build/distributions/*
|
||||
*/build/executable/*
|
||||
"""#
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@ fixed job {
|
||||
when (os == "windows") {
|
||||
["JAVA_HOME"] = "/jdk"
|
||||
}
|
||||
when (os == "macOS") {
|
||||
["DEVELOPER_DIR"] = "/Applications/Xcode_swift_6.4.app"
|
||||
}
|
||||
}
|
||||
when (os == "macOS") {
|
||||
`if` =
|
||||
@@ -65,6 +68,7 @@ fixed job {
|
||||
new Listing {
|
||||
"self-hosted"
|
||||
"macos"
|
||||
"goldengate"
|
||||
when (nightlyMacOS) {
|
||||
"nightly"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ set -e
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -34,13 +34,28 @@ if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
>From 7813e9119eb5fe681b6750b8a033a0490bca0941 Mon Sep 17 00:00:00 2001
|
||||
From: Szabolcs Nagy <nsz@port70.net>
|
||||
Date: Thu, 23 Apr 2026 21:22:18 +0000
|
||||
Subject: [PATCH] regex: avoid int overflow in regcomp
|
||||
|
||||
regcomp has many int arith ops that may overflow. before tre_expand_ast
|
||||
int values are limited by 2x the input length n, e.g.:
|
||||
|
||||
input ERE int field max value
|
||||
aaaaaaaaaaaa... position n
|
||||
()()()()()()... submatch_id n/2+1
|
||||
()||||||||||... num_tags 2n-3
|
||||
|
||||
so overflow before expand requires large n (and a lot of memory). later
|
||||
some values can become big due to repetitions:
|
||||
|
||||
input ERE int field that overflows
|
||||
(((a{255}){255}){255}){255} position
|
||||
((a|b*){255,}){255,} num_transitions
|
||||
|
||||
num_transitions and memory use can be big without {k,} repetitions too:
|
||||
|
||||
input ERE what max value
|
||||
(a|a|a|a...|a)* num_transitions n^2/4
|
||||
(()|a|a|...|a)* sum tnfa tags > n^3/16 - n^2
|
||||
|
||||
so memory can run out quickly as n grows (with 31bit va space 1700 long
|
||||
input is enough even without {k,}) about half is tnfa and half is ast
|
||||
firstpos/lastpos data. but overflow can happen before allocations fail.
|
||||
|
||||
fix early overflow by limiting n. the stack usage is in [n,11n] without
|
||||
repetitions, usually 7n, so the stack limit got adjusted too. the limit
|
||||
is such that almost all inputs that worked before still work.
|
||||
|
||||
overflows during and after expand are fixed by explicit checks via a
|
||||
check_add helper and xcalloc instead of xmalloc.
|
||||
---
|
||||
src/regex/regcomp.c | 41 +++++++++++++++++++++++++++++++++++------
|
||||
1 file changed, 35 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/regex/regcomp.c b/src/regex/regcomp.c
|
||||
index b4b81968..a7115b12 100644
|
||||
--- a/src/regex/regcomp.c
|
||||
+++ b/src/regex/regcomp.c
|
||||
@@ -1680,6 +1680,12 @@ tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree,
|
||||
AST to TNFA compilation routines.
|
||||
*/
|
||||
|
||||
+/* check if a+b overflows for a,b in [0,INT_MAX] */
|
||||
+static int check_add(unsigned a, unsigned b)
|
||||
+{
|
||||
+ return a + b > INT_MAX;
|
||||
+}
|
||||
+
|
||||
typedef enum {
|
||||
COPY_RECURSE,
|
||||
COPY_SET_RESULT_PTR
|
||||
@@ -1731,6 +1737,8 @@ tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
|
||||
/* XXX - e.g. [ab] has only one position but two
|
||||
nodes, so we are creating holes in the state space
|
||||
here. Not fatal, just wastes memory. */
|
||||
+ if (check_add(pos, *pos_add))
|
||||
+ return REG_ESPACE;
|
||||
pos += *pos_add;
|
||||
num_copied++;
|
||||
}
|
||||
@@ -1826,6 +1834,8 @@ tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
|
||||
break;
|
||||
}
|
||||
}
|
||||
+ if (check_add(*pos_add, num_copied))
|
||||
+ return REG_ESPACE;
|
||||
*pos_add += num_copied;
|
||||
return status;
|
||||
}
|
||||
@@ -1870,6 +1880,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
|
||||
tre_literal_t *lit= node->obj;
|
||||
if (!IS_SPECIAL(lit) || IS_BACKREF(lit))
|
||||
{
|
||||
+ if (check_add(lit->position, pos_add))
|
||||
+ return REG_ESPACE;
|
||||
lit->position += pos_add;
|
||||
if (lit->position > max_pos)
|
||||
max_pos = lit->position;
|
||||
@@ -1998,6 +2010,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
|
||||
}
|
||||
|
||||
iter_depth--;
|
||||
+ if (check_add(pos_add_total, pos_add - pos_add_last))
|
||||
+ return REG_ESPACE;
|
||||
pos_add_total += pos_add - pos_add_last;
|
||||
if (iter_depth == 0)
|
||||
pos_add = pos_add_total;
|
||||
@@ -2010,6 +2024,8 @@ tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
|
||||
}
|
||||
}
|
||||
|
||||
+ if (check_add(*position, pos_add_total))
|
||||
+ return REG_ESPACE;
|
||||
*position += pos_add_total;
|
||||
|
||||
/* `max_pos' should never be larger than `*position' if the above
|
||||
@@ -2711,9 +2727,19 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags)
|
||||
/* Parse context. */
|
||||
tre_parse_ctx_t parse_ctx;
|
||||
|
||||
+ /* Limits: before tre_expand_ast, int values like position, subid or
|
||||
+ * num_tags are bounded by 2x input length, used stack entries are
|
||||
+ * bounded by 16x input length. input length is checked upfront to
|
||||
+ * avoid overflows before expand. later, values that can grow big are
|
||||
+ * bounds checked via check_add and xcalloc. */
|
||||
+ const int input_limit = 1024000;
|
||||
+ const int stack_limit = 8*input_limit;
|
||||
+ if (strnlen(regex, input_limit) >= input_limit)
|
||||
+ return REG_ESPACE;
|
||||
+
|
||||
/* Allocate a stack used throughout the compilation process for various
|
||||
purposes. */
|
||||
- stack = tre_stack_new(512, 1024000, 128);
|
||||
+ stack = tre_stack_new(512, stack_limit, 128);
|
||||
if (!stack)
|
||||
return REG_ESPACE;
|
||||
/* Allocate a fast memory allocator. */
|
||||
@@ -2801,9 +2827,12 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags)
|
||||
for example "a*" or "ab*". Figure out a simple way to detect
|
||||
this possibility. */
|
||||
tmp_ast_l = tree;
|
||||
- tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position++);
|
||||
+ tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position);
|
||||
if (tmp_ast_r == NULL)
|
||||
ERROR_EXIT(REG_ESPACE);
|
||||
+ if (check_add(parse_ctx.position, 1))
|
||||
+ ERROR_EXIT(REG_ESPACE);
|
||||
+ parse_ctx.position++;
|
||||
|
||||
tree = tre_ast_new_catenation(mem, tmp_ast_l, tmp_ast_r);
|
||||
if (tree == NULL)
|
||||
@@ -2813,22 +2842,22 @@ regcomp(regex_t *restrict preg, const char *restrict regex, int cflags)
|
||||
if (errcode != REG_OK)
|
||||
ERROR_EXIT(errcode);
|
||||
|
||||
- counts = xmalloc(sizeof(int) * parse_ctx.position);
|
||||
+ counts = xcalloc(sizeof(int), parse_ctx.position);
|
||||
if (counts == NULL)
|
||||
ERROR_EXIT(REG_ESPACE);
|
||||
|
||||
- offs = xmalloc(sizeof(int) * parse_ctx.position);
|
||||
+ offs = xcalloc(sizeof(int), parse_ctx.position);
|
||||
if (offs == NULL)
|
||||
ERROR_EXIT(REG_ESPACE);
|
||||
|
||||
- for (i = 0; i < parse_ctx.position; i++)
|
||||
- counts[i] = 0;
|
||||
tre_ast_to_tnfa(tree, NULL, counts, NULL);
|
||||
|
||||
add = 0;
|
||||
for (i = 0; i < parse_ctx.position; i++)
|
||||
{
|
||||
offs[i] = add;
|
||||
+ if (check_add(add, counts[i] + 1))
|
||||
+ ERROR_EXIT(REG_ESPACE);
|
||||
add += counts[i] + 1;
|
||||
counts[i] = 0;
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
@@ -0,0 +1,177 @@
|
||||
>From 228da39e38c1cae13cbe637e771412c1984dba5d Mon Sep 17 00:00:00 2001
|
||||
From: Rich Felker <dalias@aerifal.cx>
|
||||
Date: Thu, 9 Apr 2026 22:51:30 -0400
|
||||
Subject: [PATCH 1/3] qsort: fix leonardo heap corruption from bug in
|
||||
doubleword ctz primitive
|
||||
|
||||
the pntz function, implementing a "count trailing zeros" variant for a
|
||||
bit vector consisting of two size_t words, erroneously returned zero
|
||||
rather than the number of bits in the low word when the first bit set
|
||||
was the low bit of the high word.
|
||||
|
||||
as a result, a loop in the trinkle function which should have a
|
||||
guaranteed small bound on the number of iterations, could run
|
||||
unboundedly, thereby overflowing a stack-based working-space array
|
||||
which was sized for the bound.
|
||||
|
||||
CVE-2026-40200 has been assigned for this issue.
|
||||
---
|
||||
src/stdlib/qsort.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c
|
||||
index ab79dc6f..13219ab3 100644
|
||||
--- a/src/stdlib/qsort.c
|
||||
+++ b/src/stdlib/qsort.c
|
||||
@@ -34,11 +34,11 @@
|
||||
|
||||
typedef int (*cmpfun)(const void *, const void *, void *);
|
||||
|
||||
+/* returns index of first bit set, excluding the low bit assumed to always
|
||||
+ * be set, starting from low bit of p[0] up through high bit of p[1] */
|
||||
static inline int pntz(size_t p[2]) {
|
||||
- int r = ntz(p[0] - 1);
|
||||
- if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) {
|
||||
- return r;
|
||||
- }
|
||||
+ if (p[0] != 1) return ntz(p[0] - 1);
|
||||
+ if (p[1]) return 8*sizeof(size_t) + ntz(p[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.21.0
|
||||
|
||||
|
||||
>From b3291b9a9f77f1f993d2b4f8c68a26cf09221ae7 Mon Sep 17 00:00:00 2001
|
||||
From: Rich Felker <dalias@aerifal.cx>
|
||||
Date: Thu, 9 Apr 2026 23:40:53 -0400
|
||||
Subject: [PATCH 2/3] qsort: hard-preclude oob array writes independent of any
|
||||
invariants
|
||||
|
||||
while the root cause of CVE-2026-40200 was a faulty ctz primitive, the
|
||||
fallout of the bug would have been limited to erroneous sorting or
|
||||
infinite loop if not for the stores to a stack-based array that
|
||||
depended on trusting invariants in order not to go out of bounds.
|
||||
|
||||
increase the size of the array to a power of two so that we can mask
|
||||
indices into it to force them into range. in the absence of any
|
||||
further bug, the masking is a no-op, but it does not have any
|
||||
measurable performance cost, and it makes spatial memory safety
|
||||
trivial to prove (and for readers not familiar with the algorithms to
|
||||
trust).
|
||||
---
|
||||
src/stdlib/qsort.c | 20 +++++++++++++-------
|
||||
1 file changed, 13 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c
|
||||
index 13219ab3..e4bce9f7 100644
|
||||
--- a/src/stdlib/qsort.c
|
||||
+++ b/src/stdlib/qsort.c
|
||||
@@ -89,10 +89,16 @@ static inline void shr(size_t p[2], int n)
|
||||
p[1] >>= n;
|
||||
}
|
||||
|
||||
+/* power-of-two length for working array so that we can mask indices and
|
||||
+ * not depend on any invariant of the algorithm for spatial memory safety.
|
||||
+ * the original size was just 14*sizeof(size_t)+1 */
|
||||
+#define AR_LEN (16 * sizeof(size_t))
|
||||
+#define AR_MASK (AR_LEN - 1)
|
||||
+
|
||||
static void sift(unsigned char *head, size_t width, cmpfun cmp, void *arg, int pshift, size_t lp[])
|
||||
{
|
||||
unsigned char *rt, *lf;
|
||||
- unsigned char *ar[14 * sizeof(size_t) + 1];
|
||||
+ unsigned char *ar[AR_LEN];
|
||||
int i = 1;
|
||||
|
||||
ar[0] = head;
|
||||
@@ -104,16 +110,16 @@ static void sift(unsigned char *head, size_t width, cmpfun cmp, void *arg, int p
|
||||
break;
|
||||
}
|
||||
if(cmp(lf, rt, arg) >= 0) {
|
||||
- ar[i++] = lf;
|
||||
+ ar[i++ & AR_MASK] = lf;
|
||||
head = lf;
|
||||
pshift -= 1;
|
||||
} else {
|
||||
- ar[i++] = rt;
|
||||
+ ar[i++ & AR_MASK] = rt;
|
||||
head = rt;
|
||||
pshift -= 2;
|
||||
}
|
||||
}
|
||||
- cycle(width, ar, i);
|
||||
+ cycle(width, ar, i & AR_MASK);
|
||||
}
|
||||
|
||||
static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, size_t pp[2], int pshift, int trusty, size_t lp[])
|
||||
@@ -121,7 +127,7 @@ static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, si
|
||||
unsigned char *stepson,
|
||||
*rt, *lf;
|
||||
size_t p[2];
|
||||
- unsigned char *ar[14 * sizeof(size_t) + 1];
|
||||
+ unsigned char *ar[AR_LEN];
|
||||
int i = 1;
|
||||
int trail;
|
||||
|
||||
@@ -142,7 +148,7 @@ static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, si
|
||||
}
|
||||
}
|
||||
|
||||
- ar[i++] = stepson;
|
||||
+ ar[i++ & AR_MASK] = stepson;
|
||||
head = stepson;
|
||||
trail = pntz(p);
|
||||
shr(p, trail);
|
||||
@@ -150,7 +156,7 @@ static void trinkle(unsigned char *head, size_t width, cmpfun cmp, void *arg, si
|
||||
trusty = 0;
|
||||
}
|
||||
if(!trusty) {
|
||||
- cycle(width, ar, i);
|
||||
+ cycle(width, ar, i & AR_MASK);
|
||||
sift(head, width, cmp, arg, pshift, lp);
|
||||
}
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
|
||||
|
||||
>From 5122f9f3c99fee366167c5de98b31546312921ab Mon Sep 17 00:00:00 2001
|
||||
From: Luca Kellermann <mailto.luca.kellermann@gmail.com>
|
||||
Date: Fri, 10 Apr 2026 03:03:22 +0200
|
||||
Subject: [PATCH 3/3] qsort: fix shift UB in shl and shr
|
||||
|
||||
if shl() or shr() are called with n==8*sizeof(size_t), n is adjusted
|
||||
to 0. the shift by (sizeof(size_t) * 8 - n) that then follows will
|
||||
consequently shift by the width of size_t, which is UB and in practice
|
||||
produces an incorrect result.
|
||||
|
||||
return early in this case. the bitvector p was already shifted by the
|
||||
required amount.
|
||||
---
|
||||
src/stdlib/qsort.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/src/stdlib/qsort.c b/src/stdlib/qsort.c
|
||||
index e4bce9f7..28607450 100644
|
||||
--- a/src/stdlib/qsort.c
|
||||
+++ b/src/stdlib/qsort.c
|
||||
@@ -71,6 +71,7 @@ static inline void shl(size_t p[2], int n)
|
||||
n -= 8 * sizeof(size_t);
|
||||
p[1] = p[0];
|
||||
p[0] = 0;
|
||||
+ if (!n) return;
|
||||
}
|
||||
p[1] <<= n;
|
||||
p[1] |= p[0] >> (sizeof(size_t) * 8 - n);
|
||||
@@ -83,6 +84,7 @@ static inline void shr(size_t p[2], int n)
|
||||
n -= 8 * sizeof(size_t);
|
||||
p[0] = p[1];
|
||||
p[1] = 0;
|
||||
+ if (!n) return;
|
||||
}
|
||||
p[0] >>= n;
|
||||
p[0] |= p[1] << (sizeof(size_t) * 8 - n);
|
||||
--
|
||||
2.21.0
|
||||
@@ -0,0 +1,319 @@
|
||||
>From 67219f0130ec7c876ac0b299046460fad31caabf Mon Sep 17 00:00:00 2001
|
||||
From: Rich Felker <dalias@aerifal.cx>
|
||||
Date: Mon, 30 Mar 2026 16:00:50 -0400
|
||||
Subject: [PATCH] fix pathological slowness & incorrect mappings in iconv
|
||||
gb18030 decoder
|
||||
|
||||
in order to implement the "UTF" aspect of gb18030 (ability to
|
||||
represent arbitrary unicode characters not present in the 2-byte
|
||||
mapping), we have to apply the index obtained from the encoded 4-byte
|
||||
sequence into the set of unmapped characters. this was done by
|
||||
scanning repeatedly over the table of mapped characters and counting
|
||||
off mapped characters below a running index by which to adjust the
|
||||
running index by on each iteration. this iterative process eventually
|
||||
leaves us with the value of the Nth unmapped character replacing the
|
||||
index, but depending on which particular character that is, the number
|
||||
of iterations needed to find it can be in the tens of thousands, and
|
||||
each iteration traverses the whole 126x190 table in the inner loop.
|
||||
this can lead to run times exceeding an entire second per character on
|
||||
moderate-speed machines.
|
||||
|
||||
on top of that, the transformation logic produced wrong results for
|
||||
BMP characters above the the surrogate range, as a result of not
|
||||
correctly accounting for it being excluded, and for characters outside
|
||||
the BMP, as a result of a misunderstanding of how gb18030 encodes
|
||||
them.
|
||||
|
||||
this patch replaces the unmapped character lookup with a single linear
|
||||
search of a list of unmapped ranges. there are only 206 such ranges,
|
||||
and these are permanently assigned and unchangeable as a consequence
|
||||
of the character encoding having to be stable, so a simple array of
|
||||
16-bit start/length values for each range consumes only 824 bytes, a
|
||||
very reasonable size cost here.
|
||||
|
||||
this new table accounts for the previously-incorrect surrogate
|
||||
handling, and non-BMP characters are handled correctly by a single
|
||||
offset, without the need for any unmapped-range search.
|
||||
|
||||
there are still a small number of mappings that are incorrect due to
|
||||
late changes made in the definition of gb18030, swapping PUA
|
||||
codepoints with proper Unicode characters. correcting these requires a
|
||||
postprocessing step that will be added later.
|
||||
---
|
||||
src/locale/gb18030utf.h | 206 ++++++++++++++++++++++++++++++++++++++++
|
||||
src/locale/iconv.c | 33 +++++--
|
||||
2 files changed, 230 insertions(+), 9 deletions(-)
|
||||
create mode 100644 src/locale/gb18030utf.h
|
||||
|
||||
diff --git a/src/locale/gb18030utf.h b/src/locale/gb18030utf.h
|
||||
new file mode 100644
|
||||
index 00000000..322a2440
|
||||
--- /dev/null
|
||||
+++ b/src/locale/gb18030utf.h
|
||||
@@ -0,0 +1,206 @@
|
||||
+{ 0x80, 36 },
|
||||
+{ 0xa5, 2 },
|
||||
+{ 0xa9, 7 },
|
||||
+{ 0xb2, 5 },
|
||||
+{ 0xb8, 31 },
|
||||
+{ 0xd8, 8 },
|
||||
+{ 0xe2, 6 },
|
||||
+{ 0xeb, 1 },
|
||||
+{ 0xee, 4 },
|
||||
+{ 0xf4, 3 },
|
||||
+{ 0xf8, 1 },
|
||||
+{ 0xfb, 1 },
|
||||
+{ 0xfd, 4 },
|
||||
+{ 0x102, 17 },
|
||||
+{ 0x114, 7 },
|
||||
+{ 0x11c, 15 },
|
||||
+{ 0x12c, 24 },
|
||||
+{ 0x145, 3 },
|
||||
+{ 0x149, 4 },
|
||||
+{ 0x14e, 29 },
|
||||
+{ 0x16c, 98 },
|
||||
+{ 0x1cf, 1 },
|
||||
+{ 0x1d1, 1 },
|
||||
+{ 0x1d3, 1 },
|
||||
+{ 0x1d5, 1 },
|
||||
+{ 0x1d7, 1 },
|
||||
+{ 0x1d9, 1 },
|
||||
+{ 0x1db, 1 },
|
||||
+{ 0x1dd, 28 },
|
||||
+{ 0x1fa, 87 },
|
||||
+{ 0x252, 15 },
|
||||
+{ 0x262, 101 },
|
||||
+{ 0x2c8, 1 },
|
||||
+{ 0x2cc, 13 },
|
||||
+{ 0x2da, 183 },
|
||||
+{ 0x3a2, 1 },
|
||||
+{ 0x3aa, 7 },
|
||||
+{ 0x3c2, 1 },
|
||||
+{ 0x3ca, 55 },
|
||||
+{ 0x402, 14 },
|
||||
+{ 0x450, 1 },
|
||||
+{ 0x452, 7102 },
|
||||
+{ 0x2011, 2 },
|
||||
+{ 0x2017, 1 },
|
||||
+{ 0x201a, 2 },
|
||||
+{ 0x201e, 7 },
|
||||
+{ 0x2027, 9 },
|
||||
+{ 0x2031, 1 },
|
||||
+{ 0x2034, 1 },
|
||||
+{ 0x2036, 5 },
|
||||
+{ 0x203c, 112 },
|
||||
+{ 0x20ad, 86 },
|
||||
+{ 0x2104, 1 },
|
||||
+{ 0x2106, 3 },
|
||||
+{ 0x210a, 12 },
|
||||
+{ 0x2117, 10 },
|
||||
+{ 0x2122, 62 },
|
||||
+{ 0x216c, 4 },
|
||||
+{ 0x217a, 22 },
|
||||
+{ 0x2194, 2 },
|
||||
+{ 0x219a, 110 },
|
||||
+{ 0x2209, 6 },
|
||||
+{ 0x2210, 1 },
|
||||
+{ 0x2212, 3 },
|
||||
+{ 0x2216, 4 },
|
||||
+{ 0x221b, 2 },
|
||||
+{ 0x2221, 2 },
|
||||
+{ 0x2224, 1 },
|
||||
+{ 0x2226, 1 },
|
||||
+{ 0x222c, 2 },
|
||||
+{ 0x222f, 5 },
|
||||
+{ 0x2238, 5 },
|
||||
+{ 0x223e, 10 },
|
||||
+{ 0x2249, 3 },
|
||||
+{ 0x224d, 5 },
|
||||
+{ 0x2253, 13 },
|
||||
+{ 0x2262, 2 },
|
||||
+{ 0x2268, 6 },
|
||||
+{ 0x2270, 37 },
|
||||
+{ 0x2296, 3 },
|
||||
+{ 0x229a, 11 },
|
||||
+{ 0x22a6, 25 },
|
||||
+{ 0x22c0, 82 },
|
||||
+{ 0x2313, 333 },
|
||||
+{ 0x246a, 10 },
|
||||
+{ 0x249c, 100 },
|
||||
+{ 0x254c, 4 },
|
||||
+{ 0x2574, 13 },
|
||||
+{ 0x2590, 3 },
|
||||
+{ 0x2596, 10 },
|
||||
+{ 0x25a2, 16 },
|
||||
+{ 0x25b4, 8 },
|
||||
+{ 0x25be, 8 },
|
||||
+{ 0x25c8, 3 },
|
||||
+{ 0x25cc, 2 },
|
||||
+{ 0x25d0, 18 },
|
||||
+{ 0x25e6, 31 },
|
||||
+{ 0x2607, 2 },
|
||||
+{ 0x260a, 54 },
|
||||
+{ 0x2641, 1 },
|
||||
+{ 0x2643, 2110 },
|
||||
+{ 0x2e82, 2 },
|
||||
+{ 0x2e85, 3 },
|
||||
+{ 0x2e89, 2 },
|
||||
+{ 0x2e8d, 10 },
|
||||
+{ 0x2e98, 15 },
|
||||
+{ 0x2ea8, 2 },
|
||||
+{ 0x2eab, 3 },
|
||||
+{ 0x2eaf, 4 },
|
||||
+{ 0x2eb4, 2 },
|
||||
+{ 0x2eb8, 3 },
|
||||
+{ 0x2ebc, 14 },
|
||||
+{ 0x2ecb, 293 },
|
||||
+{ 0x2ffc, 4 },
|
||||
+{ 0x3004, 1 },
|
||||
+{ 0x3018, 5 },
|
||||
+{ 0x301f, 2 },
|
||||
+{ 0x302a, 20 },
|
||||
+{ 0x303f, 2 },
|
||||
+{ 0x3094, 7 },
|
||||
+{ 0x309f, 2 },
|
||||
+{ 0x30f7, 5 },
|
||||
+{ 0x30ff, 6 },
|
||||
+{ 0x312a, 246 },
|
||||
+{ 0x322a, 7 },
|
||||
+{ 0x3232, 113 },
|
||||
+{ 0x32a4, 234 },
|
||||
+{ 0x3390, 12 },
|
||||
+{ 0x339f, 2 },
|
||||
+{ 0x33a2, 34 },
|
||||
+{ 0x33c5, 9 },
|
||||
+{ 0x33cf, 2 },
|
||||
+{ 0x33d3, 2 },
|
||||
+{ 0x33d6, 113 },
|
||||
+{ 0x3448, 43 },
|
||||
+{ 0x3474, 298 },
|
||||
+{ 0x359f, 111 },
|
||||
+{ 0x360f, 11 },
|
||||
+{ 0x361b, 765 },
|
||||
+{ 0x3919, 85 },
|
||||
+{ 0x396f, 96 },
|
||||
+{ 0x39d1, 14 },
|
||||
+{ 0x39e0, 147 },
|
||||
+{ 0x3a74, 218 },
|
||||
+{ 0x3b4f, 287 },
|
||||
+{ 0x3c6f, 113 },
|
||||
+{ 0x3ce1, 885 },
|
||||
+{ 0x4057, 264 },
|
||||
+{ 0x4160, 471 },
|
||||
+{ 0x4338, 116 },
|
||||
+{ 0x43ad, 4 },
|
||||
+{ 0x43b2, 43 },
|
||||
+{ 0x43de, 248 },
|
||||
+{ 0x44d7, 373 },
|
||||
+{ 0x464d, 20 },
|
||||
+{ 0x4662, 193 },
|
||||
+{ 0x4724, 5 },
|
||||
+{ 0x472a, 82 },
|
||||
+{ 0x477d, 16 },
|
||||
+{ 0x478e, 441 },
|
||||
+{ 0x4948, 50 },
|
||||
+{ 0x497b, 2 },
|
||||
+{ 0x497e, 4 },
|
||||
+{ 0x4984, 1 },
|
||||
+{ 0x4987, 20 },
|
||||
+{ 0x499c, 3 },
|
||||
+{ 0x49a0, 22 },
|
||||
+{ 0x49b8, 703 },
|
||||
+{ 0x4c78, 39 },
|
||||
+{ 0x4ca4, 111 },
|
||||
+{ 0x4d1a, 148 },
|
||||
+{ 0x4daf, 81 },
|
||||
+{ 0x9fa6, 14426 },
|
||||
+{ 0xe76c, 1 },
|
||||
+{ 0xe7c8, 1 },
|
||||
+{ 0xe7e7, 13 },
|
||||
+{ 0xe815, 1 },
|
||||
+{ 0xe819, 5 },
|
||||
+{ 0xe81f, 7 },
|
||||
+{ 0xe827, 4 },
|
||||
+{ 0xe82d, 4 },
|
||||
+{ 0xe833, 8 },
|
||||
+{ 0xe83c, 7 },
|
||||
+{ 0xe844, 16 },
|
||||
+{ 0xe856, 14 },
|
||||
+{ 0xe865, 4295 },
|
||||
+{ 0xf92d, 76 },
|
||||
+{ 0xf97a, 27 },
|
||||
+{ 0xf996, 81 },
|
||||
+{ 0xf9e8, 9 },
|
||||
+{ 0xf9f2, 26 },
|
||||
+{ 0xfa10, 1 },
|
||||
+{ 0xfa12, 1 },
|
||||
+{ 0xfa15, 3 },
|
||||
+{ 0xfa19, 6 },
|
||||
+{ 0xfa22, 1 },
|
||||
+{ 0xfa25, 2 },
|
||||
+{ 0xfa2a, 1030 },
|
||||
+{ 0xfe32, 1 },
|
||||
+{ 0xfe45, 4 },
|
||||
+{ 0xfe53, 1 },
|
||||
+{ 0xfe58, 1 },
|
||||
+{ 0xfe67, 1 },
|
||||
+{ 0xfe6c, 149 },
|
||||
+{ 0xff5f, 129 },
|
||||
+{ 0xffe6, 26 },
|
||||
diff --git a/src/locale/iconv.c b/src/locale/iconv.c
|
||||
index 52178950..4151411d 100644
|
||||
--- a/src/locale/iconv.c
|
||||
+++ b/src/locale/iconv.c
|
||||
@@ -74,6 +74,10 @@ static const unsigned short gb18030[126][190] = {
|
||||
#include "gb18030.h"
|
||||
};
|
||||
|
||||
+static const unsigned short gb18030utf[][2] = {
|
||||
+#include "gb18030utf.h"
|
||||
+};
|
||||
+
|
||||
static const unsigned short big5[89][157] = {
|
||||
#include "big5.h"
|
||||
};
|
||||
@@ -224,6 +228,8 @@ static unsigned uni_to_jis(unsigned c)
|
||||
}
|
||||
}
|
||||
|
||||
+#define countof(a) (sizeof (a) / sizeof *(a))
|
||||
+
|
||||
size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restrict out, size_t *restrict outb)
|
||||
{
|
||||
size_t x=0;
|
||||
@@ -430,15 +436,24 @@ size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restri
|
||||
d = *((unsigned char *)*in + 3);
|
||||
if (d-'0'>9) goto ilseq;
|
||||
c += d-'0';
|
||||
- c += 128;
|
||||
- for (d=0; d<=c; ) {
|
||||
- k = 0;
|
||||
- for (int i=0; i<126; i++)
|
||||
- for (int j=0; j<190; j++)
|
||||
- if (gb18030[i][j]-d <= c-d)
|
||||
- k++;
|
||||
- d = c+1;
|
||||
- c += k;
|
||||
+ /* Starting at 90 30 81 30 (189000), mapping is
|
||||
+ * linear without gaps, to U+10000 and up. */
|
||||
+ if (c >= 189000) {
|
||||
+ c -= 189000;
|
||||
+ c += 0x10000;
|
||||
+ if (c >= 0x110000) goto ilseq;
|
||||
+ break;
|
||||
+ }
|
||||
+ /* Otherwise we must process an index into set
|
||||
+ * of characters unmapped by 2-byte table. */
|
||||
+ for (int i=0; ; i++) {
|
||||
+ if (i==countof(gb18030utf))
|
||||
+ goto ilseq;
|
||||
+ if (c<gb18030utf[i][1]) {
|
||||
+ c += gb18030utf[i][0];
|
||||
+ break;
|
||||
+ }
|
||||
+ c -= gb18030utf[i][1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
--
|
||||
2.21.0
|
||||
Generated
+135
-12
@@ -185,9 +185,6 @@ jobs:
|
||||
if [[ "$RUNNER_DEBUG" -eq 1 ]]; then
|
||||
echo "DEBUG_ARGS=--info --stacktrace" >> $GITHUB_ENV
|
||||
fi
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: gradle build java executables
|
||||
shell: bash
|
||||
run: ./gradlew $DEBUG_ARGS --no-daemon -DpklMultiJdkTesting=true pkl-doc:build pkl-cli:build pkl-codegen-java:build pkl-codegen-kotlin:build
|
||||
@@ -244,6 +241,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -294,6 +296,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -314,8 +321,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -343,6 +352,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -385,7 +399,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -417,13 +431,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -449,6 +478,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -494,6 +528,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -542,6 +581,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -592,6 +636,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -612,8 +661,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -641,6 +692,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -683,7 +739,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -715,13 +771,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -747,6 +818,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -792,6 +868,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -840,6 +921,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-amd64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -890,6 +976,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-aarch64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -910,8 +1001,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -939,6 +1032,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -981,7 +1079,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -1013,13 +1111,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -1045,6 +1158,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -1092,6 +1210,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-windows-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-windows-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
|
||||
Generated
+135
-12
@@ -183,9 +183,6 @@ jobs:
|
||||
if [[ "$RUNNER_DEBUG" -eq 1 ]]; then
|
||||
echo "DEBUG_ARGS=--info --stacktrace" >> $GITHUB_ENV
|
||||
fi
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: gradle build java executables
|
||||
shell: bash
|
||||
run: ./gradlew $DEBUG_ARGS --no-daemon -DpklMultiJdkTesting=true pkl-doc:build pkl-cli:build pkl-codegen-java:build pkl-codegen-kotlin:build
|
||||
@@ -242,6 +239,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -292,6 +294,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -312,8 +319,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -341,6 +350,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -383,7 +397,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -415,13 +429,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -447,6 +476,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -492,6 +526,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -540,6 +579,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -590,6 +634,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -610,8 +659,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -639,6 +690,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -681,7 +737,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -713,13 +769,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -745,6 +816,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -790,6 +866,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -838,6 +919,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-amd64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -888,6 +974,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-aarch64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -908,8 +999,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -937,6 +1030,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -979,7 +1077,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -1011,13 +1109,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -1043,6 +1156,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -1090,6 +1208,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-windows-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-windows-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
|
||||
Generated
+135
-9
@@ -128,6 +128,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -180,6 +185,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -201,8 +211,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -230,6 +242,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -274,7 +291,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -306,13 +323,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -338,6 +370,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -385,6 +422,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -435,6 +477,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -487,6 +534,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -508,8 +560,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -537,6 +591,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -581,7 +640,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -613,13 +672,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -645,6 +719,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -692,6 +771,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -742,6 +826,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-amd64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -794,6 +883,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-aarch64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -815,8 +909,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -844,6 +940,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -888,7 +989,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -920,13 +1021,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -952,6 +1068,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -1001,6 +1122,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-windows-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-windows-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
|
||||
Generated
+135
-12
@@ -183,9 +183,6 @@ jobs:
|
||||
if [[ "$RUNNER_DEBUG" -eq 1 ]]; then
|
||||
echo "DEBUG_ARGS=--info --stacktrace" >> $GITHUB_ENV
|
||||
fi
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: gradle build java executables
|
||||
shell: bash
|
||||
run: ./gradlew $DEBUG_ARGS --no-daemon -DpklMultiJdkTesting=true pkl-doc:build pkl-cli:build pkl-codegen-java:build pkl-codegen-kotlin:build
|
||||
@@ -242,6 +239,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -292,6 +294,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -312,8 +319,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -341,6 +350,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -383,7 +397,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -415,13 +429,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -447,6 +476,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -492,6 +526,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -540,6 +579,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -590,6 +634,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -610,8 +659,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -639,6 +690,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -681,7 +737,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -713,13 +769,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -745,6 +816,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -790,6 +866,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -838,6 +919,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-amd64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -888,6 +974,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-aarch64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -908,8 +999,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -937,6 +1030,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -979,7 +1077,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -1011,13 +1109,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -1043,6 +1156,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -1090,6 +1208,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-windows-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-windows-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
|
||||
Generated
+158
-14
@@ -184,9 +184,6 @@ jobs:
|
||||
if [[ "$RUNNER_DEBUG" -eq 1 ]]; then
|
||||
echo "DEBUG_ARGS=--info --stacktrace" >> $GITHUB_ENV
|
||||
fi
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: gradle build java executables
|
||||
shell: bash
|
||||
run: ./gradlew $DEBUG_ARGS --no-daemon -DpklMultiJdkTesting=true -DreleaseBuild=true pkl-doc:build pkl-cli:build pkl-codegen-java:build pkl-codegen-kotlin:build
|
||||
@@ -244,6 +241,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -295,6 +297,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-linux-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -315,8 +322,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -345,6 +354,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-macOS-aarch64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -388,7 +402,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -420,13 +434,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -452,6 +481,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-alpine-linux-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -498,6 +532,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-cli-windows-amd64
|
||||
path: pkl-cli*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -547,6 +586,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -598,6 +642,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-linux-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -618,8 +667,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -648,6 +699,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-macOS-aarch64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -691,7 +747,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -723,13 +779,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -755,6 +826,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-alpine-linux-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -801,6 +877,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-pkl-doc-windows-amd64
|
||||
path: pkl-doc*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -850,6 +931,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-amd64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -901,6 +987,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-linux-aarch64
|
||||
path: libpkl/build/native-libs/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-linux-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -921,8 +1012,10 @@ jobs:
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- macos
|
||||
- goldengate
|
||||
env:
|
||||
LANG: en_US.UTF-8
|
||||
DEVELOPER_DIR: /Applications/Xcode_swift_6.4.app
|
||||
steps:
|
||||
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
||||
with:
|
||||
@@ -951,6 +1044,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/executable/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-macOS-aarch64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -994,7 +1092,7 @@ jobs:
|
||||
mkdir -p ~/staticdeps/
|
||||
|
||||
ZLIB_VERSION="1.2.13"
|
||||
MUSL_VERSION="1.2.5"
|
||||
MUSL_VERSION="9fa28ece75d8a2191de7c5bb53bed224c5947417" # v1.2.6
|
||||
|
||||
# install zlib
|
||||
if [[ ! -f ~/staticdeps/include/zlib.h ]]; then
|
||||
@@ -1026,13 +1124,28 @@ jobs:
|
||||
rm -rf /tmp/dep_zlib-${ZLIB_VERSION}
|
||||
fi
|
||||
|
||||
declare -a MUSL_REPOS=(
|
||||
https://git.musl-libc.org/git/musl
|
||||
https://gogs.librecmc.org/OWEALS/musl.git
|
||||
)
|
||||
|
||||
# install musl
|
||||
if [[ ! -f ~/staticdeps/bin/x86_64-linux-musl-gcc ]]; then
|
||||
# Download musl git repo
|
||||
cd /tmp
|
||||
git clone https://git.musl-libc.org/git/musl /tmp/musl
|
||||
for repo in "${MUSL_REPOS[@]}"; do
|
||||
if git clone --depth 1 --revision "$MUSL_VERSION" "$repo" /tmp/musl; then
|
||||
break
|
||||
else
|
||||
rm -rf /tmp/musl
|
||||
fi
|
||||
done
|
||||
cd /tmp/musl
|
||||
git checkout "v$MUSL_VERSION"
|
||||
|
||||
for patch in $GITHUB_WORKSPACE/.github/scripts/musl-*.patch; do
|
||||
echo "musl-${MUSL_VERSION}: applying $patch..."
|
||||
cat "$patch" | git apply
|
||||
done
|
||||
|
||||
echo "musl-${MUSL_VERSION}: configure..."
|
||||
./configure --disable-shared --prefix="$HOME"/staticdeps > /dev/null
|
||||
@@ -1058,6 +1171,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-alpine-linux-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -1106,6 +1224,11 @@ jobs:
|
||||
with:
|
||||
name: deploy-artifacts-libpkl-windows-amd64
|
||||
path: libpkl*/build/distributions/**/*
|
||||
- name: Upload compiled classes list
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
with:
|
||||
name: compiled-classes-libpkl-windows-amd64
|
||||
path: libpkl*/build/compiled-classes/**/*
|
||||
- name: Upload Test Result XML
|
||||
if: '!cancelled()'
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
@@ -1180,7 +1303,27 @@ jobs:
|
||||
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPEUSERNAME }}
|
||||
run: ./gradlew $DEBUG_ARGS --no-daemon -DpklMultiJdkTesting=true -DreleaseBuild=true publishToSonatype closeAndReleaseSonatypeStagingRepository
|
||||
github-release:
|
||||
needs: deploy-release
|
||||
needs:
|
||||
- gradle-check
|
||||
- gradle-check-windows
|
||||
- bench
|
||||
- gradle-compatibility
|
||||
- java-executables-release
|
||||
- pkl-cli-linux-amd64-release
|
||||
- pkl-cli-linux-aarch64-release
|
||||
- pkl-cli-macOS-aarch64-release
|
||||
- pkl-cli-alpine-linux-amd64-release
|
||||
- pkl-cli-windows-amd64-release
|
||||
- pkl-doc-linux-amd64-release
|
||||
- pkl-doc-linux-aarch64-release
|
||||
- pkl-doc-macOS-aarch64-release
|
||||
- pkl-doc-alpine-linux-amd64-release
|
||||
- pkl-doc-windows-amd64-release
|
||||
- libpkl-linux-amd64-release
|
||||
- libpkl-linux-aarch64-release
|
||||
- libpkl-macOS-aarch64-release
|
||||
- libpkl-alpine-linux-amd64-release
|
||||
- libpkl-windows-amd64-release
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
@@ -1197,11 +1340,12 @@ jobs:
|
||||
GH_REPO: ${{ github.repository }}
|
||||
run: |-
|
||||
gh release create ${TAG_NAME} \
|
||||
--draft \
|
||||
--title "${TAG_NAME}" \
|
||||
--target "${GIT_SHA}" \
|
||||
--verify-tag \
|
||||
--notes "Release notes: https://pkl-lang.org/main/current/release-notes/changelog.html#release-${TAG_NAME}" \
|
||||
*/build/executable/* */build/distributions/*
|
||||
*/build/executable/*
|
||||
publish-test-results:
|
||||
if: '!cancelled()'
|
||||
needs:
|
||||
|
||||
@@ -408,3 +408,56 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
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.
|
||||
|
||||
28) protobuf-java
|
||||
License URL: https://github.com/protocolbuffers/protobuf/blob/main/LICENSE
|
||||
|
||||
Copyright 2008 Google Inc. 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 Google Inc. 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.
|
||||
|
||||
Code generated by the Protocol Buffer compiler is owned by the owner
|
||||
of the input file used when generating it. This code is not
|
||||
standalone and requires a support library to be linked with it. This
|
||||
support library is itself covered by the above license.
|
||||
|
||||
29) pprof
|
||||
License URL: https://github.com/google/pprof/blob/main/LICENSE
|
||||
|
||||
Copyright 2016 Google Inc. 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
|
||||
|
||||
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
-4
@@ -31,13 +31,17 @@ dependencies {
|
||||
}
|
||||
|
||||
jmh {
|
||||
// include = ["fib_class_java"]
|
||||
// include = ["fib_class_constrained1", "fib_class_constrained2"]
|
||||
// includes = listOf("ParserBenchmark")
|
||||
jmhVersion.set(libs.versions.jmh)
|
||||
// jvmArgsAppend = "-Dgraal.TruffleCompilationExceptionsAreFatal=true " +
|
||||
// "-Dgraal.Dump=Truffle,TruffleTree -Dgraal.TraceTruffleCompilation=true " +
|
||||
// "-Dgraal.TruffleFunctionInlining=false"
|
||||
jvm.set("${buildInfo.graalVmAmd64.baseDir}/bin/java")
|
||||
val graalVm =
|
||||
when (buildInfo.arch) {
|
||||
Target.Arch.AARCH64 -> buildInfo.graalVmAarch64
|
||||
Target.Arch.AMD64 -> buildInfo.graalVmAmd64
|
||||
}
|
||||
jvm.set("${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(
|
||||
@@ -51,7 +55,13 @@ jmh {
|
||||
// synchronizeIterations = false
|
||||
}
|
||||
|
||||
tasks.named("jmh") { dependsOn(":installGraalVmAmd64") }
|
||||
tasks.named("jmh") {
|
||||
if (buildInfo.arch == Target.Arch.AARCH64) {
|
||||
dependsOn(":installGraalVmAarch64")
|
||||
} else if (buildInfo.arch == Target.Arch.AMD64) {
|
||||
dependsOn(":installGraalVmAmd64")
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@@ -304,7 +304,15 @@ open class BuildInfo(private val project: Project) {
|
||||
classpath = template.classpath
|
||||
testClassesDirs = template.testClassesDirs
|
||||
jvmArgs.addAll(template.jvmArgs)
|
||||
jvmArgumentProviders.addAll(template.jvmArgumentProviders)
|
||||
jvmArgumentProviders.addAll(
|
||||
template.jvmArgumentProviders.map { provider ->
|
||||
// Gradle injects this arg, which is not compatible across JDK versions
|
||||
// other JDK versions (see https://github.com/gradle/gradle/issues/39442)
|
||||
CommandLineArgumentProvider {
|
||||
provider.asArguments().filter { !it.startsWith("--sun-misc-unsafe-memory-access") }
|
||||
}
|
||||
}
|
||||
)
|
||||
forkEvery = template.forkEvery
|
||||
maxParallelForks = template.maxParallelForks
|
||||
minHeapSize = template.minHeapSize
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import java.io.File
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.Optional
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
open class BuildSourceBundle : DefaultTask() {
|
||||
/** Sources jars that are included in full. */
|
||||
@get:InputFiles val inputJars: ConfigurableFileCollection = project.objects.fileCollection()
|
||||
|
||||
/**
|
||||
* Sources jars that are only included in part, if [compiledClasses] is set.
|
||||
*
|
||||
* Only `.java` files are dropped, if their class is not in [compiledClasses]. Everything else is
|
||||
* kept: other languages (e.g. Kotlin) can't be matched by name, because the classes that they
|
||||
* compile to don't necessarily relate to the file name or package (e.g. with `@file:JvmName` or
|
||||
* `@file:JvmPackageName`), and licenses and other metadata must be retained.
|
||||
*
|
||||
* If [compiledClasses] is not set, these jars are included in full.
|
||||
*/
|
||||
@get:InputFiles
|
||||
val filteredInputJars: ConfigurableFileCollection = project.objects.fileCollection()
|
||||
|
||||
/** Fully qualified names of top-level classes, one per line. */
|
||||
@get:[InputFile Optional]
|
||||
val compiledClasses: RegularFileProperty = project.objects.fileProperty()
|
||||
|
||||
@get:OutputFile val outputZip: RegularFileProperty = project.objects.fileProperty()
|
||||
|
||||
@TaskAction
|
||||
@Suppress("unused")
|
||||
fun merge() {
|
||||
val zipFile = outputZip.asFile.get()
|
||||
if (!zipFile.getParentFile().exists()) zipFile.getParentFile().mkdirs()
|
||||
val classes =
|
||||
if (compiledClasses.isPresent) {
|
||||
compiledClasses
|
||||
.get()
|
||||
.asFile
|
||||
.readLines()
|
||||
.map { it.trim() }
|
||||
.filterTo(hashSetOf()) { it.isNotEmpty() }
|
||||
} else null
|
||||
val packages = classes?.mapTo(hashSetOf()) { it.substringBeforeLast('.', "").replace('.', '/') }
|
||||
var dropped = 0
|
||||
ZipOutputStream(zipFile.outputStream()).use { zip ->
|
||||
fun copyJar(jar: File, keep: (String) -> Boolean) {
|
||||
val jarName = jar.toPath().fileName.toString().removeSuffix(".jar")
|
||||
project.zipTree(jar).visit {
|
||||
if (isDirectory) return@visit
|
||||
val path = relativePath.pathString
|
||||
if (!keep(path)) {
|
||||
dropped++
|
||||
return@visit
|
||||
}
|
||||
zip.putNextEntry(ZipEntry("$jarName/$path"))
|
||||
copyTo(zip)
|
||||
zip.closeEntry()
|
||||
}
|
||||
}
|
||||
for (jar in inputJars) copyJar(jar) { true }
|
||||
for (jar in filteredInputJars) {
|
||||
copyJar(jar) { path ->
|
||||
classes == null || packages == null || isEvident(path, classes, packages)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (classes != null) {
|
||||
logger.lifecycle("Dropped $dropped source files that are not in ${compiledClasses.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun isEvident(path: String, classes: Set<String>, packages: Set<String>): Boolean {
|
||||
// sources of multi-release jars have the same classes as the unversioned ones
|
||||
val sourcePath = path.replace(multiReleasePrefix, "")
|
||||
val packagePath = sourcePath.substringBeforeLast('/', "")
|
||||
val fileName = sourcePath.substringAfterLast('/')
|
||||
return when (sourcePath.substringAfterLast('.', "")) {
|
||||
"java" ->
|
||||
when (fileName) {
|
||||
"package-info.java" -> packagePath in packages
|
||||
"module-info.java" -> true
|
||||
else -> sourcePath.removeSuffix(".java").replace('/', '.') in classes
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
private val multiReleasePrefix = Regex("^META-INF/versions/\\d+/")
|
||||
}
|
||||
@@ -77,6 +77,8 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
|
||||
@get:InputFile @get:Optional abstract val nativeCompilerPath: RegularFileProperty
|
||||
|
||||
@get:Internal abstract val compiledClassesFile: RegularFileProperty
|
||||
|
||||
@get:Internal abstract val outputDir: DirectoryProperty
|
||||
|
||||
@get:Inject protected abstract val execOperations: ExecOperations
|
||||
@@ -194,6 +196,12 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
.asFile
|
||||
.toPath()
|
||||
.also { it.createDirectories() }
|
||||
val reportsDir = workingDir.resolve("reports")
|
||||
// reports are timestamped and never cleaned up by native-image; make sure we read a fresh one
|
||||
reportsDir
|
||||
.toFile()
|
||||
.listFiles { f -> f.name.startsWith(COMPILATION_REPORT_PREFIX) }
|
||||
?.forEach { it.delete() }
|
||||
val execResult = execOperations.exec {
|
||||
val exclusions =
|
||||
listOf(buildInfo.libs.findLibrary("graalSdk").get()).map { it.get().module.name }
|
||||
@@ -205,6 +213,8 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
add("--color=always")
|
||||
// must be emitted before any experimental options are used
|
||||
add("-H:+UnlockExperimentalVMOptions")
|
||||
// emit `reports/universe_compilation_*.txt`, listing all compiled methods
|
||||
add("-H:+PrintUniverse")
|
||||
// currently gives a deprecation warning, but we've been told
|
||||
// that the "initialize everything at build time" *CLI* option is likely here to stay
|
||||
add("--initialize-at-build-time=")
|
||||
@@ -217,6 +227,8 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
add("--initialize-at-run-time=org.pkl.core.util.DebugLogger")
|
||||
// needed for jline-terminal-jni
|
||||
add("--initialize-at-run-time=org.jline.nativ,org.jline.terminal.impl.jni")
|
||||
// needed for protobuf-java
|
||||
add("--initialize-at-run-time=com.google.protobuf.UnsafeUtil")
|
||||
add("--no-fallback")
|
||||
add("-H:IncludeResources=org/pkl/core/stdlib/.*\\.pkl")
|
||||
add("-H:IncludeResources=org/jline/utils/.*")
|
||||
@@ -267,8 +279,12 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
add("--native-compiler-path=${nativeCompilerPath.get().asFile}")
|
||||
}
|
||||
// Pass through all `HOMEBREW_` prefixed environment variables to allow build with shimmed
|
||||
// tools.
|
||||
addAll(environment.keys.filter { it.startsWith("HOMEBREW_") }.map { "-E$it" })
|
||||
// tools, and `DEVELOPER_DIR` so that `cc` on macOS uses the selected Xcode toolchain.
|
||||
addAll(
|
||||
environment.keys
|
||||
.filter { it.startsWith("HOMEBREW_") || it == "DEVELOPER_DIR" }
|
||||
.map { "-E$it" }
|
||||
)
|
||||
addAll(extraNativeImageArgs.get())
|
||||
addAll(extraArgsFromProperties)
|
||||
}
|
||||
@@ -293,6 +309,36 @@ abstract class NativeImageBuild : DefaultTask() {
|
||||
targetDir.deleteRecursively()
|
||||
sourceDir.copyRecursively(targetDir, overwrite = true)
|
||||
}
|
||||
writeCompiledClasses(reportsDir.toFile())
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeCompiledClasses(reportsDir: java.io.File) {
|
||||
val report =
|
||||
reportsDir
|
||||
.listFiles { f -> f.name.startsWith(COMPILATION_REPORT_PREFIX) }
|
||||
?.maxByOrNull { it.lastModified() }
|
||||
?: throw GradleException("Expected to find $COMPILATION_REPORT_PREFIX*.txt in $reportsDir")
|
||||
// Method lines look like `336 2232 apple.security.AppleProvider$Service.newInstance(...): ...`
|
||||
// (offset, size, qualified method name, signature).
|
||||
val methodLine = Regex("""^\s*\d+\s+\d+\s+([^\s(]+)\(""")
|
||||
val classNames = sortedSetOf<String>()
|
||||
report.useLines { lines ->
|
||||
for (line in lines) {
|
||||
val method = methodLine.find(line)?.groupValues?.get(1) ?: continue
|
||||
// Nested, hidden, and lambda classes all live in their top-level class' source file.
|
||||
classNames.add(method.substringBeforeLast('.').substringBefore('$').substringBefore('/'))
|
||||
}
|
||||
}
|
||||
if (classNames.isEmpty()) {
|
||||
throw GradleException("Found no compiled methods in $report")
|
||||
}
|
||||
val file = compiledClassesFile.get().asFile
|
||||
file.parentFile.mkdirs()
|
||||
file.writeText(classNames.joinToString("\n", postfix = "\n"))
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val COMPILATION_REPORT_PREFIX = "universe_compilation_"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.SetProperty
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
/**
|
||||
* Collects the JDK, SubstrateVM, and Graal Java sources for every class that has methods compiled
|
||||
* into a native image.
|
||||
*
|
||||
* The classes are read from [compiledClasses], and their sources are looked up in the OpenJDK and
|
||||
* Graal repositories' tagged source archives. These archives contain the sources of every platform
|
||||
* and architecture, so this task does not need to run on the platform that it collects sources for.
|
||||
*/
|
||||
abstract class NativeImageSourcesJar : DefaultTask() {
|
||||
/**
|
||||
* Fully qualified top-level names of the classes compiled into the image, one per line.
|
||||
*
|
||||
* This is the list that native-image reports (via `-H:+PrintUniverse`) when building the image.
|
||||
*/
|
||||
@get:InputFile abstract val compiledClasses: RegularFileProperty
|
||||
|
||||
/** The gzipped tarball of the OpenJDK repository (e.g. `jdk25u`) at the JDK's release tag. */
|
||||
@get:InputFiles abstract val openJdkTarball: ConfigurableFileCollection
|
||||
|
||||
/** The gzipped tarball of the `oracle/graal` repository at the GraalVM's release tag. */
|
||||
@get:InputFiles abstract val graalTarball: ConfigurableFileCollection
|
||||
|
||||
/**
|
||||
* The platform-specific source roots to include from OpenJDK; any of `share`, `unix`, `linux`,
|
||||
* `macosx`, and `windows`.
|
||||
*/
|
||||
@get:Input abstract val openJdkPlatforms: SetProperty<String>
|
||||
|
||||
@get:OutputFile abstract val outputJar: RegularFileProperty
|
||||
|
||||
@TaskAction
|
||||
@Suppress("unused")
|
||||
fun collect() {
|
||||
val wanted =
|
||||
compiledClasses
|
||||
.get()
|
||||
.asFile
|
||||
.readLines()
|
||||
.filter { it.isNotBlank() }
|
||||
.mapTo(hashSetOf()) { it.trim().replace('.', '/') + ".java" }
|
||||
if (wanted.isEmpty()) {
|
||||
throw GradleException("No compiled classes found in ${compiledClasses.get()}")
|
||||
}
|
||||
|
||||
val platforms = openJdkPlatforms.get()
|
||||
// <repo>-<tag>/src/<module>/<platform>/classes/<package path>.java
|
||||
val openJdkSource = Regex("""^[^/]+/src/[^/]+/([^/]+)/classes/(.+\.java)$""")
|
||||
// <repo>-<tag>/<suite>/src/<project>/src/<package path>.java
|
||||
//
|
||||
// Truffle sources are intentionally omitted; they are already published as sources jars.
|
||||
val graalSource = Regex("""^[^/]+/(?:substratevm|compiler|sdk)/src/[^/]+/src/(.+\.java)$""")
|
||||
|
||||
val out = outputJar.get().asFile
|
||||
out.parentFile.mkdirs()
|
||||
val written = hashSetOf<String>()
|
||||
ZipOutputStream(out.outputStream().buffered()).use { zip ->
|
||||
fun collectFrom(tarball: java.io.File, sourcePathOf: (String) -> String?) {
|
||||
project.tarTree(project.resources.gzip(tarball)).visit {
|
||||
if (isDirectory) return@visit
|
||||
val sourcePath = sourcePathOf(relativePath.pathString) ?: return@visit
|
||||
if (sourcePath !in wanted || !written.add(sourcePath)) return@visit
|
||||
zip.putNextEntry(ZipEntry(sourcePath))
|
||||
copyTo(zip)
|
||||
zip.closeEntry()
|
||||
}
|
||||
}
|
||||
collectFrom(openJdkTarball.singleFile) { path ->
|
||||
openJdkSource
|
||||
.matchEntire(path)
|
||||
?.takeIf { it.groupValues[1] in platforms }
|
||||
?.let { it.groupValues[2] }
|
||||
}
|
||||
collectFrom(graalTarball.singleFile) { path ->
|
||||
graalSource.matchEntire(path)?.groupValues?.get(1)
|
||||
}
|
||||
}
|
||||
logger.lifecycle(
|
||||
"Collected sources of ${written.size} of ${wanted.size} compiled classes into $out"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.provider.Property
|
||||
|
||||
/**
|
||||
* The inputs that source bundles of a project are made of.
|
||||
*
|
||||
* This is configured by the `pklSourceBundle` plugin; the plugins that register the actual source
|
||||
* bundles (`pklJvmSourceBundle` and `pklNativeSourceBundle`) consume it.
|
||||
*/
|
||||
abstract class SourceBundleSpec {
|
||||
/** Sources jars of the project itself, and of the projects that it depends on. */
|
||||
abstract val firstPartyJars: ConfigurableFileCollection
|
||||
|
||||
/** Sources jars of third-party dependencies, as resolved from the runtime classpath. */
|
||||
abstract val dependencyJars: ConfigurableFileCollection
|
||||
|
||||
/**
|
||||
* Additional sources to include in source bundles of native targets (e.g. C sources of the
|
||||
* project itself).
|
||||
*/
|
||||
abstract val extraNativeSources: ConfigurableFileCollection
|
||||
|
||||
/**
|
||||
* Whether musl and zlib are statically linked into the project's native executable for musl
|
||||
* targets, in which case their sources are included in the source bundle of those targets.
|
||||
*/
|
||||
abstract val staticMuslLibc: Property<Boolean>
|
||||
}
|
||||
@@ -24,6 +24,7 @@ plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
id("com.gradleup.shadow")
|
||||
id("pklJvmSourceBundle")
|
||||
}
|
||||
|
||||
// make fat Jar available to other subprojects
|
||||
@@ -31,10 +32,6 @@ 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
|
||||
@@ -69,6 +66,11 @@ val relocations =
|
||||
|
||||
// pkl-codegen-kotlin dependencies
|
||||
"com.squareup.kotlinpoet." to "org.pkl.thirdparty.kotlinpoet.",
|
||||
|
||||
// pkl-profiler dependencies
|
||||
"com.google.protobuf." to "org.pkl.thirdparty.com.google.protobuf.",
|
||||
"com.google.perftools." to "org.pkl.thirdparty.com.google.perftools.",
|
||||
"google.protobuf." to "org.pkl.thirdparty.google.protobuf.",
|
||||
)
|
||||
|
||||
for ((key, value) in relocations) {
|
||||
@@ -182,17 +184,13 @@ val validateFatJar =
|
||||
|
||||
tasks.check { dependsOn(validateFatJar) }
|
||||
|
||||
val resolveSourcesJars =
|
||||
tasks.register<ResolveSourcesJars>("resolveSourcesJars") {
|
||||
configuration.set(configurations.runtimeClasspath)
|
||||
outputDir.set(layout.buildDirectory.dir("resolveSourcesJars"))
|
||||
}
|
||||
|
||||
val fatSourcesJar =
|
||||
tasks.register<MergeSourcesJars>("fatSourcesJar") {
|
||||
plugins.withId("pklJavaLibrary") { inputJars.from(tasks.named("sourcesJar")) }
|
||||
inputJars.from(firstPartySourcesJarsConfiguration)
|
||||
inputJars.from(resolveSourcesJars.map { fileTree(it.outputDir) })
|
||||
inputJars.from(configurations.named("firstPartySourcesJars"))
|
||||
inputJars.from(
|
||||
tasks.named<ResolveSourcesJars>("resolveSourcesJars").map { fileTree(it.outputDir) }
|
||||
)
|
||||
|
||||
mergedBinaryJars.from(tasks.shadowJar)
|
||||
relocatedPackages.set(relocations)
|
||||
|
||||
@@ -76,3 +76,11 @@ val installGraalVmAmd64 =
|
||||
dependsOn(verifyGraalVmAmd64)
|
||||
graalVm = buildInfo.graalVmAmd64
|
||||
}
|
||||
|
||||
// Picked up by GitHub Actions and uploaded as a build artifact
|
||||
tasks.withType<NativeImageBuild>().configureEach {
|
||||
compiledClassesFile =
|
||||
layout.buildDirectory.file(
|
||||
"compiled-classes/${project.name}-${project.version}-${buildInfo.targetMachine.targetName}.txt"
|
||||
)
|
||||
}
|
||||
@@ -21,6 +21,7 @@ plugins {
|
||||
id("pklJavaLibrary")
|
||||
// id("pklPublishLibrary")
|
||||
id("com.gradleup.shadow")
|
||||
id("pklJvmSourceBundle")
|
||||
}
|
||||
|
||||
val executableSpec = project.extensions.create("executable", ExecutableSpec::class.java)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright © 2026 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.
|
||||
*/
|
||||
// Source bundle for the JVM variant of a project: its fat JAR, or its executable JAR.
|
||||
//
|
||||
// These contain the complete sources of all dependencies, because fat JARs contain the complete
|
||||
// classes of all dependencies.
|
||||
plugins { id("pklSourceBundle") }
|
||||
|
||||
val sourceBundleSpec = extensions.getByType<SourceBundleSpec>()
|
||||
|
||||
val sourceBundleJava =
|
||||
tasks.register<BuildSourceBundle>("sourceBundleJava") {
|
||||
group = "build"
|
||||
description = "Builds the source bundle of ${project.name}'s JVM variant."
|
||||
inputJars.from(sourceBundleSpec.firstPartyJars, sourceBundleSpec.dependencyJars)
|
||||
outputZip =
|
||||
layout.buildDirectory.file(
|
||||
"sourceBundle/${project.name}-${project.version}-java-sourcebundle.zip"
|
||||
)
|
||||
}
|
||||
|
||||
tasks.named("sourceBundle") { dependsOn(sourceBundleJava) }
|
||||
@@ -22,6 +22,7 @@ plugins {
|
||||
id("pklGraalVm")
|
||||
id("pklJavaLibrary")
|
||||
id("pklNativeLifecycle")
|
||||
id("pklNativeSourceBundle")
|
||||
id("pklPublishLibrary")
|
||||
id("com.gradleup.shadow")
|
||||
}
|
||||
@@ -30,6 +31,9 @@ plugins {
|
||||
val executableSpec = project.extensions.getByType<ExecutableSpec>()
|
||||
val buildInfo = project.extensions.getByType<BuildInfo>()
|
||||
|
||||
// musl executables are linked with `--static`, so musl and zlib become part of the executable
|
||||
extensions.getByType<SourceBundleSpec>().staticMuslLibc = true
|
||||
|
||||
val stagedMacAarch64Executable: Configuration = configurations.create("stagedMacAarch64Executable")
|
||||
val stagedLinuxAmd64Executable: Configuration = configurations.create("stagedLinuxAmd64Executable")
|
||||
val stagedLinuxAarch64Executable: Configuration =
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright © 2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import javax.inject.Inject
|
||||
import org.gradle.accessors.dm.LibrariesForLibs
|
||||
import org.gradle.api.tasks.options.Option
|
||||
import org.gradle.process.ExecOperations
|
||||
|
||||
// Source bundles for the native variants of a project, one for each `Target`.
|
||||
//
|
||||
// Each bundle consists of the sources of everything that is compiled into the native image or
|
||||
// library of that target:
|
||||
// * the project's own sources, and those of its first-party dependencies;
|
||||
// * the sources of third-party dependencies that have classes in the image;
|
||||
// * the Java sources of the JDK, SubstrateVM, and Graal classes that are in the image;
|
||||
// * the C sources of the JDK and SubstrateVM native libraries that are linked into the image;
|
||||
// * for statically linked musl executables, the sources of musl and zlib.
|
||||
//
|
||||
// Which classes are in the image is read from the lists in `build/compiled-classes` (download them
|
||||
// with the `downloadCompiledClasses` task). native-image produces these lists, and CI uploads them
|
||||
// as `compiled-classes-<project>-*` artifacts. This way, the source bundle of any target can be
|
||||
// built on any machine.
|
||||
//
|
||||
// Sources of the JDK, SubstrateVM, and Graal come from the OpenJDK and Graal repositories at the
|
||||
// tags matching the GraalVM that is used to build, because GraalVM doesn't ship all of the Java
|
||||
// sources (or any of the C sources).
|
||||
plugins { id("pklSourceBundle") }
|
||||
|
||||
val libs = the<LibrariesForLibs>()
|
||||
val sourceBundleSpec = extensions.getByType<SourceBundleSpec>()
|
||||
|
||||
val openJdkSourcesTarball: Configuration = configurations.create("openJdkSourcesTarball")
|
||||
val graalSourcesTarball: Configuration = configurations.create("graalSourcesTarball")
|
||||
|
||||
val muslSourcesTarball: Configuration = configurations.create("muslSourcesTarball")
|
||||
val zlibSourcesTarball: Configuration = configurations.create("zlibSourcesTarball")
|
||||
|
||||
// CI builds musl and zlib from source for statically linked executables; use the same versions.
|
||||
fun muslToolchainVersion(name: String): String {
|
||||
val script = rootProject.file(".github/scripts/install_musl.sh").readText()
|
||||
return Regex("${name}_VERSION=\"([^\"]+)\"").find(script)?.groupValues?.get(1)
|
||||
?: throw GradleException("Could not find ${name}_VERSION in .github/scripts/install_musl.sh")
|
||||
}
|
||||
|
||||
// The "GitHub tag archives" and "musl releases" repositories are declared in settings.gradle.kts;
|
||||
// declaring repositories in a project would stop it from using the ones declared in settings.
|
||||
dependencies {
|
||||
val jdkVersion = libs.versions.graalVmJdkVersion.get()
|
||||
openJdkSourcesTarball("openjdk:jdk${jdkVersion.substringBefore('.')}u:jdk-$jdkVersion-ga")
|
||||
graalSourcesTarball("oracle:graal:vm-${libs.versions.graalVm.get()}")
|
||||
muslSourcesTarball("musl:musl:${muslToolchainVersion("MUSL")}")
|
||||
zlibSourcesTarball("madler:zlib:v${muslToolchainVersion("ZLIB")}")
|
||||
}
|
||||
|
||||
// native-image's class path can differ from the runtime class path (e.g. `nativeImageClasspath` in
|
||||
// `pklNativeExecutable`), so resolve the sources of what's actually compiled in.
|
||||
val resolveNativeSourcesJars =
|
||||
tasks.register<ResolveSourcesJars>("resolveNativeSourcesJars") {
|
||||
configuration.set(
|
||||
provider {
|
||||
configurations.findByName("nativeImageClasspath")
|
||||
?: configurations.getByName("runtimeClasspath")
|
||||
}
|
||||
)
|
||||
outputDir.set(layout.buildDirectory.dir("resolveNativeSourcesJars"))
|
||||
}
|
||||
|
||||
// The JDK native libraries that native-image links into the image.
|
||||
val openJdkNativeLibraries = listOf("java", "net", "nio", "zip", "extnet", "management_ext")
|
||||
|
||||
// Platform-specific directories in OpenJDK's `src/<module>/<platform>/`.
|
||||
val Target.OS.openJdkPlatforms: List<String>
|
||||
get() = buildList {
|
||||
add("share")
|
||||
if (!isWindows) add("unix")
|
||||
add(
|
||||
when {
|
||||
isMacOS -> "macosx"
|
||||
isWindows -> "windows"
|
||||
else -> "linux"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// The `substratevm/src/com.oracle.svm.native.*` projects that apply to the OS.
|
||||
val Target.OS.svmNativeProjects: List<String>
|
||||
get() = buildList {
|
||||
add("libchelper")
|
||||
when {
|
||||
isMacOS -> {
|
||||
add("darwin")
|
||||
add("jvm.posix")
|
||||
}
|
||||
isLinux -> {
|
||||
add("libcontainer")
|
||||
add("jvm.posix")
|
||||
}
|
||||
isWindows -> add("jvm.windows")
|
||||
}
|
||||
}
|
||||
|
||||
val sourceBundleTasks =
|
||||
Target.entries.map { target ->
|
||||
val variant = target.name
|
||||
val outputDir = layout.buildDirectory.dir("tmp/nativeImageSources/${target.targetName}")
|
||||
val compiledClassesFile =
|
||||
layout.buildDirectory.file("compiled-classes/${target.targetName}.txt")
|
||||
|
||||
val nativeImageSourcesJar =
|
||||
tasks.register<NativeImageSourcesJar>("nativeImageSourcesJar$variant") {
|
||||
compiledClasses = compiledClassesFile
|
||||
openJdkTarball.from(openJdkSourcesTarball)
|
||||
graalTarball.from(graalSourcesTarball)
|
||||
openJdkPlatforms.addAll(target.os.openJdkPlatforms)
|
||||
outputJar = outputDir.map { it.file("native-image-sources.jar") }
|
||||
}
|
||||
|
||||
val openJdkNativeSourcesJar =
|
||||
tasks.register<Zip>("openJdkNativeSourcesJar$variant") {
|
||||
archiveFileName = "openjdk-native-sources.jar"
|
||||
destinationDirectory = outputDir
|
||||
includeEmptyDirs = false
|
||||
|
||||
from(provider { tarTree(resources.gzip(openJdkSourcesTarball.singleFile)) }) {
|
||||
for (platform in target.os.openJdkPlatforms) {
|
||||
include("*/src/*/$platform/native/include/**")
|
||||
for (library in openJdkNativeLibraries) {
|
||||
include("*/src/*/$platform/native/lib$library/**")
|
||||
}
|
||||
}
|
||||
// drop the `<repo>-<tag>/` root directory
|
||||
eachFile {
|
||||
relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val graalNativeSourcesJar =
|
||||
tasks.register<Zip>("graalNativeSourcesJar$variant") {
|
||||
archiveFileName = "graal-native-sources.jar"
|
||||
destinationDirectory = outputDir
|
||||
includeEmptyDirs = false
|
||||
|
||||
from(provider { tarTree(resources.gzip(graalSourcesTarball.singleFile)) }) {
|
||||
for (svmProject in target.os.svmNativeProjects) {
|
||||
include("*/substratevm/src/com.oracle.svm.native.$svmProject/**")
|
||||
}
|
||||
eachFile {
|
||||
relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Executables for musl targets are statically linked, so musl and zlib are part of them.
|
||||
val staticLibcSources =
|
||||
if (target.musl) {
|
||||
val muslArch =
|
||||
when (target.arch) {
|
||||
Target.Arch.AMD64 -> "x86_64"
|
||||
Target.Arch.AARCH64 -> "aarch64"
|
||||
}
|
||||
|
||||
val muslSourcesJar =
|
||||
tasks.register<Zip>("muslSourcesJar$variant") {
|
||||
archiveFileName = "musl-sources.jar"
|
||||
destinationDirectory = outputDir
|
||||
includeEmptyDirs = false
|
||||
|
||||
from(provider { tarTree(resources.gzip(muslSourcesTarball.singleFile)) }) {
|
||||
// skip the other architectures
|
||||
include("*/src/**", "*/include/**", "*/crt/**", "*/ldso/**", "*/compat/**")
|
||||
include("*/arch/generic/**", "*/arch/$muslArch/**")
|
||||
include("*/COPYRIGHT", "*/VERSION", "*/WHATSNEW")
|
||||
eachFile {
|
||||
relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val zlibSourcesJar =
|
||||
tasks.register<Zip>("zlibSourcesJar$variant") {
|
||||
archiveFileName = "zlib-sources.jar"
|
||||
destinationDirectory = outputDir
|
||||
includeEmptyDirs = false
|
||||
|
||||
from(provider { tarTree(resources.gzip(zlibSourcesTarball.singleFile)) }) {
|
||||
exclude("*/.github/**")
|
||||
eachFile {
|
||||
relativePath = RelativePath(true, *relativePath.segments.drop(1).toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceBundleSpec.staticMuslLibc.map { isStatic ->
|
||||
if (isStatic) files(muslSourcesJar, zlibSourcesJar) else files()
|
||||
}
|
||||
} else {
|
||||
provider { files() }
|
||||
}
|
||||
|
||||
tasks.register<BuildSourceBundle>("sourceBundle$variant") {
|
||||
group = "build"
|
||||
description = "Builds the source bundle of ${project.name} for ${target.targetName}."
|
||||
inputJars.from(
|
||||
sourceBundleSpec.firstPartyJars,
|
||||
sourceBundleSpec.extraNativeSources,
|
||||
nativeImageSourcesJar,
|
||||
openJdkNativeSourcesJar,
|
||||
graalNativeSourcesJar,
|
||||
staticLibcSources,
|
||||
)
|
||||
// Only include sources of dependency classes that are compiled into the image.
|
||||
filteredInputJars.from(resolveNativeSourcesJars.map { fileTree(it.outputDir) })
|
||||
compiledClasses = compiledClassesFile
|
||||
outputZip =
|
||||
layout.buildDirectory.file(
|
||||
"sourceBundle/${project.name}-${project.version}-${target.targetName}-sourcebundle.zip"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("sourceBundle") { dependsOn(sourceBundleTasks) }
|
||||
|
||||
/**
|
||||
* Downloads the lists of classes compiled into native images, which CI uploads as
|
||||
* `compiled-classes-<project>-<os>-<arch>` artifacts, into `build/compiled-classes`.
|
||||
*
|
||||
* Requires the GitHub CLI (`gh`) to be installed and authenticated.
|
||||
*/
|
||||
abstract class DownloadCompiledClasses : DefaultTask() {
|
||||
@get:Option(option = "run-id", description = "ID of the GitHub Actions run to download from.")
|
||||
@get:Input
|
||||
abstract val runId: Property<String>
|
||||
|
||||
@get:Option(option = "repo", description = "GitHub repository that the run belongs to.")
|
||||
@get:Input
|
||||
abstract val repo: Property<String>
|
||||
|
||||
/** The project whose artifacts to download (named `compiled-classes-<project>-*`). */
|
||||
@get:Input abstract val projectName: Property<String>
|
||||
|
||||
@get:OutputDirectory abstract val destinationDir: DirectoryProperty
|
||||
|
||||
@get:Inject protected abstract val execOperations: ExecOperations
|
||||
|
||||
init {
|
||||
group = "build"
|
||||
description = "Downloads the compiled classes lists that CI produced into the build directory."
|
||||
repo.convention("apple/pkl")
|
||||
// always re-download; this task is meant to be run manually
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
@Suppress("unused")
|
||||
fun download() {
|
||||
if (!runId.isPresent) {
|
||||
throw GradleException("Specify the run to download from, e.g. `--run-id=<id>`")
|
||||
}
|
||||
val name = projectName.get()
|
||||
val downloadDir = temporaryDir.resolve("download")
|
||||
downloadDir.deleteRecursively()
|
||||
downloadDir.mkdirs()
|
||||
|
||||
execOperations.exec {
|
||||
commandLine(
|
||||
"gh",
|
||||
"run",
|
||||
"download",
|
||||
runId.get(),
|
||||
"--repo",
|
||||
repo.get(),
|
||||
"--pattern",
|
||||
"compiled-classes-$name-*",
|
||||
"--dir",
|
||||
downloadDir.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
// Files are named `<project>-<version>-<target name>.txt`; keep only the target name.
|
||||
val fileName = Regex("^${Regex.escape(name)}-\\d+(?:\\.\\d+)*(?:-SNAPSHOT)?-(.+\\.txt)$")
|
||||
val downloaded =
|
||||
downloadDir
|
||||
.walkTopDown()
|
||||
.filter { it.isFile }
|
||||
.associate { file ->
|
||||
val target =
|
||||
fileName.matchEntire(file.name)?.groupValues?.get(1)
|
||||
?: throw GradleException("Unexpected file in downloaded artifacts: $file")
|
||||
target to file
|
||||
}
|
||||
if (downloaded.isEmpty()) {
|
||||
throw GradleException("Run ${runId.get()} has no `compiled-classes-$name-*` artifacts")
|
||||
}
|
||||
|
||||
val destination = destinationDir.get().asFile
|
||||
destination.mkdirs()
|
||||
// remove lists of targets that are no longer built
|
||||
destination.listFiles { f -> f.extension == "txt" }?.forEach { it.delete() }
|
||||
for ((target, file) in downloaded) {
|
||||
file.copyTo(destination.resolve(target))
|
||||
}
|
||||
logger.lifecycle("Downloaded ${downloaded.keys.sorted()} into $destination")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<DownloadCompiledClasses>("downloadCompiledClasses") {
|
||||
projectName = project.name
|
||||
destinationDir = layout.buildDirectory.dir("compiled-classes")
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright © 2026 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.
|
||||
*/
|
||||
plugins { id("pklAllProjects") }
|
||||
|
||||
// Sources jars of the first-party projects that this project depends on.
|
||||
// Ideally we'd configure this automatically based on project dependencies.
|
||||
val firstPartySourcesJars: Configuration = configurations.create("firstPartySourcesJars")
|
||||
|
||||
// Sources jars of third-party dependencies. Project dependencies are not covered by this; they
|
||||
// are added to `firstPartySourcesJars` instead.
|
||||
val resolveSourcesJars =
|
||||
tasks.register<ResolveSourcesJars>("resolveSourcesJars") {
|
||||
configuration.set(configurations.named("runtimeClasspath"))
|
||||
outputDir.set(layout.buildDirectory.dir("resolveSourcesJars"))
|
||||
}
|
||||
|
||||
val sourceBundleSpec = extensions.create<SourceBundleSpec>("sourceBundleSpec")
|
||||
|
||||
sourceBundleSpec.staticMuslLibc.convention(false)
|
||||
|
||||
plugins.withId("pklJavaLibrary") { sourceBundleSpec.firstPartyJars.from(tasks.named("sourcesJar")) }
|
||||
|
||||
plugins.withId("pklKotlinLibrary") {
|
||||
sourceBundleSpec.firstPartyJars.from(tasks.named("sourcesJar"))
|
||||
}
|
||||
|
||||
sourceBundleSpec.firstPartyJars.from(firstPartySourcesJars)
|
||||
|
||||
sourceBundleSpec.dependencyJars.from(resolveSourcesJars.map { fileTree(it.outputDir) })
|
||||
|
||||
// Builds every source bundle of this project; there is one for each variant that the project is
|
||||
// distributed as. The variants are registered by `pklJvmSourceBundle` and `pklNativeSourceBundle`.
|
||||
tasks.register("sourceBundle") {
|
||||
group = "build"
|
||||
description = "Builds the source bundles of all variants of this project."
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
name: main
|
||||
title: Main Project
|
||||
version: 0.33.0-dev
|
||||
version: 0.34.0-dev
|
||||
prerelease: true
|
||||
nav:
|
||||
- nav.adoc
|
||||
@@ -3,7 +3,7 @@
|
||||
// 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.33.0
|
||||
:pkl-version-no-suffix: 0.34.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:
|
||||
@@ -74,8 +74,9 @@ endif::[]
|
||||
:uri-stdlib-jsonnetModule: {uri-pkl-stdlib-docs}/jsonnet
|
||||
:uri-stdlib-reflectModule: {uri-pkl-stdlib-docs}/reflect
|
||||
:uri-stdlib-mathModule: {uri-pkl-stdlib-docs}/math
|
||||
:uri-stdlib-netModule: {uri-pkl-stdlib-docs}/net
|
||||
:uri-stdlib-net-Url: {uri-stdlib-netModule}/Url
|
||||
:uri-stdlib-xmlModule: {uri-pkl-stdlib-docs}/xml
|
||||
:uri-stdlib-protobufModule: {uri-pkl-stdlib-docs}/protobuf
|
||||
:uri-stdlib-pklbinaryModule: {uri-pkl-stdlib-docs}/pklbinary
|
||||
:uri-stdlib-yamlModule: {uri-pkl-stdlib-docs}/yaml
|
||||
:uri-stdlib-YamlParser: {uri-stdlib-yamlModule}/Parser
|
||||
|
||||
@@ -46,7 +46,7 @@ The first slot of the array designates the value's type.
|
||||
The remaining slots have fixed meanings depending on the type.
|
||||
Additional slots may be added to types in future Pkl releases. Decoders *must* be designed to defensively discard values beyond the number of known slots for a type or provide meaningful error messages.
|
||||
|
||||
The array's length is the number of slots that are filled. For example, xref:{uri-stdlib-List}[List] is encoded as an MessagePack array with two elements.
|
||||
The array's length is the number of slots that are filled. For example, link:{uri-stdlib-List}[List] is encoded as an MessagePack array with two elements.
|
||||
|
||||
|===
|
||||
|Pkl type |Slot 1 2+|Slot 2 2+|Slot 3 2+|Slot 4
|
||||
|
||||
@@ -22,6 +22,24 @@ Default: (not set) +
|
||||
Flag that indicates to generate config classes for use with Spring Boot.
|
||||
====
|
||||
|
||||
.--spring-boot-configuration-properties
|
||||
[%collapsible]
|
||||
====
|
||||
Default: (none) +
|
||||
Example: `my.mod#Server=server` +
|
||||
Explicitly configures which generated classes receive the Spring Boot `@ConfigurationProperties` annotation, and with what prefix.
|
||||
Only applies if `--generate-spring-boot` is set.
|
||||
|
||||
The key is the Pkl class name (for example, `my.mod` for a module class, or `my.mod#Server` for a class within a module), and the value is the annotation's prefix.
|
||||
An empty value generates a bare `@ConfigurationProperties` annotation.
|
||||
|
||||
If this option is omitted, the annotations are inferred from the structure of the input modules.
|
||||
If this option is set, no annotations are inferred, and only the specified classes are annotated.
|
||||
|
||||
Repeat this option to define multiple mappings.
|
||||
Values must be valid Spring Boot configuration properties prefixes.
|
||||
====
|
||||
|
||||
.--implement-serializable
|
||||
[%collapsible]
|
||||
====
|
||||
|
||||
@@ -2100,6 +2100,8 @@ The xref:blog:ROOT:class-as-a-function.adoc[Class-as-a-function] pattern may be
|
||||
TIP: In most cases, methods without parameters should not be defined.
|
||||
Instead, use <<fixed-properties,`fixed` properties>> on the module or class.
|
||||
|
||||
Methods may also be <<generic-methods,generic>>.
|
||||
|
||||
[[modules]]
|
||||
== Modules
|
||||
|
||||
@@ -2750,7 +2752,6 @@ The standard library provides these renderers:
|
||||
* link:{uri-stdlib-baseModule}/PcfRenderer[PcfRenderer]
|
||||
* link:{uri-stdlib-baseModule}/PListRenderer[PListRenderer]
|
||||
* link:{uri-stdlib-baseModule}/PropertiesRenderer[PropertiesRenderer]
|
||||
* link:{uri-stdlib-protobufModule}/Renderer[protobuf.Renderer]
|
||||
* link:{uri-stdlib-xmlModule}/Renderer[xml.Renderer]
|
||||
* link:{uri-stdlib-baseModule}/YamlRenderer[YamlRenderer]
|
||||
|
||||
@@ -3282,7 +3283,8 @@ This section discusses language features that are generally more relevant to tem
|
||||
<<projects,Projects>> +
|
||||
<<external-readers,External Readers>> +
|
||||
<<mirroring_packages,Mirroring packages>> +
|
||||
<<references,References>>
|
||||
<<references,References>> +
|
||||
<<generic-methods,Generic Methods>>
|
||||
|
||||
[[meaning-of-new]]
|
||||
=== Meaning of `new`
|
||||
@@ -3361,6 +3363,7 @@ The value will not have property `isPredatory = true` as the `default` property
|
||||
<3> Assigning a `new` explicitly-typed value to a `Mapping` entry.
|
||||
The value will not have property `isPredatory = true` as the `default` property of the `Mapping` is not used.
|
||||
|
||||
[[implicitly-typed-new]]
|
||||
==== Implicitly Typed `new`
|
||||
|
||||
When using the implicitly typed `new` invocation, there is no explicit parent value to amend.
|
||||
@@ -3368,6 +3371,8 @@ In these cases, Pkl infers the amend operation's parent value based on context:
|
||||
|
||||
* When assigning to a declared property, the property's default value is amended (<<amend-null, including `null`>>).
|
||||
If there is no type associated with the property, an empty `Dynamic` object is amended.
|
||||
* In method argument, method return value, and let binding positions, the annotated type's default value is amended.
|
||||
If there is no type annotation, an empty `Dynamic` object is amended.
|
||||
* When assigning to an entry (e.g. a `Mapping` member) or element (e.g. a `Listing` member), the enclosing object's `default` property is applied to the corresponding index or key, respectively, to produce the value to be amended.
|
||||
* In other cases, evaluation fails with the error message "Cannot tell which parent to amend".
|
||||
|
||||
@@ -3379,29 +3384,29 @@ In this case, the argument's type should be specified explicitly.
|
||||
class Bird {
|
||||
name: String
|
||||
|
||||
function listHatchlings(items: Listing<String>): Listing<String> = new {
|
||||
function listHatchlings(items: Listing<String>): Listing<String> = new { // <1>
|
||||
for (item in items) {
|
||||
"\(name):\(item)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedProperty: Bird = new { // <1>
|
||||
typedProperty: Bird = new { // <2>
|
||||
name = "Swift"
|
||||
}
|
||||
|
||||
untypedProperty = new { // <2>
|
||||
untypedProperty = new { // <3>
|
||||
hello = "world"
|
||||
}
|
||||
|
||||
typedListing: Listing<Bird> = new {
|
||||
new { // <3>
|
||||
new { // <4>
|
||||
name = "Kite"
|
||||
}
|
||||
}
|
||||
|
||||
untypedListing: Listing = new {
|
||||
new { // <4>
|
||||
new { // <5>
|
||||
hello = "there"
|
||||
}
|
||||
}
|
||||
@@ -3410,13 +3415,13 @@ typedMapping: Mapping<String, Bird> = new {
|
||||
default { entryKey ->
|
||||
name = entryKey
|
||||
}
|
||||
["Saltmarsh Sparrow"] = new { // <5>
|
||||
["Saltmarsh Sparrow"] = new { // <6>
|
||||
name = "Sharp-tailed Sparrow"
|
||||
}
|
||||
}
|
||||
|
||||
amendedMapping = (typedMapping) {
|
||||
["Saltmarsh Sparrow"] = new {} // <6>
|
||||
["Saltmarsh Sparrow"] = new {} // <7>
|
||||
}
|
||||
|
||||
class Aviary {
|
||||
@@ -3426,22 +3431,27 @@ class Aviary {
|
||||
}
|
||||
|
||||
aviary: Aviary = new {
|
||||
birds = new { // <7>
|
||||
birds = new { // <8>
|
||||
new { name = "Kiwi" }
|
||||
}
|
||||
}
|
||||
|
||||
swiftHatchlings = typedProperty.listHatchlings(new { "Poppy"; "Chirpy" }) // <8>
|
||||
----
|
||||
swiftHatchlings = typedProperty.listHatchlings(new { "Poppy"; "Chirpy" }) // <9>
|
||||
|
||||
<1> Assignment to a property with an explicitly declared type, amending `new Bird {}`.
|
||||
<2> Assignment to an undeclared property in module context, amending `new Dynamic {}`.
|
||||
<3> `Listing` element creation, amending implicit `default`, `new Bird {}`.
|
||||
<4> `Listing` element creation, amending implicit `default`, `new Dynamic {}`.
|
||||
<5> `Mapping` value assignment, amending the result of applying `default` to `"Saltmarsh Sparrow"`, `new Bird { name = "Saltmarsh Sparrow" }`.
|
||||
<6> `Mapping` value assignment _replacing_ the parent's entry, amending the result of applying `default` to `"Saltmarsh Sparrow"`, `new Bird { name = "Saltmarsh Sparrow" }`.
|
||||
<7> Amending the property default value `new Listing { new Bird { name = "Osprey" } }`; the result contains both birds.
|
||||
<8> Error: Cannot tell which parent to amend.
|
||||
pigeonHatchlings =
|
||||
let (hatchlingNames: Listing<String> = new { "Polly"; "Daisy" }) // <10>
|
||||
new Bird { name = "Pigeon" }.listHatchlings(hatchlingNames)
|
||||
----
|
||||
<1> Instantiation of a method return value, amending the return type's default value `new Listing<String> {}`.
|
||||
<2> Assignment to a property with an explicitly declared type, amending `new Bird {}`.
|
||||
<3> Assignment to an undeclared property in module context, amending `new Dynamic {}`.
|
||||
<4> `Listing` element creation, amending implicit `default`, `new Bird {}`.
|
||||
<5> `Listing` element creation, amending implicit `default`, `new Dynamic {}`.
|
||||
<6> `Mapping` value assignment, amending the result of applying `default` to `"Saltmarsh Sparrow"`, `new Bird { name = "Saltmarsh Sparrow" }`.
|
||||
<7> `Mapping` value assignment _replacing_ the parent's entry, amending the result of applying `default` to `"Saltmarsh Sparrow"`, `new Bird { name = "Saltmarsh Sparrow" }`.
|
||||
<8> Amending the property default value `new Listing { new Bird { name = "Osprey" } }`; the result contains both birds.
|
||||
<9> Instantiation of a method argument, amending the parameter type's default value `new Listing<String> {}`.
|
||||
<10> Instantiation inside a <<let-expressions,`let` binding>>, amending the binding's type's default value `new Listing<String> {}`.
|
||||
|
||||
[[let-expressions]]
|
||||
=== Let Expressions
|
||||
@@ -5994,32 +6004,13 @@ There are some restrictions on properties that may be referenced; attempting to
|
||||
* Properties originally defined in `external` classes (this only includes `Module.output`)
|
||||
|
||||
pkldoc:Reference[pkl:ref] instances are created using the constructor method pkldoc:#Reference()[pkl:ref].
|
||||
This method accepts three parameters:
|
||||
This method accepts two type arguments and two parameters:
|
||||
|
||||
* `domain` - An instance of a `ref.Domain` subclass; its type becomes the `D` type argument of the resulting `Reference` instance.
|
||||
* `class` - A `Class` instance that will be the referent type of the returned `Reference`; it is the `T` type argument of the resulting instance.
|
||||
* `D` - The type of the reference's domain. Must be a subclass of `ref.Domain`.
|
||||
* `Referent` - The type the reference refers to.
|
||||
* `domain` - An instance of `D` that becomes the domain resulting `Reference` instance.
|
||||
* `data` - A domain-specific value used to identify the root or context of the reference.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
It is only possible to construct new references with a referent type that is a simple (non-generic) class type.
|
||||
To obtain a reference to values of other types (generic, typealias, nullable, union, etc.), libraries must wrap those types in a class:
|
||||
|
||||
[source%parsed,pkl]
|
||||
----
|
||||
import "pkl:ref"
|
||||
|
||||
class TypeHolder {
|
||||
$: *Listing<String>? | Mapping<UInt, String> // <1>
|
||||
}
|
||||
|
||||
local r: ref.Reference<MyDomain, Listing<String>? | Mapping<UInt, String>> =
|
||||
ref.Reference(myDomain, TypeHolder, null).$ // <2>
|
||||
----
|
||||
<1> Define a "holder" class with a property of the desired type.
|
||||
<2> Access the `$` property of the reference to get a reference to the desired non-class type.
|
||||
====
|
||||
|
||||
Here's a realistic example of how references might be used:
|
||||
|
||||
[source,pkl]
|
||||
@@ -6027,7 +6018,7 @@ Here's a realistic example of how references might be used:
|
||||
----
|
||||
import "pkl:ref"
|
||||
|
||||
class Domain extends ref.Domain { // <1>
|
||||
class Domain extends ref.AbstractDomain { // <1>
|
||||
function renderReference(reference: ref.Reference<Domain, Any>): String =
|
||||
if (reference.getData() is Task)
|
||||
let (path = reference.getPath().map((access) -> access.property ?? access.key.toString()))
|
||||
@@ -6038,18 +6029,20 @@ class Domain extends ref.Domain { // <1>
|
||||
|
||||
typealias Ref<T> = ref.Reference<Domain, T> // <2>
|
||||
|
||||
abstract class Task { // <3>
|
||||
const function Ref<T>(data: Any): Ref<T> = ref.Reference<Domain, T>(new Domain {}, data) // <3>
|
||||
|
||||
abstract class Task { // <4>
|
||||
name: String
|
||||
}
|
||||
|
||||
class TaskA extends Task {
|
||||
input1: String | Ref<String> // <4>
|
||||
input1: String | Ref<String> // <5>
|
||||
input2: Int | Ref<Int>
|
||||
|
||||
hidden fixed outputs: Ref<TaskAOutputs> = ref.Reference(new Domain {}, TaskAOutputs, this) // <5>
|
||||
hidden fixed outputs: Ref<TaskAOutputs> = Ref<TaskAOutputs>(this) // <6>
|
||||
}
|
||||
|
||||
abstract class TaskAOutputs { // <6>
|
||||
abstract class TaskAOutputs { // <7>
|
||||
foo: String
|
||||
bar: Int
|
||||
}
|
||||
@@ -6059,24 +6052,25 @@ class TaskB extends Task {
|
||||
inputY: Int | Ref<Int>
|
||||
}
|
||||
|
||||
tasks: Listing<Task>(isDistinctBy((it) -> it.name)) // <7>
|
||||
tasks: Listing<Task>(isDistinctBy((it) -> it.name)) // <8>
|
||||
|
||||
output {
|
||||
renderer {
|
||||
converters {
|
||||
[ref.Reference] = (it) -> it.toString() // <8>
|
||||
[ref.Reference] = (it) -> it.toString() // <9>
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
<1> Define a `ref.Domain` subclass that determines how `Reference` instances are rendered as strings.
|
||||
<2> For convenience, create a type alias for references of this domain.
|
||||
<3> Create a new base class that can be referenced. `Task` instances will be identified by their `name` value.
|
||||
<4> In a specific `Task` subclass, input values accept both literal values and references to the same type.
|
||||
<5> `Task` subclasses that provide output values define an `outputs` property where the referent type is `TaskAOutputs`.
|
||||
<6> The `TaskAOutputs` class defines the possible runtime outputs of `TaskA` tasks. It is `abstract` and never instantiated, only used for producing references.
|
||||
<7> Users provide `Task` instances with unique `name` values.
|
||||
<8> Delegate to `Domain` for rendering `Reference` values.
|
||||
<3> For convenience, wrap the `Reference` constructor to pass appropriate the domain type and value.
|
||||
<4> Create a new base class that can be referenced. `Task` instances will be identified by their `name` value.
|
||||
<5> In a specific `Task` subclass, input values accept both literal values and references to the same type.
|
||||
<6> `Task` subclasses that provide output values define an `outputs` property where the referent type is `TaskAOutputs`.
|
||||
<7> The `TaskAOutputs` class defines the possible runtime outputs of `TaskA` tasks. It is `abstract` and never instantiated, only used for producing references.
|
||||
<8> Users provide `Task` instances with unique `name` values.
|
||||
<9> Delegate to `Domain` for rendering `Reference` values.
|
||||
|
||||
[source,pkl]
|
||||
.myWorkflow.pkl
|
||||
@@ -6119,3 +6113,37 @@ tasks {
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
[[generic-methods]]
|
||||
=== Generic Methods
|
||||
|
||||
Methods may be declared as "generic", with types that are themselves parameters.
|
||||
Method type parameters may be used within the method anywhere else a type may be used: in a parameter's type, in the return type, or within the method body (e.g. <<defining-objects,object instantiation>>, <<type-tests,type tests>>, <<type-casts,type casts>>).
|
||||
|
||||
When calling a generic method, a caller may manually specify type arguments by writing `methodName<TypeArg1, TypeArg2>(arg1, arg2)`.
|
||||
When no type arguments are provided, type checks of parameter types behave like <<unknown-type,`unknown`>> and always succeed.
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
class Pigeon {
|
||||
name: String
|
||||
}
|
||||
|
||||
class Hawk {
|
||||
name: String
|
||||
}
|
||||
|
||||
function makeFlock<Bird>(names: Listing<String>): Listing<Bird> = new {
|
||||
for (n in names) {
|
||||
new { name = n }
|
||||
}
|
||||
}
|
||||
|
||||
pigeonFlock = makeFlock<Pigeon>(new { "Alice"; "Bill"; "Ruth" }) // <1>
|
||||
hawkFlock = makeFlock<Hawk>(new { "Florence"; "Holly"; "Jim" }) // <2>
|
||||
----
|
||||
<1> Result: a `Listing` where every element is a `Pigeon`.
|
||||
<2> Result: a `Listing` where every element is a `Hawk`.
|
||||
|
||||
NOTE: A `<` following an identifier is parsed as the start of a type argument list when it is well-formed and directly followed by `(`.
|
||||
Otherwise, it is parsed as the less-than operator; for example, `foo<bar>(baz)` is a method call with type arguments, whereas `foo<bar + 5>(baz)` is a comparison.
|
||||
@@ -7,6 +7,14 @@ It is designed to be a low-level API that interacts with Pkl via the xref:bindin
|
||||
It is meant to be paired with higher level logic written in a host language within the context of a Pkl language binding library.
|
||||
The higher level logic deals with implementing the evaluator API, and serializing/deserializing messages according to the message passing API.
|
||||
|
||||
== Installing libpkl
|
||||
|
||||
Currently, we do not publish libpkl.
|
||||
Therefore, libpkl needs to be built from source, by cloning this repository and running the steps laid out in <<build-from-source>>.
|
||||
|
||||
Once built, it can be <<linking-to-libpkl,linked against>>, either statically or dynamically.
|
||||
|
||||
[[linking-to-libpkl]]
|
||||
== Linking to libpkl
|
||||
|
||||
It is possible to link to libpkl either as a static library or a dynamic library.
|
||||
@@ -16,50 +24,6 @@ However, this impacts the binary size of your application, as libpkl's library f
|
||||
|
||||
On the other hand, dynamically linking to libpkl has negligible impact on binary size, but requires that end users have libpkl installed on their OS.
|
||||
|
||||
== Distribution
|
||||
|
||||
We publish archives that contain header files, as well as both shared and static libraries.
|
||||
|
||||
The distributions are published as releases on GitHub, and can be downloaded for the appropriate OS/architecture.
|
||||
|
||||
The archives contain both statically linked and dynamically linked binaries for each OS.
|
||||
|
||||
The archive has the following structure:
|
||||
|
||||
[source]
|
||||
----
|
||||
.
|
||||
└── libpkl-<version>-<os>-<arch>
|
||||
├── include
|
||||
│ └── pkl.h
|
||||
├── lib
|
||||
│ ├── libpkl.<shared library extension>
|
||||
│ ├── libpkl.<static library extension>
|
||||
│ └── pkgconfig
|
||||
│ ├── libpkl-static.pc
|
||||
│ └── libpkl.pc
|
||||
├── LICENSE.txt
|
||||
├── README.md
|
||||
└── THIRD-PARTY-NOTICES.txt
|
||||
----
|
||||
|
||||
The file extensions are as follows:
|
||||
|===
|
||||
|OS |Static Library Extension |Shared library extension
|
||||
|
||||
|macOS
|
||||
|`.a`
|
||||
|`.dylib`
|
||||
|
||||
|Linux
|
||||
|`.a`
|
||||
|`.so`
|
||||
|
||||
|Windows
|
||||
|`.lib`
|
||||
|`.dll`
|
||||
|===
|
||||
|
||||
=== Linking to the static vs. shared library
|
||||
|
||||
The simplest way to configure your compiler to link to either the static or the shared library is to use https://en.wikipedia.org/wiki/Pkg-config[pkg-config].
|
||||
@@ -98,6 +62,7 @@ cc -Wl,-Bstatic $(pkg-config --libs --cflags libpkl)
|
||||
----
|
||||
====
|
||||
|
||||
[[build-from-source]]
|
||||
== Building libpkl from source
|
||||
|
||||
To build libpkl from source, the apple/pkl repository first must be cloned down to a host OS.
|
||||
@@ -126,6 +91,46 @@ This results in two directories of interest:
|
||||
|
||||
Cross-compilation is not supported.
|
||||
|
||||
=== Distribution layout
|
||||
|
||||
The built distribution archive contains both statically linked and dynamically linked binaries for each OS.
|
||||
|
||||
The archive has the following structure:
|
||||
|
||||
[source]
|
||||
----
|
||||
.
|
||||
└── libpkl-<version>-<os>-<arch>
|
||||
├── include
|
||||
│ └── pkl.h
|
||||
├── lib
|
||||
│ ├── libpkl.<shared library extension>
|
||||
│ ├── libpkl.<static library extension>
|
||||
│ └── pkgconfig
|
||||
│ ├── libpkl-static.pc
|
||||
│ └── libpkl.pc
|
||||
├── LICENSE.txt
|
||||
├── README.md
|
||||
└── THIRD-PARTY-NOTICES.txt
|
||||
----
|
||||
|
||||
The file extensions are as follows:
|
||||
|===
|
||||
|OS |Static Library Extension |Shared library extension
|
||||
|
||||
|macOS
|
||||
|`.a`
|
||||
|`.dylib`
|
||||
|
||||
|Linux
|
||||
|`.a`
|
||||
|`.so`
|
||||
|
||||
|Windows
|
||||
|`.lib`
|
||||
|`.dll`
|
||||
|===
|
||||
|
||||
== ABI compatibility
|
||||
|
||||
libpkl is ABI compatible across Pkl versions.
|
||||
|
||||
@@ -307,7 +307,6 @@ The default output renderer for a module supports the following formats:
|
||||
* `pcf`
|
||||
* `plist`
|
||||
* `properties`
|
||||
* `textproto` (deprecated in Pkl 0.33)
|
||||
* `xml`
|
||||
* `yaml`
|
||||
|
||||
@@ -450,6 +449,24 @@ When enabled, type constraint failures will show intermediate values in the asse
|
||||
Use `--no-power-assertions` to disable this feature if you prefer simpler output or better performance.
|
||||
====
|
||||
|
||||
[[profile-cpu-output]]
|
||||
.--profile-cpu-output
|
||||
[%collapsible]
|
||||
====
|
||||
Default: (none) +
|
||||
The file to write profiler output to. Omitting this option disables CPU profiling entirely. +
|
||||
|
||||
The CPU profiler writes output in https://github.com/google/pprof[pprof] format.
|
||||
====
|
||||
|
||||
[[profile-cpu-sample-period]]
|
||||
.--profile-cpu-sample-period
|
||||
[%collapsible]
|
||||
====
|
||||
Default: 10 +
|
||||
The sampling duration for the CPU sampler, in milliseconds.
|
||||
====
|
||||
|
||||
This command also takes <<common-options, common options>>.
|
||||
|
||||
[[command-server]]
|
||||
|
||||
@@ -152,7 +152,6 @@ The default output renderer for a module supports the following formats:
|
||||
* `"pcf"`
|
||||
* `"plist"`
|
||||
* `"properties"`
|
||||
* `"textproto"` (deprecated in Pkl 0.33)
|
||||
* `"xml"`
|
||||
* `"yaml"`
|
||||
====
|
||||
|
||||
@@ -36,6 +36,21 @@ Example: `generateSpringBootConfig = true` +
|
||||
Whether to generate config classes for use with Spring Boot.
|
||||
====
|
||||
|
||||
.springBootConfigurationProperties: MapProperty<String, String>
|
||||
[%collapsible]
|
||||
====
|
||||
Default: `[:]` +
|
||||
Example: `springBootConfigurationProperties = ["my.mod": "", "my.mod#Server": "server"]` +
|
||||
Explicitly configures which generated classes receive the Spring Boot `@ConfigurationProperties` annotation, and with what prefix.
|
||||
Only applies if `generateSpringBootConfig` is `true`.
|
||||
|
||||
The key is the Pkl class name (for example, `my.mod` for a module class, or `my.mod#Server` for a class within a module), and the value is the annotation's prefix.
|
||||
An empty value generates a bare `@ConfigurationProperties` annotation.
|
||||
|
||||
If this property is empty, the annotations are inferred from the structure of the input modules.
|
||||
If this property is set, no annotations are inferred, and only the specified classes are annotated.
|
||||
====
|
||||
|
||||
.implementSerializable: Property<Boolean>
|
||||
[%collapsible]
|
||||
====
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
= Pkl 0.32 Release Notes
|
||||
:version: 0.32
|
||||
:version-minor: 0.32.1
|
||||
:version-minor: 0.32.2
|
||||
:release-date: July 8th, 2026
|
||||
:version-next: 0.33
|
||||
:version-next-date: October 2026
|
||||
@@ -62,7 +62,7 @@ Library authors describe types as `ref.Reference<D, T>`, where `D` is the _domai
|
||||
----
|
||||
import "pkl:ref"
|
||||
|
||||
class MyDomain extends ref.Domain { // <1>
|
||||
class MyDomain extends ref.AbstractDomain { // <1>
|
||||
function renderReference(ref: ref.Reference<MyDomain, Any>): String =
|
||||
"${ " + ref.getData() + "." + ref.getPath().join(".") + " }"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
= Pkl 0.33 Release Notes
|
||||
:version: 0.33
|
||||
:version-minor: 0.33.0
|
||||
:release-date: XXX
|
||||
:release-date: November 5th, 2026
|
||||
:version-next: 0.34
|
||||
:version-next-date: February 2027
|
||||
|
||||
@@ -9,12 +9,302 @@ include::partial$intro.adoc[]
|
||||
|
||||
== Highlights [small]#💖#
|
||||
|
||||
=== XXX
|
||||
[[generic-methods]]
|
||||
=== Generic Methods
|
||||
|
||||
Support for generic methods has been greatly expanded (https://github.com/apple/pkl/pull/1849[#1849], https://github.com/apple/pkl/pull/1940[#1940]).
|
||||
|
||||
A generic method is a method that accepts types as arguments.
|
||||
This is a powerful tool that allows writing business logic that works over a variety of types.
|
||||
|
||||
For example, this code declares two parameters: type parameter `T`, and value parameter `arg`.
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
function identity<T>(arg: T): T = arg
|
||||
----
|
||||
|
||||
Generic methods currently already exist in a limited sense:
|
||||
|
||||
. Only the standard library can declare generic methods.
|
||||
. It is not possible to pass in type arguments when calling generic methods.
|
||||
|
||||
In Pkl 0.33, both of these restrictions are lifted.
|
||||
|
||||
To pass type arguments into a generic method, add the type surrounded by angle brackets:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
result = identity<String>("Hello, World!")
|
||||
----
|
||||
|
||||
If type arguments are omitted entirely, it behaves as calling the method with the `unknown` type.
|
||||
The following two are logically identical:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
result = identity("Hello, World!")
|
||||
result2 = identity<unknown>("Hello, World!")
|
||||
----
|
||||
|
||||
This is a <<parser-rule-change-for-comparison,breaking change>>: in some cases, code that parses as a comparison expression now parses as a method call.
|
||||
|
||||
To read more about generic methods, consult the xref:language-reference:index.adoc#generic-methods[language reference].
|
||||
|
||||
To learn more about the design of generic method calls, consult https://github.com/apple/pkl-evolution/blob/main/spices/SPICE-0032-generic-methods.adoc[SPICE-0032].
|
||||
|
||||
=== New standard library module: `pkl:net`
|
||||
|
||||
A new standard library module is introduced called pkldoc:#[pkl:net], for working with network types (https://github.com/apple/pkl/pull/1834[#1834]).
|
||||
|
||||
Its centerpiece is pkldoc:Url[pkl:net], a URL as defined by https://www.rfc-editor.org/rfc/rfc3986[RFC 3986].
|
||||
A string is parsed with pkldoc:#Url()[pkl:net], which accepts an absolute URL as well as a relative reference, and which throws if the string cannot be parsed:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
import "pkl:net"
|
||||
|
||||
local url = net.Url("https://user:pw@example.com:8080/a/b c?q=1&q=2#f")
|
||||
|
||||
scheme = url.scheme // "https"
|
||||
rawUserInfo = url.rawUserInfo // "user:pw"
|
||||
authority = url.authority // "user:pw@example.com:8080"
|
||||
rawHost = url.rawHost // "example.com"
|
||||
rawPort = url.rawPort // "8080"
|
||||
port = url.port // 8080
|
||||
rawPath = url.rawPath // "/a/b%20c"
|
||||
path = url.path // "/a/b c"
|
||||
pathSegments = url.pathSegments // List("a", "b c")
|
||||
rawQuery = url.rawQuery // "q=1&q=2"
|
||||
queryParameters = url.queryParameters // Mapping { ["q"] = Listing { "1"; "2" } }
|
||||
rawFragment = url.rawFragment // "f"
|
||||
----
|
||||
|
||||
Parsing is lenient: whatever cannot appear literally in a component is percent-encoded as its UTF-8 bytes, and whatever is already encoded is kept as written.
|
||||
Every component is held percent-encoded in its `raw` property, whether the input was encoded or not; the percent-decoded form of each is available as `userInfo`, `host`, `path`, `query`, and `fragment`.
|
||||
The derived `pathSegments` and `queryParameters` are percent-decoded too.
|
||||
|
||||
A URL can also be built from its components, or derived from another URL by amending it.
|
||||
A component given this way has to be percent-encoded already:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
built = new net.Url {
|
||||
scheme = "https"
|
||||
rawHost = "example.com"
|
||||
rawPath = "/a%20b"
|
||||
}.toString() // "https://example.com/a%20b"
|
||||
|
||||
local base = net.Url("https://example.com/a?q=1")
|
||||
|
||||
amended = (base) { rawQuery = null }.toString() // "https://example.com/a"
|
||||
----
|
||||
|
||||
Each component is type-checked, so a URL built this way cannot be malformed.
|
||||
For example, a `rawPort` can only hold digits, only a URL with a `rawHost` can have one, and a `rawPath` of `"/a b"` is rejected.
|
||||
The decoded components are `fixed`, so they cannot be amended.
|
||||
|
||||
A relative reference can be resolved against an absolute URL, which also removes dot segments from the result's path:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
resolved = net.Url("https://example.com/a/b").resolve("../c").toString() // "https://example.com/c"
|
||||
----
|
||||
|
||||
Comparing two URLs with `==` compares their components as written.
|
||||
To instead compare them as the *syntax-based normalization* of RFC 3986, where scheme and host are case-insensitive and percent-encoding is normalized, use `equals()`:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
same = net.Url("HTTPS://Example.com/%7Euser").equals(net.Url("https://example.com/~user")) // true
|
||||
----
|
||||
|
||||
The module also provides standalone helpers: pkldoc:#encodeUrlComponent()[pkl:net] and pkldoc:#decodeUrlComponent()[pkl:net] for percent-encoding, and pkldoc:#buildQuery()[pkl:net] and pkldoc:#parseQuery()[pkl:net] for `application/x-www-form-urlencoded` queries.
|
||||
|
||||
Alongside this module, `pkl:base` gains pkldoc:String#isValidUrl[], which tells whether a string is a valid absolute URL.
|
||||
It is stricter than `net.Url()`, which also parses a relative reference, and which percent-encodes whatever cannot appear literally in a URL component.
|
||||
The `Uri` typealias is now defined in terms of it, which is a <<uri-validates,breaking change>>.
|
||||
|
||||
=== New standard library module: `pkl:syntax`
|
||||
|
||||
A new standard library module is introduced called pkldoc:#[pkl:syntax], for working with Pkl source code (https://github.com/apple/pkl/pull/1821[#1821], https://github.com/apple/pkl/pull/1964[#1964], https://github.com/apple/pkl/pull/1955[#1955]).
|
||||
|
||||
It has three parts:
|
||||
|
||||
* pkldoc:Parser[pkl:syntax] parses a string or resource into a syntax tree, as either a module or an expression.
|
||||
* pkldoc:Node[pkl:syntax] is a node of that tree.
|
||||
It has a `type`, `children`, the verbatim source `text`, and the source `span`.
|
||||
Nodes can be searched, folded, and replaced with the `find*`, `fold`, and `replace*` methods.
|
||||
* pkldoc:FormattingRenderer[pkl:syntax] renders a tree back to Pkl source code, using the canonical Pkl formatter.
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
import "pkl:syntax"
|
||||
|
||||
local myModule = new syntax.Parser {}.parseModule("""
|
||||
class Point {
|
||||
x: Int
|
||||
y: Int
|
||||
}
|
||||
""")
|
||||
|
||||
className = myModule.findChild((n) -> n.type == "class").findChildOfType("identifier").text // "Point"
|
||||
|
||||
ifCount = myModule.fold(0, (acc, n) -> if (n.type == "if_expr") acc + 1 else acc) // 0
|
||||
----
|
||||
|
||||
=== C Library (libpkl)
|
||||
|
||||
A new C library, libpkl, is introduced (https://github.com/apple/pkl/pull/1238[#1238], https://github.com/apple/pkl/pull/1799[#1799], https://github.com/apple/pkl/pull/1801[#1801], https://github.com/apple/pkl/pull/1805[#1805], https://github.com/apple/pkl/pull/1812[#1812]).
|
||||
|
||||
One of Pkl's selling points is the ability to embed the language into another runtime as a library.
|
||||
However, currently, callers from non-JVM languages must spawn Pkl as a child process.
|
||||
This introduces a system dependency on downstream users, and also introduces complexity and overhead for the operating system.
|
||||
|
||||
To address this pain point, a new library called libpkl is released for the C language.
|
||||
|
||||
This is a low-level library meant to be called into from language binding libraries.
|
||||
It exposes the xref:bindings-specification:message-passing-api.adoc[message passing API] through a small C interface (`pkl.h`).
|
||||
|
||||
Archives containing the header, both static and dynamic (shared) libraries, and `pkg-config` files are published for each supported OS and architecture, as part of the GitHub release.
|
||||
|
||||
To read more about libpkl, consult the xref:libpkl:index.adoc[libpkl documentation].
|
||||
|
||||
To read more about the design of this feature, consult https://github.com/apple/pkl-evolution/blob/main/spices/SPICE-0015-c-library-for-pkl.adoc[SPICE-0015].
|
||||
|
||||
Thank you to https://github.com/KushalP[@KushalP] for their contributions to this feature!
|
||||
|
||||
=== CPU Profiler
|
||||
|
||||
The Pkl CLI can now profile where an evaluation spends its CPU time (https://github.com/apple/pkl/pull/1823[#1823], https://github.com/apple/pkl/pull/1931[#1931]).
|
||||
|
||||
Profiling is enabled by passing `--profile-cpu-output`, which sets the file to write the profile to.
|
||||
The profile is written in https://github.com/google/pprof[pprof] format, so it can be explored with any tool that reads it, such as `go tool pprof`.
|
||||
|
||||
[source,shell,opts=novalidate]
|
||||
----
|
||||
$ pkl eval --profile-cpu-output profile.pb.gz myConfig.pkl
|
||||
$ go tool pprof -http=:8080 profile.pb.gz
|
||||
----
|
||||
|
||||
Profiling is only exposed through the CLI.
|
||||
For more details, consult xref:pkl-cli:index.adoc#profile-cpu-output[the CLI documentation].
|
||||
|
||||
== Noteworthy [small]#🎶#
|
||||
|
||||
=== `this` as a type
|
||||
|
||||
The `this` keyword can now be used as a type (https://github.com/apple/pkl/pull/1708[#1708], https://github.com/apple/pkl/pull/1962[#1962]).
|
||||
|
||||
A self type is the type of the object that a member is accessed on.
|
||||
Self types are useful when building class hierarchies, because they let a member refer to the _same_ type as the object it belongs to, even after the class is extended.
|
||||
|
||||
Currently, Pkl has a self-type, `module`, but it specifically describes the type of the module object.
|
||||
There is no equivalent for regular classes nor objects.
|
||||
|
||||
To address this shortcoming, the `this` keyword is now also a type.
|
||||
It refers to the self-type of the directly enclosing object, class, or module.
|
||||
|
||||
When a class is extended, `this` in an inherited member refers to the subclass, not to the class that declares the member:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
open class Node {
|
||||
parent: this?
|
||||
children: List<this>
|
||||
}
|
||||
|
||||
class SpecialNode extends Node {
|
||||
special: Boolean
|
||||
}
|
||||
|
||||
node: SpecialNode = new {
|
||||
special = true
|
||||
parent = new SpecialNode { special = false; children = List() } // <1>
|
||||
children = List(new SpecialNode { special = true; children = List() })
|
||||
}
|
||||
|
||||
bad: SpecialNode = new {
|
||||
special = true
|
||||
parent = new Node {} // <2>
|
||||
}
|
||||
----
|
||||
<1> `parent` has type `SpecialNode?`.
|
||||
<2> Error: `Node` is not a `SpecialNode`.
|
||||
|
||||
The `this` type can be used in properties, method parameters and return types, function types, and type arguments.
|
||||
It cannot be used in a type alias body.
|
||||
|
||||
The `this` type has also been <<this-adoption,adopted in the standard library>>.
|
||||
|
||||
To read more about the design, see https://github.com/apple/pkl-evolution/blob/main/spices/SPICE-0029-self-type.adoc[SPICE-0029].
|
||||
|
||||
=== Better `new {}` inference
|
||||
|
||||
The `new {}` expression can now correctly infer its parent in more positions (https://github.com/apple/pkl/pull/1768[#1768], https://github.com/apple/pkl/pull/1824[#1824], https://github.com/apple/pkl/pull/1845[#1845], https://github.com/apple/pkl/pull/1847[#1847], https://github.com/apple/pkl/pull/1857[#1857]).
|
||||
|
||||
An xref:language-reference:index.adoc#implicitly-typed-new[implicitly typed `new {}` expression] tells Pkl to infer the parent when amending.
|
||||
When used inside a property, for example, it amends the class property default.
|
||||
|
||||
Using `new {}` in the following positions currently throw, and will work in Pkl 0.33:
|
||||
|
||||
* Method arguments
|
||||
* Let bindings
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
class Bird {
|
||||
name: String
|
||||
}
|
||||
|
||||
function greet(bird: Bird): String = "Hello, \(bird.name)"
|
||||
|
||||
greeting1 = greet(new { name = "Pigeon" }) // <1>
|
||||
|
||||
greeting2 =
|
||||
let (bird: Bird = new { name = "Parrot" }) // <2>
|
||||
greet(bird)
|
||||
----
|
||||
<1> The argument is inferred to be a `Bird`.
|
||||
<2> The `let` binding is inferred to be a `Bird`.
|
||||
|
||||
Inference is not available where the parameter type is not known ahead of time.
|
||||
Additionally, it cannot be used for constructor methods like `List()`, generic methods like `Pair()`, and `Function.apply()`.
|
||||
|
||||
It is an error for the parameter type to be `this` or `module`.
|
||||
|
||||
=== Support for parsing `.netrc` files into HTTP headers
|
||||
|
||||
Pkl now supports parsing `.netrc` files to configure HTTP Basic authentication headers (https://github.com/apple/pkl/pull/1817[#1817], https://github.com/apple/pkl/pull/1854[#1854]).
|
||||
|
||||
A new method is introduced called `netRcHeaders()` on class `pkl.EvaluatorSettings#Http`.
|
||||
|
||||
It can be used to read credentials directly from a local `.netrc` file and mapped to HTTP `Authorization` headers:
|
||||
|
||||
.~/.config/pkl/settings.pkl
|
||||
[source,pkl]
|
||||
----
|
||||
amends "pkl:settings"
|
||||
|
||||
http {
|
||||
headers = netRcHeaders(read("/Users/johnappleseed/.netrc"))
|
||||
}
|
||||
----
|
||||
|
||||
It follows standard `curl` parsing rules, supporting comments, quoted values, and escaped characters.
|
||||
|
||||
Thank you to https://github.com/ayashjorden[@ayashjorden] for their contributions to this feature!
|
||||
|
||||
=== CLI Changes
|
||||
|
||||
==== Package installation to the local cache
|
||||
|
||||
The `pkl project package` command has gained a new `--install` flag that triggers installation of the built package(s) into the module cache (https://github.com/apple/pkl/pull/1795[#1795]).
|
||||
|
||||
Local cache installation is useful for local end-to-end testing of dependency trees.
|
||||
This functionality is also available via pkl-gradle.
|
||||
|
||||
|
||||
==== Default file locations
|
||||
|
||||
For new setups, the CLI no longer stores anything under `~/.pkl` (https://github.com/apple/pkl/pull/1809[#1809]).
|
||||
@@ -51,28 +341,94 @@ For example, setting `XDG_CACHE_HOME` will configure the cache directory.
|
||||
|
||||
Note that the existing `~/.pkl/cache` directory is ignored, so Pkl will download packages to populate its cache if configured to do so.
|
||||
|
||||
To learn more about this design, consult https://github.com/apple/pkl-evolution/blob/main/spices/SPICE-0031-os-base-directories.adoc[SPICE-0031].
|
||||
|
||||
Thank you to https://github.com/florinungur[@florinungur] for their contributions to this feature!
|
||||
|
||||
=== Java Library Changes
|
||||
|
||||
==== `pkl.net#Url` maps to `java.net.URI`
|
||||
|
||||
The JVM bindings now understand the new `pkl.net#Url` class (https://github.com/apple/pkl/pull/1834[#1834]).
|
||||
|
||||
The Java and Kotlin code generators generate a `java.net.URI` for a property whose type is pkldoc:Url[pkl:net].
|
||||
|
||||
Two conversions are added to `org.pkl.config.java.mapper.Conversions`, both part of the preconfigured set:
|
||||
|
||||
* `pUrlToString` -- gives the same result as `Url.toString()`
|
||||
* `pUrlToURI` -- throws `ConversionException` if the URL cannot be represented as a `java.net.URI`
|
||||
|
||||
=== Standard Library Changes
|
||||
|
||||
==== `pkl:net`
|
||||
|
||||
* New module introduced.
|
||||
|
||||
==== `pkl:syntax`
|
||||
|
||||
* New module introduced.
|
||||
|
||||
==== `pkl:base`
|
||||
|
||||
* New property: pkldoc:String#isValidUrl[]
|
||||
* Changed typealias: pkldoc:Uri[] is now `String(isValidUrl)` (<<uri-validates,breaking change>>)
|
||||
* [[this-adoption]] Properties refined with `this` type
|
||||
** pkldoc:Any.getClass()[] now returns `Class<this>`
|
||||
** pkldoc:Any.ifNonNull()[] now accepts an argument of type `(this) \-> Result`
|
||||
|
||||
==== `pkl:ref`
|
||||
|
||||
* Renamed class: `Domain` is now `AbstractDomain` (<<reference-changes,breaking change>>)
|
||||
* Changed method: `Reference()` now takes type arguments instead of a `Class` parameter (<<reference-changes,breaking change>>)
|
||||
* pkldoc:AbstractDomain.renderReference()[pkl:ref] now accepts a `Reference<this, Any>`
|
||||
* No longer considered experimental.
|
||||
|
||||
==== `pkl:protobuf`
|
||||
|
||||
* Module deprecated for removal in Pkl 0.34 (https://github.com/apple/pkl/pull/1778[#1778]).
|
||||
|
||||
== Breaking Changes [small]#💔#
|
||||
|
||||
=== Removal of macOS amd64 (Intel) Binaries
|
||||
|
||||
Native `pkl` and `pkldoc` binaries for Intel Mac systems are no longer published with Pkl releases.
|
||||
Native `pkl` and `pkldoc` binaries for Intel Mac systems are no longer published with Pkl releases (https://github.com/apple/pkl/pull/1769[#1769]).
|
||||
|
||||
To continue running new Pkl releases on these systems, use an appropriate Java runtime and the `jpkl` and `jpkldoc` Java executables.
|
||||
|
||||
=== Type check changes for `Class<T>`
|
||||
|
||||
In prior versions of Pkl, type arguments to the `Class` type were erased.
|
||||
Currently, type arguments to the `Class` type are erased.
|
||||
Any `Class` value would typecheck against `Class<T>` for any value of `T`.
|
||||
|
||||
In Pkl 0.33, this erasure has been removed.
|
||||
A `Class` value typechecked against `Class<T>` must be a subclass of `T`.
|
||||
A `Class` value typechecked against `Class<T>` must be a subclass of `T` (https://github.com/apple/pkl/pull/1698[#1698]).
|
||||
|
||||
If `T` does not resolve to a class type (i.e. it is a union type, nullable type, string literal type, parameterized type, or `nothing`), the type check will always fail.
|
||||
|
||||
=== Standard library `external` module properties are now marked `const`
|
||||
=== Standard library properties marked `const`
|
||||
|
||||
Previously, module properties in `pkl:math` and `pkl:release` could be overriden by amending the module.
|
||||
Doing this makes little sense—these value are constants and overriding them by amending their module would be odd.
|
||||
Some properties within the `pkl:math` and `pkl:release` modules have been marked `const` (https://github.com/apple/pkl/pull/1864[#1864]).
|
||||
|
||||
Currently, module properties in `pkl:math` and `pkl:release` can be overridden by amending the module.
|
||||
Doing this makes little sense; these values are constants and overriding them by amending their module would be odd.
|
||||
|
||||
The following properties are now `const` and cannot be amended:
|
||||
|
||||
* pkldoc:minInt[pkl:math]
|
||||
* pkldoc:maxInt[pkl:math]
|
||||
* pkldoc:maxInt8[pkl:math]
|
||||
* pkldoc:maxInt16[pkl:math]
|
||||
* pkldoc:maxInt32[pkl:math]
|
||||
* pkldoc:maxUInt[pkl:math]
|
||||
* pkldoc:maxUInt8[pkl:math]
|
||||
* pkldoc:maxUInt16[pkl:math]
|
||||
* pkldoc:maxUInt32[pkl:math]
|
||||
* pkldoc:minFiniteFloat[pkl:math]
|
||||
* pkldoc:maxFiniteFloat[pkl:math]
|
||||
* pkldoc:minPositiveFloat[pkl:math]
|
||||
* pkldoc:e[pkl:math]
|
||||
* pkldoc:pi[pkl:math]
|
||||
* pkldoc:current[pkl:release]
|
||||
|
||||
This is a breaking change for code that looks like this:
|
||||
[source,pkl]
|
||||
@@ -126,12 +482,257 @@ res = """
|
||||
"""
|
||||
----
|
||||
|
||||
[[uri-validates]]
|
||||
=== `Uri` validates its value
|
||||
|
||||
The pkldoc:Uri[] typealias in `pkl:base` is now `String(isValidUrl)` instead of a plain `String` (https://github.com/apple/pkl/pull/1834[#1834]).
|
||||
|
||||
A value typed as `Uri` must be a valid absolute URL according to https://www.rfc-editor.org/rfc/rfc3986[RFC 3986].
|
||||
This means that a relative reference, or a URL containing a character that must be percent-encoded, no longer type-checks:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
good: Uri = "https://example.com/some%20path"
|
||||
|
||||
bad1: Uri = "./some/path" // throws: not absolute
|
||||
bad2: Uri = "https://example.com/some path" // throws: space must be percent-encoded
|
||||
----
|
||||
|
||||
This affects every standard library member typed as `Uri`, among them pkldoc:Resource#uri[], pkldoc:#importGraph()[pkl:analyze], and the URI-valued properties of pkldoc:#[pkl:Project], pkldoc:#[pkl:EvaluatorSettings] and pkldoc:#[pkl:DocPackageInfo].
|
||||
|
||||
As a consequence, an invalid URI is now reported as a type constraint violation at the point where it is set, rather than as an error raised later by whatever consumes it.
|
||||
|
||||
[[reference-changes]]
|
||||
=== Changes to `Reference` construction
|
||||
|
||||
As part of the introduction of generic methods, the `Reference()` constructor method in `pkl:ref` takes the domain and referent types as type arguments instead of taking a `Class` parameter (https://github.com/apple/pkl/pull/1849[#1849]).
|
||||
This also makes it possible to construct references to non-class types, such as `Listing<String>` or `String | Int`.
|
||||
|
||||
The `ref.Domain` class has been renamed to `ref.AbstractDomain`.
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
import "pkl:ref"
|
||||
|
||||
class MyDomain extends ref.AbstractDomain { // <1>
|
||||
function renderReference(reference: ref.Reference<MyDomain, Any>): String = "..."
|
||||
}
|
||||
|
||||
// current
|
||||
myRef = ref.Reference(new MyDomain {}, MyReferent, myData)
|
||||
|
||||
// new
|
||||
myRef = ref.Reference<MyDomain, MyReferent>(new MyDomain {}, myData) // <2>
|
||||
----
|
||||
<1> In Pkl 0.32, `extends ref.Domain`.
|
||||
<2> Constraints in the referent type of a `Reference` type annotation are no longer an error, they are ignored.
|
||||
|
||||
[#parser-rule-change-for-comparison]
|
||||
=== Parser rule changes for comparison
|
||||
|
||||
To support <<generic-methods,generic method calls>>, the syntax for Pkl has changed to permit passing type arguments when calling a method.
|
||||
|
||||
This purposefully introduces an ambiguity to the grammar: the following expression can be parsed as either a generic method call, or as nested comparison expressions:
|
||||
|
||||
[source,{pkl-expr}]
|
||||
----
|
||||
foo < Int > (5)
|
||||
----
|
||||
|
||||
To resolve such ambiguities, such code is preferably parsed as a generic method call.
|
||||
|
||||
This contrived example is nonsensical today, because it is an error to compare a boolean.
|
||||
However, there are times when such code might be written in a well-formed way, for example:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
res = foo(
|
||||
bar < baz,
|
||||
qux > (corge + 3)
|
||||
)
|
||||
----
|
||||
|
||||
In Pkl 0.33, this above snippet will interpret `bar` as a generic method call.
|
||||
To restore the old meaning, wrap the left-hand side with parentheses:
|
||||
|
||||
[source,diff]
|
||||
----
|
||||
res = foo(
|
||||
- bar < baz,
|
||||
+ (bar) < baz,
|
||||
qux > (corge + 3)
|
||||
)
|
||||
----
|
||||
|
||||
=== `test.catch()` and `test.catchOrNull()` force their result
|
||||
|
||||
The pkldoc:#catch()[pkl:test] and pkldoc:#catchOrNull()[pkl:test] methods now fully evaluate the value returned by the function they are given (https://github.com/apple/pkl/pull/1910[#1910]).
|
||||
|
||||
Currently, an error nested inside the returned value was not caught.
|
||||
It surfaced later, when the value was used.
|
||||
In Pkl 0.33, it is caught, and `catch()` returns its message.
|
||||
|
||||
=== Abstract methods must be implemented in extending non-abstract classes/modules
|
||||
|
||||
When extending an abstract class or module, it is now an error if any abstract methods are not implemented.
|
||||
|
||||
In the following snippet, class `Swallow` is invalid because it does not implement `canCarry`:
|
||||
|
||||
[source,pkl]
|
||||
----
|
||||
abstract class Bird {
|
||||
abstract function canCarry(fruit: Fruit): Boolean
|
||||
}
|
||||
|
||||
class Swallow extends Bird {
|
||||
type: "European" | "African"
|
||||
}
|
||||
----
|
||||
|
||||
=== Removal of `module` type in const scopes
|
||||
|
||||
The `module` type should no longer be used inside typealiases, class bodies, annotation bodies, and `const` scopes.
|
||||
Such usages will emit a deprecation warning, and will become a full error in Pkl 0.34 (https://github.com/apple/pkl/pull/1708[#1708]).
|
||||
|
||||
The `module` type is a self-type, which refers to the `this` of the module.
|
||||
When a module is extended, the `module` type refers to the extending module.
|
||||
On the other hand, the definition of classes and typealiases cannot be changed by an extending module.
|
||||
|
||||
The following snippet is misleading, because the module property `friend` _is_ a self-type, whereas class property `Feature.animal` is not.
|
||||
|
||||
.Bird.pkl
|
||||
[source,pkl]
|
||||
----
|
||||
open module Bird
|
||||
|
||||
friend: module? // <1>
|
||||
|
||||
class Feature {
|
||||
animal: module? // <2>
|
||||
}
|
||||
----
|
||||
<1> Self-type
|
||||
<2> Not a self-type
|
||||
|
||||
To have clearer semantics, the `module` type can no longer be used inside const scopes.
|
||||
|
||||
In most cases, such code should be replaced with a self-import.
|
||||
|
||||
.Bird.pkl
|
||||
[source,pkl]
|
||||
----
|
||||
open module Bird
|
||||
|
||||
import "Bird.pkl" // <1>
|
||||
|
||||
class Feature {
|
||||
animal: Bird // <2>
|
||||
}
|
||||
----
|
||||
<1> Self-import to use `Bird` as a type
|
||||
|
||||
=== Protobuf module deprecated
|
||||
|
||||
The `pkl:protobuf` module is deprecated without replacement (https://github.com/apple/pkl/pull/1778[#1778]).
|
||||
|
||||
The protobuf module renders Pkl data into the "textproto" format.
|
||||
However, Pkl is more expressive than protobuf, which means that Pkl's renderer needs to make rendering choices that are bespoke to Pkl's protobuf renderer.
|
||||
|
||||
For example, there is no native equivalent for Pkl's `null` literal.
|
||||
To address this, Pkl's protobuf renderer renders these as a "null" scalar.
|
||||
|
||||
These rendering choices are somewhat ad-hoc and likely to break from one usage to the next.
|
||||
|
||||
Users of protobuf are encouraged render Pkl into https://protobuf.dev/programming-guides/json/[ProtoJSON] instead.
|
||||
|
||||
== Miscellaneous [small]#🐸#
|
||||
|
||||
* The `abstract` modifier is now a no-op for properties. (https://github.com/apple/pkl/pull/1781[#1781]).
|
||||
* Abstract methods in non-abstract classes and modules are now rejected (https://github.com/apple/pkl/pull/1647[#1647], https://github.com/apple/pkl/pull/1780[#1780]).
|
||||
* Enforce that non-abstract classes implement all abstract methods from superclasses (https://github.com/apple/pkl/pull/1785[#1785]).
|
||||
* Introduce a new internal representation for type metadata (https://github.com/apple/pkl/pull/1838[#1838]).
|
||||
* Improve error message when amending a property with no value set (https://github.com/apple/pkl/pull/1867[#1867]).
|
||||
* Use `EnumSet` for token categories (https://github.com/apple/pkl/pull/1803[#1803]).
|
||||
* pkldoc:String.toInt()[] now supports all hexadecimal, octal, and binary formats (https://github.com/apple/pkl/pull/1808[#1808]).
|
||||
* Handle conditional pluralization in error message (https://github.com/apple/pkl/pull/1848[#1848]).
|
||||
* Avoid using Java `Object.toString()` to present language-facing string representations (https://github.com/apple/pkl/pull/1850[#1850]).
|
||||
* Unify internal construction of objects (https://github.com/apple/pkl/pull/1873[#1873]).
|
||||
* Use module cache directory configured via the CLI or Gradle while evaluating `PklProject` and `settings.pkl` files (https://github.com/apple/pkl/pull/1900[#1900]).
|
||||
* Typed values are rendered with more helpful type names in error messages and pkldoc:Any.toString()[] (https://github.com/apple/pkl/pull/1412[#1412]).
|
||||
* Add support for customizing spring boot `@ConfigurationProperties` in generated Java/Kotlin code (https://github.com/apple/pkl/pull/1897[#1897]).
|
||||
* Improve error message when instantiating a class that cannot be instantiated (https://github.com/apple/pkl/pull/1916[#1916]).
|
||||
* Improve error messages when a type alias fails to type check (https://github.com/apple/pkl/pull/1914[#1914]).
|
||||
* Add descriptions and groups to the tasks created by the pkl-gradle plugin (https://github.com/apple/pkl/pull/190[#190]).
|
||||
* Pkldoc no longer truncates the names of modules that do not start with the package's module name prefix (https://github.com/apple/pkl/pull/1909[#1909]).
|
||||
* Reject `file:` URIs that include an authority (https://github.com/apple/pkl/pull/629[#629]).
|
||||
* Upgrade to GraalVM 25.2.4 (https://github.com/apple/pkl/pull/1804[#1804]).
|
||||
* Improve performance of reading `const` members (https://github.com/apple/pkl/pull/1835[#1835]).
|
||||
* Improve performance of `Listing` and `Mapping` type casts (https://github.com/apple/pkl/pull/1837[#1837]).
|
||||
* Improve performance of lexical frame resolution (https://github.com/apple/pkl/pull/1842[#1842]).
|
||||
* Improve performance of amending `null` parents (https://github.com/apple/pkl/pull/1836[#1836]).
|
||||
* Improve performance of annotations without object bodies (https://github.com/apple/pkl/pull/1843[#1843]).
|
||||
* Improve performance of `for` and `when` generators (https://github.com/apple/pkl/pull/1844[#1844]).
|
||||
* Improve performance of parent property and subscript access (https://github.com/apple/pkl/pull/1853[#1853]).
|
||||
* Improve performance of typechecking (https://github.com/apple/pkl/pull/1871[#1871]).
|
||||
* Improve performance of string literal union types in more cases (https://github.com/apple/pkl/pull/1875[#1875]).
|
||||
* Improve performance of iterating object members (https://github.com/apple/pkl/pull/1879[#1879]). Thank you to https://github.com/odenix[@odenix] for their contributions to this feature!
|
||||
* Fix some partial evaluation issues in the GraalVM compiler (https://github.com/apple/pkl/pull/1944[#1944]).
|
||||
|
||||
== Bug Fixes [small]#🐜#
|
||||
|
||||
* XXX
|
||||
* Fix incorrect behavior when objects are partially forced (https://github.com/apple/pkl/pull/1790[#1790]).
|
||||
* Fix issues publishing pkl-gradle (https://github.com/apple/pkl/pull/1777[#1777], https://github.com/apple/pkl/pull/1807[#1807]).
|
||||
* Fix resolution of the `module` type in typealias bodies (https://github.com/apple/pkl/pull/1796[#1796]).
|
||||
* Don't fail when loading known-malformed CA certs (https://github.com/apple/pkl/pull/1806[#1806]).
|
||||
* Fix resolution of type names in typealias constraints (https://github.com/apple/pkl/pull/1826[#1826]).
|
||||
* Fix parsing of block comments at the end of a file (https://github.com/apple/pkl/pull/1828[#1828]).
|
||||
* Sanitize block comment endings in generated Kotlin doc comments (https://github.com/apple/pkl/pull/1830[#1830]).
|
||||
* Enforce max collection size when decoding pkl-binary data (https://github.com/apple/pkl/pull/1831[#1831]).
|
||||
* Correctly omit glob imports from reflected imports (https://github.com/apple/pkl/pull/1816[#1816]).
|
||||
* Escape characters that cannot appear literally in rendered YAML (https://github.com/apple/pkl/pull/1846[#1846]).
|
||||
* Fix invalid prefix when generating spring boot config (https://github.com/apple/pkl/pull/1862[#1862]).
|
||||
* Fix `pkl run` behaviors where (sub)commands amend `pkl:Command` without extending it (https://github.com/apple/pkl/pull/1882[#1882]).
|
||||
* Fix pkldoc:String.endsWith()[] for overlapping regex matches (https://github.com/apple/pkl/pull/1880[#1880], https://github.com/apple/pkl/pull/1884[#1884]).
|
||||
* Fix leak of external reader processes in the language binding server (https://github.com/apple/pkl/pull/1885[#1885]).
|
||||
* Fix decoding of `Regex` values from pkl-binary data (https://github.com/apple/pkl/pull/1895[#1895]).
|
||||
* Fix `pkl eval` of dependency notation source modules when using multiple file output (https://github.com/apple/pkl/pull/1942[#1942]).
|
||||
* Report an error, instead of overflowing the stack, when parsing or formatting code that is nested too deeply (https://github.com/apple/pkl/pull/1918[#1918], https://github.com/apple/pkl/pull/1953[#1953]).
|
||||
* Fix type check of the `module` type when it is defined in a parent member body (https://github.com/apple/pkl/pull/1936[#1936]).
|
||||
* Fix type check of subscript key types for `Map` and `Mapping` references (https://github.com/apple/pkl/pull/1933[#1933]).
|
||||
* Fix `hashCode()` and `==` inconsistency for negative zero in `Duration` and `DataSize` (https://github.com/apple/pkl/pull/1932[#1932]).
|
||||
* Fix `hashCode()` inconsistency with `==` for `Listing`, `Duration`, and `DataSize` (https://github.com/apple/pkl/pull/1922[#1922]).
|
||||
* Fix `toString()` and `value` of `Duration` and `DataSize` values that are too large to fit in a `Long` (https://github.com/apple/pkl/pull/1935[#1935]).
|
||||
* Fix iteration over `Dynamic` objects that have a negative key, such as `new Dynamic { [-1] = 2 }` (https://github.com/apple/pkl/pull/1948[#1948]).
|
||||
* Fix enforcement of `const` member access inside methods (https://github.com/apple/pkl/pull/1945[#1945]).
|
||||
* Fix parameterized type checks in type alias constraints (https://github.com/apple/pkl/pull/1906[#1906]).
|
||||
* Fix resolution of qualified type names (https://github.com/apple/pkl/pull/1915[#1915]).
|
||||
* Fix lookaround regexes in pkldoc:String.lastIndexOf()[] and pkldoc:String.replaceLast()[] (https://github.com/apple/pkl/pull/1908[#1908]).
|
||||
* Fix formatter instability (https://github.com/apple/pkl/pull/1911[#1911]).
|
||||
* Improve normalization of URIs (https://github.com/apple/pkl/pull/1937[#1937], https://github.com/apple/pkl/pull/1954[#1954]).
|
||||
* Missing const checks which allow accessing non-const members (https://github.com/apple/pkl/issues/1963[#1963]).
|
||||
|
||||
== Contributors [small]#🙏#
|
||||
|
||||
We would like to thank the contributors to this release (in alphabetical order):
|
||||
|
||||
* XXX
|
||||
* https://github.com/AAGAM17[@AAGAM17]
|
||||
* https://github.com/aashish254[@aashish254]
|
||||
* https://github.com/ayashjorden[@ayashjorden]
|
||||
* https://github.com/bioball[@bioball]
|
||||
* https://github.com/Carpe-Wang[@Carpe-Wang]
|
||||
* https://github.com/dylanpulver[@dylanpulver]
|
||||
* https://github.com/florinungur[@florinungur]
|
||||
* https://github.com/goutamadwant[@goutamadwant]
|
||||
* https://github.com/henriquejsza[@henriquejsza]
|
||||
* https://github.com/HT154[@HT154]
|
||||
* https://github.com/KushalP[@KushalP]
|
||||
* https://github.com/kwy404[@kwy404]
|
||||
* https://github.com/mayc7n[@mayc7n]
|
||||
* https://github.com/netvl[@netvl]
|
||||
* https://github.com/odenix[@odenix]
|
||||
* https://github.com/protobufel2[@protobufel2]
|
||||
* https://github.com/RushikeshGandhmal[@RushikeshGandhmal]
|
||||
* https://github.com/sergiosalvi[@sergiosalvi]
|
||||
* https://github.com/sgammon[@sgammon]
|
||||
* https://github.com/stackoverflow[@stackoverflow]
|
||||
* https://github.com/vinayakj592[@vinayakj592]
|
||||
@@ -0,0 +1,47 @@
|
||||
= Pkl 0.34 Release Notes
|
||||
|
||||
:version: 0.34
|
||||
:version-minor: 0.34.0
|
||||
:release-date: TBD
|
||||
:version-next: 0.35.0
|
||||
:version-next-date: June 2027
|
||||
|
||||
link:partial$intro.adoc[role=include]
|
||||
|
||||
== Highlights [small]#💖#
|
||||
|
||||
News you don't want to miss.
|
||||
|
||||
=== XXX
|
||||
|
||||
== Noteworthy [small]#🎶#
|
||||
|
||||
Ready when you need them.
|
||||
|
||||
=== XXX
|
||||
|
||||
== Breaking Changes [small]#💔#
|
||||
|
||||
Things to watch out for when upgrading.
|
||||
|
||||
=== XXX
|
||||
|
||||
== Miscellaneous [small]#🐸#
|
||||
|
||||
* XXX
|
||||
* XXX
|
||||
|
||||
== Bug Fixes [small]#🐜#
|
||||
|
||||
* XXX
|
||||
* XXX
|
||||
|
||||
== Security Fixes [small]#🔒#
|
||||
|
||||
The following security vulnerabilities were fixed:
|
||||
|
||||
== Contributors [small]#🙏#
|
||||
|
||||
We would like to thank the contributors to this release (in alphabetical order):
|
||||
|
||||
* XXX
|
||||
@@ -1,11 +1,34 @@
|
||||
= Changelog
|
||||
include::ROOT:partial$component-attributes.adoc[]
|
||||
|
||||
[[release-0.34.0]]
|
||||
== 0.34.0 (UNRELEASED)
|
||||
|
||||
xref:0.34.adoc[Release Notes]
|
||||
|
||||
[[release-0.33.0]]
|
||||
== 0.33.0 (UNRELEASED)
|
||||
== 0.33.0 (2026-11-05)
|
||||
|
||||
xref:0.33.adoc[Release Notes]
|
||||
|
||||
[[release-0.32.2]]
|
||||
== 0.32.2 (2026-10-21)
|
||||
|
||||
=== Security Fixes [small]#🔒#
|
||||
|
||||
* Update fallback CA certificate trust and remove trust for the issuer of compromised intermediate CAs (https://github.com/apple/pkl/pull/1923[#1923]).
|
||||
|
||||
=== Fixes
|
||||
|
||||
* Fix rendering of stack traces for evaluated multi-line expressions (https://github.com/apple/pkl/pull/1793[#1793]).
|
||||
|
||||
=== Contributors ❤️
|
||||
|
||||
Thank you to all the contributors for this release!
|
||||
|
||||
* https://github.com/HT154[@HT154]
|
||||
* https://github.com/protobufel2[@protobufel2]
|
||||
|
||||
[[release-0.32.1]]
|
||||
== 0.32.1 (2026-07-23)
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
The Pkl team aims to release a new version of Pkl in February, June, and October of each year.
|
||||
|
||||
* xref:0.34.adoc[0.34 Release Notes]
|
||||
* xref:0.33.adoc[0.33 Release Notes]
|
||||
* xref:0.32.adoc[0.32 Release Notes]
|
||||
* xref:0.31.adoc[0.31 Release Notes]
|
||||
* xref:0.30.adoc[0.30 Release Notes]
|
||||
|
||||
@@ -5,47 +5,39 @@
|
||||
:version-next: XXX (e.g., 0.10)
|
||||
:version-next-date: XXX (e.g., July 2018)
|
||||
|
||||
include::partial$intro.adoc[]
|
||||
link:partial$intro.adoc[role=include]
|
||||
|
||||
== Highlights [small]#💖#
|
||||
|
||||
News you don't want to miss.
|
||||
|
||||
.XXX
|
||||
[%collapsible]
|
||||
====
|
||||
XXX
|
||||
====
|
||||
=== XXX
|
||||
|
||||
== Noteworthy [small]#🎶#
|
||||
|
||||
Ready when you need them.
|
||||
|
||||
.XXX
|
||||
[%collapsible]
|
||||
====
|
||||
XXX
|
||||
====
|
||||
=== XXX
|
||||
|
||||
== Breaking Changes [small]#💔#
|
||||
|
||||
Things to watch out for when upgrading.
|
||||
|
||||
.XXX
|
||||
[%collapsible]
|
||||
====
|
||||
XXX
|
||||
====
|
||||
=== XXX
|
||||
|
||||
== Work In Progress [small]#🚆#
|
||||
== Miscellaneous [small]#🐸#
|
||||
|
||||
They missed the train but deserve a mention.
|
||||
* XXX
|
||||
* XXX
|
||||
|
||||
.XXX
|
||||
[%collapsible]
|
||||
====
|
||||
XXX
|
||||
====
|
||||
== Bug Fixes [small]#🐜#
|
||||
|
||||
* XXX
|
||||
* XXX
|
||||
|
||||
== Security Fixes [small]#🔒#
|
||||
|
||||
The following security vulnerabilities were fixed:
|
||||
|
||||
== Contributors [small]#🙏#
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
* xref:ROOT:evolution-and-roadmap.adoc[Evolution and Roadmap]
|
||||
|
||||
* xref:release-notes:index.adoc[Release Notes]
|
||||
** xref:release-notes:0.34.adoc[0.34 Release Notes]
|
||||
** xref:release-notes:0.33.adoc[0.33 Release Notes]
|
||||
** xref:release-notes:0.32.adoc[0.32 Release Notes]
|
||||
** xref:release-notes:0.31.adoc[0.31 Release Notes]
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# suppress inspection "UnusedProperty" for whole file
|
||||
|
||||
group=org.pkl-lang
|
||||
version=0.33.0
|
||||
version=0.34.0
|
||||
|
||||
# google-java-format requires jdk.compiler exports
|
||||
org.gradle.jvmargs= \
|
||||
|
||||
@@ -3,7 +3,7 @@ assertj = "3.27.7"
|
||||
checksumPlugin = "1.4.0"
|
||||
# 5.0.3 is the last version compatible with Kotlin 2.2
|
||||
clikt = "5.0.3"
|
||||
commonMark = "0.29.0"
|
||||
commonMark = "0.30.0"
|
||||
downloadTaskPlugin = "5.7.0"
|
||||
eclipseCdtFormat = "12.2"
|
||||
errorProne = "2.50.0"
|
||||
@@ -62,6 +62,8 @@ nullaway = "0.13.7"
|
||||
nullawayPlugin = "3.0.0"
|
||||
nuValidator = "26.7.3"
|
||||
paguro = "3.10.3"
|
||||
protobufPlugin = "0.10.0"
|
||||
protobuf = "4.35.1"
|
||||
shadowPlugin = "9.5.1"
|
||||
slf4j = "2.0.20"
|
||||
snakeYaml = "3.0.1"
|
||||
@@ -117,6 +119,8 @@ nullaway = { group = "com.uber.nullaway", name = "nullaway", version.ref = "null
|
||||
nullawayPlugin = { group = "net.ltgt.gradle", name = "gradle-nullaway-plugin", version.ref = "nullawayPlugin" }
|
||||
# to be replaced with https://github.com/usethesource/capsule or https://github.com/lacuna/bifurcan
|
||||
paguro = { group = "org.organicdesign", name = "Paguro", version.ref = "paguro" }
|
||||
protobuf = { group = "com.google.protobuf", name = "protobuf-java", version.ref = "protobuf" }
|
||||
protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" }
|
||||
pklConfigJavaAll025 = { group = "org.pkl-lang", name = "pkl-config-java-all", version = "0.25.0" }
|
||||
shadowPlugin = { group = "com.gradleup.shadow", name = "com.gradleup.shadow.gradle.plugin", version.ref = "shadowPlugin" }
|
||||
slf4jApi = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
|
||||
@@ -125,6 +129,7 @@ snakeYaml = { group = "org.snakeyaml", name = "snakeyaml-engine", version.ref =
|
||||
spotlessPlugin = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version.ref = "spotlessPlugin"}
|
||||
svm = { group = "org.graalvm.nativeimage", name = "svm", version.ref = "graalVmJdkVersion" }
|
||||
truffleApi = { group = "org.graalvm.truffle", name = "truffle-api", version.ref = "graalVm" }
|
||||
truffleProfiler = { group = "org.graalvm.tools", name = "profiler-tool", version.ref = "graalVm" }
|
||||
truffleDslProcessor = { group = "org.graalvm.truffle", name = "truffle-dsl-processor", version.ref = "graalVm" }
|
||||
truffleSvm = { group = "org.graalvm.nativeimage", name = "truffle-runtime-svm", version.ref = "graalVmJdkVersion" }
|
||||
truffleRuntime = { group = "org.graalvm.truffle", name = "truffle-runtime", version.ref = "graalVm" }
|
||||
@@ -135,10 +140,11 @@ checksum = { id = "org.gradle.crypto.checksum", version.ref = "checksumPlugin" }
|
||||
#noinspection UnusedVersionCatalogEntry
|
||||
errorProne = { id = "net.ltgt.errorprone", version.ref = "errorPronePlugin" }
|
||||
ideaExt = { id = "org.jetbrains.gradle.plugin.idea-ext", version.ref = "ideaExtPlugin" }
|
||||
jextract = { id = "de.infolektuell.jextract", version.ref = "jextractPlugin" }
|
||||
jmh = { id = "me.champeau.jmh", version.ref = "jmhPlugin" }
|
||||
kotlinxSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlinToolchain" }
|
||||
nexusPublish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexusPublishPlugin" }
|
||||
#noinspection UnusedVersionCatalogEntry
|
||||
nullaway = { id = "net.ltgt.nullaway", version.ref = "nullawayPlugin" }
|
||||
shadow = { id = "com.gradleup.shadow", version.ref = "shadowPlugin" }
|
||||
jextract = { id = "de.infolektuell.jextract", version.ref = "jextractPlugin" }
|
||||
protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" }
|
||||
Vendored
BIN
Binary file not shown.
+2
-2
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
|
||||
distributionSha256Sum=dce76f55f8e251a3a1f130eb120f30b3d271de2b76c9b0729d316b5a1b6dc01f
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.1-bin.zip
|
||||
networkTimeout=10000
|
||||
retries=0
|
||||
retryBackOffMs=500
|
||||
|
||||
Vendored
+41
-11
@@ -26,6 +26,33 @@
|
||||
@rem Set local scope for the variables, and ensure extensions are enabled
|
||||
setlocal EnableExtensions
|
||||
|
||||
@rem Catch executions from older scripts and ensure they exit cleanly.
|
||||
@rem This can be removed once we can be reasonably confident that few people
|
||||
@rem will be migrating directly to this new wrapper.
|
||||
goto afterSafetyNet
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
goto exitWithErrorLevel
|
||||
:afterSafetyNet
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
@@ -45,13 +72,14 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
1>&2 echo.
|
||||
1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
1>&2 echo.
|
||||
1>&2 echo Please set the JAVA_HOME variable in your environment to match the
|
||||
1>&2 echo location of your Java installation.
|
||||
|
||||
"%COMSPEC%" /c exit 1
|
||||
goto exitWithErrorLevel
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
@@ -59,13 +87,14 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
1>&2 echo.
|
||||
1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
1>&2 echo.
|
||||
1>&2 echo Please set the JAVA_HOME variable in your environment to match the
|
||||
1>&2 echo location of your Java installation.
|
||||
|
||||
"%COMSPEC%" /c exit 1
|
||||
goto exitWithErrorLevel
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
@@ -75,8 +104,9 @@ echo location of your Java installation. 1>&2
|
||||
@rem Execute gradlew
|
||||
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
||||
@rem which allows us to clear the local environment before executing the java command
|
||||
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
|
||||
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel & goto exitWithErrorLevel
|
||||
|
||||
@rem This label must not be changed. We rely on old scripts being able to jump to this point.
|
||||
:exitWithErrorLevel
|
||||
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
||||
"%COMSPEC%" /c exit %ERRORLEVEL%
|
||||
+3
-3
@@ -2,15 +2,15 @@
|
||||
"catalogs": {},
|
||||
"aliases": {
|
||||
"pkl": {
|
||||
"script-ref": "org.pkl-lang:pkl-cli-java:0.32.1",
|
||||
"script-ref": "org.pkl-lang:pkl-cli-java:0.33.0",
|
||||
"java-agents": []
|
||||
},
|
||||
"pkl-codegen-java": {
|
||||
"script-ref": "org.pkl-lang:pkl-codegen-java:0.32.1",
|
||||
"script-ref": "org.pkl-lang:pkl-codegen-java:0.33.0",
|
||||
"java-agents": []
|
||||
},
|
||||
"pkl-codegen-kotlin": {
|
||||
"script-ref": "org.pkl-lang:pkl-codegen-kotlin:0.32.1",
|
||||
"script-ref": "org.pkl-lang:pkl-codegen-kotlin:0.33.0",
|
||||
"java-agents": []
|
||||
}
|
||||
},
|
||||
|
||||
+39
-11
@@ -23,6 +23,7 @@ plugins {
|
||||
id("pklGraalVm")
|
||||
id("pklJavaLibrary")
|
||||
id("pklNativeLifecycle")
|
||||
id("pklNativeSourceBundle")
|
||||
}
|
||||
|
||||
val stagedMacAarch64NativeLibrary: Configuration =
|
||||
@@ -48,6 +49,8 @@ val nativeTestRuntimeOnly: Configuration =
|
||||
extendsFrom(configurations.testRuntimeOnly.get())
|
||||
}
|
||||
|
||||
val externalReaderFixtureConfiguration = configurations.create("externalReaderFixture")
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.graalSdk)
|
||||
|
||||
@@ -62,6 +65,13 @@ dependencies {
|
||||
nativeTestImplementation(libs.jna)
|
||||
nativeTestImplementation(libs.jnaPlatform)
|
||||
nativeTestRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
|
||||
externalReaderFixtureConfiguration(project(":pkl-core", "externalReaderFixture"))
|
||||
|
||||
// firstPartySourcesJars(project(":pkl-formatter", "sourcesJar")) // TODO when syntax merges
|
||||
firstPartySourcesJars(project(":pkl-core", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-parser", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-server", "sourcesJar"))
|
||||
}
|
||||
|
||||
tasks.withType(CCompile::class) {
|
||||
@@ -142,19 +152,20 @@ val windowsNativeImageAmd64 =
|
||||
extraNativeImageArgs.addAll("-Dfile.encoding=UTF-8", "-H:-CheckToolchain")
|
||||
}
|
||||
|
||||
val nativeImageBuildTask =
|
||||
when (buildInfo.targetMachine) {
|
||||
Target.MacosAarch64 -> macNativeImageAarch64
|
||||
Target.LinuxAarch64 -> linuxNativeImageAarch64
|
||||
Target.LinuxAmd64 -> linuxNativeImageAmd64
|
||||
Target.WindowsAmd64 -> windowsNativeImageAmd64
|
||||
Target.AlpineLinuxAmd64 -> alpineLinuxNativeImageAmd64
|
||||
}
|
||||
|
||||
val buildNativeImageLibrary =
|
||||
tasks.register("buildNativeImageLibrary") {
|
||||
group = "build"
|
||||
val underlyingTask =
|
||||
when (buildInfo.targetMachine) {
|
||||
Target.MacosAarch64 -> macNativeImageAarch64
|
||||
Target.LinuxAarch64 -> linuxNativeImageAarch64
|
||||
Target.LinuxAmd64 -> linuxNativeImageAmd64
|
||||
Target.WindowsAmd64 -> windowsNativeImageAmd64
|
||||
Target.AlpineLinuxAmd64 -> alpineLinuxNativeImageAmd64
|
||||
}
|
||||
dependsOn(underlyingTask)
|
||||
outputs.files(underlyingTask)
|
||||
dependsOn(nativeImageBuildTask)
|
||||
outputs.files(nativeImageBuildTask)
|
||||
}
|
||||
|
||||
val buildPklObjectFile =
|
||||
@@ -249,7 +260,7 @@ val buildSharedLibrary =
|
||||
|
||||
if (buildInfo.os.isMacOS) {
|
||||
frameworks.addAll("Foundation", "CoreServices")
|
||||
linkerFlags.addAll("-current_version", project.version.toString())
|
||||
linkerFlags.addAll("-current_version", project.version.toString().substringBefore("-"))
|
||||
linkerFlags.addAll("-compatibility_version", "0.1.0")
|
||||
// prevent JNI symbols from being exported and clobbering the symbol table
|
||||
val exportedSymbolsFile = file("src/main/c/pkl.exported_symbols")
|
||||
@@ -278,6 +289,17 @@ val buildSharedLibrary =
|
||||
}
|
||||
}
|
||||
|
||||
// Source bundles for each target are registered by `pklNativeSourceBundle`. libpkl additionally
|
||||
// includes its own C sources, which are the same for all targets.
|
||||
val libpklNativeSourcesJar =
|
||||
tasks.register<Zip>("libpklNativeSourcesJar") {
|
||||
archiveFileName = "libpkl-native-sources.jar"
|
||||
destinationDirectory = layout.buildDirectory.dir("tmp/nativeImageSources")
|
||||
from("src/main/c")
|
||||
}
|
||||
|
||||
sourceBundleSpec { extraNativeSources.from(libpklNativeSourcesJar) }
|
||||
|
||||
val Target.outputDir
|
||||
get() = layout.buildDirectory.dir("native-libs/$targetName")
|
||||
|
||||
@@ -344,6 +366,7 @@ val processFiles =
|
||||
val testNativeJava =
|
||||
tasks.register<Test>("testNativeJava") {
|
||||
dependsOn(tasks.assembleNative)
|
||||
dependsOn(externalReaderFixtureConfiguration)
|
||||
|
||||
description = "Test native libraries from Java"
|
||||
group = "verification"
|
||||
@@ -366,6 +389,11 @@ val testNativeJava =
|
||||
environment("LD_LIBRARY_PATH", buildInfo.targetMachine.libraryDir.get().asFile.absolutePath)
|
||||
|
||||
useJUnitPlatform()
|
||||
|
||||
systemProperty(
|
||||
"org.pkl.core.testExternalReaderPath",
|
||||
externalReaderFixtureConfiguration.files.single().absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
// link to static library
|
||||
|
||||
@@ -61,10 +61,23 @@ dependencies {
|
||||
implementation(libs.jlineTerminalJni)
|
||||
implementation(projects.pklServer)
|
||||
implementation(projects.pklFormatter)
|
||||
implementation(projects.pklProfiler)
|
||||
implementation(libs.truffleProfiler)
|
||||
implementation(libs.clikt)
|
||||
|
||||
testImplementation(projects.pklCommonsTest)
|
||||
testImplementation(libs.wiremock)
|
||||
testImplementation(libs.protobuf)
|
||||
|
||||
// used by `pklJavaExecutable` plugin (ideally this would be inferred automatically)
|
||||
firstPartySourcesJars(project(":pkl-cli", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-commons", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-commons-cli", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-core", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-formatter", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-parser", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-server", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-profiler", "sourcesJar"))
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
@@ -74,6 +87,9 @@ tasks.jar {
|
||||
|
||||
tasks.javadoc { enabled = false }
|
||||
|
||||
// has its own dedicated task; see `testProfilerOutput` and `testNativeProfilerOutput` below
|
||||
tasks.test { exclude("**/SubprocessProfilerOutputTest.class") }
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveFileName.set("jpkl")
|
||||
|
||||
@@ -96,6 +112,8 @@ val testJavaExecutable =
|
||||
// executable;
|
||||
// to verify that, we don't want to include them here)
|
||||
(configurations.testRuntimeClasspath.get() - configurations.runtimeClasspath.get())
|
||||
// has its own dedicated task; see `testProfilerOutput` and `testNativeProfilerOutput` below
|
||||
exclude("**/SubprocessProfilerOutputTest.class")
|
||||
}
|
||||
|
||||
// Setup `testJavaExecutable` tasks for multi-JDK testing.
|
||||
@@ -153,18 +171,97 @@ val testEvalJavaExecutableOnOtherJdks =
|
||||
}
|
||||
}
|
||||
|
||||
val generateReachabilityMetadata =
|
||||
tasks.register<JavaExec>("generateReachabilityMetadata") {
|
||||
dependsOn(tasks.javaExecutable)
|
||||
|
||||
// The native-image-agent requires GraalVM's java, not a regular JDK.
|
||||
val graalVm =
|
||||
if (buildInfo.arch == Target.Arch.AMD64) buildInfo.graalVmAmd64 else buildInfo.graalVmAarch64
|
||||
dependsOn(
|
||||
if (buildInfo.arch == Target.Arch.AMD64) ":installGraalVmAmd64" else ":installGraalVmAarch64"
|
||||
)
|
||||
|
||||
executable(
|
||||
File(graalVm.baseDir)
|
||||
.resolve("bin")
|
||||
.resolve(if (buildInfo.os.isWindows) "java.exe" else "java")
|
||||
.absolutePath
|
||||
)
|
||||
|
||||
val outputDir = layout.buildDirectory.dir("generated-reachability-metadata")
|
||||
val outputFile = outputDir.map {
|
||||
it.asFile.resolve("META-INF/native-image/org.pkl-lang/pkl-cli/reachability-metadata.json")
|
||||
}
|
||||
val profilerOutput = layout.buildDirectory.file("tmp/profile.pb.gz")
|
||||
outputs.file(outputFile)
|
||||
|
||||
classpath = tasks.javaExecutable.get().outputs.files
|
||||
|
||||
// invoke the profiler to include metadata for protobuf serdes
|
||||
args("eval", "--profile-cpu-output", profilerOutput.get().asFile.absolutePath, "pkl:settings")
|
||||
setStandardOutput(OutputStream.nullOutputStream())
|
||||
|
||||
jvmArgumentProviders.add(
|
||||
CommandLineArgumentProvider {
|
||||
buildList {
|
||||
add("-agentlib:native-image-agent=config-output-dir=${outputFile.get().parent}")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
doLast {
|
||||
if (!outputFile.get().exists()) {
|
||||
throw GradleException("Did not create expected file: ${outputFile.get()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val testProfilerOutput =
|
||||
tasks.register<Test>("testProfilerOutput") {
|
||||
group = "verification"
|
||||
dependsOn(tasks.javaExecutable)
|
||||
testClassesDirs = sourceSets.test.get().output.classesDirs
|
||||
classpath = sourceSets.test.get().runtimeClasspath
|
||||
include("**/SubprocessProfilerOutputTest.class")
|
||||
systemProperty(
|
||||
"org.pkl.cli.testJar",
|
||||
tasks.javaExecutable.get().outputs.files.singleFile.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
val testNativeProfilerOutput =
|
||||
tasks.register<Test>("testNativeProfilerOutput") {
|
||||
group = "verification"
|
||||
dependsOn(tasks.assembleNative)
|
||||
testClassesDirs = sourceSets.test.get().output.classesDirs
|
||||
classpath = sourceSets.test.get().runtimeClasspath
|
||||
include("**/SubprocessProfilerOutputTest.class")
|
||||
systemProperty(
|
||||
"org.pkl.cli.testExecutable",
|
||||
tasks.assembleNative.get().outputs.files.singleFile.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
tasks.withType<NativeImageBuild>().configureEach {
|
||||
dependsOn(generateReachabilityMetadata)
|
||||
classpath.from(layout.buildDirectory.dir("generated-reachability-metadata"))
|
||||
}
|
||||
|
||||
tasks.check {
|
||||
dependsOn(
|
||||
testJavaExecutable,
|
||||
testJavaExecutableOnOtherJdks,
|
||||
testEvalJavaExecutable,
|
||||
testEvalJavaExecutableOnOtherJdks,
|
||||
testProfilerOutput,
|
||||
)
|
||||
}
|
||||
|
||||
tasks.checkNative {
|
||||
dependsOn(":pkl-core:checkNative")
|
||||
dependsOn(":pkl-server:checkNative")
|
||||
dependsOn(testNativeProfilerOutput)
|
||||
}
|
||||
|
||||
executable {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.github.ajalt.clikt.core.*
|
||||
import com.github.ajalt.clikt.parameters.arguments.*
|
||||
import com.github.ajalt.clikt.parameters.options.*
|
||||
import com.github.ajalt.clikt.parameters.types.int
|
||||
import com.oracle.truffle.api.TruffleOptions
|
||||
import java.io.OutputStream
|
||||
import java.net.URI
|
||||
import java.nio.file.Path
|
||||
@@ -40,6 +41,8 @@ import org.pkl.core.FileOutput
|
||||
import org.pkl.core.ModuleSource.uri
|
||||
import org.pkl.core.PklBugException
|
||||
import org.pkl.core.PklException
|
||||
import org.pkl.core.ProfilerOptions
|
||||
import org.pkl.core.runtime.VmUtils
|
||||
import org.pkl.core.util.IoUtils
|
||||
|
||||
class CliCommandRunner
|
||||
@@ -51,20 +54,24 @@ constructor(
|
||||
private val args: List<String>,
|
||||
private val outputStream: OutputStream = System.out,
|
||||
private val errStream: OutputStream = System.err,
|
||||
private val profilerOptions: ProfilerOptions = ProfilerOptions.DEFAULT,
|
||||
) : CliCommand(options) {
|
||||
|
||||
override fun doRun() {
|
||||
val builder = evaluatorBuilder()
|
||||
try {
|
||||
evalCmd(builder)
|
||||
withCpuProfiler(profilerOptions) { startProfiling -> evalCmd(builder, startProfiling) }
|
||||
} finally {
|
||||
Closeables.closeQuietly(builder.moduleKeyFactories)
|
||||
Closeables.closeQuietly(builder.resourceReaders)
|
||||
if (TruffleOptions.AOT) {
|
||||
VmUtils.closeEngine()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun evalCmd(builder: EvaluatorBuilder) {
|
||||
private fun evalCmd(builder: EvaluatorBuilder, startProfiling: () -> Unit) {
|
||||
val evaluator = builder.build()
|
||||
startProfiling()
|
||||
evaluator.use {
|
||||
evaluator.evaluateCommand(
|
||||
uri(options.normalizedSourceModules.first()),
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.pkl.cli
|
||||
|
||||
import com.oracle.truffle.api.TruffleOptions
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
@@ -99,14 +100,19 @@ constructor(
|
||||
override fun doRun() {
|
||||
val builder = evaluatorBuilder()
|
||||
try {
|
||||
if (options.multipleFileOutputPath != null) {
|
||||
writeMultipleFileOutput(builder)
|
||||
} else {
|
||||
writeOutput(builder)
|
||||
withCpuProfiler(options.profilerOptions) { startProfiling ->
|
||||
if (options.multipleFileOutputPath != null) {
|
||||
writeMultipleFileOutput(builder, startProfiling)
|
||||
} else {
|
||||
writeOutput(builder, startProfiling)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Closeables.closeQuietly(builder.moduleKeyFactories)
|
||||
Closeables.closeQuietly(builder.resourceReaders)
|
||||
if (TruffleOptions.AOT) {
|
||||
VmUtils.closeEngine()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,18 +123,23 @@ constructor(
|
||||
|
||||
return options.base.normalizedSourceModules.associateWith { uri ->
|
||||
val moduleDir: String? =
|
||||
IoUtils.toPath(uri)?.let {
|
||||
IoUtils.relativize(it.parent, workingDir).toString().ifEmpty { "." }
|
||||
}
|
||||
val moduleKey =
|
||||
try {
|
||||
moduleResolver.resolve(uri)
|
||||
} catch (e: VmException) {
|
||||
throw e.toPklException(stackFrameTransformer, options.base.color?.hasColor() ?: false)
|
||||
}
|
||||
if (!uri.isAbsolute && uri.schemeSpecificPart.startsWith("@")) null
|
||||
else
|
||||
IoUtils.toPath(uri)?.let {
|
||||
IoUtils.relativize(it.parent, workingDir).toString().ifEmpty { "." }
|
||||
}
|
||||
val moduleName =
|
||||
if (!uri.isAbsolute && uri.schemeSpecificPart.startsWith("@"))
|
||||
IoUtils.getNameWithoutExtension(uri.path)
|
||||
else
|
||||
try {
|
||||
IoUtils.inferModuleName(moduleResolver.resolve(uri))
|
||||
} catch (e: VmException) {
|
||||
throw e.toPklException(stackFrameTransformer, options.base.color?.hasColor() ?: false)
|
||||
}
|
||||
val substituted =
|
||||
pathStr
|
||||
.replace("%{moduleName}", IoUtils.inferModuleName(moduleKey))
|
||||
.replace("%{moduleName}", moduleName)
|
||||
.replace("%{outputFormat}", options.outputFormat ?: "%{outputFormat}")
|
||||
.replace("%{moduleDir}", moduleDir ?: "%{moduleDir}")
|
||||
if (substituted.contains("%{moduleDir}")) {
|
||||
@@ -151,8 +162,9 @@ constructor(
|
||||
}
|
||||
|
||||
/** Renders each module's `output.bytes`, writing it to the specified output file. */
|
||||
private fun writeOutput(builder: EvaluatorBuilder) {
|
||||
private fun writeOutput(builder: EvaluatorBuilder, startProfiling: () -> Unit) {
|
||||
val evaluator = builder.setOutputFormat(options.outputFormat).build()
|
||||
startProfiling()
|
||||
evaluator.use { ev ->
|
||||
val outputFiles = fileOutputPaths
|
||||
if (outputFiles != null) {
|
||||
@@ -226,10 +238,11 @@ constructor(
|
||||
* Renders each module's `output.files`, writing each entry as a file into the specified output
|
||||
* directory.
|
||||
*/
|
||||
private fun writeMultipleFileOutput(builder: EvaluatorBuilder) {
|
||||
private fun writeMultipleFileOutput(builder: EvaluatorBuilder, startProfiling: () -> Unit) {
|
||||
val outputDirs = directoryOutputPaths!!
|
||||
val writtenFiles = mutableMapOf<Path, OutputFile>()
|
||||
builder.setOutputFormat(options.outputFormat).build().use { evaluator ->
|
||||
startProfiling()
|
||||
for ((moduleUri, outputDir) in outputDirs) {
|
||||
if (outputDir.exists() && !outputDir.isDirectory()) {
|
||||
throw CliException("Output path `$outputDir` exists and is not a directory.")
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.pkl.cli
|
||||
|
||||
import org.pkl.commons.cli.CliBaseOptions
|
||||
import org.pkl.core.ProfilerOptions
|
||||
|
||||
/** Configuration options for [CliEvaluator]. */
|
||||
data class CliEvaluatorOptions(
|
||||
@@ -51,7 +52,6 @@ data class CliEvaluatorOptions(
|
||||
* - `"pcf"` (default)
|
||||
* - `"plist"`
|
||||
* - `"properties"`
|
||||
* - `"textproto"` (deprecated in Pkl 0.33)
|
||||
* - `"xml"`
|
||||
* - `"yaml"`
|
||||
*/
|
||||
@@ -77,6 +77,13 @@ data class CliEvaluatorOptions(
|
||||
* If unset, the module's `output.bytes` property is evaluated.
|
||||
*/
|
||||
val expression: String? = null,
|
||||
|
||||
/**
|
||||
* CPU/Memory profiling options.
|
||||
*
|
||||
* WARN: This is an internal option only. Profiling is currently only supported via CLI flags.
|
||||
*/
|
||||
val profilerOptions: ProfilerOptions = ProfilerOptions.DEFAULT,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.pkl.core.util.IoUtils
|
||||
import org.pkl.formatter.Formatter
|
||||
import org.pkl.formatter.GrammarVersion
|
||||
import org.pkl.parser.GenericParserError
|
||||
import org.pkl.parser.ParserError
|
||||
|
||||
class CliFormatterCommand
|
||||
@JvmOverloads
|
||||
@@ -128,10 +127,7 @@ constructor(
|
||||
consoleWriter.write(formatted)
|
||||
consoleWriter.flush()
|
||||
}
|
||||
} catch (pe: ParserError) { // thrown by the lexer
|
||||
writeErrLine("Could not format `$pathStr`: $pe")
|
||||
status.update(ERROR)
|
||||
} catch (pe: GenericParserError) { // thrown by the generic parser
|
||||
} catch (pe: GenericParserError) {
|
||||
writeErrLine("Could not format `$pathStr`: $pe")
|
||||
status.update(ERROR)
|
||||
} catch (e: IOException) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.pkl.cli
|
||||
|
||||
import com.oracle.truffle.api.TruffleOptions
|
||||
import java.io.StringWriter
|
||||
import java.io.Writer
|
||||
import org.pkl.commons.cli.*
|
||||
@@ -22,7 +23,9 @@ import org.pkl.core.Closeables
|
||||
import org.pkl.core.EvaluatorBuilder
|
||||
import org.pkl.core.ModuleSource.uri
|
||||
import org.pkl.core.PklException
|
||||
import org.pkl.core.ProfilerOptions
|
||||
import org.pkl.core.TestResults
|
||||
import org.pkl.core.runtime.VmUtils
|
||||
import org.pkl.core.stdlib.test.report.JUnitReporter
|
||||
import org.pkl.core.stdlib.test.report.MinimalReporter
|
||||
import org.pkl.core.stdlib.test.report.SpecReporter
|
||||
@@ -35,19 +38,22 @@ constructor(
|
||||
private val testOptions: CliTestOptions,
|
||||
private val consoleWriter: Writer = System.out.writer(),
|
||||
private val errWriter: Writer = System.err.writer(),
|
||||
private val profilerOptions: ProfilerOptions = ProfilerOptions.DEFAULT,
|
||||
) : CliCommand(options) {
|
||||
|
||||
override fun doRun() {
|
||||
val builder = evaluatorBuilder()
|
||||
try {
|
||||
evalTest(builder)
|
||||
withCpuProfiler(profilerOptions) { startProfiling -> evalTest(builder, startProfiling) }
|
||||
} finally {
|
||||
Closeables.closeQuietly(builder.moduleKeyFactories)
|
||||
Closeables.closeQuietly(builder.resourceReaders)
|
||||
if (TruffleOptions.AOT) {
|
||||
VmUtils.closeEngine()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun evalTest(builder: EvaluatorBuilder) {
|
||||
private fun evalTest(builder: EvaluatorBuilder, startProfiling: () -> Unit) {
|
||||
val sources =
|
||||
options.normalizedSourceModules.ifEmpty { project?.tests?.map { it.toUri() } }
|
||||
?:
|
||||
@@ -62,6 +68,7 @@ constructor(
|
||||
)
|
||||
|
||||
val evaluator = builder.build()
|
||||
startProfiling()
|
||||
evaluator.use {
|
||||
var failed = false
|
||||
var isExampleWrittenFailure = true
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.pkl.cli.commands
|
||||
|
||||
import com.github.ajalt.clikt.completion.CompletionCandidates
|
||||
import com.github.ajalt.clikt.parameters.groups.provideDelegate
|
||||
import com.github.ajalt.clikt.parameters.options.default
|
||||
import com.github.ajalt.clikt.parameters.options.flag
|
||||
import com.github.ajalt.clikt.parameters.options.option
|
||||
@@ -23,6 +24,7 @@ import com.github.ajalt.clikt.parameters.options.validate
|
||||
import org.pkl.cli.CliEvaluator
|
||||
import org.pkl.cli.CliEvaluatorOptions
|
||||
import org.pkl.commons.cli.commands.ModulesCommand
|
||||
import org.pkl.commons.cli.commands.ProfileOptions
|
||||
import org.pkl.commons.cli.commands.single
|
||||
|
||||
class EvalCommand : ModulesCommand(name = "eval", helpLink = helpLink) {
|
||||
@@ -81,21 +83,25 @@ class EvalCommand : ModulesCommand(name = "eval", helpLink = helpLink) {
|
||||
)
|
||||
.flag("--no-power-assertions", default = true, defaultForHelp = "enabled")
|
||||
|
||||
val profileOptions: ProfileOptions by ProfileOptions()
|
||||
|
||||
override fun run() {
|
||||
val cliBaseOptions =
|
||||
baseOptions.baseOptions(
|
||||
modules,
|
||||
projectOptions,
|
||||
testMode = testMode,
|
||||
powerAssertionsEnabled = powerAssertionsEnabled,
|
||||
)
|
||||
val options =
|
||||
CliEvaluatorOptions(
|
||||
base =
|
||||
baseOptions.baseOptions(
|
||||
modules,
|
||||
projectOptions,
|
||||
testMode = testMode,
|
||||
powerAssertionsEnabled = powerAssertionsEnabled,
|
||||
),
|
||||
base = cliBaseOptions,
|
||||
outputPath = outputPath,
|
||||
outputFormat = baseOptions.format,
|
||||
moduleOutputSeparator = moduleOutputSeparator,
|
||||
multipleFileOutputPath = multipleFileOutputPath,
|
||||
expression = expression ?: CliEvaluatorOptions.defaults.expression,
|
||||
profilerOptions = profileOptions.toOptions(cliBaseOptions.normalizedWorkingDir),
|
||||
)
|
||||
CliEvaluator(options).run()
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.net.URI
|
||||
import org.pkl.cli.CliCommandRunner
|
||||
import org.pkl.commons.cli.commands.BaseCommand
|
||||
import org.pkl.commons.cli.commands.BaseOptions
|
||||
import org.pkl.commons.cli.commands.ProfileOptions
|
||||
import org.pkl.commons.cli.commands.ProjectOptions
|
||||
|
||||
class RunCommand : BaseCommand(name = "run", helpLink = helpLink) {
|
||||
@@ -61,6 +62,8 @@ class RunCommand : BaseCommand(name = "run", helpLink = helpLink) {
|
||||
|
||||
private val projectOptions by ProjectOptions()
|
||||
|
||||
private val profileOptions by ProfileOptions()
|
||||
|
||||
override fun run() {
|
||||
// if no module is specified but --help is show help, otherwise error becuase module is missing
|
||||
if (module == null)
|
||||
@@ -75,11 +78,13 @@ class RunCommand : BaseCommand(name = "run", helpLink = helpLink) {
|
||||
else reservedFlagShortNames.add(it.trimStart('-'))
|
||||
}
|
||||
}
|
||||
val cliBaseOptions = baseOptions.baseOptions(listOf(module!!), projectOptions)
|
||||
CliCommandRunner(
|
||||
baseOptions.baseOptions(listOf(module!!), projectOptions),
|
||||
cliBaseOptions,
|
||||
reservedFlagNames,
|
||||
reservedFlagShortNames,
|
||||
if (showHelp) args + listOf("--help") else args,
|
||||
profilerOptions = profileOptions.toOptions(cliBaseOptions.normalizedWorkingDir),
|
||||
)
|
||||
.run()
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.net.URI
|
||||
import org.pkl.cli.CliTestRunner
|
||||
import org.pkl.commons.cli.commands.BaseCommand
|
||||
import org.pkl.commons.cli.commands.BaseOptions
|
||||
import org.pkl.commons.cli.commands.ProfileOptions
|
||||
import org.pkl.commons.cli.commands.ProjectOptions
|
||||
import org.pkl.commons.cli.commands.TestOptions
|
||||
|
||||
@@ -45,6 +46,8 @@ class TestCommand : BaseCommand(name = "test", helpLink = helpLink) {
|
||||
|
||||
private val testOptions by TestOptions()
|
||||
|
||||
private val profileOptions by ProfileOptions()
|
||||
|
||||
private val powerAssertionsEnabled: Boolean by
|
||||
option(
|
||||
names = arrayOf("--power-assertions"),
|
||||
@@ -53,14 +56,16 @@ class TestCommand : BaseCommand(name = "test", helpLink = helpLink) {
|
||||
.flag("--no-power-assertions", default = true, defaultForHelp = "enabled")
|
||||
|
||||
override fun run() {
|
||||
val cliBaseOptions =
|
||||
baseOptions.baseOptions(
|
||||
modules,
|
||||
projectOptions,
|
||||
powerAssertionsEnabled = powerAssertionsEnabled,
|
||||
)
|
||||
CliTestRunner(
|
||||
options =
|
||||
baseOptions.baseOptions(
|
||||
modules,
|
||||
projectOptions,
|
||||
powerAssertionsEnabled = powerAssertionsEnabled,
|
||||
),
|
||||
options = cliBaseOptions,
|
||||
testOptions = testOptions.cliTestOptions,
|
||||
profilerOptions = profileOptions.toOptions(cliBaseOptions.normalizedWorkingDir),
|
||||
)
|
||||
.run()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright © 2026 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.cli
|
||||
|
||||
import org.pkl.core.ProfilerOptions
|
||||
import org.pkl.core.runtime.VmUtils
|
||||
import org.pkl.profiler.CpuProfiler
|
||||
import org.pkl.profiler.CpuProfilerInstrument
|
||||
|
||||
/**
|
||||
* Runs [body], sampling it with the CPU profiler if [options] enables CPU profiling.
|
||||
*
|
||||
* Sampling does not begin until [body] calls the `startProfiling` function it is passed. Call it
|
||||
* after the evaluator has been built: starting Truffle's sampling thread while the main thread is
|
||||
* still creating the engine context can race inside Truffle's thread-local handshake setup.
|
||||
*
|
||||
* Profiler output is written when [body] finishes, whether normally or exceptionally. If
|
||||
* `startProfiling` was never called, no output is written.
|
||||
*/
|
||||
internal inline fun <T> withCpuProfiler(
|
||||
options: ProfilerOptions,
|
||||
body: (startProfiling: () -> Unit) -> T,
|
||||
): T {
|
||||
if (!options.cpu().isEnabled) {
|
||||
return body {}
|
||||
}
|
||||
val profiler =
|
||||
VmUtils.getEngine().instruments[CpuProfilerInstrument.ID]?.lookup(CpuProfiler::class.java)!!
|
||||
try {
|
||||
return body { profiler.start(options.cpu) }
|
||||
} finally {
|
||||
profiler.stop()
|
||||
}
|
||||
}
|
||||
@@ -709,8 +709,7 @@ result = someLib.x
|
||||
assertThat(output).isEqualTo("x: 1\n---\nx: 3\n")
|
||||
}
|
||||
|
||||
// prototext can't render `Dynamic`.
|
||||
@EnumSource(names = ["TEXTPROTO"], mode = EnumSource.Mode.EXCLUDE)
|
||||
@EnumSource
|
||||
@ParameterizedTest(name = "{0} console output ends with newline")
|
||||
fun `console output ends with newline`(outputFormat: OutputFormat) {
|
||||
val sourceFiles = listOf(writePklFile("test0.pkl", "foo = 0\nbar=\"Baz\""))
|
||||
@@ -1777,7 +1776,7 @@ result = someLib.x
|
||||
PackageServer.populateCacheDir(tempDir)
|
||||
val projectPath =
|
||||
FileTestUtils.rootProjectDir.resolve(
|
||||
"pkl-commons-cli/src/main/resources/org/pkl/commons/cli/project1/"
|
||||
"pkl-commons-cli/src/test/resources/org/pkl/commons/cli/project1/"
|
||||
)
|
||||
val options =
|
||||
CliEvaluatorOptions(
|
||||
@@ -1798,6 +1797,31 @@ result = someLib.x
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `eval dependency notation source with multiple file output`(
|
||||
@TempDir tempDir: Path,
|
||||
@TempDir cacheDir: Path,
|
||||
) {
|
||||
PackageServer.populateCacheDir(cacheDir)
|
||||
val projectPath =
|
||||
FileTestUtils.rootProjectDir.resolve(
|
||||
"pkl-commons-cli/src/test/resources/org/pkl/commons/cli/project1/"
|
||||
)
|
||||
val options =
|
||||
CliEvaluatorOptions(
|
||||
CliBaseOptions(
|
||||
sourceModules = listOf(URI("@fruit/catalog/basket.pkl")),
|
||||
projectDir = projectPath,
|
||||
moduleCacheDir = cacheDir,
|
||||
workingDir = tempDir,
|
||||
),
|
||||
multipleFileOutputPath = "output",
|
||||
)
|
||||
val output = evalToConsole(options)
|
||||
assertThat(output.split('\n')).hasSize(3)
|
||||
assertThat(tempDir.resolve("output").listDirectoryEntries()).hasSize(2)
|
||||
}
|
||||
|
||||
private fun evalModuleThatImportsPackage(certsFile: Path?, testPort: Int = -1) {
|
||||
val moduleUri =
|
||||
writePklFile(
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright © 2026 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.cli
|
||||
|
||||
import com.google.perftools.profiles.ProfileProto.Profile
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.StringWriter
|
||||
import java.net.URI
|
||||
import java.nio.file.Path
|
||||
import java.util.zip.GZIPInputStream
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.inputStream
|
||||
import kotlin.io.path.writeText
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import org.pkl.commons.cli.CliBaseOptions
|
||||
import org.pkl.commons.cli.CliTestOptions
|
||||
import org.pkl.core.ProfilerOptions
|
||||
|
||||
/**
|
||||
* Exercises the CPU profiler by calling into the CLI classes in-process.
|
||||
*
|
||||
* See [SubprocessProfilerOutputTest] for tests that run the packaged executables.
|
||||
*/
|
||||
class ProfilerOutputTest {
|
||||
private fun profilerOptions(outputFile: Path) =
|
||||
ProfilerOptions(ProfilerOptions.Cpu(outputFile, 1))
|
||||
|
||||
private fun fib(name: String) =
|
||||
"function $name(n) = if (n < 2) n else $name(n - 1) + $name(n - 2)"
|
||||
|
||||
private fun evalCode(name: String) =
|
||||
"""
|
||||
${fib(name)}
|
||||
x = $name(30)
|
||||
"""
|
||||
.trimIndent()
|
||||
|
||||
private fun testCode(name: String) =
|
||||
"""
|
||||
amends "pkl:test"
|
||||
|
||||
local ${fib(name)}
|
||||
|
||||
facts {
|
||||
["fib"] {
|
||||
$name(30) > 0
|
||||
}
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
|
||||
private fun runCode(name: String) =
|
||||
"""
|
||||
amends "pkl:Command"
|
||||
|
||||
command {
|
||||
name = "do-run"
|
||||
}
|
||||
|
||||
local ${fib(name)}
|
||||
|
||||
output {
|
||||
text = $name(30).toString()
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
|
||||
private fun baseOptions(source: Path) =
|
||||
CliBaseOptions(sourceModules = listOf(source.toUri()), settings = URI("pkl:settings"))
|
||||
|
||||
private fun eval(tempDir: Path, name: String, outputFile: Path) {
|
||||
val source = tempDir.resolve("$name.pkl").also { it.writeText(evalCode(name)) }
|
||||
val options =
|
||||
CliEvaluatorOptions(baseOptions(source), profilerOptions = profilerOptions(outputFile))
|
||||
CliEvaluator(options, outputStream = ByteArrayOutputStream()).run()
|
||||
}
|
||||
|
||||
private fun test(tempDir: Path, name: String, outputFile: Path) {
|
||||
val source = tempDir.resolve("$name.pkl").also { it.writeText(testCode(name)) }
|
||||
CliTestRunner(
|
||||
baseOptions(source),
|
||||
CliTestOptions(),
|
||||
consoleWriter = StringWriter(),
|
||||
errWriter = StringWriter(),
|
||||
profilerOptions = profilerOptions(outputFile),
|
||||
)
|
||||
.run()
|
||||
}
|
||||
|
||||
private fun run(tempDir: Path, name: String, outputFile: Path) {
|
||||
val source = tempDir.resolve("$name.pkl").also { it.writeText(runCode(name)) }
|
||||
CliCommandRunner(
|
||||
baseOptions(source),
|
||||
emptySet(),
|
||||
emptySet(),
|
||||
emptyList(),
|
||||
outputStream = ByteArrayOutputStream(),
|
||||
errStream = ByteArrayOutputStream(),
|
||||
profilerOptions = profilerOptions(outputFile),
|
||||
)
|
||||
.run()
|
||||
}
|
||||
|
||||
private fun readProfile(outputFile: Path): Profile =
|
||||
GZIPInputStream(outputFile.inputStream()).use { Profile.parseFrom(it) }
|
||||
|
||||
private fun Profile.functionNames() = functionList.map { stringTableList[it.name.toInt()] }
|
||||
|
||||
/** Smoke test of the profile's structure, and that it contains samples of [fibName]. */
|
||||
private fun assertValidProfile(outputFile: Path, fibName: String) {
|
||||
val profile = readProfile(outputFile)
|
||||
assertThat(profile.stringTableList.first()).isEmpty() // string_table[0] must be ""
|
||||
assertThat(profile.sampleTypeList).isNotEmpty
|
||||
assertThat(profile.functionList).isNotEmpty
|
||||
assertThat(profile.functionNames()).anyMatch { it.contains(fibName) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pkl eval`(@TempDir tempDir: Path) {
|
||||
val outputFile = tempDir.resolve("profile.pb.gz")
|
||||
eval(tempDir, "evalFib", outputFile)
|
||||
assertValidProfile(outputFile, "evalFib")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pkl test`(@TempDir tempDir: Path) {
|
||||
val outputFile = tempDir.resolve("profile.pb.gz")
|
||||
test(tempDir, "testFib", outputFile)
|
||||
assertValidProfile(outputFile, "testFib")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pkl run`(@TempDir tempDir: Path) {
|
||||
val outputFile = tempDir.resolve("profile.pb.gz")
|
||||
run(tempDir, "runFib", outputFile)
|
||||
assertValidProfile(outputFile, "runFib")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `profiler can be restarted, and runs don't share samples`(@TempDir tempDir: Path) {
|
||||
val firstOutput = tempDir.resolve("first.pb.gz")
|
||||
val secondOutput = tempDir.resolve("second.pb.gz")
|
||||
val thirdOutput = tempDir.resolve("third.pb.gz")
|
||||
|
||||
eval(tempDir, "firstFib", firstOutput)
|
||||
test(tempDir, "secondFib", secondOutput)
|
||||
run(tempDir, "thirdFib", thirdOutput)
|
||||
|
||||
assertValidProfile(firstOutput, "firstFib")
|
||||
assertValidProfile(secondOutput, "secondFib")
|
||||
assertValidProfile(thirdOutput, "thirdFib")
|
||||
|
||||
// samples from earlier runs must not leak into later ones
|
||||
assertThat(readProfile(secondOutput).functionNames()).noneMatch { it.contains("firstFib") }
|
||||
assertThat(readProfile(thirdOutput).functionNames()).noneMatch {
|
||||
it.contains("firstFib") || it.contains("secondFib")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `profiler restarts after a failed evaluation`(@TempDir tempDir: Path) {
|
||||
val failingSource = tempDir.resolve("failing.pkl").also { it.writeText("x = throw(\"boom\")") }
|
||||
val failingOutput = tempDir.resolve("failing.pb.gz")
|
||||
val options =
|
||||
CliEvaluatorOptions(
|
||||
baseOptions(failingSource),
|
||||
profilerOptions = profilerOptions(failingOutput),
|
||||
)
|
||||
runCatching { CliEvaluator(options, outputStream = ByteArrayOutputStream()).run() }
|
||||
.also { assertThat(it.isFailure).isTrue() }
|
||||
|
||||
val outputFile = tempDir.resolve("profile.pb.gz")
|
||||
eval(tempDir, "afterFailureFib", outputFile)
|
||||
assertValidProfile(outputFile, "afterFailureFib")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no output is written if profiling is not enabled`(@TempDir tempDir: Path) {
|
||||
val source = tempDir.resolve("noProfile.pkl").also { it.writeText(evalCode("noProfileFib")) }
|
||||
CliEvaluator(CliEvaluatorOptions(baseOptions(source)), outputStream = ByteArrayOutputStream())
|
||||
.run()
|
||||
assertThat(tempDir.resolve("profile.pb.gz").exists()).isFalse()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright © 2026 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.cli
|
||||
|
||||
import com.google.perftools.profiles.ProfileProto.Profile
|
||||
import java.nio.file.Path
|
||||
import java.util.zip.GZIPInputStream
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.inputStream
|
||||
import kotlin.io.path.writeText
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
|
||||
/**
|
||||
* Exercises the CPU profiler end-to-end by running the packaged executable jar (or native
|
||||
* executable) as a subprocess.
|
||||
*
|
||||
* Run this test using `./gradlew pkl-cli:testProfilerOutput` (executable jar) or `./gradlew
|
||||
* pkl-cli:testNativeProfilerOutput` (native executable).
|
||||
*
|
||||
* To use an IntelliJ JUnit run configuration, configure the VM options and add
|
||||
* `-Dorg.pkl.cli.testJar=<path>` (or `-Dorg.pkl.cli.testExecutable=<path>`).
|
||||
*/
|
||||
class SubprocessProfilerOutputTest {
|
||||
/**
|
||||
* The command that launches Pkl: the native executable if `org.pkl.cli.testExecutable` is set,
|
||||
* otherwise the executable jar given by `org.pkl.cli.testJar`.
|
||||
*/
|
||||
private fun launcher(): Array<String> {
|
||||
System.getProperty("org.pkl.cli.testExecutable")?.let {
|
||||
return arrayOf(it)
|
||||
}
|
||||
val jar =
|
||||
checkNotNull(System.getProperty("org.pkl.cli.testJar")) {
|
||||
"neither system property `org.pkl.cli.testExecutable` nor `org.pkl.cli.testJar` is set"
|
||||
}
|
||||
val javaBin = ProcessHandle.current().info().command().orElseThrow()
|
||||
return arrayOf(javaBin, "-jar", jar)
|
||||
}
|
||||
|
||||
private fun runTest(tempDir: Path, pklCode: String, command: Array<String>) {
|
||||
val sourceFile = tempDir.resolve("profiled.pkl").also { it.writeText(pklCode) }
|
||||
val outputFile = tempDir.resolve("profile.pb.gz")
|
||||
|
||||
val process =
|
||||
ProcessBuilder(
|
||||
*launcher(),
|
||||
*command,
|
||||
"--profile-cpu-output",
|
||||
outputFile.absolutePathString(),
|
||||
"--profile-cpu-sample-period",
|
||||
"1",
|
||||
sourceFile.absolutePathString(),
|
||||
)
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
|
||||
val output = process.inputStream.bufferedReader().readText()
|
||||
val exitCode = process.waitFor()
|
||||
assertThat(exitCode).withFailMessage { "process failed with output:\n$output" }.isZero()
|
||||
|
||||
// smoke test only
|
||||
val profile = GZIPInputStream(outputFile.inputStream()).use { Profile.parseFrom(it) }
|
||||
assertThat(profile.stringTableList.first()).isEmpty() // string_table[0] must be ""
|
||||
assertThat(profile.sampleTypeList).isNotEmpty
|
||||
assertThat(profile.functionList).isNotEmpty
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pkl eval`(@TempDir tempDir: Path) {
|
||||
val pklCode =
|
||||
"""
|
||||
function fib(n) = if (n < 2) n else fib(n - 1) + fib(n - 2)
|
||||
x = fib(30)
|
||||
"""
|
||||
.trimIndent()
|
||||
runTest(tempDir, pklCode, arrayOf("eval"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pkl test`(@TempDir tempDir: Path) {
|
||||
val pklCode =
|
||||
"""
|
||||
amends "pkl:test"
|
||||
|
||||
local function fib(n) = if (n < 2) n else fib(n - 1) + fib(n - 2)
|
||||
|
||||
facts {
|
||||
["fib"] {
|
||||
fib(30) > 0
|
||||
}
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
runTest(tempDir, pklCode, arrayOf("eval"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pkl run`(@TempDir tempDir: Path) {
|
||||
val pklCode =
|
||||
"""
|
||||
amends "pkl:Command"
|
||||
|
||||
command {
|
||||
name = "do-run"
|
||||
}
|
||||
|
||||
local function fib(n) = if (n < 2) n else fib(n - 1) + fib(n - 2)
|
||||
|
||||
output {
|
||||
text = fib(30).toString()
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
runTest(tempDir, pklCode, arrayOf("run"))
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,13 @@ dependencies {
|
||||
|
||||
testImplementation(projects.pklConfigJava)
|
||||
testImplementation(projects.pklCommonsTest)
|
||||
|
||||
// used by `pklJavaExecutable` plugin (ideally this would be inferred automatically)
|
||||
firstPartySourcesJars(project(":pkl-codegen-java", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-commons", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-commons-cli", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-core", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-parser", "sourcesJar"))
|
||||
}
|
||||
|
||||
executable {
|
||||
|
||||
+12
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2024-2026 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.
|
||||
@@ -77,7 +77,17 @@ data class CliJavaCodeGeneratorOptions(
|
||||
* Pkl module name, and the value is the desired replacement.
|
||||
*/
|
||||
val renames: Map<String, String> = emptyMap(),
|
||||
|
||||
/**
|
||||
* The mapping of Pkl class names to the spring boot `@ConfigurationProperties` prefix name, when
|
||||
* [generateSpringBootConfig] is enabled.
|
||||
*
|
||||
* Setting this field is optional, and by default is inferred through the schema of the input
|
||||
* modules.
|
||||
*/
|
||||
val springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||
) {
|
||||
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("deprecated without replacement")
|
||||
fun toJavaCodegenOptions() = toJavaCodeGeneratorOptions()
|
||||
@@ -93,5 +103,6 @@ data class CliJavaCodeGeneratorOptions(
|
||||
nonNullAnnotation,
|
||||
implementSerializable,
|
||||
renames,
|
||||
springBootConfigurationProperties,
|
||||
)
|
||||
}
|
||||
@@ -97,7 +97,24 @@ data class JavaCodeGeneratorOptions(
|
||||
* from the corresponding name derived from the Pkl module declaration .
|
||||
*/
|
||||
val renames: Map<String, String> = emptyMap(),
|
||||
)
|
||||
|
||||
/**
|
||||
* The mapping of Pkl class names to the spring boot `@ConfigurationProperties` prefix name, when
|
||||
* [generateSpringBootConfig] is enabled.
|
||||
*
|
||||
* Setting this field is optional, and by default is inferred through the schema of the input
|
||||
* modules.
|
||||
*/
|
||||
val springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||
) {
|
||||
init {
|
||||
for (value in springBootConfigurationProperties.values) {
|
||||
require(value.isEmpty() || value.isValidConfigurationPropertiesPrefix) {
|
||||
"Invalid value in `springBootConfigurationProperties`: expected a valid ConfigurationProperties prefix, but got '$value'."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Entrypoint for the Java code generator API. */
|
||||
class JavaCodeGenerator(
|
||||
@@ -523,7 +540,25 @@ class JavaCodeGenerator(
|
||||
}
|
||||
|
||||
fun generateSpringBootAnnotations(builder: TypeSpec.Builder) {
|
||||
if (isModuleClass) {
|
||||
if (codegenOptions.springBootConfigurationProperties.isNotEmpty()) {
|
||||
val configurationPropertyPrefix =
|
||||
codegenOptions.springBootConfigurationProperties[pClass.displayName] ?: return
|
||||
val annotation =
|
||||
with(
|
||||
AnnotationSpec.builder(
|
||||
ClassName.get(
|
||||
"org.springframework.boot.context.properties",
|
||||
"ConfigurationProperties",
|
||||
)
|
||||
)
|
||||
) {
|
||||
if (!configurationPropertyPrefix.isEmpty()) {
|
||||
addMember("value", "\$S", configurationPropertyPrefix)
|
||||
}
|
||||
build()
|
||||
}
|
||||
builder.addAnnotation(annotation)
|
||||
} else if (isModuleClass) {
|
||||
builder.addAnnotation(
|
||||
ClassName.get("org.springframework.boot.context.properties", "ConfigurationProperties")
|
||||
)
|
||||
@@ -845,6 +880,7 @@ class JavaCodeGenerator(
|
||||
PClassInfo.Class -> PCLASS.nullableIf(nullable)
|
||||
PClassInfo.Regex -> PATTERN.nullableIf(nullable)
|
||||
PClassInfo.Version -> VERSION.nullableIf(nullable)
|
||||
PClassInfo.Url -> URI.nullableIf(nullable)
|
||||
else ->
|
||||
when {
|
||||
!classInfo.isStandardLibraryClass -> pClass.toJavaPoetName().nullableIf(nullable)
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.pkl.commons.cli.CliBaseOptions
|
||||
import org.pkl.commons.cli.cliMain
|
||||
import org.pkl.commons.cli.commands.ModulesCommand
|
||||
import org.pkl.commons.cli.commands.installCommonOptions
|
||||
import org.pkl.commons.isValidConfigurationPropertiesPrefix
|
||||
import org.pkl.commons.toPath
|
||||
import org.pkl.core.Release
|
||||
|
||||
@@ -131,6 +132,29 @@ class PklJavaCodegenCommand : ModulesCommand(name = "pkl-codegen-java", helpLink
|
||||
)
|
||||
.associate()
|
||||
|
||||
private val springBootConfigurationProperties: Map<String, String> by
|
||||
option(
|
||||
names = arrayOf("--spring-boot-configuration-properties"),
|
||||
metavar = "pkl_class_name=prefix_value",
|
||||
help =
|
||||
"""
|
||||
Turn the specified Pkl classes into Java classes with the `@ConfigurationProperties`
|
||||
annotation.
|
||||
|
||||
If this setting is omitted, the `@ConfigurationProperties` annotation is inferred
|
||||
according to the structure of the input modules.
|
||||
"""
|
||||
.trimIndent(),
|
||||
)
|
||||
.associate()
|
||||
.validate { map ->
|
||||
for (prefix in map.values) {
|
||||
require(prefix.isEmpty() || prefix.isValidConfigurationPropertiesPrefix) {
|
||||
"value must be a valid spring boot config prefix, but got '$prefix'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val helpString: String = "Generate Java classes and interfaces from Pkl module(s)"
|
||||
|
||||
override fun run() {
|
||||
@@ -147,6 +171,7 @@ class PklJavaCodegenCommand : ModulesCommand(name = "pkl-codegen-java", helpLink
|
||||
nonNullAnnotation = nonNullAnnotation,
|
||||
implementSerializable = implementSerializable,
|
||||
renames = renames,
|
||||
springBootConfigurationProperties = springBootConfigurationProperties,
|
||||
)
|
||||
CliJavaCodeGenerator(options).run()
|
||||
}
|
||||
|
||||
@@ -1159,6 +1159,52 @@ class JavaCodeGeneratorTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pkl_net Url`() {
|
||||
val javaCode =
|
||||
generateJavaCode(
|
||||
"""
|
||||
module mod
|
||||
|
||||
import "pkl:net"
|
||||
|
||||
url: net.Url
|
||||
nullableUrl: net.Url?
|
||||
listing: Listing<net.Url>
|
||||
mapping: Mapping<String, net.Url>
|
||||
|
||||
class Foo {
|
||||
url: net.Url
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
)
|
||||
|
||||
assertThat(javaCode)
|
||||
.compilesSuccessfully()
|
||||
.contains("import java.net.URI;")
|
||||
.contains(
|
||||
"""
|
||||
|public final class Mod {
|
||||
| public final @NonNull URI url;
|
||||
|
|
||||
| public final URI nullableUrl;
|
||||
|
|
||||
| public final @NonNull List<@NonNull URI> listing;
|
||||
|
|
||||
| public final @NonNull Map<@NonNull String, @NonNull URI> mapping;
|
||||
"""
|
||||
.trimMargin()
|
||||
)
|
||||
.contains(
|
||||
"""
|
||||
| public static final class Foo {
|
||||
| public final @NonNull URI url;
|
||||
"""
|
||||
.trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `nullable properties`() {
|
||||
var javaCode =
|
||||
@@ -1605,6 +1651,65 @@ class JavaCodeGeneratorTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `spring boot -- explicitly configured ConfigurationProperties`() {
|
||||
val javaCode =
|
||||
generateJavaCode(
|
||||
"""
|
||||
module my.mod
|
||||
|
||||
class Server
|
||||
"""
|
||||
.trimIndent(),
|
||||
JavaCodeGeneratorOptions(
|
||||
generateSpringBootConfig = true,
|
||||
springBootConfigurationProperties =
|
||||
mapOf("my.mod" to "", "my.mod#Server" to "my-server-prefix"),
|
||||
),
|
||||
)
|
||||
assertThat(javaCode)
|
||||
.contains(
|
||||
"""
|
||||
|@ConfigurationProperties
|
||||
|public final class Mod {
|
||||
| private Mod() {
|
||||
| }
|
||||
"""
|
||||
.trimMargin()
|
||||
)
|
||||
assertThat(javaCode)
|
||||
.contains(
|
||||
"""
|
||||
| @ConfigurationProperties("my-server-prefix")
|
||||
| public static final class Server {
|
||||
"""
|
||||
.trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `spring boot -- explicity configured properties means no interface`() {
|
||||
val javaCode =
|
||||
generateJavaCode(
|
||||
"""
|
||||
module my.mod
|
||||
|
||||
server: Server
|
||||
|
||||
class Server
|
||||
"""
|
||||
.trimIndent(),
|
||||
JavaCodeGeneratorOptions(
|
||||
generateSpringBootConfig = true,
|
||||
springBootConfigurationProperties = mapOf("foo" to "foo"),
|
||||
),
|
||||
)
|
||||
// normally this would generate `@ConfigurationProperties` annotations through inference.
|
||||
// but setting this option means that the user is in total control of how these annotations
|
||||
// get produced.
|
||||
assertThat(javaCode).doesNotContain("@ConfigurationProperties")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `import module`() {
|
||||
val library =
|
||||
|
||||
@@ -53,6 +53,13 @@ dependencies {
|
||||
testImplementation(projects.pklConfigKotlin)
|
||||
testImplementation(projects.pklCommonsTest)
|
||||
testRuntimeOnly(libs.kotlinScripting)
|
||||
|
||||
// used by `pklJavaExecutable` plugin (ideally this would be inferred automatically)
|
||||
firstPartySourcesJars(project(":pkl-codegen-kotlin", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-commons", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-commons-cli", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-core", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-parser", "sourcesJar"))
|
||||
}
|
||||
|
||||
executable {
|
||||
|
||||
+11
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2024-2026 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.
|
||||
@@ -49,6 +49,15 @@ data class CliKotlinCodeGeneratorOptions(
|
||||
* original Pkl module name, and the value is the desired replacement.
|
||||
*/
|
||||
val renames: Map<String, String> = emptyMap(),
|
||||
|
||||
/**
|
||||
* The mapping of Pkl class names to the spring boot `@ConfigurationProperties` prefix name, when
|
||||
* [generateSpringBootConfig] is enabled.
|
||||
*
|
||||
* Setting this field is optional, and by default is inferred through the schema of the input
|
||||
* modules.
|
||||
*/
|
||||
val springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||
) {
|
||||
@Suppress("DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("deprecated without replacement")
|
||||
@@ -62,5 +71,6 @@ data class CliKotlinCodeGeneratorOptions(
|
||||
implementSerializable,
|
||||
addGeneratedAnnotation,
|
||||
renames,
|
||||
springBootConfigurationProperties,
|
||||
)
|
||||
}
|
||||
@@ -53,7 +53,25 @@ data class KotlinCodeGeneratorOptions(
|
||||
* from the corresponding name derived from the Pkl module declaration .
|
||||
*/
|
||||
val renames: Map<String, String> = emptyMap(),
|
||||
)
|
||||
|
||||
/**
|
||||
* Explicitly configures `@ConfigurationProperties` on generated classes.
|
||||
*
|
||||
* The key is the Pkl class name (e.g. `my.mod` for a module class, `my.mod#Server` for a nested
|
||||
* class), and the value is the prefix. An empty prefix generates a bare annotation.
|
||||
*
|
||||
* If non-empty, no `@ConfigurationProperties` annotations are inferred.
|
||||
*/
|
||||
val springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||
) {
|
||||
init {
|
||||
for (value in springBootConfigurationProperties.values) {
|
||||
require(value.isEmpty() || value.isValidConfigurationPropertiesPrefix) {
|
||||
"Invalid value in `springBootConfigurationProperties`: expected a valid ConfigurationProperties prefix, but got '$value'."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinCodeGeneratorException(message: String) : RuntimeException(message)
|
||||
|
||||
@@ -136,7 +154,11 @@ class KotlinCodeGenerator(
|
||||
|
||||
val hasModuleProperties = pModuleClass.properties.any { !it.value.isHidden }
|
||||
val isGenerateModuleClass =
|
||||
hasModuleProperties || pModuleClass.isOpen || pModuleClass.isAbstract
|
||||
hasModuleProperties ||
|
||||
pModuleClass.isOpen ||
|
||||
pModuleClass.isAbstract ||
|
||||
options.generateSpringBootConfig &&
|
||||
options.springBootConfigurationProperties.containsKey(pModuleClass.displayName)
|
||||
|
||||
fun generateCompanionRelatedCode(
|
||||
builder: TypeSpec.Builder,
|
||||
@@ -420,7 +442,21 @@ class KotlinCodeGenerator(
|
||||
}
|
||||
|
||||
fun generateSpringBootAnnotations(builder: TypeSpec.Builder) {
|
||||
if (isModuleClass) {
|
||||
if (options.springBootConfigurationProperties.isNotEmpty()) {
|
||||
// explicit configuration: the user is in total control, so don't infer anything
|
||||
val prefix = options.springBootConfigurationProperties[pClass.displayName] ?: return
|
||||
val annotation =
|
||||
AnnotationSpec.builder(
|
||||
ClassName("org.springframework.boot.context.properties", "ConfigurationProperties")
|
||||
)
|
||||
.apply {
|
||||
if (prefix.isNotEmpty()) {
|
||||
addMember("%S", prefix)
|
||||
}
|
||||
}
|
||||
.build()
|
||||
builder.addAnnotation(annotation)
|
||||
} else if (isModuleClass) {
|
||||
builder.addAnnotation(
|
||||
ClassName("org.springframework.boot.context.properties", "ConfigurationProperties")
|
||||
)
|
||||
@@ -703,6 +739,7 @@ class KotlinCodeGenerator(
|
||||
PClassInfo.Class -> PCLASS
|
||||
PClassInfo.Regex -> REGEX
|
||||
PClassInfo.Version -> VERSION
|
||||
PClassInfo.Url -> URI
|
||||
else ->
|
||||
when {
|
||||
!classInfo.isStandardLibraryClass -> pClass.toKotlinPoetName()
|
||||
|
||||
@@ -22,12 +22,14 @@ import com.github.ajalt.clikt.parameters.options.associate
|
||||
import com.github.ajalt.clikt.parameters.options.default
|
||||
import com.github.ajalt.clikt.parameters.options.flag
|
||||
import com.github.ajalt.clikt.parameters.options.option
|
||||
import com.github.ajalt.clikt.parameters.options.validate
|
||||
import com.github.ajalt.clikt.parameters.types.path
|
||||
import java.nio.file.Path
|
||||
import org.pkl.commons.cli.CliBaseOptions
|
||||
import org.pkl.commons.cli.cliMain
|
||||
import org.pkl.commons.cli.commands.ModulesCommand
|
||||
import org.pkl.commons.cli.commands.installCommonOptions
|
||||
import org.pkl.commons.isValidConfigurationPropertiesPrefix
|
||||
import org.pkl.commons.toPath
|
||||
import org.pkl.core.Release
|
||||
|
||||
@@ -72,6 +74,29 @@ class PklKotlinCodegenCommand : ModulesCommand(name = "pkl-codegen-kotlin", help
|
||||
)
|
||||
.flag()
|
||||
|
||||
private val springBootConfigurationProperties: Map<String, String> by
|
||||
option(
|
||||
names = arrayOf("--spring-boot-configuration-properties"),
|
||||
metavar = "pkl_class_name=prefix_value",
|
||||
help =
|
||||
"""
|
||||
Turn the specified Pkl classes into Kotlin classes with the `@ConfigurationProperties`
|
||||
annotation.
|
||||
|
||||
If this setting is omitted, the `@ConfigurationProperties` annotation is inferred
|
||||
according to the structure of the input modules.
|
||||
"""
|
||||
.trimIndent(),
|
||||
)
|
||||
.associate()
|
||||
.validate { map ->
|
||||
for (prefix in map.values) {
|
||||
require(prefix.isEmpty() || prefix.isValidConfigurationPropertiesPrefix) {
|
||||
"value must be a valid spring boot config prefix, but got '$prefix'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val implementSerializable: Boolean by
|
||||
option(
|
||||
names = arrayOf("--implement-serializable"),
|
||||
@@ -113,6 +138,7 @@ class PklKotlinCodegenCommand : ModulesCommand(name = "pkl-codegen-kotlin", help
|
||||
implementSerializable = implementSerializable,
|
||||
addGeneratedAnnotation = addGeneratedAnnotation,
|
||||
renames = renames,
|
||||
springBootConfigurationProperties = springBootConfigurationProperties,
|
||||
)
|
||||
CliKotlinCodeGenerator(options).run()
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ class KotlinCodeGeneratorTest {
|
||||
generateKdoc: Boolean = false,
|
||||
generateSpringBootConfig: Boolean = false,
|
||||
implementSerializable: Boolean = false,
|
||||
springBootConfigurationProperties: Map<String, String> = emptyMap(),
|
||||
): KotlinSourceCode {
|
||||
|
||||
val module = Evaluator.preconfigured().evaluateSchema(ModuleSource.text(pklCode))
|
||||
@@ -153,6 +154,7 @@ class KotlinCodeGeneratorTest {
|
||||
generateKdoc = generateKdoc,
|
||||
generateSpringBootConfig = generateSpringBootConfig,
|
||||
implementSerializable = implementSerializable,
|
||||
springBootConfigurationProperties = springBootConfigurationProperties,
|
||||
),
|
||||
)
|
||||
return KotlinSourceCode(generator.kotlinFile)
|
||||
@@ -1186,6 +1188,52 @@ class KotlinCodeGeneratorTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pkl_net Url`() {
|
||||
val kotlinCode =
|
||||
generateKotlinCode(
|
||||
"""
|
||||
module mod
|
||||
|
||||
import "pkl:net"
|
||||
|
||||
url: net.Url
|
||||
nullableUrl: net.Url?
|
||||
listing: Listing<net.Url>
|
||||
mapping: Mapping<String, net.Url>
|
||||
|
||||
class Foo {
|
||||
url: net.Url
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
)
|
||||
|
||||
assertThat(kotlinCode)
|
||||
.compilesSuccessfully()
|
||||
.isEqualTo(
|
||||
"""
|
||||
import java.net.URI
|
||||
import kotlin.String
|
||||
import kotlin.collections.List
|
||||
import kotlin.collections.Map
|
||||
|
||||
data class Mod(
|
||||
val url: URI,
|
||||
val nullableUrl: URI?,
|
||||
val listing: List<URI>,
|
||||
val mapping: Map<String, URI>
|
||||
) {
|
||||
data class Foo(
|
||||
val url: URI
|
||||
)
|
||||
}
|
||||
|
||||
"""
|
||||
.trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `user defined type aliases`() {
|
||||
val kotlinCode =
|
||||
@@ -1520,6 +1568,42 @@ class KotlinCodeGeneratorTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `spring boot -- explicitly configured ConfigurationProperties`() {
|
||||
val kotlinCode =
|
||||
generateKotlinCode(
|
||||
"""
|
||||
module my.mod
|
||||
|
||||
class Server
|
||||
"""
|
||||
.trimIndent(),
|
||||
generateSpringBootConfig = true,
|
||||
springBootConfigurationProperties =
|
||||
mapOf("my.mod" to "", "my.mod#Server" to "my-server-prefix"),
|
||||
)
|
||||
assertThat(kotlinCode).contains("@ConfigurationProperties\ndata class Mod")
|
||||
assertThat(kotlinCode).contains("@ConfigurationProperties(\"my-server-prefix\")")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `spring boot -- explicitly configured properties disables inference`() {
|
||||
val kotlinCode =
|
||||
generateKotlinCode(
|
||||
"""
|
||||
module my.mod
|
||||
|
||||
server: Server
|
||||
|
||||
class Server
|
||||
"""
|
||||
.trimIndent(),
|
||||
generateSpringBootConfig = true,
|
||||
springBootConfigurationProperties = mapOf("foo" to "foo"),
|
||||
)
|
||||
assertThat(kotlinCode).doesNotContain("@ConfigurationProperties")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `import module`() {
|
||||
val library =
|
||||
|
||||
@@ -69,9 +69,9 @@ abstract class CliCommand(protected val cliOptions: CliBaseOptions) {
|
||||
protected val settings: PklSettings by lazy {
|
||||
try {
|
||||
if (cliOptions.normalizedSettingsModule != null) {
|
||||
PklSettings.load(ModuleSource.uri(cliOptions.normalizedSettingsModule))
|
||||
PklSettings.load(ModuleSource.uri(cliOptions.normalizedSettingsModule), cliModuleCacheDir)
|
||||
} else {
|
||||
PklSettings.loadFromSystem()
|
||||
PklSettings.loadFromSystem(cliModuleCacheDir)
|
||||
}
|
||||
} catch (e: PklException) {
|
||||
// do not use `errorRenderer` because it depends on `settings`
|
||||
@@ -107,9 +107,19 @@ abstract class CliCommand(protected val cliOptions: CliBaseOptions) {
|
||||
stackFrameTransformer,
|
||||
envVars,
|
||||
cliOptions.powerAssertionsEnabled,
|
||||
cliModuleCacheDir,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The module cache dir as determined by CLI options alone. Used to evaluate the settings and
|
||||
* project files, which are loaded before project evaluator settings are known.
|
||||
*/
|
||||
private val cliModuleCacheDir: Path? by lazy {
|
||||
if (cliOptions.noCache) null
|
||||
else cliOptions.normalizedModuleCacheDir ?: IoUtils.getSystemModuleCacheDir()
|
||||
}
|
||||
|
||||
private val evaluatorSettings: PklEvaluatorSettings? by lazy {
|
||||
@Suppress("PklCliDirectProjectEvaluatorSettingsAccess")
|
||||
if (cliOptions.omitProjectSettings) null else project?.resolvedEvaluatorSettings
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright © 2026 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.commons.cli.commands
|
||||
|
||||
import com.github.ajalt.clikt.parameters.groups.OptionGroup
|
||||
import com.github.ajalt.clikt.parameters.options.default
|
||||
import com.github.ajalt.clikt.parameters.options.option
|
||||
import com.github.ajalt.clikt.parameters.types.long
|
||||
import com.github.ajalt.clikt.parameters.types.path
|
||||
import java.nio.file.Path
|
||||
import org.pkl.core.ProfilerOptions
|
||||
|
||||
class ProfileOptions : OptionGroup() {
|
||||
val profileCpuOutput: Path? by
|
||||
option(
|
||||
names = arrayOf("--profile-cpu-output"),
|
||||
help =
|
||||
"The file to write CPU profiler output to. Omitting this option disables CPU profiling.",
|
||||
)
|
||||
.single()
|
||||
.path()
|
||||
|
||||
val profileCpuSamplePeriod: Long by
|
||||
option(
|
||||
names = arrayOf("--profile-cpu-sample-period"),
|
||||
help = "Duration, in milliseconds, for the CPU profiler to poll for samples.",
|
||||
)
|
||||
.single()
|
||||
.long()
|
||||
.default(ProfilerOptions.DEFAULT.cpu.samplePeriod)
|
||||
|
||||
fun toOptions(workingDir: Path): ProfilerOptions =
|
||||
ProfilerOptions(
|
||||
ProfilerOptions.Cpu(profileCpuOutput?.let(workingDir::resolve), profileCpuSamplePeriod)
|
||||
)
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,5 +0,0 @@
|
||||
amends "pkl:Project"
|
||||
|
||||
dependencies {
|
||||
["fruit"] { uri = "package://localhost:0/fruit@1.1.0" }
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import org.junit.jupiter.api.condition.JRE
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import org.pkl.commons.cli.commands.BaseCommand
|
||||
import org.pkl.commons.cli.commands.ProjectOptions
|
||||
import org.pkl.commons.test.PackageServer
|
||||
import org.pkl.commons.writeString
|
||||
import org.pkl.core.SecurityManagers
|
||||
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings
|
||||
@@ -134,7 +135,9 @@ class CliCommandTest {
|
||||
@DisabledOnJre(JRE.JAVA_22, JRE.JAVA_23, JRE.JAVA_24)
|
||||
fun `test that --omit-project-settings actually omits project settings`(@TempDir tempDir: Path) {
|
||||
val project = tempDir.resolve("PklProject").writeString(projectWithAllEvaluatorSettings)
|
||||
cmd.parse(arrayOf("--working-dir=$tempDir", "--omit-project-settings"))
|
||||
cmd.parse(
|
||||
arrayOf("--working-dir=$tempDir", "--omit-project-settings", "--settings=pkl:settings")
|
||||
)
|
||||
val opts =
|
||||
cmd.baseOptions.baseOptions(listOf(project.toUri()), cmd.projectOptions, testMode = true)
|
||||
val cliTest = CliTest(opts)
|
||||
@@ -200,4 +203,31 @@ class CliCommandTest {
|
||||
assertThat(cliTest.myExternalModuleReaders)
|
||||
.isEqualTo(mapOf("bar" to PklEvaluatorSettings.ExternalReader("bar", listOf(), null)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `--cache-dir is used when loading the project`(@TempDir tempDir: Path) {
|
||||
val cacheDir = tempDir.resolve("cache").also(PackageServer::populateCacheDir)
|
||||
tempDir
|
||||
.resolve("PklProject")
|
||||
.writeString(
|
||||
// language=pkl
|
||||
"""
|
||||
amends "pkl:Project"
|
||||
|
||||
import "package://localhost:0/fruit@1.0.5#/catalog/apple.pkl"
|
||||
|
||||
evaluatorSettings {
|
||||
externalProperties {
|
||||
["fruit"] = apple.name
|
||||
}
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
)
|
||||
cmd.parse(arrayOf("--working-dir=$tempDir", "--cache-dir=$cacheDir"))
|
||||
val opts = cmd.baseOptions.baseOptions(emptyList(), cmd.projectOptions, testMode = true)
|
||||
val cliTest = CliTest(opts)
|
||||
assertThat(cliTest.myProjectEvaluatorSettings!!.externalProperties)
|
||||
.containsEntry("fruit", "Apple")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
amends "pkl:Project"
|
||||
|
||||
dependencies {
|
||||
["fruit"] { uri = "package://localhost:0/fruit@1.2.0" }
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
"resolvedDependencies": {
|
||||
"package://localhost:0/fruit@1": {
|
||||
"type": "remote",
|
||||
"uri": "projectpackage://localhost:0/fruit@1.1.0",
|
||||
"uri": "projectpackage://localhost:0/fruit@1.2.0",
|
||||
"checksums": {
|
||||
"sha256": "$skipChecksumVerification"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"packageUri": "package://localhost:0/fruit@1.2.0",
|
||||
"name": "fruit",
|
||||
"version": "1.2.0",
|
||||
"packageZipUrl": "https://localhost:0/fruit@1.2.0/fruit@1.2.0.zip",
|
||||
"dependencies": {},
|
||||
"packageZipChecksums": {
|
||||
"sha256": "$computedChecksum"
|
||||
},
|
||||
"sourceCode": "https://example.com/fruit",
|
||||
"documentation": "https://example.com/fruit-docs",
|
||||
"license": "UNLICENSED",
|
||||
"authors": [
|
||||
"apple-1@example.com",
|
||||
"banana-2@example.com"
|
||||
],
|
||||
"issueTracker": "https://example.com/fruit/issues"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
module fruit.Fruit
|
||||
|
||||
name: String
|
||||
@@ -0,0 +1,13 @@
|
||||
module fruit.Fruits
|
||||
|
||||
import "Fruit.pkl"
|
||||
|
||||
fruits: Listing<Fruit>
|
||||
|
||||
output {
|
||||
files {
|
||||
for (fruit in fruits) {
|
||||
[fruit.name] = fruit.output
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
amends "../Fruit.pkl"
|
||||
|
||||
name = "Apple 🍎"
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
amends "../Fruits.pkl"
|
||||
|
||||
fruits {
|
||||
import("apple.pkl")
|
||||
import("pineapple.pkl")
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
amends "../Fruit.pkl"
|
||||
|
||||
name = "Pineapple 🍍"
|
||||
@@ -19,6 +19,7 @@ import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.exists
|
||||
import org.pkl.commons.test.FileTestUtils.rootProjectDir
|
||||
import org.pkl.core.util.IoUtils
|
||||
|
||||
sealed class ExecutablePaths(protected val gradleProject: String) {
|
||||
abstract val allNative: List<Path>
|
||||
@@ -80,4 +81,20 @@ object Executables {
|
||||
override val allNative: List<Path> =
|
||||
listOf(macAarch64, linuxAarch64, linuxAmd64, alpineAmd64, windowsAmd64)
|
||||
}
|
||||
|
||||
val externalReaderFixture by lazy {
|
||||
val readerPath =
|
||||
System.getProperty("org.pkl.core.testExternalReaderPath")
|
||||
?: "pkl-core/build/fixtures/externalreader"
|
||||
.let { if (IoUtils.isWindows()) "$it.bat" else it }
|
||||
|
||||
rootProjectDir.resolve(readerPath).also { path ->
|
||||
if (!Files.exists(path)) {
|
||||
throw AssertionError(
|
||||
"Fixture `${readerPath.substringAfterLast('/')}` not found. To fix this problem, first run" +
|
||||
" `./gradlew pkl-core:externalReaderFixture`."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
-15
@@ -35,6 +35,7 @@ import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import org.msgpack.core.MessagePack
|
||||
import org.pkl.commons.test.Executables
|
||||
import org.pkl.commons.test.PackageServer
|
||||
import org.pkl.commons.test.debugRendering
|
||||
import org.pkl.core.messaging.Messages.*
|
||||
@@ -238,9 +239,6 @@ abstract class AbstractServerTest {
|
||||
assertThat(value.asStringValue().asString()).isEqualTo("my bahumbug")
|
||||
}
|
||||
|
||||
@Disabled(
|
||||
"Unable to construct ReadResourceResponse with null contents due to Kotlin compiler bug"
|
||||
)
|
||||
@Test
|
||||
fun `read resource -- null contents and null error`() {
|
||||
val reader = ResourceReaderSpec("bahumbug", true, false)
|
||||
@@ -260,18 +258,10 @@ abstract class AbstractServerTest {
|
||||
assertThat(readResourceMsg.uri.toString()).isEqualTo("bahumbug:/foo.pkl")
|
||||
assertThat(readResourceMsg.evaluatorId).isEqualTo(evaluatorId)
|
||||
|
||||
client.send(ReadResourceResponse(readResourceMsg.requestId, evaluatorId, byteArrayOf(), null))
|
||||
// for this test to be correct this should actually be:
|
||||
// client.send(ReadResourceResponse(readResourceMsg.requestId, evaluatorId, null, null))
|
||||
// this should be evaluated again once https://github.com/apple/pkl/issues/698 is addressed
|
||||
// see conversation here https://github.com/apple/pkl/pull/660#discussion_r1819545811
|
||||
client.send(ReadResourceResponse(readResourceMsg.requestId, evaluatorId, null, null))
|
||||
|
||||
val evaluateResponse = client.receive<EvaluateResponse>()
|
||||
assertThat(evaluateResponse.error).isNull()
|
||||
|
||||
val unpacker = MessagePack.newDefaultUnpacker(evaluateResponse.result)
|
||||
val value = unpacker.unpackValue()
|
||||
assertThat(value.asStringValue().asString()).isEqualTo("")
|
||||
assertThat(evaluateResponse.error).contains("Cannot find resource `bahumbug:/foo.pkl`.")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1133,6 +1123,40 @@ abstract class AbstractServerTest {
|
||||
.contains("Rewrite rule must end with '/', but was 'https://example.com'")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test external reader`() {
|
||||
val evaluatorId =
|
||||
client.sendCreateEvaluatorRequest(
|
||||
externalResourceReaders =
|
||||
mapOf(
|
||||
"foo" to ExternalReader(Executables.externalReaderFixture.toString(), emptyList(), null)
|
||||
)
|
||||
)
|
||||
val requestId = 234L
|
||||
|
||||
client.send(
|
||||
EvaluateRequest(
|
||||
requestId,
|
||||
evaluatorId,
|
||||
URI("repl:text"),
|
||||
"""
|
||||
res = read("foo:bar")
|
||||
"""
|
||||
.trimIndent(),
|
||||
"res.text",
|
||||
)
|
||||
)
|
||||
|
||||
val response = client.receive<EvaluateResponse>()
|
||||
assertThat(response.error).isNull()
|
||||
assertThat(response.result).isNotNull
|
||||
assertThat(response.requestId()).isEqualTo(requestId)
|
||||
|
||||
val unpacker = MessagePack.newDefaultUnpacker(response.result)
|
||||
val value = unpacker.unpackValue()
|
||||
assertThat(value.asStringValue().asString()).isEqualTo("hello")
|
||||
}
|
||||
|
||||
protected fun TestTransport.sendCreateEvaluatorRequest(
|
||||
requestId: Long = 123,
|
||||
resourceReaders: List<ResourceReaderSpec> = listOf(),
|
||||
@@ -1141,6 +1165,8 @@ abstract class AbstractServerTest {
|
||||
project: Project? = null,
|
||||
cacheDir: Path? = null,
|
||||
http: Http? = null,
|
||||
externalResourceReaders: Map<String, ExternalReader>? = null,
|
||||
externalModuleReaders: Map<String, ExternalReader>? = null,
|
||||
): Long {
|
||||
val message =
|
||||
CreateEvaluatorRequest(
|
||||
@@ -1158,8 +1184,8 @@ abstract class AbstractServerTest {
|
||||
null,
|
||||
project,
|
||||
http,
|
||||
null,
|
||||
null,
|
||||
externalModuleReaders,
|
||||
externalResourceReaders,
|
||||
null,
|
||||
)
|
||||
|
||||
|
||||
@@ -87,7 +87,9 @@ dependencies {
|
||||
|
||||
testImplementation(libs.javaxInject)
|
||||
|
||||
// firstPartySourcesJars(project(":pkl-formatter", "sourcesJar")) // TODO when syntax merges
|
||||
firstPartySourcesJars(project(":pkl-core", "sourcesJar"))
|
||||
firstPartySourcesJars(project(":pkl-parser", "sourcesJar"))
|
||||
|
||||
pklCodegenJava(projects.pklCodegenJava)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2024-2026 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.
|
||||
@@ -265,6 +265,36 @@ public final class Conversions {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Conversion from {@code pkl.net#Url} to {@link String}. Gives the same result as {@code
|
||||
* Url.toString()}.
|
||||
*/
|
||||
public static final Conversion<PObject, String> pUrlToString =
|
||||
Conversion.of(PClassInfo.Url, String.class, (value, mapper) -> serializeUrl(value));
|
||||
|
||||
/**
|
||||
* Conversion from {@code pkl.net#Url} to {@link URI}. Throws {@link ConversionException} if the
|
||||
* URL cannot be represented as a {@link URI}, which is the case for a host that is an IPvFuture
|
||||
* address.
|
||||
*/
|
||||
public static final Conversion<PObject, URI> pUrlToURI =
|
||||
Conversion.of(
|
||||
PClassInfo.Url,
|
||||
URI.class,
|
||||
(value, mapper) -> {
|
||||
var url = serializeUrl(value);
|
||||
try {
|
||||
return new URI(url);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ConversionException(
|
||||
String.format("Failed to convert `pkl.net#Url` `%s` to `java.net.URI`.", url), e);
|
||||
}
|
||||
});
|
||||
|
||||
private static String serializeUrl(PObject url) {
|
||||
return (String) url.getProperty("stringValue");
|
||||
}
|
||||
|
||||
/**
|
||||
* Identity conversions used when the Java representation of the Pkl type matches the target type
|
||||
* or when the target type is {@link Object}.
|
||||
@@ -323,7 +353,9 @@ public final class Conversions {
|
||||
pDurationToDuration,
|
||||
pVersionToVersion,
|
||||
pVersionToString,
|
||||
pStringToVersion);
|
||||
pStringToVersion,
|
||||
pUrlToString,
|
||||
pUrlToURI);
|
||||
|
||||
/** All conversions defined in this class. */
|
||||
public static final Collection<Conversion<?, ?>> all = collectAll();
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright © 2026 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.config.java.mapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.pkl.core.ModuleSource.modulePath;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pkl.core.Evaluator;
|
||||
import org.pkl.core.PModule;
|
||||
|
||||
public class PUrlToStringTest {
|
||||
private static final Evaluator evaluator = Evaluator.preconfigured();
|
||||
|
||||
private static final PModule module =
|
||||
evaluator.evaluate(modulePath("org/pkl/config/java/mapper/PUrlToURITest.pkl"));
|
||||
|
||||
private static final ValueMapper mapper = ValueMapperBuilder.preconfigured().build();
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
evaluator.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void absolute() {
|
||||
assertThat(map("absolute")).isEqualTo("https://user:pw@example.com:8080/a/b?q=1#frag");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void percentEncoding() {
|
||||
assertThat(map("literalSpace")).isEqualTo("https://example.com/a%20b");
|
||||
assertThat(map("nonAscii")).isEqualTo("https://example.com/%C3%A9");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void relative() {
|
||||
assertThat(map("relative")).isEqualTo("/foo/bar");
|
||||
assertThat(map("colonSegment")).isEqualTo("./a:b");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ipvFuture() {
|
||||
assertThat(map("ipvFuture")).isEqualTo("http://[v1.fe80::a+en1]/");
|
||||
}
|
||||
|
||||
private static String map(String propertyName) {
|
||||
var url = module.get(propertyName);
|
||||
assert url != null;
|
||||
return mapper.map(url, String.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright © 2026 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.config.java.mapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.pkl.core.ModuleSource.modulePath;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pkl.core.Evaluator;
|
||||
import org.pkl.core.PModule;
|
||||
|
||||
public class PUrlToURITest {
|
||||
private static final Evaluator evaluator = Evaluator.preconfigured();
|
||||
|
||||
private static final PModule module =
|
||||
evaluator.evaluate(modulePath("org/pkl/config/java/mapper/PUrlToURITest.pkl"));
|
||||
|
||||
private static final ValueMapper mapper = ValueMapperBuilder.preconfigured().build();
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
evaluator.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void absolute() {
|
||||
assertThat(map("absolute"))
|
||||
.isEqualTo(URI.create("https://user:pw@example.com:8080/a/b?q=1#frag"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void percentEncoding() {
|
||||
// characters that cannot appear literally are encoded, and what is already encoded is kept
|
||||
assertThat(map("literalSpace")).isEqualTo(URI.create("https://example.com/a%20b"));
|
||||
assertThat(map("encodedSpace")).isEqualTo(URI.create("https://example.com/a%20b"));
|
||||
assertThat(map("encodedSlash")).isEqualTo(URI.create("https://example.com/a%2Fb"));
|
||||
assertThat(map("nonAscii")).isEqualTo(URI.create("https://example.com/%C3%A9"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void relative() {
|
||||
assertThat(map("relative")).isEqualTo(URI.create("/foo/bar"));
|
||||
// a first segment holding a ":" has to be preceded by a dot-segment, or it would be read as a
|
||||
// scheme
|
||||
assertThat(map("colonSegment")).isEqualTo(URI.create("./a:b"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authority() {
|
||||
assertThat(map("rootless")).isEqualTo(URI.create("mailto:user@example.com"));
|
||||
assertThat(map("noAuthority")).isEqualTo(URI.create("file:/tmp"));
|
||||
assertThat(map("emptyAuthority")).isEqualTo(URI.create("file:///tmp"));
|
||||
assertThat(map("emptyQuery")).isEqualTo(URI.create("https://example.com/?"));
|
||||
assertThat(map("ipv6Zone")).isEqualTo(URI.create("http://[fe80::1%25eth0]/p"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructed() {
|
||||
assertThat(map("constructed")).isEqualTo(URI.create("https://example.com/a%20b?x%20y"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ipvFuture() {
|
||||
// `java.net.URI` doesn't know IPvFuture addresses
|
||||
assertThatThrownBy(() -> map("ipvFuture"))
|
||||
.isInstanceOf(ConversionException.class)
|
||||
.hasMessageContaining("http://[v1.fe80::a+en1]/")
|
||||
.hasCauseInstanceOf(URISyntaxException.class);
|
||||
}
|
||||
|
||||
private static URI map(String propertyName) {
|
||||
var url = module.get(propertyName);
|
||||
assert url != null;
|
||||
return mapper.map(url, URI.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import "pkl:net"
|
||||
|
||||
absolute = net.Url("https://user:pw@example.com:8080/a/b?q=1#frag")
|
||||
literalSpace = net.Url("https://example.com/a b")
|
||||
encodedSpace = net.Url("https://example.com/a%20b")
|
||||
encodedSlash = net.Url("https://example.com/a%2Fb")
|
||||
nonAscii = net.Url("https://example.com/é")
|
||||
relative = net.Url("/foo/bar")
|
||||
rootless = net.Url("mailto:user@example.com")
|
||||
noAuthority = net.Url("file:/tmp")
|
||||
emptyAuthority = net.Url("file:///tmp")
|
||||
emptyQuery = net.Url("https://example.com/?")
|
||||
ipv6Zone = net.Url("http://[fe80::1%25eth0]/p")
|
||||
ipvFuture = net.Url("http://[v1.fe80::a+en1]/")
|
||||
constructed = new net.Url { scheme = "https"; rawHost = "example.com"; rawPath = "/a%20b"; rawQuery = "x%20y" }
|
||||
colonSegment = new net.Url { rawPath = "./a:b" }
|
||||
@@ -40,6 +40,8 @@ val externalReaderFixtureImplementation: Configuration =
|
||||
extendsFrom(configurations.testImplementation.get())
|
||||
}
|
||||
|
||||
val externalReaderFixtureConfiguration = configurations.create("externalReaderFixture")
|
||||
|
||||
idea {
|
||||
module {
|
||||
// mark generated/truffle as generated source dir
|
||||
@@ -59,6 +61,7 @@ dependencies {
|
||||
compileOnly(projects.pklExecutor)
|
||||
|
||||
implementation(projects.pklParser)
|
||||
implementation(projects.pklFormatter)
|
||||
implementation(libs.msgpack)
|
||||
implementation(libs.truffleApi)
|
||||
implementation(libs.graalSdk)
|
||||
@@ -170,6 +173,13 @@ val externalReaderFixture =
|
||||
}
|
||||
}
|
||||
|
||||
artifacts {
|
||||
add(
|
||||
externalReaderFixtureConfiguration.name,
|
||||
externalReaderFixture.map { it.outputs.files.singleFile },
|
||||
)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
configureTest()
|
||||
dependsOn(externalReaderFixture)
|
||||
@@ -191,7 +201,7 @@ tasks.test {
|
||||
|
||||
systemProperty(
|
||||
"org.pkl.core.testExternalReaderPath",
|
||||
externalReaderFixture.map { it.outputs.files.singleFile.absolutePath },
|
||||
externalReaderFixture.map { it.outputs.files.singleFile.absolutePath }.get(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -247,11 +247,14 @@ public final class DataSize implements Value {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Double.hashCode(convertValueTo(DataSizeUnit.BYTES));
|
||||
// adding 0.0 normalizes -0.0 to 0.0, because -0.0 == 0.0 but their hash codes differ
|
||||
return Double.hashCode(convertValueTo(DataSizeUnit.BYTES) + 0.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MathUtils.isMathematicalInteger(value) ? (long) value + "." + unit : value + "." + unit;
|
||||
return MathUtils.isMathematicalIntegerFittingLong(value)
|
||||
? (long) value + "." + unit
|
||||
: value + "." + unit;
|
||||
}
|
||||
}
|
||||
@@ -222,7 +222,8 @@ public final class Duration implements Value {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Double.hashCode(convertValueTo(DurationUnit.NANOS));
|
||||
// adding 0.0 normalizes -0.0 to 0.0, because -0.0 == 0.0 but their hash codes differ
|
||||
return Double.hashCode(convertValueTo(DurationUnit.NANOS) + 0.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.pkl.core;
|
||||
|
||||
import com.oracle.truffle.api.nodes.IndirectCallNode;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
@@ -195,7 +196,9 @@ public final class EvaluatorImpl implements Evaluator {
|
||||
(module) -> {
|
||||
var output = VmUtils.readModuleOutput(module);
|
||||
return VmUtils.readFilesProperty(
|
||||
output, (fileOutput) -> new FileOutputImpl(this, fileOutput));
|
||||
output,
|
||||
(fileOutput) -> new FileOutputImpl(this, fileOutput),
|
||||
IndirectCallNode.getUncached());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2024-2026 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.
|
||||
@@ -22,7 +22,6 @@ public enum OutputFormat {
|
||||
PCF("pcf"),
|
||||
PROPERTIES("properties"),
|
||||
PLIST("plist"),
|
||||
TEXTPROTO("textproto"),
|
||||
XML("xml"),
|
||||
YAML("yaml");
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ public final class PClassInfo<T> implements Serializable {
|
||||
|
||||
public static final URI pklBaseUri = URI.create("pkl:base");
|
||||
public static final URI pklSemverUri = URI.create("pkl:semver");
|
||||
public static final URI pklNetUri = URI.create("pkl:net");
|
||||
public static final URI pklSettingsUri = URI.create("pkl:settings");
|
||||
public static final URI pklProjectUri = URI.create("pkl:Project");
|
||||
public static final URI pklRefUri = URI.create("pkl:ref");
|
||||
@@ -82,6 +83,8 @@ public final class PClassInfo<T> implements Serializable {
|
||||
pklBaseClassInfo("ModuleInfo", PObject.class);
|
||||
public static final PClassInfo<PObject> Version =
|
||||
new PClassInfo<>("pkl.semver", "Version", PObject.class, pklSemverUri);
|
||||
public static final PClassInfo<PObject> Url =
|
||||
new PClassInfo<>("pkl.net", "Url", PObject.class, pklNetUri);
|
||||
public static final PClassInfo<PObject> Project =
|
||||
new PClassInfo<>("pkl.Project", MODULE_CLASS_NAME, PObject.class, pklProjectUri);
|
||||
public static final PClassInfo<PObject> Settings =
|
||||
|
||||
Loaded 100 of 658 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user