1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
package main
import (
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strconv"
"gopkg.in/yaml.v2"
"github.com/lxc/incus/v6/shared/api"
"github.com/lxc/incus/v6/shared/util"
)
func templatesApply(path string) ([]string, error) {
metaName := filepath.Join(path, "metadata.yaml")
if !util.PathExists(metaName) {
return nil, nil
}
// Parse the metadata.
content, err := os.ReadFile(metaName)
if err != nil {
return nil, fmt.Errorf("Failed to read metadata: %w", err)
}
metadata := new(api.ImageMetadata)
err = yaml.Unmarshal(content, &metadata)
if err != nil {
return nil, fmt.Errorf("Could not parse metadata.yaml: %w", err)
}
// Go through the files and copy them into place.
files := []string{}
for tplPath, tpl := range metadata.Templates {
err = func(tplPath string, tpl *api.ImageMetadataTemplate) error {
filePath := filepath.Join(path, fmt.Sprintf("%s.out", tpl.Template))
if !util.PathExists(filePath) {
return nil
}
var w *os.File
if util.PathExists(tplPath) {
if tpl.CreateOnly {
return nil
}
// Open the existing file.
w, err = os.Create(tplPath)
if err != nil {
return fmt.Errorf("Failed to create template file: %w", err)
}
} else {
// UID and GID
fileUID := int64(0)
fileGID := int64(0)
if tpl.UID != "" {
id, err := strconv.ParseInt(tpl.UID, 10, 64)
if err != nil {
return fmt.Errorf("Bad file UID %q for %q: %w", tpl.UID, tplPath, err)
}
fileUID = id
}
if tpl.GID != "" {
id, err := strconv.ParseInt(tpl.GID, 10, 64)
if err != nil {
return fmt.Errorf("Bad file GID %q for %q: %w", tpl.GID, tplPath, err)
}
fileGID = id
}
// Mode
fileMode := fs.FileMode(0o644)
if tpl.Mode != "" {
if len(tpl.Mode) == 3 {
tpl.Mode = fmt.Sprintf("0%s", tpl.Mode)
}
mode, err := strconv.ParseInt(tpl.Mode, 0, 0)
if err != nil {
return fmt.Errorf("Bad mode %q for %q: %w", tpl.Mode, tplPath, err)
}
fileMode = os.FileMode(mode) & os.ModePerm
}
// Create the directories leading to the file.
err := os.MkdirAll(filepath.Dir(tplPath), 0o755)
if err != nil {
return err
}
// Create the file itself.
w, err = os.Create(tplPath)
if err != nil {
return err
}
// Fix ownership.
err = w.Chown(int(fileUID), int(fileGID))
if err != nil {
return err
}
// Fix mode.
err = w.Chmod(fileMode)
if err != nil {
return err
}
}
defer func() { _ = w.Close() }()
// Do the copy.
src, err := os.Open(filePath)
if err != nil {
return err
}
defer func() { _ = src.Close() }()
_, err = io.Copy(w, src)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
files = append(files, tplPath)
return nil
}(tplPath, tpl)
if err != nil {
return nil, err
}
}
return files, nil
}
|