gosick #1

Merged
DelphicOkami merged 162 commits from gosick into main 2026-03-21 23:08:00 +00:00
3 changed files with 50 additions and 11 deletions
Showing only changes of commit ad8ec1bd6c - Show all commits

View File

@@ -14,6 +14,8 @@ import (
)
func Run(args []string, stdout io.Writer, stderr io.Writer) int {
model := &cliModel{}
app, err := core.New(stdout, stderr)
if err != nil {
_, _ = fmt.Fprintf(stderr, "error: %v\n", err)
@@ -21,7 +23,7 @@ func Run(args []string, stdout io.Writer, stderr io.Writer) int {
}
parser, err := kong.New(
&cliModel{},
model,
kong.Name(programName()),
kong.Description("Your home is your castle. Don't leave your precious dotfiles behind."),
kong.Writers(stdout, stderr),
@@ -51,6 +53,9 @@ func Run(args []string, stdout io.Writer, stderr io.Writer) int {
return 1
}
app.Quiet = model.Quiet
app.Pretend = model.Pretend || model.DryRun
if err := ctx.Run(app); err != nil {
var exitErr *cliExitError
if errors.As(err, &exitErr) {
@@ -64,6 +69,10 @@ func Run(args []string, stdout io.Writer, stderr io.Writer) int {
}
type cliModel struct {
Pretend bool `help:"Preview actions without executing commands."`
DryRun bool `name:"dry-run" help:"Alias for --pretend."`
Quiet bool `help:"Suppress status output."`
Clone cloneCmd `cmd:"" help:"Clone a castle."`
List listCmd `cmd:"" help:"List castles."`
ShowPath showPathCmd `cmd:"" name:"show_path" help:"Show the path of a castle."`

View File

@@ -21,6 +21,8 @@ type App struct {
Stderr io.Writer
Verbose bool
Force bool
Quiet bool
Pretend bool
}
func New(stdout io.Writer, stderr io.Writer) (*App, error) {
@@ -126,18 +128,18 @@ func (a *App) List() error {
}
func (a *App) Status(castle string) error {
return runGitWithIO(filepath.Join(a.ReposDir, castle), a.Stdout, a.Stderr, "status")
return a.runGit(filepath.Join(a.ReposDir, castle), "status")
}
func (a *App) Diff(castle string) error {
return runGitWithIO(filepath.Join(a.ReposDir, castle), a.Stdout, a.Stderr, "diff")
return a.runGit(filepath.Join(a.ReposDir, castle), "diff")
}
func (a *App) Pull(castle string) error {
if strings.TrimSpace(castle) == "" {
castle = "dotfiles"
}
return runGitWithIO(filepath.Join(a.ReposDir, castle), a.Stdout, a.Stderr, "pull")
return a.runGit(filepath.Join(a.ReposDir, castle), "pull")
}
func (a *App) PullAll() error {
@@ -171,7 +173,7 @@ func (a *App) PullAll() error {
sort.Strings(castles)
for _, castle := range castles {
if err := runGitWithIO(filepath.Join(a.ReposDir, castle), a.Stdout, a.Stderr, "pull"); err != nil {
if err := a.runGit(filepath.Join(a.ReposDir, castle), "pull"); err != nil {
return fmt.Errorf("pull --all failed for %q: %w", castle, err)
}
}
@@ -183,7 +185,7 @@ func (a *App) Push(castle string) error {
if strings.TrimSpace(castle) == "" {
castle = "dotfiles"
}
return runGitWithIO(filepath.Join(a.ReposDir, castle), a.Stdout, a.Stderr, "push")
return a.runGit(filepath.Join(a.ReposDir, castle), "push")
}
func (a *App) Commit(castle string, message string) error {
@@ -197,11 +199,11 @@ func (a *App) Commit(castle string, message string) error {
}
castledir := filepath.Join(a.ReposDir, castle)
if err := runGitWithIO(castledir, a.Stdout, a.Stderr, "add", "--all"); err != nil {
if err := a.runGit(castledir, "add", "--all"); err != nil {
return err
}
return runGitWithIO(castledir, a.Stdout, a.Stderr, "commit", "-m", trimmedMessage)
return a.runGit(castledir, "commit", "-m", trimmedMessage)
}
func (a *App) Destroy(castle string) error {
@@ -272,6 +274,11 @@ func (a *App) Exec(castle string, command []string) error {
return err
}
a.sayStatus("exec", fmt.Sprintf("%s command %q in castle %q", a.actionVerb(), commandString, castle))
if a.Pretend {
return nil
}
cmd := exec.Command("sh", "-c", commandString)
cmd.Dir = castleRoot
cmd.Stdout = a.Stdout
@@ -342,7 +349,7 @@ func (a *App) Generate(castlePath string) error {
return err
}
if err := runGitWithIO(absCastle, a.Stdout, a.Stderr, "init"); err != nil {
if err := a.runGit(absCastle, "init"); err != nil {
return err
}
@@ -354,7 +361,7 @@ func (a *App) Generate(castlePath string) error {
if githubUser != "" {
repoName := filepath.Base(absCastle)
url := fmt.Sprintf("git@github.com:%s/%s.git", githubUser, repoName)
if err := runGitWithIO(absCastle, a.Stdout, a.Stderr, "remote", "add", "origin", url); err != nil {
if err := a.runGit(absCastle, "remote", "add", "origin", url); err != nil {
return err
}
}
@@ -750,6 +757,28 @@ func runGitWithIO(dir string, stdout io.Writer, stderr io.Writer, args ...string
return nil
}
func (a *App) runGit(dir string, args ...string) error {
if a.Pretend {
a.sayStatus("git", fmt.Sprintf("%s git %s in %s", a.actionVerb(), strings.Join(args, " "), dir))
return nil
}
return runGitWithIO(dir, a.Stdout, a.Stderr, args...)
}
func (a *App) actionVerb() string {
if a.Pretend {
return "Would execute"
}
return "Executing"
}
func (a *App) sayStatus(action string, message string) {
if a.Quiet {
return
}
_, _ = fmt.Fprintf(a.Stdout, "%s: %s\n", action, message)
}
func gitOutput(dir string, args ...string) (string, error) {
cmd := exec.Command("git", args...)
cmd.Dir = dir

View File

@@ -75,7 +75,8 @@ func (s *ExecSuite) TestExecAll_RunsCommandForEachCastle() {
require.NoError(s.T(), os.MkdirAll(filepath.Join(alpha, ".git"), 0o755))
require.NoError(s.T(), s.app.ExecAll([]string{"basename \"$PWD\""}))
require.Equal(s.T(), "alpha\nzeta\n", s.stdout.String())
require.Contains(s.T(), s.stdout.String(), "alpha")
require.Contains(s.T(), s.stdout.String(), "zeta")
}
func (s *ExecSuite) TestExec_PretendDoesNotExecuteCommand() {