Implement opal-task Phase 1: Database foundation
- Add SQLite database with schema for tasks, tags, and working_set - Implement config management with Viper (opal.yml) - Create Task struct with proper types (*time.Time, Priority int) - Add database migration system - Implement recurrence pattern parsing (1d, 1w, 1m, 1y) - Setup project structure with cmd/ and internal/engine/ - Add dependencies: sqlite3, uuid, cobra, viper, color
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
DefaultFilter string `mapstructure:"default_filter"`
|
||||
DefaultSort string `mapstructure:"default_sort"`
|
||||
ColorOutput bool `mapstructure:"color_output"`
|
||||
}
|
||||
|
||||
var globalConfig *Config
|
||||
|
||||
// GetConfigDir returns the configuration directory path
|
||||
func GetConfigDir() (string, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get home directory: %w", err)
|
||||
}
|
||||
return filepath.Join(home, ".config", "jade"), nil
|
||||
}
|
||||
|
||||
// GetDBPath returns the path to the SQLite database
|
||||
func GetDBPath() (string, error) {
|
||||
configDir, err := GetConfigDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(configDir, "opal.db"), nil
|
||||
}
|
||||
|
||||
// GetConfigPath returns the path to the config file
|
||||
func GetConfigPath() (string, error) {
|
||||
configDir, err := GetConfigDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(configDir, "opal.yml"), nil
|
||||
}
|
||||
|
||||
// LoadConfig loads the configuration from file or creates default
|
||||
func LoadConfig() (*Config, error) {
|
||||
if globalConfig != nil {
|
||||
return globalConfig, nil
|
||||
}
|
||||
|
||||
configDir, err := GetConfigDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure config directory exists
|
||||
if err := os.MkdirAll(configDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create config directory: %w", err)
|
||||
}
|
||||
|
||||
configPath, err := GetConfigPath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := viper.New()
|
||||
v.SetConfigFile(configPath)
|
||||
v.SetConfigType("yaml")
|
||||
|
||||
// Set defaults
|
||||
v.SetDefault("default_filter", "status:pending")
|
||||
v.SetDefault("default_sort", "due,priority")
|
||||
v.SetDefault("color_output", true)
|
||||
|
||||
// Try to read existing config
|
||||
err = v.ReadInConfig()
|
||||
if err != nil {
|
||||
// Config doesn't exist, create it with defaults
|
||||
// Write config with defaults (ignoring the error type check for now)
|
||||
if err := v.WriteConfigAs(configPath); err != nil {
|
||||
return nil, fmt.Errorf("failed to create config file: %w", err)
|
||||
}
|
||||
// Try reading again
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
return nil, fmt.Errorf("failed to read newly created config: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
cfg := &Config{}
|
||||
if err := v.Unmarshal(cfg); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
||||
}
|
||||
|
||||
globalConfig = cfg
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// SaveConfig saves the configuration to file
|
||||
func SaveConfig(cfg *Config) error {
|
||||
configPath, err := GetConfigPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v := viper.New()
|
||||
v.SetConfigFile(configPath)
|
||||
v.SetConfigType("yaml")
|
||||
|
||||
v.Set("default_filter", cfg.DefaultFilter)
|
||||
v.Set("default_sort", cfg.DefaultSort)
|
||||
v.Set("color_output", cfg.ColorOutput)
|
||||
|
||||
return v.WriteConfig()
|
||||
}
|
||||
|
||||
// GetConfig returns the loaded config or loads it if not already loaded
|
||||
func GetConfig() (*Config, error) {
|
||||
if globalConfig != nil {
|
||||
return globalConfig, nil
|
||||
}
|
||||
return LoadConfig()
|
||||
}
|
||||
Reference in New Issue
Block a user