summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2017-11-23 03:10:14 -0500
committerLuke Shumaker <lukeshu@lukeshu.com>2017-11-23 03:10:14 -0500
commit81ce784f367dcd29de79cb12a750b28a7facfaac (patch)
treec9ad3772f70ac28948a1060fcbde923e10e181c3
parent991fcf53af926668c513b8fd74d47fcf8f243756 (diff)
more
-rw-r--r--filter.go83
-rw-r--r--git.go29
-rw-r--r--heuristics.go51
3 files changed, 126 insertions, 37 deletions
diff --git a/filter.go b/filter.go
index 56fddca..e263988 100644
--- a/filter.go
+++ b/filter.go
@@ -13,6 +13,11 @@ import (
"git.lukeshu.com/go/libfastimport"
)
+type fullcommit struct {
+ metadata libfastimport.CmdCommit
+ fileactions []libfastimport.Cmd
+}
+
type Filter struct {
fromRef string
toPfx string
@@ -20,16 +25,25 @@ type Filter struct {
frontend *libfastimport.Frontend
backend *libfastimport.Backend
+ refs map[string]string
mark int
+
+ curCommitIn libfastimport.CmdCommit
+ curCommitOut map[string]fullcommit
}
-func NewFilter(fromRef string, toPfix string) (*Filter, error) {
+func NewFilter(fromRef string, toPfx string) (*Filter, error) {
var err error
ret := &Filter{
- fromPfx: fromPfx,
+ fromRef: fromRef,
toPfx: toPfx,
}
+ ret.refs, err = gitRefs()
+ if err != nil {
+ return nil, err
+ }
+
ret.frontend, err = gitFastExport(
"--use-done-feature",
"--no-data",
@@ -144,52 +158,47 @@ func (f *Filter) Run() error {
return fmt.Errorf("git fast-export kept going after 'done': cmd=%v err=%v", cmd, err)
}
return nil
+ case libfastimport.CmdReset:
+ // TODO
case libfastimport.CmdCommit:
- err = f.handleCommit(cmdt)
- if err != nil {
- return err
- }
- default:
- return fmt.Errorf("Unexpected command: %[1]T(%#[1]v)", cmd)
- }
- }
-}
-
-func (f *Filter) handleCommit(commit libfastimport.CmdCommit) error {
- out := make(map[string]libfastimport.CmdCommit)
- for _, action := range commit.Tree {
- switch actiont := action.(type) {
+ // TODO
+ case libfastimport.CmdCommitEnd:
+ // TODO
case libfastimport.FileModify:
- branch_ref := f.toPfx + "/" + path.Dir(string(actiont.Path))
- from_dataref, err := f.ref2dataref(branch_ref)
- if err == nil {
- file_mode, file_dataref, _, err := f.backend.Ls(libfastimport.CmdLs{DataRef: from_dataref, Path: actiont.Path})
+ branchname := filename2branchname(string(cmdt.Path))
+ if branchname == "" {
+ continue
+ }
+ branch_ref := f.toPfx + "/" + path.Dir(string(cmdt.Path))
+ from_dataref, from_dataref_ok := f.refs[branch_ref]
+ if from_dataref_ok {
+ file_mode, file_dataref, _, err := f.backend.Ls(libfastimport.CmdLs{DataRef: from_dataref, Path: cmdt.Path})
if err != nil {
return err
}
- if file_mode == actiont.Mode && file_dataref == actiont.DataRef {
+ if file_mode == cmdt.Mode && file_dataref == cmdt.DataRef {
continue
}
+ } else {
+ from_dataref = branch_ref + "^0"
}
- if _, ok := out[branch_ref]; !ok {
- out[branch_ref] = libfastimport.CmdCommit{
- Ref: branch_ref,
- Mark: f.newmark(),
- Author: commit.Author,
- Committer: commit.Committer,
- Msg: commit.Msg,
- From: from_dataref
- Merge: nil
- Tree: nil
- }
+ if _, ok := f.curCommitOut[branch_ref]; !ok {
+ f.curCommitOut[branch_ref] = fullcommit{metadata: libfastimport.CmdCommit{
+ Ref: branch_ref,
+ Mark: f.newmark(),
+ Author: f.curCommitIn.Author,
+ Committer: f.curCommitIn.Committer,
+ Msg: f.curCommitIn.Msg,
+ From: from_dataref,
+ Merge: nil,
+ }}
}
- outcommit := out[branch_ref]
-
+ //outcommit := f.curCommitOut[branch_ref]
+ // TODO
case libfastimport.FileDelete:
- ref := f.toPfx + "/" + path.Dir(string(actiont.Path))
- default:
- return fmt.Errorf("Unexpected file action: %[1]T(%#[1]v)", action)
+ //ref := f.toPfx + "/" + path.Dir(string(cmdt.Path))
+ // TODO
}
}
return nil
diff --git a/git.go b/git.go
index d406d1c..1adb461 100644
--- a/git.go
+++ b/git.go
@@ -2,8 +2,10 @@ package svn2git2aur
import (
"bytes"
+ "fmt"
"os"
"os/exec"
+ "strings"
"git.lukeshu.com/go/libfastimport"
)
@@ -77,3 +79,30 @@ func gitFastImport(args ...string) (*libfastimport.Backend, error) {
return backend, nil
}
+
+func gitRefs() (map[string]string, error) {
+ cmd := exec.Command("git", "for-each-ref")
+ b, err := cmd.Output()
+ if err != nil {
+ return nil, err
+ }
+ lines := strings.Split(string(b), "\n")
+ ret := make(map[string]string, len(lines)-1)
+ for _, line := range lines {
+ if line == "" {
+ continue
+ }
+ fields := strings.SplitN(line, " ", 3)
+ if len(fields) != 3 {
+ return nil, fmt.Errorf("malformed git for-each-ref line: %q", line)
+ }
+ refTarget := fields[0]
+ refType := fields[1]
+ refName := fields[2]
+ if refType != "commit" {
+ continue
+ }
+ ret[refName] = refTarget
+ }
+ return ret, nil
+}
diff --git a/heuristics.go b/heuristics.go
new file mode 100644
index 0000000..1ae4395
--- /dev/null
+++ b/heuristics.go
@@ -0,0 +1,51 @@
+package svn2git2aur
+
+import (
+ "path"
+)
+
+func filename2branchname(filename string) string {
+ // Let us write the .SRCINFO files.
+ switch path.Base(filename) {
+ case ".AURINFO", ".SRCINFO":
+ return ""
+ }
+
+ // There is nothing logical or universally true about the
+ // remainder of this function. It is simply a set of
+ // heuristics that works on the packages.git and community.git
+ // svn2git repos.
+ //
+ // The more truthful method would be to use PKGBUILD as a
+ // signal that a directory is a branch. However, that would
+ // be fairly expensive.
+
+ branchname := path.Dir(filename)
+
+ if branchname == "xalan-c/repos/extra-i686" {
+ // xalan-c has only ever been in community, not extra.
+ // Arch has now dropped i686, so this won't happen in
+ // the future either.
+ return ""
+ }
+ // This blackliast assumes that no package named one of those
+ // strings will ever exist.
+ for {
+ switch path.Base(branchname) {
+ case "log", "src": // packages.git
+ branchname = path.Dir(branchname)
+ case "CVS", "examples": // community.git
+ branchname = path.Dir(branchname)
+ case "repos":
+ return ""
+ default:
+ break
+ }
+ }
+ // A branch must contain a "/"
+ if path.Dir(branchname) == "." {
+ return ""
+ }
+
+ return branchname
+}