Skip to content

Commit

Permalink
Dockerfile frontend: expose exclude keyword to ADD and COPY commands
Browse files Browse the repository at this point in the history
It exposes the `ExcludePatterns` to the Dockerfile frontend, adding
`--exclude=<pattern>` option in the COPY and ADD commands, which will
cause filepaths matching such patterns not to be copied.

`--exclude` can be used multiple times.

References moby#4439

Signed-off-by: Leandro Santiago <[email protected]>
  • Loading branch information
leandrosansilva committed Feb 15, 2024
1 parent 331b5d5 commit 42a0c9c
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 43 deletions.
79 changes: 46 additions & 33 deletions frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -744,17 +744,18 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
}
if err == nil {
err = dispatchCopy(d, copyConfig{
params: c.SourcesAndDest,
source: opt.buildContext,
isAddCommand: true,
cmdToPrint: c,
chown: c.Chown,
chmod: c.Chmod,
link: c.Link,
keepGitDir: c.KeepGitDir,
checksum: checksum,
location: c.Location(),
opt: opt,
params: c.SourcesAndDest,
excludePatterns: c.ExcludePatterns,
source: opt.buildContext,
isAddCommand: true,
cmdToPrint: c,
chown: c.Chown,
chmod: c.Chmod,
link: c.Link,
keepGitDir: c.KeepGitDir,
checksum: checksum,
location: c.Location(),
opt: opt,
})
}
if err == nil {
Expand Down Expand Up @@ -796,16 +797,17 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
l = src.state
}
err = dispatchCopy(d, copyConfig{
params: c.SourcesAndDest,
source: l,
isAddCommand: false,
cmdToPrint: c,
chown: c.Chown,
chmod: c.Chmod,
link: c.Link,
parents: c.Parents,
location: c.Location(),
opt: opt,
params: c.SourcesAndDest,
excludePatterns: c.ExcludePatterns,
source: l,
isAddCommand: false,
cmdToPrint: c,
chown: c.Chown,
chmod: c.Chmod,
link: c.Link,
parents: c.Parents,
location: c.Location(),
opt: opt,
})
if err == nil {
if len(cmd.sources) == 0 {
Expand Down Expand Up @@ -1112,6 +1114,14 @@ func dispatchWorkdir(d *dispatchState, c *instructions.WorkdirCommand, commit bo
return nil
}

type excludeOnCopy struct {
patterns []string
}

func (e *excludeOnCopy) SetCopyOption(i *llb.CopyInfo) {
i.ExcludePatterns = append(i.ExcludePatterns, e.patterns...)
}

func dispatchCopy(d *dispatchState, cfg copyConfig) error {
dest, err := pathRelativeToWorkingDir(d.state, cfg.params.DestPath, *d.platform)
if err != nil {
Expand All @@ -1128,6 +1138,8 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error {
copyOpt = append(copyOpt, llb.WithUser(cfg.chown))
}

copyOpt = append(copyOpt, &excludeOnCopy{cfg.excludePatterns})

var mode *os.FileMode
if cfg.chmod != "" {
p, err := strconv.ParseUint(cfg.chmod, 8, 32)
Expand Down Expand Up @@ -1329,18 +1341,19 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error {
}

type copyConfig struct {
params instructions.SourcesAndDest
source llb.State
isAddCommand bool
cmdToPrint fmt.Stringer
chown string
chmod string
link bool
keepGitDir bool
checksum digest.Digest
parents bool
location []parser.Range
opt dispatchOpt
params instructions.SourcesAndDest
excludePatterns []string
source llb.State
isAddCommand bool
cmdToPrint fmt.Stringer
chown string
chmod string
link bool
keepGitDir bool
checksum digest.Digest
parents bool
location []parser.Range
opt dispatchOpt
}

func dispatchMaintainer(d *dispatchState, c *instructions.MaintainerCommand) error {
Expand Down
16 changes: 16 additions & 0 deletions frontend/dockerfile/dockerfile2llb/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,19 @@ COPY --from=stage1 f2 /sub/
_, _, _, err = Dockerfile2LLB(appcontext.Context(), []byte(df), ConvertOpt{})
assert.EqualError(t, err, "circular dependency detected on stage: stage0")
}

func TestDockerfileCopyExcludePatterns(t *testing.T) {
df := `FROM scratch
COPY --exclude=src/*.go --exclude=tmp/*.txt dir /sub/
`
_, _, _, err := Dockerfile2LLB(appcontext.Context(), []byte(df), ConvertOpt{})
assert.NoError(t, err)
}

func TestDockerfileAddExcludePatterns(t *testing.T) {
df := `FROM scratch
ADD --exclude=src/*.go --exclude=tmp/*.txt dir /sub/
`
_, _, _, err := Dockerfile2LLB(appcontext.Context(), []byte(df), ConvertOpt{})
assert.NoError(t, err)
}
22 changes: 12 additions & 10 deletions frontend/dockerfile/instructions/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,12 @@ func (s *SourcesAndDest) ExpandRaw(expander SingleWordExpander) error {
type AddCommand struct {
withNameAndCode
SourcesAndDest
Chown string
Chmod string
Link bool
KeepGitDir bool // whether to keep .git dir, only meaningful for git sources
Checksum string
Chown string
Chmod string
Link bool
ExcludePatterns []string
KeepGitDir bool // whether to keep .git dir, only meaningful for git sources
Checksum string
}

func (c *AddCommand) Expand(expander SingleWordExpander) error {
Expand All @@ -270,11 +271,12 @@ func (c *AddCommand) Expand(expander SingleWordExpander) error {
type CopyCommand struct {
withNameAndCode
SourcesAndDest
From string
Chown string
Chmod string
Link bool
Parents bool // parents preserves directory structure
From string
Chown string
Chmod string
Link bool
ExcludePatterns []string
Parents bool // parents preserves directory structure
}

func (c *CopyCommand) Expand(expander SingleWordExpander) error {
Expand Down
6 changes: 6 additions & 0 deletions frontend/dockerfile/instructions/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ func parseAdd(req parseRequest) (*AddCommand, error) {
if len(req.args) < 2 {
return nil, errNoDestinationArgument("ADD")
}

flExcludes := req.flags.AddStrings("exclude")
flChown := req.flags.AddString("chown", "")
flChmod := req.flags.AddString("chmod", "")
flLink := req.flags.AddBool("link", false)
Expand All @@ -306,13 +308,16 @@ func parseAdd(req parseRequest) (*AddCommand, error) {
Link: flLink.Value == "true",
KeepGitDir: flKeepGitDir.Value == "true",
Checksum: flChecksum.Value,
ExcludePatterns: flExcludes.StringValues,
}, nil
}

func parseCopy(req parseRequest) (*CopyCommand, error) {
if len(req.args) < 2 {
return nil, errNoDestinationArgument("COPY")
}

flExcludes := req.flags.AddStrings("exclude")
flChown := req.flags.AddString("chown", "")
flFrom := req.flags.AddString("from", "")
flChmod := req.flags.AddString("chmod", "")
Expand All @@ -335,6 +340,7 @@ func parseCopy(req parseRequest) (*CopyCommand, error) {
Chmod: flChmod.Value,
Link: flLink.Value == "true",
Parents: (flParents.Value == "true") && parentsEnabled, // silently ignore if not -labs
ExcludePatterns: flExcludes.StringValues,
}, nil
}

Expand Down

0 comments on commit 42a0c9c

Please sign in to comment.