summaryrefslogtreecommitdiffstatshomepage
path: root/repository/common.go
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2021-01-03 23:59:25 +0100
committerMichael Muré <batolettre@gmail.com>2021-02-14 12:19:00 +0100
commit8d63c983c982f93cc48d3996d6bd097ddeeb327f (patch)
tree94d85594e11965f9780df53a5c0c2b2550c02184 /repository/common.go
parent4ef92efeb905102d37b81fafa0ac2173594ef30a (diff)
downloadgit-bug-8d63c983c982f93cc48d3996d6bd097ddeeb327f.tar.gz
git-bug-8d63c983c982f93cc48d3996d6bd097ddeeb327f.zip
WIP
Diffstat (limited to 'repository/common.go')
-rw-r--r--repository/common.go120
1 files changed, 120 insertions, 0 deletions
diff --git a/repository/common.go b/repository/common.go
new file mode 100644
index 00000000..7fd7ae19
--- /dev/null
+++ b/repository/common.go
@@ -0,0 +1,120 @@
+package repository
+
+import (
+ "io"
+
+ "golang.org/x/crypto/openpgp"
+ "golang.org/x/crypto/openpgp/armor"
+ "golang.org/x/crypto/openpgp/errors"
+)
+
+// nonNativeMerge is an implementation of a branch merge, for the case where
+// the underlying git implementation doesn't support it natively.
+func nonNativeMerge(repo RepoData, ref string, otherRef string, treeHashFn func() Hash) error {
+ commit, err := repo.ResolveRef(ref)
+ if err != nil {
+ return err
+ }
+
+ otherCommit, err := repo.ResolveRef(otherRef)
+ if err != nil {
+ return err
+ }
+
+ if commit == otherCommit {
+ // nothing to merge
+ return nil
+ }
+
+ // fast-forward is possible if otherRef include ref
+
+ otherCommits, err := repo.ListCommits(otherRef)
+ if err != nil {
+ return err
+ }
+
+ fastForwardPossible := false
+ for _, hash := range otherCommits {
+ if hash == commit {
+ fastForwardPossible = true
+ break
+ }
+ }
+
+ if fastForwardPossible {
+ return repo.UpdateRef(ref, otherCommit)
+ }
+
+ // fast-forward is not possible, we need to create a merge commit
+
+ // we need a Tree to make the commit, an empty Tree will do
+ emptyTreeHash, err := repo.StoreTree(nil)
+ if err != nil {
+ return err
+ }
+
+ newHash, err := repo.StoreCommit(emptyTreeHash, commit, otherCommit)
+ if err != nil {
+ return err
+ }
+
+ return repo.UpdateRef(ref, newHash)
+}
+
+// nonNativeListCommits is an implementation for ListCommits, for the case where
+// the underlying git implementation doesn't support if natively.
+func nonNativeListCommits(repo RepoData, ref string) ([]Hash, error) {
+ var result []Hash
+
+ stack := make([]Hash, 0, 32)
+ visited := make(map[Hash]struct{})
+
+ hash, err := repo.ResolveRef(ref)
+ if err != nil {
+ return nil, err
+ }
+
+ stack = append(stack, hash)
+
+ for len(stack) > 0 {
+ // pop
+ hash := stack[len(stack)-1]
+ stack = stack[:len(stack)-1]
+
+ if _, ok := visited[hash]; ok {
+ continue
+ }
+
+ // mark as visited
+ visited[hash] = struct{}{}
+ result = append(result, hash)
+
+ commit, err := repo.ReadCommit(hash)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, parent := range commit.Parents {
+ stack = append(stack, parent)
+ }
+ }
+
+ // reverse
+ for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
+ result[i], result[j] = result[j], result[i]
+ }
+
+ return result, nil
+}
+
+// deArmorSignature convert an armored (text serialized) signature into raw binary
+func deArmorSignature(armoredSig io.Reader) (io.Reader, error) {
+ block, err := armor.Decode(armoredSig)
+ if err != nil {
+ return nil, err
+ }
+ if block.Type != openpgp.SignatureType {
+ return nil, errors.InvalidArgumentError("expected '" + openpgp.SignatureType + "', got: " + block.Type)
+ }
+ return block.Body, nil
+}