-
Notifications
You must be signed in to change notification settings - Fork 0
/
interpret_name.go
135 lines (127 loc) · 3.46 KB
/
interpret_name.go
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SPDX-License-Identifier: Apache-2.0
// Copyright © 2021 Wrangle Ltd
package ref
import (
"encoding/hex"
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"github.com/wrgl/core/pkg/objects"
)
var (
HeadPattern = regexp.MustCompile(`^[-_0-9a-zA-Z/]+$`)
HashPattern = regexp.MustCompile(`^[a-f0-9]{32}$`)
peelPattern = regexp.MustCompile(`^(.*[^\^])(\^+)$`)
tildePattern = regexp.MustCompile(`^(.*[^\~])\~(\d+)$`)
)
func ParseNavigationChars(commitStr string) (commitName string, numPeel int, err error) {
commitName = commitStr
if peelPattern.MatchString(commitStr) {
sl := peelPattern.FindStringSubmatch(commitStr)
commitName = sl[1]
numPeel = len(sl[2])
} else if tildePattern.MatchString(commitStr) {
sl := tildePattern.FindStringSubmatch(commitStr)
commitName = sl[1]
numPeel, err = strconv.Atoi(sl[2])
}
return
}
func PeelCommit(db objects.Store, hash []byte, commit *objects.Commit, numPeel int) ([]byte, *objects.Commit, error) {
var err error
for numPeel > 0 {
hash = commit.Parents[0][:]
commit, err = objects.GetCommit(db, hash)
if err != nil {
return nil, nil, err
}
numPeel--
}
return hash, commit, nil
}
func interpretRef(s Store, name string, excludeTag bool) (ref string, sum []byte, err error) {
name = strings.TrimPrefix(name, "refs/")
m, err := ListAllRefs(s)
if err != nil {
return
}
sl := make([]string, 0, len(m))
for k := range m {
if excludeTag && strings.HasPrefix(k, "tags/") {
continue
}
sl = append(sl, k)
}
sort.Slice(sl, func(i, j int) bool {
if strings.HasPrefix(sl[i], "heads/") {
if strings.HasPrefix(sl[j], "heads/") {
return sl[i] < sl[j]
}
return true
} else if strings.HasPrefix(sl[i], "tags/") {
if strings.HasPrefix(sl[j], "heads/") {
return false
} else if strings.HasPrefix(sl[j], "tags/") {
return sl[i] < sl[j]
}
return true
} else if strings.HasPrefix(sl[i], "remotes/") {
if strings.HasPrefix(sl[j], "heads/") || strings.HasPrefix(sl[j], "tags/") {
return false
} else if strings.HasPrefix(sl[j], "remotes/") {
return sl[i] < sl[j]
}
return true
}
if strings.HasPrefix(sl[j], "heads/") || strings.HasPrefix(sl[j], "tags/") || strings.HasPrefix(sl[j], "remotes/") {
return false
}
return sl[i] < sl[j]
})
for _, ref := range sl {
if ref == name || strings.HasSuffix(ref, "/"+name) {
sum, err := GetRef(s, ref)
if err != nil {
return name, nil, err
}
return ref, sum, nil
}
}
return name, nil, ErrKeyNotFound
}
func InterpretCommitName(db objects.Store, rs Store, commitStr string, excludeTag bool) (name string, hash []byte, commit *objects.Commit, err error) {
name, numPeel, err := ParseNavigationChars(commitStr)
if err != nil {
return "", nil, nil, err
}
if HashPattern.MatchString(name) {
hash, err = hex.DecodeString(name)
if err != nil {
return
}
commit, err = objects.GetCommit(db, hash)
if err == nil {
hash, commit, err = PeelCommit(db, hash, commit, numPeel)
name = hex.EncodeToString(hash)
return
}
}
if HeadPattern.MatchString(name) {
var commitSum []byte
name, commitSum, err = interpretRef(rs, name, excludeTag)
if err == nil {
commit, err = objects.GetCommit(db, commitSum)
if err != nil {
return "", nil, nil, err
}
hash, commit, err = PeelCommit(db, commitSum, commit, numPeel)
return
}
}
if HashPattern.MatchString(name) {
return "", nil, nil, fmt.Errorf("can't find commit %s", name)
}
return "", nil, nil, fmt.Errorf("can't find branch %s", name)
}