ocilayout: handle Windows paths in local OCI layout refs

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2026-04-22 11:38:34 +02:00
parent 872d8e5e58
commit 2d58ee6f98
2 changed files with 43 additions and 3 deletions
+11 -3
View File
@@ -34,7 +34,7 @@ func Parse(s string) (Ref, bool, error) {
} }
} }
if i := strings.LastIndex(localPath, ":"); i >= 0 { if i := strings.LastIndex(localPath, ":"); i >= 0 && !isWindowsDrivePath(localPath, i) {
after := localPath[i+1:] after := localPath[i+1:]
if reference.TagRegexp.MatchString(after) { if reference.TagRegexp.MatchString(after) {
localPath, out.Tag = localPath[:i], after localPath, out.Tag = localPath[:i], after
@@ -51,10 +51,18 @@ func Parse(s string) (Ref, bool, error) {
func (r Ref) String() string { func (r Ref) String() string {
s := prefix + r.Path s := prefix + r.Path
if r.Tag != "" { if r.Tag != "" {
return s + ":" + r.Tag s += ":" + r.Tag
} }
if r.Digest != "" { if r.Digest != "" {
return s + "@" + r.Digest.String() s += "@" + r.Digest.String()
} }
return s return s
} }
func isWindowsDrivePath(path string, colon int) bool {
if colon != 1 || len(path) < 2 {
return false
}
c := path[0]
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
}
+32
View File
@@ -3,6 +3,7 @@ package ocilayout
import ( import (
"testing" "testing"
digest "github.com/opencontainers/go-digest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -39,6 +40,27 @@ func TestParse(t *testing.T) {
path: "/path/to/oci/@/layout", path: "/path/to/oci/@/layout",
tag: "latest", tag: "latest",
}, },
{
s: `oci-layout://C:\path\to\oci\layout`,
path: `C:\path\to\oci\layout`,
tag: "latest",
},
{
s: `oci-layout://C:\path\to\oci\layout:1.3`,
path: `C:\path\to\oci\layout`,
tag: "1.3",
},
{
s: `oci-layout://C:\path\to\oci\layout@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`,
path: `C:\path\to\oci\layout`,
dgst: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
},
{
s: `oci-layout://C:\path\to\oci\layout:1.3@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`,
path: `C:\path\to\oci\layout`,
tag: "1.3",
dgst: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
},
} { } {
ref, ok, err := Parse(tt.s) ref, ok, err := Parse(tt.s)
require.True(t, ok) require.True(t, ok)
@@ -48,3 +70,13 @@ func TestParse(t *testing.T) {
assert.Equal(t, tt.tag, ref.Tag, "comparing tag: %s", tt.s) assert.Equal(t, tt.tag, ref.Tag, "comparing tag: %s", tt.s)
} }
} }
func TestRefString(t *testing.T) {
ref := Ref{
Path: "/path/to/oci/layout",
Tag: "1.3",
Digest: digest.Digest("sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
}
assert.Equal(t, "oci-layout:///path/to/oci/layout:1.3@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ref.String())
}