Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make EvalTask track resolved output paths #403

Merged
merged 11 commits into from
Jul 26, 2024
7 changes: 4 additions & 3 deletions pkl-cli/src/main/kotlin/org/pkl/cli/CliEvaluator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ constructor(
private val consoleWriter: Writer = System.out.writer(),
) : CliCommand(options.base) {
/**
* Output files for the modules to be evaluated. Returns `null` if `options.outputPath` is `null`.
* Multiple modules may be mapped to the same output file, in which case their outputs are
* concatenated with [CliEvaluatorOptions.moduleOutputSeparator].
* Output files for the modules to be evaluated. Returns `null` if `options.outputPath` is `null`
* or if `options.multipleFileOutputPath` is not `null`. Multiple modules may be mapped to the
* same output file, in which case their outputs are concatenated with
* [CliEvaluatorOptions.moduleOutputSeparator].
*/
@Suppress("MemberVisibilityCanBePrivate")
val outputFiles: Set<File>? by lazy {
Expand Down
10 changes: 10 additions & 0 deletions pkl-gradle/src/main/java/org/pkl/gradle/task/BasePklTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.gradle.api.DefaultTask;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileSystemLocation;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
Expand Down Expand Up @@ -142,6 +145,7 @@ public void runTask() {

@LateInit protected CliBaseOptions cachedOptions;

// Must be called during task execution time only.
@Internal
protected CliBaseOptions getCliBaseOptions() {
if (cachedOptions == null) {
Expand Down Expand Up @@ -176,6 +180,12 @@ protected List<URI> getSourceModulesAsUris() {
return Collections.emptyList();
}

@Inject
protected abstract ObjectFactory getObjects();

@Inject
protected abstract ProviderFactory getProviders();

protected List<Path> parseModulePath() {
return getModulePath().getFiles().stream().map(File::toPath).collect(Collectors.toList());
}
Expand Down
72 changes: 52 additions & 20 deletions pkl-gradle/src/main/java/org/pkl/gradle/task/EvalTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,50 +16,82 @@
package org.pkl.gradle.task;

import java.io.File;
import java.util.Collections;
import java.util.Set;
import javax.annotation.Nullable;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.OutputDirectories;
import org.gradle.api.tasks.OutputFiles;
import org.pkl.cli.CliEvaluator;
import org.pkl.cli.CliEvaluatorOptions;

public abstract class EvalTask extends ModulesTask {
@OutputFile
@Optional

// not tracked because it might contain placeholders
// required
@Internal
public abstract RegularFileProperty getOutputFile();

// not tracked because it might contain placeholders
// optional
@Internal
bioball marked this conversation as resolved.
Show resolved Hide resolved
public abstract DirectoryProperty getMultipleFileOutputDir();

@Input
@Optional
public abstract Property<String> getOutputFormat();

@Input
@Optional
public abstract Property<String> getModuleOutputSeparator();

@OutputDirectory
@Input
public abstract Property<String> getExpression();

private final Provider<CliEvaluator> cliEvaluator =
getProviders()
.provider(
() ->
new CliEvaluator(
new CliEvaluatorOptions(
getCliBaseOptions(),
getOutputFile().get().getAsFile().getAbsolutePath(),
getOutputFormat().get(),
getModuleOutputSeparator().get(),
mapAndGetOrNull(
getMultipleFileOutputDir(), it -> it.getAsFile().getAbsolutePath()),
getExpression().get())));

@SuppressWarnings("unused")
@OutputFiles
@Optional
public abstract DirectoryProperty getMultipleFileOutputDir();
public FileCollection getEffectiveOutputFiles() {
return getObjects()
.fileCollection()
.from(cliEvaluator.map(e -> nullToEmpty(e.getOutputFiles())));
}

@Input
@OutputDirectories
@Optional
public abstract Property<String> getExpression();
public FileCollection getEffectiveOutputDirs() {
return getObjects()
.fileCollection()
.from(cliEvaluator.map(e -> nullToEmpty(e.getOutputDirectories())));
}

private static <T> Set<T> nullToEmpty(@Nullable Set<T> set) {
return set == null ? Collections.emptySet() : set;
}

@Override
protected void doRunTask() {
//noinspection ResultOfMethodCallIgnored
getOutputs().getPreviousOutputFiles().forEach(File::delete);

new CliEvaluator(
new CliEvaluatorOptions(
getCliBaseOptions(),
getOutputFile().get().getAsFile().getAbsolutePath(),
getOutputFormat().get(),
getModuleOutputSeparator().get(),
mapAndGetOrNull(getMultipleFileOutputDir(), it -> it.getAsFile().getAbsolutePath()),
getExpression().get()))
.run();
cliEvaluator.get().run();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,15 @@ private Pair<List<File>, List<URI>> splitFilesAndUris(List<Object> modules) {
}

/**
* Converts either a file or a URI to a URI. We convert a file to a URI via the {@link
* Converts either a file or a URI to a URI. We convert a relative file to a URI via the {@link
* IoUtils#createUri(String)} because other ways of conversion can make relative paths into
* absolute URIs, which may break module loading.
*/
private URI parsedModuleNotationToUri(Object notation) {
if (notation instanceof File file) {
if (file.isAbsolute()) {
return file.toPath().toUri();
}
return IoUtils.createUri(IoUtils.toNormalizedPathString(file.toPath()));
} else if (notation instanceof URI uri) {
return uri;
Expand Down
Loading