From 483fe60bc5f4dfd673de3a6703e7ce4b64608636 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Sat, 22 Jun 2019 18:59:11 +0200 Subject: [PATCH 1/5] Improve use of ReadOnlyFS --- cmd/config.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/config.go b/cmd/config.go index 2b970a9e668..cd3630a07c3 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -130,6 +130,7 @@ func (c *Config) addTemplateFunc(key string, value interface{}) { } func (c *Config) applyArgs(fs vfs.FS, args []string, mutator chezmoi.Mutator) error { + fs = vfs.NewReadOnlyFS(fs) ts, err := c.getTargetState(fs) if err != nil { return err @@ -250,6 +251,7 @@ func (c *Config) getEntries(fs vfs.Stater, ts *chezmoi.TargetState, args []strin } func (c *Config) getTargetState(fs vfs.FS) (*chezmoi.TargetState, error) { + fs = vfs.NewReadOnlyFS(fs) defaultData, err := getDefaultData(fs) if err != nil { return nil, err @@ -265,8 +267,7 @@ func (c *Config) getTargetState(fs vfs.FS) (*chezmoi.TargetState, error) { c.GPG.Recipient = c.GPGRecipient } ts := chezmoi.NewTargetState(c.DestDir, os.FileMode(c.Umask), c.SourceDir, data, c.templateFuncs, &c.GPG) - readOnlyFS := vfs.NewReadOnlyFS(fs) - if err := ts.Populate(readOnlyFS); err != nil { + if err := ts.Populate(fs); err != nil { return nil, err } if Version != nil && ts.MinVersion != nil && Version.LessThan(*ts.MinVersion) { From 4db775f963df0f7a3ba6b597bd077a77adf38337 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Sat, 22 Jun 2019 19:46:23 +0200 Subject: [PATCH 2/5] Add remove functionality --- cmd/apply_test.go | 118 ++++++++++++++++++++++++++++ cmd/config.go | 2 + cmd/root.go | 3 + completions/chezmoi-completion.bash | 36 +++++++++ completions/chezmoi.fish | 36 +++++++++ docs/FAQ.md | 17 ---- docs/HOWTO.md | 18 +++++ docs/REFERENCE.md | 12 +++ go.mod | 5 +- go.sum | 14 +++- lib/chezmoi/chezmoi.go | 1 + lib/chezmoi/targetstate.go | 56 ++++++++++++- lib/chezmoi/targetstate_test.go | 43 +++++++++- 13 files changed, 333 insertions(+), 28 deletions(-) diff --git a/cmd/apply_test.go b/cmd/apply_test.go index b17a7335adc..cc676f1bffb 100644 --- a/cmd/apply_test.go +++ b/cmd/apply_test.go @@ -121,6 +121,124 @@ func TestApplyCommand(t *testing.T) { } } +func TestApplyRemove(t *testing.T) { + for _, tc := range []struct { + name string + noRemove bool + root interface{} + data map[string]interface{} + tests []vfst.Test + }{ + { + name: "simple", + root: map[string]interface{}{ + "/home/user/.local/share/chezmoi/.chezmoiremove": "foo", + "/home/user/foo": "# contents of foo\n", + }, + tests: []vfst.Test{ + vfst.TestPath("/home/user/foo", + vfst.TestDoesNotExist, + ), + }, + }, + { + name: "no_remove", + noRemove: true, + root: map[string]interface{}{ + "/home/user/.local/share/chezmoi/.chezmoiremove": "foo", + "/home/user/foo": "# contents of foo\n", + }, + tests: []vfst.Test{ + vfst.TestPath("/home/user/foo", + vfst.TestModeIsRegular, + vfst.TestContentsString("# contents of foo\n"), + ), + }, + }, + { + name: "pattern", + root: map[string]interface{}{ + "/home/user/.local/share/chezmoi/.chezmoiremove": "f*", + "/home/user/foo": "# contents of foo\n", + }, + tests: []vfst.Test{ + vfst.TestPath("/home/user/foo", + vfst.TestDoesNotExist, + ), + }, + }, + { + name: "template", + root: map[string]interface{}{ + "/home/user/.local/share/chezmoi/.chezmoiremove": "{{ .bar }}", + "/home/user/foo": "# contents of foo\n", + }, + data: map[string]interface{}{ + "bar": "foo", + }, + tests: []vfst.Test{ + vfst.TestPath("/home/user/foo", + vfst.TestDoesNotExist, + ), + }, + }, + { + name: "dont_remove_negative_pattern", + root: map[string]interface{}{ + "/home/user/.local/share/chezmoi/.chezmoiremove": "f*\n!foo\n", + "/home/user/foo": "# contents of foo\n", + }, + tests: []vfst.Test{ + vfst.TestPath("/home/user/foo", + vfst.TestModeIsRegular, + vfst.TestContentsString("# contents of foo\n"), + ), + }, + }, + { + name: "dont_remove_ignored", + root: map[string]interface{}{ + "/home/user/.local/share/chezmoi/.chezmoiignore": "foo", + "/home/user/.local/share/chezmoi/.chezmoiremove": "f*", + "/home/user/foo": "# contents of foo\n", + }, + tests: []vfst.Test{ + vfst.TestPath("/home/user/foo", + vfst.TestModeIsRegular, + vfst.TestContentsString("# contents of foo\n"), + ), + }, + }, + { + name: "remove_subdirectory_first", + root: map[string]interface{}{ + "/home/user/.local/share/chezmoi/.chezmoiremove": "foo\nfoo/bar\n", + "/home/user/foo/bar": "# contents of bar\n", + }, + tests: []vfst.Test{ + vfst.TestPath("/home/user/foo", + vfst.TestDoesNotExist, + ), + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + fs, cleanup, err := vfst.NewTestFS(tc.root) + require.NoError(t, err) + defer cleanup() + c := &Config{ + SourceDir: "/home/user/.local/share/chezmoi", + DestDir: "/home/user", + Data: tc.data, + Remove: !tc.noRemove, + Umask: 022, + } + assert.NoError(t, c.runApplyCmd(fs, nil)) + vfst.RunTests(t, fs, "", tc.tests) + }) + } +} + func TestApplyScript(t *testing.T) { tempDir, err := ioutil.TempDir("", "chezmoi") require.NoError(t, err) diff --git a/cmd/config.go b/cmd/config.go index cd3630a07c3..7991bab6152 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -39,6 +39,7 @@ type Config struct { DestDir string Umask permValue DryRun bool + Remove bool Verbose bool Color string GPG chezmoi.GPG @@ -140,6 +141,7 @@ func (c *Config) applyArgs(fs vfs.FS, args []string, mutator chezmoi.Mutator) er DryRun: c.DryRun, Ignore: ts.TargetIgnore.Match, PersistentState: c.persistentState, + Remove: c.Remove, ScriptStateBucket: c.scriptStateBucket, Stdout: c.Stdout(), Umask: ts.Umask, diff --git a/cmd/root.go b/cmd/root.go index f64c6cefdfc..c464c33b502 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -74,6 +74,9 @@ func init() { persistentFlags.BoolVarP(&config.DryRun, "dry-run", "n", false, "dry run") _ = viper.BindPFlag("dry-run", persistentFlags.Lookup("dry-run")) + persistentFlags.BoolVar(&config.Remove, "remove", false, "remove targets") + _ = viper.BindPFlag("remove", persistentFlags.Lookup("remove")) + persistentFlags.StringVarP(&config.SourceDir, "source", "S", getDefaultSourceDir(config.bds), "source directory") _ = viper.BindPFlag("source", persistentFlags.Lookup("source")) diff --git a/completions/chezmoi-completion.bash b/completions/chezmoi-completion.bash index 10e8cf5f097..eba154fc959 100644 --- a/completions/chezmoi-completion.bash +++ b/completions/chezmoi-completion.bash @@ -287,6 +287,7 @@ _chezmoi_add() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -322,6 +323,7 @@ _chezmoi_apply() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -357,6 +359,7 @@ _chezmoi_archive() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -392,6 +395,7 @@ _chezmoi_cat() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -427,6 +431,7 @@ _chezmoi_cd() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -462,6 +467,7 @@ _chezmoi_chattr() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -500,6 +506,7 @@ _chezmoi_completion() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -541,6 +548,7 @@ _chezmoi_data() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -576,6 +584,7 @@ _chezmoi_diff() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -611,6 +620,7 @@ _chezmoi_doctor() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -651,6 +661,7 @@ _chezmoi_dump() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -692,6 +703,7 @@ _chezmoi_edit() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -727,6 +739,7 @@ _chezmoi_edit-config() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -762,6 +775,7 @@ _chezmoi_forget() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -803,6 +817,7 @@ _chezmoi_import() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -839,6 +854,7 @@ _chezmoi_init() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -874,6 +890,7 @@ _chezmoi_merge() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -909,6 +926,7 @@ _chezmoi_remove() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -944,6 +962,7 @@ _chezmoi_secret_bitwarden() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -979,6 +998,7 @@ _chezmoi_secret_generic() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1014,6 +1034,7 @@ _chezmoi_secret_keepassxc() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1049,6 +1070,7 @@ _chezmoi_secret_keyring_get() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--service=") two_word_flags+=("--service") flags+=("--source=") @@ -1090,6 +1112,7 @@ _chezmoi_secret_keyring_set() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--service=") two_word_flags+=("--service") flags+=("--source=") @@ -1135,6 +1158,7 @@ _chezmoi_secret_keyring() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1172,6 +1196,7 @@ _chezmoi_secret_lastpass() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1207,6 +1232,7 @@ _chezmoi_secret_onepassword() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1242,6 +1268,7 @@ _chezmoi_secret_pass() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1277,6 +1304,7 @@ _chezmoi_secret_vault() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1320,6 +1348,7 @@ _chezmoi_secret() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1355,6 +1384,7 @@ _chezmoi_source() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1390,6 +1420,7 @@ _chezmoi_source-path() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1425,6 +1456,7 @@ _chezmoi_unmanaged() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1462,6 +1494,7 @@ _chezmoi_update() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1508,6 +1541,7 @@ _chezmoi_upgrade() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1543,6 +1577,7 @@ _chezmoi_verify() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") @@ -1615,6 +1650,7 @@ _chezmoi_root_command() two_word_flags+=("-D") flags+=("--dry-run") flags+=("-n") + flags+=("--remove") flags+=("--source=") two_word_flags+=("--source") two_word_flags+=("-S") diff --git a/completions/chezmoi.fish b/completions/chezmoi.fish index 3c21631dde4..ea2c06da4da 100644 --- a/completions/chezmoi.fish +++ b/completions/chezmoi.fish @@ -64,6 +64,7 @@ complete -c chezmoi -f -n '__fish_chezmoi_no_subcommand' -r -l color -d 'colori complete -c chezmoi -f -n '__fish_chezmoi_no_subcommand' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_no_subcommand' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_no_subcommand' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_no_subcommand' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_no_subcommand' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_no_subcommand' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path add' -s e -l empty -d 'add empty files' @@ -77,36 +78,42 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path add' -r -l color complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path add' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path add' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path add' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path add' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path add' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path add' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path apply' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path apply' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path apply' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path apply' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path apply' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path apply' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path apply' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path archive' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path archive' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path archive' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path archive' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path archive' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path archive' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path archive' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cat' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cat' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cat' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cat' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cat' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cat' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cat' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cd' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cd' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cd' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cd' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cd' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cd' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path cd' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path chattr' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path chattr' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path chattr' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path chattr' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path chattr' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path chattr' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path chattr' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path completion; and not __fish_seen_argument -s h -l help' -a bash -d 'Positional Argument to completion' @@ -117,6 +124,7 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path completion' -r - complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path completion' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path completion' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path completion' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path completion' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path completion' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path completion' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path data' -r -s f -l format -d 'format (JSON, TOML, or YAML)' @@ -124,18 +132,21 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path data' -r -l colo complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path data' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path data' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path data' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path data' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path data' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path data' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path diff' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path diff' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path diff' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path diff' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path diff' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path diff' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path diff' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path doctor' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path doctor' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path doctor' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path doctor' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path doctor' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path doctor' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path doctor' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path dump' -r -s f -l format -d 'format (JSON, TOML, or YAML)' @@ -144,6 +155,7 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path dump' -r -l colo complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path dump' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path dump' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path dump' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path dump' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path dump' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path dump' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit' -s a -l apply -d 'apply edit after editing' @@ -153,18 +165,21 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit' -r -l colo complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit-config' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit-config' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit-config' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit-config' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit-config' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit-config' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path edit-config' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path forget' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path forget' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path forget' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path forget' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path forget' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path forget' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path forget' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path import' -s x -l exact -d 'import directories exactly' @@ -174,6 +189,7 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path import' -r -l co complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path import' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path import' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path import' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path import' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path import' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path import' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path init' -l apply -d 'update destination directory' @@ -181,18 +197,21 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path init' -r -l colo complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path init' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path init' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path init' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path init' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path init' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path init' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path merge' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path merge' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path merge' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path merge' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path merge' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path merge' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path merge' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path remove' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path remove' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path remove' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path remove' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path remove' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path remove' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path remove' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret' -a bitwarden -d 'Execute the Bitwarden CLI (bw)' @@ -207,24 +226,28 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret' -r -l co complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret bitwarden' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret bitwarden' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret bitwarden' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret bitwarden' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret bitwarden' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret bitwarden' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret bitwarden' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret generic' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret generic' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret generic' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret generic' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret generic' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret generic' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret generic' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keepassxc' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keepassxc' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keepassxc' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keepassxc' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keepassxc' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keepassxc' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keepassxc' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring' -a get -d 'Get a password from keyring' @@ -235,12 +258,14 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring' - complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring get' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring get' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring get' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring get' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring get' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring get' -r -l service -d 'service' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring get' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring get' -r -l user -d 'user' @@ -250,6 +275,7 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring se complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring set' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring set' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring set' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring set' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring set' -r -l service -d 'service' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring set' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret keyring set' -r -l user -d 'user' @@ -258,42 +284,49 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret lastpass' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret lastpass' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret lastpass' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret lastpass' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret lastpass' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret lastpass' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret lastpass' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret onepassword' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret onepassword' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret onepassword' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret onepassword' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret onepassword' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret onepassword' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret onepassword' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret pass' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret pass' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret pass' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret pass' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret pass' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret pass' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret pass' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret vault' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret vault' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret vault' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret vault' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret vault' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret vault' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path secret vault' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source-path' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source-path' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source-path' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source-path' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source-path' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source-path' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path source-path' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path unmanaged' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path unmanaged' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path unmanaged' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path unmanaged' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path unmanaged' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path unmanaged' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path unmanaged' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path update' -s a -l apply -d 'apply after pulling' @@ -301,6 +334,7 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path update' -r -l co complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path update' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path update' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path update' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path update' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path update' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path update' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path upgrade' -s f -l force -d 'force upgrade' @@ -311,11 +345,13 @@ complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path upgrade' -r -l c complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path upgrade' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path upgrade' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path upgrade' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path upgrade' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path upgrade' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path upgrade' -s v -l verbose -d 'verbose' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path verify' -r -l color -d 'colorize diffs' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path verify' -r -s c -l config -d 'config file' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path verify' -r -s D -l destination -d 'destination directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path verify' -s n -l dry-run -d 'dry run' +complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path verify' -l remove -d 'remove targets' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path verify' -r -s S -l source -d 'source directory' complete -c chezmoi -f -n '__fish_chezmoi_seen_subcommand_path verify' -s v -l verbose -d 'verbose' diff --git a/docs/FAQ.md b/docs/FAQ.md index 71bd1f081e8..4b4488638ff 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -6,7 +6,6 @@ * [If there's a mechanism in place for the above, is there also a way to tell chezmoi to ignore specific files or groups of files (e.g. by directory name or by glob)?](#If-theres-a-mechanism-in-place-for-the-above-is-there-also-a-way-to-tell-chezmoi-to-ignore-specific-files-or-groups-of-files-eg-by-directory-name-or-by-glob) * [If the target already exists, but is "behind" the source, can chezmoi be configured to preserve the target version before replacing it with one derived from the source?](#If-the-target-already-exists-but-is-behind-the-source-can-chezmoi-be-configured-to-preserve-the-target-version-before-replacing-it-with-one-derived-from-the-source) * [I've made changes to both the destination state and the source state that I want to keep. How can I keep them both?](#Ive-made-changes-to-both-the-destination-state-and-the-source-state-that-I-want-to-keep-How-can-I-keep-them-both) -* [How do I tell chezmoi to always delete a file?](#How-do-I-tell-chezmoi-to-always-delete-a-file) * [gpg encryption fails. What could be wrong?](#gpg-encryption-fails-What-could-be-wrong) * [What inspired chezmoi?](#What-inspired-chezmoi) * [Can I use chezmoi outside my home directory?](#Can-I-use-chezmoi-outside-my-home-directory) @@ -52,22 +51,6 @@ diff`. state, target state, and destination state. Copy the changes you want to keep in to the source state. -## How do I tell chezmoi to always delete a file? - -chezmoi will delete files if their target state is empty, unless they have the -`empty` attribute set. Therefore an empty file in the source state without the -`empty` attribute will always be deleted. - -Say you want chezmoi to always delete `~/.foo`, you can use the following -sequence of commands: - - rm -f ~/.foo - touch ~/.foo - chezmoi add --empty ~/.foo - chezmoi chattr noempty ~/.foo - -When you next run `chezmoi apply`, `~/.foo` will be deleted. - ## gpg encryption fails. What could be wrong? The `gpgRecipient` key should be ultimately trusted, otherwise encryption will diff --git a/docs/HOWTO.md b/docs/HOWTO.md index cce7412242c..d519a92a10d 100644 --- a/docs/HOWTO.md +++ b/docs/HOWTO.md @@ -3,6 +3,7 @@ * [Use a hosted repo to manage your dotfiles across multiple machines](#Use-a-hosted-repo-to-manage-your-dotfiles-across-multiple-machines) * [Use templates to manage files that vary from machine to machine](#Use-templates-to-manage-files-that-vary-from-machine-to-machine) * [Create a config file on a new machine automatically](#Create-a-config-file-on-a-new-machine-automatically) +* [Ensure that a target is removed](#Ensure-that-a-target-is-removed) * [Keep data private](#Keep-data-private) * [Use Bitwarden to keep your secrets](#Use-Bitwarden-to-keep-your-secrets) * [Use gpg to keep your secrets](#Use-gpg-to-keep-your-secrets) @@ -171,6 +172,23 @@ Specifically, if you have `.chezmoi.toml.tmpl` that looks like this: Then `chezmoi init` will create an initial `chezmoi.toml` using this template. `promptString` is a special function that prompts the user (you) for a value. +## Ensure that a target is removed + +Create a file called `.chezmoiremove` in the source directory containing a list +of patterns of files to remove. When you run + + chezmoi apply --remove + +chezmoi will remove anything in the target directory that matches the pattern. +As this command is potentially dangerous, you should run chezmoi in verbose, +dry-run mode beforehand to see what would be deleted: + + chezmoi apply --remove --dry-run --verbose + +`.chezmoiremove` is interpreted as a template, so you can remove different files +on different machines. Negative matches (patterns prefixed with a `!`) or +targets listed in `.chezmoiignore` will never be removed. + ## Keep data private chezmoi automatically detects when files and directories are private when adding diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index 3b17a45f56e..5fc0e21c424 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -18,6 +18,7 @@ Manage your dotfiles securely across multiple machines. * [Special files and directories](#Special-files-and-directories) * [`.chezmoi..tmpl`](#chezmoiformattmpl) * [`.chezmoiignore`](#chezmoiignore) + * [`.chezmoiremove`](#chezmoiremove) * [`.chezmoitemplates`](#chezmoitemplates) * [`.chezmoiversion`](#chezmoiversion) * [Commands](#Commands) @@ -113,6 +114,10 @@ that would be made without making them. Print help. +### `-r`. `--remove` + +Also remove targets according to `.chezmoiremove`. + ### `-S`, `--source` *directory* Use *directory* as the source directory. @@ -159,6 +164,7 @@ The following configuration variables are available: | `merge.command` | string | `vimdiff` | 3-way merge command | | `onepassword.command` | string | `op` | 1Password CLI command | | `pass.command` | string | `pass` | Pass CLI command | +| `remove` | boolean | `false` | Remove targets | | `sourceDir` | string | `~/.config/share/chezmoi` | Source directory | | `sourceVCS.command` | string | `git` | Source version control system | | `umask` | integer | from system | Umask | @@ -241,6 +247,12 @@ implementation and corner case behaviour may differ. .personal-file {{- end }} +### `.chezmoiremove` + +If a file called `.chezmoiremove` exists in the source state then it is +interpreted as a list of targets to remove. `.chezmoiremove` is interpreted as a +template. + ### `.chezmoitemplates` If a directory called `.chezmoitemplates` exists, then all files in this diff --git a/go.mod b/go.mod index 43f43740191..2922085ddfa 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/google/go-github/v26 v26.0.4 github.com/google/renameio v0.1.0 github.com/google/uuid v1.1.0 // indirect + github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95 // indirect github.com/huandu/xstrings v1.2.0 // indirect github.com/imdario/mergo v0.3.7 // indirect github.com/kr/text v0.1.0 @@ -26,14 +27,14 @@ require ( github.com/stretchr/testify v1.3.0 github.com/twpayne/go-difflib v1.3.1 github.com/twpayne/go-shell v0.0.1 - github.com/twpayne/go-vfs v1.1.0 + github.com/twpayne/go-vfs v1.3.0 github.com/twpayne/go-vfsafero v1.0.0 github.com/twpayne/go-xdg/v3 v3.1.0 github.com/zalando/go-keyring v0.0.0-20180221093347-6d81c293b3fb go.etcd.io/bbolt v1.3.3 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be - golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa // indirect + golang.org/x/sys v0.0.0-20190621203818-d432491b9138 // indirect gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index 390dcfed2ae..9b84b5948fc 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,9 @@ github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hectane/go-acl v0.0.0-20190523051433-dfeb47f3e2ef/go.mod h1:xk/21OELzVCkl0NZCoB+eLISXe1p+YDiha8WaQDD1d8= +github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95 h1:S4qyfL2sEm5Budr4KVMyEniCy+PbS55651I/a+Kn/NQ= +github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E= github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= @@ -87,8 +90,8 @@ github.com/twpayne/go-shell v0.0.1/go.mod h1:QCjEvdZndTuPObd+11NYAI1UeNLSuGZVxJ+ github.com/twpayne/go-vfs v1.0.1/go.mod h1:OIXA6zWkcn7Jk46XT7ceYqBMeIkfzJ8WOBhGJM0W4y8= github.com/twpayne/go-vfs v1.0.5 h1:i45a6Ykg/asDB94fHH5OmScCQHFx/P9A//9M5dfXwQk= github.com/twpayne/go-vfs v1.0.5/go.mod h1:OIXA6zWkcn7Jk46XT7ceYqBMeIkfzJ8WOBhGJM0W4y8= -github.com/twpayne/go-vfs v1.1.0 h1:UPEV+YPvnCTFTJCuZWd+5Fg5TvXjs7CODNKemZZdcNE= -github.com/twpayne/go-vfs v1.1.0/go.mod h1:A7YkNSb8q0vkRm4fPKNntU6tKePPh96OOwxHYxhZzOU= +github.com/twpayne/go-vfs v1.3.0 h1:LFEORfCPfxyh++bqeenXAWDN7bTLMypj1mfb/25Y+jg= +github.com/twpayne/go-vfs v1.3.0/go.mod h1:BH2oQurpkb3roQDR7hZH+9DITZidl6JHOEfHlCModXY= github.com/twpayne/go-vfsafero v1.0.0 h1:ZlH32HF4OoVX/aRqc5bZa+2+M+/ezmJ4XYpT0ShtZNc= github.com/twpayne/go-vfsafero v1.0.0/go.mod h1:rs2H15b2z0euJzwyoBS63eUHZgBhNXVQfIFfRp8DKEk= github.com/twpayne/go-xdg/v3 v3.1.0 h1:AxX5ZLJIzqYHJh+4uGxWT97ySh1ND1bJLjqMxdYF+xs= @@ -113,8 +116,11 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1 golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa h1:lqti/xP+yD/6zH5TqEwx2MilNIJY5Vbc6Qr8J3qyPIQ= -golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5 h1:sM3evRHxE/1RuMe1FYAL3j7C7fUfIjkbE+NiDAYUF8U= +golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190621203818-d432491b9138 h1:t8BZD9RDjkm9/h7yYN6kE8oaeov5r9aztkB7zKA5Tkg= +golang.org/x/sys v0.0.0-20190621203818-d432491b9138/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= diff --git a/lib/chezmoi/chezmoi.go b/lib/chezmoi/chezmoi.go index 64c1a6fe445..527fb836d7d 100644 --- a/lib/chezmoi/chezmoi.go +++ b/lib/chezmoi/chezmoi.go @@ -45,6 +45,7 @@ type ApplyOptions struct { DryRun bool Ignore func(string) bool PersistentState PersistentState + Remove bool ScriptStateBucket []byte Stdout io.Writer Umask os.FileMode diff --git a/lib/chezmoi/targetstate.go b/lib/chezmoi/targetstate.go index 20a564c3d97..b36d0e1fffe 100644 --- a/lib/chezmoi/targetstate.go +++ b/lib/chezmoi/targetstate.go @@ -10,6 +10,7 @@ import ( "os" "os/user" "path/filepath" + "sort" "strconv" "strings" "text/template" @@ -21,6 +22,7 @@ import ( const ( ignoreName = ".chezmoiignore" + removeName = ".chezmoiremove" templatesDirName = ".chezmoitemplates" versionName = ".chezmoiversion" ) @@ -45,6 +47,7 @@ type ImportTAROptions struct { type TargetState struct { DestDir string TargetIgnore *PatternSet + TargetRemove *PatternSet Umask os.FileMode SourceDir string Data map[string]interface{} @@ -60,6 +63,7 @@ func NewTargetState(destDir string, umask os.FileMode, sourceDir string, data ma return &TargetState{ DestDir: destDir, TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: umask, SourceDir: sourceDir, Data: data, @@ -163,6 +167,49 @@ func (ts *TargetState) Add(fs vfs.FS, addOptions AddOptions, targetPath string, // Apply ensures that ts.DestDir in fs matches ts. func (ts *TargetState) Apply(fs vfs.FS, mutator Mutator, applyOptions *ApplyOptions) error { + if applyOptions.Remove { + // Build a set of targets to remove. + targetsToRemove := make(map[string]struct{}) + includes := make([]string, 0, len(ts.TargetRemove.includes)) + for include := range ts.TargetRemove.includes { + includes = append(includes, include) + } + for _, include := range includes { + matches, err := fs.Glob(filepath.Join(ts.DestDir, include)) + if err != nil { + return err + } + for _, match := range matches { + relPath := strings.TrimPrefix(match, ts.DestDir+"/") + // Don't remove targets that are ignored. + if ts.TargetIgnore.Match(relPath) { + continue + } + // Don't remove targets that are excluded from remove. + if !ts.TargetRemove.Match(relPath) { + continue + } + targetsToRemove[match] = struct{}{} + } + } + + // FIXME check that the set of targets to remove does not intersect wth + // the list of all entries. + + // Remove targets in reverse order so we remove children before their + // parents. + sortedTargetsToRemove := make([]string, 0, len(targetsToRemove)) + for target := range targetsToRemove { + sortedTargetsToRemove = append(sortedTargetsToRemove, target) + } + sort.Sort(sort.Reverse(sort.StringSlice(sortedTargetsToRemove))) + for _, target := range sortedTargetsToRemove { + if err := mutator.RemoveAll(target); err != nil { + return err + } + } + } + for _, entryName := range sortedEntryNames(ts.Entries) { if err := ts.Entries[entryName].Apply(fs, mutator, applyOptions); err != nil { return err @@ -285,7 +332,10 @@ func (ts *TargetState) Populate(fs vfs.FS) error { switch { case info.Name() == ignoreName: dns := dirNames(parseDirNameComponents(splitPathList(relPath))) - return ts.addSourceIgnore(fs, path, filepath.Join(dns...)) + return ts.addPatterns(fs, ts.TargetIgnore, path, filepath.Join(dns...)) + case info.Name() == removeName: + dns := dirNames(parseDirNameComponents(splitPathList(relPath))) + return ts.addPatterns(fs, ts.TargetRemove, path, filepath.Join(dns...)) case info.Name() == templatesDirName: if err := ts.addTemplatesDir(fs, path); err != nil { return err @@ -489,7 +539,7 @@ func (ts *TargetState) addFile(targetName string, entries map[string]Entry, pare return mutator.WriteFile(filepath.Join(ts.SourceDir, sourceName), contents, 0666&^ts.Umask, existingContents) } -func (ts *TargetState) addSourceIgnore(fs vfs.FS, path, relPath string) error { +func (ts *TargetState) addPatterns(fs vfs.FS, ps *PatternSet, path, relPath string) error { data, err := ts.executeTemplate(fs, path) if err != nil { return err @@ -511,7 +561,7 @@ func (ts *TargetState) addSourceIgnore(fs vfs.FS, path, relPath string) error { text = strings.TrimPrefix(text, "!") } pattern := filepath.Join(dir, text) - if err := ts.TargetIgnore.Add(pattern, include); err != nil { + if err := ps.Add(pattern, include); err != nil { return fmt.Errorf("%s: %v", path, err) } } diff --git a/lib/chezmoi/targetstate_test.go b/lib/chezmoi/targetstate_test.go index e2c267acc03..0f7cf45e592 100644 --- a/lib/chezmoi/targetstate_test.go +++ b/lib/chezmoi/targetstate_test.go @@ -130,6 +130,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Entries: map[string]Entry{ @@ -151,6 +152,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Entries: map[string]Entry{ @@ -172,6 +174,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Entries: map[string]Entry{ @@ -193,6 +196,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Entries: map[string]Entry{ @@ -222,6 +226,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Entries: map[string]Entry{ @@ -254,6 +259,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Data: map[string]interface{}{ @@ -279,6 +285,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Entries: map[string]Entry{ @@ -308,6 +315,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Entries: map[string]Entry{ @@ -328,6 +336,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Entries: map[string]Entry{ @@ -351,6 +360,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Data: map[string]interface{}{ @@ -384,6 +394,31 @@ func TestTargetStatePopulate(t *testing.T) { "g": {}, }, }, + TargetRemove: NewPatternSet(), + Umask: 0, + SourceDir: "/", + Entries: map[string]Entry{}, + }, + }, + { + name: "remove_pattern", + root: map[string]interface{}{ + "/.chezmoiremove": "" + + "f*\n" + + "!g\n", + }, + sourceDir: "/", + want: &TargetState{ + DestDir: "/", + TargetIgnore: NewPatternSet(), + TargetRemove: &PatternSet{ + includes: map[string]struct{}{ + "f*": {}, + }, + excludes: map[string]struct{}{ + "g": {}, + }, + }, Umask: 0, SourceDir: "/", Entries: map[string]Entry{}, @@ -407,8 +442,9 @@ func TestTargetStatePopulate(t *testing.T) { "dir/bar": {}, }, }, - Umask: 0, - SourceDir: "/", + TargetRemove: NewPatternSet(), + Umask: 0, + SourceDir: "/", Entries: map[string]Entry{ "dir": &Dir{ sourceName: "dir", @@ -428,6 +464,7 @@ func TestTargetStatePopulate(t *testing.T) { sourceDir: "/", want: &TargetState{ DestDir: "/", + TargetRemove: NewPatternSet(), TargetIgnore: NewPatternSet(), Umask: 0, SourceDir: "/", @@ -450,6 +487,7 @@ func TestTargetStatePopulate(t *testing.T) { sourceDir: "/", want: &TargetState{ DestDir: "/", + TargetRemove: NewPatternSet(), TargetIgnore: NewPatternSet(), Umask: 0, SourceDir: "/", @@ -465,6 +503,7 @@ func TestTargetStatePopulate(t *testing.T) { want: &TargetState{ DestDir: "/", TargetIgnore: NewPatternSet(), + TargetRemove: NewPatternSet(), Umask: 0, SourceDir: "/", Entries: map[string]Entry{}, From df82247ca22f4eeae149a1f43b0b934943061ef0 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Sat, 22 Jun 2019 19:46:52 +0200 Subject: [PATCH 3/5] Improve section title --- docs/REFERENCE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index 5fc0e21c424..31f9c599c9d 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -14,7 +14,7 @@ Manage your dotfiles securely across multiple machines. * [`--version`](#--version) * [Configuration file](#Configuration-file) * [Configuration variables](#Configuration-variables) -* [Attributes](#Attributes) +* [Source state attributes](#Source-state-attributes) * [Special files and directories](#Special-files-and-directories) * [`.chezmoi..tmpl`](#chezmoiformattmpl) * [`.chezmoiignore`](#chezmoiignore) @@ -174,7 +174,7 @@ The following configuration variables are available: In addition, a number of secret manager integrations add configuration variables. These are documented in the secret manager section. -## Attributes +## Source state attributes chezmoi stores the source state of files, symbolic links, and directories in regular files and directories in the source directory (`~/.local/share/chezmoi` From 8c614a605679577e798b6ab5e88588eb48c0cbd4 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Sat, 22 Jun 2019 19:53:13 +0200 Subject: [PATCH 4/5] Update tables of contents --- docs/FAQ.md | 6 +++--- docs/REFERENCE.md | 17 +++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 4b4488638ff..be5b6e5d38b 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -1,15 +1,15 @@ # chezmoi Frequently Asked Questions * [How can I quickly check for problems with chezmoi on my machine?](#How-can-I-quickly-check-for-problems-with-chezmoi-on-my-machine) -* [What are the consequences of "bare" modifications to the target files? If my `.zshrc` is managed by chezmoi and I edit `~/.zshrc` without using `chezmoi edit`, what happens?](#What-are-the-consequences-of-bare-modifications-to-the-target-files-If-my-zshrc-is-managed-by-chezmoi-and-I-edit-zshrc-without-using-chezmoi-edit-what-happens) +* [What are the consequences of "bare" modifications to the target files? If my `.zshrc` is managed by chezmoi and I edit `~/.zshrc` without using `chezmoi edit`, what happens?](#What-are-the-consequences-of-%22bare%22-modifications-to-the-target-files-If-my-zshrc-is-managed-by-chezmoi-and-I-edit-zshrc-without-using-chezmoi-edit-what-happens) * [How can I tell what dotfiles in my home directory aren't managed by chezmoi? Is there an easy way to have chezmoi manage a subset of them?](#How-can-I-tell-what-dotfiles-in-my-home-directory-arent-managed-by-chezmoi-Is-there-an-easy-way-to-have-chezmoi-manage-a-subset-of-them) * [If there's a mechanism in place for the above, is there also a way to tell chezmoi to ignore specific files or groups of files (e.g. by directory name or by glob)?](#If-theres-a-mechanism-in-place-for-the-above-is-there-also-a-way-to-tell-chezmoi-to-ignore-specific-files-or-groups-of-files-eg-by-directory-name-or-by-glob) -* [If the target already exists, but is "behind" the source, can chezmoi be configured to preserve the target version before replacing it with one derived from the source?](#If-the-target-already-exists-but-is-behind-the-source-can-chezmoi-be-configured-to-preserve-the-target-version-before-replacing-it-with-one-derived-from-the-source) +* [If the target already exists, but is "behind" the source, can chezmoi be configured to preserve the target version before replacing it with one derived from the source?](#If-the-target-already-exists-but-is-%22behind%22-the-source-can-chezmoi-be-configured-to-preserve-the-target-version-before-replacing-it-with-one-derived-from-the-source) * [I've made changes to both the destination state and the source state that I want to keep. How can I keep them both?](#Ive-made-changes-to-both-the-destination-state-and-the-source-state-that-I-want-to-keep-How-can-I-keep-them-both) * [gpg encryption fails. What could be wrong?](#gpg-encryption-fails-What-could-be-wrong) * [What inspired chezmoi?](#What-inspired-chezmoi) * [Can I use chezmoi outside my home directory?](#Can-I-use-chezmoi-outside-my-home-directory) -* [Where does the name "chezmoi" come from?](#Where-does-the-name-chezmoi-come-from) +* [Where does the name "chezmoi" come from?](#Where-does-the-name-%22chezmoi%22-come-from) * [What other questions have been asked about chezmoi?](#What-other-questions-have-been-asked-about-chezmoi) * [Where do I ask a question that isn't answered here?](#Where-do-I-ask-a-question-that-isnt-answered-here) diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index 31f9c599c9d..7b9fb4c4b32 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -4,14 +4,15 @@ Manage your dotfiles securely across multiple machines. * [Concepts](#Concepts) * [Global command line flags](#Global-command-line-flags) - * [`--color` *value*](#--color-value) - * [`-c`, `--config` *filename*](#-c---config-filename) - * [`-D`, `--destination` *directory*](#-D---destination-directory) - * [`-n`, `--dry-run`](#-n---dry-run) - * [`-h`, `--help`](#-h---help) - * [`-S`, `--source` *directory*](#-S---source-directory) - * [`-v`, `--verbose`](#-v---verbose) - * [`--version`](#--version) + * [`--color` *value*](#color-value) + * [`-c`, `--config` *filename*](#c---config-filename) + * [`-D`, `--destination` *directory*](#D---destination-directory) + * [`-n`, `--dry-run`](#n---dry-run) + * [`-h`, `--help`](#h---help) + * [`-r`. `--remove`](#r---remove) + * [`-S`, `--source` *directory*](#S---source-directory) + * [`-v`, `--verbose`](#v---verbose) + * [`--version`](#version) * [Configuration file](#Configuration-file) * [Configuration variables](#Configuration-variables) * [Source state attributes](#Source-state-attributes) From 64d52b4bc213294b128e28803aaf80d4083b0a40 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Sat, 22 Jun 2019 19:57:45 +0200 Subject: [PATCH 5/5] Ignore downloaded binaries --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2d129794394..679352e18e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /*coverage.out +/bin /chezmoi /dist /goreleaser/goreleaser.host.yaml