mirror of
https://github.com/apple/pkl.git
synced 2026-05-25 08:09:17 +02:00
Added support for external readers in Gradle plugins (#1578)
Adds support for configuring external module and resource readers in the Gradle plugin
This commit is contained in:
@@ -63,13 +63,59 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Support for testing with a real external reader in tests - this builds an additional source set
|
||||||
|
// into a jar with a main class which provides a simple external reader implementation.
|
||||||
|
// Then the path to the jar file and the toolchain's `java` binary
|
||||||
|
// are injected into tests as properties.
|
||||||
|
|
||||||
|
val externalReader by sourceSets.creating {}
|
||||||
|
|
||||||
|
dependencies { "externalReaderImplementation"(libs.msgpack) }
|
||||||
|
|
||||||
|
val externalReaderJar by
|
||||||
|
tasks.registering(Jar::class) {
|
||||||
|
description = "Builds an external reader executable jar file"
|
||||||
|
archiveBaseName = "external-reader"
|
||||||
|
archiveVersion = ""
|
||||||
|
|
||||||
|
// Package all dependencies into the jar (shadow plugin lite).
|
||||||
|
from(
|
||||||
|
externalReader.runtimeClasspath.elements.map { locations ->
|
||||||
|
locations.mapNotNull { location ->
|
||||||
|
val f = location.asFile
|
||||||
|
when {
|
||||||
|
f.isDirectory -> f
|
||||||
|
f.isFile -> zipTree(f)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
manifest { attributes("Main-Class" to "org.pkl.gradle.test.extreader.Main") }
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
dependsOn(externalReaderJar)
|
||||||
|
// Currently the only way to inject system properties from lazy values in Gradle
|
||||||
|
// is via `jvmArgumentProviders`.
|
||||||
|
jvmArgumentProviders += CommandLineArgumentProvider {
|
||||||
|
listOf(
|
||||||
|
"-DpklGradle.externalReaderJar=" +
|
||||||
|
externalReaderJar.get().archiveFile.get().asFile.absolutePath,
|
||||||
|
"-DpklGradle.javaExecutable=" +
|
||||||
|
javaToolchains.launcherFor(java.toolchain).get().executablePath.asFile.absolutePath,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
withType<MavenPublication>().configureEach {
|
withType<MavenPublication>().configureEach {
|
||||||
pom {
|
pom {
|
||||||
name.set("pkl-gradle plugin")
|
name = "pkl-gradle plugin"
|
||||||
url.set("https://github.com/apple/pkl/tree/main/pkl-gradle")
|
url = "https://github.com/apple/pkl/tree/main/pkl-gradle"
|
||||||
description.set("Gradle plugin for the Pkl configuration language.")
|
description = "Gradle plugin for the Pkl configuration language."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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.gradle.test.extreader;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import org.msgpack.core.MessagePack;
|
||||||
|
import org.msgpack.value.Value;
|
||||||
|
import org.msgpack.value.ValueFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A minimal external resource reader for Pkl. Uppercases the scheme-specific part of the URI and
|
||||||
|
* returns it as binary content. Implements the Pkl external reader MessagePack protocol over
|
||||||
|
* stdin/stdout.
|
||||||
|
*/
|
||||||
|
public class Main {
|
||||||
|
private static final int INITIALIZE_RESOURCE_READER_REQUEST = 0x30;
|
||||||
|
private static final int INITIALIZE_RESOURCE_READER_RESPONSE = 0x31;
|
||||||
|
private static final int READ_RESOURCE_REQUEST = 0x26;
|
||||||
|
private static final int READ_RESOURCE_RESPONSE = 0x27;
|
||||||
|
private static final int CLOSE_EXTERNAL_PROCESS = 0x32;
|
||||||
|
|
||||||
|
private static final Value KEY_REQUEST_ID = ValueFactory.newString("requestId");
|
||||||
|
private static final Value KEY_EVALUATOR_ID = ValueFactory.newString("evaluatorId");
|
||||||
|
private static final Value KEY_SCHEME = ValueFactory.newString("scheme");
|
||||||
|
private static final Value KEY_URI = ValueFactory.newString("uri");
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
var unpacker = MessagePack.newDefaultUnpacker(System.in);
|
||||||
|
var packer = MessagePack.newDefaultPacker(System.out);
|
||||||
|
|
||||||
|
while (unpacker.hasNext()) {
|
||||||
|
var arrayLen = unpacker.unpackArrayHeader();
|
||||||
|
if (arrayLen != 2) {
|
||||||
|
throw new IOException("Expected array of 2, got " + arrayLen);
|
||||||
|
}
|
||||||
|
var msgType = unpacker.unpackInt();
|
||||||
|
var body = unpacker.unpackValue().asMapValue().map();
|
||||||
|
|
||||||
|
switch (msgType) {
|
||||||
|
case INITIALIZE_RESOURCE_READER_REQUEST -> {
|
||||||
|
var requestId = body.get(KEY_REQUEST_ID).asIntegerValue().asLong();
|
||||||
|
var scheme = body.get(KEY_SCHEME).asStringValue().asString();
|
||||||
|
|
||||||
|
packer.packArrayHeader(2);
|
||||||
|
packer.packInt(INITIALIZE_RESOURCE_READER_RESPONSE);
|
||||||
|
packer.packMapHeader(2);
|
||||||
|
packer.packString("requestId");
|
||||||
|
packer.packLong(requestId);
|
||||||
|
packer.packString("spec");
|
||||||
|
packer.packMapHeader(3);
|
||||||
|
packer.packString("scheme");
|
||||||
|
packer.packString(scheme);
|
||||||
|
packer.packString("hasHierarchicalUris");
|
||||||
|
packer.packBoolean(false);
|
||||||
|
packer.packString("isGlobbable");
|
||||||
|
packer.packBoolean(false);
|
||||||
|
packer.flush();
|
||||||
|
}
|
||||||
|
case READ_RESOURCE_REQUEST -> {
|
||||||
|
var requestId = body.get(KEY_REQUEST_ID).asIntegerValue().asLong();
|
||||||
|
var evaluatorId = body.get(KEY_EVALUATOR_ID).asIntegerValue().asLong();
|
||||||
|
var uri = body.get(KEY_URI).asStringValue().asString();
|
||||||
|
|
||||||
|
var colonIndex = uri.indexOf(':');
|
||||||
|
var schemeSpecific = colonIndex >= 0 ? uri.substring(colonIndex + 1) : uri;
|
||||||
|
var contents = schemeSpecific.toUpperCase().getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
packer.packArrayHeader(2);
|
||||||
|
packer.packInt(READ_RESOURCE_RESPONSE);
|
||||||
|
packer.packMapHeader(3);
|
||||||
|
packer.packString("requestId");
|
||||||
|
packer.packLong(requestId);
|
||||||
|
packer.packString("evaluatorId");
|
||||||
|
packer.packLong(evaluatorId);
|
||||||
|
packer.packString("contents");
|
||||||
|
packer.packBinaryHeader(contents.length);
|
||||||
|
packer.writePayload(contents);
|
||||||
|
packer.flush();
|
||||||
|
}
|
||||||
|
case CLOSE_EXTERNAL_PROCESS -> {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,8 +26,10 @@ import org.gradle.api.NamedDomainObjectContainer;
|
|||||||
import org.gradle.api.Plugin;
|
import org.gradle.api.Plugin;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.Transformer;
|
import org.gradle.api.Transformer;
|
||||||
|
import org.gradle.api.file.ProjectLayout;
|
||||||
import org.gradle.api.file.SourceDirectorySet;
|
import org.gradle.api.file.SourceDirectorySet;
|
||||||
import org.gradle.api.provider.Provider;
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.provider.ProviderFactory;
|
||||||
import org.gradle.api.tasks.SourceSet;
|
import org.gradle.api.tasks.SourceSet;
|
||||||
import org.gradle.api.tasks.SourceSetContainer;
|
import org.gradle.api.tasks.SourceSetContainer;
|
||||||
import org.gradle.api.tasks.TaskProvider;
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
@@ -138,11 +140,13 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
configureBaseSpec(project, spec);
|
configureBaseSpec(project, spec);
|
||||||
spec.getOutputFormat().convention(OutputFormat.PCF.toString());
|
spec.getOutputFormat().convention(OutputFormat.PCF.toString());
|
||||||
var analyzeImportsTask = createTask(project, AnalyzeImportsTask.class, spec);
|
var analyzeImportsTask = createTask(project, AnalyzeImportsTask.class, spec);
|
||||||
|
var layout = project.getLayout();
|
||||||
|
var providers = project.getProviders();
|
||||||
analyzeImportsTask.configure(
|
analyzeImportsTask.configure(
|
||||||
task -> {
|
task -> {
|
||||||
task.getOutputFormat().set(spec.getOutputFormat());
|
task.getOutputFormat().set(spec.getOutputFormat());
|
||||||
task.getOutputFile().set(spec.getOutputFile());
|
task.getOutputFile().set(spec.getOutputFile());
|
||||||
configureModulesTask(project, task, spec, null);
|
configureModulesTask(layout, providers, task, spec, null, null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -465,8 +469,8 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private <T extends BasePklTask, S extends BasePklSpec> void configureBaseTask(
|
private <T extends BasePklTask, S extends BasePklSpec> void configureBaseTask(
|
||||||
Project project, T task, S spec) {
|
ProjectLayout layout, ProviderFactory providers, T task, S spec) {
|
||||||
task.getWorkingDir().set(project.getLayout().getProjectDirectory());
|
task.getWorkingDir().set(layout.getProjectDirectory());
|
||||||
task.getAllowedModules().set(spec.getAllowedModules());
|
task.getAllowedModules().set(spec.getAllowedModules());
|
||||||
task.getAllowedResources().set(spec.getAllowedResources());
|
task.getAllowedResources().set(spec.getAllowedResources());
|
||||||
task.getEnvironmentVariables().set(spec.getEnvironmentVariables());
|
task.getEnvironmentVariables().set(spec.getEnvironmentVariables());
|
||||||
@@ -482,15 +486,20 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
task.getHttpProxy().set(spec.getHttpProxy());
|
task.getHttpProxy().set(spec.getHttpProxy());
|
||||||
task.getHttpNoProxy().set(spec.getHttpNoProxy());
|
task.getHttpNoProxy().set(spec.getHttpNoProxy());
|
||||||
task.getHttpRewrites().set(spec.getHttpRewrites());
|
task.getHttpRewrites().set(spec.getHttpRewrites());
|
||||||
|
task.getExternalModuleReaders()
|
||||||
|
.set(providers.provider(() -> spec.getExternalModuleReaders().getAsMap()));
|
||||||
|
task.getExternalResourceReaders()
|
||||||
|
.set(providers.provider(() -> spec.getExternalResourceReaders().getAsMap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends ModulesTask, S extends ModulesSpec> void configureModulesTask(
|
private <T extends ModulesTask, S extends ModulesSpec> void configureModulesTask(
|
||||||
Project project,
|
ProjectLayout layout,
|
||||||
|
ProviderFactory providers,
|
||||||
T task,
|
T task,
|
||||||
S spec,
|
S spec,
|
||||||
@Nullable TaskProvider<AnalyzeImportsTask> analyzeImportsTask,
|
@Nullable TaskProvider<AnalyzeImportsTask> analyzeImportsTask,
|
||||||
@Nullable Transformer<List<?>, List<?>> mapSourceModules) {
|
@Nullable Transformer<List<?>, List<?>> mapSourceModules) {
|
||||||
configureBaseTask(project, task, spec);
|
configureBaseTask(layout, providers, task, spec);
|
||||||
if (mapSourceModules != null) {
|
if (mapSourceModules != null) {
|
||||||
task.getSourceModules().set(spec.getSourceModules().map(mapSourceModules));
|
task.getSourceModules().set(spec.getSourceModules().map(mapSourceModules));
|
||||||
} else {
|
} else {
|
||||||
@@ -513,21 +522,12 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends ModulesTask, S extends ModulesSpec> void configureModulesTask(
|
private TaskProvider<AnalyzeImportsTask> createGatherImportsTask(
|
||||||
Project project,
|
|
||||||
T task,
|
|
||||||
S spec,
|
|
||||||
@Nullable TaskProvider<AnalyzeImportsTask> analyzeImportsTask) {
|
|
||||||
configureModulesTask(project, task, spec, analyzeImportsTask, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TaskProvider<AnalyzeImportsTask> createAnalyzeImportsTask(
|
|
||||||
Project project, ModulesSpec spec) {
|
Project project, ModulesSpec spec) {
|
||||||
|
var layout = project.getLayout();
|
||||||
var outputFile =
|
var outputFile =
|
||||||
project
|
layout.getBuildDirectory().file("pkl-gradle/imports/" + spec.getName() + ".json");
|
||||||
.getLayout()
|
var providers = project.getProviders();
|
||||||
.getBuildDirectory()
|
|
||||||
.file("pkl-gradle/imports/" + spec.getName() + ".json");
|
|
||||||
return project
|
return project
|
||||||
.getTasks()
|
.getTasks()
|
||||||
.register(
|
.register(
|
||||||
@@ -535,7 +535,8 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
AnalyzeImportsTask.class,
|
AnalyzeImportsTask.class,
|
||||||
task -> {
|
task -> {
|
||||||
configureModulesTask(
|
configureModulesTask(
|
||||||
project,
|
layout,
|
||||||
|
providers,
|
||||||
task,
|
task,
|
||||||
spec,
|
spec,
|
||||||
null,
|
null,
|
||||||
@@ -550,7 +551,10 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
(it) ->
|
(it) ->
|
||||||
it.getScheme() == null || it.getScheme().equalsIgnoreCase("file"))
|
it.getScheme() == null || it.getScheme().equalsIgnoreCase("file"))
|
||||||
.toList());
|
.toList());
|
||||||
task.setDescription("Compute the set of imports declared by input modules");
|
task.setDescription(
|
||||||
|
"Compute the set of imports declared by input modules of "
|
||||||
|
+ spec.getName()
|
||||||
|
+ " Pkl operation");
|
||||||
task.setGroup("build");
|
task.setGroup("build");
|
||||||
task.getOutputFormat().set(OutputFormat.JSON.toString());
|
task.getOutputFormat().set(OutputFormat.JSON.toString());
|
||||||
task.getOutputFile().set(outputFile);
|
task.getOutputFile().set(outputFile);
|
||||||
@@ -570,20 +574,25 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
*/
|
*/
|
||||||
private <T extends ModulesTask> TaskProvider<T> createModulesTask(
|
private <T extends ModulesTask> TaskProvider<T> createModulesTask(
|
||||||
Project project, Class<T> taskClass, ModulesSpec spec) {
|
Project project, Class<T> taskClass, ModulesSpec spec) {
|
||||||
var analyzeImportsTask = createAnalyzeImportsTask(project, spec);
|
var gatherImportsTask = createGatherImportsTask(project, spec);
|
||||||
|
var layout = project.getLayout();
|
||||||
|
var providers = project.getProviders();
|
||||||
return project
|
return project
|
||||||
.getTasks()
|
.getTasks()
|
||||||
.register(
|
.register(
|
||||||
spec.getName(),
|
spec.getName(),
|
||||||
taskClass,
|
taskClass,
|
||||||
task -> configureModulesTask(project, task, spec, analyzeImportsTask));
|
task -> configureModulesTask(layout, providers, task, spec, gatherImportsTask, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends BasePklTask> TaskProvider<T> createTask(
|
private <T extends BasePklTask> TaskProvider<T> createTask(
|
||||||
Project project, Class<T> taskClass, BasePklSpec spec) {
|
Project project, Class<T> taskClass, BasePklSpec spec) {
|
||||||
|
var layout = project.getLayout();
|
||||||
|
var providers = project.getProviders();
|
||||||
return project
|
return project
|
||||||
.getTasks()
|
.getTasks()
|
||||||
.register(spec.getName(), taskClass, task -> configureBaseTask(project, task, spec));
|
.register(
|
||||||
|
spec.getName(), taskClass, task -> configureBaseTask(layout, providers, task, spec));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> Set<T> append(Set<? extends T> set1, T element) {
|
private <T> Set<T> append(Set<? extends T> set1, T element) {
|
||||||
|
|||||||
@@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,6 +17,7 @@ package org.pkl.gradle.spec;
|
|||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import org.gradle.api.NamedDomainObjectContainer;
|
||||||
import org.gradle.api.file.ConfigurableFileCollection;
|
import org.gradle.api.file.ConfigurableFileCollection;
|
||||||
import org.gradle.api.file.DirectoryProperty;
|
import org.gradle.api.file.DirectoryProperty;
|
||||||
import org.gradle.api.provider.ListProperty;
|
import org.gradle.api.provider.ListProperty;
|
||||||
@@ -59,4 +60,8 @@ public interface BasePklSpec {
|
|||||||
ListProperty<String> getHttpNoProxy();
|
ListProperty<String> getHttpNoProxy();
|
||||||
|
|
||||||
MapProperty<URI, URI> getHttpRewrites();
|
MapProperty<URI, URI> getHttpRewrites();
|
||||||
|
|
||||||
|
NamedDomainObjectContainer<ExternalReaderSpec> getExternalModuleReaders();
|
||||||
|
|
||||||
|
NamedDomainObjectContainer<ExternalReaderSpec> getExternalResourceReaders();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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.gradle.spec;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import org.gradle.api.Named;
|
||||||
|
import org.gradle.api.provider.ListProperty;
|
||||||
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.tasks.Input;
|
||||||
|
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings.ExternalReader;
|
||||||
|
|
||||||
|
public abstract class ExternalReaderSpec implements Named {
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ExternalReaderSpec(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Input
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract Property<String> getExecutable();
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract ListProperty<String> getArguments();
|
||||||
|
|
||||||
|
public ExternalReader toExternalReader() {
|
||||||
|
return new ExternalReader(getExecutable().get(), getArguments().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, ExternalReader> toExternalReaderMap(
|
||||||
|
Collection<? extends ExternalReaderSpec> externalReaderSpecs) {
|
||||||
|
return externalReaderSpecs.stream()
|
||||||
|
.collect(
|
||||||
|
Collectors.toMap(ExternalReaderSpec::getName, ExternalReaderSpec::toExternalReader));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.gradle.task;
|
package org.pkl.gradle.task;
|
||||||
|
|
||||||
|
import static org.pkl.gradle.utils.PluginUtils.mapAndGetOrNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import org.gradle.api.file.RegularFileProperty;
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.gradle.task;
|
package org.pkl.gradle.task;
|
||||||
|
|
||||||
|
import static org.pkl.gradle.spec.ExternalReaderSpec.toExternalReaderMap;
|
||||||
|
import static org.pkl.gradle.utils.PluginUtils.mapAndGetOrNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -22,8 +25,6 @@ import java.nio.file.Paths;
|
|||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -42,6 +43,7 @@ import org.gradle.api.tasks.Input;
|
|||||||
import org.gradle.api.tasks.InputFile;
|
import org.gradle.api.tasks.InputFile;
|
||||||
import org.gradle.api.tasks.InputFiles;
|
import org.gradle.api.tasks.InputFiles;
|
||||||
import org.gradle.api.tasks.Internal;
|
import org.gradle.api.tasks.Internal;
|
||||||
|
import org.gradle.api.tasks.Nested;
|
||||||
import org.gradle.api.tasks.Optional;
|
import org.gradle.api.tasks.Optional;
|
||||||
import org.gradle.api.tasks.PathSensitive;
|
import org.gradle.api.tasks.PathSensitive;
|
||||||
import org.gradle.api.tasks.PathSensitivity;
|
import org.gradle.api.tasks.PathSensitivity;
|
||||||
@@ -50,6 +52,7 @@ import org.jspecify.annotations.Nullable;
|
|||||||
import org.pkl.commons.cli.CliBaseOptions;
|
import org.pkl.commons.cli.CliBaseOptions;
|
||||||
import org.pkl.core.Pair;
|
import org.pkl.core.Pair;
|
||||||
import org.pkl.core.evaluatorSettings.Color;
|
import org.pkl.core.evaluatorSettings.Color;
|
||||||
|
import org.pkl.gradle.spec.ExternalReaderSpec;
|
||||||
import org.pkl.gradle.utils.PluginUtils;
|
import org.pkl.gradle.utils.PluginUtils;
|
||||||
|
|
||||||
@CacheableTask
|
@CacheableTask
|
||||||
@@ -170,6 +173,12 @@ public abstract class BasePklTask extends DefaultTask {
|
|||||||
@Optional
|
@Optional
|
||||||
public abstract Property<Boolean> getPowerAssertions();
|
public abstract Property<Boolean> getPowerAssertions();
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
public abstract MapProperty<String, ExternalReaderSpec> getExternalModuleReaders();
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
public abstract MapProperty<String, ExternalReaderSpec> getExternalResourceReaders();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There are issues with using native libraries in Gradle plugins. As a workaround for now, make
|
* There are issues with using native libraries in Gradle plugins. As a workaround for now, make
|
||||||
* Truffle use an un-optimized runtime.
|
* Truffle use an un-optimized runtime.
|
||||||
@@ -224,8 +233,8 @@ public abstract class BasePklTask extends DefaultTask {
|
|||||||
getHttpNoProxy().getOrElse(List.of()),
|
getHttpNoProxy().getOrElse(List.of()),
|
||||||
getHttpRewrites().getOrNull(),
|
getHttpRewrites().getOrNull(),
|
||||||
getHttpHeaders().getOrNull(),
|
getHttpHeaders().getOrNull(),
|
||||||
Map.of(),
|
toExternalReaderMap(getExternalModuleReaders().get().values()),
|
||||||
Map.of(),
|
toExternalReaderMap(getExternalResourceReaders().get().values()),
|
||||||
null,
|
null,
|
||||||
getPowerAssertions().getOrElse(false));
|
getPowerAssertions().getOrElse(false));
|
||||||
}
|
}
|
||||||
@@ -248,16 +257,4 @@ public abstract class BasePklTask extends DefaultTask {
|
|||||||
protected List<Pattern> patternsFromStrings(List<String> patterns) {
|
protected List<Pattern> patternsFromStrings(List<String> patterns) {
|
||||||
return patterns.stream().map(Pattern::compile).collect(Collectors.toList());
|
return patterns.stream().map(Pattern::compile).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Equivalent to {@code provider.map(it -> f.apply(it)).getOrNull()}.
|
|
||||||
*
|
|
||||||
* <p>This function is necessary because in some cases doing {@code
|
|
||||||
* someProvider.map(...).getOrNull()} may trigger validation errors inside Gradle, when {@code
|
|
||||||
* someProvider} is derived from a property.
|
|
||||||
*/
|
|
||||||
protected <T, U> @Nullable U mapAndGetOrNull(Provider<T> provider, Function<T, U> f) {
|
|
||||||
@Nullable T value = provider.getOrNull();
|
|
||||||
return value == null ? null : f.apply(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.gradle.task;
|
package org.pkl.gradle.task;
|
||||||
|
|
||||||
|
import static org.pkl.gradle.utils.PluginUtils.mapAndGetOrNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|||||||
@@ -15,13 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.gradle.task;
|
package org.pkl.gradle.task;
|
||||||
|
|
||||||
|
import static org.pkl.gradle.spec.ExternalReaderSpec.toExternalReaderMap;
|
||||||
|
import static org.pkl.gradle.utils.PluginUtils.mapAndGetOrNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.gradle.api.InvalidUserDataException;
|
import org.gradle.api.InvalidUserDataException;
|
||||||
import org.gradle.api.file.DirectoryProperty;
|
import org.gradle.api.file.DirectoryProperty;
|
||||||
@@ -165,8 +167,8 @@ public abstract class ModulesTask extends BasePklTask {
|
|||||||
List.of(),
|
List.of(),
|
||||||
getHttpRewrites().getOrNull(),
|
getHttpRewrites().getOrNull(),
|
||||||
getHttpHeaders().getOrNull(),
|
getHttpHeaders().getOrNull(),
|
||||||
Map.of(),
|
toExternalReaderMap(getExternalModuleReaders().get().values()),
|
||||||
Map.of(),
|
toExternalReaderMap(getExternalResourceReaders().get().values()),
|
||||||
null,
|
null,
|
||||||
getPowerAssertions().getOrElse(false));
|
getPowerAssertions().getOrElse(false));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.gradle.task;
|
package org.pkl.gradle.task;
|
||||||
|
|
||||||
|
import static org.pkl.gradle.utils.PluginUtils.mapAndGetOrNull;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.pkl.gradle.task;
|
package org.pkl.gradle.task;
|
||||||
|
|
||||||
|
import static org.pkl.gradle.utils.PluginUtils.mapAndGetOrNull;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import org.gradle.api.file.DirectoryProperty;
|
import org.gradle.api.file.DirectoryProperty;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
|
|||||||
@@ -25,13 +25,16 @@ import java.nio.file.Path;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
import org.gradle.api.InvalidUserDataException;
|
import org.gradle.api.InvalidUserDataException;
|
||||||
import org.gradle.api.file.FileSystemLocation;
|
import org.gradle.api.file.FileSystemLocation;
|
||||||
import org.gradle.api.file.RegularFile;
|
import org.gradle.api.file.RegularFile;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.pkl.core.ImportGraph;
|
import org.pkl.core.ImportGraph;
|
||||||
import org.pkl.core.util.IoUtils;
|
import org.pkl.core.util.IoUtils;
|
||||||
|
|
||||||
public class PluginUtils {
|
public final class PluginUtils {
|
||||||
private PluginUtils() {}
|
private PluginUtils() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,4 +163,16 @@ public class PluginUtils {
|
|||||||
"Failed to parse transitive imports from " + outputFile.getAsFile(), e);
|
"Failed to parse transitive imports from " + outputFile.getAsFile(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to {@code provider.map(it -> f.apply(it)).getOrNull()}.
|
||||||
|
*
|
||||||
|
* <p>This function is necessary because in some cases doing {@code
|
||||||
|
* someProvider.map(...).getOrNull()} may trigger validation errors inside Gradle, when {@code
|
||||||
|
* someProvider} is derived from a property.
|
||||||
|
*/
|
||||||
|
public static <T, U> @Nullable U mapAndGetOrNull(Provider<T> provider, Function<T, U> f) {
|
||||||
|
@Nullable T value = provider.getOrNull();
|
||||||
|
return value == null ? null : f.apply(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,356 @@
|
|||||||
|
/*
|
||||||
|
* 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.gradle
|
||||||
|
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.condition.DisabledIf
|
||||||
|
|
||||||
|
class ExternalReadersTest : AbstractTest() {
|
||||||
|
companion object {
|
||||||
|
// Adjust paths on Windows to prevent unexpected character escapes.
|
||||||
|
private fun getPathSafeSystemProperty(name: String): String? =
|
||||||
|
System.getProperty(name)?.replace('\\', '/')
|
||||||
|
|
||||||
|
private val externalReaderJar: String? by lazy {
|
||||||
|
getPathSafeSystemProperty("pklGradle.externalReaderJar")
|
||||||
|
}
|
||||||
|
|
||||||
|
private val javaExecutable: String? by lazy {
|
||||||
|
getPathSafeSystemProperty("pklGradle.javaExecutable")
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun systemPropertiesAreNotSet(): Boolean {
|
||||||
|
return externalReaderJar == null || javaExecutable == null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `external module readers DSL is accepted`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalModuleReaders =
|
||||||
|
"""
|
||||||
|
externalModuleReaders {
|
||||||
|
myscheme {
|
||||||
|
executable = "/nonexistent/my-reader"
|
||||||
|
arguments = ["--arg1", "--arg2"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
writePklFile()
|
||||||
|
runTask("evalTest")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `external resource readers DSL is accepted`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalResourceReaders =
|
||||||
|
"""
|
||||||
|
externalResourceReaders {
|
||||||
|
myscheme {
|
||||||
|
executable = "/nonexistent/my-resource-reader"
|
||||||
|
arguments = ["--resource"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
writePklFile()
|
||||||
|
runTask("evalTest")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `multiple external readers can be configured`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalModuleReaders =
|
||||||
|
"""
|
||||||
|
externalModuleReaders {
|
||||||
|
scheme1 {
|
||||||
|
executable = "/nonexistent/reader1"
|
||||||
|
arguments = ["--mod"]
|
||||||
|
}
|
||||||
|
scheme2 {
|
||||||
|
executable = "/nonexistent/reader2"
|
||||||
|
arguments = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
externalResourceReaders =
|
||||||
|
"""
|
||||||
|
externalResourceReaders {
|
||||||
|
scheme3 {
|
||||||
|
executable = "/nonexistent/reader3"
|
||||||
|
arguments = ["--res", "--verbose"]
|
||||||
|
}
|
||||||
|
scheme4 {
|
||||||
|
executable = "/nonexistent/reader4"
|
||||||
|
arguments = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
writePklFile()
|
||||||
|
runTask("evalTest")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `external module reader with invalid executable produces error`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalModuleReaders =
|
||||||
|
"""
|
||||||
|
externalModuleReaders {
|
||||||
|
myscheme {
|
||||||
|
executable = "/nonexistent/my-reader"
|
||||||
|
arguments = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
additionalContents =
|
||||||
|
"""
|
||||||
|
allowedModules = ["repl:", "file:", "modulepath:", "https:", "pkl:", "package:", "projectpackage:", "myscheme:"]
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
writePklFile(
|
||||||
|
"""
|
||||||
|
import "myscheme:/something"
|
||||||
|
result = 1
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
val result = runTask("evalTest", expectFailure = true)
|
||||||
|
assertThat(result.output).contains("/nonexistent/my-reader")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `external resource reader with invalid executable produces error`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalResourceReaders =
|
||||||
|
"""
|
||||||
|
externalResourceReaders {
|
||||||
|
myscheme {
|
||||||
|
executable = "/nonexistent/my-resource-reader"
|
||||||
|
arguments = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
additionalContents =
|
||||||
|
"""
|
||||||
|
allowedResources = ["env:", "prop:", "file:", "modulepath:", "https:", "package:", "myscheme:"]
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
writePklFile(
|
||||||
|
"""
|
||||||
|
result = read("myscheme:/something")
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
val result = runTask("evalTest", expectFailure = true)
|
||||||
|
assertThat(result.output).contains("/nonexistent/my-resource-reader")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `external module reader scheme must be in allowedModules`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalModuleReaders =
|
||||||
|
"""
|
||||||
|
externalModuleReaders {
|
||||||
|
myscheme {
|
||||||
|
executable = "/nonexistent/my-reader"
|
||||||
|
arguments = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
writePklFile(
|
||||||
|
"""
|
||||||
|
import "myscheme:/something"
|
||||||
|
result = 1
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
val result = runTask("evalTest", expectFailure = true)
|
||||||
|
assertThat(result.output).containsAnyOf("myscheme:/something", "/nonexistent/my-reader")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `external resource reader scheme must be in allowedResources`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalResourceReaders =
|
||||||
|
"""
|
||||||
|
externalResourceReaders {
|
||||||
|
myscheme {
|
||||||
|
executable = "/nonexistent/my-resource-reader"
|
||||||
|
arguments = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
writePklFile(
|
||||||
|
"""
|
||||||
|
result = read("myscheme:/something")
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
val result = runTask("evalTest", expectFailure = true)
|
||||||
|
assertThat(result.output).contains("myscheme:/something")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisabledIf("systemPropertiesAreNotSet")
|
||||||
|
fun `external resource reader reads and uppercases content`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalResourceReaders =
|
||||||
|
"""
|
||||||
|
externalResourceReaders {
|
||||||
|
upper {
|
||||||
|
executable = "$javaExecutable"
|
||||||
|
arguments = ["-jar", "$externalReaderJar"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
additionalContents =
|
||||||
|
"""
|
||||||
|
allowedResources = ["env:", "prop:", "file:", "modulepath:", "https:", "package:", "upper:"]
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
writePklFile(
|
||||||
|
"""
|
||||||
|
result = read("upper:hello-world").text
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
runTask("evalTest")
|
||||||
|
val outputFile = testProjectDir.resolve("test.pcf")
|
||||||
|
checkFileContents(outputFile, """result = "HELLO-WORLD"""")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisabledIf("systemPropertiesAreNotSet")
|
||||||
|
fun `external resource reader handles path-like URI`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalResourceReaders =
|
||||||
|
"""
|
||||||
|
externalResourceReaders {
|
||||||
|
upper {
|
||||||
|
executable = "$javaExecutable"
|
||||||
|
arguments = ["-jar", "$externalReaderJar"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
additionalContents =
|
||||||
|
"""
|
||||||
|
allowedResources = ["env:", "prop:", "file:", "modulepath:", "https:", "package:", "upper:"]
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
writePklFile(
|
||||||
|
"""
|
||||||
|
result = read("upper:/some/path").text
|
||||||
|
"""
|
||||||
|
.trimIndent()
|
||||||
|
)
|
||||||
|
runTask("evalTest")
|
||||||
|
val outputFile = testProjectDir.resolve("test.pcf")
|
||||||
|
checkFileContents(outputFile, """result = "/SOME/PATH"""")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `external readers are configuration cache compatible`() {
|
||||||
|
writeBuildFile(
|
||||||
|
externalModuleReaders =
|
||||||
|
"""
|
||||||
|
externalModuleReaders {
|
||||||
|
myscheme {
|
||||||
|
executable = "/nonexistent/my-reader"
|
||||||
|
arguments = ["--arg1"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
externalResourceReaders =
|
||||||
|
"""
|
||||||
|
externalResourceReaders {
|
||||||
|
myresscheme {
|
||||||
|
executable = "/nonexistent/my-resource-reader"
|
||||||
|
arguments = ["--res"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
writePklFile()
|
||||||
|
|
||||||
|
val (firstRun, secondRun) = runTaskWithConfigurationCache("evalTest")
|
||||||
|
|
||||||
|
assertThat(firstRun.output).contains(CONFIG_CACHE_STORED)
|
||||||
|
assertThat(secondRun.output).contains(CONFIG_CACHE_REUSED)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeBuildFile(
|
||||||
|
outputFormat: String = "pcf",
|
||||||
|
externalModuleReaders: String = "",
|
||||||
|
externalResourceReaders: String = "",
|
||||||
|
additionalContents: String = "",
|
||||||
|
) {
|
||||||
|
writeFile(
|
||||||
|
"build.gradle",
|
||||||
|
"""
|
||||||
|
plugins {
|
||||||
|
id "org.pkl-lang"
|
||||||
|
}
|
||||||
|
|
||||||
|
pkl {
|
||||||
|
evaluators {
|
||||||
|
evalTest {
|
||||||
|
sourceModules = ["test.pkl"]
|
||||||
|
outputFormat = "$outputFormat"
|
||||||
|
settingsModule = "pkl:settings"
|
||||||
|
$additionalContents
|
||||||
|
$externalModuleReaders
|
||||||
|
$externalResourceReaders
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writePklFile(
|
||||||
|
contents: String =
|
||||||
|
"""
|
||||||
|
person {
|
||||||
|
name = "Pigeon"
|
||||||
|
age = 20 + 10
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
) {
|
||||||
|
writeFile("test.pkl", contents)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user