Files
backup-master/internal/restore/order.go
T
mrleo1nidandClaude Opus 5.5 1d44d067e9 backup-master: сервер бэкапов, агент и восстановление VPS
Один бинарник backupctl:
- server: API для агентов и restore, веб-морда (один админ), SQLite,
  ретеншн GFS, heavy-части, уведомления ntfy, раздача agent.sh/restore.sh;
- backup/plan: сбор по каталогу категорий (files/systemd/xui/compose),
  горячие дампы Postgres/Mongo/MySQL, снимок x-ui.db, docker-тома,
  digest образов, проверка crontab, потоковая отправка tar.zst;
- restore: провижининг на основе vps_installer с теми же версиями пакетов,
  recipes 3x-ui/nebula/sing-box нужных версий, восстановление compose
  с заливкой дампов и закреплением образов по digest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 21:52:40 +03:00

45 lines
1.1 KiB
Go

package restore
import "gitea.hsrv.site/mrleo1nid/backup-master/internal/manifest"
// order сортирует категории так, чтобы restore_after шли раньше зависящих от них.
// Порядок манифеста сохраняется, отсутствующие зависимости игнорируются, при цикле
// оставшиеся категории идут в исходном порядке.
func order(cats []manifest.Category) []manifest.Category {
idx := map[string]int{}
for i, c := range cats {
idx[c.Name] = i
}
done := make([]bool, len(cats))
var out []manifest.Category
for len(out) < len(cats) {
progressed := false
for i, c := range cats {
if done[i] {
continue
}
ready := true
for _, dep := range c.RestoreAfter {
if j, ok := idx[dep]; ok && !done[j] && j != i {
ready = false
break
}
}
if ready {
done[i] = true
out = append(out, c)
progressed = true
}
}
if !progressed {
for i, c := range cats {
if !done[i] {
done[i] = true
out = append(out, c)
}
}
}
}
return out
}