Skip to content

Commit

Permalink
Create .keep files when adding directories non-recursively
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed Apr 18, 2020
1 parent aba694f commit 8499f4d
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 20 deletions.
11 changes: 5 additions & 6 deletions cmd/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ var addCmd = &cobra.Command{
}

type addCmdConfig struct {
force bool
recursive bool
prompt bool
options chezmoi.AddOptions
force bool
prompt bool
options chezmoi.AddOptions
}

func init() {
Expand All @@ -39,7 +38,7 @@ func init() {
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.recursive, "recursive", "r", false, "recurse in to subdirectories")
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")

Expand Down Expand Up @@ -75,7 +74,7 @@ func (c *Config) runAddCmd(cmd *cobra.Command, args []string) (err error) {
if err != nil {
return err
}
if c.add.recursive {
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
Expand Down
47 changes: 42 additions & 5 deletions cmd/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,37 @@ func TestAddCommand(t *testing.T) {
),
},
},
{
name: "add_non_empty_dir",
args: []string{"/home/user/.config/htop"},
root: map[string]interface{}{
"/home/user/.config/htop": map[string]interface{}{
"foo": "bar",
},
},
tests: []vfst.Test{
vfst.TestPath("/home/user/.local/share/chezmoi",
vfst.TestIsDir,
vfst.TestModePerm(0700),
),
vfst.TestPath("/home/user/.local/share/chezmoi/dot_config",
vfst.TestIsDir,
vfst.TestModePerm(0755),
),
vfst.TestPath("/home/user/.local/share/chezmoi/dot_config/htop",
vfst.TestIsDir,
vfst.TestModePerm(0755),
),
vfst.TestPath("/home/user/.local/share/chezmoi/dot_config/htop/.keep",
vfst.TestModeIsRegular,
vfst.TestModePerm(0644),
vfst.TestContents(nil),
),
vfst.TestPath("/home/user/.local/share/chezmoi/dot_config/htop/foo",
vfst.TestDoesNotExist,
),
},
},
{
name: "add_first_file",
args: []string{"/home/user/.bashrc"},
Expand Down Expand Up @@ -136,7 +167,9 @@ func TestAddCommand(t *testing.T) {
name: "add_recursive",
args: []string{"/home/user/.config"},
add: addCmdConfig{
recursive: true,
options: chezmoi.AddOptions{
Recursive: true,
},
},
root: map[string]interface{}{
"/home/user": &vfst.Dir{Perm: 0755},
Expand Down Expand Up @@ -188,9 +221,9 @@ func TestAddCommand(t *testing.T) {
name: "add_exact_dir_recursive",
args: []string{"/home/user/dir"},
add: addCmdConfig{
recursive: true,
options: chezmoi.AddOptions{
Exact: true,
Exact: true,
Recursive: true,
},
},
root: map[string]interface{}{
Expand Down Expand Up @@ -331,7 +364,9 @@ func TestAddCommand(t *testing.T) {
name: "add_symlink_in_dir_recursive",
args: []string{"/home/user/foo"},
add: addCmdConfig{
recursive: true,
options: chezmoi.AddOptions{
Recursive: true,
},
},
root: map[string]interface{}{
"/home/user": &vfst.Dir{Perm: 0755},
Expand Down Expand Up @@ -392,7 +427,9 @@ func TestAddCommand(t *testing.T) {
name: "dont_add_ignored_file_recursive",
args: []string{"/home/user/foo"},
add: addCmdConfig{
recursive: true,
options: chezmoi.AddOptions{
Recursive: true,
},
},
root: map[string]interface{}{
"/home/user": &vfst.Dir{Perm: 0755},
Expand Down
19 changes: 10 additions & 9 deletions internal/chezmoi/targetstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type AddOptions struct {
Empty bool
Encrypt bool
Exact bool
Recursive bool
Template bool
AutoTemplate bool
}
Expand Down Expand Up @@ -226,15 +227,18 @@ func (ts *TargetState) Add(fs vfs.FS, addOptions AddOptions, targetPath string,
if err != nil {
return err
}
empty := len(infos) == 0
private, err := IsPrivate(fs, targetPath, perm&077 == 0)
if err != nil {
return err
}
if private {
perm &^= 077
}
return ts.addDir(targetName, entries, parentDirSourceName, addOptions.Exact, perm, empty, mutator)
// If the directory is empty, or the directory was not added
// recursively, add a .keep file so the directory is managed by git.
// chezmoi will ignore the .keep file as it begins with a dot.
createKeepFile := len(infos) == 0 || !addOptions.Recursive
return ts.addDir(targetName, entries, parentDirSourceName, addOptions.Exact, perm, createKeepFile, mutator)
case info.Mode().IsRegular():
if info.Size() == 0 && !addOptions.Empty {
entry, err := ts.Get(fs, targetPath)
Expand Down Expand Up @@ -580,7 +584,7 @@ func (ts *TargetState) Populate(fs vfs.FS, options *PopulateOptions) error {
})
}

func (ts *TargetState) addDir(targetName string, entries map[string]Entry, parentDirSourceName string, exact bool, perm os.FileMode, empty bool, mutator Mutator) error {
func (ts *TargetState) addDir(targetName string, entries map[string]Entry, parentDirSourceName string, exact bool, perm os.FileMode, createKeepFile bool, mutator Mutator) error {
name := filepath.Base(targetName)
if entry, ok := entries[name]; ok {
if _, ok = entry.(*Dir); !ok {
Expand All @@ -600,10 +604,7 @@ func (ts *TargetState) addDir(targetName string, entries map[string]Entry, paren
if err := mutator.Mkdir(filepath.Join(ts.SourceDir, sourceName), 0777&^ts.Umask); err != nil {
return err
}
// If the directory is empty, add a .keep file so the directory is
// managed by git. Chezmoi will ignore the .keep file as it begins with
// a dot.
if empty {
if createKeepFile {
if err := mutator.WriteFile(filepath.Join(ts.SourceDir, sourceName, ".keep"), nil, 0666&^ts.Umask, nil); err != nil {
return err
}
Expand Down Expand Up @@ -833,8 +834,8 @@ func (ts *TargetState) importHeader(r io.Reader, importTAROptions ImportTAROptio
switch header.Typeflag {
case tar.TypeDir:
perm := os.FileMode(header.Mode).Perm()
empty := false // FIXME don't assume directory is empty
return ts.addDir(targetName, entries, parentDirSourceName, importTAROptions.Exact, perm, empty, mutator)
createKeepFile := false // FIXME don't assume that we don't need a keep file
return ts.addDir(targetName, entries, parentDirSourceName, importTAROptions.Exact, perm, createKeepFile, mutator)
case tar.TypeReg:
info := header.FileInfo()
contents, err := ioutil.ReadAll(r)
Expand Down

0 comments on commit 8499f4d

Please sign in to comment.