restrict file writes for --multi to the specified output directory

This commit is contained in:
John Bartholomew 2026-02-18 18:44:46 +00:00
parent 6d35a88517
commit acd4ea256d

View File

@ -20,6 +20,7 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"sort"
"strings"
@ -293,6 +294,48 @@ func processArgs(givenArgs []string, config *config, vm *jsonnet.VM) (processArg
return processArgsStatusContinue, nil
}
// (*Root) ReadFile() is added in Go 1.25; switch to that in the future.
func rootReadFile(root *os.Root, name string) ([]byte, error) {
f, err := root.Open(name)
if err != nil {
return nil, err
}
defer f.Close()
return io.ReadAll(f)
}
// (*Root) WriteFile() is added in Go 1.25; switch to that in the future.
func rootWriteFile(root *os.Root, name string, data []byte, perm os.FileMode) error {
f, err := root.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
}
_, finalErr := f.Write(data)
if err := f.Close(); err != nil {
finalErr = err
}
return finalErr
}
// (*Root) MkdirAll() is added in Go 1.25; switch to that in the future.
func rootMkdirAll(root *os.Root, name string, perm os.FileMode) error {
var dirs []string
rest := name
for rest != "." && rest != "/" && rest != "" {
dirs = append(dirs, rest)
rest = path.Dir(rest)
}
for i := range dirs {
if err := root.Mkdir(dirs[len(dirs)-i-1], perm); err != nil {
if os.IsExist(err) {
continue
}
return err
}
}
return nil
}
func writeMultiOutputFiles(output map[string]string, outputDir, outputFile string, createDirs bool) (err error) {
// If multiple file output is used, then iterate over each string from
// the sequence of strings returned by jsonnet_evaluate_snippet_multi,
@ -320,22 +363,43 @@ func writeMultiOutputFiles(output map[string]string, outputDir, outputFile strin
keys = append(keys, k)
}
sort.Strings(keys)
if len(keys) == 0 {
return nil
}
outputDir = filepath.Clean(outputDir)
root, err := os.OpenRoot(outputDir)
if err != nil {
if os.IsNotExist(err) && createDirs {
if err := os.MkdirAll(outputDir, 0755); err != nil {
return err
}
root, err = os.OpenRoot(outputDir)
}
if err != nil {
return err
}
}
for _, key := range keys {
newContent := output[key]
filename := outputDir + key
relpath := filepath.Clean(key)
if filepath.IsAbs(key) {
relpath, err = filepath.Rel("/", key)
if err != nil {
return err
}
}
abspath := filepath.Join(outputDir, relpath)
_, err := manifest.WriteString(filename)
_, err := manifest.WriteString(abspath + "\n")
if err != nil {
return err
}
_, err = manifest.WriteString("\n")
if err != nil {
return err
}
if _, err := os.Stat(filename); !os.IsNotExist(err) {
existingContent, err := os.ReadFile(filename)
if _, err := root.Stat(relpath); !os.IsNotExist(err) {
existingContent, err := rootReadFile(root, relpath)
if err != nil {
return err
}
@ -347,12 +411,12 @@ func writeMultiOutputFiles(output map[string]string, outputDir, outputFile strin
}
}
if createDirs {
if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil {
if err := rootMkdirAll(root, filepath.Dir(relpath), 0755); err != nil {
return err
}
}
err = os.WriteFile(filename, []byte(newContent), 0666)
err = rootWriteFile(root, relpath, []byte(newContent), 0666)
if err != nil {
return err
}