github.com/containerd/nerdctl/v2@v2.0.0-beta.5.0.20240520001846-b5758f54fa28/pkg/composer/serviceparser/build.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package serviceparser 18 19 import ( 20 "errors" 21 "fmt" 22 "path/filepath" 23 "strings" 24 25 "github.com/compose-spec/compose-go/types" 26 "github.com/containerd/containerd/errdefs" 27 "github.com/containerd/containerd/identifiers" 28 "github.com/containerd/log" 29 "github.com/containerd/nerdctl/v2/pkg/reflectutil" 30 31 securejoin "github.com/cyphar/filepath-securejoin" 32 ) 33 34 func parseBuildConfig(c *types.BuildConfig, project *types.Project, imageName string) (*Build, error) { 35 if unknown := reflectutil.UnknownNonEmptyFields(c, 36 "Context", "Dockerfile", "Args", "CacheFrom", "Target", "Labels", "Secrets", 37 ); len(unknown) > 0 { 38 log.L.Warnf("Ignoring: build: %+v", unknown) 39 } 40 41 if c.Context == "" { 42 return nil, errors.New("build: context must be specified") 43 } 44 if strings.Contains(c.Context, "://") { 45 return nil, fmt.Errorf("build: URL-style context (%q) is not supported yet: %w", c.Context, errdefs.ErrNotImplemented) 46 } 47 ctxDir := project.RelativePath(c.Context) 48 49 var b Build 50 b.BuildArgs = append(b.BuildArgs, "-t="+imageName) 51 if c.Dockerfile != "" { 52 if filepath.IsAbs(c.Dockerfile) { 53 log.L.Warnf("build.dockerfile should be relative path, got %q", c.Dockerfile) 54 b.BuildArgs = append(b.BuildArgs, "-f="+c.Dockerfile) 55 } else { 56 // no need to use securejoin 57 dockerfile := filepath.Join(ctxDir, c.Dockerfile) 58 b.BuildArgs = append(b.BuildArgs, "-f="+dockerfile) 59 } 60 } 61 62 for k, v := range c.Args { 63 if v == nil { 64 b.BuildArgs = append(b.BuildArgs, "--build-arg="+k) 65 } else { 66 b.BuildArgs = append(b.BuildArgs, "--build-arg="+k+"="+*v) 67 } 68 } 69 70 for _, s := range c.CacheFrom { 71 b.BuildArgs = append(b.BuildArgs, "--cache-from="+s) 72 } 73 74 if c.Target != "" { 75 b.BuildArgs = append(b.BuildArgs, "--target="+c.Target) 76 } 77 78 if c.Labels != nil { 79 for k, v := range c.Labels { 80 b.BuildArgs = append(b.BuildArgs, "--label="+k+"="+v) 81 } 82 } 83 84 for _, s := range c.Secrets { 85 fileRef := types.FileReferenceConfig(s) 86 if err := identifiers.Validate(fileRef.Source); err != nil { 87 return nil, fmt.Errorf("secret source %q is invalid: %w", fileRef.Source, err) 88 } 89 projectSecret, ok := project.Secrets[fileRef.Source] 90 if !ok { 91 return nil, fmt.Errorf("build: secret %s is undefined", fileRef.Source) 92 } 93 var src string 94 if filepath.IsAbs(projectSecret.File) { 95 log.L.Warnf("build.secrets should be relative path, got %q", projectSecret.File) 96 src = projectSecret.File 97 } else { 98 var err error 99 src, err = securejoin.SecureJoin(ctxDir, projectSecret.File) 100 if err != nil { 101 return nil, err 102 } 103 } 104 id := fileRef.Source 105 if fileRef.Target != "" { 106 id = fileRef.Target 107 } 108 b.BuildArgs = append(b.BuildArgs, "--secret=id="+id+",src="+src) 109 } 110 111 b.BuildArgs = append(b.BuildArgs, ctxDir) 112 return &b, nil 113 }