aboutsummaryrefslogtreecommitdiff
path: root/lmtp_handle_patch.go
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-04-02 03:06:54 +0800
committerRunxi Yu <me@runxiyu.org>2025-04-02 03:06:54 +0800
commit35efa2a9c96f6f6660e8f1ed5b964141ced9995b (patch)
tree6bdf06bc91ea378d75c0eecb32eec704ee6ccc46 /lmtp_handle_patch.go
parentGit: Return fsPath from OpenRepo (diff)
downloadforge-35efa2a9c96f6f6660e8f1ed5b964141ced9995b.tar.gz
forge-35efa2a9c96f6f6660e8f1ed5b964141ced9995b.tar.zst
forge-35efa2a9c96f6f6660e8f1ed5b964141ced9995b.zip
LMTP: Stub patch application
Diffstat (limited to 'lmtp_handle_patch.go')
-rw-r--r--lmtp_handle_patch.go79
1 files changed, 76 insertions, 3 deletions
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
}