Commit e64e7d14 authored by Kirill Unitsaev's avatar Kirill Unitsaev

preset: integrate status indicators into result output

parent 6eeca1f8
......@@ -22,7 +22,7 @@ var (
validActions = []string{"enable", "disable", "remove"}
)
func processCopies(prof config.PresetProfile, opts opOptions, res *config.PresetResult) {
func processCopies(prof config.PresetProfile, opts opOptions, res *Result) {
for _, c := range prof.Copy {
src := expandPath(c.Src, "")
dest := expandPath(c.Dest, "")
......@@ -31,7 +31,7 @@ func processCopies(prof config.PresetProfile, opts opOptions, res *config.Preset
}
}
func processLinks(prof config.PresetProfile, opts opOptions, res *config.PresetResult) {
func processLinks(prof config.PresetProfile, opts opOptions, res *Result) {
for _, entry := range prof.Links {
handle := func(app string) {
......@@ -58,31 +58,40 @@ func processLinks(prof config.PresetProfile, opts opOptions, res *config.PresetR
}
}
func processReleaseReplace(prof config.PresetProfile, opts opOptions, res *config.PresetResult) {
func processReleaseReplace(prof config.PresetProfile, opts opOptions, res *Result) {
sysVer := getSystemVersion()
for _, rr := range prof.ReleaseReplace {
src := expandPath(rr.Src, "")
dest := expandPath(rr.Dest, "")
msg := handleReleaseReplace(src, dest, sysVer, opts)
res.Replaced = append(res.Replaced, msg)
item := handleReleaseReplace(src, dest, sysVer, opts)
res.Replaced = append(res.Replaced, item)
}
}
func handleReleaseReplace(src, dest, sysVer string, opts opOptions) string {
func handleReleaseReplace(src, dest, sysVer string, opts opOptions) ui.TreeItem {
if _, err := os.Stat(dest); os.IsNotExist(err) {
return fmt.Sprintf("Не найден: '%s' — пропущен", dest)
return ui.TreeItem{
Name: fmt.Sprintf("Не найден: '%s'", dest),
Status: config.OpStatus.Skipped,
}
}
data, err := os.ReadFile(dest)
if err != nil {
return fmt.Sprintf("Не удалось прочитать %s: %v", dest, err)
return ui.TreeItem{
Name: fmt.Sprintf("Не удалось прочитать %s: %v", dest, err),
Status: config.OpStatus.Error,
}
}
content := string(data)
if strings.Contains(content, "XIMPER_LOCK") {
return fmt.Sprintf("Заблокирован: %s — пропущен", dest)
return ui.TreeItem{
Name: fmt.Sprintf("Заблокирован: %s", dest),
Status: config.OpStatus.Skipped,
}
}
fileVer := getFileVersionTag(dest)
......@@ -91,59 +100,83 @@ func handleReleaseReplace(src, dest, sysVer string, opts opOptions) string {
}
if fileVer == sysVer {
return fmt.Sprintf("Актуально: '%s' — пропущено", dest)
return ui.TreeItem{
Name: fmt.Sprintf("Актуально: '%s'", dest),
Status: config.OpStatus.Skipped,
}
}
if opts.DryRun {
return fmt.Sprintf("[Dry-run] Заменён: %s на %s", dest, src)
return ui.TreeItem{
Name: fmt.Sprintf("%s → %s", src, dest),
Status: config.OpStatus.DryRun,
}
}
_ = os.Rename(dest, dest+".old")
if err := copyFile(src, dest); err != nil {
return fmt.Sprintf("Ошибка замены %s: %v", dest, err)
return ui.TreeItem{
Name: fmt.Sprintf("Ошибка замены %s: %v", dest, err),
Status: config.OpStatus.Error,
}
}
return fmt.Sprintf("Обновлён: %s (%s → %s)", dest, fileVer, sysVer)
return ui.TreeItem{
Name: fmt.Sprintf("%s (%s → %s)", dest, fileVer, sysVer),
Status: config.OpStatus.Done,
}
}
func processHyprVars(manager *hyprland.HyprlandManager, prof config.PresetProfile, opts opOptions, res *config.PresetResult) {
func processHyprVars(manager *hyprland.HyprlandManager, prof config.PresetProfile, opts opOptions, res *Result) {
for _, v := range prof.Hyprland.Vars {
if !v.Force {
if V := manager.GetVar(v.Var); V != "" {
res.HyprVars = append(res.HyprVars,
fmt.Sprintf("Уже существует: '%s' — пропущено", v.Var))
res.HyprVars = append(res.HyprVars, ui.TreeItem{
Name: fmt.Sprintf("Уже существует: '%s'", v.Var),
Status: config.OpStatus.Skipped,
})
continue
}
}
if opts.DryRun {
res.HyprVars = append(res.HyprVars,
fmt.Sprintf("[Dry-run] Установлена переменная: %s = %s", v.Var, v.Value))
res.HyprVars = append(res.HyprVars, ui.TreeItem{
Name: fmt.Sprintf("%s = %s", v.Var, v.Value),
Status: config.OpStatus.DryRun,
})
continue
}
if _, err := manager.SetVar(v.Var, v.Value); err != nil {
res.HyprVars = append(res.HyprVars,
fmt.Sprintf("Ошибка установки %s: %v", v.Var, err))
res.HyprVars = append(res.HyprVars, ui.TreeItem{
Name: fmt.Sprintf("Ошибка установки %s: %v", v.Var, err),
Status: config.OpStatus.Error,
})
} else {
res.HyprVars = append(res.HyprVars,
fmt.Sprintf("Установлена переменная: %s = %s", v.Var, v.Value))
res.HyprVars = append(res.HyprVars, ui.TreeItem{
Name: fmt.Sprintf("%s = %s", v.Var, v.Value),
Status: config.OpStatus.Done,
})
}
}
}
func processHyprModules(manager *hyprland.HyprlandManager, prof config.PresetProfile, opts opOptions, res *config.PresetResult) {
func processHyprModules(manager *hyprland.HyprlandManager, prof config.PresetProfile, opts opOptions, res *Result) {
for _, m := range prof.Hyprland.Modules {
if m.Module == "" {
res.HyprModules = append(res.HyprModules, "Пропущен модуль без имени")
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: "Пропущен модуль без имени",
Status: config.OpStatus.Skipped,
})
continue
}
if !slices.Contains(validActions, m.Action) {
res.HyprModules = append(res.HyprModules,
fmt.Sprintf("Модуль '%s' пропущен: неподдерживаемый action",
m.Module))
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: fmt.Sprintf("Модуль '%s': неподдерживаемый action", m.Module),
Status: config.OpStatus.Skipped,
})
continue
}
......@@ -152,24 +185,28 @@ func processHyprModules(manager *hyprland.HyprlandManager, prof config.PresetPro
cmd := exec.Command("sh", "-c", m.IfExec)
output, err := cmd.Output()
if err != nil {
res.HyprModules = append(res.HyprModules,
fmt.Sprintf("Модуль '%s' пропущен: команда '%s' завершилась с ошибкой",
m.Module, m.IfExec))
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: fmt.Sprintf("Модуль '%s': команда '%s' завершилась с ошибкой", m.Module, m.IfExec),
Status: config.OpStatus.Skipped,
})
continue
}
if len(bytes.TrimSpace(output)) == 0 {
res.HyprModules = append(res.HyprModules,
fmt.Sprintf("Модуль '%s' пропущен: команда '%s' не вернула данных",
m.Module, m.IfExec))
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: fmt.Sprintf("Модуль '%s': команда '%s' не вернула данных", m.Module, m.IfExec),
Status: config.OpStatus.Skipped,
})
continue
}
}
// if-binary
if m.IfBinary != "" && !commandExists(m.IfBinary) {
res.HyprModules = append(res.HyprModules,
fmt.Sprintf("Модуль '%s' пропущен: бинарник '%s' не найден", m.Module, m.IfBinary))
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: fmt.Sprintf("Модуль '%s': бинарник '%s' не найден", m.Module, m.IfBinary),
Status: config.OpStatus.Skipped,
})
continue
}
......@@ -178,28 +215,35 @@ func processHyprModules(manager *hyprland.HyprlandManager, prof config.PresetPro
if _, err := os.Stat(modulefile); os.IsNotExist(err) {
if opts.DryRun {
res.HyprModules = append(res.HyprModules,
fmt.Sprintf("[Dry-run] Создан пустой модуль: %s", m.Module))
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: fmt.Sprintf("Создан пустой модуль: %s", m.Module),
Status: config.OpStatus.DryRun,
})
} else {
_ = os.WriteFile(modulefile, []byte(""), 0o644)
res.HyprModules = append(res.HyprModules,
fmt.Sprintf("Создан пустой модуль: %s", m.Module))
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: fmt.Sprintf("Создан пустой модуль: %s", m.Module),
Status: config.OpStatus.Done,
})
}
}
}
// dry-run
if opts.DryRun {
var dryrunmessage string
var msg string
switch m.Action {
case "enable":
dryrunmessage = fmt.Sprintf("[Dry-run] Подключён модуль: %s", m.Module)
msg = fmt.Sprintf("Подключён модуль: %s", m.Module)
case "disable":
dryrunmessage = fmt.Sprintf("[Dry-run] Отключён модуль: %s", m.Module)
msg = fmt.Sprintf("Отключён модуль: %s", m.Module)
case "remove":
dryrunmessage = fmt.Sprintf("[Dry-run] Удалён модуль: %s", m.Module)
msg = fmt.Sprintf("Удалён модуль: %s", m.Module)
}
res.HyprModules = append(res.HyprModules, dryrunmessage)
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: msg,
Status: config.OpStatus.DryRun,
})
continue
}
......@@ -209,38 +253,47 @@ func processHyprModules(manager *hyprland.HyprlandManager, prof config.PresetPro
m.User,
m.NewOnly,
); err != nil {
res.HyprModules = append(res.HyprModules,
fmt.Sprintf("Ошибка (%s): %v", m.Module, err))
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: fmt.Sprintf("Ошибка (%s): %v", m.Module, err),
Status: config.OpStatus.Error,
})
} else {
var message string
var msg string
switch m.Action {
case "enable":
message = fmt.Sprintf("Подключён модуль: %s", m.Module)
msg = fmt.Sprintf("Подключён модуль: %s", m.Module)
case "disable":
message = fmt.Sprintf("Отключён модуль: %s", m.Module)
msg = fmt.Sprintf("Отключён модуль: %s", m.Module)
case "remove":
message = fmt.Sprintf("Удалён модуль: %s", m.Module)
msg = fmt.Sprintf("Удалён модуль: %s", m.Module)
}
res.HyprModules = append(res.HyprModules, message)
res.HyprModules = append(res.HyprModules, ui.TreeItem{
Name: msg,
Status: config.OpStatus.Done,
})
}
}
}
func processHyprLayoutSync(manager *hyprland.HyprlandManager, prof config.PresetProfile, opts opOptions, res *config.PresetResult) {
func processHyprLayoutSync(manager *hyprland.HyprlandManager, prof config.PresetProfile, opts opOptions, res *Result) {
if !prof.Hyprland.Option.SyncSystemLayouts {
return
}
if opts.DryRun {
res.SyncSystemLayouts = append(res.SyncSystemLayouts,
"[Dry-run] Синхронизация раскладок Hyprland пропущена")
res.SyncSystemLayouts = append(res.SyncSystemLayouts, ui.TreeItem{
Name: "Синхронизация раскладок Hyprland",
Status: config.OpStatus.DryRun,
})
return
}
sysLayouts, err := hyprland.HyprlandGetKeyboardLayouts()
if err != nil {
res.SyncSystemLayouts = append(res.SyncSystemLayouts,
"Не удалось получить системные раскладки")
res.SyncSystemLayouts = append(res.SyncSystemLayouts, ui.TreeItem{
Name: "Не удалось получить системные раскладки",
Status: config.OpStatus.Error,
})
return
}
......@@ -250,48 +303,73 @@ func processHyprLayoutSync(manager *hyprland.HyprlandManager, prof config.Preset
hyprLayouts = "<empty>"
}
res.SyncSystemLayouts = append(res.SyncSystemLayouts,
fmt.Sprintf("Раскладка XCB: %s", sysLayouts))
res.SyncSystemLayouts = append(res.SyncSystemLayouts,
fmt.Sprintf("Раскладка Hyprland: %s", hyprLayouts))
res.SyncSystemLayouts = append(res.SyncSystemLayouts, ui.TreeItem{
Name: fmt.Sprintf("Раскладка XCB: %s", sysLayouts),
Status: config.OpStatus.Done,
})
res.SyncSystemLayouts = append(res.SyncSystemLayouts, ui.TreeItem{
Name: fmt.Sprintf("Раскладка Hyprland: %s", hyprLayouts),
Status: config.OpStatus.Done,
})
if hyprLayouts == "<empty>" {
if _, err := manager.SetVar("kb_layout", sysLayouts); err != nil {
res.SyncSystemLayouts = append(res.SyncSystemLayouts,
"Не удалось обновить kb_layout")
res.SyncSystemLayouts = append(res.SyncSystemLayouts, ui.TreeItem{
Name: "Не удалось обновить kb_layout",
Status: config.OpStatus.Error,
})
return
}
res.SyncSystemLayouts = append(res.SyncSystemLayouts,
fmt.Sprintf("Раскладка обновлена: %s", sysLayouts))
res.SyncSystemLayouts = append(res.SyncSystemLayouts, ui.TreeItem{
Name: fmt.Sprintf("Раскладка обновлена: %s", sysLayouts),
Status: config.OpStatus.Done,
})
} else {
res.SyncSystemLayouts = append(res.SyncSystemLayouts,
fmt.Sprintf("Раскладка уже установлена: %s", hyprLayouts))
res.SyncSystemLayouts = append(res.SyncSystemLayouts, ui.TreeItem{
Name: fmt.Sprintf("Раскладка уже установлена: %s", hyprLayouts),
Status: config.OpStatus.Skipped,
})
}
}
func processSystemGrub(prof config.PresetProfile, opts opOptions, res *config.PresetResult) {
func processSystemGrub(prof config.PresetProfile, opts opOptions, res *Result) {
if prof.System.Grub.FixResolution {
autoUpdate := prof.System.Grub.Update
if opts.DryRun {
res.System = append(res.System, "[Dry-run] GRUB_GFXMODE не исправлен")
res.System = append(res.System, ui.TreeItem{
Name: "GRUB_GFXMODE",
Status: config.OpStatus.DryRun,
})
if autoUpdate {
res.System = append(res.System, "[Dry-run] update-grub не выполнен")
res.System = append(res.System, ui.TreeItem{
Name: "update-grub",
Status: config.OpStatus.DryRun,
})
}
} else {
err := system.SystemGrubFixResolution(autoUpdate, false)
if err != nil {
res.System = append(res.System, fmt.Sprintf("Ошибка GRUB: %v", err))
res.System = append(res.System, ui.TreeItem{
Name: fmt.Sprintf("Ошибка GRUB: %v", err),
Status: config.OpStatus.Error,
})
} else {
res.System = append(res.System, "GRUB_GFXMODE исправлен")
res.System = append(res.System, ui.TreeItem{
Name: "GRUB_GFXMODE исправлен",
Status: config.OpStatus.Done,
})
if autoUpdate {
res.System = append(res.System, "update-grub выполнен")
res.System = append(res.System, ui.TreeItem{
Name: "update-grub выполнен",
Status: config.OpStatus.Done,
})
}
}
}
}
}
func processProfile(prof config.PresetProfile, dryRun bool, res *config.PresetResult) {
func processProfile(prof config.PresetProfile, dryRun bool, res *Result) {
opts := opOptions{DryRun: dryRun}
processCopies(prof, opts, res)
......@@ -309,7 +387,7 @@ func processProfile(prof config.PresetProfile, dryRun bool, res *config.PresetRe
processHyprLayoutSync(manager, prof, opts, res)
}
func createProfile(profileName string, prof config.PresetProfile, dryRun bool, res *config.PresetResult) {
func createProfile(profileName string, prof config.PresetProfile, dryRun bool, res *Result) {
color.Green("Создаётся профиль: %s", profileName)
if !profileAvailable(prof) {
color.Red("Профиль %s недоступен", profileName)
......@@ -364,7 +442,7 @@ func presetApplyCommand(ctx context.Context, cmd *cli.Command) error {
return nil
}
res := &config.PresetResult{}
res := &Result{}
createProfile(profileName, mainProf, dryRun, res)
renderPresetResult(res)
......@@ -388,7 +466,7 @@ func presetApplyAllCommand(ctx context.Context, cmd *cli.Command) error {
continue
}
res := &config.PresetResult{}
res := &Result{}
createProfile(name, prof, dryRun, res)
renderPresetResult(res)
}
......
......@@ -34,25 +34,27 @@ func profileStatus(p config.PresetProfile) config.ItemStatus {
return config.ProfileStatus.Unavailable
}
func AppendOpResult(res *config.PresetResult, r opResult) {
var msg string
func AppendOpResult(res *Result, r opResult) {
item := ui.TreeItem{
Status: r.Status,
}
switch r.Status {
case StatusSkipped:
msg = fmt.Sprintf("Уже существует: %s — пропущено", r.Target)
case StatusDryRun:
msg = fmt.Sprintf("[Dry-run] %s → %s", r.Source, r.Target)
case StatusDone:
msg = fmt.Sprintf("Выполнено: %s → %s", r.Source, r.Target)
case StatusError:
msg = fmt.Sprintf("Ошибка: %s", r.Reason)
switch {
case r.Status.IsEqual(config.OpStatus.Skipped):
item.Name = fmt.Sprintf("Уже существует: %s", r.Target)
case r.Status.IsEqual(config.OpStatus.DryRun):
item.Name = fmt.Sprintf("%s → %s", r.Source, r.Target)
case r.Status.IsEqual(config.OpStatus.Done):
item.Name = fmt.Sprintf("%s → %s", r.Source, r.Target)
case r.Status.IsEqual(config.OpStatus.Error):
item.Name = fmt.Sprintf("Ошибка: %s", r.Reason)
}
switch r.Kind {
case OpCopy:
res.Copies = append(res.Copies, msg)
res.Copies = append(res.Copies, item)
case OpLink:
res.Links = append(res.Links, msg)
res.Links = append(res.Links, item)
}
}
......@@ -78,12 +80,12 @@ func expandPath(path, name string) string {
return path
}
func renderPresetResult(res *config.PresetResult) {
ui.RenderTreeLines("Копируем", res.Copies)
ui.RenderTreeLines("Создаём ссылки", res.Links)
ui.RenderTreeLines("Обновляем", res.Replaced)
ui.RenderTreeLines("Настраиваем систему", res.System)
ui.RenderTreeLines("Создаём переменные Hyprland", res.HyprVars)
ui.RenderTreeLines("Подключаем модули Hyprland", res.HyprModules)
ui.RenderTreeLines("Синхронизируем раскладку Hyprland", res.SyncSystemLayouts)
func renderPresetResult(res *Result) {
ui.RenderTreeItems("Копируем", res.Copies)
ui.RenderTreeItems("Создаём ссылки", res.Links)
ui.RenderTreeItems("Обновляем", res.Replaced)
ui.RenderTreeItems("Настраиваем систему", res.System)
ui.RenderTreeItems("Создаём переменные Hyprland", res.HyprVars)
ui.RenderTreeItems("Подключаем модули Hyprland", res.HyprModules)
ui.RenderTreeItems("Синхронизируем раскладку Hyprland", res.SyncSystemLayouts)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment