From 875cacb26fe8b2a0b6367ad5d9867d19e3d98ead Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 13 Feb 2019 23:43:29 -0500 Subject: fi-filefilter: clean up - handle all commands robustly - error checking - don't worry about pruning empty commits, fi-prune-empty exists now --- fi-filefilter/main.go | 154 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 101 insertions(+), 53 deletions(-) diff --git a/fi-filefilter/main.go b/fi-filefilter/main.go index 645b8c4..44ab5fe 100644 --- a/fi-filefilter/main.go +++ b/fi-filefilter/main.go @@ -13,6 +13,8 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +// Command fi-filefilter prunes a fast-import stream, removing +// filenames that do not match a regexp. package main import ( @@ -20,106 +22,152 @@ import ( "io" "os" "regexp" - "strings" "time" "git.lukeshu.com/go/libfastimport" + "github.com/pkg/errors" ) -func abort(err error) { - fmt.Fprintln(os.Stderr, "Error:", err) - os.Exit(1) +func usage(w io.Writer) { + fmt.Fprintf(w, "Usage: git fast-export --full-tree | %s REGEXP | git fast-import\n", os.Args[0]) + fmt.Fprintf(w, "Prunes a fast-import stream, removing filenames that do not match a regexp\n") } -var commit *libfastimport.CmdCommit - -var ( - frontend = libfastimport.NewFrontend(os.Stdin, nil, nil) - backend = libfastimport.NewBackend(os.Stdout, nil, nil) -) - -func ensureCommit() { - if commit == nil { - return +func main() { + if len(os.Args) != 2 { + usage(os.Stderr) + os.Exit(2) } - backend.Do(*commit) - commit = nil -} -func main() { re, err := regexp.Compile(os.Args[1]) if err != nil { - abort(err) + fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) + os.Exit(2) } + frontend := libfastimport.NewFrontend(os.Stdin, os.Stdin, nil) + backend := libfastimport.NewBackend(os.Stdout, os.Stdout, nil) + + if err := filefilter(backend, frontend, re); err != nil { + fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) + os.Exit(1) + } +} + +func filefilter(backend *libfastimport.Backend, frontend *libfastimport.Frontend, re *regexp.Regexp) error { commits := 0 + filesIn := 0 + filesOut := 0 beg := time.Now() status := func() { fmt.Fprintf(os.Stderr, - "%d commits (%.2f commit/s)\r", - commits, + "%d commits (%d => %d files) (%.2f commit/s)\r", + commits, filesIn, filesOut, float64(commits)/time.Since(beg).Seconds()) } - froms := map[string]string{} for { cmd, err := frontend.ReadCmd() if err != nil { if err == io.EOF { break } - abort(err) + return err } switch cmdt := cmd.(type) { - case libfastimport.CmdCommit: - commit = &cmdt - if strings.HasPrefix(commit.From, ":") { - if from, ok := froms[commit.From]; ok { - commit.From = from - } - } - for i, m := range commit.Merge { - if strings.HasPrefix(m, ":") { - if from, ok := froms[m]; ok { - commit.Merge[i] = from - } - } - } - + // file commands case libfastimport.FileModify: + filesIn++ if re.MatchString(string(cmdt.Path)) { - ensureCommit() - backend.Do(cmd) + filesOut++ + if err := backend.Do(cmd); err != nil { + return err + } } case libfastimport.FileModifyInline: + filesIn++ if re.MatchString(string(cmdt.Path)) { - ensureCommit() - backend.Do(cmd) + filesOut++ + if err := backend.Do(cmd); err != nil { + return err + } } case libfastimport.FileDelete: + filesIn++ if re.MatchString(string(cmdt.Path)) { - ensureCommit() - backend.Do(cmd) + filesOut++ + if err := backend.Do(cmd); err != nil { + return err + } + } + case libfastimport.FileDeleteAll: + if err := backend.Do(cmd); err != nil { + return err } case libfastimport.FileCopy: - panic("copy") + return errors.New("unexpected \"filecopy\" command: this filter requires --full-tree") case libfastimport.FileRename: - panic("rename") + return errors.New("unexpected \"filerename\" command: this filter requires --full-tree") + // statistics case libfastimport.CmdCommitEnd: - if commit != nil { - if commit.Mark >= 0 { - froms[fmt.Sprintf(":%d", commit.Mark)] = commit.From - } - commit = nil - } commits++ status() + // regular commands + case libfastimport.CmdBlob, libfastimport.CmdCheckpoint, libfastimport.CmdComment, libfastimport.CmdCommit, libfastimport.CmdDone, libfastimport.CmdReset, libfastimport.CmdTag: + if err := backend.Do(cmd); err != nil { + return err + } + + // special commands + case libfastimport.CmdProgress, libfastimport.CmdOption: + if err := backend.Do(cmd); err != nil { + return err + } + case libfastimport.CmdFeature: + switch cmdt.Feature { + case "date-format": + if cmdt.Argument != "raw" { + return errors.Errorf("date-format=%q: only supports the %q format", cmdt.Argument, "raw") + } + if err := backend.Do(cmd); err != nil { + return err + } + case "export-marks", "relative-marks", "no-relative-marks", "force", "import-marks", "import-marks-if-exists", "get-mark", "cat-blob", "ls", "notes", "done": + if err := backend.Do(cmd); err != nil { + return err + } + } + case libfastimport.CmdCatBlob: + sha1, data, err := backend.CatBlob(cmdt) + if err != nil { + return err + } + if err := frontend.RespondCatBlob(sha1, data); err != nil { + return err + } + case libfastimport.CmdGetMark: + sha1, err := backend.GetMark(cmdt) + if err != nil { + return err + } + if err := frontend.RespondGetMark(sha1); err != nil { + return err + } + case libfastimport.CmdLs: + mode, dataref, path, err := backend.Ls(cmdt) + if err != nil { + return err + } + if err := frontend.RespondLs(mode, dataref, path); err != nil { + return err + } default: - backend.Do(cmd) + panic("should not happen") } } + return nil } -- cgit v1.2.2