/* * Copyright 2026 Oleg Borodin * * */ package repocli import ( "net/url" "path" "strings" ) type Referer struct { urlobj *url.URL user, pass string base, tag string } func NewReferer(rawref string) (*Referer, error) { ref := &Referer{} if !strings.Contains(rawref, "://") { rawref = "https://" + rawref } urlobj, err := url.Parse(rawref) if err != nil { return ref, err } if urlobj.User != nil { ref.user = urlobj.User.Username() ref.pass, _ = urlobj.User.Password() urlobj.User = nil } ref.urlobj = urlobj if strings.Contains(ref.urlobj.Path, ":") { m := strings.SplitN(ref.urlobj.Path, ":", 2) ref.base = m[0] ref.tag = m[1] } else { ref.base = ref.urlobj.Path } ref.urlobj.Path = "/" ref.urlobj = urlobj return ref, err } func (ref *Referer) RawWithTag(tag string) string { return path.Join(ref.urlobj.Host, ref.base+":"+tag) } func (ref *Referer) Raw() string { if ref.tag != "" { return path.Join(ref.urlobj.Host, ref.base+":"+ref.tag) } return path.Join(ref.urlobj.Host, ref.base) } func (ref *Referer) RawRepo() string { return path.Join(ref.urlobj.Host, ref.base) } func (ref *Referer) Tag() string { return ref.tag } func (ref *Referer) ManifestEP() string { curl := ref.urlobj.JoinPath("/v2", ref.base, "/manifests", ref.tag) return curl.String() } func (ref *Referer) BlobEP(digest string) string { curl := ref.urlobj.JoinPath("/v2", ref.base, "/blobs", digest) return curl.String() } func (ref *Referer) UploadEP() string { curl := ref.urlobj.JoinPath("/v2", ref.base, "/blobs/uploads/") return curl.String() } func (ref *Referer) PatchEP(loc string) (string, error) { var curl *url.URL var out string var err error if isUUID(loc) { curl = ref.urlobj.JoinPath("/v2/", ref.base, "/blobs/uploads/", loc) return curl.String(), nil } if strings.Contains(loc, "://") { curl, err = url.Parse(loc) if err != nil { return out, err } } else { curl = ref.urlobj.JoinPath(loc) } out = curl.String() return out, err } func (ref *Referer) PutEP(loc, digest string) (string, error) { var curl *url.URL var out string var err error if isUUID(loc) { curl = ref.urlobj.JoinPath("/v2/", ref.base, "/blobs/uploads/", loc) } else if strings.Contains(loc, "://") { curl, err = url.Parse(loc) if err != nil { return out, err } } else { curl = ref.urlobj.JoinPath(loc) } query := curl.Query() query.Set("digest", digest) curl.RawQuery = query.Encode() out = curl.String() return out, err } func (ref *Referer) TagsEP() string { curl := ref.urlobj.JoinPath("/v2", ref.base, "/tags/list") return curl.String() } func (ref *Referer) ReferersEP(digest string) string { curl := ref.urlobj.JoinPath("/v2", ref.base, "/referers/", digest) return curl.String() } func (ref *Referer) CatalogEP() string { curl := ref.urlobj.JoinPath("/v2/_catalog") return curl.String() } func (ref *Referer) Userinfo() (string, string) { return ref.user, ref.pass } func (ref *Referer) SetUserinfo(user, pass string) { if user != "" && pass != "" { ref.user, ref.pass = user, pass } }