This commit is contained in:
naudachu
2026-01-28 16:24:21 +05:00
commit e10b389661
38 changed files with 5909 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
package config
const (
// DefaultConfigDir is the directory for global config
DefaultConfigDir = ".config/aevs"
// DefaultGlobalConfigFile is the global config filename
DefaultGlobalConfigFile = "config.yaml"
// DefaultProjectConfigFile is the project config filename
DefaultProjectConfigFile = "aevs.yaml"
// DefaultStorageType is the default storage backend
DefaultStorageType = "s3"
// DefaultRegion is the default AWS region
DefaultRegion = "us-east-1"
// DefaultEndpoint is the default S3 endpoint
DefaultEndpoint = "https://s3.amazonaws.com"
// ArchiveFileName is the name of the archive in storage
ArchiveFileName = "envs.tar.gz"
// MetadataFileName is the name of the metadata file in storage
MetadataFileName = "metadata.json"
)
+89
View File
@@ -0,0 +1,89 @@
package config
import (
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
// GlobalConfig represents ~/.config/aevs/config.yaml
type GlobalConfig struct {
Storage StorageConfig `yaml:"storage"`
}
// StorageConfig holds S3-compatible storage credentials
type StorageConfig struct {
Type string `yaml:"type"` // storage type: "s3"
Endpoint string `yaml:"endpoint"` // S3 endpoint URL
Region string `yaml:"region"` // AWS region (optional, default: us-east-1)
Bucket string `yaml:"bucket"` // S3 bucket name
AccessKey string `yaml:"access_key"` // AWS Access Key ID
SecretKey string `yaml:"secret_key"` // AWS Secret Access Key
}
// GlobalConfigPath returns the full path to the global config file
func GlobalConfigPath() string {
home, err := os.UserHomeDir()
if err != nil {
return ""
}
return filepath.Join(home, DefaultConfigDir, DefaultGlobalConfigFile)
}
// GlobalConfigExists checks if the global config file exists
func GlobalConfigExists() bool {
path := GlobalConfigPath()
if path == "" {
return false
}
_, err := os.Stat(path)
return err == nil
}
// LoadGlobalConfig loads the global config from ~/.config/aevs/config.yaml
func LoadGlobalConfig() (*GlobalConfig, error) {
path := GlobalConfigPath()
if path == "" {
return nil, os.ErrNotExist
}
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var cfg GlobalConfig
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, err
}
return &cfg, nil
}
// SaveGlobalConfig saves the global config to ~/.config/aevs/config.yaml with 0600 permissions
func SaveGlobalConfig(cfg *GlobalConfig) error {
path := GlobalConfigPath()
if path == "" {
return os.ErrNotExist
}
// Ensure directory exists
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0700); err != nil {
return err
}
// Marshal to YAML
data, err := yaml.Marshal(cfg)
if err != nil {
return err
}
// Write with secure permissions (0600)
if err := os.WriteFile(path, data, 0600); err != nil {
return err
}
return nil
}
+72
View File
@@ -0,0 +1,72 @@
package config
import (
"fmt"
"os"
"regexp"
"gopkg.in/yaml.v3"
)
// ProjectConfig represents ./aevs.yaml
type ProjectConfig struct {
Project string `yaml:"project"` // unique project identifier
Files []string `yaml:"files"` // list of file paths to sync
}
// projectNameRegex validates project names (only a-z, 0-9, -, _)
var projectNameRegex = regexp.MustCompile(`^[a-z0-9_-]+$`)
// LoadProjectConfig loads a project config from the specified path
func LoadProjectConfig(path string) (*ProjectConfig, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var cfg ProjectConfig
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, err
}
// Validate project name
if err := ValidateProjectName(cfg.Project); err != nil {
return nil, err
}
return &cfg, nil
}
// SaveProjectConfig saves a project config to the specified path
func SaveProjectConfig(path string, cfg *ProjectConfig) error {
// Validate project name before saving
if err := ValidateProjectName(cfg.Project); err != nil {
return err
}
// Marshal to YAML
data, err := yaml.Marshal(cfg)
if err != nil {
return err
}
// Write file
if err := os.WriteFile(path, data, 0644); err != nil {
return err
}
return nil
}
// ValidateProjectName checks if the project name contains only a-z, 0-9, -, _
func ValidateProjectName(name string) error {
if name == "" {
return fmt.Errorf("project name cannot be empty")
}
if !projectNameRegex.MatchString(name) {
return fmt.Errorf("invalid project name %q; use only a-z, 0-9, -, _", name)
}
return nil
}