1package config
  2
  3import (
  4	"fmt"
  5	"os"
  6	"path/filepath"
  7	"slices"
  8	"strings"
  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 instance atomic.Pointer[Config]
 22
 23func Init(workingDir, dataDir string, debug bool) (*Config, error) {
 24	cfg, err := Load(workingDir, dataDir, debug)
 25	if err != nil {
 26		return nil, err
 27	}
 28	instance.Store(cfg)
 29	return instance.Load(), nil
 30}
 31
 32func Get() *Config {
 33	cfg := instance.Load()
 34	return cfg
 35}
 36
 37func ProjectNeedsInitialization() (bool, error) {
 38	cfg := Get()
 39	if cfg == nil {
 40		return false, fmt.Errorf("config not loaded")
 41	}
 42
 43	flagFilePath := filepath.Join(cfg.Options.DataDirectory, InitFlagFilename)
 44
 45	_, err := os.Stat(flagFilePath)
 46	if err == nil {
 47		return false, nil
 48	}
 49
 50	if !os.IsNotExist(err) {
 51		return false, fmt.Errorf("failed to check init flag file: %w", err)
 52	}
 53
 54	someContextFileExists, err := contextPathsExist(cfg.WorkingDir())
 55	if err != nil {
 56		return false, fmt.Errorf("failed to check for context files: %w", err)
 57	}
 58	if someContextFileExists {
 59		return false, nil
 60	}
 61
 62	return true, nil
 63}
 64
 65func contextPathsExist(dir string) (bool, error) {
 66	entries, err := os.ReadDir(dir)
 67	if err != nil {
 68		return false, err
 69	}
 70
 71	// Create a slice of lowercase filenames for lookup with slices.Contains
 72	var files []string
 73	for _, entry := range entries {
 74		if !entry.IsDir() {
 75			files = append(files, strings.ToLower(entry.Name()))
 76		}
 77	}
 78
 79	// Check if any of the default context paths exist in the directory
 80	for _, path := range defaultContextPaths {
 81		// Extract just the filename from the path
 82		_, filename := filepath.Split(path)
 83		filename = strings.ToLower(filename)
 84
 85		if slices.Contains(files, filename) {
 86			return true, nil
 87		}
 88	}
 89
 90	return false, nil
 91}
 92
 93func MarkProjectInitialized() error {
 94	cfg := Get()
 95	if cfg == nil {
 96		return fmt.Errorf("config not loaded")
 97	}
 98	flagFilePath := filepath.Join(cfg.Options.DataDirectory, InitFlagFilename)
 99
100	file, err := os.Create(flagFilePath)
101	if err != nil {
102		return fmt.Errorf("failed to create init flag file: %w", err)
103	}
104	defer file.Close()
105
106	return nil
107}
108
109func HasInitialDataConfig() bool {
110	cfgPath := GlobalConfigData()
111	if _, err := os.Stat(cfgPath); err != nil {
112		return false
113	}
114	return Get().IsConfigured()
115}