Merging in the new dependency resolver
diff --git a/cmd/flatten.go b/cmd/flatten.go
index eac3773..cfff217 100644
--- a/cmd/flatten.go
+++ b/cmd/flatten.go
@@ -56,7 +56,10 @@
 
 	f := &flattening{conf, vend, vend, deps, packages}
 
-	err := recFlatten(f, force, home, cache, cacheGopath, skipGopath)
+	// The assumption here is that once something has been scanned once in a
+	// run, there is no need to scan it again.
+	scanned := map[string]bool{}
+	err := recFlatten(f, force, home, cache, cacheGopath, skipGopath, scanned)
 	if err != nil {
 		return conf, err
 	}
@@ -106,7 +109,7 @@
 var updateCache = map[string]bool{}
 
 // refFlatten recursively flattens the vendor tree.
-func recFlatten(f *flattening, force bool, home string, cache, cacheGopath, skipGopath bool) error {
+func recFlatten(f *flattening, force bool, home string, cache, cacheGopath, skipGopath bool, scanned map[string]bool) error {
 	Debug("---> Inspecting %s for changes (%d packages).\n", f.curr, len(f.scan))
 	for _, imp := range f.scan {
 		Debug("----> Scanning %s", imp)
@@ -120,7 +123,7 @@
 			mod = m
 		} else if m, ok = mergeGb(base, imp, f.deps, f.top); ok {
 			mod = m
-		} else if m, ok = mergeGuess(base, imp, f.deps, f.top); ok {
+		} else if m, ok = mergeGuess(base, imp, f.deps, f.top, scanned); ok {
 			mod = m
 		}
 
@@ -133,7 +136,7 @@
 				curr: base,
 				deps: f.deps,
 				scan: mod}
-			recFlatten(f2, force, home, cache, cacheGopath, skipGopath)
+			recFlatten(f2, force, home, cache, cacheGopath, skipGopath, scanned)
 		}
 	}
 
@@ -261,7 +264,7 @@
 // This always returns true because it always handles the job of searching
 // for dependencies. So generally it should be the last merge strategy
 // that you try.
