build: handle at symbols in an oci-layout path
The buildx command line will now handle `@` symbols in the `oci-layout://` path when used with named contexts. Instead of assuming the `@` symbol is part of the reference digest, it will first check that it is a valid reference digest. Otherwise, it will assume it's part of the file path. Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
This commit is contained in:
+35
-7
@@ -558,12 +558,8 @@ func loadInputs(ctx context.Context, d *driver.DriverHandle, inp *Inputs, pw pro
|
||||
|
||||
// handle OCI layout
|
||||
if localPath, ok := strings.CutPrefix(v.Path, "oci-layout://"); ok {
|
||||
localPath, dig, hasDigest := strings.Cut(localPath, "@")
|
||||
localPath, tag, hasTag := strings.Cut(localPath, ":")
|
||||
if !hasTag {
|
||||
tag = "latest"
|
||||
}
|
||||
if !hasDigest {
|
||||
localPath, dig, tag := parseOCILayoutPath(localPath)
|
||||
if dig == "" {
|
||||
dig, err = resolveDigest(localPath, tag)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "oci-layout reference %q could not be resolved", v.Path)
|
||||
@@ -899,7 +895,7 @@ type lazyFileWriter struct {
|
||||
|
||||
func (w *lazyFileWriter) Write(p []byte) (int, error) {
|
||||
if w.file == nil {
|
||||
if err := os.MkdirAll(filepath.Dir(w.path), 0755); err != nil {
|
||||
if err := os.MkdirAll(filepath.Dir(w.path), 0o755); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
f, err := os.Create(w.path)
|
||||
@@ -1017,3 +1013,35 @@ func isActive(ce *client.CacheOptionsEntry) bool {
|
||||
}
|
||||
return ce.Attrs["token"] != "" && (ce.Attrs["url"] != "" || ce.Attrs["url_v2"] != "")
|
||||
}
|
||||
|
||||
// parseOCILayoutPath handles the oci-layout url accepted by buildx.
|
||||
func parseOCILayoutPath(s string) (localPath, dgst, tag string) {
|
||||
localPath = s
|
||||
|
||||
// Look for the digest reference. There might be multiple @ symbols
|
||||
// in the path and the @ symbol may be part of the path or part of
|
||||
// the digest. If we find the @ symbol, verify that it's a valid
|
||||
// digest reference instead of just assuming it is because it
|
||||
// might be part of the file path.
|
||||
if i := strings.LastIndex(localPath, "@"); i >= 0 {
|
||||
after := localPath[i+1:]
|
||||
if reference.DigestRegexp.MatchString(after) {
|
||||
localPath, dgst = localPath[:i], after
|
||||
}
|
||||
}
|
||||
|
||||
// Do the same with the tag. This isn't as necessary since colons
|
||||
// aren't valid as file paths on Linux/Unix systems, but they are valid
|
||||
// on Windows systems so we might as well just be safe.
|
||||
if i := strings.LastIndex(localPath, ":"); i >= 0 {
|
||||
after := localPath[i+1:]
|
||||
if reference.TagRegexp.MatchString(after) {
|
||||
localPath, tag = localPath[:i], after
|
||||
}
|
||||
}
|
||||
|
||||
if tag == "" {
|
||||
tag = "latest"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/docker/buildx/util/buildflags"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -38,3 +39,45 @@ func TestCacheOptions_DerivedVars(t *testing.T) {
|
||||
},
|
||||
}, CreateCaches(cacheFrom))
|
||||
}
|
||||
|
||||
func TestParseOCILayoutPath(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
s string
|
||||
path string
|
||||
dgst string
|
||||
tag string
|
||||
}{
|
||||
{
|
||||
s: "/path/to/oci/layout",
|
||||
path: "/path/to/oci/layout",
|
||||
tag: "latest",
|
||||
},
|
||||
{
|
||||
s: "/path/to/oci/layout:1.3",
|
||||
path: "/path/to/oci/layout",
|
||||
tag: "1.3",
|
||||
},
|
||||
{
|
||||
s: "/path/to/oci/layout@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
path: "/path/to/oci/layout",
|
||||
dgst: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
tag: "latest",
|
||||
},
|
||||
{
|
||||
s: "/path/to/oci/@/layout@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
path: "/path/to/oci/@/layout",
|
||||
dgst: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
tag: "latest",
|
||||
},
|
||||
{
|
||||
s: "/path/to/oci/@/layout",
|
||||
path: "/path/to/oci/@/layout",
|
||||
tag: "latest",
|
||||
},
|
||||
} {
|
||||
path, dgst, tag := parseOCILayoutPath(tt.s)
|
||||
assert.Equal(t, tt.path, path, "comparing path: %s", tt.s)
|
||||
assert.Equal(t, tt.dgst, dgst, "comparing digest: %s", tt.s)
|
||||
assert.Equal(t, tt.tag, tag, "comparing tag: %s", tt.s)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user