summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2019-02-13 23:43:29 -0500
committerLuke Shumaker <lukeshu@lukeshu.com>2019-02-13 23:43:29 -0500
commit875cacb26fe8b2a0b6367ad5d9867d19e3d98ead (patch)
tree2bb796cfc8b70e64fe10674cfda0ebfcc1745c0c
parent789ebb3d63a0a1dd79132edb91da95df81bf03f1 (diff)
fi-filefilter: clean up
- handle all commands robustly - error checking - don't worry about pruning empty commits, fi-prune-empty exists now
-rw-r--r--fi-filefilter/main.go154
1 files 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 <http://www.gnu.org/licenses/>.
+// 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
}