blob: 1ab3ebc6b97680e326132bc304b19e6fcedb1b0e [file] [log] [blame] [edit]
package cmd
import (
"os"
"path/filepath"
"sort"
"strings"
"github.com/Masterminds/cookoo"
"github.com/Masterminds/glide/cfg"
"github.com/Masterminds/glide/dependency"
"github.com/Masterminds/glide/util"
)
// GuessDeps tries to get the dependencies for the current directory.
//
// Params
// - dirname (string): Directory to use as the base. Default: "."
// - skipImport (book): Whether to skip importing from Godep, GPM, and gb
func GuessDeps(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
buildContext, err := util.GetBuildContext()
if err != nil {
return nil, err
}
base := p.Get("dirname", ".").(string)
skipImport := p.Get("skipImport", false).(bool)
name := guessPackageName(buildContext, base)
Info("Generating a YAML configuration file and guessing the dependencies")
config := new(cfg.Config)
// Get the name of the top level package
config.Name = name
// Import by looking at other package managers and looking over the
// entire directory structure.
// Attempt to import from other package managers.
if !skipImport {
Info("Attempting to import from other package managers (use --skip-import to skip)")
deps := []*cfg.Dependency{}
absBase, err := filepath.Abs(base)
if err != nil {
return nil, err
}
if d, ok := guessImportGodep(absBase); ok {
Info("Importing Godep configuration")
Warn("Godep uses commit id versions. Consider using Semantic Versions with Glide")
deps = d
} else if d, ok := guessImportGPM(absBase); ok {
Info("Importing GPM configuration")
deps = d
} else if d, ok := guessImportGB(absBase); ok {
Info("Importing GB configuration")
deps = d
}
for _, i := range deps {
Info("Found imported reference to %s\n", i.Name)
config.Imports = append(config.Imports, i)
}
}
// Resolve dependencies by looking at the tree.
r, err := dependency.NewResolver(base)
if err != nil {
return nil, err
}
h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}}
r.Handler = h
sortable, err := r.ResolveLocal(false)
if err != nil {
return nil, err
}
sort.Strings(sortable)
vpath := r.VendorDir
if !strings.HasSuffix(vpath, "/") {
vpath = vpath + string(os.PathSeparator)
}
for _, pa := range sortable {
n := strings.TrimPrefix(pa, vpath)
root := util.GetRootFromPackage(n)
if !config.HasDependency(root) {
Info("Found reference to %s\n", n)
d := &cfg.Dependency{
Name: root,
}
subpkg := strings.TrimPrefix(n, root)
if len(subpkg) > 0 && subpkg != "/" {
d.Subpackages = []string{subpkg}
}
config.Imports = append(config.Imports, d)
} else {
subpkg := strings.TrimPrefix(n, root)
if len(subpkg) > 0 && subpkg != "/" {
subpkg = strings.TrimPrefix(subpkg, "/")
d := config.Imports.Get(root)
f := false
for _, v := range d.Subpackages {
if v == subpkg {
f = true
}
}
if !f {
Info("Adding sub-package %s to %s\n", subpkg, root)
d.Subpackages = append(d.Subpackages, subpkg)
}
}
}
}
return config, nil
}
// Attempt to guess at the package name at the top level. When unable to detect
// a name goes to default of "main".
func guessPackageName(b *util.BuildCtxt, base string) string {
cwd, err := os.Getwd()
if err != nil {
return "main"
}
pkg, err := b.Import(base, cwd, 0)
if err != nil {
// There may not be any top level Go source files but the project may
// still be within the GOPATH.
if strings.HasPrefix(base, b.GOPATH) {
p := strings.TrimPrefix(base, b.GOPATH)
return strings.Trim(p, string(os.PathSeparator))
}
}
return pkg.ImportPath
}
func guessImportGodep(dir string) ([]*cfg.Dependency, bool) {
d, err := parseGodepGodeps(dir)
if err != nil || len(d) == 0 {
return []*cfg.Dependency{}, false
}
return d, true
}
func guessImportGPM(dir string) ([]*cfg.Dependency, bool) {
d, err := parseGPMGodeps(dir)
if err != nil || len(d) == 0 {
return []*cfg.Dependency{}, false
}
return d, true
}
func guessImportGB(dir string) ([]*cfg.Dependency, bool) {
d, err := parseGbManifest(dir)
if err != nil || len(d) == 0 {
return []*cfg.Dependency{}, false
}
return d, true
}