From ebf2bec98b15e62349583054c34bac243a254c22 Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 13:04:54 +0200 Subject: [PATCH 01/10] format and add builkit --- flake.nix | 56 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/flake.nix b/flake.nix index 9b1e658..3951c28 100644 --- a/flake.nix +++ b/flake.nix @@ -3,36 +3,52 @@ inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1.*.tar.gz"; - outputs = { self, nixpkgs }: + outputs = + { self, nixpkgs }: let goVersion = 22; # Change this to update the whole stack - supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; - forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f { - pkgs = import nixpkgs { - inherit system; - overlays = [ self.overlays.default ]; - }; - }); + supportedSystems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + forEachSupportedSystem = + f: + nixpkgs.lib.genAttrs supportedSystems ( + system: + f { + pkgs = import nixpkgs { + inherit system; + overlays = [ self.overlays.default ]; + }; + } + ); in { overlays.default = final: prev: { go = final."go_1_${toString goVersion}"; }; - devShells = forEachSupportedSystem ({ pkgs }: { - default = pkgs.mkShell { - packages = with pkgs; [ - # go (version is specified by overlay) - go + devShells = forEachSupportedSystem ( + { pkgs }: + { + default = pkgs.mkShell { + packages = with pkgs; [ + # go (version is specified by overlay) + go - # goimports, godoc, etc. - gotools gopls + buildkit + # goimports, godoc, etc. + gotools + gopls - # https://github.com/golangci/golangci-lint - golangci-lint - ]; - }; - }); + # https://github.com/golangci/golangci-lint + golangci-lint + ]; + }; + } + ); }; } From 0064a96340bb3fe06cce59488a98af2239acdafc Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 13:05:29 +0200 Subject: [PATCH 02/10] use dockerspec instead of opencontainers --- internal/parser/jockerfile.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/parser/jockerfile.go b/internal/parser/jockerfile.go index 2d37293..83effbf 100644 --- a/internal/parser/jockerfile.go +++ b/internal/parser/jockerfile.go @@ -2,8 +2,8 @@ package parser import ( "encoding/json" - - specs "github.com/opencontainers/image-spec/specs-go/v1" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" + // specs "github.com/opencontainers/image-spec/specs-go/v1" ) type ArgStep struct { @@ -37,7 +37,8 @@ type BuildStage struct { type Jockerfile struct { Stages []BuildStage `json:"stages"` - Image specs.ImageConfig `json:"image"` + Image dockerspec.DockerOCIImage + // Image specs.ImageConfig `json:"image"` Excludes []string `json:"excludes,omitempty"` } From 1643c9b1da849f7c248986e76e970b1fd4edf6bc Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 13:06:22 +0200 Subject: [PATCH 03/10] inject echo into LLB for debugging. resolve FROM image Inherit Image.Config from the Base Image --- internal/parser/llb.go | 87 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/internal/parser/llb.go b/internal/parser/llb.go index 7356eea..4ebbe01 100644 --- a/internal/parser/llb.go +++ b/internal/parser/llb.go @@ -1,22 +1,51 @@ package parser import ( + "context" + "encoding/json" "fmt" - "log" + "log/slog" + "strings" "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/client/llb/imagemetaresolver" + "github.com/moby/buildkit/client/llb/sourceresolver" + // specs "github.com/opencontainers/image-spec/specs-go/v1" + dockerspec "github.com/moby/docker-image-spec/specs-go/v1" ) type BuildContext struct { stages map[string]llb.State state llb.State context llb.State + debug string + ctx context.Context + // image specs.ImageConfig + image dockerspec.DockerOCIImage } type BuildStep interface { Evaluate(*BuildContext) llb.State } +func parseKeyValue(env string) (string, string) { + parts := strings.SplitN(env, "=", 2) + v := "" + if len(parts) > 1 { + v = parts[1] + } + + return parts[0], v +} + +// debugLog conditionally logs a debug message and injects an echo command into the LLB state. +func debugLog(b *BuildContext, msg string) { + if b.debug == "all" { + slog.Warn("Step: ", "buildctx", msg) + b.state = b.state.Run(shf("echo DEBUG " + msg)).Root() + } +} + func (c *ArgStep) Evaluate(b *BuildContext) llb.State { b.state = b.state.AddEnv(c.Name, c.Value) return b.state @@ -49,11 +78,14 @@ func (c *RunStep) Evaluate(b *BuildContext) llb.State { return b.state } + debugLog(b, c.Command) + b.state = b.state.Run(shf(c.Command)).Root() return b.state } func (c *WorkdirStep) Evaluate(b *BuildContext) llb.State { + debugLog(b, c.Path) b.state = b.state.Dir(c.Path) return b.state } @@ -71,20 +103,59 @@ func (stage *BuildStage) ToLLB(b *BuildContext) llb.State { if stage.From == "scratch" { b.state = llb.Scratch() } else { + metaresolver := imagemetaresolver.Default() + _, _, dt, err := metaresolver.ResolveImageConfig(b.ctx, "docker.io/library/" + stage.From, sourceresolver.Opt{ + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: llb.ResolveModeDefault.String(), + }, + }) + + if err != nil { + debugLog(b, "failed to resolve image") + slog.Error("failed to resolve image", "FROM", err) + } + + // var img specs.ImageConfig + var img dockerspec.DockerOCIImage + if err := json.Unmarshal(dt, &img); err != nil { + debugLog(b, "failed to unmarshal image") + slog.Error("failed to unmarshal image", "FROM", err) + } + + debugLog(b, string(dt)) + b.state = llb.Image(stage.From) + + b.image = img + + debugLog(b, b.image.Config.WorkingDir) + debugLog(b, img.Config.WorkingDir) + // This checks that the envs are set + for _, env := range img.Config.Env { + debugLog(b, env) + k, v := parseKeyValue(env) + b.state = b.state.AddEnv(k, v) + } + + // b.state, err = llb.Image(stage.From).WithImageConfig(dt) + if err != nil { + slog.Error("failed to insert config in image", "FROM", err) + } } for i := range *stage.Steps { - log.Printf("building stage %#v\n", (*stage.Steps)[i]) + slog.Info("Building steps", "stage", (*stage.Steps)[i]) b.state = (*stage.Steps)[i].Evaluate(b) } return b.state } -func (j *Jockerfile) ToLLB() llb.State { +func (j *Jockerfile) ToLLB(debug string, ctx context.Context) llb.State { b := BuildContext{ stages: make(map[string]llb.State), + debug: debug, + ctx: ctx, } var state llb.State opts := []llb.LocalOption{ @@ -94,11 +165,17 @@ func (j *Jockerfile) ToLLB() llb.State { b.context = llb.Local("context", opts...) for _, stage := range j.Stages { - log.Println("building stage", stage.Name) - + slog.Info("Building stage", "ctx", stage.Name) state = stage.ToLLB(&b) b.stages[stage.Name] = state } + // after all stages align the imageConfig to export + slog.Info("setting image config") + slog.Info(b.image.Config.WorkingDir) + j.Image = b.image + + slog.Info(j.Image.Config.WorkingDir) + return state } From a3a1fb6478981d86020d595b8b9db0c489380ca6 Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 13:07:06 +0200 Subject: [PATCH 04/10] draft inheriting image conf --- Jockerfile | 48 +++++++++++++++++++------------------- cmd/jocker/debug-dump.go | 6 +---- internal/parser/builder.go | 27 ++++++++++++++------- 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/Jockerfile b/Jockerfile index 9a894ab..d800048 100644 --- a/Jockerfile +++ b/Jockerfile @@ -1,40 +1,40 @@ #syntax=ghcr.io/jocker-org/jocker -local std = import "std.libsonnet"; +// local std = import "std.libsonnet"; { "stages": [ { "name": "builder", - "from": "alpine:latest", + "from": "golang:alpine", "steps": [ - std.stage.step.workdir("/src"), - // {"type": "WORKDIR", "path": "/src"}, + // std.stage.step.workdir("/src"), + {"type": "WORKDIR", "path": "/src"}, {"type": "RUN", "command": "apk update"}, {"type": "RUN", "command": "apk upgrade"}, - {"type": "RUN", "command": "apk add mkdocs"}, - {"type": "COPY", "src": "mkdocs.yml", "dst": "/src"}, - {"type": "COPY", "src": "./docs", "dst": "/src/docs"}, - {"type": "RUN", "command": "mkdocs build"} + // {"type": "RUN", "command": "apk add mkdocs"}, + // {"type": "COPY", "src": "mkdocs.yml", "dst": "/src"}, + // {"type": "COPY", "src": "./docs", "dst": "/src/docs"}, + // {"type": "RUN", "command": "mkdocs build"} ] }, - { - "name": "server", - "from": "alpine:latest", - "steps": [ - {"type": "RUN", "command": "addgroup -g 1000 app && adduser -G app -u 1000 app -D"}, - {"type": "RUN", "command": "apk update"}, - {"type": "RUN", "command": "apk upgrade"}, - {"type": "RUN", "command": "apk add darkhttpd"}, - {"type": "COPY", "from": "builder", "src": "/src/site", "dst": "/www"}, - {"type": "USER", "user": "1000"}, - ], - }, + // { + // "name": "server", + // "from": "alpine:latest", + // "steps": [ + // {"type": "RUN", "command": "addgroup -g 1000 app && adduser -G app -u 1000 app -D"}, + // {"type": "RUN", "command": "apk update"}, + // {"type": "RUN", "command": "apk upgrade"}, + // {"type": "RUN", "command": "apk add darkhttpd"}, + // {"type": "COPY", "from": "builder", "src": "/src/site", "dst": "/www"}, + // {"type": "USER", "user": "1000"}, + // ], + // }, ], - "image": { - "Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], - "Cmd": ["darkhttpd", "/www"], - }, + // "image": { + // "Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], + // "Cmd": ["darkhttpd", "/www"], + // }, "excludes" : ["*", "!docs", "!mkdocs.yml"], } diff --git a/cmd/jocker/debug-dump.go b/cmd/jocker/debug-dump.go index 5a7a95b..85f76f9 100644 --- a/cmd/jocker/debug-dump.go +++ b/cmd/jocker/debug-dump.go @@ -14,26 +14,22 @@ func DebugDump() error { vm := jsonnet.MakeVM() vm.Importer(&jsonnet.FileImporter{JPaths: []string{"/lib/"}}) - // Initialize Jsonnet VM and evaluate Jockerfile jsonStr, err := vm.EvaluateFile("Jockerfile") if err != nil { log.Fatal(err) } - // Parse JSON into Jockerfile struct j, err := parser.ParseJockerfile(jsonStr) if err != nil { log.Fatal(err) } - // Generate LLB state from Jockerfile - state := j.ToLLB() + state := j.ToLLB("all", context.TODO()) ctx := context.TODO() dt, err := state.Marshal(ctx, llb.LinuxAmd64) if err != nil { log.Fatal(err) } - // Write LLB definition to stdout return llb.WriteTo(dt, os.Stdout) } diff --git a/internal/parser/builder.go b/internal/parser/builder.go index 3f52987..5dd543c 100644 --- a/internal/parser/builder.go +++ b/internal/parser/builder.go @@ -6,6 +6,7 @@ import ( _ "embed" "encoding/json" "fmt" + // "log" "strings" "github.com/containerd/platforms" @@ -14,7 +15,8 @@ import ( "github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/moby/buildkit/frontend/gateway/client" - specs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + // specs "github.com/opencontainers/image-spec/specs-go/v1" ) func readFile(ctx context.Context, c client.Client, filename string) (content []byte, err error) { @@ -84,7 +86,8 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { j.Excludes, _ = dockerignore.Parse(bytes.NewReader(content)) } } - state := j.ToLLB() + + state := j.ToLLB(buildargs["debug"], ctx) dt, err := state.Marshal(ctx, llb.LinuxAmd64) if err != nil { @@ -111,17 +114,23 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { userplatform, err) } } - img := &specs.Image{ - Platform: p, - Config: j.Image, - } - config, err := json.Marshal(img) + j.Image.Platform = p + j.Image.Author = "test" + // j.Image.Config = + // img := &specs.Image{ + // Platform: p, + // Config: j.Image, + // } + + config, err := json.Marshal(j.Image) + if err != nil { - return nil, fmt.Errorf("failed to marshal image config: %w", err) + return nil, errors.Wrapf(err, "failed to marshal image config") } - res.AddMeta(exptypes.ExporterImageConfigKey, config) res.SetRef(ref) + res.AddMeta(exptypes.ExporterImageConfigKey, config) + res.AddMeta(exptypes.ExporterImageBaseConfigKey, config) return res, nil } From 3d74e4113f2abb61c552dadb32660357f51166b1 Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 14:52:06 +0200 Subject: [PATCH 05/10] pass nil reference for debub-dump needed because in the build step we need to pass client.Client --- cmd/jocker/debug-dump.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/jocker/debug-dump.go b/cmd/jocker/debug-dump.go index 85f76f9..b557f31 100644 --- a/cmd/jocker/debug-dump.go +++ b/cmd/jocker/debug-dump.go @@ -23,9 +23,9 @@ func DebugDump() error { if err != nil { log.Fatal(err) } - - state := j.ToLLB("all", context.TODO()) ctx := context.TODO() + state := j.ToLLB("all", ctx, nil) + dt, err := state.Marshal(ctx, llb.LinuxAmd64) if err != nil { log.Fatal(err) From 09ceff9e4a28ef3edc63cc4738e186f4d17147c7 Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 14:52:48 +0200 Subject: [PATCH 06/10] pass client.Client (gwclient) to toLLB --- internal/parser/builder.go | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/internal/parser/builder.go b/internal/parser/builder.go index 5dd543c..3ddd132 100644 --- a/internal/parser/builder.go +++ b/internal/parser/builder.go @@ -6,7 +6,6 @@ import ( _ "embed" "encoding/json" "fmt" - // "log" "strings" "github.com/containerd/platforms" @@ -16,7 +15,6 @@ import ( "github.com/moby/buildkit/exporter/containerimage/exptypes" "github.com/moby/buildkit/frontend/gateway/client" "github.com/pkg/errors" - // specs "github.com/opencontainers/image-spec/specs-go/v1" ) func readFile(ctx context.Context, c client.Client, filename string) (content []byte, err error) { @@ -87,7 +85,8 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { } } - state := j.ToLLB(buildargs["debug"], ctx) + + state := j.ToLLB(buildargs["debug"], ctx, c) dt, err := state.Marshal(ctx, llb.LinuxAmd64) if err != nil { @@ -116,21 +115,13 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { } j.Image.Platform = p - j.Image.Author = "test" - // j.Image.Config = - // img := &specs.Image{ - // Platform: p, - // Config: j.Image, - // } config, err := json.Marshal(j.Image) - if err != nil { return nil, errors.Wrapf(err, "failed to marshal image config") } res.SetRef(ref) res.AddMeta(exptypes.ExporterImageConfigKey, config) - res.AddMeta(exptypes.ExporterImageBaseConfigKey, config) return res, nil } From 8136dba2608e32b6fae94ab578d01a6a96b8a279 Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 14:53:11 +0200 Subject: [PATCH 07/10] handle debub-dump and build image resolving using different resolvers for debug-dump allow us to resolve the image metadata both for debug-dump and docker build --- internal/parser/llb.go | 100 ++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 36 deletions(-) diff --git a/internal/parser/llb.go b/internal/parser/llb.go index 4ebbe01..b33324f 100644 --- a/internal/parser/llb.go +++ b/internal/parser/llb.go @@ -2,6 +2,7 @@ package parser import ( "context" + "crypto/rand" "encoding/json" "fmt" "log/slog" @@ -10,7 +11,9 @@ import ( "github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/client/llb/imagemetaresolver" "github.com/moby/buildkit/client/llb/sourceresolver" - // specs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/moby/buildkit/frontend/gateway/client" + + gw "github.com/moby/buildkit/frontend/gateway/client" dockerspec "github.com/moby/docker-image-spec/specs-go/v1" ) @@ -20,7 +23,6 @@ type BuildContext struct { context llb.State debug string ctx context.Context - // image specs.ImageConfig image dockerspec.DockerOCIImage } @@ -38,11 +40,35 @@ func parseKeyValue(env string) (string, string) { return parts[0], v } +// normalizeImage returns the image with the docker.io/library prefixed if it's not +// from a registry. Otherwise we can't resolve the Image Metadata +func normalizeImage(image string) string { + parts := strings.Split(image, "/") + + if len(parts) > 1 && (strings.Contains(parts[0], ".") || strings.Contains(parts[0], ":")) { + return image + } + + if len(parts) == 1 { + return "docker.io/library/" + image + } + + return "docker.io/" + image +} + // debugLog conditionally logs a debug message and injects an echo command into the LLB state. +// it also adds a random uuid for invalidating docker cache +// https://github.com/docker/buildx/issues/2387 func debugLog(b *BuildContext, msg string) { + by := make([]byte, 4) + _, err := rand.Read(by) + if err != nil { + slog.Error("error while creating unique id", "error", err) + } + uuid := fmt.Sprintf("%x ", by) if b.debug == "all" { slog.Warn("Step: ", "buildctx", msg) - b.state = b.state.Run(shf("echo DEBUG " + msg)).Root() + b.state = b.state.Run(shf("echo DEBUG " + uuid + msg)).Root() } } @@ -99,48 +125,52 @@ func shf(cmd string, v ...interface{}) llb.RunOption { return llb.Args([]string{"/bin/sh", "-c", fmt.Sprintf(cmd, v...)}) } -func (stage *BuildStage) ToLLB(b *BuildContext) llb.State { +func (stage *BuildStage) ToLLB(b *BuildContext, c client.Client) llb.State { if stage.From == "scratch" { b.state = llb.Scratch() } else { - metaresolver := imagemetaresolver.Default() - _, _, dt, err := metaresolver.ResolveImageConfig(b.ctx, "docker.io/library/" + stage.From, sourceresolver.Opt{ - ImageOpt: &sourceresolver.ResolveImageOpt{ - ResolveMode: llb.ResolveModeDefault.String(), - }, - }) - - if err != nil { - debugLog(b, "failed to resolve image") - slog.Error("failed to resolve image", "FROM", err) - } - - // var img specs.ImageConfig var img dockerspec.DockerOCIImage - if err := json.Unmarshal(dt, &img); err != nil { - debugLog(b, "failed to unmarshal image") - slog.Error("failed to unmarshal image", "FROM", err) - } - - debugLog(b, string(dt)) + baseImg := normalizeImage(stage.From) + if c == nil { + metaresolver := imagemetaresolver.Default() + _, _, dt, err := metaresolver.ResolveImageConfig(b.ctx, baseImg, sourceresolver.Opt{ + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: llb.ResolveModeDefault.String(), + }, + }) + if err != nil { + debugLog(b, "failed to resolve image") + slog.Error("failed to resolve image", "FROM", err) + } + if err := json.Unmarshal(dt, &img); err != nil { + debugLog(b, "failed to unmarshal image") + slog.Error("failed to unmarshal image", "FROM", err) + } + } else { + _, _, dt, err := gw.Client.ResolveImageConfig(c, b.ctx, baseImg, sourceresolver.Opt{ + ImageOpt: &sourceresolver.ResolveImageOpt{ + ResolveMode: llb.ResolveModeDefault.String(), + }, + }) + if err != nil { + debugLog(b, "failed to resolve image") + slog.Error("failed to resolve image", "FROM", err) + } + if err := json.Unmarshal(dt, &img); err != nil { + debugLog(b, "failed to unmarshal image") + slog.Error("failed to unmarshal image", "FROM", err) + } + } b.state = llb.Image(stage.From) - b.image = img - debugLog(b, b.image.Config.WorkingDir) - debugLog(b, img.Config.WorkingDir) - // This checks that the envs are set + // initialize metadata for _, env := range img.Config.Env { debugLog(b, env) k, v := parseKeyValue(env) b.state = b.state.AddEnv(k, v) } - - // b.state, err = llb.Image(stage.From).WithImageConfig(dt) - if err != nil { - slog.Error("failed to insert config in image", "FROM", err) - } } for i := range *stage.Steps { @@ -151,7 +181,7 @@ func (stage *BuildStage) ToLLB(b *BuildContext) llb.State { return b.state } -func (j *Jockerfile) ToLLB(debug string, ctx context.Context) llb.State { +func (j *Jockerfile) ToLLB(debug string, ctx context.Context, c client.Client) llb.State { b := BuildContext{ stages: make(map[string]llb.State), debug: debug, @@ -166,7 +196,7 @@ func (j *Jockerfile) ToLLB(debug string, ctx context.Context) llb.State { for _, stage := range j.Stages { slog.Info("Building stage", "ctx", stage.Name) - state = stage.ToLLB(&b) + state = stage.ToLLB(&b, c) b.stages[stage.Name] = state } @@ -175,7 +205,5 @@ func (j *Jockerfile) ToLLB(debug string, ctx context.Context) llb.State { slog.Info(b.image.Config.WorkingDir) j.Image = b.image - slog.Info(j.Image.Config.WorkingDir) - return state } From f69d45d09919814276b9e034384504024a4d1b45 Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 16:58:42 +0200 Subject: [PATCH 08/10] use llb.Shlex instead of costum function --- internal/parser/llb.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/parser/llb.go b/internal/parser/llb.go index b33324f..a590ff9 100644 --- a/internal/parser/llb.go +++ b/internal/parser/llb.go @@ -68,7 +68,7 @@ func debugLog(b *BuildContext, msg string) { uuid := fmt.Sprintf("%x ", by) if b.debug == "all" { slog.Warn("Step: ", "buildctx", msg) - b.state = b.state.Run(shf("echo DEBUG " + uuid + msg)).Root() + b.state = b.state.Run(llb.Shlex("echo DEBUG " + uuid + msg)).Root() } } @@ -203,6 +203,7 @@ func (j *Jockerfile) ToLLB(debug string, ctx context.Context, c client.Client) l // after all stages align the imageConfig to export slog.Info("setting image config") slog.Info(b.image.Config.WorkingDir) + j.Image = b.image return state From 6ee536e7994870aac9c1fb3d02a3a2f2f06445b6 Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 16:59:03 +0200 Subject: [PATCH 09/10] include `json:image` for overriding from jockerfile --- internal/parser/jockerfile.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/parser/jockerfile.go b/internal/parser/jockerfile.go index 83effbf..c094cf0 100644 --- a/internal/parser/jockerfile.go +++ b/internal/parser/jockerfile.go @@ -37,8 +37,7 @@ type BuildStage struct { type Jockerfile struct { Stages []BuildStage `json:"stages"` - Image dockerspec.DockerOCIImage - // Image specs.ImageConfig `json:"image"` + Image dockerspec.DockerOCIImage `json:image` Excludes []string `json:"excludes,omitempty"` } From 4440ef8d817a1173f3cf800c186cd6bf6bab5e06 Mon Sep 17 00:00:00 2001 From: heph Date: Thu, 24 Apr 2025 16:59:23 +0200 Subject: [PATCH 10/10] wip: fix path and filename issues Right now jocker can't handle Jockerfiles with different names and in different location (examples/Jockerfile.alpine for example) --- internal/parser/builder.go | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/internal/parser/builder.go b/internal/parser/builder.go index 3ddd132..004f58d 100644 --- a/internal/parser/builder.go +++ b/internal/parser/builder.go @@ -19,9 +19,15 @@ import ( func readFile(ctx context.Context, c client.Client, filename string) (content []byte, err error) { src := llb.Local("context", - llb.IncludePatterns([]string{filename}), + llb.IncludePatterns([]string{ + filename, + "**/" + filename, + "*/", + }), llb.SessionID(c.BuildOpts().SessionID), llb.SharedKeyHint("Jockerfile"), + llb.WithCustomName("load " + filename), + ) def, err := src.Marshal(ctx) @@ -60,6 +66,11 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { } } + jopts, err := json.Marshal(opts) + if err != nil { + return nil, fmt.Errorf("failed to marshal opts: %w", err) + } + jbuildargs, err := json.Marshal(buildargs) if err != nil { return nil, fmt.Errorf("failed to marshal buildargs: %w", err) @@ -67,8 +78,17 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { vm := jsonnet.MakeVM() vm.ExtCode("buildArgs", string(jbuildargs)) + vm.ExtCode("filename", fmt.Sprintf("%q",filename)) + vm.ExtCode("opts", fmt.Sprintf("%q",jopts)) vm.Importer(NewChainedImporter(NewContextImporter(ctx, c), []string{"/lib/"})) - jsonStr, err := vm.EvaluateFile(filename) + + dtJockerfile, err := readFile(ctx, c, filename) + if err != nil { + return nil, errors.Wrapf(err, "failed to read Jockerfile") + } + + // jsonStr, err := vm.EvaluateFile(filename) + jsonStr, err := vm.EvaluateAnonymousSnippet(filename, string(dtJockerfile)) if err != nil { return nil, err } @@ -85,7 +105,6 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { } } - state := j.ToLLB(buildargs["debug"], ctx, c) dt, err := state.Marshal(ctx, llb.LinuxAmd64) @@ -98,7 +117,7 @@ func Build(ctx context.Context, c client.Client) (*client.Result, error) { }) if err != nil { - return nil, fmt.Errorf("failed to resolve dockerfile: %w", err) + return nil, fmt.Errorf("failed to resolve jockerfile: %w", err) } ref, err := res.SingleRef()