diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2019-02-18 18:01:37 -0500 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2019-02-18 18:01:37 -0500 |
commit | 019f0dfd8d8b3a77552a39ddf83d0f4fc6e8b2f8 (patch) | |
tree | 87b134b09e6fb572f88c8486bbb516e857516844 | |
parent | a0571345b9a2e8f0d13d30981581e3643eff7d21 (diff) |
combined progress tracking
-rw-r--r-- | fi-filefilter/main.go | 29 | ||||
-rw-r--r-- | fi-progress/progress.go | 137 | ||||
-rw-r--r-- | fi-prune-empty/main.go | 40 |
3 files changed, 187 insertions, 19 deletions
diff --git a/fi-filefilter/main.go b/fi-filefilter/main.go index 6731c1e..12c291d 100644 --- a/fi-filefilter/main.go +++ b/fi-filefilter/main.go @@ -19,7 +19,6 @@ package main import ( "fmt" - "io" "os" "regexp" "time" @@ -30,21 +29,24 @@ import ( "git.parabola.nu/~lukeshu/fastimport-go-utils/fiutil" ) -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") +func usage() { + fmt.Printf("Usage: git fast-export --full-tree | %s REGEXP | git fast-import\n", os.Args[0]) + fmt.Printf(" or: %s --help\n", os.Args[0]) + fmt.Printf("Prunes a fast-import stream, removing filenames that do not match a regexp\n") + os.Exit(0) } func main() { if len(os.Args) != 2 { - usage(os.Stderr) - os.Exit(2) + fiutil.ErrUsage(fmt.Sprintf("expected exactly 1 argument, got %d", len(os.Args)-1)) + } + if os.Args[1] == "--help" { + usage() } re, err := regexp.Compile(os.Args[1]) if err != nil { - fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) - os.Exit(2) + fiutil.ErrUsage(fmt.Sprintf("bad regexp: %q: %v", os.Args[1], err)) } frontend := libfastimport.NewFrontend(os.Stdin, os.Stdin, nil) @@ -111,11 +113,12 @@ func (h *FileFilter) FileRename(cmd libfastimport.FileRename) error { // statistics ////////////////////////////////////////////////////////////////// func (h *FileFilter) CmdCommitEnd(cmd libfastimport.CmdCommitEnd) error { h.commits++ - fmt.Fprintf(os.Stderr, - "%d commits (%d => %d files) (%.2f commit/s)\r", - h.commits, h.filesIn, h.filesOut, - float64(h.commits)/time.Since(h.beg).Seconds()) - return nil + return h.backend.Do(libfastimport.CmdProgress{ + Str: fmt.Sprintf("[%s] %d commits (%d => %d files) (%.2f commit/s)", + os.Args[0], + h.commits, h.filesIn, h.filesOut, + float64(h.commits)/time.Since(h.beg).Seconds()), + }) } // note commands /////////////////////////////////////////////////////////////// diff --git a/fi-progress/progress.go b/fi-progress/progress.go new file mode 100644 index 0000000..a49923f --- /dev/null +++ b/fi-progress/progress.go @@ -0,0 +1,137 @@ +// Copyright 2019 Luke Shumaker <lukeshu@parabola.nu> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package main + +import ( + "fmt" + "os" + "regexp" + + "git.lukeshu.com/go/libfastimport" + + "git.parabola.nu/~lukeshu/fastimport-go-utils/fiutil" +) + +func usage() { + fmt.Printf("Usage: %s REGEX1 [REGEX2...]\n", os.Args[0]) + os.Exit(0) +} + +func main() { + if len(os.Args) < 2 { + fiutil.ErrUsage("must give at least 1 regexp") + } + + frontend := libfastimport.NewFrontend(os.Stdin, os.Stdin, nil) + backend := libfastimport.NewBackend(os.Stdout, os.Stdout, nil) + + filter := &Progress{ + backend: backend, + } + for _, str := range os.Args[1:] { + if str == "--help" { + usage() + } + re, err := regexp.Compile(str) + if err != nil { + fiutil.ErrUsage(fmt.Sprintf("bad regexp: %q: %v", str, err)) + } + filter.filters = append(filter.filters, re) + } + + filter.start() + err := fiutil.RunHandler(frontend, filter) + filter.end() + if err != nil { + fmt.Fprintf(os.Stderr, "%s: error: %v\n", os.Args[0], err) + os.Exit(1) + } +} + +type Progress struct { + backend *libfastimport.Backend + filters []*regexp.Regexp + curLine int +} + +func (h *Progress) start() { + for _ = range h.filters { + fmt.Fprintln(os.Stderr, "progress ") + h.curLine++ + } +} + +func (h *Progress) end() { + if h.curLine == len(h.filters) { + return + } + fmt.Fprintf(os.Stderr, "\r\x1B[%dB", len(h.filters)-h.curLine) +} + +func (h *Progress) CmdProgress(cmd libfastimport.CmdProgress) error { + for i := range h.filters { + if h.filters[i].MatchString(cmd.Str) { + d := i - h.curLine + var prefix string + switch { + case d < 0: + prefix = fmt.Sprintf("\x1B[%dA", -d) + case d == 0: + prefix = "" + case d > 0: + prefix = fmt.Sprintf("\x1B[%dB", d) + } + fmt.Fprintf(os.Stderr, "\r%sprogress %s\x1B[0K", prefix, cmd.Str) + h.curLine = i + return nil + } + } + return h.backend.Do(cmd) +} + +// pass through everything else +func (h *Progress) CmdBlob(cmd libfastimport.CmdBlob) error { return h.backend.Do(cmd) } +func (h *Progress) CmdCheckpoint(cmd libfastimport.CmdCheckpoint) error { return h.backend.Do(cmd) } +func (h *Progress) CmdComment(cmd libfastimport.CmdComment) error { return h.backend.Do(cmd) } +func (h *Progress) CmdCommit(cmd libfastimport.CmdCommit) error { return h.backend.Do(cmd) } +func (h *Progress) CmdCommitEnd(cmd libfastimport.CmdCommitEnd) error { return h.backend.Do(cmd) } +func (h *Progress) CmdDone(cmd libfastimport.CmdDone) error { return h.backend.Do(cmd) } +func (h *Progress) CmdFeature(cmd libfastimport.CmdFeature) error { return h.backend.Do(cmd) } +func (h *Progress) CmdOption(cmd libfastimport.CmdOption) error { return h.backend.Do(cmd) } +func (h *Progress) CmdReset(cmd libfastimport.CmdReset) error { return h.backend.Do(cmd) } +func (h *Progress) CmdTag(cmd libfastimport.CmdTag) error { return h.backend.Do(cmd) } +func (h *Progress) FileCopy(cmd libfastimport.FileCopy) error { return h.backend.Do(cmd) } +func (h *Progress) FileDelete(cmd libfastimport.FileDelete) error { return h.backend.Do(cmd) } +func (h *Progress) FileDeleteAll(cmd libfastimport.FileDeleteAll) error { return h.backend.Do(cmd) } +func (h *Progress) FileModify(cmd libfastimport.FileModify) error { return h.backend.Do(cmd) } +func (h *Progress) FileModifyInline(cmd libfastimport.FileModifyInline) error { + return h.backend.Do(cmd) +} +func (h *Progress) FileRename(cmd libfastimport.FileRename) error { return h.backend.Do(cmd) } +func (h *Progress) NoteModify(cmd libfastimport.NoteModify) error { return h.backend.Do(cmd) } +func (h *Progress) NoteModifyInline(cmd libfastimport.NoteModifyInline) error { + return h.backend.Do(cmd) +} + +func (h *Progress) CmdCatBlob(cmd libfastimport.CmdCatBlob) (sha1 string, data string, err error) { + return h.backend.CatBlob(cmd) +} +func (h *Progress) CmdGetMark(cmd libfastimport.CmdGetMark) (sha1 string, err error) { + return h.backend.GetMark(cmd) +} +func (h *Progress) CmdLs(cmd libfastimport.CmdLs) (mode libfastimport.Mode, dataref string, path libfastimport.Path, err error) { + return h.backend.Ls(cmd) +} diff --git a/fi-prune-empty/main.go b/fi-prune-empty/main.go index e729a12..7c1ea5d 100644 --- a/fi-prune-empty/main.go +++ b/fi-prune-empty/main.go @@ -19,11 +19,11 @@ package main import ( "fmt" - "io" "os" "sort" "strconv" "strings" + "time" "git.lukeshu.com/go/libfastimport" "github.com/pkg/errors" @@ -31,15 +31,18 @@ import ( "git.parabola.nu/~lukeshu/fastimport-go-utils/fiutil" ) -func usage(w io.Writer) { - fmt.Fprintf(w, "Usage: git fast-export --full-tree | %s | git fast-import\n", os.Args[0]) - fmt.Fprintf(w, "Prunes a fast-import stream, removing empty commits and empty merges\n") +func usage() { + fmt.Printf("Usage: git fast-export --full-tree | %s | git fast-import\n", os.Args[0]) + fmt.Printf("Prunes a fast-import stream, removing empty commits and empty merges\n") + os.Exit(0) } func main() { + if len(os.Args) == 2 && os.Args[1] == "--help" { + usage() + } if len(os.Args) != 1 { - usage(os.Stderr) - os.Exit(2) + fiutil.ErrUsage(fmt.Sprintf("expected 0 arguments, got %d", len(os.Args)-1)) } frontend := libfastimport.NewFrontend(os.Stdin, os.Stdin, nil) @@ -73,28 +76,42 @@ func TreesEqual(a, b Tree) bool { type PruneEmpty struct { backend *libfastimport.Backend + // history replace map[string]string + // history ancestors map[string]map[string]struct{} trees map[string]Tree refs map[string]string + // current commit commitMeta libfastimport.CmdCommit commitFile Tree + + // statistics + commitsIn int + commitsOut int + beg time.Time } func NewPruneEmpty(backend *libfastimport.Backend) *PruneEmpty { return &PruneEmpty{ backend: backend, + // history replace: map[string]string{}, + // history ancestors: map[string]map[string]struct{}{}, trees: map[string]Tree{}, refs: map[string]string{}, + // current commit commitMeta: libfastimport.CmdCommit{}, commitFile: Tree{}, + + // statistics + beg: time.Now(), } } @@ -155,6 +172,16 @@ func (h *PruneEmpty) CmdCommit(cmd libfastimport.CmdCommit) error { return nil } func (h *PruneEmpty) CmdCommitEnd(cmd libfastimport.CmdCommitEnd) error { + h.commitsIn++ + defer func() { + h.backend.Do(libfastimport.CmdProgress{ + Str: fmt.Sprintf("[%s] %d commits => %d commits (%.2f commit/s)", + os.Args[0], + h.commitsIn, h.commitsOut, + float64(h.commitsIn)/time.Since(h.beg).Seconds()), + }) + }() + mark := fmt.Sprintf(":%d", h.commitMeta.Mark) from := h.commitMeta.From if from == "" { @@ -183,6 +210,7 @@ func (h *PruneEmpty) CmdCommitEnd(cmd libfastimport.CmdCommitEnd) error { h.commitMeta.From = parents[0] h.commitMeta.Merge = parents[1:] } + h.commitsOut++ // remember the commit h.addCommit(mark, parents, h.commitFile) |