From d525646f3aa98e4b2cc378fbd8ae67645b76631e Mon Sep 17 00:00:00 2001 From: MDietermann Date: Tue, 14 Apr 2026 21:49:09 +0200 Subject: [PATCH] feat(module): add PlanForce to Module interface with stubs --- internal/engine/engine_test.go | 6 ++++++ internal/module/module.go | 6 ++++++ internal/module/registry_test.go | 1 + internal/modules/arduinocli/arduinocli.go | 5 +++++ internal/modules/fonts/fonts.go | 5 +++++ internal/modules/gittools/gittools.go | 5 +++++ internal/modules/hello/hello.go | 5 +++++ internal/modules/neovim/neovim.go | 5 +++++ internal/modules/packages/packages.go | 5 +++++ internal/modules/renode/renode.go | 5 +++++ internal/modules/shellconfig/shellconfig.go | 5 +++++ internal/modules/starship/starship.go | 5 +++++ internal/modules/themes/themes.go | 5 +++++ internal/modules/yazi/yazi.go | 5 +++++ internal/modules/zellij/zellij.go | 5 +++++ internal/modules/zsh/zsh.go | 5 +++++ internal/subcommands/doctor/doctor_test.go | 9 +++++++++ internal/tui/state_test.go | 3 +++ internal/tui/wizard/wizard_test.go | 6 ++++++ 19 files changed, 96 insertions(+) diff --git a/internal/engine/engine_test.go b/internal/engine/engine_test.go index a579d87..c1453d9 100644 --- a/internal/engine/engine_test.go +++ b/internal/engine/engine_test.go @@ -31,6 +31,12 @@ func (s scriptedModule) Plan(ctx context.Context, _ module.State) (module.Plan, } return module.Plan{}, nil } +func (s scriptedModule) PlanForce(ctx context.Context) (module.Plan, error) { + if s.plan != nil { + return s.plan() + } + return module.Plan{}, nil +} func (s scriptedModule) Apply(ctx context.Context, _ module.Plan, _ module.Reporter) error { if s.apply != nil { return s.apply() diff --git a/internal/module/module.go b/internal/module/module.go index a286066..8fb9e25 100644 --- a/internal/module/module.go +++ b/internal/module/module.go @@ -49,6 +49,12 @@ type Module interface { Meta() Meta Detect(ctx context.Context) (State, error) Plan(ctx context.Context, current State) (Plan, error) + // PlanForce returns a plan that reapplies the module unconditionally, + // ignoring current detected state. Used by `archduino install --force`. + // Implementations should produce a plan equivalent to a from-scratch + // install — reinstall packages without pacman's --needed guard and + // rewrite managed config files. + PlanForce(ctx context.Context) (Plan, error) Apply(ctx context.Context, plan Plan, r Reporter) error Verify(ctx context.Context) error } diff --git a/internal/module/registry_test.go b/internal/module/registry_test.go index 0aa0d6c..a399cc1 100644 --- a/internal/module/registry_test.go +++ b/internal/module/registry_test.go @@ -13,6 +13,7 @@ type fakeModule struct { func (f fakeModule) Meta() Meta { return Meta{ID: f.id, Name: f.id, Deps: f.deps} } func (f fakeModule) Detect(context.Context) (State, error) { return nil, nil } func (f fakeModule) Plan(context.Context, State) (Plan, error) { return Plan{}, nil } +func (f fakeModule) PlanForce(context.Context) (Plan, error) { return Plan{}, nil } func (f fakeModule) Apply(context.Context, Plan, Reporter) error { return nil } func (f fakeModule) Verify(context.Context) error { return nil } diff --git a/internal/modules/arduinocli/arduinocli.go b/internal/modules/arduinocli/arduinocli.go index 9dc83bd..d098be8 100644 --- a/internal/modules/arduinocli/arduinocli.go +++ b/internal/modules/arduinocli/arduinocli.go @@ -4,6 +4,7 @@ package arduinocli import ( "bytes" "context" + "errors" "fmt" "os" "path/filepath" @@ -136,3 +137,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/fonts/fonts.go b/internal/modules/fonts/fonts.go index f9d5648..f2f3b18 100644 --- a/internal/modules/fonts/fonts.go +++ b/internal/modules/fonts/fonts.go @@ -3,6 +3,7 @@ package fonts import ( "context" + "errors" "fmt" "strings" @@ -80,3 +81,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/gittools/gittools.go b/internal/modules/gittools/gittools.go index 3f2f5c1..d18f6f5 100644 --- a/internal/modules/gittools/gittools.go +++ b/internal/modules/gittools/gittools.go @@ -3,6 +3,7 @@ package gittools import ( "context" + "errors" "fmt" "strings" @@ -72,3 +73,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/hello/hello.go b/internal/modules/hello/hello.go index a762bf1..30c5b5f 100644 --- a/internal/modules/hello/hello.go +++ b/internal/modules/hello/hello.go @@ -4,6 +4,7 @@ package hello import ( "context" + "errors" "fmt" "os" "path/filepath" @@ -96,3 +97,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/neovim/neovim.go b/internal/modules/neovim/neovim.go index ef6ebe6..64c26d1 100644 --- a/internal/modules/neovim/neovim.go +++ b/internal/modules/neovim/neovim.go @@ -6,6 +6,7 @@ package neovim import ( "bytes" "context" + "errors" "embed" "fmt" "os" @@ -461,3 +462,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/packages/packages.go b/internal/modules/packages/packages.go index 963fc9f..b276052 100644 --- a/internal/modules/packages/packages.go +++ b/internal/modules/packages/packages.go @@ -3,6 +3,7 @@ package packages import ( "context" + "errors" "fmt" "strings" @@ -72,3 +73,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/renode/renode.go b/internal/modules/renode/renode.go index b8ffc77..25da265 100644 --- a/internal/modules/renode/renode.go +++ b/internal/modules/renode/renode.go @@ -5,6 +5,7 @@ package renode import ( "bytes" "context" + "errors" "embed" "fmt" "os" @@ -185,3 +186,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/shellconfig/shellconfig.go b/internal/modules/shellconfig/shellconfig.go index 420e7f4..a84ca88 100644 --- a/internal/modules/shellconfig/shellconfig.go +++ b/internal/modules/shellconfig/shellconfig.go @@ -3,6 +3,7 @@ package shellconfig import ( "context" + "errors" "fmt" "os" "path/filepath" @@ -88,3 +89,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/starship/starship.go b/internal/modules/starship/starship.go index 113b74a..55f8911 100644 --- a/internal/modules/starship/starship.go +++ b/internal/modules/starship/starship.go @@ -3,6 +3,7 @@ package starship import ( "context" + "errors" "fmt" "strings" @@ -72,3 +73,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/themes/themes.go b/internal/modules/themes/themes.go index 123dc44..283f358 100644 --- a/internal/modules/themes/themes.go +++ b/internal/modules/themes/themes.go @@ -4,6 +4,7 @@ package themes import ( "bytes" "context" + "errors" "fmt" "io/fs" "os" @@ -113,3 +114,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/yazi/yazi.go b/internal/modules/yazi/yazi.go index 45965d3..f573b51 100644 --- a/internal/modules/yazi/yazi.go +++ b/internal/modules/yazi/yazi.go @@ -3,6 +3,7 @@ package yazi import ( "context" + "errors" "fmt" "strings" @@ -72,3 +73,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/zellij/zellij.go b/internal/modules/zellij/zellij.go index 42b6df9..4462666 100644 --- a/internal/modules/zellij/zellij.go +++ b/internal/modules/zellij/zellij.go @@ -3,6 +3,7 @@ package zellij import ( "context" + "errors" "fmt" "os" "path/filepath" @@ -108,3 +109,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/modules/zsh/zsh.go b/internal/modules/zsh/zsh.go index ddec612..6f37287 100644 --- a/internal/modules/zsh/zsh.go +++ b/internal/modules/zsh/zsh.go @@ -3,6 +3,7 @@ package zsh import ( "context" + "errors" "fmt" "os" "path/filepath" @@ -130,3 +131,7 @@ func (m Module) Verify(ctx context.Context) error { } return nil } + +func (m Module) PlanForce(ctx context.Context) (module.Plan, error) { + return module.Plan{}, errors.New("PlanForce not implemented") +} diff --git a/internal/subcommands/doctor/doctor_test.go b/internal/subcommands/doctor/doctor_test.go index 8851394..3d1718f 100644 --- a/internal/subcommands/doctor/doctor_test.go +++ b/internal/subcommands/doctor/doctor_test.go @@ -19,6 +19,9 @@ func (c convergedModule) Detect(context.Context) (module.State, error) { return func (c convergedModule) Plan(context.Context, module.State) (module.Plan, error) { return module.Plan{}, nil } +func (c convergedModule) PlanForce(context.Context) (module.Plan, error) { + return module.Plan{}, nil +} func (c convergedModule) Apply(context.Context, module.Plan, module.Reporter) error { return nil } func (c convergedModule) Verify(context.Context) error { return nil } @@ -29,6 +32,9 @@ func (p pendingModule) Detect(context.Context) (module.State, error) { return ni func (p pendingModule) Plan(context.Context, module.State) (module.Plan, error) { return module.Plan{Actions: []module.Action{{Description: "do a thing"}}}, nil } +func (p pendingModule) PlanForce(context.Context) (module.Plan, error) { + return module.Plan{Actions: []module.Action{{Description: "do a thing"}}}, nil +} func (p pendingModule) Apply(context.Context, module.Plan, module.Reporter) error { return nil } func (p pendingModule) Verify(context.Context) error { return nil } @@ -41,6 +47,9 @@ func (d detectFailModule) Detect(context.Context) (module.State, error) { func (d detectFailModule) Plan(context.Context, module.State) (module.Plan, error) { return module.Plan{}, nil } +func (d detectFailModule) PlanForce(context.Context) (module.Plan, error) { + return module.Plan{}, nil +} func (d detectFailModule) Apply(context.Context, module.Plan, module.Reporter) error { return nil } func (d detectFailModule) Verify(context.Context) error { return nil } diff --git a/internal/tui/state_test.go b/internal/tui/state_test.go index 6593311..47d4fe5 100644 --- a/internal/tui/state_test.go +++ b/internal/tui/state_test.go @@ -18,6 +18,9 @@ func (f fakeModule) Detect(context.Context) (module.State, error) { return nil, func (f fakeModule) Plan(context.Context, module.State) (module.Plan, error) { return module.Plan{}, nil } +func (f fakeModule) PlanForce(context.Context) (module.Plan, error) { + return module.Plan{}, nil +} func (f fakeModule) Apply(context.Context, module.Plan, module.Reporter) error { return nil } func (f fakeModule) Verify(context.Context) error { return nil } diff --git a/internal/tui/wizard/wizard_test.go b/internal/tui/wizard/wizard_test.go index 6898b4e..bc190a2 100644 --- a/internal/tui/wizard/wizard_test.go +++ b/internal/tui/wizard/wizard_test.go @@ -119,6 +119,12 @@ func (c countingModule) Plan(context.Context, module.State) (module.Plan, error) } return module.Plan{}, nil } +func (c countingModule) PlanForce(context.Context) (module.Plan, error) { + if c.onPlan != nil { + c.onPlan() + } + return module.Plan{}, nil +} func (c countingModule) Apply(context.Context, module.Plan, module.Reporter) error { return nil } func (c countingModule) Verify(context.Context) error { return nil }