github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/ref/ref.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package ref 16 17 import ( 18 "errors" 19 "fmt" 20 "strings" 21 ) 22 23 // ErrUnknownRefType is the error returned when parsing a ref in the format refs/type/... where type is unknown 24 var ErrUnknownRefType = errors.New("unknown ref type") 25 26 const ( 27 refPrefix = "refs/" 28 remotesPrefix = "remotes/" 29 ) 30 31 // IsRef returns true if the string is a reference string (meanings it starts with the prefix refs/) 32 func IsRef(str string) bool { 33 return strings.HasPrefix(str, refPrefix) 34 } 35 36 // RefType is the type of the reference, and this value follows the refPrefix in a ref string. e.g. refs/type/... 37 type RefType string 38 39 const ( 40 // BranchRefType is a reference to a local branch in the format refs/heads/... 41 BranchRefType RefType = "heads" 42 43 // RemoteRefType is a reference to a local remote tracking branch 44 RemoteRefType RefType = "remotes" 45 46 // InternalRefType is a reference to a dolt internal commit 47 InternalRefType RefType = "internal" 48 49 // TagRefType is a reference to commit tag 50 TagRefType RefType = "tags" 51 52 // WorkspaceRefType is a reference to a workspace 53 WorkspaceRefType RefType = "workspaces" 54 ) 55 56 // HeadRefTypes are the ref types that point to a HEAD and contain a Commit struct. These are the types that are 57 // returned by GetHeadRefs. Other ref types don't point to Commits necessarily, so aren't in this list and must be 58 // asked for explicitly. 59 var HeadRefTypes = map[RefType]struct{}{ 60 BranchRefType: {}, 61 RemoteRefType: {}, 62 InternalRefType: {}, 63 TagRefType: {}, 64 WorkspaceRefType: {}, 65 } 66 67 // PrefixForType returns what a reference string for a given type should start with 68 func PrefixForType(refType RefType) string { 69 return refPrefix + string(refType) + "/" 70 } 71 72 type UpdateMode struct { 73 Force bool 74 } 75 76 var ForceUpdate = UpdateMode{true} 77 var FastForwardOnly = UpdateMode{false} 78 79 // DoltRef is a reference to a commit. 80 type DoltRef interface { 81 fmt.Stringer 82 83 // GetType returns the RefType of this ref 84 GetType() RefType 85 86 // GetPath returns the identifier for the reference 87 GetPath() string 88 } 89 90 // Equals returns true if two DoltRefs have the same Type and Path 91 func Equals(dr, other DoltRef) bool { 92 if dr == nil && other == nil { 93 return true 94 } else if dr == nil || other == nil { 95 return false 96 } 97 98 return dr.GetType() == other.GetType() && dr.GetPath() == other.GetPath() 99 } 100 101 // EqualsStr compares a DoltRef to a reference string to see if they are referring to the same thing 102 func EqualsStr(dr DoltRef, str string) bool { 103 other, err := Parse(str) 104 105 if err != nil { 106 return false 107 } 108 109 return Equals(dr, other) 110 } 111 112 // String converts the DoltRef to a reference string in the format refs/type/path 113 func String(dr DoltRef) string { 114 return PrefixForType(dr.GetType()) + dr.GetPath() 115 } 116 117 // MarshalJSON implements the json Marshaler interface to json encode DoltRefs as their string representation 118 func MarshalJSON(dr DoltRef) ([]byte, error) { 119 str := dr.String() 120 data := make([]byte, len(str)+2) 121 122 data[0] = '"' 123 data[len(str)+1] = '"' 124 125 for i, b := range str { 126 data[i+1] = byte(b) 127 } 128 129 return data, nil 130 } 131 132 // Parse will parse ref strings and return a DoltRef or an error for refs that can't be parsed. 133 // refs without a RefType prefix ("refs/heads/", "refs/tags/", etc) are assumed to be branches) 134 func Parse(str string) (DoltRef, error) { 135 if !IsRef(str) { 136 if strings.HasPrefix(str, remotesPrefix) { 137 return NewRemoteRefFromPathStr(str) 138 } else { 139 return NewBranchRef(str), nil 140 } 141 } 142 143 for rType := range HeadRefTypes { 144 prefix := PrefixForType(rType) 145 if strings.HasPrefix(str, prefix) { 146 str = str[len(prefix):] 147 switch rType { 148 case BranchRefType: 149 return NewBranchRef(str), nil 150 case RemoteRefType: 151 return NewRemoteRefFromPathStr(str) 152 case InternalRefType: 153 return NewInternalRef(str), nil 154 case TagRefType: 155 return NewTagRef(str), nil 156 case WorkspaceRefType: 157 return NewWorkspaceRef(str), nil 158 default: 159 panic("unknown type " + rType) 160 } 161 } 162 } 163 164 return nil, ErrUnknownRefType 165 }