/
add.go
152 lines (142 loc) · 4.2 KB
/
add.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package cmd
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
vfs "github.com/twpayne/go-vfs"
"github.com/twpayne/chezmoi/internal/chezmoi"
)
var addCmd = &cobra.Command{
Use: "add targets...",
Aliases: []string{"manage"},
Args: cobra.MinimumNArgs(1),
Short: "Add an existing file, directory, or symlink to the source state",
Long: mustGetLongHelp("add"),
Example: getExample("add"),
PreRunE: config.ensureNoError,
RunE: config.runAddCmd,
PostRunE: config.autoCommitAndAutoPush,
}
type addCmdConfig struct {
force bool
prompt bool
options chezmoi.AddOptions
}
func init() {
rootCmd.AddCommand(addCmd)
persistentFlags := addCmd.PersistentFlags()
persistentFlags.BoolVarP(&config.add.options.Empty, "empty", "e", false, "add empty files")
persistentFlags.BoolVar(&config.add.options.Encrypt, "encrypt", false, "encrypt files")
persistentFlags.BoolVarP(&config.add.force, "force", "f", false, "overwrite source state, even if template would be lost")
persistentFlags.BoolVarP(&config.add.options.Exact, "exact", "x", false, "add directories exactly")
persistentFlags.BoolVarP(&config.add.prompt, "prompt", "p", false, "prompt before adding")
persistentFlags.BoolVarP(&config.add.options.Recursive, "recursive", "r", false, "recurse in to subdirectories")
persistentFlags.BoolVarP(&config.add.options.Template, "template", "T", false, "add files as templates")
persistentFlags.BoolVarP(&config.add.options.AutoTemplate, "autotemplate", "a", false, "auto generate the template when adding files as templates")
markRemainingZshCompPositionalArgumentsAsFiles(addCmd, 1)
}
func (c *Config) runAddCmd(cmd *cobra.Command, args []string) (err error) {
// Make --autotemplate imply --template.
if c.add.options.AutoTemplate {
c.add.options.Template = true
}
ts, err := c.getTargetState(nil)
if err != nil {
return err
}
if err := c.ensureSourceDirectory(); err != nil {
return err
}
destDirPrefix := filepath.FromSlash(ts.DestDir + "/")
var quit int // quit is an int with a unique address
defer func() {
if r := recover(); r != nil {
if p, ok := r.(*int); ok && p == &quit {
err = nil
} else {
panic(r)
}
}
}()
for _, arg := range args {
path, err := filepath.Abs(arg)
if err != nil {
return err
}
if c.add.options.Recursive {
if err := vfs.Walk(c.fs, path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if ts.TargetIgnore.Match(strings.TrimPrefix(path, destDirPrefix)) {
cmd.Printf("warning: %s: skipping file ignored by .chezmoiignore\n", path)
return nil
}
if !c.add.force {
entry, err := ts.Get(c.fs, path)
if err != nil && !os.IsNotExist(err) {
return err
}
if file, ok := entry.(*chezmoi.File); ok && file.Template {
cmd.Printf("warning: %s: skipping file generated by template, use --force to force\n", path)
return nil
}
}
if c.add.prompt {
choice, err := c.prompt(fmt.Sprintf("Add %s", path), "ynqa")
if err != nil {
return err
}
switch choice {
case 'y':
case 'n':
return nil
case 'q':
panic(&quit) // abort vfs.Walk by panicking
case 'a':
c.add.prompt = false
}
}
return ts.Add(c.fs, c.add.options, path, info, c.Follow, c.mutator)
}); err != nil {
return err
}
} else {
if ts.TargetIgnore.Match(strings.TrimPrefix(path, destDirPrefix)) {
cmd.Printf("warning: %s: skipping file ignored by .chezmoiignore\n", path)
continue
}
if !c.add.force {
entry, err := ts.Get(c.fs, path)
if err != nil && !os.IsNotExist(err) {
return err
}
if file, ok := entry.(*chezmoi.File); ok && file.Template {
cmd.Printf("warning: %s: skipping file generated by template, use --force to force\n", path)
continue
}
}
if c.add.prompt {
choice, err := c.prompt(fmt.Sprintf("Add %s", path), "ynqa")
if err != nil {
return err
}
switch choice {
case 'y':
case 'n':
continue
case 'q':
return nil
case 'a':
c.add.prompt = false
}
}
if err := ts.Add(c.fs, c.add.options, path, nil, c.Follow, c.mutator); err != nil {
return err
}
}
}
return nil
}