123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- package remotecontext // import "github.com/docker/docker/builder/remotecontext"
- import (
- "encoding/hex"
- "os"
- "path/filepath"
- "runtime"
- "strings"
- "github.com/docker/docker/builder"
- "github.com/docker/docker/pkg/pools"
- "github.com/pkg/errors"
- )
- // NewLazySource creates a new LazyContext. LazyContext defines a hashed build
- // context based on a root directory. Individual files are hashed first time
- // they are asked. It is not safe to call methods of LazyContext concurrently.
- func NewLazySource(root string) (builder.Source, error) {
- return &lazySource{
- root: root,
- sums: make(map[string]string),
- }, nil
- }
- type lazySource struct {
- root string
- sums map[string]string
- }
- func (c *lazySource) Root() string {
- return c.root
- }
- func (c *lazySource) Close() error {
- return nil
- }
- func (c *lazySource) Hash(path string) (string, error) {
- cleanPath, fullPath, err := normalize(path, c.root)
- if err != nil {
- return "", err
- }
- relPath, err := Rel(c.root, fullPath)
- if err != nil {
- return "", errors.WithStack(convertPathError(err, cleanPath))
- }
- fi, err := os.Lstat(fullPath)
- if err != nil {
- // Backwards compatibility: a missing file returns a path as hash.
- // This is reached in the case of a broken symlink.
- return relPath, nil
- }
- sum, ok := c.sums[relPath]
- if !ok {
- sum, err = c.prepareHash(relPath, fi)
- if err != nil {
- return "", err
- }
- }
- return sum, nil
- }
- func (c *lazySource) prepareHash(relPath string, fi os.FileInfo) (string, error) {
- p := filepath.Join(c.root, relPath)
- h, err := NewFileHash(p, relPath, fi)
- if err != nil {
- return "", errors.Wrapf(err, "failed to create hash for %s", relPath)
- }
- if fi.Mode().IsRegular() && fi.Size() > 0 {
- f, err := os.Open(p)
- if err != nil {
- return "", errors.Wrapf(err, "failed to open %s", relPath)
- }
- defer f.Close()
- if _, err := pools.Copy(h, f); err != nil {
- return "", errors.Wrapf(err, "failed to copy file data for %s", relPath)
- }
- }
- sum := hex.EncodeToString(h.Sum(nil))
- c.sums[relPath] = sum
- return sum, nil
- }
- // Rel makes a path relative to base path. Same as `filepath.Rel` but can also
- // handle UUID paths in windows.
- func Rel(basepath string, targpath string) (string, error) {
- // filepath.Rel can't handle UUID paths in windows
- if runtime.GOOS == "windows" {
- pfx := basepath + `\`
- if strings.HasPrefix(targpath, pfx) {
- p := strings.TrimPrefix(targpath, pfx)
- if p == "" {
- p = "."
- }
- return p, nil
- }
- }
- return filepath.Rel(basepath, targpath)
- }
|