diff --git a/build/build.go b/build/build.go
index 58b75141..d2a108b5 100644
--- a/build/build.go
+++ b/build/build.go
@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"os"
+ "path"
"path/filepath"
"strconv"
"strings"
@@ -36,8 +37,10 @@ import (
"github.com/docker/docker/pkg/jsonmessage"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb"
+ "github.com/moby/buildkit/client/ociindex"
"github.com/moby/buildkit/exporter/containerimage/exptypes"
gateway "github.com/moby/buildkit/frontend/gateway/client"
+ "github.com/moby/buildkit/identity"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/upload/uploadprovider"
"github.com/moby/buildkit/solver/errdefs"
@@ -1497,26 +1500,59 @@ func LoadInputs(ctx context.Context, d driver.Driver, inp Inputs, pw progress.Wr
// handle OCI layout
if strings.HasPrefix(v.Path, "oci-layout://") {
pathAlone := strings.TrimPrefix(v.Path, "oci-layout://")
- parts := strings.SplitN(pathAlone, "@", 2)
- if len(parts) != 2 {
- return nil, errors.Errorf("invalid oci-layout context %s, must be oci-layout:///path/to/layout@sha256:hash", v.Path)
+ localPath := pathAlone
+ localPath, dig, hasDigest := strings.Cut(localPath, "@")
+ localPath, tag, hasTag := strings.Cut(localPath, ":")
+ if !hasDigest {
+ indexPath := path.Join(localPath, "index.json")
+ index, err := ociindex.ReadIndexJSONFileLocked(indexPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to read oci-layout index at %s", indexPath)
+ }
+
+ if len(index.Manifests) == 1 {
+ dig = string(index.Manifests[0].Digest)
+ hasDigest = true
+ }
+
+ if !hasTag {
+ tag = "latest"
+ }
+ for _, m := range index.Manifests {
+ if m.Annotations[specs.AnnotationRefName] == tag {
+ dig = string(m.Digest)
+ hasDigest = true
+ break
+ }
+ }
+ }
+ if !hasDigest {
+ return nil, errors.Errorf("oci-layout reference %q could not be resolved", v.Path)
}
- localPath := parts[0]
- dgst, err := digest.Parse(parts[1])
+ _, err := digest.Parse(dig)
if err != nil {
- return nil, errors.Wrapf(err, "invalid oci-layout context %s, does not have proper hash, must be oci-layout:///path/to/layout@sha256:hash", v.Path)
+ return nil, errors.Wrapf(err, "invalid oci-layout digest %s", dig)
}
+
store, err := local.NewStore(localPath)
if err != nil {
return nil, errors.Wrapf(err, "invalid store at %s", localPath)
}
- // now we can add it
+ storeName := identity.NewID()
if target.OCIStores == nil {
target.OCIStores = map[string]content.Store{}
}
- target.OCIStores[k] = store
+ target.OCIStores[storeName] = store
+
+ layout := "oci-layout://" + storeName
+ if hasTag {
+ layout += ":" + tag
+ }
+ if hasDigest {
+ layout += "@" + dig
+ }
- target.FrontendAttrs["context:"+k] = fmt.Sprintf("oci-layout:%s@%s", k, dgst.String())
+ target.FrontendAttrs["context:"+k] = layout
continue
}
st, err := os.Stat(v.Path)
diff --git a/docs/reference/buildx_build.md b/docs/reference/buildx_build.md
index 020e4535..b26154dc 100644
--- a/docs/reference/buildx_build.md
+++ b/docs/reference/buildx_build.md
@@ -139,10 +139,12 @@ COPY --from=project myfile /
#### Source image from OCI layout directory
-Source an image from a local [OCI layout compliant directory](https://github.com/opencontainers/image-spec/blob/main/image-layout.md):
+Source an image from a local [OCI layout compliant directory](https://github.com/opencontainers/image-spec/blob/main/image-layout.md),
+either by tag, or by digest:
```console
-$ docker buildx build --build-context foo=oci-layout:///path/to/local/layout@sha256:abcd12345 .
+$ docker buildx build --build-context foo=oci-layout:///path/to/local/layout:
+$ docker buildx build --build-context foo=oci-layout:///path/to/local/layout@sha256:
```
```dockerfile
@@ -154,14 +156,8 @@ COPY --from=foo myfile /
FROM foo
```
-The OCI layout directory must be compliant with the [OCI layout specification](https://github.com/opencontainers/image-spec/blob/main/image-layout.md). It looks _solely_ for hashes. It does not
-do any form of `image:tag` resolution to find the hash of the manifest; that is up to you.
-
-The format of the `--build-context` must be: `=oci-layout://@sha256:`, where:
-
-* `context` is the name of the build context as used in the `Dockerfile`.
-* `path-to-local-layout` is the path on the local machine, where you are running `docker build`, to the spec-compliant OCI layout.
-* `hash-of-manifest` is the hash of the manifest for the image. It can be a single-architecture manifest or a multi-architecture index.
+The OCI layout directory must be compliant with the [OCI layout specification](https://github.com/opencontainers/image-spec/blob/main/image-layout.md).
+You can reference an image in the layout using either tags, or the exact digest.
### Override the configured builder instance (--builder)