Skip to content

Commit

Permalink
feat: Add merge-all command
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed Oct 9, 2021
1 parent c9a9d9b commit 42e8323
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
14 changes: 14 additions & 0 deletions docs/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ Manage your dotfiles across multiple machines, securely.
* [`manage` *targets*](#manage-targets)
* [`managed`](#managed)
* [`merge` *target*...](#merge-target)
* [`merge-all` [*target*...]](#merge-all-target)
* [`purge`](#purge)
* [`remove` *targets*](#remove-targets)
* [`re-add`](#re-add)
Expand Down Expand Up @@ -1492,6 +1493,19 @@ $ chezmoi merge ~/.bashrc

---

### `merge-all` [*target*...]

Perform a three-way merge for file whose actual state does not match its target
state. The merge is performed with `chezmoi merge`.

#### `merge-all` examples

```console
$ chezmoi merge-all
```

---

### `purge`

Remove chezmoi's configuration, state, and source directory, but leave the
Expand Down
5 changes: 5 additions & 0 deletions internal/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ type Config struct {
_import importCmdConfig
init initCmdConfig
managed managedCmdConfig
mergeAll mergeAllCmdConfig
purge purgeCmdConfig
reAdd reAddCmdConfig
remove removeCmdConfig
Expand Down Expand Up @@ -336,6 +337,9 @@ func newConfig(options ...configOption) (*Config, error) {
exclude: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesNone),
include: chezmoi.NewEntryTypeSet(chezmoi.EntryTypeDirs | chezmoi.EntryTypeFiles | chezmoi.EntryTypeSymlinks | chezmoi.EntryTypeEncrypted),
},
mergeAll: mergeAllCmdConfig{
recursive: true,
},
reAdd: reAddCmdConfig{
exclude: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesNone),
include: chezmoi.NewEntryTypeSet(chezmoi.EntryTypesAll),
Expand Down Expand Up @@ -1237,6 +1241,7 @@ func (c *Config) newRootCmd() (*cobra.Command, error) {
c.newInternalTestCmd(),
c.newManagedCmd(),
c.newMergeCmd(),
c.newMergeAllCmd(),
c.newPurgeCmd(),
c.newReAddCmd(),
c.newRemoveCmd(),
Expand Down
61 changes: 61 additions & 0 deletions internal/cmd/mergeallcmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cmd

import (
"github.com/spf13/cobra"

"github.com/twpayne/chezmoi/v2/internal/chezmoi"
)

type mergeAllCmdConfig struct {
init bool
recursive bool
}

func (c *Config) newMergeAllCmd() *cobra.Command {
mergeAllCmd := &cobra.Command{
Use: "merge-all",
Short: "Perform a three-way merge for each modified file",
Long: mustLongHelp("merge-all"),
Example: example("merge-all"),
RunE: c.makeRunEWithSourceState(c.runMergeAllCmd),
Annotations: map[string]string{
modifiesSourceDirectory: "true",
requiresSourceDirectory: "true",
},
}

flags := mergeAllCmd.Flags()
flags.BoolVar(&c.mergeAll.init, "init", c.mergeAll.init, "Recreate config file from template")
flags.BoolVarP(&c.mergeAll.recursive, "recursive", "r", c.mergeAll.recursive, "Recurse into subdirectories")

return mergeAllCmd
}

func (c *Config) runMergeAllCmd(cmd *cobra.Command, args []string, sourceState *chezmoi.SourceState) error {
var targetRelPaths []chezmoi.RelPath
dryRunSystem := chezmoi.NewDryRunSystem(c.destSystem)
preApplyFunc := func(targetRelPath chezmoi.RelPath, targetEntryState, lastWrittenEntryState, actualEntryState *chezmoi.EntryState) error {
if !targetEntryState.Equivalent(actualEntryState) {
targetRelPaths = append(targetRelPaths, targetRelPath)
}
return chezmoi.Skip
}
if err := c.applyArgs(cmd.Context(), dryRunSystem, c.DestDirAbsPath, args, applyArgsOptions{
include: chezmoi.NewEntryTypeSet(chezmoi.EntryTypeFiles),
init: c.mergeAll.init,
recursive: c.mergeAll.recursive,
umask: c.Umask,
preApplyFunc: preApplyFunc,
}); err != nil {
return err
}

for _, targetRelPath := range targetRelPaths {
sourceStateEntry := sourceState.MustEntry(targetRelPath)
if err := c.doMerge(targetRelPath, sourceStateEntry); err != nil {
return err
}
}

return nil
}
18 changes: 18 additions & 0 deletions internal/cmd/testdata/scripts/mergeall_unix.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[windows] skip 'UNIX only'

# test that chezmoi merge-all does not run the merge command if nothing is modified
chezmoi merge-all
! stdout .

# test that chezmoi merge-all runs the merge command if a file is modified
edit $HOME/.file
chezmoi merge-all
stdout ^${HOME@R}/\.file\s+${CHEZMOISOURCEDIR@R}/dot_file\.tmpl\s+${WORK@R}/.*/\.file$

-- home/user/.file --
# contents of .file
-- home/user/.config/chezmoi/chezmoi.toml --
[merge]
command = "echo"
-- home/user/.local/share/chezmoi/dot_file.tmpl --
{{ "# contents of .file" }}

0 comments on commit 42e8323

Please sign in to comment.