Fix newline handling in file, softlink, and ImportLink template functions
Use state-based routing instead of sentinel strings, so whitespace-trimming
syntax (e.g. `{{- file "name" -}}`) correctly creates all named files and
symlinks.
Fixes: #2118
Signed-off-by: Jonathon Anderson <janderson@ciq.com>
Co-authored-by: Christian Goll <cgoll@suse.com>
Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
@@ -1,12 +1,9 @@
|
||||
package show
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -28,6 +25,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
overlayFile := overlay_.File(fileName)
|
||||
|
||||
if NodeName == "" {
|
||||
// No node specified: show the raw template source without rendering.
|
||||
if !util.IsFile(overlayFile) {
|
||||
return fmt.Errorf("%s: %s not found", overlayName, overlayFile)
|
||||
}
|
||||
@@ -38,6 +36,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
|
||||
wwlog.Output("%s", string(f))
|
||||
} else {
|
||||
// Node specified: render the template for the given node and show output.
|
||||
|
||||
// If the caller gave the output filename (without .ww), find the template.
|
||||
if !util.IsFile(overlayFile) {
|
||||
possibleFile := fmt.Sprintf("%s.ww", overlayFile)
|
||||
if filepath.Ext(overlayFile) != ".ww" && util.IsFile(possibleFile) {
|
||||
@@ -56,6 +57,8 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
nodeConf, err := nodeDB.GetNode(NodeName)
|
||||
if err == node.ErrNotFound {
|
||||
// Unknown node name: fall back to the local hostname so operators can
|
||||
// preview templates on the warewulf server itself.
|
||||
hostName, err := os.Hostname()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get host name: %s", err)
|
||||
@@ -73,43 +76,50 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
tstruct.BuildSource = overlayFile
|
||||
buffer, backupFile, writeFile, err := overlay.RenderTemplateFile(overlayFile, tstruct)
|
||||
rendered, err := overlay.RenderTemplate(overlayFile, tstruct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var outBuffer bytes.Buffer
|
||||
// search for magic file name comment
|
||||
bufferScanner := bufio.NewScanner(bytes.NewReader(buffer.Bytes()))
|
||||
bufferScanner.Split(overlay.ScanLines)
|
||||
reg := regexp.MustCompile(`.*{{\s*/\*\s*file\s*["'](.*)["']\s*\*/\s*}}.*`)
|
||||
foundFileComment := false
|
||||
destFileName := strings.TrimSuffix(fileName, ".ww")
|
||||
for bufferScanner.Scan() {
|
||||
line := bufferScanner.Text()
|
||||
filenameFromTemplate := reg.FindAllStringSubmatch(line, -1)
|
||||
if len(filenameFromTemplate) != 0 {
|
||||
wwlog.Debug("Found multifile comment, new filename %s", filenameFromTemplate[0][1])
|
||||
if foundFileComment {
|
||||
if !Quiet {
|
||||
wwlog.Info("backupFile: %v", *backupFile)
|
||||
wwlog.Info("writeFile: %v", *writeFile)
|
||||
wwlog.Info("Filename: %s", destFileName)
|
||||
}
|
||||
wwlog.Output("%s", outBuffer.String())
|
||||
outBuffer.Reset()
|
||||
|
||||
if !rendered.WriteFile {
|
||||
// abort() was called in the template: nothing would be written to disk.
|
||||
// Still show any content rendered before the abort() call for debugging.
|
||||
if !Quiet {
|
||||
wwlog.Info("backupFile: %v", rendered.BackupFile)
|
||||
wwlog.Info("writeFile: %v", rendered.WriteFile)
|
||||
}
|
||||
wwlog.Output("%s", rendered.Files[0].Buffer.String())
|
||||
if !Quiet {
|
||||
wwlog.Info("Aborted")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, f := range rendered.Files {
|
||||
// The default slot (Name == "") holds pre-file() content or a symlink.
|
||||
// When named files are also present, non-symlink content is discarded
|
||||
// for disk output; skip it here too so that show output matches what
|
||||
// is actually written to disk. A default symlink is always shown.
|
||||
if f.Name == "" && len(rendered.Files) > 1 && !f.IsSymlink {
|
||||
continue
|
||||
}
|
||||
// The default slot's display name is the template filename with .ww stripped.
|
||||
displayName := f.Name
|
||||
if displayName == "" {
|
||||
displayName = strings.TrimSuffix(fileName, ".ww")
|
||||
}
|
||||
if !Quiet {
|
||||
wwlog.Info("backupFile: %v", rendered.BackupFile)
|
||||
wwlog.Info("writeFile: %v", rendered.WriteFile)
|
||||
wwlog.Info("Filename: %s", displayName)
|
||||
if f.IsSymlink {
|
||||
wwlog.Info("Symlink: %s", f.Target)
|
||||
}
|
||||
destFileName = filenameFromTemplate[0][1]
|
||||
foundFileComment = true
|
||||
} else {
|
||||
_, _ = outBuffer.WriteString(line)
|
||||
}
|
||||
if !f.IsSymlink {
|
||||
wwlog.Output("%s", f.Buffer.String())
|
||||
}
|
||||
}
|
||||
if !Quiet {
|
||||
wwlog.Info("backupFile: %v", *backupFile)
|
||||
wwlog.Info("writeFile: %v", *writeFile)
|
||||
wwlog.Info("Filename: %s", destFileName)
|
||||
}
|
||||
wwlog.Output("%s", outBuffer.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user