Skip to content

Commit bd5f92d

Browse files
committed
Remove CopyOnBuild from the daemon.
Add CreateImage() to the daemon Refactor daemon.Comit() and expose a Image.NewChild() Update copy to use IDMappings. Signed-off-by: Daniel Nephin <[email protected]>
1 parent 274cc09 commit bd5f92d

16 files changed

+334
-225
lines changed

builder/builder.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import (
1111
"github.com/docker/docker/api/types/backend"
1212
"github.com/docker/docker/api/types/container"
1313
containerpkg "github.com/docker/docker/container"
14+
"github.com/docker/docker/image"
15+
"github.com/docker/docker/layer"
16+
"github.com/docker/docker/pkg/idtools"
1417
"golang.org/x/net/context"
1518
)
1619

@@ -42,11 +45,9 @@ type Backend interface {
4245
// ContainerCreateWorkdir creates the workdir
4346
ContainerCreateWorkdir(containerID string) error
4447

45-
// ContainerCopy copies/extracts a source FileInfo to a destination path inside a container
46-
// specified by a container object.
47-
// TODO: extract in the builder instead of passing `decompress`
48-
// TODO: use containerd/fs.changestream instead as a source
49-
CopyOnBuild(containerID string, destPath string, srcRoot string, srcPath string, decompress bool) error
48+
CreateImage(config []byte, parent string) (string, error)
49+
50+
IDMappings() *idtools.IDMappings
5051

5152
ImageCacheBuilder
5253
}
@@ -96,10 +97,13 @@ type ImageCache interface {
9697
type Image interface {
9798
ImageID() string
9899
RunConfig() *container.Config
100+
MarshalJSON() ([]byte, error)
101+
NewChild(child image.ChildConfig) *image.Image
99102
}
100103

101104
// ReleaseableLayer is an image layer that can be mounted and released
102105
type ReleaseableLayer interface {
103106
Release() error
104107
Mount() (string, error)
108+
DiffID() layer.DiffID
105109
}

builder/dockerfile/builder.go

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
"github.com/docker/docker/builder/dockerfile/command"
1616
"github.com/docker/docker/builder/dockerfile/parser"
1717
"github.com/docker/docker/builder/remotecontext"
18+
"github.com/docker/docker/pkg/archive"
19+
"github.com/docker/docker/pkg/chrootarchive"
1820
"github.com/docker/docker/pkg/streamformatter"
1921
"github.com/docker/docker/pkg/stringid"
2022
"github.com/pkg/errors"
@@ -98,6 +100,7 @@ type Builder struct {
98100
docker builder.Backend
99101
clientCtx context.Context
100102

103+
archiver *archive.Archiver
101104
buildStages *buildStages
102105
disableCommit bool
103106
buildArgs *buildArgs
@@ -121,6 +124,7 @@ func newBuilder(clientCtx context.Context, options builderOptions) *Builder {
121124
Aux: options.ProgressWriter.AuxFormatter,
122125
Output: options.ProgressWriter.Output,
123126
docker: options.Backend,
127+
archiver: chrootarchive.NewArchiver(options.Backend.IDMappings()),
124128
buildArgs: newBuildArgs(config.BuildArgs),
125129
buildStages: newBuildStages(),
126130
imageSources: newImageSources(clientCtx, options),

builder/dockerfile/copy.go

+57
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ import (
1313

1414
"github.com/docker/docker/builder"
1515
"github.com/docker/docker/builder/remotecontext"
16+
"github.com/docker/docker/pkg/archive"
17+
"github.com/docker/docker/pkg/idtools"
1618
"github.com/docker/docker/pkg/ioutils"
1719
"github.com/docker/docker/pkg/progress"
1820
"github.com/docker/docker/pkg/streamformatter"
21+
"github.com/docker/docker/pkg/symlink"
1922
"github.com/docker/docker/pkg/system"
2023
"github.com/docker/docker/pkg/urlutil"
2124
"github.com/pkg/errors"
@@ -34,6 +37,10 @@ type copyInfo struct {
3437
hash string
3538
}
3639

40+
func (c copyInfo) fullPath() (string, error) {
41+
return symlink.FollowSymlinkInScope(filepath.Join(c.root, c.path), c.root)
42+
}
43+
3744
func newCopyInfoFromSource(source builder.Source, path string, hash string) copyInfo {
3845
return copyInfo{root: source.Root(), path: path, hash: hash}
3946
}
@@ -355,3 +362,53 @@ func downloadSource(output io.Writer, stdout io.Writer, srcURL string) (remote b
355362
lc, err := remotecontext.NewLazyContext(tmpDir)
356363
return lc, filename, err
357364
}
365+
366+
type copyFileOptions struct {
367+
decompress bool
368+
archiver *archive.Archiver
369+
}
370+
371+
func copyFile(dest copyInfo, source copyInfo, options copyFileOptions) error {
372+
srcPath, err := source.fullPath()
373+
if err != nil {
374+
return err
375+
}
376+
destPath, err := dest.fullPath()
377+
if err != nil {
378+
return err
379+
}
380+
381+
archiver := options.archiver
382+
rootIDs := archiver.IDMappings.RootPair()
383+
384+
src, err := os.Stat(srcPath)
385+
if err != nil {
386+
return err // TODO: errors.Wrapf
387+
}
388+
if src.IsDir() {
389+
if err := archiver.CopyWithTar(srcPath, destPath); err != nil {
390+
return err
391+
}
392+
return fixPermissions(srcPath, destPath, rootIDs)
393+
}
394+
395+
if options.decompress && archive.IsArchivePath(srcPath) {
396+
// To support the untar feature we need to clean up the path a little bit
397+
// because tar is not very forgiving
398+
tarDest := dest.path
399+
// TODO: could this be just TrimSuffix()?
400+
if strings.HasSuffix(tarDest, string(os.PathSeparator)) {
401+
tarDest = filepath.Dir(dest.path)
402+
}
403+
return archiver.UntarPath(srcPath, tarDest)
404+
}
405+
406+
if err := idtools.MkdirAllAndChownNew(filepath.Dir(destPath), 0755, rootIDs); err != nil {
407+
return err
408+
}
409+
if err := archiver.CopyFileWithTar(srcPath, destPath); err != nil {
410+
return err
411+
}
412+
// TODO: do I have to change destPath to the filename?
413+
return fixPermissions(srcPath, destPath, rootIDs)
414+
}

builder/dockerfile/copy_unix.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package dockerfile
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
7+
"github.com/docker/docker/pkg/idtools"
8+
)
9+
10+
func pathExists(path string) (bool, error) {
11+
_, err := os.Stat(path)
12+
switch {
13+
case err == nil:
14+
return true, nil
15+
case os.IsNotExist(err):
16+
return false, nil
17+
}
18+
return false, err
19+
}
20+
21+
// TODO: review this
22+
func fixPermissions(source, destination string, rootIDs idtools.IDPair) error {
23+
doChownDestination, err := chownDestinationRoot(destination)
24+
if err != nil {
25+
return err
26+
}
27+
28+
// We Walk on the source rather than on the destination because we don't
29+
// want to change permissions on things we haven't created or modified.
30+
return filepath.Walk(source, func(fullpath string, info os.FileInfo, err error) error {
31+
// Do not alter the walk root iff. it existed before, as it doesn't fall under
32+
// the domain of "things we should chown".
33+
if !doChownDestination && (source == fullpath) {
34+
return nil
35+
}
36+
37+
// Path is prefixed by source: substitute with destination instead.
38+
cleaned, err := filepath.Rel(source, fullpath)
39+
if err != nil {
40+
return err
41+
}
42+
43+
fullpath = filepath.Join(destination, cleaned)
44+
return os.Lchown(fullpath, rootIDs.UID, rootIDs.GID)
45+
})
46+
}
47+
48+
// If the destination didn't already exist, or the destination isn't a
49+
// directory, then we should Lchown the destination. Otherwise, we shouldn't
50+
// Lchown the destination.
51+
func chownDestinationRoot(destination string) (bool, error) {
52+
destExists, err := pathExists(destination)
53+
if err != nil {
54+
return false, err
55+
}
56+
destStat, err := os.Stat(destination)
57+
if err != nil {
58+
// This should *never* be reached, because the destination must've already
59+
// been created while untar-ing the context.
60+
return false, err
61+
}
62+
63+
return !destExists || !destStat.IsDir(), nil
64+
}

builder/dockerfile/copy_windows.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package dockerfile
2+
3+
import "github.com/docker/docker/pkg/idtools"
4+
5+
func fixPermissions(source, destination string, rootIDs idtools.IDPair) error {
6+
// chown is not supported on Windows
7+
return nil
8+
}

builder/dockerfile/dispatchers.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/docker/docker/api/types/strslice"
2424
"github.com/docker/docker/builder"
2525
"github.com/docker/docker/builder/dockerfile/parser"
26+
"github.com/docker/docker/image"
2627
"github.com/docker/docker/pkg/jsonmessage"
2728
"github.com/docker/docker/pkg/signal"
2829
"github.com/docker/go-connections/nat"
@@ -251,10 +252,8 @@ func parseBuildStageName(args []string) (string, error) {
251252
return stageName, nil
252253
}
253254

254-
// scratchImage is used as a token for the empty base image. It uses buildStage
255-
// as a convenient implementation of builder.Image, but is not actually a
256-
// buildStage.
257-
var scratchImage builder.Image = &buildStage{}
255+
// scratchImage is used as a token for the empty base image.
256+
var scratchImage builder.Image = &image.Image{}
258257

259258
func (b *Builder) getFromImage(shlex *ShellLex, name string) (builder.Image, error) {
260259
substitutionArgs := []string{}
@@ -267,8 +266,8 @@ func (b *Builder) getFromImage(shlex *ShellLex, name string) (builder.Image, err
267266
return nil, err
268267
}
269268

270-
if im, ok := b.buildStages.getByName(name); ok {
271-
return im, nil
269+
if stage, ok := b.buildStages.getByName(name); ok {
270+
name = stage.ImageID()
272271
}
273272

274273
// Windows cannot support a container with no base image.

builder/dockerfile/imagecontext.go

+14-18
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,29 @@ import (
66

77
"github.com/Sirupsen/logrus"
88
"github.com/docker/docker/api/types/backend"
9-
"github.com/docker/docker/api/types/container"
109
"github.com/docker/docker/builder"
1110
"github.com/docker/docker/builder/remotecontext"
11+
"github.com/docker/docker/layer"
1212
"github.com/pkg/errors"
1313
"golang.org/x/net/context"
1414
)
1515

1616
type buildStage struct {
17-
id string
18-
config *container.Config
17+
id string
1918
}
2019

21-
func newBuildStageFromImage(image builder.Image) *buildStage {
22-
return &buildStage{id: image.ImageID(), config: image.RunConfig()}
20+
func newBuildStage(imageID string) *buildStage {
21+
return &buildStage{id: imageID}
2322
}
2423

2524
func (b *buildStage) ImageID() string {
2625
return b.id
2726
}
2827

29-
func (b *buildStage) RunConfig() *container.Config {
30-
return b.config
31-
}
32-
33-
func (b *buildStage) update(imageID string, runConfig *container.Config) {
28+
func (b *buildStage) update(imageID string) {
3429
b.id = imageID
35-
b.config = runConfig
3630
}
3731

38-
var _ builder.Image = &buildStage{}
39-
4032
// buildStages tracks each stage of a build so they can be retrieved by index
4133
// or by name.
4234
type buildStages struct {
@@ -48,12 +40,12 @@ func newBuildStages() *buildStages {
4840
return &buildStages{byName: make(map[string]*buildStage)}
4941
}
5042

51-
func (s *buildStages) getByName(name string) (builder.Image, bool) {
43+
func (s *buildStages) getByName(name string) (*buildStage, bool) {
5244
stage, ok := s.byName[strings.ToLower(name)]
5345
return stage, ok
5446
}
5547

56-
func (s *buildStages) get(indexOrName string) (builder.Image, error) {
48+
func (s *buildStages) get(indexOrName string) (*buildStage, error) {
5749
index, err := strconv.Atoi(indexOrName)
5850
if err == nil {
5951
if err := s.validateIndex(index); err != nil {
@@ -78,7 +70,7 @@ func (s *buildStages) validateIndex(i int) error {
7870
}
7971

8072
func (s *buildStages) add(name string, image builder.Image) error {
81-
stage := newBuildStageFromImage(image)
73+
stage := newBuildStage(image.ImageID())
8274
name = strings.ToLower(name)
8375
if len(name) > 0 {
8476
if _, ok := s.byName[name]; ok {
@@ -90,8 +82,8 @@ func (s *buildStages) add(name string, image builder.Image) error {
9082
return nil
9183
}
9284

93-
func (s *buildStages) update(imageID string, runConfig *container.Config) {
94-
s.sequence[len(s.sequence)-1].update(imageID, runConfig)
85+
func (s *buildStages) update(imageID string) {
86+
s.sequence[len(s.sequence)-1].update(imageID)
9587
}
9688

9789
type getAndMountFunc func(string) (builder.Image, builder.ReleaseableLayer, error)
@@ -190,3 +182,7 @@ func (im *imageMount) Image() builder.Image {
190182
func (im *imageMount) ImageID() string {
191183
return im.image.ImageID()
192184
}
185+
186+
func (im *imageMount) DiffID() layer.DiffID {
187+
return im.layer.DiffID()
188+
}

0 commit comments

Comments
 (0)