mirror of
https://github.com/apple/pkl.git
synced 2026-07-06 13:05:11 +02:00
Add color to error formatting (#746)
* Add color to error formatting * Apply suggestions from code review Co-authored-by: Daniel Chao <daniel.h.chao@gmail.com> * Address reviewer comments * Apply suggestions from code review Co-authored-by: Daniel Chao <daniel.h.chao@gmail.com> * Define style choices as operations on formatter (abandon semantic API) * Adjust margin styling * Review feedback * Documentation nits --------- Co-authored-by: Daniel Chao <daniel.h.chao@gmail.com>
This commit is contained in:
committed by
GitHub
parent
e217cfcd6f
commit
03462fefae
@@ -50,7 +50,8 @@ public class ListSort {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
IoUtils.getCurrentWorkingDir(),
|
IoUtils.getCurrentWorkingDir(),
|
||||||
StackFrameTransformers.defaultTransformer);
|
StackFrameTransformers.defaultTransformer,
|
||||||
|
false);
|
||||||
private static final List<Object> list = new ArrayList<>(100000);
|
private static final List<Object> list = new ArrayList<>(100000);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|||||||
@@ -19,6 +19,19 @@ Patterns are matched against the beginning of resource URIs.
|
|||||||
At least one pattern needs to match for a resource to be readable.
|
At least one pattern needs to match for a resource to be readable.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
[[color]]
|
||||||
|
.--color
|
||||||
|
[%collapsible]
|
||||||
|
====
|
||||||
|
Default: `auto` +
|
||||||
|
When to format messages with ANSI color codes.
|
||||||
|
Possible values:
|
||||||
|
|
||||||
|
- `"never"`: Never format
|
||||||
|
- `"auto"`: Format if `stdin`, `stdout`, or `stderr` are connected to a console.
|
||||||
|
- `"always"`: Always format
|
||||||
|
====
|
||||||
|
|
||||||
[[cache-dir]]
|
[[cache-dir]]
|
||||||
.--cache-dir
|
.--cache-dir
|
||||||
[%collapsible]
|
[%collapsible]
|
||||||
|
|||||||
@@ -67,6 +67,13 @@ The cache directory for storing packages.
|
|||||||
If `null`, defaults to `~/.pkl/cache`.
|
If `null`, defaults to `~/.pkl/cache`.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
.color: Property<Boolean>
|
||||||
|
[%collapsible]
|
||||||
|
====
|
||||||
|
Default: `false` +
|
||||||
|
Format messages using ANSI color.
|
||||||
|
====
|
||||||
|
|
||||||
.noCache: Property<Boolean>
|
.noCache: Property<Boolean>
|
||||||
[%collapsible]
|
[%collapsible]
|
||||||
====
|
====
|
||||||
|
|||||||
@@ -96,7 +96,8 @@ class DocSnippetTestsEngine : HierarchicalTestEngine<DocSnippetTestsEngine.Execu
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
IoUtils.getCurrentWorkingDir(),
|
IoUtils.getCurrentWorkingDir(),
|
||||||
StackFrameTransformers.defaultTransformer
|
StackFrameTransformers.defaultTransformer,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
return ExecutionContext(replServer)
|
return ExecutionContext(replServer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ constructor(
|
|||||||
try {
|
try {
|
||||||
moduleResolver.resolve(uri)
|
moduleResolver.resolve(uri)
|
||||||
} catch (e: VmException) {
|
} catch (e: VmException) {
|
||||||
throw e.toPklException(stackFrameTransformer)
|
throw e.toPklException(stackFrameTransformer, options.base.color?.hasColor() ?: false)
|
||||||
}
|
}
|
||||||
val substituted =
|
val substituted =
|
||||||
pathStr
|
pathStr
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ class CliProjectPackager(
|
|||||||
cliOptions.normalizedWorkingDir,
|
cliOptions.normalizedWorkingDir,
|
||||||
outputPath,
|
outputPath,
|
||||||
stackFrameTransformer,
|
stackFrameTransformer,
|
||||||
|
cliOptions.color?.hasColor() ?: false,
|
||||||
securityManager,
|
securityManager,
|
||||||
httpClient,
|
httpClient,
|
||||||
skipPublishCheck,
|
skipPublishCheck,
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ internal class CliRepl(private val options: CliEvaluatorOptions) : CliCommand(op
|
|||||||
project?.dependencies,
|
project?.dependencies,
|
||||||
options.outputFormat,
|
options.outputFormat,
|
||||||
options.base.normalizedWorkingDir,
|
options.base.normalizedWorkingDir,
|
||||||
stackFrameTransformer
|
stackFrameTransformer,
|
||||||
|
options.base.color?.hasColor() ?: false,
|
||||||
)
|
)
|
||||||
Repl(options.base.normalizedWorkingDir, server).run()
|
Repl(options.base.normalizedWorkingDir, server).run()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ class ReplMessagesTest {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
"/".toPath(),
|
"/".toPath(),
|
||||||
StackFrameTransformers.defaultTransformer
|
StackFrameTransformers.defaultTransformer,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.nio.file.Files
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
import org.pkl.core.evaluatorSettings.Color
|
||||||
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings.ExternalReader
|
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings.ExternalReader
|
||||||
import org.pkl.core.module.ProjectDependenciesManager
|
import org.pkl.core.module.ProjectDependenciesManager
|
||||||
import org.pkl.core.util.IoUtils
|
import org.pkl.core.util.IoUtils
|
||||||
@@ -101,6 +102,9 @@ data class CliBaseOptions(
|
|||||||
/** The cache directory for storing packages. */
|
/** The cache directory for storing packages. */
|
||||||
private val moduleCacheDir: Path? = null,
|
private val moduleCacheDir: Path? = null,
|
||||||
|
|
||||||
|
/** Whether to render errors in ANSI color. */
|
||||||
|
val color: Color? = null,
|
||||||
|
|
||||||
/** Whether to disable the module cache. */
|
/** Whether to disable the module cache. */
|
||||||
val noCache: Boolean = false,
|
val noCache: Boolean = false,
|
||||||
|
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ abstract class CliCommand(protected val cliOptions: CliBaseOptions) {
|
|||||||
.setEnvironmentVariables(environmentVariables)
|
.setEnvironmentVariables(environmentVariables)
|
||||||
.addModuleKeyFactories(moduleKeyFactories(modulePathResolver))
|
.addModuleKeyFactories(moduleKeyFactories(modulePathResolver))
|
||||||
.addResourceReaders(resourceReaders(modulePathResolver))
|
.addResourceReaders(resourceReaders(modulePathResolver))
|
||||||
|
.setColor(cliOptions.color?.hasColor() ?: false)
|
||||||
.setLogger(Loggers.stdErr())
|
.setLogger(Loggers.stdErr())
|
||||||
.setTimeout(cliOptions.timeout)
|
.setTimeout(cliOptions.timeout)
|
||||||
.setModuleCacheDir(moduleCacheDir)
|
.setModuleCacheDir(moduleCacheDir)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package org.pkl.commons.cli.commands
|
|||||||
|
|
||||||
import com.github.ajalt.clikt.parameters.groups.OptionGroup
|
import com.github.ajalt.clikt.parameters.groups.OptionGroup
|
||||||
import com.github.ajalt.clikt.parameters.options.*
|
import com.github.ajalt.clikt.parameters.options.*
|
||||||
|
import com.github.ajalt.clikt.parameters.types.enum
|
||||||
import com.github.ajalt.clikt.parameters.types.int
|
import com.github.ajalt.clikt.parameters.types.int
|
||||||
import com.github.ajalt.clikt.parameters.types.long
|
import com.github.ajalt.clikt.parameters.types.long
|
||||||
import com.github.ajalt.clikt.parameters.types.path
|
import com.github.ajalt.clikt.parameters.types.path
|
||||||
@@ -29,6 +30,7 @@ import java.util.regex.Pattern
|
|||||||
import org.pkl.commons.cli.CliBaseOptions
|
import org.pkl.commons.cli.CliBaseOptions
|
||||||
import org.pkl.commons.cli.CliException
|
import org.pkl.commons.cli.CliException
|
||||||
import org.pkl.commons.shlex
|
import org.pkl.commons.shlex
|
||||||
|
import org.pkl.core.evaluatorSettings.Color
|
||||||
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings.ExternalReader
|
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings.ExternalReader
|
||||||
import org.pkl.core.runtime.VmUtils
|
import org.pkl.core.runtime.VmUtils
|
||||||
import org.pkl.core.util.IoUtils
|
import org.pkl.core.util.IoUtils
|
||||||
@@ -141,6 +143,17 @@ class BaseOptions : OptionGroup() {
|
|||||||
)
|
)
|
||||||
.associateProps()
|
.associateProps()
|
||||||
|
|
||||||
|
val color: Color by
|
||||||
|
option(
|
||||||
|
names = arrayOf("--color"),
|
||||||
|
metavar = "<when>",
|
||||||
|
help =
|
||||||
|
"Whether to format messages in ANSI color. Possible values of <when> are 'never', 'auto', and 'always'."
|
||||||
|
)
|
||||||
|
.enum<Color> { it.name.lowercase() }
|
||||||
|
.single()
|
||||||
|
.default(Color.AUTO)
|
||||||
|
|
||||||
val noCache: Boolean by
|
val noCache: Boolean by
|
||||||
option(names = arrayOf("--no-cache"), help = "Disable caching of packages")
|
option(names = arrayOf("--no-cache"), help = "Disable caching of packages")
|
||||||
.single()
|
.single()
|
||||||
@@ -265,6 +278,7 @@ class BaseOptions : OptionGroup() {
|
|||||||
projectDir = projectOptions?.projectDir,
|
projectDir = projectOptions?.projectDir,
|
||||||
timeout = timeout,
|
timeout = timeout,
|
||||||
moduleCacheDir = cacheDir ?: defaults.normalizedModuleCacheDir,
|
moduleCacheDir = cacheDir ?: defaults.normalizedModuleCacheDir,
|
||||||
|
color = color,
|
||||||
noCache = noCache,
|
noCache = noCache,
|
||||||
testMode = testMode,
|
testMode = testMode,
|
||||||
testPort = testPort,
|
testPort = testPort,
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import org.pkl.core.util.Nullable;
|
|||||||
/** Utility library for static analysis of Pkl programs. */
|
/** Utility library for static analysis of Pkl programs. */
|
||||||
public class Analyzer {
|
public class Analyzer {
|
||||||
private final StackFrameTransformer transformer;
|
private final StackFrameTransformer transformer;
|
||||||
|
private final boolean color;
|
||||||
private final SecurityManager securityManager;
|
private final SecurityManager securityManager;
|
||||||
private final @Nullable Path moduleCacheDir;
|
private final @Nullable Path moduleCacheDir;
|
||||||
private final @Nullable DeclaredDependencies projectDependencies;
|
private final @Nullable DeclaredDependencies projectDependencies;
|
||||||
@@ -49,12 +50,14 @@ public class Analyzer {
|
|||||||
|
|
||||||
public Analyzer(
|
public Analyzer(
|
||||||
StackFrameTransformer transformer,
|
StackFrameTransformer transformer,
|
||||||
|
boolean color,
|
||||||
SecurityManager securityManager,
|
SecurityManager securityManager,
|
||||||
Collection<ModuleKeyFactory> moduleKeyFactories,
|
Collection<ModuleKeyFactory> moduleKeyFactories,
|
||||||
@Nullable Path moduleCacheDir,
|
@Nullable Path moduleCacheDir,
|
||||||
@Nullable DeclaredDependencies projectDependencies,
|
@Nullable DeclaredDependencies projectDependencies,
|
||||||
HttpClient httpClient) {
|
HttpClient httpClient) {
|
||||||
this.transformer = transformer;
|
this.transformer = transformer;
|
||||||
|
this.color = color;
|
||||||
this.securityManager = securityManager;
|
this.securityManager = securityManager;
|
||||||
this.moduleCacheDir = moduleCacheDir;
|
this.moduleCacheDir = moduleCacheDir;
|
||||||
this.projectDependencies = projectDependencies;
|
this.projectDependencies = projectDependencies;
|
||||||
@@ -82,7 +85,7 @@ public class Analyzer {
|
|||||||
} catch (PklException err) {
|
} catch (PklException err) {
|
||||||
throw err;
|
throw err;
|
||||||
} catch (VmException err) {
|
} catch (VmException err) {
|
||||||
throw err.toPklException(transformer);
|
throw err.toPklException(transformer, color);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new PklBugException(e);
|
throw new PklBugException(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ public final class EvaluatorBuilder {
|
|||||||
|
|
||||||
private @Nullable String outputFormat;
|
private @Nullable String outputFormat;
|
||||||
|
|
||||||
|
private boolean color = false;
|
||||||
|
|
||||||
private @Nullable StackFrameTransformer stackFrameTransformer;
|
private @Nullable StackFrameTransformer stackFrameTransformer;
|
||||||
|
|
||||||
private @Nullable DeclaredDependencies dependencies;
|
private @Nullable DeclaredDependencies dependencies;
|
||||||
@@ -144,6 +146,17 @@ public final class EvaluatorBuilder {
|
|||||||
return new EvaluatorBuilder();
|
return new EvaluatorBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sets the option to render errors in ANSI color. */
|
||||||
|
public EvaluatorBuilder setColor(boolean color) {
|
||||||
|
this.color = color;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the current setting of the option to render errors in ANSI color. */
|
||||||
|
public boolean getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
/** Sets the given stack frame transformer, replacing any previously set transformer. */
|
/** Sets the given stack frame transformer, replacing any previously set transformer. */
|
||||||
public EvaluatorBuilder setStackFrameTransformer(StackFrameTransformer stackFrameTransformer) {
|
public EvaluatorBuilder setStackFrameTransformer(StackFrameTransformer stackFrameTransformer) {
|
||||||
this.stackFrameTransformer = stackFrameTransformer;
|
this.stackFrameTransformer = stackFrameTransformer;
|
||||||
@@ -475,6 +488,9 @@ public final class EvaluatorBuilder {
|
|||||||
if (settings.rootDir() != null) {
|
if (settings.rootDir() != null) {
|
||||||
setRootDir(settings.rootDir());
|
setRootDir(settings.rootDir());
|
||||||
}
|
}
|
||||||
|
if (settings.color() != null) {
|
||||||
|
setColor(settings.color().hasColor());
|
||||||
|
}
|
||||||
if (Boolean.TRUE.equals(settings.noCache())) {
|
if (Boolean.TRUE.equals(settings.noCache())) {
|
||||||
setModuleCacheDir(null);
|
setModuleCacheDir(null);
|
||||||
} else if (settings.moduleCacheDir() != null) {
|
} else if (settings.moduleCacheDir() != null) {
|
||||||
@@ -513,6 +529,7 @@ public final class EvaluatorBuilder {
|
|||||||
|
|
||||||
return new EvaluatorImpl(
|
return new EvaluatorImpl(
|
||||||
stackFrameTransformer,
|
stackFrameTransformer,
|
||||||
|
color,
|
||||||
securityManager,
|
securityManager,
|
||||||
httpClient,
|
httpClient,
|
||||||
new LoggerImpl(logger, stackFrameTransformer),
|
new LoggerImpl(logger, stackFrameTransformer),
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ import org.pkl.core.util.Nullable;
|
|||||||
|
|
||||||
public class EvaluatorImpl implements Evaluator {
|
public class EvaluatorImpl implements Evaluator {
|
||||||
protected final StackFrameTransformer frameTransformer;
|
protected final StackFrameTransformer frameTransformer;
|
||||||
|
protected final boolean color;
|
||||||
protected final ModuleResolver moduleResolver;
|
protected final ModuleResolver moduleResolver;
|
||||||
protected final Context polyglotContext;
|
protected final Context polyglotContext;
|
||||||
protected final @Nullable Duration timeout;
|
protected final @Nullable Duration timeout;
|
||||||
@@ -68,6 +69,7 @@ public class EvaluatorImpl implements Evaluator {
|
|||||||
|
|
||||||
public EvaluatorImpl(
|
public EvaluatorImpl(
|
||||||
StackFrameTransformer transformer,
|
StackFrameTransformer transformer,
|
||||||
|
boolean color,
|
||||||
SecurityManager manager,
|
SecurityManager manager,
|
||||||
HttpClient httpClient,
|
HttpClient httpClient,
|
||||||
Logger logger,
|
Logger logger,
|
||||||
@@ -82,6 +84,7 @@ public class EvaluatorImpl implements Evaluator {
|
|||||||
|
|
||||||
securityManager = manager;
|
securityManager = manager;
|
||||||
frameTransformer = transformer;
|
frameTransformer = transformer;
|
||||||
|
this.color = color;
|
||||||
moduleResolver = new ModuleResolver(factories);
|
moduleResolver = new ModuleResolver(factories);
|
||||||
this.logger = new BufferedLogger(logger);
|
this.logger = new BufferedLogger(logger);
|
||||||
packageResolver = PackageResolver.getInstance(securityManager, httpClient, moduleCacheDir);
|
packageResolver = PackageResolver.getInstance(securityManager, httpClient, moduleCacheDir);
|
||||||
@@ -304,20 +307,20 @@ public class EvaluatorImpl implements Evaluator {
|
|||||||
.bug("Stack overflow")
|
.bug("Stack overflow")
|
||||||
.withCause(e.getCause())
|
.withCause(e.getCause())
|
||||||
.build()
|
.build()
|
||||||
.toPklException(frameTransformer);
|
.toPklException(frameTransformer, color);
|
||||||
}
|
}
|
||||||
handleTimeout(timeoutTask);
|
handleTimeout(timeoutTask);
|
||||||
throw e.toPklException(frameTransformer);
|
throw e.toPklException(frameTransformer, color);
|
||||||
} catch (VmException e) {
|
} catch (VmException e) {
|
||||||
handleTimeout(timeoutTask);
|
handleTimeout(timeoutTask);
|
||||||
throw e.toPklException(frameTransformer);
|
throw e.toPklException(frameTransformer, color);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new PklBugException(e);
|
throw new PklBugException(e);
|
||||||
} catch (ExceptionInInitializerError e) {
|
} catch (ExceptionInInitializerError e) {
|
||||||
if (!(e.getCause() instanceof VmException vmException)) {
|
if (!(e.getCause() instanceof VmException vmException)) {
|
||||||
throw new PklBugException(e);
|
throw new PklBugException(e);
|
||||||
}
|
}
|
||||||
var pklException = vmException.toPklException(frameTransformer);
|
var pklException = vmException.toPklException(frameTransformer, color);
|
||||||
var error = new ExceptionInInitializerError(pklException);
|
var error = new ExceptionInInitializerError(pklException);
|
||||||
error.setStackTrace(e.getStackTrace());
|
error.setStackTrace(e.getStackTrace());
|
||||||
throw new PklBugException(error);
|
throw new PklBugException(error);
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.evaluatorSettings;
|
||||||
|
|
||||||
|
public enum Color {
|
||||||
|
NEVER,
|
||||||
|
AUTO,
|
||||||
|
ALWAYS;
|
||||||
|
|
||||||
|
public boolean hasColor() {
|
||||||
|
return switch (this) {
|
||||||
|
case AUTO -> System.console() != null;
|
||||||
|
case NEVER -> false;
|
||||||
|
case ALWAYS -> true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ public record PklEvaluatorSettings(
|
|||||||
@Nullable Map<String, String> env,
|
@Nullable Map<String, String> env,
|
||||||
@Nullable List<Pattern> allowedModules,
|
@Nullable List<Pattern> allowedModules,
|
||||||
@Nullable List<Pattern> allowedResources,
|
@Nullable List<Pattern> allowedResources,
|
||||||
|
@Nullable Color color,
|
||||||
@Nullable Boolean noCache,
|
@Nullable Boolean noCache,
|
||||||
@Nullable Path moduleCacheDir,
|
@Nullable Path moduleCacheDir,
|
||||||
@Nullable List<Path> modulePath,
|
@Nullable List<Path> modulePath,
|
||||||
@@ -102,11 +103,14 @@ public record PklEvaluatorSettings(
|
|||||||
Collectors.toMap(
|
Collectors.toMap(
|
||||||
Entry::getKey, entry -> ExternalReader.parse(entry.getValue())));
|
Entry::getKey, entry -> ExternalReader.parse(entry.getValue())));
|
||||||
|
|
||||||
|
var color = (String) pSettings.get("color");
|
||||||
|
|
||||||
return new PklEvaluatorSettings(
|
return new PklEvaluatorSettings(
|
||||||
(Map<String, String>) pSettings.get("externalProperties"),
|
(Map<String, String>) pSettings.get("externalProperties"),
|
||||||
(Map<String, String>) pSettings.get("env"),
|
(Map<String, String>) pSettings.get("env"),
|
||||||
allowedModules,
|
allowedModules,
|
||||||
allowedResources,
|
allowedResources,
|
||||||
|
color == null ? null : Color.valueOf(color.toUpperCase()),
|
||||||
(Boolean) pSettings.get("noCache"),
|
(Boolean) pSettings.get("noCache"),
|
||||||
moduleCacheDir,
|
moduleCacheDir,
|
||||||
modulePath,
|
modulePath,
|
||||||
@@ -198,6 +202,7 @@ public record PklEvaluatorSettings(
|
|||||||
&& Objects.equals(env, that.env)
|
&& Objects.equals(env, that.env)
|
||||||
&& arePatternsEqual(allowedModules, that.allowedModules)
|
&& arePatternsEqual(allowedModules, that.allowedModules)
|
||||||
&& arePatternsEqual(allowedResources, that.allowedResources)
|
&& arePatternsEqual(allowedResources, that.allowedResources)
|
||||||
|
&& Objects.equals(color, that.color)
|
||||||
&& Objects.equals(noCache, that.noCache)
|
&& Objects.equals(noCache, that.noCache)
|
||||||
&& Objects.equals(moduleCacheDir, that.moduleCacheDir)
|
&& Objects.equals(moduleCacheDir, that.moduleCacheDir)
|
||||||
&& Objects.equals(timeout, that.timeout)
|
&& Objects.equals(timeout, that.timeout)
|
||||||
@@ -219,7 +224,8 @@ public record PklEvaluatorSettings(
|
|||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
var result =
|
var result =
|
||||||
Objects.hash(externalProperties, env, noCache, moduleCacheDir, timeout, rootDir, http);
|
Objects.hash(
|
||||||
|
externalProperties, env, color, noCache, moduleCacheDir, timeout, rootDir, http);
|
||||||
result = 31 * result + hashPatterns(allowedModules);
|
result = 31 * result + hashPatterns(allowedModules);
|
||||||
result = 31 * result + hashPatterns(allowedResources);
|
result = 31 * result + hashPatterns(allowedResources);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ public final class Project {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
// stack frame transformer never used; this exception has no stack frames.
|
// stack frame transformer never used; this exception has no stack frames.
|
||||||
throw vmException.toPklException(StackFrameTransformers.defaultTransformer);
|
throw vmException.toPklException(StackFrameTransformers.defaultTransformer, false);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
@@ -192,6 +192,7 @@ public final class Project {
|
|||||||
var analyzer =
|
var analyzer =
|
||||||
new Analyzer(
|
new Analyzer(
|
||||||
StackFrameTransformers.defaultTransformer,
|
StackFrameTransformers.defaultTransformer,
|
||||||
|
builder.getColor(),
|
||||||
SecurityManagers.defaultManager,
|
SecurityManagers.defaultManager,
|
||||||
builder.getModuleKeyFactories(),
|
builder.getModuleKeyFactories(),
|
||||||
builder.getModuleCacheDir(),
|
builder.getModuleCacheDir(),
|
||||||
@@ -517,6 +518,7 @@ public final class Project {
|
|||||||
env,
|
env,
|
||||||
allowedModules,
|
allowedModules,
|
||||||
allowedResources,
|
allowedResources,
|
||||||
|
null,
|
||||||
noCache,
|
noCache,
|
||||||
moduleCacheDir,
|
moduleCacheDir,
|
||||||
modulePath,
|
modulePath,
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ public final class ProjectPackager {
|
|||||||
private final Path workingDir;
|
private final Path workingDir;
|
||||||
private final String outputPathPattern;
|
private final String outputPathPattern;
|
||||||
private final StackFrameTransformer stackFrameTransformer;
|
private final StackFrameTransformer stackFrameTransformer;
|
||||||
|
private final boolean color;
|
||||||
private final SecurityManager securityManager;
|
private final SecurityManager securityManager;
|
||||||
private final PackageResolver packageResolver;
|
private final PackageResolver packageResolver;
|
||||||
private final boolean skipPublishCheck;
|
private final boolean skipPublishCheck;
|
||||||
@@ -108,6 +109,7 @@ public final class ProjectPackager {
|
|||||||
Path workingDir,
|
Path workingDir,
|
||||||
String outputPathPattern,
|
String outputPathPattern,
|
||||||
StackFrameTransformer stackFrameTransformer,
|
StackFrameTransformer stackFrameTransformer,
|
||||||
|
boolean color,
|
||||||
SecurityManager securityManager,
|
SecurityManager securityManager,
|
||||||
HttpClient httpClient,
|
HttpClient httpClient,
|
||||||
boolean skipPublishCheck,
|
boolean skipPublishCheck,
|
||||||
@@ -116,6 +118,7 @@ public final class ProjectPackager {
|
|||||||
this.workingDir = workingDir;
|
this.workingDir = workingDir;
|
||||||
this.outputPathPattern = outputPathPattern;
|
this.outputPathPattern = outputPathPattern;
|
||||||
this.stackFrameTransformer = stackFrameTransformer;
|
this.stackFrameTransformer = stackFrameTransformer;
|
||||||
|
this.color = color;
|
||||||
this.securityManager = securityManager;
|
this.securityManager = securityManager;
|
||||||
// intentionally use InMemoryPackageResolver
|
// intentionally use InMemoryPackageResolver
|
||||||
this.packageResolver = PackageResolver.getInstance(securityManager, httpClient, null);
|
this.packageResolver = PackageResolver.getInstance(securityManager, httpClient, null);
|
||||||
@@ -409,14 +412,14 @@ public final class ProjectPackager {
|
|||||||
.evalError("invalidModuleUri", importStr)
|
.evalError("invalidModuleUri", importStr)
|
||||||
.withSourceSection(sourceSection)
|
.withSourceSection(sourceSection)
|
||||||
.build()
|
.build()
|
||||||
.toPklException(stackFrameTransformer);
|
.toPklException(stackFrameTransformer, color);
|
||||||
}
|
}
|
||||||
if (importStr.startsWith("/") && !project.getProjectDir().toString().equals("/")) {
|
if (importStr.startsWith("/") && !project.getProjectDir().toString().equals("/")) {
|
||||||
throw new VmExceptionBuilder()
|
throw new VmExceptionBuilder()
|
||||||
.evalError("invalidRelativeProjectImport", importStr)
|
.evalError("invalidRelativeProjectImport", importStr)
|
||||||
.withSourceSection(sourceSection)
|
.withSourceSection(sourceSection)
|
||||||
.build()
|
.build()
|
||||||
.toPklException(stackFrameTransformer);
|
.toPklException(stackFrameTransformer, color);
|
||||||
}
|
}
|
||||||
var currentPath = pklModulePath.getParent();
|
var currentPath = pklModulePath.getParent();
|
||||||
var importPath = Path.of(importUri.getPath());
|
var importPath = Path.of(importUri.getPath());
|
||||||
@@ -433,7 +436,7 @@ public final class ProjectPackager {
|
|||||||
.evalError("invalidRelativeProjectImport", importStr)
|
.evalError("invalidRelativeProjectImport", importStr)
|
||||||
.withSourceSection(sourceSection)
|
.withSourceSection(sourceSection)
|
||||||
.build()
|
.build()
|
||||||
.toPklException(stackFrameTransformer);
|
.toPklException(stackFrameTransformer, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,12 +78,13 @@ public class ReplServer implements AutoCloseable {
|
|||||||
@Nullable DeclaredDependencies projectDependencies,
|
@Nullable DeclaredDependencies projectDependencies,
|
||||||
@Nullable String outputFormat,
|
@Nullable String outputFormat,
|
||||||
Path workingDir,
|
Path workingDir,
|
||||||
StackFrameTransformer frameTransformer) {
|
StackFrameTransformer frameTransformer,
|
||||||
|
boolean color) {
|
||||||
|
|
||||||
this.workingDir = workingDir;
|
this.workingDir = workingDir;
|
||||||
this.securityManager = securityManager;
|
this.securityManager = securityManager;
|
||||||
this.moduleResolver = new ModuleResolver(moduleKeyFactories);
|
this.moduleResolver = new ModuleResolver(moduleKeyFactories);
|
||||||
this.errorRenderer = new VmExceptionRenderer(new StackTraceRenderer(frameTransformer));
|
this.errorRenderer = new VmExceptionRenderer(new StackTraceRenderer(frameTransformer), color);
|
||||||
replState = new ReplState(createEmptyReplModule(BaseModule.getModuleClass().getPrototype()));
|
replState = new ReplState(createEmptyReplModule(BaseModule.getModuleClass().getPrototype()));
|
||||||
|
|
||||||
var languageRef = new MutableReference<VmLanguage>(null);
|
var languageRef = new MutableReference<VmLanguage>(null);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.pkl.core.StackFrame;
|
import org.pkl.core.StackFrame;
|
||||||
|
import org.pkl.core.runtime.TextFormatter.Element;
|
||||||
import org.pkl.core.util.Nullable;
|
import org.pkl.core.util.Nullable;
|
||||||
|
|
||||||
public final class StackTraceRenderer {
|
public final class StackTraceRenderer {
|
||||||
@@ -28,66 +29,68 @@ public final class StackTraceRenderer {
|
|||||||
this.frameTransformer = frameTransformer;
|
this.frameTransformer = frameTransformer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(List<StackFrame> frames, @Nullable String hint, StringBuilder builder) {
|
public void render(List<StackFrame> frames, @Nullable String hint, TextFormatter out) {
|
||||||
var compressed = compressFrames(frames);
|
var compressed = compressFrames(frames);
|
||||||
doRender(compressed, hint, builder, "", true);
|
doRender(compressed, hint, out, "", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// non-private for testing
|
// non-private for testing
|
||||||
void doRender(
|
void doRender(
|
||||||
List<Object /*StackFrame|StackFrameLoop*/> frames,
|
List<Object /*StackFrame|StackFrameLoop*/> frames,
|
||||||
@Nullable String hint,
|
@Nullable String hint,
|
||||||
StringBuilder builder,
|
TextFormatter out,
|
||||||
String leftMargin,
|
String leftMargin,
|
||||||
boolean isFirstElement) {
|
boolean isFirstElement) {
|
||||||
for (var frame : frames) {
|
for (var frame : frames) {
|
||||||
if (frame instanceof StackFrameLoop loop) {
|
if (frame instanceof StackFrameLoop loop) {
|
||||||
// ensure a cycle of length 1 doesn't get rendered as a loop
|
// ensure a cycle of length 1 doesn't get rendered as a loop
|
||||||
if (loop.count == 1) {
|
if (loop.count == 1) {
|
||||||
doRender(loop.frames, null, builder, leftMargin, isFirstElement);
|
doRender(loop.frames, null, out, leftMargin, isFirstElement);
|
||||||
} else {
|
} else {
|
||||||
if (!isFirstElement) {
|
if (!isFirstElement) {
|
||||||
builder.append(leftMargin).append("\n");
|
out.margin(leftMargin).newline();
|
||||||
}
|
}
|
||||||
builder.append(leftMargin).append("┌─ ").append(loop.count).append(" repetitions of:\n");
|
out.margin(leftMargin)
|
||||||
|
.margin("┌─ ")
|
||||||
|
.style(Element.STACK_OVERFLOW_LOOP_COUNT)
|
||||||
|
.append(loop.count)
|
||||||
|
.style(Element.TEXT)
|
||||||
|
.append(" repetitions of:\n");
|
||||||
var newLeftMargin = leftMargin + "│ ";
|
var newLeftMargin = leftMargin + "│ ";
|
||||||
doRender(loop.frames, null, builder, newLeftMargin, isFirstElement);
|
doRender(loop.frames, null, out, newLeftMargin, isFirstElement);
|
||||||
if (isFirstElement) {
|
if (isFirstElement) {
|
||||||
renderHint(hint, builder, newLeftMargin);
|
renderHint(hint, out, newLeftMargin);
|
||||||
isFirstElement = false;
|
isFirstElement = false;
|
||||||
}
|
}
|
||||||
builder.append(leftMargin).append("└─\n");
|
out.margin(leftMargin).margin("└─").newline();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!isFirstElement) {
|
if (!isFirstElement) {
|
||||||
builder.append(leftMargin).append('\n');
|
out.margin(leftMargin).newline();
|
||||||
}
|
}
|
||||||
renderFrame((StackFrame) frame, builder, leftMargin);
|
renderFrame((StackFrame) frame, out, leftMargin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFirstElement) {
|
if (isFirstElement) {
|
||||||
renderHint(hint, builder, leftMargin);
|
renderHint(hint, out, leftMargin);
|
||||||
isFirstElement = false;
|
isFirstElement = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderFrame(StackFrame frame, StringBuilder builder, String leftMargin) {
|
private void renderFrame(StackFrame frame, TextFormatter out, String leftMargin) {
|
||||||
var transformed = frameTransformer.apply(frame);
|
var transformed = frameTransformer.apply(frame);
|
||||||
renderSourceLine(transformed, builder, leftMargin);
|
renderSourceLine(transformed, out, leftMargin);
|
||||||
renderSourceLocation(transformed, builder, leftMargin);
|
renderSourceLocation(transformed, out, leftMargin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderHint(@Nullable String hint, StringBuilder builder, String leftMargin) {
|
private void renderHint(@Nullable String hint, TextFormatter out, String leftMargin) {
|
||||||
if (hint == null || hint.isEmpty()) return;
|
if (hint == null || hint.isEmpty()) return;
|
||||||
|
|
||||||
builder.append('\n');
|
out.newline().margin(leftMargin).style(Element.HINT).append(hint).newline();
|
||||||
builder.append(leftMargin);
|
|
||||||
builder.append(hint);
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderSourceLine(StackFrame frame, StringBuilder builder, String leftMargin) {
|
private void renderSourceLine(StackFrame frame, TextFormatter out, String leftMargin) {
|
||||||
var originalSourceLine = frame.getSourceLines().get(0);
|
var originalSourceLine = frame.getSourceLines().get(0);
|
||||||
var leadingWhitespace = VmUtils.countLeadingWhitespace(originalSourceLine);
|
var leadingWhitespace = VmUtils.countLeadingWhitespace(originalSourceLine);
|
||||||
var sourceLine = originalSourceLine.strip();
|
var sourceLine = originalSourceLine.strip();
|
||||||
@@ -98,27 +101,28 @@ public final class StackTraceRenderer {
|
|||||||
: sourceLine.length();
|
: sourceLine.length();
|
||||||
|
|
||||||
var prefix = frame.getStartLine() + " | ";
|
var prefix = frame.getStartLine() + " | ";
|
||||||
builder.append(leftMargin).append(prefix).append(sourceLine).append('\n');
|
out.margin(leftMargin)
|
||||||
builder.append(leftMargin);
|
.style(Element.LINE_NUMBER)
|
||||||
//noinspection StringRepeatCanBeUsed
|
.append(prefix)
|
||||||
for (int i = 1; i < prefix.length() + startColumn; i++) {
|
.style(Element.TEXT)
|
||||||
builder.append(' ');
|
.append(sourceLine)
|
||||||
}
|
.newline()
|
||||||
//noinspection StringRepeatCanBeUsed
|
.margin(leftMargin)
|
||||||
for (int i = startColumn; i <= endColumn; i++) {
|
.repeat(prefix.length() + startColumn - 1, ' ')
|
||||||
builder.append('^');
|
.style(Element.ERROR)
|
||||||
}
|
.repeat(endColumn - startColumn + 1, '^')
|
||||||
builder.append('\n');
|
.newline();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderSourceLocation(StackFrame frame, StringBuilder builder, String leftMargin) {
|
private void renderSourceLocation(StackFrame frame, TextFormatter out, String leftMargin) {
|
||||||
builder.append(leftMargin).append("at ");
|
out.margin(leftMargin)
|
||||||
if (frame.getMemberName() != null) {
|
.style(Element.TEXT)
|
||||||
builder.append(frame.getMemberName());
|
.append("at ")
|
||||||
} else {
|
.append(frame.getMemberName() != null ? frame.getMemberName() : "<unknown>")
|
||||||
builder.append("<unknown>");
|
.append(" (")
|
||||||
}
|
.append(frame.getModuleUri())
|
||||||
builder.append(" (").append(frame.getModuleUri()).append(')').append('\n');
|
.append(")")
|
||||||
|
.newline();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ public final class TestRunner {
|
|||||||
try {
|
try {
|
||||||
checkAmendsPklTest(testModule);
|
checkAmendsPklTest(testModule);
|
||||||
} catch (VmException v) {
|
} catch (VmException v) {
|
||||||
var error = new TestResults.Error(v.getMessage(), v.toPklException(stackFrameTransformer));
|
var error =
|
||||||
|
new TestResults.Error(v.getMessage(), v.toPklException(stackFrameTransformer, false));
|
||||||
return resultsBuilder.setError(error).build();
|
return resultsBuilder.setError(error).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ public final class TestRunner {
|
|||||||
} catch (VmException err) {
|
} catch (VmException err) {
|
||||||
var error =
|
var error =
|
||||||
new TestResults.Error(
|
new TestResults.Error(
|
||||||
err.getMessage(), err.toPklException(stackFrameTransformer));
|
err.getMessage(), err.toPklException(stackFrameTransformer, false));
|
||||||
resultBuilder.addError(error);
|
resultBuilder.addError(error);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -208,7 +209,7 @@ public final class TestRunner {
|
|||||||
errored.set(true);
|
errored.set(true);
|
||||||
testResultBuilder.addError(
|
testResultBuilder.addError(
|
||||||
new TestResults.Error(
|
new TestResults.Error(
|
||||||
err.getMessage(), err.toPklException(stackFrameTransformer)));
|
err.getMessage(), err.toPklException(stackFrameTransformer, false)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var expectedValue = VmUtils.readMember(expectedGroup, exampleIndex);
|
var expectedValue = VmUtils.readMember(expectedGroup, exampleIndex);
|
||||||
@@ -305,7 +306,7 @@ public final class TestRunner {
|
|||||||
} catch (VmException err) {
|
} catch (VmException err) {
|
||||||
testResultBuilder.addError(
|
testResultBuilder.addError(
|
||||||
new TestResults.Error(
|
new TestResults.Error(
|
||||||
err.getMessage(), err.toPklException(stackFrameTransformer)));
|
err.getMessage(), err.toPklException(stackFrameTransformer, false)));
|
||||||
allSucceeded.set(false);
|
allSucceeded.set(false);
|
||||||
success.set(false);
|
success.set(false);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pkl.core.runtime;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.pkl.core.util.Nullable;
|
||||||
|
import org.pkl.core.util.StringBuilderWriter;
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO:
|
||||||
|
* Make "margin matter" a facility of the formatter, managing margins in e.g. `newline()`.
|
||||||
|
- `pushMargin(String matter)` / `popMargin()`
|
||||||
|
* Replace implementation methods `repeat()` with more semantic equivalents.
|
||||||
|
- `underline(int startColumn, int endColumn)`
|
||||||
|
* Replace `newInstance()` with an alternative that doesn't require instance management,
|
||||||
|
i.e. better composition (currently only used for pre-rendering `hint`s).
|
||||||
|
* Assert assumed invariants (e.g. `append(String text)` checking there are no newlines).
|
||||||
|
* Replace `THEME_ANSI` with one read from `pkl:settings`.
|
||||||
|
*/
|
||||||
|
public final class TextFormatter {
|
||||||
|
public static final Map<Element, @Nullable Styling> THEME_PLAIN = new HashMap<>();
|
||||||
|
public static final Map<Element, @Nullable Styling> THEME_ANSI;
|
||||||
|
|
||||||
|
static {
|
||||||
|
THEME_ANSI =
|
||||||
|
Map.of(
|
||||||
|
Element.MARGIN, new Styling(Color.YELLOW, true, false),
|
||||||
|
Element.HINT, new Styling(Color.YELLOW, true, true),
|
||||||
|
Element.STACK_OVERFLOW_LOOP_COUNT, new Styling(Color.MAGENTA, false, false),
|
||||||
|
Element.LINE_NUMBER, new Styling(Color.BLUE, false, false),
|
||||||
|
Element.ERROR_HEADER, new Styling(Color.RED, false, false),
|
||||||
|
Element.ERROR, new Styling(Color.RED, false, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<Element, @Nullable Styling> theme;
|
||||||
|
private final StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
private @Nullable Styling currentStyle;
|
||||||
|
|
||||||
|
private TextFormatter(Map<Element, Styling> theme) {
|
||||||
|
this.theme = theme;
|
||||||
|
this.currentStyle = theme.getOrDefault(Element.PLAIN, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TextFormatter create(boolean usingColor) {
|
||||||
|
return new TextFormatter(usingColor ? THEME_ANSI : THEME_PLAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrintWriter toPrintWriter() {
|
||||||
|
return new PrintWriter(new StringBuilderWriter(builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter newline() {
|
||||||
|
return newlines(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter newInstance() {
|
||||||
|
return new TextFormatter(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter newlines(int count) {
|
||||||
|
return repeat(count, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter margin(String marginMatter) {
|
||||||
|
return style(Element.MARGIN).append(marginMatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter style(Element element) {
|
||||||
|
var style = theme.getOrDefault(element, null);
|
||||||
|
if (currentStyle == style) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if (style == null) {
|
||||||
|
append("\033[0m");
|
||||||
|
currentStyle = style;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
var colorCode =
|
||||||
|
style.bright() ? style.foreground().fgBrightCode() : style.foreground().fgCode();
|
||||||
|
append('\033');
|
||||||
|
append('[');
|
||||||
|
append(colorCode);
|
||||||
|
if (style.bold() && (currentStyle == null || !currentStyle.bold())) {
|
||||||
|
append(";1");
|
||||||
|
} else if (!style.bold() && currentStyle != null && currentStyle.bold()) {
|
||||||
|
append(";22");
|
||||||
|
}
|
||||||
|
append('m');
|
||||||
|
currentStyle = style;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter repeat(int width, char ch) {
|
||||||
|
for (var i = 0; i < width; i++) {
|
||||||
|
append(ch);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter append(String s) {
|
||||||
|
builder.append(s);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter append(char ch) {
|
||||||
|
builder.append(ch);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter append(int i) {
|
||||||
|
builder.append(i);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextFormatter append(Object obj) {
|
||||||
|
builder.append(obj);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Element {
|
||||||
|
PLAIN,
|
||||||
|
MARGIN,
|
||||||
|
HINT,
|
||||||
|
STACK_OVERFLOW_LOOP_COUNT,
|
||||||
|
LINE_NUMBER,
|
||||||
|
TEXT,
|
||||||
|
ERROR_HEADER,
|
||||||
|
ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Styling(Color foreground, boolean bold, boolean bright) {}
|
||||||
|
|
||||||
|
public enum Color {
|
||||||
|
BLACK(30),
|
||||||
|
RED(31),
|
||||||
|
GREEN(32),
|
||||||
|
YELLOW(33),
|
||||||
|
BLUE(34),
|
||||||
|
MAGENTA(35),
|
||||||
|
CYAN(36),
|
||||||
|
WHITE(37);
|
||||||
|
|
||||||
|
private final int code;
|
||||||
|
|
||||||
|
Color(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fgCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int bgCode() {
|
||||||
|
return code + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fgBrightCode() {
|
||||||
|
return code + 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int bgBrightCode() {
|
||||||
|
return code + 70;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -58,8 +58,8 @@ public final class VmBugException extends VmException {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
public PklException toPklException(StackFrameTransformer transformer) {
|
public PklException toPklException(StackFrameTransformer transformer, boolean color) {
|
||||||
var renderer = new VmExceptionRenderer(new StackTraceRenderer(transformer));
|
var renderer = new VmExceptionRenderer(new StackTraceRenderer(transformer), color);
|
||||||
var rendered = renderer.render(this);
|
var rendered = renderer.render(this);
|
||||||
return new PklBugException(rendered, this);
|
return new PklBugException(rendered, this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ public abstract class VmException extends AbstractTruffleException {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
public PklException toPklException(StackFrameTransformer transformer) {
|
public PklException toPklException(StackFrameTransformer transformer, boolean color) {
|
||||||
var renderer = new VmExceptionRenderer(new StackTraceRenderer(transformer));
|
var renderer = new VmExceptionRenderer(new StackTraceRenderer(transformer), color);
|
||||||
var rendered = renderer.render(this);
|
var rendered = renderer.render(this);
|
||||||
return new PklException(rendered);
|
return new PklException(rendered);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,66 +16,67 @@
|
|||||||
package org.pkl.core.runtime;
|
package org.pkl.core.runtime;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.pkl.core.Release;
|
import org.pkl.core.Release;
|
||||||
|
import org.pkl.core.runtime.TextFormatter.Element;
|
||||||
import org.pkl.core.util.ErrorMessages;
|
import org.pkl.core.util.ErrorMessages;
|
||||||
import org.pkl.core.util.Nullable;
|
import org.pkl.core.util.Nullable;
|
||||||
import org.pkl.core.util.StringBuilderWriter;
|
|
||||||
|
|
||||||
public final class VmExceptionRenderer {
|
public final class VmExceptionRenderer {
|
||||||
private final @Nullable StackTraceRenderer stackTraceRenderer;
|
private final @Nullable StackTraceRenderer stackTraceRenderer;
|
||||||
|
private final boolean color;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an error renderer with the given stack trace renderer. If stack trace renderer is
|
* Constructs an error renderer with the given stack trace renderer. If stack trace renderer is
|
||||||
* {@code null}, stack traces will not be included in error output.
|
* {@code null}, stack traces will not be included in error output.
|
||||||
*/
|
*/
|
||||||
public VmExceptionRenderer(@Nullable StackTraceRenderer stackTraceRenderer) {
|
public VmExceptionRenderer(@Nullable StackTraceRenderer stackTraceRenderer, boolean color) {
|
||||||
this.stackTraceRenderer = stackTraceRenderer;
|
this.stackTraceRenderer = stackTraceRenderer;
|
||||||
|
this.color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
public String render(VmException exception) {
|
public String render(VmException exception) {
|
||||||
var builder = new StringBuilder();
|
var formatter = TextFormatter.create(color);
|
||||||
render(exception, builder);
|
render(exception, formatter);
|
||||||
return builder.toString();
|
return formatter.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void render(VmException exception, StringBuilder builder) {
|
private void render(VmException exception, TextFormatter out) {
|
||||||
if (exception instanceof VmBugException bugException) {
|
if (exception instanceof VmBugException bugException) {
|
||||||
renderBugException(bugException, builder);
|
renderBugException(bugException, out);
|
||||||
} else {
|
} else {
|
||||||
renderException(exception, builder, true);
|
renderException(exception, out, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderBugException(VmBugException exception, StringBuilder builder) {
|
private void renderBugException(VmBugException exception, TextFormatter out) {
|
||||||
// if a cause exists, it's more useful to report just that
|
// if a cause exists, it's more useful to report just that
|
||||||
var exceptionToReport = exception.getCause() != null ? exception.getCause() : exception;
|
var exceptionToReport = exception.getCause() != null ? exception.getCause() : exception;
|
||||||
|
var exceptionUrl = URLEncoder.encode(exceptionToReport.toString(), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
builder
|
out.style(Element.TEXT)
|
||||||
.append("An unexpected error has occurred. Would you mind filing a bug report?\n")
|
.append("An unexpected error has occurred. Would you mind filing a bug report?")
|
||||||
.append("Cmd+Double-click the link below to open an issue.\n")
|
.newline()
|
||||||
.append(
|
.append("Cmd+Double-click the link below to open an issue.")
|
||||||
"Please copy and paste the entire error output into the issue's description, provided you can share it.\n\n")
|
.newline()
|
||||||
.append("https://github.com/apple/pkl/issues/new\n\n");
|
.append("Please copy and paste the entire error output into the issue's description.")
|
||||||
|
.newlines(2)
|
||||||
|
.append("https://github.com/apple/pkl/issues/new")
|
||||||
|
.newlines(2)
|
||||||
|
.append(exceptionUrl.replaceAll("\\+", "%20"))
|
||||||
|
.newlines(2);
|
||||||
|
|
||||||
builder.append(
|
renderException(exception, out, true);
|
||||||
URLEncoder.encode(exceptionToReport.toString(), StandardCharsets.UTF_8)
|
|
||||||
.replaceAll("\\+", "%20"));
|
|
||||||
|
|
||||||
builder.append("\n\n");
|
out.newline().style(Element.TEXT).append(Release.current().versionInfo()).newlines(2);
|
||||||
renderException(exception, builder, true);
|
|
||||||
builder.append('\n').append(Release.current().versionInfo()).append("\n\n");
|
|
||||||
|
|
||||||
exceptionToReport.printStackTrace(new PrintWriter(new StringBuilderWriter(builder)));
|
exceptionToReport.printStackTrace(out.toPrintWriter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderException(VmException exception, StringBuilder builder, boolean withHeader) {
|
private void renderException(VmException exception, TextFormatter out, boolean withHeader) {
|
||||||
var header = "–– Pkl Error ––";
|
|
||||||
|
|
||||||
String message;
|
String message;
|
||||||
var hint = exception.getHint();
|
var hint = exception.getHint();
|
||||||
if (exception.isExternalMessage()) {
|
if (exception.isExternalMessage()) {
|
||||||
@@ -96,15 +97,9 @@ public final class VmExceptionRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (withHeader) {
|
if (withHeader) {
|
||||||
builder.append(header).append('\n');
|
out.style(Element.ERROR_HEADER).append("–– Pkl Error ––").newline();
|
||||||
}
|
|
||||||
builder.append(message).append('\n');
|
|
||||||
|
|
||||||
if (exception instanceof VmWrappedEvalException vmWrappedEvalException) {
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
renderException(vmWrappedEvalException.getWrappedException(), sb, false);
|
|
||||||
hint = sb.toString().lines().map((it) -> ">\t" + it).collect(Collectors.joining("\n"));
|
|
||||||
}
|
}
|
||||||
|
out.style(Element.ERROR).append(message).newline();
|
||||||
|
|
||||||
// include cause's message unless it's the same as this exception's message
|
// include cause's message unless it's the same as this exception's message
|
||||||
if (exception.getCause() != null) {
|
if (exception.getCause() != null) {
|
||||||
@@ -112,11 +107,11 @@ public final class VmExceptionRenderer {
|
|||||||
var causeMessage = cause.getMessage();
|
var causeMessage = cause.getMessage();
|
||||||
// null for Truffle's LazyStackTrace
|
// null for Truffle's LazyStackTrace
|
||||||
if (causeMessage != null && !causeMessage.equals(message)) {
|
if (causeMessage != null && !causeMessage.equals(message)) {
|
||||||
builder
|
out.style(Element.TEXT)
|
||||||
.append(cause.getClass().getSimpleName())
|
.append(cause.getClass().getSimpleName())
|
||||||
.append(": ")
|
.append(": ")
|
||||||
.append(causeMessage)
|
.append(causeMessage)
|
||||||
.append('\n');
|
.newline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,22 +119,28 @@ public final class VmExceptionRenderer {
|
|||||||
exception.getProgramValues().stream().mapToInt(v -> v.name.length()).max().orElse(0);
|
exception.getProgramValues().stream().mapToInt(v -> v.name.length()).max().orElse(0);
|
||||||
|
|
||||||
for (var value : exception.getProgramValues()) {
|
for (var value : exception.getProgramValues()) {
|
||||||
builder.append(value.name);
|
out.style(Element.TEXT)
|
||||||
builder.append(" ".repeat(Math.max(0, maxNameLength - value.name.length())));
|
.append(value.name)
|
||||||
builder.append(": ");
|
.repeat(Math.max(0, maxNameLength - value.name.length()), ' ')
|
||||||
builder.append(value);
|
.append(": ")
|
||||||
builder.append('\n');
|
.append(value)
|
||||||
|
.newline();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stackTraceRenderer != null) {
|
if (stackTraceRenderer != null) {
|
||||||
var frames = StackTraceGenerator.capture(exception);
|
var frames = StackTraceGenerator.capture(exception);
|
||||||
|
|
||||||
|
if (exception instanceof VmWrappedEvalException vmWrappedEvalException) {
|
||||||
|
var sb = out.newInstance();
|
||||||
|
renderException(vmWrappedEvalException.getWrappedException(), sb, false);
|
||||||
|
hint = sb.toString().lines().map((it) -> ">\t" + it).collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
if (!frames.isEmpty()) {
|
if (!frames.isEmpty()) {
|
||||||
builder.append('\n');
|
stackTraceRenderer.render(frames, hint, out.newline());
|
||||||
stackTraceRenderer.render(frames, hint, builder);
|
|
||||||
} else if (hint != null) {
|
} else if (hint != null) {
|
||||||
// render hint if there are no stack frames
|
// render hint if there are no stack frames
|
||||||
builder.append('\n');
|
out.newline().style(Element.HINT).append(hint);
|
||||||
builder.append(hint);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import org.pkl.core.stdlib.PklName;
|
|||||||
|
|
||||||
public final class TestNodes {
|
public final class TestNodes {
|
||||||
private static final VmExceptionRenderer noStackTraceExceptionRenderer =
|
private static final VmExceptionRenderer noStackTraceExceptionRenderer =
|
||||||
new VmExceptionRenderer(null);
|
new VmExceptionRenderer(null, false);
|
||||||
|
|
||||||
private TestNodes() {}
|
private TestNodes() {}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class AnalyzerTest {
|
|||||||
private val simpleAnalyzer =
|
private val simpleAnalyzer =
|
||||||
Analyzer(
|
Analyzer(
|
||||||
StackFrameTransformers.defaultTransformer,
|
StackFrameTransformers.defaultTransformer,
|
||||||
|
false,
|
||||||
SecurityManagers.defaultManager,
|
SecurityManagers.defaultManager,
|
||||||
listOf(ModuleKeyFactories.file, ModuleKeyFactories.standardLibrary, ModuleKeyFactories.pkg),
|
listOf(ModuleKeyFactories.file, ModuleKeyFactories.standardLibrary, ModuleKeyFactories.pkg),
|
||||||
null,
|
null,
|
||||||
@@ -108,6 +109,7 @@ class AnalyzerTest {
|
|||||||
val analyzer =
|
val analyzer =
|
||||||
Analyzer(
|
Analyzer(
|
||||||
StackFrameTransformers.defaultTransformer,
|
StackFrameTransformers.defaultTransformer,
|
||||||
|
false,
|
||||||
SecurityManagers.defaultManager,
|
SecurityManagers.defaultManager,
|
||||||
listOf(ModuleKeyFactories.file, ModuleKeyFactories.standardLibrary, ModuleKeyFactories.pkg),
|
listOf(ModuleKeyFactories.file, ModuleKeyFactories.standardLibrary, ModuleKeyFactories.pkg),
|
||||||
tempDir.resolve("packages"),
|
tempDir.resolve("packages"),
|
||||||
@@ -177,6 +179,7 @@ class AnalyzerTest {
|
|||||||
val analyzer =
|
val analyzer =
|
||||||
Analyzer(
|
Analyzer(
|
||||||
StackFrameTransformers.defaultTransformer,
|
StackFrameTransformers.defaultTransformer,
|
||||||
|
false,
|
||||||
SecurityManagers.defaultManager,
|
SecurityManagers.defaultManager,
|
||||||
listOf(
|
listOf(
|
||||||
ModuleKeyFactories.file,
|
ModuleKeyFactories.file,
|
||||||
@@ -288,6 +291,7 @@ class AnalyzerTest {
|
|||||||
val analyzer =
|
val analyzer =
|
||||||
Analyzer(
|
Analyzer(
|
||||||
StackFrameTransformers.defaultTransformer,
|
StackFrameTransformers.defaultTransformer,
|
||||||
|
false,
|
||||||
SecurityManagers.defaultManager,
|
SecurityManagers.defaultManager,
|
||||||
listOf(
|
listOf(
|
||||||
ModuleKeyFactories.file,
|
ModuleKeyFactories.file,
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ class ReplServerTest {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
"/".toPath(),
|
"/".toPath(),
|
||||||
StackFrameTransformers.defaultTransformer
|
StackFrameTransformers.defaultTransformer,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class ImportsAndReadsParserTest {
|
|||||||
assertThrows<VmException> {
|
assertThrows<VmException> {
|
||||||
ImportsAndReadsParser.parse(moduleKey, moduleKey.resolve(SecurityManagers.defaultManager))
|
ImportsAndReadsParser.parse(moduleKey, moduleKey.resolve(SecurityManagers.defaultManager))
|
||||||
}
|
}
|
||||||
assertThat(err.toPklException(StackFrameTransformers.defaultTransformer))
|
assertThat(err.toPklException(StackFrameTransformers.defaultTransformer, false))
|
||||||
.hasMessage(
|
.hasMessage(
|
||||||
"""
|
"""
|
||||||
–– Pkl Error ––
|
–– Pkl Error ––
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ class ProjectTest {
|
|||||||
mapOf("one" to "1"),
|
mapOf("one" to "1"),
|
||||||
listOf("foo:", "bar:").map(Pattern::compile),
|
listOf("foo:", "bar:").map(Pattern::compile),
|
||||||
listOf("baz:", "biz:").map(Pattern::compile),
|
listOf("baz:", "biz:").map(Pattern::compile),
|
||||||
|
null,
|
||||||
false,
|
false,
|
||||||
path.resolve("cache/"),
|
path.resolve("cache/"),
|
||||||
listOf(path.resolve("modulepath1/"), path.resolve("modulepath2/")),
|
listOf(path.resolve("modulepath1/"), path.resolve("modulepath2/")),
|
||||||
|
|||||||
@@ -190,7 +190,9 @@ class StackTraceRendererTest {
|
|||||||
}
|
}
|
||||||
val loop = StackTraceRenderer.StackFrameLoop(loopFrames, 1)
|
val loop = StackTraceRenderer.StackFrameLoop(loopFrames, 1)
|
||||||
val frames = listOf(createFrame("bar", 1), createFrame("baz", 2), loop)
|
val frames = listOf(createFrame("bar", 1), createFrame("baz", 2), loop)
|
||||||
val renderedFrames = buildString { renderer.doRender(frames, null, this, "", true) }
|
val formatter = TextFormatter.create(false)
|
||||||
|
renderer.doRender(frames, null, formatter, "", true)
|
||||||
|
val renderedFrames = formatter.toString()
|
||||||
assertThat(renderedFrames)
|
assertThat(renderedFrames)
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ evaluatorSettings {
|
|||||||
["two"] = "2"
|
["two"] = "2"
|
||||||
}
|
}
|
||||||
moduleCacheDir = "my-cache-dir/"
|
moduleCacheDir = "my-cache-dir/"
|
||||||
|
color = "always"
|
||||||
noCache = false
|
noCache = false
|
||||||
rootDir = "my-root-dir/"
|
rootDir = "my-root-dir/"
|
||||||
timeout = 5.min
|
timeout = 5.min
|
||||||
|
|||||||
@@ -445,6 +445,7 @@ public class PklPlugin implements Plugin<Project> {
|
|||||||
task.getModulePath().from(spec.getModulePath());
|
task.getModulePath().from(spec.getModulePath());
|
||||||
task.getSettingsModule().set(spec.getSettingsModule());
|
task.getSettingsModule().set(spec.getSettingsModule());
|
||||||
task.getEvalRootDir().set(spec.getEvalRootDir());
|
task.getEvalRootDir().set(spec.getEvalRootDir());
|
||||||
|
task.getColor().set(spec.getColor());
|
||||||
task.getNoCache().set(spec.getNoCache());
|
task.getNoCache().set(spec.getNoCache());
|
||||||
task.getModuleCacheDir().set(spec.getModuleCacheDir());
|
task.getModuleCacheDir().set(spec.getModuleCacheDir());
|
||||||
task.getEvalTimeout().set(spec.getEvalTimeout());
|
task.getEvalTimeout().set(spec.getEvalTimeout());
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ public interface BasePklSpec {
|
|||||||
|
|
||||||
DirectoryProperty getModuleCacheDir();
|
DirectoryProperty getModuleCacheDir();
|
||||||
|
|
||||||
|
Property<Boolean> getColor();
|
||||||
|
|
||||||
Property<Boolean> getNoCache();
|
Property<Boolean> getNoCache();
|
||||||
|
|
||||||
// use same type (Duration) as Gradle's `Task.timeout`
|
// use same type (Duration) as Gradle's `Task.timeout`
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import org.gradle.api.tasks.Internal;
|
|||||||
import org.gradle.api.tasks.Optional;
|
import org.gradle.api.tasks.Optional;
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
import org.pkl.commons.cli.CliBaseOptions;
|
import org.pkl.commons.cli.CliBaseOptions;
|
||||||
|
import org.pkl.core.evaluatorSettings.Color;
|
||||||
import org.pkl.core.util.IoUtils;
|
import org.pkl.core.util.IoUtils;
|
||||||
import org.pkl.core.util.LateInit;
|
import org.pkl.core.util.LateInit;
|
||||||
import org.pkl.core.util.Nullable;
|
import org.pkl.core.util.Nullable;
|
||||||
@@ -117,6 +118,10 @@ public abstract class BasePklTask extends DefaultTask {
|
|||||||
@Internal
|
@Internal
|
||||||
public abstract DirectoryProperty getModuleCacheDir();
|
public abstract DirectoryProperty getModuleCacheDir();
|
||||||
|
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
public abstract Property<Boolean> getColor();
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
@Optional
|
@Optional
|
||||||
public abstract Property<Boolean> getNoCache();
|
public abstract Property<Boolean> getNoCache();
|
||||||
@@ -164,6 +169,7 @@ public abstract class BasePklTask extends DefaultTask {
|
|||||||
null,
|
null,
|
||||||
getEvalTimeout().getOrNull(),
|
getEvalTimeout().getOrNull(),
|
||||||
mapAndGetOrNull(getModuleCacheDir(), it1 -> it1.getAsFile().toPath()),
|
mapAndGetOrNull(getModuleCacheDir(), it1 -> it1.getAsFile().toPath()),
|
||||||
|
getColor().getOrElse(false) ? Color.ALWAYS : Color.NEVER,
|
||||||
getNoCache().getOrElse(false),
|
getNoCache().getOrElse(false),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import org.gradle.api.tasks.Internal;
|
|||||||
import org.gradle.api.tasks.Optional;
|
import org.gradle.api.tasks.Optional;
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
import org.pkl.commons.cli.CliBaseOptions;
|
import org.pkl.commons.cli.CliBaseOptions;
|
||||||
|
import org.pkl.core.evaluatorSettings.Color;
|
||||||
import org.pkl.core.util.IoUtils;
|
import org.pkl.core.util.IoUtils;
|
||||||
import org.pkl.core.util.Pair;
|
import org.pkl.core.util.Pair;
|
||||||
|
|
||||||
@@ -175,6 +176,7 @@ public abstract class ModulesTask extends BasePklTask {
|
|||||||
getProjectDir().isPresent() ? getProjectDir().get().getAsFile().toPath() : null,
|
getProjectDir().isPresent() ? getProjectDir().get().getAsFile().toPath() : null,
|
||||||
getEvalTimeout().getOrNull(),
|
getEvalTimeout().getOrNull(),
|
||||||
mapAndGetOrNull(getModuleCacheDir(), it1 -> it1.getAsFile().toPath()),
|
mapAndGetOrNull(getModuleCacheDir(), it1 -> it1.getAsFile().toPath()),
|
||||||
|
getColor().getOrElse(false) ? Color.ALWAYS : Color.NEVER,
|
||||||
getNoCache().getOrElse(false),
|
getNoCache().getOrElse(false),
|
||||||
getOmitProjectSettings().getOrElse(false),
|
getOmitProjectSettings().getOrElse(false),
|
||||||
getNoProject().getOrElse(false),
|
getNoProject().getOrElse(false),
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ internal class BinaryEvaluator(
|
|||||||
) :
|
) :
|
||||||
EvaluatorImpl(
|
EvaluatorImpl(
|
||||||
transformer,
|
transformer,
|
||||||
|
false,
|
||||||
manager,
|
manager,
|
||||||
httpClient,
|
httpClient,
|
||||||
logger,
|
logger,
|
||||||
|
|||||||
@@ -67,6 +67,16 @@ allowedModules: Listing<String(isRegex)>?
|
|||||||
/// ```
|
/// ```
|
||||||
allowedResources: Listing<String(isRegex)>?
|
allowedResources: Listing<String(isRegex)>?
|
||||||
|
|
||||||
|
/// When to format messages with ANSI color codes.
|
||||||
|
///
|
||||||
|
/// Possible values:
|
||||||
|
///
|
||||||
|
/// - `"never"`: Never format
|
||||||
|
/// - `"auto"`: Format if the process' stdin, stdout, or stderr are connected to a console.
|
||||||
|
/// - `"always"`: Always format
|
||||||
|
@Since { version = "0.27.0" }
|
||||||
|
color: ("never"|"auto"|"always")?
|
||||||
|
|
||||||
/// Disables the file system cache for `package:` modules.
|
/// Disables the file system cache for `package:` modules.
|
||||||
///
|
///
|
||||||
/// When caching is disabled, packages are loaded over the network and stored in memory.
|
/// When caching is disabled, packages are loaded over the network and stored in memory.
|
||||||
|
|||||||
Reference in New Issue
Block a user