100 lines
2.3 KiB
Go
100 lines
2.3 KiB
Go
package stack
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
|
|
"gitea.oxpoe.qzz.io/oxpoe/tia-love/internal/docker"
|
|
)
|
|
|
|
// ComposeFileNames — nama file compose yang diterima (REA modul 2 — Dockge).
|
|
var ComposeFileNames = []string{"compose.yaml", "docker-compose.yaml", "docker-compose.yml", "compose.yml"}
|
|
|
|
// Status — status stack (nilai mengikuti referensi Dockge).
|
|
type Status int
|
|
|
|
const (
|
|
StatusUnknown Status = iota
|
|
StatusCreatedFile
|
|
StatusCreatedStack
|
|
StatusRunning
|
|
StatusExited
|
|
)
|
|
|
|
// Stack — satu stack terkelola di direktori stack.
|
|
type Stack struct {
|
|
Name string
|
|
Dir string
|
|
ComposeFile string
|
|
Status Status
|
|
}
|
|
|
|
// ScanFS — daftar stack dari disk: setiap subfolder yang berisi file compose.
|
|
// Folder tidak ada → daftar kosong, bukan error (belum onboarding).
|
|
func ScanFS(dir string) ([]Stack, error) {
|
|
entries, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
var out []Stack
|
|
for _, e := range entries {
|
|
if !e.IsDir() {
|
|
continue
|
|
}
|
|
stackDir := filepath.Join(dir, e.Name())
|
|
if f := findComposeFile(stackDir); f != "" {
|
|
out = append(out, Stack{
|
|
Name: e.Name(),
|
|
Dir: stackDir,
|
|
ComposeFile: f,
|
|
Status: StatusCreatedFile,
|
|
})
|
|
}
|
|
}
|
|
sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })
|
|
return out, nil
|
|
}
|
|
|
|
func findComposeFile(dir string) string {
|
|
for _, name := range ComposeFileNames {
|
|
p := filepath.Join(dir, name)
|
|
if st, err := os.Stat(p); err == nil && !st.IsDir() {
|
|
return p
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Reconcile — overlay status dari `docker compose ls` (parity Dockge:
|
|
// nama project compose = nama folder stack).
|
|
func Reconcile(stacks []Stack, projects []docker.ComposeProject) []Stack {
|
|
byName := make(map[string]Status, len(projects))
|
|
for _, p := range projects {
|
|
byName[p.Name] = parseComposeStatus(p.Status)
|
|
}
|
|
for i := range stacks {
|
|
if s, ok := byName[stacks[i].Name]; ok {
|
|
stacks[i].Status = s
|
|
}
|
|
}
|
|
return stacks
|
|
}
|
|
|
|
func parseComposeStatus(s string) Status {
|
|
switch {
|
|
case strings.HasPrefix(s, "running"):
|
|
return StatusRunning
|
|
case strings.HasPrefix(s, "exited"):
|
|
return StatusExited
|
|
case strings.HasPrefix(s, "created"):
|
|
return StatusCreatedStack
|
|
default:
|
|
return StatusUnknown
|
|
}
|
|
}
|