diff options
-rw-r--r-- | .golangci.yaml | 2 | ||||
-rw-r--r-- | go.mod | 1 | ||||
-rw-r--r-- | go.sum | 2 | ||||
-rw-r--r-- | lmtp_handle_patch.go | 79 | ||||
-rw-r--r-- | lmtp_server.go | 3 |
5 files changed, 83 insertions, 4 deletions
diff --git a/.golangci.yaml b/.golangci.yaml index 00ba1ea..7edd4c3 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -16,6 +16,8 @@ linters: - wrapcheck # wrapping all errors is just not necessary - varnamelen # "from" and "to" are very valid - stylecheck + - containedctx + - godot - maintidx # e - nestif # e - gocognit # e @@ -5,6 +5,7 @@ go 1.24.1 require ( github.com/alecthomas/chroma/v2 v2.15.0 github.com/alexedwards/argon2id v1.0.0 + github.com/bluekeyes/go-gitdiff v0.8.1 github.com/dgraph-io/ristretto/v2 v2.1.0 github.com/dustin/go-humanize v1.0.1 github.com/gliderlabs/ssh v0.3.8 @@ -19,6 +19,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/bluekeyes/go-gitdiff v0.8.1 h1:lL1GofKMywO17c0lgQmJYcKek5+s8X6tXVNOLxy4smI= +github.com/bluekeyes/go-gitdiff v0.8.1/go.mod h1:WWAk1Mc6EgWarCrPFO+xeYlujPu98VuLW3Tu+B/85AE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= diff --git a/lmtp_handle_patch.go b/lmtp_handle_patch.go index a3064d1..4e49d55 100644 --- a/lmtp_handle_patch.go +++ b/lmtp_handle_patch.go @@ -4,12 +4,85 @@ package main import ( - "log/slog" + "bytes" + // "crypto/rand" + // "fmt" + "os" + "os/exec" + "github.com/bluekeyes/go-gitdiff/gitdiff" "github.com/emersion/go-message" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/object" ) -func lmtpHandlePatch(groupPath []string, repoName string, email *message.Entity) (err error) { - slog.Info("Pretend like I'm handling a patch!") +func lmtpHandlePatch(session *lmtpSession, groupPath []string, repoName string, email *message.Entity) (err error) { + var diffFiles []*gitdiff.File + var preamble string + if diffFiles, preamble, err = gitdiff.Parse(email.Body); err != nil { + return + } + + var repo *git.Repository + var fsPath string + repo, _, _, fsPath, err = openRepo(session.ctx, groupPath, repoName) + if err != nil { + return + } + + var headRef *plumbing.Reference + if headRef, err = repo.Head(); err != nil { + return + } + + var headCommit *object.Commit + if headCommit, err = repo.CommitObject(headRef.Hash()); err != nil { + return + } + + var headTree *object.Tree + if headTree, err = headCommit.Tree(); err != nil { + return + } + + // TODO: Try to not shell out + + for _, diffFile := range diffFiles { + var sourceFile *object.File + if sourceFile, err = headTree.File(diffFile.OldName); err != nil { + return err + } + var sourceString string + if sourceString, err = sourceFile.Contents(); err != nil { + return err + } + hashBuf := bytes.Buffer{} + patchedBuf := bytes.Buffer{} + sourceBuf := bytes.NewReader(stringToBytes(sourceString)) + if err = gitdiff.Apply(&patchedBuf, sourceBuf, diffFile); err != nil { + return err + } + proc := exec.CommandContext(session.ctx, "git", "hash-object", "w", "-t", "blob", "--stdin") + proc.Env = append(os.Environ(), "GIT_DIR="+fsPath) + proc.Stdout = &hashBuf + proc.Stdin = &patchedBuf + if err = proc.Start(); err != nil { + return err + } + newHash := hashBuf.Bytes() + if len(newHash) != 20*2+1 { // TODO: Hardcoded from the size of plumbing.Hash + panic("unexpected hash size") + } + // TODO: Add to tree + } + + // contribBranchName := rand.Text() + + // TODO: Store the branch + + // fmt.Println(repo, diffFiles, preamble) + _ = preamble + return nil } diff --git a/lmtp_server.go b/lmtp_server.go index 998b53c..44dc8d4 100644 --- a/lmtp_server.go +++ b/lmtp_server.go @@ -163,8 +163,9 @@ func (session *lmtpSession) Data(r io.Reader) error { moduleName := segments[sepIndex+2] switch moduleType { case "repos": - err = lmtpHandlePatch(groupPath, moduleName, email) + err = lmtpHandlePatch(session, groupPath, moduleName, email) if err != nil { + slog.Error("error handling patch", "error", err) goto end } default: |