From c8c5616b5380e265f060b5828d0df39950f7891d Mon Sep 17 00:00:00 2001 From: thesayyn Date: Tue, 24 Oct 2023 09:13:35 -0700 Subject: [PATCH] feat: implement mutate command --- cmd/gomtree/cmd/mutate.go | 144 +++++++++++++++++++++++++++++++++++ cmd/gomtree/main.go | 1 + go.mod | 2 +- testdata/flat.relative.mtree | 20 +++++ 4 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 cmd/gomtree/cmd/mutate.go create mode 100644 testdata/flat.relative.mtree diff --git a/cmd/gomtree/cmd/mutate.go b/cmd/gomtree/cmd/mutate.go new file mode 100644 index 0000000..bbcfc68 --- /dev/null +++ b/cmd/gomtree/cmd/mutate.go @@ -0,0 +1,144 @@ +package cmd + +import ( + "fmt" + "io" + "math" + "os" + "slices" + "strings" + + cli "github.com/urfave/cli/v2" + "github.com/vbatts/go-mtree" +) + +func NewMutateCommand() *cli.Command { + + return &cli.Command{ + Name: "mutate", + Usage: "mutate an mtree", + Description: `Mutate an mtree to have different shapes. +TODO: more info examples`, + Action: mutateAction, + ArgsUsage: " [path to output]", + Flags: []cli.Flag{ + &cli.StringSliceFlag{ + Name: "strip-prefix", + }, + &cli.BoolFlag{ + Name: "keep-comments", + Value: false, + }, + &cli.BoolFlag{ + Name: "keep-blank", + Value: false, + }, + &cli.StringFlag{ + Name: "output", + TakesFile: true, + }, + }, + } +} + +func mutateAction(c *cli.Context) error { + mtreePath := c.Args().Get(0) + outputPath := c.Args().Get(1) + stripPrexies := c.StringSlice("strip-prefix") + keepComments := c.Bool("keep-comments") + keepBlank := c.Bool("keep-blank") + + if mtreePath == "" { + return fmt.Errorf("mtree path is required.") + } else if outputPath == "" { + outputPath = mtreePath + } + + file, err := os.Open(mtreePath) + if err != nil { + return fmt.Errorf("opening %s: %w", mtreePath, err) + } + + spec, err := mtree.ParseSpec(file) + if err != nil { + return fmt.Errorf("parsing mtree %s: %w", mtreePath, err) + } + + dropDotDot := 0 + droppedParents := []*mtree.Entry{} + + entries := []mtree.Entry{} + +skip: + for _, entry := range spec.Entries { + + if !keepComments && entry.Type == mtree.CommentType { + continue + } + if !keepBlank && entry.Type == mtree.BlankType { + continue + } + + if entry.Parent != nil && slices.Contains(droppedParents, &entry) { + entry.Parent = nil + 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 { + return err + } + pathSegments := strings.Split(fp, "/") + + for _, prefix := range stripPrexies { + + 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 == "" { + 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) + } + + spec.Entries = entries + + var writer io.Writer = os.Stdout + if outputPath != "-" { + writer, err = os.Create(outputPath) + if err != nil { + return fmt.Errorf("creating output %s: %w", outputPath, err) + } + } + + spec.WriteTo(writer) + + return nil +} diff --git a/cmd/gomtree/main.go b/cmd/gomtree/main.go index 90fff23..3de5825 100644 --- a/cmd/gomtree/main.go +++ b/cmd/gomtree/main.go @@ -42,6 +42,7 @@ to support xattrs and interacting with tar archives.` } app.Commands = []*cli.Command{ cmd.NewValidateCommand(), + cmd.NewMutateCommand(), } // Unfortunately urfave/cli is not at good at using DefaultCommand diff --git a/go.mod b/go.mod index 944aeaa..5d44607 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/vbatts/go-mtree -go 1.17 +go 1.18 require ( github.com/davecgh/go-spew v1.1.1 diff --git a/testdata/flat.relative.mtree b/testdata/flat.relative.mtree new file mode 100644 index 0000000..e575ec3 --- /dev/null +++ b/testdata/flat.relative.mtree @@ -0,0 +1,20 @@ +# ./lib +lib type=dir mode=0644 + foo mode=0644 size=12288 time=1457644483.833957552 type=file + +# ./lib/dir +lib type=dir mode=0644 + +dir type=dir mode=0644 + +# ./lib +.. + +# . +.. + +# ./lib/dir/sub +lib/dir/sub type=dir +lib/dir/sub/file.txt type=file + +lib/dir/PKG.info type=file mode=0644