Files
2026-07-20 04:51:20 +00:00

76 lines
1.6 KiB
Go

//go:build linux
package scenario
import (
"context"
"errors"
"fmt"
"sync"
)
var (
ErrInvalidHeldCleanupAction = errors.New("held cleanup action is invalid")
ErrHeldCleanupClosed = errors.New("held cleanup stack is closed")
)
type heldCleanupAction struct {
name string
cleanup func(context.Context) error
}
type heldCleanupStackState uint8
const (
heldCleanupOpen heldCleanupStackState = iota
heldCleanupRunning
heldCleanupClosed
)
type heldCleanupStack struct {
mu sync.Mutex
state heldCleanupStackState
actions []heldCleanupAction
}
func newHeldCleanupStack() *heldCleanupStack {
return &heldCleanupStack{state: heldCleanupOpen}
}
func (stack *heldCleanupStack) Push(action heldCleanupAction) error {
if action.name == "" || action.cleanup == nil {
return ErrInvalidHeldCleanupAction
}
stack.mu.Lock()
defer stack.mu.Unlock()
if stack.state != heldCleanupOpen {
return ErrHeldCleanupClosed
}
stack.actions = append(stack.actions, action)
return nil
}
func (stack *heldCleanupStack) Run(ctx context.Context) error {
stack.mu.Lock()
if stack.state != heldCleanupOpen {
stack.mu.Unlock()
return ErrHeldCleanupClosed
}
stack.state = heldCleanupRunning
actions := append([]heldCleanupAction(nil), stack.actions...)
stack.mu.Unlock()
var joined error
for index := len(actions) - 1; index >= 0; index-- {
action := actions[index]
if err := action.cleanup(ctx); err != nil {
joined = errors.Join(joined, fmt.Errorf("cleanup %s: %w", action.name, err))
}
}
stack.mu.Lock()
stack.state = heldCleanupClosed
stack.mu.Unlock()
return joined
}