Files
wehub-resource-sync 5357c39144
Fuzzer / Run Fuzzer (push) Has been cancelled
Race tests / Go race tests (ubuntu-22.04) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:01:40 +08:00

116 lines
4.0 KiB
Go

// Copyright 2019 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package doltdb
import (
"regexp"
"strings"
"github.com/dolthub/dolt/go/libraries/doltcore/ref"
)
var hashRegex = regexp.MustCompile(`^[0-9a-v]{32}$`)
const head string = "head"
// IsValidUserBranchName returns true if name isn't a valid commit hash, it is not named "head" and
// it matches the regular expression `[0-9a-z]+[-_0-9a-z]*[0-9a-z]+$`
func IsValidUserBranchName(name string) bool {
return name != head && !hashRegex.MatchString(name) && ref.IsValidBranchName(name)
}
// IsValidBranchRef validates that a BranchRef doesn't violate naming constraints.
func IsValidBranchRef(dref ref.DoltRef) bool {
return dref.GetType() == ref.BranchRefType && IsValidUserBranchName(dref.GetPath())
}
// IsValidTagRef validates that a TagRef doesn't violate naming constraints.
func IsValidTagRef(dref ref.DoltRef) bool {
s := dref.GetPath()
return dref.GetType() == ref.TagRefType &&
s != head &&
!hashRegex.MatchString(s) &&
ref.IsValidTagName(s)
}
func IsValidCommitHash(s string) bool {
return hashRegex.MatchString(s)
}
type commitSpecType string
const (
refCommitSpec commitSpecType = "ref"
hashCommitSpec commitSpecType = "hash"
headCommitSpec commitSpecType = "head"
)
// CommitSpec handles three different types of string representations of commits. Commits can either be represented
// by the hash of the commit, a branch name, or using "head" to represent the latest commit of the current branch.
// An Ancestor spec can be appended to the end of any of these in order to reach commits that are in the ancestor tree
// of the referenced commit.
type CommitSpec struct {
baseSpec string
csType commitSpecType
aSpec *AncestorSpec
}
// NewCommitSpec parses a string specifying a commit using dolt commit spec
// syntax and returns a |*CommitSpec|. A commit spec has a base commit and an
// optional ancestor specification. The syntax admits three types of base
// commit references:
// * head -- the literal string HEAD specifies the HEAD reference of the
// current working set.
// * a commit hash, like 46m0aqr8c1vuv76ml33cdtr8722hsbhn -- a fully specified
// commit hash.
// * a ref -- referring to a branch or tag reference in the current dolt database.
// Examples of branch refs include `master`, `heads/master`, `refs/heads/master`,
// `origin/master`, `refs/remotes/origin/master`.
// Examples of tag refs include `v1.0`, `tags/v1.0`, `refs/tags/v1.0`,
// `origin/v1.0`, `refs/remotes/origin/v1.0`.
//
// A commit spec has an optional ancestor specification, which describes a
// traversal of commit parents, starting at the base commit, in order to arrive
// at the actually specified commit. See |AncestorSpec|. Examples of
// |CommitSpec|s:
// * HEAD
// * master
// * HEAD~
// * remotes/origin/master~~
// * refs/heads/my-feature-branch^2~
//
// Constructing a |CommitSpec| does not mean the specified branch or commit
// exists. This carries a description of how to find the specified commit. See
// |doltdb.Resolve| for resolving a |CommitSpec| to a |Commit|.
func NewCommitSpec(cSpecStr string) (*CommitSpec, error) {
cSpecStrLwr := strings.TrimSpace(cSpecStr)
name, as, err := SplitAncestorSpec(cSpecStrLwr)
if err != nil {
return nil, err
}
if strings.EqualFold(name, head) {
return &CommitSpec{head, headCommitSpec, as}, nil
}
if hashRegex.MatchString(name) {
return &CommitSpec{name, hashCommitSpec, as}, nil
}
if !ref.IsValidBranchName(name) {
return nil, ErrInvalidBranchOrHash
}
return &CommitSpec{name, refCommitSpec, as}, nil
}