diff --git a/frontend/mariner2/handle_container.go b/frontend/mariner2/handle_container.go index 6112aa2c..43f5c9c9 100644 --- a/frontend/mariner2/handle_container.go +++ b/frontend/mariner2/handle_container.go @@ -1,7 +1,6 @@ package mariner2 import ( - "bytes" "context" "fmt" "path/filepath" @@ -143,51 +142,11 @@ rm -rf ` + rpmdbDir + ` // The return value is the state representing the contents of the mounted directory after the commands are run rootfs := worker.AddMount(workPath, baseImg) - if post := getImagePostInstall(spec, target); post != nil && len(post.Symlinks) > 0 { + if post := spec.GetImagePost(target); post != nil && len(post.Symlinks) > 0 { rootfs = worker. - Run(dalec.WithConstraints(opts...), addImagePost(post, workPath)). + Run(dalec.WithConstraints(opts...), dalec.InstallPostSymlinks(post, workPath)). AddMount(workPath, rootfs) } return rootfs, nil } - -func getImagePostInstall(spec *dalec.Spec, targetKey string) *dalec.PostInstall { - tgt, ok := spec.Targets[targetKey] - if ok && tgt.Image != nil && tgt.Image.Post != nil { - return tgt.Image.Post - } - - if spec.Image == nil { - return nil - } - return spec.Image.Post -} - -func addImagePost(post *dalec.PostInstall, rootfsPath string) llb.RunOption { - return runOptionFunc(func(ei *llb.ExecInfo) { - if post == nil { - return - } - - if len(post.Symlinks) == 0 { - return - } - - buf := bytes.NewBuffer(nil) - buf.WriteString("set -ex\n") - fmt.Fprintf(buf, "cd %q\n", rootfsPath) - - for src, tgt := range post.Symlinks { - fmt.Fprintf(buf, "ln -s %q %q\n", src, filepath.Join(rootfsPath, tgt.Path)) - } - shArgs(buf.String()).SetRunOption(ei) - dalec.ProgressGroup("Add post-install symlinks").SetRunOption(ei) - }) -} - -type runOptionFunc func(*llb.ExecInfo) - -func (f runOptionFunc) SetRunOption(ei *llb.ExecInfo) { - f(ei) -} diff --git a/frontend/windows/handle_container.go b/frontend/windows/handle_container.go index 889d3e57..2c2d4fde 100644 --- a/frontend/windows/handle_container.go +++ b/frontend/windows/handle_container.go @@ -68,7 +68,7 @@ func handleContainer(ctx context.Context, client gwclient.Client) (*gwclient.Res out := baseImage. File(llb.Copy(bin, "/", windowsSystemDir)). - With(copySymlinks(spec.GetSymlinks(targetKey))) + With(copySymlinks(spec.GetImagePost(targetKey))) def, err := out.Marshal(ctx) if err != nil { @@ -95,8 +95,13 @@ func handleContainer(ctx context.Context, client gwclient.Client) (*gwclient.Res }) } -func copySymlinks(lm map[string]dalec.SymlinkTarget) llb.StateOption { +func copySymlinks(post *dalec.PostInstall) llb.StateOption { return func(s llb.State) llb.State { + if post == nil { + return s + } + + lm := post.Symlinks if len(lm) == 0 { return s } diff --git a/helpers.go b/helpers.go index b499982e..a784b82f 100644 --- a/helpers.go +++ b/helpers.go @@ -1,8 +1,11 @@ package dalec import ( + "bytes" "encoding/json" + "fmt" "path" + "path/filepath" "sort" "sync/atomic" @@ -304,28 +307,53 @@ func (s *Spec) GetBuildDeps(targetKey string) []string { } -func (s *Spec) GetSymlinks(target string) map[string]SymlinkTarget { - lm := make(map[string]SymlinkTarget) - - if s.Image != nil && s.Image.Post != nil && s.Image.Post.Symlinks != nil { - for k, v := range s.Image.Post.Symlinks { - lm[k] = v +func (s *Spec) GetImagePost(target string) *PostInstall { + img := s.Targets[target].Image + if img != nil { + if img.Post != nil { + return img.Post } } - tgt, ok := s.Targets[target] - if !ok { - return lm + if s.Image != nil { + return s.Image.Post } - if tgt.Image != nil && tgt.Image.Post != nil && tgt.Image.Post.Symlinks != nil { - for k, v := range tgt.Image.Post.Symlinks { - // target-specific values replace the ones in the spec toplevel - lm[k] = v + return nil +} + +// ShArgs returns a RunOption that runs the given command in a shell. +func ShArgs(args string) llb.RunOption { + return llb.Args(append([]string{"sh", "-c"}, args)) +} + +// InstallPostSymlinks returns a RunOption that adds symlinks defined in the [PostInstall] underneath the provided rootfs path. +func InstallPostSymlinks(post *PostInstall, rootfsPath string) llb.RunOption { + return runOptionFunc(func(ei *llb.ExecInfo) { + if post == nil { + return } - } - return lm + if len(post.Symlinks) == 0 { + return + } + + llb.Dir(rootfsPath).SetRunOption(ei) + + buf := bytes.NewBuffer(nil) + buf.WriteString("set -ex\n") + + for src, tgt := range post.Symlinks { + fmt.Fprintf(buf, "ln -s %q %q\n", src, filepath.Join(rootfsPath, tgt.Path)) + } + + const name = "tmp.dalec.symlink.sh" + script := llb.Scratch().File(llb.Mkfile(name, 0o400, buf.Bytes())) + + llb.AddMount(name, script, llb.SourcePath(name)).SetRunOption(ei) + llb.Args([]string{"/bin/sh", name}).SetRunOption(ei) + ProgressGroup("Add post-install symlinks").SetRunOption(ei) + }) } func (s *Spec) GetSigner(targetKey string) (*Frontend, bool) { diff --git a/test/windows_test.go b/test/windows_test.go index a6bd828f..5649ec76 100644 --- a/test/windows_test.go +++ b/test/windows_test.go @@ -221,7 +221,8 @@ echo "$BAR" > bar.txt return nil, err } - for srcPath, l := range spec.GetSymlinks("windowscross") { + post := spec.GetImagePost("windowscross") + for srcPath, l := range post.Symlinks { b1, err := ref.ReadFile(ctx, gwclient.ReadRequest{ Filename: srcPath, })