-func mergeGuess(dir, pkg string, deps map[string]*cfg.Dependency, vend string) ([]string, bool) {
+func mergeGuess(dir, pkg string, deps map[string]*cfg.Dependency, vend string, scanned map[string]bool) ([]string, bool) {
 	Info("Scanning %s for dependencies.", pkg)
 	buildContext, err := GetBuildContext()
 	if err != nil {
@@ -275,18 +278,27 @@
 		Warn("Directory is missing: %s", dir)
 		return res, true
 	}
+
 	d := walkDeps(buildContext, dir, pkg)
-	for _, name := range d {
-		name, _ := NormalizeName(name)
-		if _, ok := deps[name]; ok {
-			Debug("====> Seen %s already. Skipping", name)
+	for _, oname := range d {
+		if _, ok := scanned[oname]; ok {
+			//Info("===> Scanned %s already. Skipping", name)
 			continue
 		}
+		Info("=> Scanning %s", oname)
+		name, _ := NormalizeName(oname)
+		//if _, ok := deps[name]; ok {
+		//scanned[oname] = true
+		//Debug("====> Seen %s already. Skipping", name)
+		//continue
+		//}
+
+		repo := util.GetRootFromPackage(name)
 		found := findPkg(buildContext, name, dir)
 		switch found.PType {
 		case ptypeUnknown:
+			Info("==> Unknown %s (%s)", name, oname)
 			Debug("✨☆ Undownloaded dependency: %s", name)
-			repo := util.GetRootFromPackage(name)
 			nd := &cfg.Dependency{
 				Name:       name,
 				Repository: "https://" + repo,
@@ -294,6 +306,8 @@
 			deps[name] = nd
 			res = append(res, name)
 		case ptypeGoroot, ptypeCgo:
+			scanned[oname] = true
+			// Why do we break rather than continue?
 			break
 		default:
 			// We're looking for dependencies that might exist in $GOPATH
@@ -304,6 +318,7 @@
 				deps[name] = nd
 				res = append(res, name)
 			}
+			scanned[oname] = true
 		}
 	}
 
diff --git a/cmd/tree.go b/cmd/tree.go
index 61ba869..60181ec 100644
--- a/cmd/tree.go
+++ b/cmd/tree.go
@@ -9,6 +9,8 @@
 	"strings"
 
 	"github.com/Masterminds/cookoo"
+	"github.com/Masterminds/glide/dependency"
+	"github.com/Masterminds/glide/msg"
 )
 
 // Tree prints a tree representing dependencies.
@@ -40,40 +42,55 @@
 // ListDeps lists all of the dependencies of the current project.
 //
 // Params:
+//  - dir (string): basedir
+//  - deep (bool): whether to do a deep scan or a shallow scan
 //
 // Returns:
 //
 func ListDeps(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
-	buildContext, err := GetBuildContext()
-	if err != nil {
-		return nil, err
-	}
 	basedir := p.Get("dir", ".").(string)
-	myName := guessPackageName(buildContext, basedir)
+	deep := p.Get("deep", true).(bool)
 
-	basedir, err = filepath.Abs(basedir)
+	basedir, err := filepath.Abs(basedir)
 	if err != nil {
 		return nil, err
 	}
 
-	direct := map[string]*pinfo{}
-	d := walkDeps(buildContext, basedir, myName)
-	for _, i := range d {
-		listDeps(buildContext, direct, i, basedir)
+	r, err := dependency.NewResolver(basedir)
+	if err != nil {
+		return nil, err
 	}
+	h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}}
+	r.Handler = h
 
-	sortable := make([]string, len(direct))
-	i := 0
-	for k := range direct {
-		sortable[i] = k
-		i++
+	sortable, err := r.ResolveLocal(deep)
+	if err != nil {
+		return nil, err
 	}
 
 	sort.Strings(sortable)
 
+	fmt.Println("INSTALLED packages:")
 	for _, k := range sortable {
-		t := direct[k].PType
-		fmt.Printf("%s (Location: %s)\n", k, ptypeString(t))
+		v, err := filepath.Rel(basedir, k)
+		if err != nil {
+			msg.Warn("Failed to Rel path: %s", err)
+			v = k
+		}
+		fmt.Printf("\t%s\n", v)
+	}
+
+	if len(h.Missing) > 0 {
+		fmt.Println("\nMISSING packages:")
+		for _, pkg := range h.Missing {
+			fmt.Printf("\t%s\n", pkg)
+		}
+	}
+	if len(h.Gopath) > 0 {
+		fmt.Println("\nGOPATH packages:")
+		for _, pkg := range h.Gopath {
+			fmt.Printf("\t%s\n", pkg)
+		}
 	}
 
 	return nil, nil
@@ -231,7 +248,11 @@
 
 		pkg, err := b.ImportDir(path, 0)
 		if err != nil {
-			return err
+			if !strings.HasPrefix(err.Error(), "no buildable Go source") {
+				Warn("Error: %s (%s)", err, path)
+				// Not sure if we should return here.
+				//return err
+			}
 		}
 
 		if pkg.Goroot {
diff --git a/cmd/update_references.go b/cmd/update_references.go
index 1cf47ec..92fe235 100644
--- a/cmd/update_references.go
+++ b/cmd/update_references.go
@@ -70,6 +70,7 @@
 
 func discoverDependencyTree(f *flattening) error {
 	Debug("---> Inspecting %s for dependencies (%d packages).\n", f.curr, len(f.scan))
+	scanned := map[string]bool{}
 	for _, imp := range f.scan {
 		Debug("----> Scanning %s", imp)
 		base := path.Join(f.top, imp)
@@ -82,7 +83,7 @@
 			mod = m
 		} else if m, ok = mergeGb(base, imp, f.deps, f.top); ok {
 			mod = m
-		} else if m, ok = mergeGuess(base, imp, f.deps, f.top); ok {
+		} else if m, ok = mergeGuess(base, imp, f.deps, f.top, scanned); ok {
 			mod = m
 		}
 
diff --git a/dependency/resolver.go b/dependency/resolver.go
new file mode 100644
index 0000000..943c3aa
--- /dev/null
+++ b/dependency/resolver.go
@@ -0,0 +1,530 @@
+package dependency
+
+import (
+	"container/list"
+	"go/build"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/Masterminds/glide/cfg"
+	"github.com/Masterminds/glide/msg"
+)
+
+// MissingPackageHandler handles the case where a package is missing during scanning.
+//
+// It returns true if the package can be passed to the resolver, false otherwise.
+// False may be returned even if error is nil.
+type MissingPackageHandler interface {
+	// NotFound is called when the Resolver fails to find a package with the given name.
+	//
+	// NotFound returns true when the resolver should attempt to re-resole the
+	// dependency (e.g. when NotFound has gone and fetched the missing package).
+	//
+	// When NotFound returns false, the Resolver does not try to do any additional
+	// work on the missing package.
+	//
+	// NotFound only returns errors when it fails to perform its internal goals.
+	// When it returns false with no error, this indicates that the handler did
+	// its job, but the resolver should not do any additional work on the
+	// package.
+	NotFound(pkg string) (bool, error)
+
+	// OnGopath is called when the Resolver finds a dependency, but it's only on GOPATH.
+	//
+	// OnGopath provides an opportunity to copy, move, warn, or ignore cases like this.
+	//
+	// OnGopath returns true when the resolver should attempt to re-resolve the
+	// dependency (e.g. when the dependency is copied to a new location).
+	//
+	// When OnGopath returns false, the Resolver does not try to do any additional
+	// work on the package.
+	//
+	// An error indicates that OnGopath cannot complete its intended operation.
+	// Not all false results are errors.
+	OnGopath(pkg string) (bool, error)
+}
+
+// DefaultMissingPackageHandler is the default handler for missing packages.
+//
+// When asked to handle a missing package, it will report the miss as a warning,
+// and then store the package in the Missing slice for later access.
+type DefaultMissingPackageHandler struct {
+	Missing []string
+	Gopath  []string
+}
+
+// NotFound prints a warning and then stores the package name in Missing.
+//
+// It never returns an error, and it always returns false.
+func (d *DefaultMissingPackageHandler) NotFound(pkg string) (bool, error) {
+	msg.Warn("Package %s is not installed", pkg)
+	d.Missing = append(d.Missing, pkg)
+	return false, nil
+}
+
+func (d *DefaultMissingPackageHandler) OnGopath(pkg string) (bool, error) {
+	msg.Warn("Package %s is only on GOPATH.", pkg)
+	d.Gopath = append(d.Gopath, pkg)
+	return false, nil
+}
+
+// Resolver resolves a dependency tree.
+//
+// It operates in two modes:
+// - local resolution (ResolveLocal) determines the dependencies of the local project.
+// - vendor resolving (Resolve, ResolveAll) determines the dependencies of vendored
+//   projects.
+//
+// Local resolution is for guessing initial dependencies. Vendor resolution is
+// for determining vendored dependencies.
+type Resolver struct {
+	Handler      MissingPackageHandler
+	basedir      string
+	VendorDir    string
+	BuildContext build.Context
+	seen         map[string]bool
+
+	// Items already in the queue.
+	alreadyQ map[string]bool
+
+	// findCache caches hits from Find. This reduces the number of filesystem
+	// touches that have to be done for dependency resolution.
+	findCache map[string]*PkgInfo
+}
+
+// NewResolver returns a new Resolver initialized with the DefaultMissingPackageHandler.
+//
+// This will return an error if the given path does not meet the basic criteria
+// for a Go source project. For example, basedir must have a vendor subdirectory.
+//
+// The BuildContext uses the "go/build".Default to resolve dependencies.
+func NewResolver(basedir string) (*Resolver, error) {
+
+	var err error
+	basedir, err = filepath.Abs(basedir)
+	if err != nil {
+		return nil, err
+	}
+	vdir := filepath.Join(basedir, "vendor")
+
+	r := &Resolver{
+		Handler:      &DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}},
+		basedir:      basedir,
+		VendorDir:    vdir,
+		BuildContext: build.Default,
+		seen:         map[string]bool{},
+		alreadyQ:     map[string]bool{},
+		findCache:    map[string]*PkgInfo{},
+	}
+
+	// TODO: Make sure the build context is correctly set up. Especially in
+	// regards to GOROOT, which is not always set.
+
+	return r, nil
+}
+
+// Resolve takes a package name and returns all of the imported package names.
+//
+// If a package is not found, this calls the Fetcher. If the Fetcher returns
+// true, it will re-try traversing that package for dependencies. Otherwise it
+// will add that package to the deps array and continue on without trying it.
+// And if the Fetcher returns an error, this will stop resolution and return
+// the error.
+//
+// If basepath is set to $GOPATH, this will start from that package's root there.
+// If basepath is set to a project's vendor path, the scanning will begin from
+// there.
+func (r *Resolver) Resolve(pkg, basepath string) ([]string, error) {
+	target := filepath.Join(basepath, pkg)
+	//msg.Debug("Scanning %s", target)
+	l := list.New()
+	l.PushBack(target)
+	return r.resolveList(l)
+}
+
+// ResolveLocal resolves dependencies for the current project.
+//
+// This begins with the project, builds up a list of external dependencies.
+//
+// If the deep flag is set to true, this will then resolve all of the dependencies
+// of the dependencies it has found. If not, it will return just the packages that
+// the base project relies upon.
+func (r *Resolver) ResolveLocal(deep bool) ([]string, error) {
+	// We build a list of local source to walk, then send this list
+	// to resolveList.
+	l := list.New()
+	alreadySeen := map[string]bool{}
+	err := filepath.Walk(r.basedir, func(path string, fi os.FileInfo, err error) error {
+		if err != nil && err != filepath.SkipDir {
+			return err
+		}
+		if !fi.IsDir() {
+			return nil
+		}
+		if !srcDir(fi) {
+			return filepath.SkipDir
+		}
+
+		// Scan for dependencies, and anything that's not part of the local
+		// package gets added to the scan list.
+		p, err := r.BuildContext.ImportDir(path, 0)
+		if err != nil {
+			if strings.HasPrefix(err.Error(), "no buildable Go source") {
+				return nil
+			}
+			return err
+		}
+
+		// We are only looking for dependencies in vendor. No root, cgo, etc.
+		for _, imp := range p.Imports {
+			if alreadySeen[imp] {
+				continue
+			}
+			alreadySeen[imp] = true
+			info := r.FindPkg(imp)
+			switch info.Loc {
+			case LocUnknown, LocVendor:
+				l.PushBack(filepath.Join(r.VendorDir, imp)) // Do we need a path on this?
+			case LocGopath:
+				if !strings.HasPrefix(info.Path, r.basedir) {
+					// FIXME: This is a package outside of the project we're
+					// scanning. It should really be on vendor. But we don't
+					// want it to reference GOPATH. We want it to be detected
+					// and moved.
+					l.PushBack(filepath.Join(r.VendorDir, imp))
+				}
+			}
+		}
+
+		return nil
+	})
+
+	if err != nil {
+		msg.Error("Failed to build an initial list of packages to scan: %s", err)
+		return []string{}, err
+	}
+
+	if deep {
+		return r.resolveList(l)
+	}
+
+	// If we're not doing a deep scan, we just convert the list into an
+	// array and return.
+	res := make([]string, 0, l.Len())
+	for e := l.Front(); e != nil; e = e.Next() {
+		res = append(res, e.Value.(string))
+	}
+	return res, nil
+}
+
+// ResolveAll takes a list of packages and returns an inclusive list of all
+// vendored dependencies.
+//
+// While this will scan all of the source code it can find, it will only return
+// packages that were either explicitly passed in as deps, or were explicitly
+// imported by the code.
+//
+// Packages that are either CGO or on GOROOT are ignored. Packages that are
+// on GOPATH, but not vendored currently generate a warning.
+//
+// If one of the passed in packages does not exist in the vendor directory,
+// an error is returned.
+func (r *Resolver) ResolveAll(deps []*cfg.Dependency) ([]string, error) {
+	queue := sliceToQueue(deps, r.VendorDir)
+	return r.resolveList(queue)
+}
+
+// resolveList takes a list and resolves it.
+func (r *Resolver) resolveList(queue *list.List) ([]string, error) {
+
+	var failedDep string
+	for e := queue.Front(); e != nil; e = e.Next() {
+		dep := e.Value.(string)
+		//msg.Warn("#### %s ####", dep)
+		//msg.Info("Seen Count: %d", len(r.seen))
+		// Catch the outtermost dependency.
+		failedDep = dep
+		err := filepath.Walk(dep, func(path string, fi os.FileInfo, err error) error {
+			if err != nil && err != filepath.SkipDir {
+				return err
+			}
+
+			// Skip files.
+			if !fi.IsDir() {
+				return nil
+			}
+			// Skip dirs that are not source.
+			if !srcDir(fi) {
+				//msg.Debug("Skip resource %s", fi.Name())
+				return filepath.SkipDir
+			}
+
+			// Anything that comes through here has already been through
+			// the queue.
+			r.alreadyQ[path] = true
+			e := r.queueUnseen(path, queue)
+			if err != nil {
+				failedDep = path
+				//msg.Error("Failed to fetch dependency %s: %s", path, err)
+			}
+			return e
+		})
+		if err != nil && err != filepath.SkipDir {
+			msg.Error("Dependency %s failed to resolve: %s.", failedDep, err)
+			return []string{}, err
+		}
+	}
+
+	res := make([]string, 0, queue.Len())
+	for e := queue.Front(); e != nil; e = e.Next() {
+		res = append(res, e.Value.(string))
+	}
+
+	return res, nil
+}
+
+// queueUnseenImports scans a package's imports and adds any new ones to the
+// processing queue.
+func (r *Resolver) queueUnseen(pkg string, queue *list.List) error {
+	// A pkg is marked "seen" as soon as we have inspected it the first time.
+	// Seen means that we have added all of its imports to the list.
+
+	// Already queued indicates that we've either already put it into the queue
+	// or intentionally not put it in the queue for fatal reasons (e.g. no
+	// buildable source).
+
+	deps, err := r.imports(pkg)
+	if err != nil && !strings.HasPrefix(err.Error(), "no buildable Go source") {
+		msg.Error("Could not find %s: %s", pkg, err)
+		return err
+		// NOTE: If we uncomment this, we get lots of "no buildable Go source" errors,
+		// which don't ever seem to be helpful. They don't actually indicate an error
+		// condition, and it's perfectly okay to run into that condition.
+		//} else if err != nil {
+		//	msg.Warn(err.Error())
+	}
+
+	for _, d := range deps {
+		if _, ok := r.alreadyQ[d]; !ok {
+			r.alreadyQ[d] = true
+			queue.PushBack(d)
+		}
+	}
+	return nil
+}
+
+// imports gets all of the imports for a given package.
+//
+// If the package is in GOROOT, this will return an empty list (but not
+// an error).
+// If it cannot resolve the pkg, it will return an error.
+func (r *Resolver) imports(pkg string) ([]string, error) {
+
+	// If this pkg is marked seen, we don't scan it again.
+	if _, ok := r.seen[pkg]; ok {
+		msg.Debug("Already saw %s", pkg)
+		return []string{}, nil
+	}
+
+	// FIXME: On error this should try to NotFound to the dependency, and then import
+	// it again.
+	p, err := r.BuildContext.ImportDir(pkg, 0)
+	if err != nil {
+		return []string{}, err
+	}
+
+	// It is okay to scan a package more than once. In some cases, this is
+	// desirable because the package can change between scans (e.g. as a result
+	// of a failed scan resolving the situation).
+	msg.Debug("=> Scanning %s (%s)", p.ImportPath, pkg)
+	r.seen[pkg] = true
+
+	// Optimization: If it's in GOROOT, it has no imports worth scanning.
+	if p.Goroot {
+		return []string{}, nil
+	}
+
+	// We are only looking for dependencies in vendor. No root, cgo, etc.
+	buf := []string{}
+	for _, imp := range p.Imports {
+		info := r.FindPkg(imp)
+		switch info.Loc {
+		case LocUnknown:
+			// Do we resolve here?
+			found, err := r.Handler.NotFound(imp)
+			if err != nil {
+				msg.Error("Failed to fetch %s: %s", imp, err)
+			}
+			if found {
+				buf = append(buf, filepath.Join(r.VendorDir, imp))
+				continue
+			}
+			r.seen[info.Path] = true
+		case LocVendor:
+			//msg.Debug("Vendored: %s", imp)
+			buf = append(buf, info.Path)
+		case LocGopath:
+			found, err := r.Handler.OnGopath(imp)
+			if err != nil {
+				msg.Error("Failed to fetch %s: %s", imp, err)
+			}
+			// If the Handler marks this as found, we drop it into the buffer
+			// for subsequent processing. Otherwise, we assume that we're
+			// in a less-than-perfect, but functional, situation.
+			if found {
+				buf = append(buf, filepath.Join(r.VendorDir, imp))
+				continue
+			}
+			msg.Warn("Package %s is on GOPATH, but not vendored. Ignoring.", imp)
+			r.seen[info.Path] = true
+		default:
+			// Local packages are an odd case. CGO cannot be scanned.
+			msg.Debug("===> Skipping %s", imp)
+		}
+	}
+
+	return buf, nil
+}
+
+// sliceToQueue is a special-purpose function for unwrapping a slice of
+// dependencies into a queue of fully qualified paths.
+func sliceToQueue(deps []*cfg.Dependency, basepath string) *list.List {
+	l := list.New()
+	for _, e := range deps {
+		l.PushBack(filepath.Join(basepath, e.Name))
+	}
+	return l
+}
+
+// PkgLoc describes the location of the package.
+type PkgLoc uint8
+
+const (
+	// LocUnknown indicates the package location is unknown (probably not present)
+	LocUnknown PkgLoc = iota
+	// LocLocal inidcates that the package is in a local dir, not GOPATH or GOROOT.
+	LocLocal
+	// LocVendor indicates that the package is in a vendor/ dir
+	LocVendor
+	// LocGopath inidcates that the package is in GOPATH
+	LocGopath
+	// LocGoroot indicates that the package is in GOROOT
+	LocGoroot
+	// LocCgo indicates that the package is a a CGO package
+	LocCgo
+)
+
+type PkgInfo struct {
+	Name, Path string
+	Vendored   bool
+	Loc        PkgLoc
+}
+
+// FindPkg takes a package name and attempts to find it on the filesystem
+//
+// The resulting PkgInfo will indicate where it was found.
+func (r *Resolver) FindPkg(name string) *PkgInfo {
+	// We cachae results for FindPkg to reduce the number of filesystem ops
+	// that we have to do. This is a little risky because certain directories,
+	// like GOPATH, can be modified while we're running an operation, and
+	// render the cache inaccurate.
+	//
+	// Unfound items (LocUnkown) are never cached because we assume that as
+	// part of the response, the Resolver may fetch that dependency.
+	if i, ok := r.findCache[name]; ok {
+		//msg.Info("Cache hit on %s", name)
+		return i
+	}
+
+	// 502 individual packages scanned.
+	// No cache:
+	// glide -y etcd.yaml list  0.27s user 0.19s system 85% cpu 0.534 total
+	// With cache:
+	// glide -y etcd.yaml list  0.22s user 0.15s system 85% cpu 0.438 total
+
+	var p string
+	info := &PkgInfo{
+		Name: name,
+	}
+
+	// Check _only_ if this dep is in the current vendor directory.
+	p = filepath.Join(r.VendorDir, name)
+	if pkgExists(p) {
+		info.Path = p
+		info.Loc = LocVendor
+		info.Vendored = true
+		r.findCache[name] = info
+		return info
+	}
+
+	// TODO: Do we need this if we always flatten?
+	// Recurse backward to scan other vendor/ directories
+	//for wd := cwd; wd != "/"; wd = filepath.Dir(wd) {
+	//p = filepath.Join(wd, "vendor", name)
+	//if fi, err = os.Stat(p); err == nil && (fi.IsDir() || isLink(fi)) {
+	//info.Path = p
+	//info.PType = ptypeVendor
+	//info.Vendored = true
+	//return info
+	//}
+	//}
+
+	// Check $GOPATH
+	for _, rr := range strings.Split(r.BuildContext.GOPATH, ":") {
+		p = filepath.Join(rr, "src", name)
+		if pkgExists(p) {
+			info.Path = p
+			info.Loc = LocGopath
+			r.findCache[name] = info
+			return info
+		}
+	}
+
+	// Check $GOROOT
+	for _, rr := range strings.Split(r.BuildContext.GOROOT, ":") {
+		p = filepath.Join(rr, "src", name)
+		if pkgExists(p) {
+			info.Path = p
+			info.Loc = LocGoroot
+			r.findCache[name] = info
+			return info
+		}
+	}
+
+	// Finally, if this is "C", we're dealing with cgo
+	if name == "C" {
+		info.Loc = LocCgo
+		r.findCache[name] = info
+	}
+
+	return info
+}
+
+func pkgExists(path string) bool {
+	fi, err := os.Stat(path)
+	return err == nil && (fi.IsDir() || isLink(fi))
+}
+
+// isLink returns true if the given FileInfo is a symbolic link.
+func isLink(fi os.FileInfo) bool {
+	return fi.Mode()&os.ModeSymlink == os.ModeSymlink
+}
+
+func srcDir(fi os.FileInfo) bool {
+	if !fi.IsDir() {
+		return false
+	}
+
+	// Ignore _foo and .foo
+	if strings.HasPrefix(fi.Name(), "_") || strings.HasPrefix(fi.Name(), ".") {
+		return false
+	}
+
+	// Ignore testdata. For now, ignore vendor.
+	if fi.Name() == "testdata" || fi.Name() == "vendor" {
+		return false
+	}
+
+	return true
+}
diff --git a/dependency/resolver_test.go b/dependency/resolver_test.go
new file mode 100644
index 0000000..46268f2
--- /dev/null
+++ b/dependency/resolver_test.go
@@ -0,0 +1,99 @@
+package dependency
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/Masterminds/glide/cfg"
+)
+
+func TestResolveLocalShallow(t *testing.T) {
+	r, err := NewResolver("../")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	l, err := r.ResolveLocal(false)
+	if err != nil {
+		t.Fatalf("Failed to resolve: %s", err)
+	}
+
+	expect := []string{
+		"github.com/Masterminds/cookoo",
+		"github.com/Masterminds/semver",
+		"github.com/Masterminds/vcs",
+		"gopkg.in/yaml.v2",
+		"github.com/codegangsta/cli",
+	}
+
+	for _, p := range expect {
+		found := false
+		for _, li := range l {
+			if strings.HasSuffix(li, p) {
+				found = true
+				break
+			}
+		}
+		if !found {
+			t.Errorf("Could not find %s in resolved list.", p)
+		}
+	}
+}
+
+func TestResolveLocalDeep(t *testing.T) {
+	r, err := NewResolver("../")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	l, err := r.ResolveLocal(true)
+	if err != nil {
+		t.Fatalf("Failed to resolve: %s", err)
+	}
+
+	if len(l) < 8 {
+		t.Errorf("Expected at least 8 deps, got %d: %s", len(l))
+	}
+}
+
+func TestResolve(t *testing.T) {
+	r, err := NewResolver("../")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	base := filepath.Join(os.Getenv("GOPATH"), "src/github.com/Masterminds/glide/vendor")
+	l, err := r.Resolve("github.com/codegangsta/cli", base)
+	if err != nil {
+		t.Fatalf("Failed to resolve: %s", err)
+	}
+
+	if len(l) != 1 {
+		t.Errorf("Expected 1 dep, got %d: %s", len(l), l[0])
+	}
+}
+
+func TestResolveAll(t *testing.T) {
+	// These are build dependencies of Glide, so we know they are here.
+	deps := []*cfg.Dependency{
+		&cfg.Dependency{Name: "github.com/codegangsta/cli"},
+		&cfg.Dependency{Name: "github.com/Masterminds/cookoo"},
+		&cfg.Dependency{Name: "github.com/Masterminds/semver"},
+		&cfg.Dependency{Name: "gopkg.in/yaml.v2"},
+	}
+
+	r, err := NewResolver("../")
+	if err != nil {
+		t.Fatalf("No new resolver: %s", err)
+	}
+	l, err := r.ResolveAll(deps)
+	if err != nil {
+		t.Fatalf("Failed to resolve: %s", err)
+	}
+
+	if len(l) < len(deps) {
+		t.Errorf("Expected at least %d deps, got %d", len(deps), len(l))
+	}
+}
diff --git a/msg/msg.go b/msg/msg.go
new file mode 100644
index 0000000..a357a39
--- /dev/null
+++ b/msg/msg.go
@@ -0,0 +1,92 @@
+// +build !windows
+
+package msg
+
+import (
+	"fmt"
+	"strings"
+)
+
+// These contanstants map to color codes for shell scripts making them
+// human readable.
+const (
+	Blue   = "0;34"
+	Red    = "0;31"
+	Green  = "0;32"
+	Yellow = "0;33"
+	Cyan   = "0;36"
+	Pink   = "1;35"
+)
+
+// Color returns a string in a certain color. The first argument is a string
+// containing the color code or a constant from the table above mapped to a code.
+//
+// The following will print the string "Foo" in yellow:
+//     fmt.Print(Color(Yellow, "Foo"))
+func Color(code, msg string) string {
+	if NoColor {
+		return msg
+	}
+	return fmt.Sprintf("\033[%sm%s\033[m", code, msg)
+}
+
+// Info logs information
+func Info(msg string, args ...interface{}) {
+	if Quiet {
+		return
+	}
+	fmt.Fprint(Stderr, Color(Green, "[INFO] "))
+	Msg(msg, args...)
+}
+
+// Debug logs debug information
+func Debug(msg string, args ...interface{}) {
+	if Quiet || !IsDebugging {
+		return
+	}
+	fmt.Fprint(Stderr, "[DEBUG] ")
+	Msg(msg, args...)
+}
+
+// Warn logs a warning
+func Warn(msg string, args ...interface{}) {
+	fmt.Fprint(Stderr, Color(Yellow, "[WARN] "))
+	ErrMsg(msg, args...)
+}
+
+// Error logs and error.
+func Error(msg string, args ...interface{}) {
+	fmt.Fprint(Stderr, Color(Red, "[ERROR] "))
+	ErrMsg(msg, args...)
+}
+
+// ErrMsg sends a message to Stderr
+func ErrMsg(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fmt.Fprint(Stderr, msg)
+	} else {
+		fmt.Fprintf(Stderr, msg, args...)
+	}
+
+	// Get rid of the annoying fact that messages need \n at the end, but do
+	// it in a backward compatible way.
+	if !strings.HasSuffix(msg, "\n") {
+		fmt.Fprintln(Stderr)
+	}
+}
+
+// Msg prints a message with optional arguments, that can be printed, of
+// varying types.
+func Msg(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fmt.Fprint(Stderr, msg)
+	} else {
+		fmt.Fprintf(Stderr, msg, args...)
+	}
+
+	// Get rid of the annoying fact that messages need \n at the end, but do
+	// it in a backward compatible way.
+	if !strings.HasSuffix(msg, "\n") {
+		fmt.Fprintln(Stderr)
+	}
+}
diff --git a/msg/msg_windows.go b/msg/msg_windows.go
new file mode 100644
index 0000000..7a715f1
--- /dev/null
+++ b/msg/msg_windows.go
@@ -0,0 +1,63 @@
+// +build windows
+
+package msg
+
+import (
+	"fmt"
+	"strings"
+)
+
+// Info logs information
+func Info(msg string, args ...interface{}) {
+	if Quiet {
+		return
+	}
+	fmt.Print("[INFO] ")
+	Msg(msg, args...)
+}
+
+// Debug logs debug information
+func Debug(msg string, args ...interface{}) {
+	if Quiet || !IsDebugging {
+		return
+	}
+	fmt.Print("[DEBUG] ")
+	Msg(msg, args...)
+}
+
+// Warn logs a warning
+func Warn(msg string, args ...interface{}) {
+	fmt.Fprint(Stderr, "[WARN] ")
+	ErrMsg(msg, args...)
+}
+
+// Error logs and error.
+func Error(msg string, args ...interface{}) {
+	fmt.Fprint(Stderr, "[ERROR] ")
+	ErrMsg(msg, args...)
+}
+
+// ErrMsg sends a message to Stderr
+func ErrMsg(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fmt.Fprint(Stderr, msg)
+		return
+	}
+	fmt.Fprintf(Stderr, msg, args...)
+}
+
+// Msg prints a message with optional arguments, that can be printed, of
+// varying types.
+func Msg(msg string, args ...interface{}) {
+	if len(args) == 0 {
+		fmt.Print(msg)
+		return
+	}
+	fmt.Printf(msg, args...)
+
+	// Get rid of the annoying fact that messages need \n at the end, but do
+	// it in a backward compatible way.
+	if !strings.HasSuffix(msg, "\n") {
+		fmt.Println("")
+	}
+}
diff --git a/msg/vars.go b/msg/vars.go
new file mode 100644
index 0000000..129b53c
--- /dev/null
+++ b/msg/vars.go
@@ -0,0 +1,31 @@
+package msg
+
+import (
+	"fmt"
+	"os"
+)
+
+// Quiet, if true, suppresses chatty levels, like Info.
+var Quiet = false
+
+// IsDebugging, if true, shows verbose levels, like Debug.
+var IsDebugging = false
+
+// NoColor, if true, will not use color in the output.
+var NoColor = false
+
+// Stdout is the location where this prints output.
+var Stdout = os.Stdout
+
+// Stderr is the location where this prints logs.
+var Stderr = os.Stderr
+
+// Puts formats a message and then prints to Stdout.
+//
+// It does not prefix the message, does not color it, or otherwise decorate it.
+//
+// It does add a line feed.
+func Puts(msg string, args ...interface{}) {
+	fmt.Fprintf(Stdout, msg, args...)
+	fmt.Fprintln(Stdout)
+}