fix compile error
[platform/upstream/docker-engine.git] / builder / remotecontext / lazycontext.go
1 package remotecontext
2
3 import (
4         "encoding/hex"
5         "os"
6         "path/filepath"
7         "runtime"
8         "strings"
9
10         "github.com/docker/docker/builder"
11         "github.com/docker/docker/pkg/pools"
12         "github.com/pkg/errors"
13 )
14
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) {
19         return &lazySource{
20                 root: root,
21                 sums: make(map[string]string),
22         }, nil
23 }
24
25 type lazySource struct {
26         root string
27         sums map[string]string
28 }
29
30 func (c *lazySource) Root() string {
31         return c.root
32 }
33
34 func (c *lazySource) Close() error {
35         return nil
36 }
37
38 func (c *lazySource) Hash(path string) (string, error) {
39         cleanPath, fullPath, err := normalize(path, c.root)
40         if err != nil {
41                 return "", err
42         }
43
44         fi, err := os.Lstat(fullPath)
45         if err != nil {
46                 return "", errors.WithStack(err)
47         }
48
49         relPath, err := Rel(c.root, fullPath)
50         if err != nil {
51                 return "", errors.WithStack(convertPathError(err, cleanPath))
52         }
53
54         sum, ok := c.sums[relPath]
55         if !ok {
56                 sum, err = c.prepareHash(relPath, fi)
57                 if err != nil {
58                         return "", err
59                 }
60         }
61
62         return sum, nil
63 }
64
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)
68         if err != nil {
69                 return "", errors.Wrapf(err, "failed to create hash for %s", relPath)
70         }
71         if fi.Mode().IsRegular() && fi.Size() > 0 {
72                 f, err := os.Open(p)
73                 if err != nil {
74                         return "", errors.Wrapf(err, "failed to open %s", relPath)
75                 }
76                 defer f.Close()
77                 if _, err := pools.Copy(h, f); err != nil {
78                         return "", errors.Wrapf(err, "failed to copy file data for %s", relPath)
79                 }
80         }
81         sum := hex.EncodeToString(h.Sum(nil))
82         c.sums[relPath] = sum
83         return sum, nil
84 }
85
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" {
91                 pfx := basepath + `\`
92                 if strings.HasPrefix(targpath, pfx) {
93                         p := strings.TrimPrefix(targpath, pfx)
94                         if p == "" {
95                                 p = "."
96                         }
97                         return p, nil
98                 }
99         }
100         return filepath.Rel(basepath, targpath)
101 }