Implement controlled app launch (T-401)
This commit is contained in:
@@ -14,6 +14,11 @@ var (
|
||||
|
||||
type HealthCheck func(currentPath string) error
|
||||
|
||||
// PreSwitchCheck runs immediately before replacing an existing current
|
||||
// directory. It is intentionally core-only so callers can inject process
|
||||
// state without bringing platform APIs into the transaction.
|
||||
type PreSwitchCheck func() error
|
||||
|
||||
type switchStep string
|
||||
|
||||
const (
|
||||
@@ -42,13 +47,27 @@ func (err *RollbackError) Unwrap() []error {
|
||||
|
||||
// Switcher activates a verified staging directory and runs an injected check.
|
||||
type Switcher struct {
|
||||
health HealthCheck
|
||||
afterStep func(switchStep) error
|
||||
durability durabilityFence
|
||||
health HealthCheck
|
||||
preSwitchCheck PreSwitchCheck
|
||||
afterStep func(switchStep) error
|
||||
durability durabilityFence
|
||||
}
|
||||
|
||||
func NewSwitcher(health HealthCheck) *Switcher {
|
||||
return &Switcher{health: health, durability: defaultDurability()}
|
||||
return NewSwitcherWithPreSwitchCheck(health, nil)
|
||||
}
|
||||
|
||||
// NewSwitcherWithPreSwitchCheck creates a switcher that performs the optional
|
||||
// check only for updates with an existing current directory.
|
||||
func NewSwitcherWithPreSwitchCheck(
|
||||
health HealthCheck,
|
||||
preSwitchCheck PreSwitchCheck,
|
||||
) *Switcher {
|
||||
return &Switcher{
|
||||
health: health,
|
||||
preSwitchCheck: preSwitchCheck,
|
||||
durability: defaultDurability(),
|
||||
}
|
||||
}
|
||||
|
||||
func (switcher *Switcher) Switch(root string) error {
|
||||
@@ -75,6 +94,14 @@ func (switcher *Switcher) Switch(root string) error {
|
||||
if state.backup {
|
||||
return ErrBackupExists
|
||||
}
|
||||
if state.current && switcher.preSwitchCheck != nil {
|
||||
if err := switcher.preSwitchCheck(); err != nil {
|
||||
if cleanupErr := removeManagedDirectoryWithFence(layout, layout.staging, fence); cleanupErr != nil {
|
||||
return errors.Join(err, cleanupErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
record := newTransaction(phasePrepared, state.current)
|
||||
if err := writeTransactionWithFence(layout, record, fence); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user