Skip to content

Commit afba971

Browse files
committed
Cleanup referenceutil
Signed-off-by: apostasie <[email protected]>
1 parent 57bafac commit afba971

File tree

2 files changed

+383
-74
lines changed

2 files changed

+383
-74
lines changed

pkg/referenceutil/referenceutil.go

Lines changed: 91 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -17,94 +17,121 @@
1717
package referenceutil
1818

1919
import (
20-
"fmt"
2120
"path"
2221
"strings"
2322

24-
distributionref "github.com/distribution/reference"
23+
"github.com/distribution/reference"
2524
"github.com/ipfs/go-cid"
25+
"github.com/opencontainers/go-digest"
2626
)
2727

28-
// Reference is a reference to an image.
29-
type Reference interface {
28+
type Protocol string
3029

31-
// String returns the full reference which can be understood by containerd.
32-
String() string
30+
const IPFSProtocol Protocol = "ipfs"
31+
const IPNSProtocol Protocol = "ipns"
32+
const shortIDLength = 5
33+
34+
type ImageReference struct {
35+
Protocol Protocol
36+
Digest digest.Digest
37+
Tag string
38+
ExplicitTag string
39+
Path string
40+
Domain string
41+
42+
nn reference.Reference
3343
}
3444

35-
// ParseAnyReference parses the passed reference as IPFS, CID, or a classic reference.
36-
// Unlike ParseAny, it is not limited to the DockerRef limitations (being either tagged or digested)
37-
// and should be used instead.
38-
func ParseAnyReference(rawRef string) (Reference, error) {
39-
if scheme, ref, err := ParseIPFSRefWithScheme(rawRef); err == nil {
40-
return Reference(stringRef{scheme: scheme, s: ref}), nil
45+
func (ir *ImageReference) Name() string {
46+
ret := ir.Domain
47+
if ret != "" {
48+
ret += "/"
4149
}
42-
if c, err := cid.Decode(rawRef); err == nil {
43-
return c, nil
44-
}
45-
return distributionref.ParseAnyReference(rawRef)
50+
ret += ir.Path
51+
return ret
4652
}
4753

48-
// ParseAny parses the passed reference with allowing it to be non-docker reference.
49-
// If the ref has IPFS scheme or can be parsed as CID, it's parsed as an IPFS reference.
50-
// Otherwise it's parsed as a docker reference.
51-
func ParseAny(rawRef string) (Reference, error) {
52-
if scheme, ref, err := ParseIPFSRefWithScheme(rawRef); err == nil {
53-
return stringRef{scheme: scheme, s: ref}, nil
54+
func (ir *ImageReference) FamiliarName() string {
55+
if ir.Protocol != "" && ir.Domain == "" {
56+
return ir.Path
5457
}
55-
if c, err := cid.Decode(rawRef); err == nil {
56-
return c, nil
58+
if ir.nn != nil {
59+
return reference.FamiliarName(ir.nn.(reference.Named))
5760
}
58-
return ParseDockerRef(rawRef)
61+
return ""
5962
}
6063

61-
// ParseDockerRef parses the passed reference with assuming it's a docker reference.
62-
func ParseDockerRef(rawRef string) (distributionref.Named, error) {
63-
return distributionref.ParseDockerRef(rawRef)
64+
func (ir *ImageReference) FamiliarMatch(pattern string) (bool, error) {
65+
return reference.FamiliarMatch(pattern, ir.nn)
6466
}
6567

66-
// ParseIPFSRefWithScheme parses the passed reference with assuming it's an IPFS reference with scheme prefix.
67-
func ParseIPFSRefWithScheme(name string) (scheme, ref string, err error) {
68-
if strings.HasPrefix(name, "ipfs://") || strings.HasPrefix(name, "ipns://") {
69-
return name[:4], name[7:], nil
68+
func (ir *ImageReference) String() string {
69+
if ir.Protocol != "" && ir.Domain == "" {
70+
return ir.Path
71+
}
72+
if ir.Path == "" && ir.Digest != "" {
73+
return ir.Digest.String()
7074
}
71-
return "", "", fmt.Errorf("reference is not an IPFS reference")
75+
if ir.nn != nil {
76+
return ir.nn.String()
77+
}
78+
return ""
7279
}
7380

74-
type stringRef struct {
75-
scheme string
76-
s string
81+
func (ir *ImageReference) SuggestContainerName(suffix string) string {
82+
name := "untitled"
83+
if ir.Protocol != "" && ir.Domain == "" {
84+
name = string(ir.Protocol) + "-" + ir.String()[:shortIDLength]
85+
} else if ir.Path != "" {
86+
name = path.Base(ir.Path)
87+
}
88+
return name + "-" + suffix[:5]
7789
}
7890

79-
func (s stringRef) String() string {
80-
return s.s
81-
}
91+
func Parse(rawRef string) (*ImageReference, error) {
92+
ir := &ImageReference{}
93+
94+
if strings.HasPrefix(rawRef, "ipfs://") {
95+
ir.Protocol = IPFSProtocol
96+
rawRef = rawRef[7:]
97+
} else if strings.HasPrefix(rawRef, "ipns://") {
98+
ir.Protocol = IPNSProtocol
99+
rawRef = rawRef[7:]
100+
}
101+
if decodedCID, err := cid.Decode(rawRef); err == nil {
102+
ir.Protocol = IPFSProtocol
103+
rawRef = decodedCID.String()
104+
ir.Path = rawRef
105+
return ir, nil
106+
}
107+
108+
if dgst, err := digest.Parse(rawRef); err == nil {
109+
ir.Digest = dgst
110+
return ir, nil
111+
} else if dgst, err := digest.Parse("sha256:" + rawRef); err == nil {
112+
ir.Digest = dgst
113+
return ir, nil
114+
}
82115

83-
// SuggestContainerName generates a container name from name.
84-
// The result MUST NOT be parsed.
85-
func SuggestContainerName(rawRef, containerID string) string {
86-
const shortIDLength = 5
87-
if len(containerID) < shortIDLength {
88-
panic(fmt.Errorf("got too short (< %d) container ID: %q", shortIDLength, containerID))
116+
var err error
117+
ir.nn, err = reference.ParseNormalizedNamed(rawRef)
118+
if err != nil {
119+
return ir, err
89120
}
90-
name := "untitled-" + containerID[:shortIDLength]
91-
if rawRef != "" {
92-
r, err := ParseAny(rawRef)
93-
if err == nil {
94-
switch rr := r.(type) {
95-
case distributionref.Named:
96-
if rrName := rr.Name(); rrName != "" {
97-
imageNameBased := path.Base(rrName)
98-
if imageNameBased != "" {
99-
name = imageNameBased + "-" + containerID[:shortIDLength]
100-
}
101-
}
102-
case cid.Cid:
103-
name = "ipfs" + "-" + rr.String()[:shortIDLength] + "-" + containerID[:shortIDLength]
104-
case stringRef:
105-
name = rr.scheme + "-" + rr.s[:shortIDLength] + "-" + containerID[:shortIDLength]
106-
}
107-
}
121+
if tg, ok := ir.nn.(reference.Tagged); ok {
122+
ir.ExplicitTag = tg.Tag()
108123
}
109-
return name
124+
if tg, ok := ir.nn.(reference.Named); ok {
125+
ir.nn = reference.TagNameOnly(tg)
126+
ir.Domain = reference.Domain(tg)
127+
ir.Path = reference.Path(tg)
128+
}
129+
if tg, ok := ir.nn.(reference.Tagged); ok {
130+
ir.Tag = tg.Tag()
131+
}
132+
if tg, ok := ir.nn.(reference.Digested); ok {
133+
ir.Digest = tg.Digest()
134+
}
135+
136+
return ir, nil
110137
}

0 commit comments

Comments
 (0)