102 lines
2.4 KiB
Go
102 lines
2.4 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/aspect-build/bazel-lib/tools/common"
|
||
|
"golang.org/x/exp/maps"
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
args := os.Args[1:]
|
||
|
|
||
|
if len(args) == 1 {
|
||
|
if args[0] == "--version" || args[0] == "-v" {
|
||
|
fmt.Printf("expand_template %s\n", common.Version())
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if len(args) != 6 {
|
||
|
fmt.Println("Usage: expand_template <template> <out> <substitutions_json> <volatile_status_file> <stable_status_file> <executable>")
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
|
||
|
executable := args[5] == "true" || args[5] == "1"
|
||
|
|
||
|
substitutions := map[string]string{}
|
||
|
substitutionJson, err := os.ReadFile(args[2])
|
||
|
if err != nil {
|
||
|
log.Fatal(fmt.Errorf("failed to read substitutions file: %w", err))
|
||
|
}
|
||
|
if err := json.Unmarshal(substitutionJson, &substitutions); err != nil {
|
||
|
log.Fatal(fmt.Errorf("failed to parse substitutions file: %w", err))
|
||
|
}
|
||
|
|
||
|
volatileStatus, err := parseStatusFile(args[3])
|
||
|
if err != nil {
|
||
|
log.Fatal(fmt.Errorf("failed to parse volatile status file: %w", err))
|
||
|
}
|
||
|
stableStatus, err := parseStatusFile(args[4])
|
||
|
if err != nil {
|
||
|
log.Fatal(fmt.Errorf("failed to parse stable status file: %w", err))
|
||
|
}
|
||
|
|
||
|
statuses := map[string]string{}
|
||
|
maps.Copy(statuses, volatileStatus)
|
||
|
maps.Copy(statuses, stableStatus)
|
||
|
|
||
|
for key, value := range substitutions {
|
||
|
for token, replacement := range statuses {
|
||
|
value = strings.ReplaceAll(value, fmt.Sprintf("{{%s}}", token), replacement)
|
||
|
}
|
||
|
substitutions[key] = value
|
||
|
}
|
||
|
|
||
|
contentBytes, err := os.ReadFile(args[0])
|
||
|
if err != nil {
|
||
|
log.Fatal(fmt.Errorf("failed to read the template file: %w", err))
|
||
|
}
|
||
|
content := string(contentBytes)
|
||
|
|
||
|
for key, value := range substitutions {
|
||
|
content = strings.ReplaceAll(content, key, value)
|
||
|
}
|
||
|
|
||
|
var mode os.FileMode = 0x666
|
||
|
if executable {
|
||
|
mode = 0o777
|
||
|
}
|
||
|
err = os.WriteFile(args[1], []byte(content), mode)
|
||
|
if err != nil {
|
||
|
log.Fatal(fmt.Errorf("failed to write output file: %w", err))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// captures every `KEY VALUE` line in the status file.
|
||
|
// for explanation see: https://regex101.com/r/B28NN7/1
|
||
|
var STATUS_REGEX = regexp.MustCompile(`(?m)^([^\s]+)\s+([^\n ]*)$`)
|
||
|
|
||
|
func parseStatusFile(statusFilePath string) (map[string]string, error) {
|
||
|
statusFile, err := os.ReadFile(statusFilePath)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
matches := STATUS_REGEX.FindAllStringSubmatch(string(statusFile), -1)
|
||
|
|
||
|
results := map[string]string{}
|
||
|
|
||
|
for _, match := range matches {
|
||
|
results[match[1]] = match[2]
|
||
|
}
|
||
|
|
||
|
return results, nil
|
||
|
|
||
|
}
|