func loadBinary(provider fsProviderFn, c Config) string {
	log.Printf("Encoding project: %s", c.Project)
	fs, err := provider(c)
	if err != nil {
		log.Printf("Failed creating filesystem %q: %s", c.Project, err)
		return ""
	}
	b, err := encode(fs)
	if err != nil {
		log.Printf("Failed encoding filesystem %q: %s", c.Project, err)
		return ""
	}
	return string(b)
}
projectBinary retruns the binary encoded format of a single project.
package binfs
import (
	"go/ast"
	"go/token"
	"log"
	"net/http"
	"strings"
	"github.com/pkg/errors"
	"golang.org/x/tools/go/packages"
)
type Calls map[string]*Config
type Config struct {
	Project string
	globPatterns []string
	noPatterns bool
}
func (c *Config) GlobPatterns() []string {
	if c.noPatterns {
		return nil
	}
	return c.globPatterns
}
type fsProviderFn func(c Config) (http.FileSystem, error)
func LoadCalls(patterns ...string) (Calls, error) {
	pkgs, err := packages.Load(&packages.Config{Mode: packages.LoadAllSyntax}, patterns...)
	if err != nil {
		return nil, errors.Wrap(err, "loading packages")
	}
	totalFiles := 0
	for _, pkg := range pkgs {
		totalFiles += len(pkg.Syntax)
	}
	if totalFiles == 0 {
		return nil, errors.New("no packages were loaded")
	}
	c := make(Calls)
	for _, pkg := range pkgs {
		for _, file := range pkg.Syntax {
			c.lookupAST(file, pkg.Fset)
		}
	}
	return c, nil
}
func GenerateBinaries(c Calls, provider fsProviderFn) map[string]string {
	binaries := make(map[string]string)
	for project, config := range c {
		binaries[project] = loadBinary(provider, *config)
	}
	return binaries
}
func (c Calls) lookupAST(file *ast.File, fset *token.FileSet) {
	ast.Inspect(file, func(n ast.Node) bool {
		if call, ok := n.(*ast.CallExpr); ok {
			var id *ast.Ident
			switch fun := call.Fun.(type) {
			case *ast.Ident:
				id = fun
			case *ast.SelectorExpr:
				id = fun.Sel
			}
			if id != nil && id.Name == "New" {
				if isPkgDot(call.Fun, "gitfs", "New") {
					project := stringExpr(call.Args[1])
					pos := fset.Position(call.Pos())
					if project == "" {
						log.Printf(
							"Skipping gitfs.New call in %s. Could not get project name from call.",
							pos)
						return false
					}
					if c[project] == nil {
						c[project] = &Config{Project: project}
					}
					patterns, err := findOptGlob(call.Args[2:])
					if err != nil {
						log.Printf(
							"Failed getting glob options in %s, building without glob pattern: %s",
							pos, err)
						patterns = nil
					}
					if len(patterns) == 0 {
						c[project].noPatterns = true
					} else {
						c[project].globPatterns = append(c[project].globPatterns, patterns...)
					}
				}
			}
		}
		return true
	})
}