Rework processing into 2 steps (preprocess - process)

This commit is contained in:
2025-10-16 14:28:15 +02:00
parent 4e4e58af83
commit 89e29eacee

View File

@@ -270,48 +270,22 @@ func ParseYAMLFile(filename, workdir string) ([]LinkInstruction, error) {
return nil, fmt.Errorf("error reading YAML file: %w", err)
}
// First try to parse as a YAMLConfig with links and from fields
var config YAMLConfig
err = yaml.Unmarshal(data, &config)
LogInfo("First parsing attempt: err=%v, links=%d, from=%d", err, len(config.Links), len(config.From))
// Parse as a direct list of instructions
var instructions []LinkInstruction
err = yaml.Unmarshal(data, &instructions)
if err != nil {
// If that fails, try parsing as a direct list of instructions
var instructions []LinkInstruction
err = yaml.Unmarshal(data, &instructions)
if err != nil {
return nil, fmt.Errorf("error parsing YAML: %w", err)
}
// Filter out invalid instructions (empty source)
validInstructions := []LinkInstruction{}
for _, instr := range instructions {
if instr.Source != "" {
validInstructions = append(validInstructions, instr)
}
}
config.Links = validInstructions
return nil, fmt.Errorf("error parsing YAML: %w", err)
}
expanded := []LinkInstruction{}
for _, link := range config.Links {
LogSource("Expanding pattern source %s in YAML file %s", link.Source, filename)
newlinks, err := ExpandPattern(link.Source, workdir, link.Target)
if err != nil {
return nil, fmt.Errorf("error expanding pattern: %w", err)
}
// "Clone" the original link instruction for each expanded link
for i := range newlinks {
newlinks[i].Delete = link.Delete
newlinks[i].Hard = link.Hard
newlinks[i].Force = link.Force
}
LogInfo("Expanded pattern %s in YAML file %s to %d links",
FormatSourcePath(link.Source), FormatSourcePath(filename), len(newlinks))
expanded = append(expanded, newlinks...)
// Preprocess instructions: expand globs and from references
processedInstructions, err := preprocessInstructions(instructions, filename, workdir)
if err != nil {
return nil, err
}
for i := range expanded {
link := &expanded[i]
// Final processing: normalize paths and set defaults
for i := range processedInstructions {
link := &processedInstructions[i]
link.Tidy()
link.Source, _ = ConvertHome(link.Source)
link.Target, _ = ConvertHome(link.Target)
@@ -324,7 +298,74 @@ func ParseYAMLFile(filename, workdir string) ([]LinkInstruction, error) {
}
}
return expanded, nil
return processedInstructions, nil
}
// preprocessInstructions handles glob expansion and from references
func preprocessInstructions(instructions []LinkInstruction, filename, workdir string) ([]LinkInstruction, error) {
var result []LinkInstruction
for _, instr := range instructions {
if instr.Source == "" {
continue // Skip invalid instructions
}
if instr.Target == "" {
// This is a from reference - load the referenced file
fromInstructions, err := loadFromReference(instr.Source, filename, workdir)
if err != nil {
return nil, fmt.Errorf("error loading from reference %s: %w", instr.Source, err)
}
result = append(result, fromInstructions...)
} else {
// This is a regular instruction - expand globs if needed
expandedInstructions, err := expandGlobs(instr, filename, workdir)
if err != nil {
return nil, fmt.Errorf("error expanding globs for %s: %w", instr.Source, err)
}
result = append(result, expandedInstructions...)
}
}
return result, nil
}
// loadFromReference loads instructions from a referenced file
func loadFromReference(fromFile, currentFile, workdir string) ([]LinkInstruction, error) {
// Convert relative paths to absolute paths based on the current file's directory
fromPath := fromFile
if !filepath.IsAbs(fromPath) {
currentDir := filepath.Dir(currentFile)
fromPath = filepath.Join(currentDir, fromPath)
}
// Normalize the path
fromPath = filepath.Clean(fromPath)
// Recursively parse the referenced file
fromWorkdir := filepath.Dir(fromPath)
return ParseYAMLFileRecursive(fromPath, fromWorkdir)
}
// expandGlobs expands glob patterns in a single instruction
func expandGlobs(instr LinkInstruction, filename, workdir string) ([]LinkInstruction, error) {
LogSource("Expanding pattern source %s in YAML file %s", instr.Source, filename)
newlinks, err := ExpandPattern(instr.Source, workdir, instr.Target)
if err != nil {
return nil, err
}
// Clone the original instruction properties for each expanded link
for i := range newlinks {
newlinks[i].Delete = instr.Delete
newlinks[i].Hard = instr.Hard
newlinks[i].Force = instr.Force
}
LogInfo("Expanded pattern %s in YAML file %s to %d links",
FormatSourcePath(instr.Source), FormatSourcePath(filename), len(newlinks))
return newlinks, nil
}
// ParseYAMLFileRecursive parses a YAML file and recursively processes any "From" references
@@ -348,50 +389,8 @@ func parseYAMLFileRecursive(filename, workdir string, visited map[string]bool) (
visited[normalizedFilename] = true
defer delete(visited, normalizedFilename)
// Parse the current file
instructions, err := ParseYAMLFile(filename, workdir)
if err != nil {
return nil, err
}
// Read the file to check for "From" references
data, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("error reading YAML file: %w", err)
}
var config YAMLConfig
err = yaml.Unmarshal(data, &config)
if err != nil {
// If parsing as YAMLConfig fails, there are no "From" references to process
return instructions, nil
}
// Process "From" references
for _, fromFile := range config.From {
// Convert relative paths to absolute paths based on the current file's directory
fromPath := fromFile
if !filepath.IsAbs(fromPath) {
currentDir := filepath.Dir(filename)
fromPath = filepath.Join(currentDir, fromPath)
}
// Normalize the path
fromPath = filepath.Clean(fromPath)
// Recursively parse the referenced file
// Use the directory of the referenced file as the workdir for pattern expansion
fromWorkdir := filepath.Dir(fromPath)
fromInstructions, err := parseYAMLFileRecursive(fromPath, fromWorkdir, visited)
if err != nil {
return nil, fmt.Errorf("error parsing referenced file %s: %w", fromFile, err)
}
// Append the instructions from the referenced file
instructions = append(instructions, fromInstructions...)
}
return instructions, nil
// Parse the current file using the new preprocessing approach
return ParseYAMLFile(filename, workdir)
}
func ExpandPattern(source, workdir, target string) (links []LinkInstruction, err error) {