func HashFileGlobs(basepath, dirpat string, filepats ...string) (map[string]string, error) {
	paths, err := getPaths(basepath, dirpat, filepats...)
	if err != nil {
		return nil, err
	}
	var pathsMap = map[string]string{}
	for _, src := range paths {
		dst, err := HashPath(src)
		if err == ErrIsDir {
			continue
		}
		if err != nil {
			return nil, err
		}
		src, _ = filepath.Rel(basepath, src)
		dst, _ = filepath.Rel(basepath, dst)
		pathsMap[src] = dst
	}
	return pathsMap, nil
}
HashFileGlobs returns a map from filepaths to their HashPath equivalent for
all files whoses parents match the dirpat regex and themselves match one
of the filepat globs.
package scattered
import (
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
)
func HashReader(r io.Reader) (string, error) {
	h := md5.New()
	_, err := io.Copy(h, r)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%x", h.Sum(nil)), nil
}
var ErrIsDir = errors.New("Tried to hash the path of a directory")
func HashPath(path string) (string, error) {
	f, err := os.Open(path)
	if err != nil {
		return "", err
	}
	defer f.Close()
	if stat, err := f.Stat(); err != nil {
		return "", err
	} else if stat.IsDir() {
		return "", ErrIsDir
	}
	hash, err := HashReader(f)
	if err != nil {
		return "", err
	}
	basename, ext := splitName(path)
	return fmt.Sprintf("%s.%s%s", basename, hash, ext), nil
}
func IsHashedPath(path string) bool {
	basename, _ := splitName(path)
	innerExt := filepath.Ext(basename)
	return len(innerExt) == (md5.Size*2)+1
}
func splitName(path string) (basename, ext string) {
	ext = filepath.Ext(path)
	basename = path[:len(path)-len(ext)]
	return
}