code.gitea.io/gitea@v1.22.3/modules/git/ref.go (about) 1 // Copyright 2018 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package git 5 6 import ( 7 "regexp" 8 "strings" 9 10 "code.gitea.io/gitea/modules/util" 11 ) 12 13 const ( 14 // RemotePrefix is the base directory of the remotes information of git. 15 RemotePrefix = "refs/remotes/" 16 // PullPrefix is the base directory of the pull information of git. 17 PullPrefix = "refs/pull/" 18 ) 19 20 // refNamePatternInvalid is regular expression with unallowed characters in git reference name 21 // They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177 DEL), space, tilde ~, caret ^, or colon : anywhere. 22 // They cannot have question-mark ?, asterisk *, or open bracket [ anywhere 23 var refNamePatternInvalid = regexp.MustCompile( 24 `[\000-\037\177 \\~^:?*[]|` + // No absolutely invalid characters 25 `(?:^[/.])|` + // Not HasPrefix("/") or "." 26 `(?:/\.)|` + // no "/." 27 `(?:\.lock$)|(?:\.lock/)|` + // No ".lock/"" or ".lock" at the end 28 `(?:\.\.)|` + // no ".." anywhere 29 `(?://)|` + // no "//" anywhere 30 `(?:@{)|` + // no "@{" 31 `(?:[/.]$)|` + // no terminal '/' or '.' 32 `(?:^@$)`) // Not "@" 33 34 // IsValidRefPattern ensures that the provided string could be a valid reference 35 func IsValidRefPattern(name string) bool { 36 return !refNamePatternInvalid.MatchString(name) 37 } 38 39 func SanitizeRefPattern(name string) string { 40 return refNamePatternInvalid.ReplaceAllString(name, "_") 41 } 42 43 // Reference represents a Git ref. 44 type Reference struct { 45 Name string 46 repo *Repository 47 Object ObjectID // The id of this commit object 48 Type string 49 } 50 51 // Commit return the commit of the reference 52 func (ref *Reference) Commit() (*Commit, error) { 53 return ref.repo.getCommit(ref.Object) 54 } 55 56 // ShortName returns the short name of the reference 57 func (ref *Reference) ShortName() string { 58 return RefName(ref.Name).ShortName() 59 } 60 61 // RefGroup returns the group type of the reference 62 func (ref *Reference) RefGroup() string { 63 return RefName(ref.Name).RefGroup() 64 } 65 66 // ForPrefix special ref to create a pull request: refs/for/<target-branch>/<topic-branch> 67 // or refs/for/<targe-branch> -o topic='<topic-branch>' 68 const ForPrefix = "refs/for/" 69 70 // TODO: /refs/for-review for suggest change interface 71 72 // RefName represents a full git reference name 73 type RefName string 74 75 func RefNameFromBranch(shortName string) RefName { 76 return RefName(BranchPrefix + shortName) 77 } 78 79 func RefNameFromTag(shortName string) RefName { 80 return RefName(TagPrefix + shortName) 81 } 82 83 func (ref RefName) String() string { 84 return string(ref) 85 } 86 87 func (ref RefName) IsBranch() bool { 88 return strings.HasPrefix(string(ref), BranchPrefix) 89 } 90 91 func (ref RefName) IsTag() bool { 92 return strings.HasPrefix(string(ref), TagPrefix) 93 } 94 95 func (ref RefName) IsRemote() bool { 96 return strings.HasPrefix(string(ref), RemotePrefix) 97 } 98 99 func (ref RefName) IsPull() bool { 100 return strings.HasPrefix(string(ref), PullPrefix) && strings.IndexByte(string(ref)[len(PullPrefix):], '/') > -1 101 } 102 103 func (ref RefName) IsFor() bool { 104 return strings.HasPrefix(string(ref), ForPrefix) 105 } 106 107 func (ref RefName) nameWithoutPrefix(prefix string) string { 108 if strings.HasPrefix(string(ref), prefix) { 109 return strings.TrimPrefix(string(ref), prefix) 110 } 111 return "" 112 } 113 114 // TagName returns simple tag name if it's an operation to a tag 115 func (ref RefName) TagName() string { 116 return ref.nameWithoutPrefix(TagPrefix) 117 } 118 119 // BranchName returns simple branch name if it's an operation to branch 120 func (ref RefName) BranchName() string { 121 return ref.nameWithoutPrefix(BranchPrefix) 122 } 123 124 // PullName returns the pull request name part of refs like refs/pull/<pull_name>/head 125 func (ref RefName) PullName() string { 126 refName := string(ref) 127 lastIdx := strings.LastIndexByte(refName[len(PullPrefix):], '/') 128 if strings.HasPrefix(refName, PullPrefix) && lastIdx > -1 { 129 return refName[len(PullPrefix) : lastIdx+len(PullPrefix)] 130 } 131 return "" 132 } 133 134 // ForBranchName returns the branch name part of refs like refs/for/<branch_name> 135 func (ref RefName) ForBranchName() string { 136 return ref.nameWithoutPrefix(ForPrefix) 137 } 138 139 func (ref RefName) RemoteName() string { 140 return ref.nameWithoutPrefix(RemotePrefix) 141 } 142 143 // ShortName returns the short name of the reference name 144 func (ref RefName) ShortName() string { 145 refName := string(ref) 146 if ref.IsBranch() { 147 return ref.BranchName() 148 } 149 if ref.IsTag() { 150 return ref.TagName() 151 } 152 if ref.IsRemote() { 153 return ref.RemoteName() 154 } 155 if ref.IsPull() { 156 return ref.PullName() 157 } 158 if ref.IsFor() { 159 return ref.ForBranchName() 160 } 161 162 return refName 163 } 164 165 // RefGroup returns the group type of the reference 166 // Using the name of the directory under .git/refs 167 func (ref RefName) RefGroup() string { 168 if ref.IsBranch() { 169 return "heads" 170 } 171 if ref.IsTag() { 172 return "tags" 173 } 174 if ref.IsRemote() { 175 return "remotes" 176 } 177 if ref.IsPull() { 178 return "pull" 179 } 180 if ref.IsFor() { 181 return "for" 182 } 183 return "" 184 } 185 186 // RefType returns the simple ref type of the reference, e.g. branch, tag 187 // It's different from RefGroup, which is using the name of the directory under .git/refs 188 // Here we using branch but not heads, using tag but not tags 189 func (ref RefName) RefType() string { 190 var refType string 191 if ref.IsBranch() { 192 refType = "branch" 193 } else if ref.IsTag() { 194 refType = "tag" 195 } 196 return refType 197 } 198 199 // RefURL returns the absolute URL for a ref in a repository 200 func RefURL(repoURL, ref string) string { 201 refFullName := RefName(ref) 202 refName := util.PathEscapeSegments(refFullName.ShortName()) 203 switch { 204 case refFullName.IsBranch(): 205 return repoURL + "/src/branch/" + refName 206 case refFullName.IsTag(): 207 return repoURL + "/src/tag/" + refName 208 case !Sha1ObjectFormat.IsValid(ref): 209 // assume they mean a branch 210 return repoURL + "/src/branch/" + refName 211 default: 212 return repoURL + "/src/commit/" + refName 213 } 214 }