Files
unitdore/cmd/order.go
T
warkanum 91811b4fa1 feat: order/delay in service files, enable cmd, --all on unit commands
- install/uninstall/start/stop/enable take <name> or --all; *all kept as shortcuts
- add enable (enable at boot + start); startall no longer enables
- order/delay resolved by config.ResolveOrder and written into systemd,
  OpenRC and runit service files (After=/sleep), so they apply at boot
- install --all stops and disables units before removing their files
- update regenerates all installed, enabled units and removes disabled ones
- edit creates the config dir; docs and man page updated
- tests: fake Init for cmd, ResolveOrder, backend ordering output
2026-10-12 21:31:41 +02:00

68 lines
1.8 KiB
Go

package cmd
import (
"fmt"
"io"
"sort"
"sync"
"github.com/warkanum/unitdore/config"
)
// sortUnits returns a copy of units sorted by order then name; reverse flips both.
func sortUnits(units []config.Unit, reverse bool) []config.Unit {
out := make([]config.Unit, len(units))
copy(out, units)
sort.SliceStable(out, func(i, j int) bool {
if out[i].Order != out[j].Order {
return (out[i].Order < out[j].Order) != reverse
}
return (out[i].Name < out[j].Name) != reverse
})
return out
}
// groupByOrder splits order-sorted units into groups sharing the same order.
func groupByOrder(sorted []config.Unit) [][]config.Unit {
var groups [][]config.Unit
for _, u := range sorted {
n := len(groups)
if n > 0 && groups[n-1][0].Order == u.Order {
groups[n-1] = append(groups[n-1], u)
continue
}
groups = append(groups, []config.Unit{u})
}
return groups
}
// runOrdered runs fn for every unit: groups of equal order one after another,
// units within a group in parallel. Start delays live in the generated service
// files, so a blocking start covers them. Output is printed per group in name
// order. Returns the number of units fn succeeded and failed for.
func runOrdered(units []config.Unit, w io.Writer, fn func(u config.Unit) (string, error)) (ok, failed int) {
for _, g := range groupByOrder(sortUnits(units, false)) {
msgs := make([]string, len(g))
errs := make([]error, len(g))
var wg sync.WaitGroup
for j, u := range g {
wg.Add(1)
go func(j int, u config.Unit) {
defer wg.Done()
msgs[j], errs[j] = fn(u)
}(j, u)
}
wg.Wait()
for j, u := range g {
if errs[j] != nil {
fmt.Fprintf(w, " ✗ failed: %s: %v\n", u.Name, errs[j])
failed++
continue
}
fmt.Fprintf(w, " ✓ %s\n", msgs[j])
ok++
}
}
return ok, failed
}