10 "github.com/docker/docker/builder"
11 "github.com/docker/docker/pkg/pools"
12 "github.com/pkg/errors"
15 // NewLazySource creates a new LazyContext. LazyContext defines a hashed build
16 // context based on a root directory. Individual files are hashed first time
17 // they are asked. It is not safe to call methods of LazyContext concurrently.
18 func NewLazySource(root string) (builder.Source, error) {
21 sums: make(map[string]string),
25 type lazySource struct {
27 sums map[string]string
30 func (c *lazySource) Root() string {
34 func (c *lazySource) Close() error {
38 func (c *lazySource) Hash(path string) (string, error) {
39 cleanPath, fullPath, err := normalize(path, c.root)
44 fi, err := os.Lstat(fullPath)
46 return "", errors.WithStack(err)
49 relPath, err := Rel(c.root, fullPath)
51 return "", errors.WithStack(convertPathError(err, cleanPath))
54 sum, ok := c.sums[relPath]
56 sum, err = c.prepareHash(relPath, fi)
65 func (c *lazySource) prepareHash(relPath string, fi os.FileInfo) (string, error) {
66 p := filepath.Join(c.root, relPath)
67 h, err := NewFileHash(p, relPath, fi)
69 return "", errors.Wrapf(err, "failed to create hash for %s", relPath)
71 if fi.Mode().IsRegular() && fi.Size() > 0 {
74 return "", errors.Wrapf(err, "failed to open %s", relPath)
77 if _, err := pools.Copy(h, f); err != nil {
78 return "", errors.Wrapf(err, "failed to copy file data for %s", relPath)
81 sum := hex.EncodeToString(h.Sum(nil))
86 // Rel makes a path relative to base path. Same as `filepath.Rel` but can also
87 // handle UUID paths in windows.
88 func Rel(basepath, targpath string) (string, error) {
89 // filepath.Rel can't handle UUID paths in windows
90 if runtime.GOOS == "windows" {
92 if strings.HasPrefix(targpath, pfx) {
93 p := strings.TrimPrefix(targpath, pfx)
100 return filepath.Rel(basepath, targpath)