pkg/oci/distribution/v2.go (37 lines of code) (raw):
// Initial Copyright (c) 2023 Xenit AB and 2024 The Spegel Authors.
// Portions Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package distribution
import (
"fmt"
"regexp"
"github.com/opencontainers/go-digest"
)
// ReferenceType is the type of reference - manifest or blob.
type ReferenceType string
const (
ReferenceTypeManifest = "Manifest"
ReferenceTypeBlob = "Blob"
)
var (
nameRegex = regexp.MustCompile(`([a-z0-9]+([._-][a-z0-9]+)*(/[a-z0-9]+([._-][a-z0-9]+)*)*)`)
tagRegex = regexp.MustCompile(`([a-zA-Z0-9_][a-zA-Z0-9._-]{0,127})`)
manifestRegexTag = regexp.MustCompile(`/v2/` + nameRegex.String() + `/manifests/` + tagRegex.String() + `$`)
manifestRegexDigest = regexp.MustCompile(`/v2/` + nameRegex.String() + `/manifests/(.*)`)
blobsRegexDigest = regexp.MustCompile(`/v2/` + nameRegex.String() + `/blobs/(.*)`)
)
// ParsePathComponents parses the registry, digest and reference type from a distribution path.
func ParsePathComponents(registry, path string) (string, digest.Digest, ReferenceType, error) {
comps := manifestRegexTag.FindStringSubmatch(path)
if len(comps) == 6 {
if registry == "" {
return "", "", "", fmt.Errorf("registry parameter needs to be set for tag references")
}
ref := fmt.Sprintf("%s/%s:%s", registry, comps[1], comps[5])
return ref, "", ReferenceTypeManifest, nil
}
comps = manifestRegexDigest.FindStringSubmatch(path)
if len(comps) == 6 {
return "", digest.Digest(comps[5]), ReferenceTypeManifest, nil
}
comps = blobsRegexDigest.FindStringSubmatch(path)
if len(comps) == 6 {
return "", digest.Digest(comps[5]), ReferenceTypeBlob, nil
}
return "", "", "", fmt.Errorf("distribution path could not be parsed")
}