go-containerregistry解析镜像引用时自定义Registry与Repository求助
自定义go-containerregistry镜像引用解析规则
我调用name.ParseReference("http://host:port/some1/some2/nginx:n")解析镜像引用,期望得到的registry为http://host:port/some1/some2,repository为nginx,但go-containerregistry默认解析逻辑不支持这种自定义规则,且相关结构体字段多为私有无法直接修改,请问该如何实现需求?
我的测试代码如下:
package main import ( "fmt" "github.com/google/go-containerregistry/pkg/name" ) func main() { ref, err := name.ParseReference("nexus.example.com/repository/test/nginx:t") if err != nil { fmt.Println(err) return } // ref = &name.Tag{Repository: name.Repository{Registry: name.Registry{}}} fmt.Println(ref.Context().RepositoryStr()) fmt.Println(ref.Context().RegistryStr()) fmt.Println(ref.Context().Name()) }
解决方案
1. 手动拆分引用字符串,自定义解析逻辑
直接对输入的镜像引用字符串进行拆分,跳过go-containerregistry的默认解析,手动提取所需的registry和repository:
package main import ( "fmt" "strings" "github.com/google/go-containerregistry/pkg/name" ) // customParseReference 自定义解析镜像引用,返回指定格式的registry和repository func customParseReference(refStr string) (registry string, repo string, err error) { // 处理HTTP/HTTPS协议头 var protocolPrefix string switch { case strings.HasPrefix(refStr, "http://"): protocolPrefix = "http://" refStr = strings.TrimPrefix(refStr, protocolPrefix) case strings.HasPrefix(refStr, "https://"): protocolPrefix = "https://" refStr = strings.TrimPrefix(refStr, protocolPrefix) } // 移除标签部分(如:n、:t) if colonIdx := strings.Index(refStr, ":"); colonIdx != -1 { refStr = refStr[:colonIdx] } // 按斜杠拆分字符串 parts := strings.Split(refStr, "/") if len(parts) < 2 { return "", "", fmt.Errorf("镜像引用格式无效") } // 最后一段是repository,前面的拼接为registry repo = parts[len(parts)-1] registry = protocolPrefix + strings.Join(parts[:len(parts)-1], "/") return } func main() { // 测试自定义解析 targetRef := "http://host:port/some1/some2/nginx:n" registry, repo, err := customParseReference(targetRef) if err != nil { fmt.Println("解析失败:", err) return } fmt.Println("自定义解析结果:") fmt.Println("Registry:", registry) fmt.Println("Repository:", repo) // 对比原解析逻辑结果 ref, err := name.ParseReference(targetRef) if err != nil { fmt.Println("\n原解析失败:", err) return } fmt.Println("\n原解析结果:") fmt.Println("RepositoryStr:", ref.Context().RepositoryStr()) fmt.Println("RegistryStr:", ref.Context().RegistryStr()) fmt.Println("Name:", ref.Context().Name()) }
2. 包装原有引用实例,覆盖接口方法
如果需要兼容go-containerregistry的name.Reference接口,可自定义结构体包装原有引用,重写Context()方法返回自定义的Repository结构:
package main import ( "fmt" "strings" "github.com/google/go-containerregistry/pkg/name" ) // CustomRepository 自定义Repository,覆盖核心方法 type CustomRepository struct { originalRepo name.Repository customReg string customRepo string } func (cr *CustomRepository) RegistryStr() string { return cr.customReg } func (cr *CustomRepository) RepositoryStr() string { return cr.customReg + "/" + cr.customRepo } func (cr *CustomRepository) Name() string { return cr.customRepo } // 实现name.Repository接口的其他必要方法,按需补充 func (cr *CustomRepository) Registry() name.Registry { return cr.originalRepo.Registry() } func (cr *CustomRepository) String() string { return cr.RepositoryStr() } // CustomReference 自定义Reference包装器 type CustomReference struct { originalRef name.Reference customRepo *CustomRepository } func (cr *CustomReference) Context() name.Repository { return cr.customRepo } // 实现name.Reference接口的其他必要方法,按需补充 func (cr *CustomReference) String() string { return cr.originalRef.String() } func (cr *CustomReference) Tag() name.Tag { t, _ := cr.originalRef.(name.Tag) return t } // wrapReference 将原有引用包装为自定义引用 func wrapReference(originalRef name.Reference, customReg, customRepo string) name.Reference { return &CustomReference{ originalRef: originalRef, customRepo: &CustomRepository{ originalRepo: originalRef.Context(), customReg: customReg, customRepo: customRepo, }, } } func main() { targetRef := "http://host:port/some1/some2/nginx:n" originalRef, err := name.ParseReference(targetRef) if err != nil { fmt.Println("原解析失败:", err) return } // 拆分得到自定义的registry和repository refStr := originalRef.String() protocolPrefix := "" switch { case strings.HasPrefix(refStr, "http://"): protocolPrefix = "http://" refStr = strings.TrimPrefix(refStr, protocolPrefix) case strings.HasPrefix(refStr, "https://"): protocolPrefix = "https://" refStr = strings.TrimPrefix(refStr, protocolPrefix) } if colonIdx := strings.Index(refStr, ":"); colonIdx != -1 { refStr = refStr[:colonIdx] } parts := strings.Split(refStr, "/") if len(parts) < 2 { fmt.Println("镜像引用格式无效") return } customReg := protocolPrefix + strings.Join(parts[:len(parts)-1], "/") customRepo := parts[len(parts)-1] // 包装引用并输出结果 customRef := wrapReference(originalRef, customReg, customRepo) fmt.Println("包装后的解析结果:") fmt.Println("RepositoryStr:", customRef.Context().RepositoryStr()) fmt.Println("RegistryStr:", customRef.Context().RegistryStr()) fmt.Println("Name:", customRef.Context().Name()) }
内容的提问来源于stack exchange,提问作者Rajesh
相关产品推荐
相关产品推荐

