github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/doltdb/commit.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 doltdb 16 17 import ( 18 "context" 19 "errors" 20 21 "github.com/dolthub/dolt/go/store/datas" 22 "github.com/dolthub/dolt/go/store/hash" 23 "github.com/dolthub/dolt/go/store/types" 24 ) 25 26 const ( 27 metaField = datas.CommitMetaField 28 parentsField = datas.ParentsField 29 parentsListField = datas.ParentsListField 30 rootValueField = datas.ValueField 31 ) 32 33 var errCommitHasNoMeta = errors.New("commit has no metadata") 34 var errHasNoRootValue = errors.New("no root value") 35 36 // Commit contains information on a commit that was written to noms 37 type Commit struct { 38 vrw types.ValueReadWriter 39 commitSt types.Struct 40 parents []types.Ref 41 } 42 43 func NewCommit(vrw types.ValueReadWriter, commitSt types.Struct) *Commit { 44 parents, err := readParents(vrw, commitSt) 45 if err != nil { 46 panic(err) 47 } 48 return &Commit{vrw, commitSt, parents} 49 } 50 51 func readParents(vrw types.ValueReadWriter, commitSt types.Struct) ([]types.Ref, error) { 52 if l, found, err := commitSt.MaybeGet(parentsListField); err != nil { 53 return nil, err 54 } else if found && l != nil { 55 l := l.(types.List) 56 parents := make([]types.Ref, 0, l.Len()) 57 i, err := l.Iterator(context.TODO()) 58 if err != nil { 59 return nil, err 60 } 61 for { 62 v, err := i.Next(context.TODO()) 63 if err != nil { 64 return nil, err 65 } 66 if v == nil { 67 break 68 } 69 parents = append(parents, v.(types.Ref)) 70 } 71 return parents, nil 72 } 73 if s, found, err := commitSt.MaybeGet(parentsField); err != nil { 74 return nil, err 75 } else if found && s != nil { 76 s := s.(types.Set) 77 parents := make([]types.Ref, 0, s.Len()) 78 i, err := s.Iterator(context.TODO()) 79 if err != nil { 80 return nil, err 81 } 82 for { 83 v, err := i.Next(context.TODO()) 84 if err != nil { 85 return nil, err 86 } 87 if v == nil { 88 break 89 } 90 parents = append(parents, v.(types.Ref)) 91 } 92 return parents, nil 93 } 94 return nil, nil 95 } 96 97 // HashOf returns the hash of the commit 98 func (c *Commit) HashOf() (hash.Hash, error) { 99 return c.commitSt.Hash(c.vrw.Format()) 100 } 101 102 // GetCommitMeta gets the metadata associated with the commit 103 func (c *Commit) GetCommitMeta() (*CommitMeta, error) { 104 metaVal, found, err := c.commitSt.MaybeGet(metaField) 105 106 if err != nil { 107 return nil, err 108 } 109 110 if !found { 111 return nil, errCommitHasNoMeta 112 } 113 114 if metaVal != nil { 115 if metaSt, ok := metaVal.(types.Struct); ok { 116 cm, err := commitMetaFromNomsSt(metaSt) 117 118 if err == nil { 119 return cm, nil 120 } 121 } 122 } 123 124 h, err := c.HashOf() 125 126 if err != nil { 127 return nil, errCommitHasNoMeta 128 } 129 130 return nil, errors.New(h.String() + " is a commit without the required metadata.") 131 } 132 133 // ParentHashes returns the commit hashes for all parent commits. 134 func (c *Commit) ParentHashes(ctx context.Context) ([]hash.Hash, error) { 135 hashes := make([]hash.Hash, len(c.parents)) 136 for i, pr := range c.parents { 137 hashes[i] = pr.TargetHash() 138 } 139 return hashes, nil 140 } 141 142 // NumParents gets the number of parents a commit has. 143 func (c *Commit) NumParents() (int, error) { 144 return len(c.parents), nil 145 } 146 147 func (c *Commit) Height() (uint64, error) { 148 ref, err := types.NewRef(c.commitSt, c.vrw.Format()) 149 if err != nil { 150 return 0, err 151 } 152 return ref.Height(), nil 153 } 154 155 func (c *Commit) getParent(ctx context.Context, idx int) (*types.Struct, error) { 156 parentRef := c.parents[idx] 157 targVal, err := parentRef.TargetValue(ctx, c.vrw) 158 if err != nil { 159 return nil, err 160 } 161 parentSt := targVal.(types.Struct) 162 return &parentSt, nil 163 } 164 165 // GetRootValue gets the RootValue of the commit. 166 func (c *Commit) GetRootValue() (*RootValue, error) { 167 rootVal, _, err := c.commitSt.MaybeGet(rootValueField) 168 169 if err != nil { 170 return nil, err 171 } 172 173 if rootVal != nil { 174 if rootSt, ok := rootVal.(types.Struct); ok { 175 return newRootValue(c.vrw, rootSt) 176 } 177 } 178 179 return nil, errHasNoRootValue 180 } 181 182 // GetStRef returns a Noms Ref for this Commit's Noms commit Struct. 183 func (c *Commit) GetStRef() (types.Ref, error) { 184 return types.NewRef(c.commitSt, c.vrw.Format()) 185 } 186 187 var ErrNoCommonAncestor = errors.New("no common ancestor") 188 189 func GetCommitAncestor(ctx context.Context, cm1, cm2 *Commit) (*Commit, error) { 190 ref1, err := types.NewRef(cm1.commitSt, cm1.vrw.Format()) 191 192 if err != nil { 193 return nil, err 194 } 195 196 ref2, err := types.NewRef(cm2.commitSt, cm2.vrw.Format()) 197 198 if err != nil { 199 return nil, err 200 } 201 202 ref, err := getCommitAncestorRef(ctx, ref1, ref2, cm1.vrw, cm2.vrw) 203 204 if err != nil { 205 return nil, err 206 } 207 208 targetVal, err := ref.TargetValue(ctx, cm1.vrw) 209 210 if err != nil { 211 return nil, err 212 } 213 214 ancestorSt := targetVal.(types.Struct) 215 return NewCommit(cm1.vrw, ancestorSt), nil 216 } 217 218 func getCommitAncestorRef(ctx context.Context, ref1, ref2 types.Ref, vrw1, vrw2 types.ValueReadWriter) (types.Ref, error) { 219 ancestorRef, ok, err := datas.FindCommonAncestor(ctx, ref1, ref2, vrw1, vrw2) 220 221 if err != nil { 222 return types.Ref{}, err 223 } 224 225 if !ok { 226 return types.Ref{}, ErrNoCommonAncestor 227 } 228 229 return ancestorRef, nil 230 } 231 232 func (c *Commit) CanFastForwardTo(ctx context.Context, new *Commit) (bool, error) { 233 ancestor, err := GetCommitAncestor(ctx, c, new) 234 235 if err != nil { 236 return false, err 237 } else if ancestor == nil { 238 return false, errors.New("cannot perform fast forward merge; commits have no common ancestor") 239 } else if ancestor.commitSt.Equals(c.commitSt) { 240 if ancestor.commitSt.Equals(new.commitSt) { 241 return true, ErrUpToDate 242 } 243 return true, nil 244 } else if ancestor.commitSt.Equals(new.commitSt) { 245 return false, ErrIsAhead 246 } 247 248 return false, nil 249 } 250 251 func (c *Commit) CanFastReverseTo(ctx context.Context, new *Commit) (bool, error) { 252 ancestor, err := GetCommitAncestor(ctx, c, new) 253 254 if err != nil { 255 return false, err 256 } else if ancestor == nil { 257 return false, errors.New("cannot perform fast forward merge; commits have no common ancestor") 258 } else if ancestor.commitSt.Equals(new.commitSt) { 259 if ancestor.commitSt.Equals(c.commitSt) { 260 return true, ErrUpToDate 261 } 262 return true, nil 263 } else if ancestor.commitSt.Equals(c.commitSt) { 264 return false, ErrIsBehind 265 } 266 267 return false, nil 268 } 269 270 func (c *Commit) GetAncestor(ctx context.Context, as *AncestorSpec) (*Commit, error) { 271 ancestorSt, err := getAncestor(ctx, c.vrw, c.commitSt, as) 272 273 if err != nil { 274 return nil, err 275 } 276 277 return NewCommit(c.vrw, ancestorSt), nil 278 }