1package config
2
3import (
4 "fmt"
5 "log/slog"
6 "os"
7 "path/filepath"
8 "strings"
9 "sync"
10 "sync/atomic"
11)
12
13const (
14 InitFlagFilename = "init"
15)
16
17type ProjectInitFlag struct {
18 Initialized bool `json:"initialized"`
19}
20
21// TODO: we need to remove the global config instance keeping it now just until everything is migrated
22var (
23 instance atomic.Pointer[Config]
24 cwd string
25 once sync.Once // Ensures the initialization happens only once
26)
27
28func Init(workingDir string, debug bool) (*Config, error) {
29 var err error
30 once.Do(func() {
31 cwd = workingDir
32 cfg, err := Load(cwd, debug)
33 if err != nil {
34 slog.Error("Failed to load config", "error", err)
35 }
36 instance.Store(cfg)
37 })
38
39 return instance.Load(), err
40}
41
42func Get() *Config {
43 return instance.Load()
44}
45
46func ProjectNeedsInitialization() (bool, error) {
47 cfg := Get()
48 if cfg == nil {
49 return false, fmt.Errorf("config not loaded")
50 }
51
52 flagFilePath := filepath.Join(cfg.Options.DataDirectory, InitFlagFilename)
53
54 _, err := os.Stat(flagFilePath)
55 if err == nil {
56 return false, nil
57 }
58
59 if !os.IsNotExist(err) {
60 return false, fmt.Errorf("failed to check init flag file: %w", err)
61 }
62
63 crushExists, err := crushMdExists(cfg.WorkingDir())
64 if err != nil {
65 return false, fmt.Errorf("failed to check for CRUSH.md files: %w", err)
66 }
67 if crushExists {
68 return false, nil
69 }
70
71 return true, nil
72}
73
74func crushMdExists(dir string) (bool, error) {
75 entries, err := os.ReadDir(dir)
76 if err != nil {
77 return false, err
78 }
79
80 for _, entry := range entries {
81 if entry.IsDir() {
82 continue
83 }
84
85 name := strings.ToLower(entry.Name())
86 if name == "crush.md" {
87 return true, nil
88 }
89 }
90
91 return false, nil
92}
93
94func MarkProjectInitialized() error {
95 cfg := Get()
96 if cfg == nil {
97 return fmt.Errorf("config not loaded")
98 }
99 flagFilePath := filepath.Join(cfg.Options.DataDirectory, InitFlagFilename)
100
101 file, err := os.Create(flagFilePath)
102 if err != nil {
103 return fmt.Errorf("failed to create init flag file: %w", err)
104 }
105 defer file.Close()
106
107 return nil
108}