Skip to content

Commit e20cafb

Browse files
committed
feat: implement mutate command
1 parent e7a79ae commit e20cafb

4 files changed

Lines changed: 166 additions & 1 deletion

File tree

cmd/gomtree/cmd/mutate.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"math"
7+
"os"
8+
"slices"
9+
"strings"
10+
11+
cli "github.com/urfave/cli/v2"
12+
"github.com/vbatts/go-mtree"
13+
)
14+
15+
func NewMutateCommand() *cli.Command {
16+
17+
return &cli.Command{
18+
Name: "mutate",
19+
Usage: "mutate an mtree",
20+
Description: `Mutate an mtree to have different shapes.
21+
TODO: more info examples`,
22+
Action: mutateAction,
23+
ArgsUsage: "<path to mtree> [path to output]",
24+
Flags: []cli.Flag{
25+
&cli.StringSliceFlag{
26+
Name: "strip-prefix",
27+
},
28+
&cli.BoolFlag{
29+
Name: "keep-comments",
30+
Value: false,
31+
},
32+
&cli.BoolFlag{
33+
Name: "keep-blank",
34+
Value: false,
35+
},
36+
&cli.StringFlag{
37+
Name: "output",
38+
TakesFile: true,
39+
},
40+
},
41+
}
42+
}
43+
44+
func mutateAction(c *cli.Context) error {
45+
mtreePath := c.Args().Get(0)
46+
outputPath := c.Args().Get(1)
47+
stripPrexies := c.StringSlice("strip-prefix")
48+
keepComments := c.Bool("keep-comments")
49+
keepBlank := c.Bool("keep-blank")
50+
51+
if mtreePath == "" {
52+
return fmt.Errorf("mtree path is required.")
53+
} else if outputPath == "" {
54+
outputPath = mtreePath
55+
}
56+
57+
file, err := os.Open(mtreePath)
58+
if err != nil {
59+
return fmt.Errorf("opening %s: %w", mtreePath, err)
60+
}
61+
62+
spec, err := mtree.ParseSpec(file)
63+
if err != nil {
64+
return fmt.Errorf("parsing mtree %s: %w", mtreePath, err)
65+
}
66+
67+
dropDotDot := 0
68+
droppedParents := []*mtree.Entry{}
69+
70+
entries := []mtree.Entry{}
71+
72+
skip:
73+
for _, entry := range spec.Entries {
74+
75+
if !keepComments && entry.Type == mtree.CommentType {
76+
continue
77+
}
78+
if !keepBlank && entry.Type == mtree.BlankType {
79+
continue
80+
}
81+
82+
if entry.Parent != nil && slices.Contains(droppedParents, &entry) {
83+
entry.Parent = nil
84+
entry.Type = mtree.FullType
85+
entry.Raw = ""
86+
}
87+
88+
if entry.Type == mtree.FullType || entry.Type == mtree.RelativeType {
89+
fp, err := entry.Path()
90+
// fmt.Println("fp", fp, entry.Name)
91+
if err != nil {
92+
return err
93+
}
94+
pathSegments := strings.Split(fp, "/")
95+
96+
for _, prefix := range stripPrexies {
97+
98+
prefixSegments := strings.Split(prefix, "/")
99+
minLen := int(math.Min(float64(len(pathSegments)), float64(len(prefixSegments))))
100+
matches := make([]string, minLen)
101+
for i := 0; i < minLen; i++ {
102+
if pathSegments[i] == prefixSegments[i] {
103+
matches[i] = prefixSegments[i]
104+
}
105+
}
106+
107+
strip := strings.Join(matches, "/")
108+
if entry.Type == mtree.FullType {
109+
entry.Name = strings.TrimPrefix(entry.Name, strip)
110+
entry.Name = strings.TrimPrefix(entry.Name, "/")
111+
if entry.Name == "" {
112+
continue skip
113+
}
114+
} else {
115+
if entry.IsDir() {
116+
dropDotDot++
117+
droppedParents = append(droppedParents, &entry)
118+
}
119+
if fp == strip {
120+
continue skip
121+
}
122+
}
123+
}
124+
} else if dropDotDot > 0 && entry.Type == mtree.DotDotType {
125+
dropDotDot--
126+
continue skip
127+
}
128+
entries = append(entries, entry)
129+
}
130+
131+
spec.Entries = entries
132+
133+
var writer io.Writer = os.Stdout
134+
if outputPath != "-" {
135+
writer, err = os.Create(outputPath)
136+
if err != nil {
137+
return fmt.Errorf("creating output %s: %w", outputPath, err)
138+
}
139+
}
140+
141+
spec.WriteTo(writer)
142+
143+
return nil
144+
}

cmd/gomtree/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ to support xattrs and interacting with tar archives.`
4242
}
4343
app.Commands = []*cli.Command{
4444
cmd.NewValidateCommand(),
45+
cmd.NewMutateCommand(),
4546
}
4647

4748
// Unfortunately urfave/cli is not at good at using DefaultCommand

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/vbatts/go-mtree
22

3-
go 1.17
3+
go 1.18
44

55
require (
66
github.com/davecgh/go-spew v1.1.1

testdata/flat.relative.mtree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# ./lib
2+
lib type=dir mode=0644
3+
foo mode=0644 size=12288 time=1457644483.833957552 type=file
4+
5+
# ./lib/dir
6+
lib type=dir mode=0644
7+
8+
dir type=dir mode=0644
9+
10+
# ./lib
11+
..
12+
13+
# .
14+
..
15+
16+
# ./lib/dir/sub
17+
lib/dir/sub type=dir
18+
lib/dir/sub/file.txt type=file
19+
20+
lib/dir/PKG.info type=file mode=0644

0 commit comments

Comments
 (0)