diff --git a/internal/config/config.go b/internal/config/config.go index a88f578..5a507d9 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -22,11 +22,13 @@ package config import ( "fmt" "os" + "os/exec" "path/filepath" "github.com/goccy/go-yaml" "github.com/knadh/koanf/providers/confmap" "github.com/knadh/koanf/v2" + ktoml "github.com/knadh/koanf/parsers/toml/v2" "gitea.plemya-x.ru/Plemya-x/ALR/internal/constants" "gitea.plemya-x.ru/Plemya-x/ALR/pkg/types" @@ -134,25 +136,12 @@ func (c *ALRConfig) ToYAML() (string, error) { func (c *ALRConfig) migrateConfig() error { // Проверяем, существует ли конфигурационный файл if _, err := os.Stat(constants.SystemConfigPath); os.IsNotExist(err) { - // Если файла нет, но конфигурация уже загружена (из defaults или env), - // создаем файл с настройкой по умолчанию - needsCreation := false - - // Проверяем, установлена ли переменная окружения ALR_UPDATESYSTEMONUPGRADE - if os.Getenv("ALR_UPDATESYSTEMONUPGRADE") == "" { - // Если переменная не установлена, проверяем наличие пакетов ALR - // чтобы определить, нужно ли включить эту опцию для обновления - needsCreation = true - } - - if needsCreation { - // Устанавливаем значение false по умолчанию для новой опции - c.System.SetUpdateSystemOnUpgrade(false) - // Сохраняем конфигурацию - if err := c.System.Save(); err != nil { - // Если не удается сохранить - это не критично, продолжаем работу - return nil - } + // Если файла нет, создаем полный конфигурационный файл с дефолтными значениями + if err := c.createDefaultConfig(); err != nil { + // Если не удается создать конфиг, это не критично - продолжаем работу + // но выводим предупреждение + fmt.Fprintf(os.Stderr, "Предупреждение: не удалось создать конфигурационный файл %s: %v\n", constants.SystemConfigPath, err) + return nil } } else { // Если файл существует, проверяем, есть ли в нем новая опция @@ -170,6 +159,100 @@ func (c *ALRConfig) migrateConfig() error { return nil } +func (c *ALRConfig) createDefaultConfig() error { + // Проверяем, запущен ли процесс от root + if os.Getuid() != 0 { + // Если не root, пытаемся запустить создание конфига с повышением привилегий + return c.createDefaultConfigWithPrivileges() + } + + // Если уже root, создаем конфиг напрямую + return c.doCreateDefaultConfig() +} + +func (c *ALRConfig) createDefaultConfigWithPrivileges() error { + // Если useRootCmd отключен, просто пытаемся создать без повышения привилегий + if !c.cfg.UseRootCmd { + return c.doCreateDefaultConfig() + } + + // Определяем команду для повышения привилегий + rootCmd := c.cfg.RootCmd + if rootCmd == "" { + rootCmd = "sudo" // fallback + } + + // Создаем временный файл с дефолтной конфигурацией + tmpFile, err := os.CreateTemp("", "alr-config-*.toml") + if err != nil { + return fmt.Errorf("не удалось создать временный файл: %w", err) + } + defer os.Remove(tmpFile.Name()) + defer tmpFile.Close() + + // Генерируем дефолтную конфигурацию во временный файл + defaults := defaultConfigKoanf() + tempSystemConfig := &SystemConfig{k: defaults} + + bytes, err := tempSystemConfig.k.Marshal(ktoml.Parser()) + if err != nil { + return fmt.Errorf("не удалось сериализовать конфигурацию: %w", err) + } + + if _, err := tmpFile.Write(bytes); err != nil { + return fmt.Errorf("не удалось записать во временный файл: %w", err) + } + tmpFile.Close() + + // Используем команду повышения привилегий для создания директории и копирования файла + + // Создаем директорию с правами + configDir := filepath.Dir(constants.SystemConfigPath) + mkdirCmd := exec.Command(rootCmd, "mkdir", "-p", configDir) + if err := mkdirCmd.Run(); err != nil { + return fmt.Errorf("не удалось создать директорию %s: %w", configDir, err) + } + + // Копируем файл в нужное место + cpCmd := exec.Command(rootCmd, "cp", tmpFile.Name(), constants.SystemConfigPath) + if err := cpCmd.Run(); err != nil { + return fmt.Errorf("не удалось скопировать конфигурацию в %s: %w", constants.SystemConfigPath, err) + } + + // Устанавливаем правильные права доступа + chmodCmd := exec.Command(rootCmd, "chmod", "644", constants.SystemConfigPath) + if err := chmodCmd.Run(); err != nil { + // Не критично, продолжаем + fmt.Fprintf(os.Stderr, "Предупреждение: не удалось установить права доступа для %s: %v\n", constants.SystemConfigPath, err) + } + + return nil +} + +func (c *ALRConfig) doCreateDefaultConfig() error { + // Проверяем, существует ли директория для конфига + configDir := filepath.Dir(constants.SystemConfigPath) + if _, err := os.Stat(configDir); os.IsNotExist(err) { + // Пытаемся создать директорию + if err := os.MkdirAll(configDir, 0755); err != nil { + return fmt.Errorf("не удалось создать директорию %s: %w", configDir, err) + } + } + + // Загружаем дефолтную конфигурацию + defaults := defaultConfigKoanf() + + // Копируем все дефолтные значения в системную конфигурацию + c.System.k = defaults + + // Сохраняем конфигурацию в файл + if err := c.System.Save(); err != nil { + return fmt.Errorf("не удалось сохранить конфигурацию в %s: %w", constants.SystemConfigPath, err) + } + + return nil +} + func (c *ALRConfig) RootCmd() string { return c.cfg.RootCmd } func (c *ALRConfig) PagerStyle() string { return c.cfg.PagerStyle } func (c *ALRConfig) AutoPull() bool { return c.cfg.AutoPull }