Skip to content

Commit

Permalink
fix: Set CHEZMOI_ environment variables for plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed Feb 29, 2024
1 parent 1f44189 commit 0405763
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 18 deletions.
48 changes: 33 additions & 15 deletions internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,7 @@ func (v VersionInfo) LogValue() slog.Value {

// Main runs chezmoi and returns an exit code.
func Main(versionInfo VersionInfo, args []string) int {
err := runMain(versionInfo, args)
// FIXME find a better way of detecting unknown commands
if err != nil && strings.Contains(err.Error(), "unknown command") && len(args) > 0 {
if name, err2 := exec.LookPath("chezmoi-" + args[0]); err2 == nil {
cmd := exec.Command(name, args[1:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
}
}
if err != nil {
if err := runMain(versionInfo, args); err != nil {
if errExitCode := chezmoi.ExitCodeError(0); errors.As(err, &errExitCode) {
return int(errExitCode)
}
Expand Down Expand Up @@ -276,12 +265,41 @@ func runMain(versionInfo VersionInfo, args []string) (err error) {
return err
}
defer chezmoierrors.CombineFunc(&err, config.Close)
err = config.execute(args)
if errors.Is(err, bbolt.ErrTimeout) {

switch err = config.execute(args); {
case errors.Is(err, bbolt.ErrTimeout):
// Translate bbolt timeout errors into a friendlier message. As the
// persistent state is opened lazily, this error could occur at any
// time, so it's easiest to intercept it here.
err = errors.New("timeout obtaining persistent state lock, is another instance of chezmoi running?")
return errors.New("timeout obtaining persistent state lock, is another instance of chezmoi running?")
case err != nil && strings.Contains(err.Error(), "unknown command") && len(args) > 0:
// If the command is unknown then look for a plugin.
if name, lookPathErr := exec.LookPath("chezmoi-" + args[0]); lookPathErr == nil {
// The following is a bit of a hack, as cobra does not have a way to
// call a function if a command is not found. We need to run the
// pre- and post- run commands to set up the environment, so we
// create a fake cobra.Command that corresponds to the name of the
// plugin.
cmd := &cobra.Command{
Use: args[0],
Annotations: newAnnotations(
doesNotRequireValidConfig,
persistentStateModeEmpty,
runsCommands,
),
}
if err := config.persistentPreRunRootE(cmd, args[1:]); err != nil {
return err
}
pluginCmd := exec.Command(name, args[1:]...)
pluginCmd.Stdin = os.Stdin
pluginCmd.Stdout = os.Stdout
pluginCmd.Stderr = os.Stderr
err = config.run("", name, args[1:])
if persistentPostRunRootEErr := config.persistentPostRunRootE(cmd, args[1:]); persistentPostRunRootEErr != nil {
err = chezmoierrors.Combine(err, persistentPostRunRootEErr)
}
}
}
return
}
9 changes: 6 additions & 3 deletions internal/cmd/testdata/scripts/plugin.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ stderr 'unknown command'

# test that chezmoi executes plugins
exec chezmoi plugin
stdout hello
stdout CHEZMOI_COMMAND=plugin
stdout CHEZMOI_SOURCE_DIR=${CHEZMOISOURCEDIR@R}

-- bin/chezmoi-plugin --
#!/bin/sh

echo hello
echo CHEZMOI_COMMAND=${CHEZMOI_COMMAND}
echo CHEZMOI_SOURCE_DIR=${CHEZMOI_SOURCE_DIR}
-- bin/chezmoi-plugin.cmd --
@echo hello
@echo CHEZMOI_COMMAND=%CHEZMOI_COMMAND%
@echo CHEZMOI_SOURCE_DIR=%CHEZMOI_SOURCE_DIR%

0 comments on commit 0405763

Please sign in to comment.