x/model: prefix NamePart constants with Part
This commit is contained in:
parent
ff68227ca1
commit
4eb7acf84b
124
x/model/name.go
124
x/model/name.go
@ -33,30 +33,30 @@ type NamePart int
|
|||||||
|
|
||||||
// Levels of concreteness
|
// Levels of concreteness
|
||||||
const (
|
const (
|
||||||
Host NamePart = iota
|
PartHost NamePart = iota
|
||||||
Namespace
|
PartNamespace
|
||||||
Model
|
PartModel
|
||||||
Tag
|
PartTag
|
||||||
Build
|
PartBuild
|
||||||
Digest
|
PartDigest
|
||||||
|
|
||||||
// Invalid is a special part that is used to indicate that a part is
|
// Invalid is a special part that is used to indicate that a part is
|
||||||
// invalid. It is not a valid part of a Name.
|
// invalid. It is not a valid part of a Name.
|
||||||
//
|
//
|
||||||
// It should be kept as the last part in the list.
|
// It should be kept as the last part in the list.
|
||||||
Invalid
|
PartInvalid
|
||||||
|
|
||||||
NumParts = Invalid
|
NumParts = PartInvalid
|
||||||
)
|
)
|
||||||
|
|
||||||
var kindNames = map[NamePart]string{
|
var kindNames = map[NamePart]string{
|
||||||
Invalid: "Invalid",
|
PartInvalid: "Invalid",
|
||||||
Host: "Host",
|
PartHost: "Host",
|
||||||
Namespace: "Namespace",
|
PartNamespace: "Namespace",
|
||||||
Model: "Name",
|
PartModel: "Name",
|
||||||
Tag: "Tag",
|
PartTag: "Tag",
|
||||||
Build: "Build",
|
PartBuild: "Build",
|
||||||
Digest: "Digest",
|
PartDigest: "Digest",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k NamePart) String() string {
|
func (k NamePart) String() string {
|
||||||
@ -139,7 +139,7 @@ type Name struct {
|
|||||||
func ParseName(s string) Name {
|
func ParseName(s string) Name {
|
||||||
var r Name
|
var r Name
|
||||||
for kind, part := range Parts(s) {
|
for kind, part := range Parts(s) {
|
||||||
if kind == Invalid {
|
if kind == PartInvalid {
|
||||||
return Name{}
|
return Name{}
|
||||||
}
|
}
|
||||||
r.parts[kind] = part
|
r.parts[kind] = part
|
||||||
@ -163,7 +163,7 @@ func Fill(dst, src Name) Name {
|
|||||||
|
|
||||||
// WithBuild returns a copy of r with the build set to the given string.
|
// WithBuild returns a copy of r with the build set to the given string.
|
||||||
func (r Name) WithBuild(build string) Name {
|
func (r Name) WithBuild(build string) Name {
|
||||||
r.parts[Build] = build
|
r.parts[PartBuild] = build
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ func (r Name) slice(from, to NamePart) Name {
|
|||||||
|
|
||||||
// DisplayModel returns the a display string composed of the model only.
|
// DisplayModel returns the a display string composed of the model only.
|
||||||
func (r Name) DisplayModel() string {
|
func (r Name) DisplayModel() string {
|
||||||
return r.parts[Model]
|
return r.parts[PartModel]
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisplayFullest returns the fullest possible display string in form:
|
// DisplayFullest returns the fullest possible display string in form:
|
||||||
@ -208,7 +208,7 @@ func (r Name) DisplayModel() string {
|
|||||||
// It does not include the build part. For the fullest possible display
|
// It does not include the build part. For the fullest possible display
|
||||||
// string with the build, use [Name.String].
|
// string with the build, use [Name.String].
|
||||||
func (r Name) DisplayFullest() string {
|
func (r Name) DisplayFullest() string {
|
||||||
return r.slice(Host, Tag).String()
|
return r.slice(PartHost, PartTag).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisplayShort returns the fullest possible display string in form:
|
// DisplayShort returns the fullest possible display string in form:
|
||||||
@ -217,7 +217,7 @@ func (r Name) DisplayFullest() string {
|
|||||||
//
|
//
|
||||||
// If any part is missing, it is omitted from the display string.
|
// If any part is missing, it is omitted from the display string.
|
||||||
func (r Name) DisplayShort() string {
|
func (r Name) DisplayShort() string {
|
||||||
return r.slice(Model, Tag).String()
|
return r.slice(PartModel, PartTag).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisplayLong returns the fullest possible display string in form:
|
// DisplayLong returns the fullest possible display string in form:
|
||||||
@ -226,16 +226,16 @@ func (r Name) DisplayShort() string {
|
|||||||
//
|
//
|
||||||
// If any part is missing, it is omitted from the display string.
|
// If any part is missing, it is omitted from the display string.
|
||||||
func (r Name) DisplayLong() string {
|
func (r Name) DisplayLong() string {
|
||||||
return r.slice(Namespace, Tag).String()
|
return r.slice(PartNamespace, PartTag).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
var seps = [...]string{
|
var seps = [...]string{
|
||||||
Host: "/",
|
PartHost: "/",
|
||||||
Namespace: "/",
|
PartNamespace: "/",
|
||||||
Model: ":",
|
PartModel: ":",
|
||||||
Tag: "+",
|
PartTag: "+",
|
||||||
Build: "@",
|
PartBuild: "@",
|
||||||
Digest: "",
|
PartDigest: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo implements io.WriterTo. It writes the fullest possible display
|
// WriteTo implements io.WriterTo. It writes the fullest possible display
|
||||||
@ -253,7 +253,7 @@ func (r Name) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
if r.parts[i] == "" {
|
if r.parts[i] == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n > 0 || NamePart(i) == Digest {
|
if n > 0 || NamePart(i) == PartDigest {
|
||||||
n1, err := io.WriteString(w, seps[i-1])
|
n1, err := io.WriteString(w, seps[i-1])
|
||||||
n += int64(n1)
|
n += int64(n1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -380,13 +380,13 @@ func (r Name) Value() (driver.Value, error) {
|
|||||||
// Complete reports whether the Name is fully qualified. That is it has a
|
// Complete reports whether the Name is fully qualified. That is it has a
|
||||||
// domain, namespace, name, tag, and build.
|
// domain, namespace, name, tag, and build.
|
||||||
func (r Name) Complete() bool {
|
func (r Name) Complete() bool {
|
||||||
return !slices.Contains(r.parts[:Digest], "")
|
return !slices.Contains(r.parts[:PartDigest], "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompleteNoBuild is like [Name.Complete] but it does not require the
|
// CompleteNoBuild is like [Name.Complete] but it does not require the
|
||||||
// build part to be present.
|
// build part to be present.
|
||||||
func (r Name) CompleteNoBuild() bool {
|
func (r Name) CompleteNoBuild() bool {
|
||||||
return !slices.Contains(r.parts[:Build], "")
|
return !slices.Contains(r.parts[:PartBuild], "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolved reports true if the Name has a valid digest.
|
// Resolved reports true if the Name has a valid digest.
|
||||||
@ -394,7 +394,7 @@ func (r Name) CompleteNoBuild() bool {
|
|||||||
// It is possible to have a valid Name, or a complete Name that is not
|
// It is possible to have a valid Name, or a complete Name that is not
|
||||||
// resolved.
|
// resolved.
|
||||||
func (r Name) Resolved() bool {
|
func (r Name) Resolved() bool {
|
||||||
return r.parts[Digest] != ""
|
return r.parts[PartDigest] != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Digest returns the digest part of the Name, if any.
|
// Digest returns the digest part of the Name, if any.
|
||||||
@ -402,7 +402,7 @@ func (r Name) Resolved() bool {
|
|||||||
// If Digest returns a non-empty string, then [Name.Resolved] will return
|
// If Digest returns a non-empty string, then [Name.Resolved] will return
|
||||||
// true, and digest is considered valid.
|
// true, and digest is considered valid.
|
||||||
func (r Name) Digest() string {
|
func (r Name) Digest() string {
|
||||||
return r.parts[Digest]
|
return r.parts[PartDigest]
|
||||||
}
|
}
|
||||||
|
|
||||||
// EqualFold reports whether r and o are equivalent model names, ignoring
|
// EqualFold reports whether r and o are equivalent model names, ignoring
|
||||||
@ -462,27 +462,27 @@ func Parts(s string) iter.Seq2[NamePart, string] {
|
|||||||
|
|
||||||
yieldValid := func(kind NamePart, part string) bool {
|
yieldValid := func(kind NamePart, part string) bool {
|
||||||
if !isValidPart(kind, part) {
|
if !isValidPart(kind, part) {
|
||||||
yield(Invalid, "")
|
yield(PartInvalid, "")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return yield(kind, part)
|
return yield(kind, part)
|
||||||
}
|
}
|
||||||
|
|
||||||
partLen := 0
|
partLen := 0
|
||||||
state, j := Digest, len(s)
|
state, j := PartDigest, len(s)
|
||||||
for i := len(s) - 1; i >= 0; i-- {
|
for i := len(s) - 1; i >= 0; i-- {
|
||||||
if partLen++; partLen > MaxNamePartLen {
|
if partLen++; partLen > MaxNamePartLen {
|
||||||
yield(Invalid, "")
|
yield(PartInvalid, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch s[i] {
|
switch s[i] {
|
||||||
case '@':
|
case '@':
|
||||||
switch state {
|
switch state {
|
||||||
case Digest:
|
case PartDigest:
|
||||||
part := s[i+1:]
|
part := s[i+1:]
|
||||||
if isValidDigest(part) {
|
if isValidDigest(part) {
|
||||||
if !yield(Digest, part) {
|
if !yield(PartDigest, part) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
@ -497,77 +497,77 @@ func Parts(s string) iter.Seq2[NamePart, string] {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
yield(Invalid, "")
|
yield(PartInvalid, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state, j, partLen = Build, i, 0
|
state, j, partLen = PartBuild, i, 0
|
||||||
default:
|
default:
|
||||||
yield(Invalid, "")
|
yield(PartInvalid, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case '+':
|
case '+':
|
||||||
switch state {
|
switch state {
|
||||||
case Build, Digest:
|
case PartBuild, PartDigest:
|
||||||
if !yieldValid(Build, s[i+1:j]) {
|
if !yieldValid(PartBuild, s[i+1:j]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state, j, partLen = Tag, i, 0
|
state, j, partLen = PartTag, i, 0
|
||||||
default:
|
default:
|
||||||
yield(Invalid, "")
|
yield(PartInvalid, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case ':':
|
case ':':
|
||||||
switch state {
|
switch state {
|
||||||
case Tag, Build, Digest:
|
case PartTag, PartBuild, PartDigest:
|
||||||
if !yieldValid(Tag, s[i+1:j]) {
|
if !yieldValid(PartTag, s[i+1:j]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state, j, partLen = Model, i, 0
|
state, j, partLen = PartModel, i, 0
|
||||||
default:
|
default:
|
||||||
yield(Invalid, "")
|
yield(PartInvalid, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case '/':
|
case '/':
|
||||||
switch state {
|
switch state {
|
||||||
case Model, Tag, Build, Digest:
|
case PartModel, PartTag, PartBuild, PartDigest:
|
||||||
if !yieldValid(Model, s[i+1:j]) {
|
if !yieldValid(PartModel, s[i+1:j]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state, j = Namespace, i
|
state, j = PartNamespace, i
|
||||||
case Namespace:
|
case PartNamespace:
|
||||||
if !yieldValid(Namespace, s[i+1:j]) {
|
if !yieldValid(PartNamespace, s[i+1:j]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state, j, partLen = Host, i, 0
|
state, j, partLen = PartHost, i, 0
|
||||||
default:
|
default:
|
||||||
yield(Invalid, "")
|
yield(PartInvalid, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if !isValidByte(state, s[i]) {
|
if !isValidByte(state, s[i]) {
|
||||||
yield(Invalid, "")
|
yield(PartInvalid, "")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if state <= Namespace {
|
if state <= PartNamespace {
|
||||||
yieldValid(state, s[:j])
|
yieldValid(state, s[:j])
|
||||||
} else {
|
} else {
|
||||||
yieldValid(Model, s[:j])
|
yieldValid(PartModel, s[:j])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid returns true if the Name has a valid nick. To know if a Name is
|
// Valid returns true if the Name hPartas a valid nick. To know if a Name is
|
||||||
// "complete", use [Name.Complete].
|
// "complete", use [Name.Complete].
|
||||||
func (r Name) Valid() bool {
|
func (r Name) Valid() bool {
|
||||||
// Parts ensures we only have valid parts, so no need to validate
|
// Parts ensures we only have valid parts, so no need to validate
|
||||||
// them here, only check if we have a name or not.
|
// them here, only check if we have a name or not.
|
||||||
return r.parts[Model] != ""
|
return r.parts[PartModel] != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// isValidPart returns true if given part is valid ascii [a-zA-Z0-9_\.-]
|
// isValidPart returns Parttrue if given part is valid ascii [a-zA-Z0-9_\.-]
|
||||||
func isValidPart(kind NamePart, s string) bool {
|
func isValidPart(kind NamePart, s string) bool {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return false
|
return false
|
||||||
@ -581,7 +581,7 @@ func isValidPart(kind NamePart, s string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isValidByte(kind NamePart, c byte) bool {
|
func isValidByte(kind NamePart, c byte) bool {
|
||||||
if kind == Namespace && c == '.' {
|
if kind == PartNamespace && c == '.' {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if c == '.' || c == '-' {
|
if c == '.' || c == '-' {
|
||||||
|
@ -18,12 +18,12 @@ type fields struct {
|
|||||||
|
|
||||||
func fieldsFromName(p Name) fields {
|
func fieldsFromName(p Name) fields {
|
||||||
return fields{
|
return fields{
|
||||||
host: p.parts[Host],
|
host: p.parts[PartHost],
|
||||||
namespace: p.parts[Namespace],
|
namespace: p.parts[PartNamespace],
|
||||||
model: p.parts[Model],
|
model: p.parts[PartModel],
|
||||||
tag: p.parts[Tag],
|
tag: p.parts[PartTag],
|
||||||
build: p.parts[Build],
|
build: p.parts[PartBuild],
|
||||||
digest: p.parts[Digest],
|
digest: p.parts[PartDigest],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user