package templatestore
import (
"cmp"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"slices"
"strings"
"unicode"
"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
"github.com/lima-vm/lima/v2/pkg/usrlocal"
)
type Template struct {
Name string `json:"name"`
Location string `json:"location"`
}
func templatesPaths() ([]string, error) {
if tmplPath := os.Getenv("LIMA_TEMPLATES_PATH"); tmplPath != "" {
return strings.Split(tmplPath, string(filepath.ListSeparator)), nil
}
limaTemplatesDir, err := dirnames.LimaTemplatesDir()
if err != nil {
return nil, err
}
shareLimaDirs, err := usrlocal.ShareLima()
if err != nil {
return nil, err
}
res := []string{limaTemplatesDir}
for _, shareLimaDir := range shareLimaDirs {
res = append(res, filepath.Join(shareLimaDir, "templates"))
}
return res, nil
}
func Read(name string) ([]byte, error) {
doubleDot := ".."
if strings.Contains(name, doubleDot) {
return nil, fmt.Errorf("template name %q must not contain %q", name, doubleDot)
}
paths, err := templatesPaths()
if err != nil {
return nil, err
}
ext := filepath.Ext(name)
if len(ext) < 2 || unicode.IsDigit(rune(ext[1])) {
name += ".yaml"
}
for _, templatesDir := range paths {
filePath := filepath.Clean(filepath.Join(templatesDir, name))
if b, err := os.ReadFile(filePath); !errors.Is(err, os.ErrNotExist) {
return b, err
}
}
return nil, fmt.Errorf("template %q not found", name)
}
const Default = "default"
func Templates() ([]Template, error) {
paths, err := templatesPaths()
if err != nil {
return nil, err
}
templates := make(map[string]string)
for _, templatesDir := range paths {
if _, err := os.Stat(templatesDir); os.IsNotExist(err) {
continue
}
walkDirFn := func(p string, _ fs.DirEntry, err error) error {
if err != nil {
return err
}
base := filepath.Base(p)
if strings.HasPrefix(base, ".") || !strings.HasSuffix(base, ".yaml") {
return nil
}
name := strings.TrimSuffix(strings.TrimPrefix(p, templatesDir+"/"), ".yaml")
if _, ok := templates[name]; !ok {
templates[name] = p
}
return nil
}
if err = filepath.WalkDir(templatesDir, walkDirFn); err != nil {
return nil, err
}
}
var res []Template
for name, loc := range templates {
res = append(res, Template{Name: name, Location: loc})
}
slices.SortFunc(res, func(i, j Template) int { return cmp.Compare(i.Name, j.Name) })
return res, nil
}