visitor pattern

This commit is contained in:
thesayyn 2023-10-24 15:58:31 -07:00
parent c8c5616b53
commit 17374843eb
No known key found for this signature in database
GPG Key ID: D10C0AE203D0E4A8
4 changed files with 93 additions and 57 deletions

View File

@ -64,67 +64,46 @@ func mutateAction(c *cli.Context) error {
return fmt.Errorf("parsing mtree %s: %w", mtreePath, err) return fmt.Errorf("parsing mtree %s: %w", mtreePath, err)
} }
dropDotDot := 0 stripPrefixVisitor := stripPrefixVisitor{
droppedParents := []*mtree.Entry{} prefixes: stripPrexies,
}
tidyVisitor := tidyVisitor{
keepComments: keepComments,
keepBlank: keepBlank,
}
visitors := []Visitor{
&stripPrefixVisitor,
&tidyVisitor,
}
dropped := []int{}
entries := []mtree.Entry{} entries := []mtree.Entry{}
skip: skip:
for _, entry := range spec.Entries { for _, entry := range spec.Entries {
if !keepComments && entry.Type == mtree.CommentType { if entry.Parent != nil && slices.Contains(dropped, entry.Parent.Pos) {
continue if entry.Type == mtree.DotDotType {
} // directory for this .. has been dropped so shall this
if !keepBlank && entry.Type == mtree.BlankType { continue
continue }
entry.Parent = entry.Parent.Parent
// TODO: i am not sure if this is the correct behavior
entry.Raw = strings.TrimPrefix(entry.Raw, " ")
} }
if entry.Parent != nil && slices.Contains(droppedParents, &entry) { for _, visitor := range visitors {
entry.Parent = nil drop, err := visitor.Visit(&entry)
entry.Type = mtree.FullType
entry.Raw = ""
}
if entry.Type == mtree.FullType || entry.Type == mtree.RelativeType {
fp, err := entry.Path()
// fmt.Println("fp", fp, entry.Name)
if err != nil { if err != nil {
return err return err
} }
pathSegments := strings.Split(fp, "/")
for _, prefix := range stripPrexies { if drop {
dropped = append(dropped, entry.Pos)
prefixSegments := strings.Split(prefix, "/") continue skip
minLen := int(math.Min(float64(len(pathSegments)), float64(len(prefixSegments))))
matches := make([]string, minLen)
for i := 0; i < minLen; i++ {
if pathSegments[i] == prefixSegments[i] {
matches[i] = prefixSegments[i]
}
}
strip := strings.Join(matches, "/")
if entry.Type == mtree.FullType {
entry.Name = strings.TrimPrefix(entry.Name, strip)
entry.Name = strings.TrimPrefix(entry.Name, "/")
if entry.Name == "" {
continue skip
}
} else {
if entry.IsDir() {
dropDotDot++
droppedParents = append(droppedParents, &entry)
}
if fp == strip {
continue skip
}
}
} }
} else if dropDotDot > 0 && entry.Type == mtree.DotDotType {
dropDotDot--
continue skip
} }
entries = append(entries, entry) entries = append(entries, entry)
} }
@ -142,3 +121,61 @@ skip:
return nil return nil
} }
type Visitor interface {
Visit(entry *mtree.Entry) (bool, error)
}
type tidyVisitor struct {
keepComments bool
keepBlank bool
}
func (m *tidyVisitor) Visit(entry *mtree.Entry) (bool, error) {
if !m.keepComments && entry.Type == mtree.CommentType {
return true, nil
} else if !m.keepBlank && entry.Type == mtree.BlankType {
return true, nil
}
return false, nil
}
type stripPrefixVisitor struct {
prefixes []string
}
func (m *stripPrefixVisitor) Visit(entry *mtree.Entry) (bool, error) {
if entry.Type != mtree.FullType && entry.Type != mtree.RelativeType {
return false, nil
}
fp, err := entry.Path()
if err != nil {
return false, err
}
pathSegments := strings.Split(fp, "/")
for _, prefix := range m.prefixes {
prefixSegments := strings.Split(prefix, "/")
minLen := int(math.Min(float64(len(pathSegments)), float64(len(prefixSegments))))
matches := make([]string, minLen)
for i := 0; i < minLen; i++ {
if pathSegments[i] == prefixSegments[i] {
matches[i] = prefixSegments[i]
}
}
strip := strings.Join(matches, "/")
if entry.Type == mtree.FullType {
entry.Name = strings.TrimPrefix(entry.Name, strip)
entry.Name = strings.TrimPrefix(entry.Name, "/")
if entry.Name == "" {
return true, nil
}
} else if fp == strip {
return true, nil
}
}
return false, nil
}

View File

@ -134,7 +134,10 @@ func (e Entry) String() string {
if e.Type == SpecialType || e.Type == FullType || inKeyValSlice("type=dir", e.Keywords) { if e.Type == SpecialType || e.Type == FullType || inKeyValSlice("type=dir", e.Keywords) {
return fmt.Sprintf("%s %s", e.Name, strings.Join(KeyValToString(e.Keywords), " ")) return fmt.Sprintf("%s %s", e.Name, strings.Join(KeyValToString(e.Keywords), " "))
} }
return fmt.Sprintf(" %s %s", e.Name, strings.Join(KeyValToString(e.Keywords), " ")) if e.Parent != nil && e.Type != DotDotType {
return fmt.Sprintf(" %s %s", e.Name, strings.Join(KeyValToString(e.Keywords), " "))
}
return fmt.Sprintf("%s %s", e.Name, strings.Join(KeyValToString(e.Keywords), " "))
} }
// AllKeys returns the full set of KeyVal for the given entry, based on the // AllKeys returns the full set of KeyVal for the given entry, based on the

View File

@ -58,6 +58,7 @@ func ParseSpec(r io.Reader) (*DirectoryHierarchy, error) {
e.Type = DotDotType e.Type = DotDotType
e.Raw = str e.Raw = str
if creator.curDir != nil { if creator.curDir != nil {
e.Parent = creator.curDir
creator.curDir = creator.curDir.Parent creator.curDir = creator.curDir.Parent
} }
// nothing else to do here // nothing else to do here

View File

@ -2,18 +2,13 @@
lib type=dir mode=0644 lib type=dir mode=0644
foo mode=0644 size=12288 time=1457644483.833957552 type=file foo mode=0644 size=12288 time=1457644483.833957552 type=file
# ./lib/dir
lib type=dir mode=0644
dir type=dir mode=0644
# ./lib
.. ..
# . ./lib type=dir mode=0644
..
ayo mode=0644 size=12288 time=1457644483.833957552 type=file
# ./lib/dir/sub
lib/dir/sub type=dir lib/dir/sub type=dir
lib/dir/sub/file.txt type=file lib/dir/sub/file.txt type=file