package admin import ( "bytes" "log" "os" "path/filepath" "gopkg.in/yaml.v3" ) func readYAMLFile(dataDir, subdir, id string) ([]byte, string, error) { path := filepath.Join(dataDir, subdir, id+".yaml") data, err := os.ReadFile(path) return data, path, err } func writeYAMLFile(path string, data any) ([]byte, error) { var buf bytes.Buffer enc := yaml.NewEncoder(&buf) enc.SetIndent(2) if err := enc.Encode(data); err != nil { return nil, err } enc.Close() content := buf.Bytes() if err := os.WriteFile(path, content, 0644); err != nil { return nil, err } return content, nil } func findYAMLFileInSubdirs(dataDir, subdir, id string) ([]byte, string, error) { base := filepath.Join(dataDir, subdir) entries, err := os.ReadDir(base) if err != nil { return nil, "", err } for _, e := range entries { fullPath := filepath.Join(base, e.Name(), id+".yaml") if data, err := os.ReadFile(fullPath); err == nil { return data, fullPath, nil } subPath := filepath.Join(base, e.Name()) subEntries, err := os.ReadDir(subPath) if err != nil { continue } for _, se := range subEntries { fullPath := filepath.Join(subPath, se.Name(), id+".yaml") if data, err := os.ReadFile(fullPath); err == nil { return data, fullPath, nil } } } return nil, "", os.ErrNotExist } func listYAMLFiles(dataDir, subdir string) ([]string, error) { var ids []string base := filepath.Join(dataDir, subdir) entries, err := os.ReadDir(base) if err != nil { return nil, err } for _, e := range entries { if !e.IsDir() && filepath.Ext(e.Name()) == ".yaml" { ids = append(ids, e.Name()[:len(e.Name())-5]) } } for _, e := range entries { if e.IsDir() { subPath := filepath.Join(base, e.Name()) subEntries, err := os.ReadDir(subPath) if err != nil { continue } for _, se := range subEntries { if !se.IsDir() && filepath.Ext(se.Name()) == ".yaml" { ids = append(ids, se.Name()[:len(se.Name())-5]) } } } } return ids, nil } type YAMLTree struct { Root []string `json:"root"` Dirs map[string][]string `json:"dirs"` } func listYAMLTree(dataDir, subdir string) (*YAMLTree, error) { tree := &YAMLTree{Root: []string{}, Dirs: map[string][]string{}} base := filepath.Join(dataDir, subdir) entries, err := os.ReadDir(base) if err != nil { return nil, err } for _, e := range entries { if !e.IsDir() && filepath.Ext(e.Name()) == ".yaml" { tree.Root = append(tree.Root, e.Name()[:len(e.Name())-5]) } } for _, e := range entries { if e.IsDir() { subPath := filepath.Join(base, e.Name()) subEntries, err := os.ReadDir(subPath) if err != nil { continue } var ids []string for _, se := range subEntries { if !se.IsDir() && filepath.Ext(se.Name()) == ".yaml" { ids = append(ids, se.Name()[:len(se.Name())-5]) } } if len(ids) > 0 { tree.Dirs[e.Name()] = ids } } } return tree, nil } func listYAMLFilesDeep(dataDir, subdir string) ([]string, error) { var ids []string base := filepath.Join(dataDir, subdir) err := filepath.WalkDir(base, func(path string, d os.DirEntry, err error) error { if err != nil { return err } if !d.IsDir() && filepath.Ext(d.Name()) == ".yaml" { rel, _ := filepath.Rel(base, path) id := rel[:len(rel)-5] ids = append(ids, id) } return nil }) return ids, err } func backupFile(path string) []byte { data, err := os.ReadFile(path) if err != nil { log.Printf("backup: WARNING failed to read %s: %v (undo will not be able to restore this file)", path, err) return nil } return data } func snapshotFile(path string) ([]byte, error) { return os.ReadFile(path) }