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
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user