func TarLayerDirectory(
	out io.Writer, root string, ignores ...string) (digest.Digest, error) {
	var err error
	root, err = filepath.Abs(root)
	if err != nil {
		return "", errors.Wrap(err, "calc absolute path of root")
	}
	for i := 0; i < len(ignores); i++ {
		if !filepath.IsAbs(ignores[i]) {
			ignores[i], err = filepath.Abs(ignores[i])
			if err != nil {
				return "", errors.Wrap(err, "calc aboluste path of ignores")
			}
		}
		ignores[i], err = filepath.Rel(root, ignores[i])
		if err != nil {
			return "", errors.Wrap(err, "calc ignored related path to root")
		}
	}
	sort.Strings(ignores)
	fileList := []string{}
	err = filepath.Walk(
		root,
		func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			relPath, err := filepath.Rel(root, path)
			if err != nil {
				return errors.Wrap(err, "calc related layer path")
			}
			position := sort.SearchStrings(ignores, relPath)
			if position < len(ignores) && ignores[position] == relPath {
				if info.IsDir() {
					return filepath.SkipDir
				}
				return nil
			}
			fileList = append(fileList, path)
			return nil
		},
	)
	if err != nil {
		return "", err
	}
	return TarLayerAndDigest(out, root, fileList)
}
TarLayerDirectory tar the whole directory to a layer
package registry
import (
	"archive/tar"
	"compress/gzip"
	"io"
	"os"
	"path/filepath"
	"sort"
	"github.com/opencontainers/go-digest"
	"github.com/pkg/errors"
)
func TarLayer(out io.Writer, root string, fileList []string) error {
	fileList = SortFiles4Layer(fileList)
	gzipOut := gzip.NewWriter(out)
	defer gzipOut.Close()
	tarOut := tar.NewWriter(gzipOut)
	defer tarOut.Close()
	for _, file := range fileList {
		err := func() error {
			path, err := filepath.Rel(root, file)
			if err != nil {
				return errors.Wrap(err, "calc rel path of root")
			}
			finfo, err := os.Stat(file)
			if err != nil {
				return errors.Wrap(err, "get file stat")
			}
			tarHdr, err := tar.FileInfoHeader(finfo, file)
			if err != nil {
				return errors.Wrap(err, "parsing tar header")
			}
			tarHdr.Name = path
			err = tarOut.WriteHeader(tarHdr)
			if err != nil {
				return errors.Wrap(err, "write tar file header")
			}
			if finfo.IsDir() {
				return nil
			}
			f, err := os.Open(file)
			if err != nil {
				return errors.Wrap(err, "open layer file")
			}
			defer f.Close()
			_, err = io.Copy(tarOut, f)
			if err != nil {
				return errors.Wrap(err, "tar layer file")
			}
			return nil
		}()
		if err != nil {
			return err
		}
	}
	return nil
}
func UntarLayer(in io.Reader) (*tar.Reader, error) {
	gzipIn, err := gzip.NewReader(in)
	if err != nil {
		return nil, errors.Wrap(err, "un-gzip")
	}
	return tar.NewReader(gzipIn), nil
}
func TarLayerAndDigest(
	out io.Writer, root string, fileList []string) (digest.Digest, error) {
	digester := digest.Canonical.Digester()
	err := TarLayer(io.MultiWriter(out, digester.Hash()), root, fileList)
	return digester.Digest(), err
}
func SortFiles4Layer(fileList []string) []string {
	sorted := make([]string, len(fileList))
	copy(sorted, fileList)
	sort.Strings(sorted)
	return sorted
}