DirTree.Prune: deletes several directories
This commit is contained in:
parent
7ae7080824
commit
421ba84e12
1 changed files with 81 additions and 0 deletions
81
fs/walk.go
81
fs/walk.go
|
@ -250,6 +250,87 @@ func (dt DirTree) Dirs() (dirNames []string) {
|
||||||
return dirNames
|
return dirNames
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prune remove directories from a directory tree. dirNames contains
|
||||||
|
// all directories to remove as keys, with true as values. dirNames
|
||||||
|
// will be modified in the function.
|
||||||
|
func (dt DirTree) Prune(dirNames map[string]bool) error {
|
||||||
|
// We use map[string]bool to avoid recursion (and potential
|
||||||
|
// stack exhaustion).
|
||||||
|
|
||||||
|
// First we need delete directories from their parents.
|
||||||
|
for dName, remove := range dirNames {
|
||||||
|
if !remove {
|
||||||
|
// Currently all values should be
|
||||||
|
// true, therefore this should not
|
||||||
|
// happen. But this makes function
|
||||||
|
// more predictable.
|
||||||
|
Infof(dName, "Directory in the map for prune, but the value is false")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dName == "" {
|
||||||
|
// if dName is root, do nothing (no parent exist)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parent := parentDir(dName)
|
||||||
|
// It may happen that dt does not have a dName key,
|
||||||
|
// since directory was excluded based on a filter. In
|
||||||
|
// such case the loop will be skipped.
|
||||||
|
for i, entry := range dt[parent] {
|
||||||
|
switch x := entry.(type) {
|
||||||
|
case Directory:
|
||||||
|
if x.Remote() == dName {
|
||||||
|
// the slice is not sorted yet
|
||||||
|
// to delete item
|
||||||
|
// a) replace it with the last one
|
||||||
|
dt[parent][i] = dt[parent][len(dt[parent])-1]
|
||||||
|
// b) remove last
|
||||||
|
dt[parent] = dt[parent][:len(dt[parent])-1]
|
||||||
|
// we modify a slice within a loop, but we stop
|
||||||
|
// iterating immediately
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case Object:
|
||||||
|
// do nothing
|
||||||
|
default:
|
||||||
|
return errors.Errorf("unknown object type %T", entry)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(dirNames) > 0 {
|
||||||
|
// According to golang specs, if new keys were added
|
||||||
|
// during range iteration, they may be skipped.
|
||||||
|
for dName, remove := range dirNames {
|
||||||
|
if !remove {
|
||||||
|
Infof(dName, "Directory in the map for prune, but the value is false")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// First, add all subdirectories to dirNames.
|
||||||
|
|
||||||
|
// It may happen that dt[dName] does not exist.
|
||||||
|
// If so, the loop will be skipped.
|
||||||
|
for _, entry := range dt[dName] {
|
||||||
|
switch x := entry.(type) {
|
||||||
|
case Directory:
|
||||||
|
excludeDir := x.Remote()
|
||||||
|
dirNames[excludeDir] = true
|
||||||
|
case Object:
|
||||||
|
// do nothing
|
||||||
|
default:
|
||||||
|
return errors.Errorf("unknown object type %T", entry)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Then remove current directory from DirTree
|
||||||
|
delete(dt, dName)
|
||||||
|
// and from dirNames
|
||||||
|
delete(dirNames, dName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// String emits a simple representation of the DirTree
|
// String emits a simple representation of the DirTree
|
||||||
func (dt DirTree) String() string {
|
func (dt DirTree) String() string {
|
||||||
out := new(bytes.Buffer)
|
out := new(bytes.Buffer)
|
||||||
|
|
Loading…
Add table
Reference in a new issue