1package config
2
3import (
4 "fmt"
5 "os"
6 "path/filepath"
7 "slices"
8 "strings"
9
10 "github.com/charmbracelet/crush/internal/fsext"
11)
12
13const (
14 InitFlagFilename = "init"
15)
16
17type ProjectInitFlag struct {
18 Initialized bool `json:"initialized"`
19}
20
21func Init(workingDir, dataDir string, debug bool) (*Service, error) {
22 svc, err := Load(workingDir, dataDir, debug)
23 if err != nil {
24 return nil, err
25 }
26 return svc, nil
27}
28
29func ProjectNeedsInitialization(svc *Service) (bool, error) {
30 if svc == nil {
31 return false, fmt.Errorf("config not loaded")
32 }
33
34 flagFilePath := filepath.Join(svc.DataDirectory(), InitFlagFilename)
35
36 _, err := os.Stat(flagFilePath)
37 if err == nil {
38 return false, nil
39 }
40
41 if !os.IsNotExist(err) {
42 return false, fmt.Errorf("failed to check init flag file: %w", err)
43 }
44
45 someContextFileExists, err := contextPathsExist(svc.WorkingDir())
46 if err != nil {
47 return false, fmt.Errorf("failed to check for context files: %w", err)
48 }
49 if someContextFileExists {
50 return false, nil
51 }
52
53 empty, err := dirHasNoVisibleFiles(svc.WorkingDir())
54 if err != nil {
55 return false, fmt.Errorf("failed to check if directory is empty: %w", err)
56 }
57 if empty {
58 return false, nil
59 }
60
61 return true, nil
62}
63
64func contextPathsExist(dir string) (bool, error) {
65 entries, err := os.ReadDir(dir)
66 if err != nil {
67 return false, err
68 }
69
70 // Create a slice of lowercase filenames for lookup with slices.Contains
71 var files []string
72 for _, entry := range entries {
73 if !entry.IsDir() {
74 files = append(files, strings.ToLower(entry.Name()))
75 }
76 }
77
78 // Check if any of the default context paths exist in the directory
79 for _, path := range defaultContextPaths {
80 // Extract just the filename from the path
81 _, filename := filepath.Split(path)
82 filename = strings.ToLower(filename)
83
84 if slices.Contains(files, filename) {
85 return true, nil
86 }
87 }
88
89 return false, nil
90}
91
92// dirHasNoVisibleFiles returns true if the directory has no files/dirs after applying ignore rules
93func dirHasNoVisibleFiles(dir string) (bool, error) {
94 files, _, err := fsext.ListDirectory(dir, nil, 1, 1)
95 if err != nil {
96 return false, err
97 }
98 return len(files) == 0, nil
99}
100
101func MarkProjectInitialized(svc *Service) error {
102 if svc == nil {
103 return fmt.Errorf("config not loaded")
104 }
105 flagFilePath := filepath.Join(svc.DataDirectory(), InitFlagFilename)
106
107 file, err := os.Create(flagFilePath)
108 if err != nil {
109 return fmt.Errorf("failed to create init flag file: %w", err)
110 }
111 defer file.Close()
112
113 return nil
114}
115
116func HasInitialDataConfig(svc *Service) bool {
117 if svc == nil {
118 return false
119 }
120 cfgPath := GlobalConfigData()
121 if _, err := os.Stat(cfgPath); err != nil {
122 return false
123 }
124 return svc.IsConfigured()
125}