Skip to content

Commit

Permalink
feat: Implement documented add --prompt flag
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed Jun 19, 2022
1 parent b95449f commit b554329
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 7 deletions.
21 changes: 17 additions & 4 deletions pkg/chezmoi/sourcestate.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,10 @@ func NewSourceState(options ...SourceStateOption) *SourceState {
}

// A PreAddFunc is called before a new source state entry is added.
type PreAddFunc func(targetRelPath RelPath, newSourceStateEntry, oldSourceStateEntry SourceStateEntry) error
type PreAddFunc func(targetRelPath RelPath) error

// A ReplaceFunc is called before a source state entry is replaced.
type ReplaceFunc func(targetRelPath RelPath, newSourceStateEntry, oldSourceStateEntry SourceStateEntry) error

// AddOptions are options to SourceState.Add.
type AddOptions struct {
Expand All @@ -271,8 +274,9 @@ type AddOptions struct {
EncryptedSuffix string // Suffix for encrypted files.
Exact bool // Add the exact_ attribute to added directories.
Include *EntryTypeSet // Only add types in this set.
PreAddFunc PreAddFunc // Function to be called before the source entry is added.
PreAddFunc PreAddFunc // Function to be called before a source entry is added.
RemoveDir RelPath // Directory to remove before adding.
ReplaceFunc ReplaceFunc // Function to be called before a source entry is replaced.
Template bool // Add the .tmpl attribute to added files.
TemplateSymlinks bool // Add symlinks with targets in the source or home directories as templates.
}
Expand Down Expand Up @@ -338,6 +342,15 @@ DESTABSPATH:
continue
}

if options.PreAddFunc != nil {
switch err := options.PreAddFunc(targetRelPath); {
case errors.Is(err, Skip):
continue DESTABSPATH
case err != nil:
return err
}
}

sourceEntryRelPath := newSourceStateEntry.SourceRelPath()

entryState, err := actualStateEntry.EntryState()
Expand All @@ -353,8 +366,8 @@ DESTABSPATH:
if oldSourceStateEntry := s.root.Get(targetRelPath); oldSourceStateEntry != nil {
oldSourceEntryRelPath := oldSourceStateEntry.SourceRelPath()
if !oldSourceEntryRelPath.Empty() && oldSourceEntryRelPath != sourceEntryRelPath {
if options.PreAddFunc != nil {
switch err := options.PreAddFunc(targetRelPath, newSourceStateEntry, oldSourceStateEntry); {
if options.ReplaceFunc != nil {
switch err := options.ReplaceFunc(targetRelPath, newSourceStateEntry, oldSourceStateEntry); {
case errors.Is(err, Skip):
continue DESTABSPATH
case err != nil:
Expand Down
34 changes: 31 additions & 3 deletions pkg/cmd/addcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type addCmdConfig struct {
exclude *chezmoi.EntryTypeSet
follow bool
include *chezmoi.EntryTypeSet
prompt bool
recursive bool
template bool
}
Expand Down Expand Up @@ -48,16 +49,42 @@ func (c *Config) newAddCmd() *cobra.Command {
flags.VarP(c.Add.exclude, "exclude", "x", "Exclude entry types")
flags.BoolVarP(&c.Add.follow, "follow", "f", c.Add.follow, "Add symlink targets instead of symlinks")
flags.VarP(c.Add.include, "include", "i", "Include entry types")
flags.BoolVarP(&c.Add.prompt, "prompt", "p", c.Add.prompt, "Prompt before adding each entry")
flags.BoolVarP(&c.Add.recursive, "recursive", "r", c.Add.recursive, "Recurse into subdirectories")
flags.BoolVarP(&c.Add.template, "template", "T", c.Add.template, "Add files as templates")
flags.BoolVar(&c.Add.TemplateSymlinks, "template-symlinks", c.Add.TemplateSymlinks, "Add symlinks with target in source or home dirs as templates") //nolint:lll

return addCmd
}

// defaultPreAddFunc prompts the user for confirmation if the adding the entry
func (c *Config) defaultPreAddFunc(targetRelPath chezmoi.RelPath) error {
if !c.Add.prompt {
return nil
}

prompt := fmt.Sprintf("add %s", c.SourceDirAbsPath.Join(targetRelPath))
for {
switch choice, err := c.promptChoice(prompt, choicesYesNoAllQuit); {
case err != nil:
return err
case choice == "all":
c.Add.prompt = false
return nil
case choice == "no":
return chezmoi.Skip
case choice == "quit":
return chezmoi.ExitCodeError(0)
case choice == "yes":
return nil
default:
panic(fmt.Sprintf("%s: unexpected choice", choice))
}
}
}

// defaulReplaceFunc prompts the user for confirmation if the adding the entry
// would remove any of the encrypted, private, or template attributes.
func (c *Config) defaultPreAddFunc(
func (c *Config) defaulReplaceFunc(
targetRelPath chezmoi.RelPath, newSourceStateEntry, oldSourceStateEntry chezmoi.SourceStateEntry,
) error {
if c.force {
Expand Down Expand Up @@ -100,7 +127,7 @@ func (c *Config) defaultPreAddFunc(
case choice == "yes":
return nil
default:
return nil
panic(fmt.Sprintf("%s: unexpected choice", choice))
}
}
}
Expand All @@ -123,6 +150,7 @@ func (c *Config) runAddCmd(cmd *cobra.Command, args []string, sourceState *chezm
Exact: c.Add.exact,
Include: c.Add.include.Sub(c.Add.exclude),
PreAddFunc: c.defaultPreAddFunc,
ReplaceFunc: c.defaulReplaceFunc,
Template: c.Add.template,
TemplateSymlinks: c.Add.TemplateSymlinks,
})
Expand Down

0 comments on commit b554329

Please sign in to comment.