aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go.mod1
-rw-r--r--go.sum2
-rw-r--r--lmtp_handle_patch.go82
-rw-r--r--lmtp_server.go3
4 files changed, 84 insertions, 4 deletions
diff --git a/go.mod b/go.mod
index 6555e3b..2ee258f 100644
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
index 70aa113..593a0f6 100644
--- a/go.sum
+++ b/go.sum
@@ -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..ed47e25 100644
--- a/lmtp_handle_patch.go
+++ b/lmtp_handle_patch.go
@@ -4,12 +4,88 @@
package main
import (
- "log/slog"
+ "crypto/rand"
+ "fmt"
+ "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/config"
+ "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
+ repo, _, _, 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
+ }
+
+ // What's left to do: apply the patch on a separate branch.
+ // I'm not sure how to do this in go-git. I have a few thoughts:
+ // Method 1. Create a copy of the tree object; then iterate through
+ // diffFiles, traversing the tree accordingly, then hash
+ // blobs, insert them into the repo, replace the entry in
+ // the tree, then commit the tree onto a new branch.
+ // Perhaps storer can help with this?
+ // Method 2. Create an index, run the patch on it, and commit the
+ // index.
+ // I think Method 1 technically suffers from a race if the repo is
+ // garbage collected between the time that the blob is created and
+ // the time it is committed to a branch. We could just prevent
+ // external GCs and lock GCs ourselves though, so it's no big deal.
+ // Method 2 is a bit annoying and I have this impression that
+ // worktrees/indexes are fragile and bloated.
+
+ myTree := *headTree
+ // TODO: Check if it's actually safe to modify myTree. We don't
+ // own these slices, so this might interfere with go-git's internal
+ // state.
+
+ for _, diffFile := range diffFiles {
+ blobObject := plumbing.EncodedObject
+ var blobHash plumbing.Hash
+ if blobHash, err = repo.Storer.SetEncodedObject(blobObject); err != nil {
+ return
+ }
+ }
+
+ /*
+ contribBranchName := rand.Text()
+
+ if err = repo.CreateBranch(&config.Branch{ Name: contribBranchName, }); err != nil {
+ return
+ }
+
+ var contribRef *plumbing.Reference
+ if contribRef, err = repo.Reference(plumbing.NewBranchReferenceName(contribBranchName, true); err != nil {
+ return
+ }
+ */
+
+ fmt.Println(repo, diffFiles, 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: