mirror of
https://github.com/apple/pkl.git
synced 2026-07-10 15:12:43 +02:00
Do not throw if output dir is symlink (#1389)
This commit is contained in:
@@ -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.
|
||||||
@@ -263,13 +263,15 @@ constructor(
|
|||||||
}
|
}
|
||||||
val moduleSource = toModuleSource(moduleUri, inputStream)
|
val moduleSource = toModuleSource(moduleUri, inputStream)
|
||||||
val output = evaluator.evaluateOutputFiles(moduleSource)
|
val output = evaluator.evaluateOutputFiles(moduleSource)
|
||||||
|
val realOutputDir = if (outputDir.exists()) outputDir.toRealPath() else outputDir
|
||||||
|
|
||||||
for ((pathSpec, fileOutput) in output) {
|
for ((pathSpec, fileOutput) in output) {
|
||||||
checkPathSpec(pathSpec)
|
checkPathSpec(pathSpec)
|
||||||
val resolvedPath = outputDir.resolve(pathSpec).normalize()
|
val resolvedPath = realOutputDir.resolve(pathSpec).normalize()
|
||||||
val realPath = if (resolvedPath.exists()) resolvedPath.toRealPath() else resolvedPath
|
val realPath = if (resolvedPath.exists()) resolvedPath.toRealPath() else resolvedPath
|
||||||
if (!realPath.startsWith(outputDir)) {
|
if (!realPath.startsWith(realOutputDir)) {
|
||||||
throw CliException(
|
throw CliException(
|
||||||
"Output file conflict: `output.files` entry `\"$pathSpec\"` in module `$moduleUri` resolves to file path `$realPath`, which is outside output directory `$outputDir`."
|
"Output file conflict: `output.files` entry `\"$pathSpec\"` in module `$moduleUri` resolves to file path `$realPath`, which is outside output directory `$realOutputDir`."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val previousOutput = writtenFiles[realPath]
|
val previousOutput = writtenFiles[realPath]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2025-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.
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -1634,6 +1634,95 @@ result = someLib.x
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisabledOnOs(OS.WINDOWS)
|
||||||
|
fun `multiple file output works with symlinked output directory`() {
|
||||||
|
val realOutputDir = tempDir.resolve("real-output").createDirectories()
|
||||||
|
|
||||||
|
val symlinkOutputDir =
|
||||||
|
Files.createSymbolicLink(tempDir.resolve("symlink-output"), realOutputDir)
|
||||||
|
|
||||||
|
val sourceFile =
|
||||||
|
writePklFile(
|
||||||
|
"test.pkl",
|
||||||
|
"""
|
||||||
|
pigeon {
|
||||||
|
name = "Pigeon"
|
||||||
|
diet = "Seeds"
|
||||||
|
}
|
||||||
|
parrot {
|
||||||
|
name = "Parrot"
|
||||||
|
diet = "Seeds"
|
||||||
|
}
|
||||||
|
output {
|
||||||
|
files {
|
||||||
|
["pigeon.json"] {
|
||||||
|
value = pigeon
|
||||||
|
renderer = new JsonRenderer {}
|
||||||
|
}
|
||||||
|
["birds/parrot.yaml"] {
|
||||||
|
value = parrot
|
||||||
|
renderer = new YamlRenderer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
|
||||||
|
val options =
|
||||||
|
CliEvaluatorOptions(
|
||||||
|
CliBaseOptions(sourceModules = listOf(sourceFile), workingDir = tempDir),
|
||||||
|
multipleFileOutputPath = symlinkOutputDir.toString(),
|
||||||
|
)
|
||||||
|
|
||||||
|
CliEvaluator(options).run()
|
||||||
|
|
||||||
|
checkOutputFile(
|
||||||
|
realOutputDir.resolve("pigeon.json"),
|
||||||
|
"pigeon.json",
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"name": "Pigeon",
|
||||||
|
"diet": "Seeds"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
|
||||||
|
checkOutputFile(
|
||||||
|
realOutputDir.resolve("birds/parrot.yaml"),
|
||||||
|
"parrot.yaml",
|
||||||
|
"""
|
||||||
|
name: Parrot
|
||||||
|
diet: Seeds
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
|
||||||
|
checkOutputFile(
|
||||||
|
symlinkOutputDir.resolve("pigeon.json"),
|
||||||
|
"pigeon.json",
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"name": "Pigeon",
|
||||||
|
"diet": "Seeds"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
|
||||||
|
checkOutputFile(
|
||||||
|
symlinkOutputDir.resolve("birds/parrot.yaml"),
|
||||||
|
"parrot.yaml",
|
||||||
|
"""
|
||||||
|
name: Parrot
|
||||||
|
diet: Seeds
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun evalModuleThatImportsPackage(certsFile: Path?, testPort: Int = -1) {
|
private fun evalModuleThatImportsPackage(certsFile: Path?, testPort: Int = -1) {
|
||||||
val moduleUri =
|
val moduleUri =
|
||||||
writePklFile(
|
writePklFile(
|
||||||
|
|||||||
Reference in New Issue
Block a user