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