aboutsummaryrefslogtreecommitdiff
path: root/lmtp_handle_patch.go
blob: 138b5927e593e37b48d29075aa4f229fe30b7c84 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileCopyrightText: Copyright (c) 2025 Runxi Yu <https://runxiyu.org>

package main

import (
	"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(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
		}
		if err = proc.Wait(); 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
}