x/model: Registry -> Host, Nick -> Model

This commit is contained in:
Blake Mizerany 2024-04-04 15:26:08 -07:00
parent a4fd06d603
commit d510a90214
2 changed files with 49 additions and 49 deletions

View File

@ -14,18 +14,18 @@ type NamePart int
// Levels of concreteness // Levels of concreteness
const ( const (
Invalid NamePart = iota Invalid NamePart = iota
Registry Host
Namespace Namespace
Nick Model
Tag Tag
Build Build
) )
var kindNames = map[NamePart]string{ var kindNames = map[NamePart]string{
Invalid: "Invalid", Invalid: "Invalid",
Registry: "Domain", Host: "Host",
Namespace: "Namespace", Namespace: "Namespace",
Nick: "Name", Model: "Name",
Tag: "Tag", Tag: "Tag",
Build: "Build", Build: "Build",
} }
@ -36,9 +36,9 @@ var kindNames = map[NamePart]string{
// //
// Users or Name must check Valid before using it. // Users or Name must check Valid before using it.
type Name struct { type Name struct {
domain string host string
namespace string namespace string
nick string model string
tag string tag string
build string build string
} }
@ -47,23 +47,23 @@ type Name struct {
// concreteness. If a part is missing, it is replaced with a loud // concreteness. If a part is missing, it is replaced with a loud
// placeholder. // placeholder.
func (r Name) Full() string { func (r Name) Full() string {
r.domain = cmp.Or(r.domain, "!(MISSING DOMAIN)") r.host = cmp.Or(r.host, "!(MISSING DOMAIN)")
r.namespace = cmp.Or(r.namespace, "!(MISSING NAMESPACE)") r.namespace = cmp.Or(r.namespace, "!(MISSING NAMESPACE)")
r.nick = cmp.Or(r.nick, "!(MISSING NAME)") r.model = cmp.Or(r.model, "!(MISSING NAME)")
r.tag = cmp.Or(r.tag, "!(MISSING TAG)") r.tag = cmp.Or(r.tag, "!(MISSING TAG)")
r.build = cmp.Or(r.build, "!(MISSING BUILD)") r.build = cmp.Or(r.build, "!(MISSING BUILD)")
return r.String() return r.String()
} }
func (r Name) NickAndTag() string { func (r Name) ModelAndTag() string {
r.domain = "" r.host = ""
r.namespace = "" r.namespace = ""
r.build = "" r.build = ""
return r.String() return r.String()
} }
func (r Name) NickTagAndBuild() string { func (r Name) ModelTagAndBuild() string {
r.domain = "" r.host = ""
r.namespace = "" r.namespace = ""
return r.String() return r.String()
} }
@ -71,15 +71,15 @@ func (r Name) NickTagAndBuild() string {
// String returns the fully qualified ref string. // String returns the fully qualified ref string.
func (r Name) String() string { func (r Name) String() string {
var b strings.Builder var b strings.Builder
if r.domain != "" { if r.host != "" {
b.WriteString(r.domain) b.WriteString(r.host)
b.WriteString("/") b.WriteString("/")
} }
if r.namespace != "" { if r.namespace != "" {
b.WriteString(r.namespace) b.WriteString(r.namespace)
b.WriteString("/") b.WriteString("/")
} }
b.WriteString(r.nick) b.WriteString(r.model)
if r.tag != "" { if r.tag != "" {
b.WriteString(":") b.WriteString(":")
b.WriteString(r.tag) b.WriteString(r.tag)
@ -121,17 +121,17 @@ func (r Name) Less(o Name) bool {
// The length of the returned slice is always 5. // The length of the returned slice is always 5.
func (r Name) Parts() []string { func (r Name) Parts() []string {
return []string{ return []string{
r.domain, r.host,
r.namespace, r.namespace,
r.nick, r.model,
r.tag, r.tag,
r.build, r.build,
} }
} }
func (r Name) Domain() string { return r.namespace } func (r Name) Host() string { return r.host }
func (r Name) Namespace() string { return r.namespace } func (r Name) Namespace() string { return r.namespace }
func (r Name) Nick() string { return r.nick } func (r Name) Model() string { return r.model }
func (r Name) Tag() string { return r.tag } func (r Name) Tag() string { return r.tag }
func (r Name) Build() string { return r.build } func (r Name) Build() string { return r.build }
@ -155,12 +155,12 @@ func ParseName(s string) Name {
var r Name var r Name
for kind, part := range NameParts(s) { for kind, part := range NameParts(s) {
switch kind { switch kind {
case Registry: case Host:
r.domain = part r.host = part
case Namespace: case Namespace:
r.namespace = part r.namespace = part
case Nick: case Model:
r.nick = part r.model = part
case Tag: case Tag:
r.tag = part r.tag = part
case Build: case Build:
@ -186,9 +186,9 @@ func ParseName(s string) Name {
func Merge(dst, src Name) Name { func Merge(dst, src Name) Name {
return Name{ return Name{
// name is left untouched // name is left untouched
nick: dst.nick, model: dst.model,
domain: cmp.Or(dst.domain, src.domain), host: cmp.Or(dst.host, src.host),
namespace: cmp.Or(dst.namespace, src.namespace), namespace: cmp.Or(dst.namespace, src.namespace),
tag: cmp.Or(dst.tag, src.tag), tag: cmp.Or(dst.tag, src.tag),
build: cmp.Or(dst.build, src.build), build: cmp.Or(dst.build, src.build),
@ -250,15 +250,15 @@ func NameParts(s string) iter.Seq2[NamePart, string] {
if !yieldValid(Tag, s[i+1:j]) { if !yieldValid(Tag, s[i+1:j]) {
return return
} }
state, j = Nick, i state, j = Model, i
default: default:
yield(Invalid, "") yield(Invalid, "")
return return
} }
case '/': case '/':
switch state { switch state {
case Nick, Tag, Build: case Model, Tag, Build:
if !yieldValid(Nick, s[i+1:j]) { if !yieldValid(Model, s[i+1:j]) {
return return
} }
state, j = Namespace, i state, j = Namespace, i
@ -266,7 +266,7 @@ func NameParts(s string) iter.Seq2[NamePart, string] {
if !yieldValid(Namespace, s[i+1:j]) { if !yieldValid(Namespace, s[i+1:j]) {
return return
} }
state, j = Registry, i state, j = Host, i
default: default:
yield(Invalid, "") yield(Invalid, "")
return return
@ -282,7 +282,7 @@ func NameParts(s string) iter.Seq2[NamePart, string] {
if state <= Namespace { if state <= Namespace {
yieldValid(state, s[:j]) yieldValid(state, s[:j])
} else { } else {
yieldValid(Nick, s[:j]) yieldValid(Model, s[:j])
} }
} }
} }
@ -292,7 +292,7 @@ func NameParts(s string) iter.Seq2[NamePart, string] {
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.nick != "" return r.model != ""
} }
// isValidPart returns true if given part is valid ascii [a-zA-Z0-9_\.-] // isValidPart returns true if given part is valid ascii [a-zA-Z0-9_\.-]

View File

@ -7,15 +7,15 @@ import (
) )
var testNames = map[string]Name{ var testNames = map[string]Name{
"mistral:latest": {nick: "mistral", tag: "latest"}, "mistral:latest": {model: "mistral", tag: "latest"},
"mistral": {nick: "mistral"}, "mistral": {model: "mistral"},
"mistral:30B": {nick: "mistral", tag: "30B"}, "mistral:30B": {model: "mistral", tag: "30B"},
"mistral:7b": {nick: "mistral", tag: "7b"}, "mistral:7b": {model: "mistral", tag: "7b"},
"mistral:7b+Q4_0": {nick: "mistral", tag: "7b", build: "Q4_0"}, "mistral:7b+Q4_0": {model: "mistral", tag: "7b", build: "Q4_0"},
"mistral+KQED": {nick: "mistral", build: "KQED"}, "mistral+KQED": {model: "mistral", build: "KQED"},
"mistral.x-3:7b+Q4_0": {nick: "mistral.x-3", tag: "7b", build: "Q4_0"}, "mistral.x-3:7b+Q4_0": {model: "mistral.x-3", tag: "7b", build: "Q4_0"},
"mistral:7b+q4_0": {nick: "mistral", tag: "7b", build: "Q4_0"}, "mistral:7b+q4_0": {model: "mistral", tag: "7b", build: "Q4_0"},
"llama2": {nick: "llama2"}, "llama2": {model: "llama2"},
// invalid (includes fuzzing trophies) // invalid (includes fuzzing trophies)
"+": {}, "+": {},
@ -36,7 +36,7 @@ var testNames = map[string]Name{
"file:///etc/passwd:latest": {}, "file:///etc/passwd:latest": {},
"file:///etc/passwd:latest+u": {}, "file:///etc/passwd:latest+u": {},
strings.Repeat("a", MaxNameLength): {nick: strings.Repeat("a", MaxNameLength)}, strings.Repeat("a", MaxNameLength): {model: strings.Repeat("a", MaxNameLength)},
strings.Repeat("a", MaxNameLength+1): {}, strings.Repeat("a", MaxNameLength+1): {},
} }
@ -66,10 +66,10 @@ func TestParseName(t *testing.T) {
t.Errorf("String() = %s; want %s", got.String(), s) t.Errorf("String() = %s; want %s", got.String(), s)
} }
if got.Valid() && got.Nick() == "" { if got.Valid() && got.Model() == "" {
t.Errorf("Valid() = true; Nick() = %q; want non-empty name", got.Nick()) t.Errorf("Valid() = true; Model() = %q; want non-empty name", got.Model())
} else if !got.Valid() && got.Nick() != "" { } else if !got.Valid() && got.Model() != "" {
t.Errorf("Valid() = false; Nick() = %q; want empty name", got.Nick()) t.Errorf("Valid() = false; Model() = %q; want empty name", got.Model())
} }
}) })
} }
@ -118,11 +118,11 @@ func TestNameStringVariants(t *testing.T) {
t.Run(tt.in, func(t *testing.T) { t.Run(tt.in, func(t *testing.T) {
p := ParseName(tt.in) p := ParseName(tt.in)
t.Logf("ParseName(%q) = %#v", tt.in, p) t.Logf("ParseName(%q) = %#v", tt.in, p)
if g := p.NickAndTag(); g != tt.nameAndTag { if g := p.ModelAndTag(); g != tt.nameAndTag {
t.Errorf("NickAndTag(%q) = %q; want %q", tt.in, g, tt.nameAndTag) t.Errorf("ModelAndTag(%q) = %q; want %q", tt.in, g, tt.nameAndTag)
} }
if g := p.NickTagAndBuild(); g != tt.nameTagAndBuild { if g := p.ModelTagAndBuild(); g != tt.nameTagAndBuild {
t.Errorf("NickTagAndBuild(%q) = %q; want %q", tt.in, g, tt.nameTagAndBuild) t.Errorf("ModelTagAndBuild(%q) = %q; want %q", tt.in, g, tt.nameTagAndBuild)
} }
}) })
} }