summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2019-02-18 18:01:37 -0500
committerLuke Shumaker <lukeshu@lukeshu.com>2019-02-18 18:01:37 -0500
commit019f0dfd8d8b3a77552a39ddf83d0f4fc6e8b2f8 (patch)
tree87b134b09e6fb572f88c8486bbb516e857516844
parenta0571345b9a2e8f0d13d30981581e3643eff7d21 (diff)
combined progress tracking
-rw-r--r--fi-filefilter/main.go29
-rw-r--r--fi-progress/progress.go137
-rw-r--r--fi-prune-empty/main.go40
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)