From 821151baeceb598d0ffd650e3332d57b6c1af794 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Wed, 02 Apr 2025 02:30:35 +0800 Subject: [PATCH] BROKEN --- go.mod | 1 + go.sum | 2 ++ lmtp_handle_patch.go | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++-- lmtp_server.go | 3 ++- diff --git a/go.mod b/go.mod index 6555e3b99749e3abd1cecea00c3a6275b59d4f3a..2ee258f25001a23f4d67598742b490de4f63663c 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ 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 70aa113c54c0f6a6727f003345ea7e5f1240359c..593a0f6acb84feb0d0c192169fc379c45bc2ac6a 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 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 a3064d1a45bf6a482bdd268123f12ca6b6d7d2ac..ed47e25651dfc9541910b4efbd08897119f9e447 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 998b53c810fa0c5f30f9ccf46c0d189980576be3..44dc8d41db3ee1fa38a8520db2b25ae3c7a6cb7e 100644 --- a/lmtp_server.go +++ b/lmtp_server.go @@ -163,8 +163,9 @@ moduleType := segments[sepIndex+1] 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: -- 2.48.1