init.go

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