Example #1
0
File: yaml.go Project: rudle/glide
// NormalizeName takes a package name and normalizes it to the top level package.
//
// For example, golang.org/x/crypto/ssh becomes golang.org/x/crypto. 'ssh' is
// returned as extra data.
func NormalizeName(name string) (string, string) {

	// Fastpath check if a name in the GOROOT. There is an issue when a pkg
	// is in the GOROOT and GetRootFromPackage tries to look it up because it
	// expects remote names.
	b, err := util.GetBuildContext()
	if err == nil {
		p := filepath.Join(b.GOROOT, "src", filepath.FromSlash(name))
		if _, err := os.Stat(p); err == nil {
			return name, ""
		}
	}

	root := util.GetRootFromPackage(name)
	extra := strings.TrimPrefix(name, root)
	if len(extra) > 0 && extra != "/" {
		extra = strings.TrimPrefix(extra, "/")
	} else {
		// If extra is / (which is what it would be here) we want to return ""
		extra = ""
	}

	return root, extra

	// parts := strings.SplitN(name, "/", 4)
	// extra := ""
	// if len(parts) < 3 {
	// 	return name, extra
	// }
	// if len(parts) == 4 {
	// 	extra = parts[3]
	// }
	// return strings.Join(parts[0:3], "/"), extra
}
Example #2
0
// 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")

	buildContext, err := util.GetBuildContext()
	if err != nil {
		return nil, err
	}

	r := &Resolver{
		Handler:      &DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}},
		basedir:      basedir,
		VendorDir:    vdir,
		BuildContext: buildContext,
		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
}
Example #3
0
// EnsureConfig loads and returns a config file.
//
// Any error will cause an immediate exit, with an error printed to Stderr.
func EnsureConfig() *cfg.Config {
	yamlpath, err := gpath.Glide()
	if err != nil {
		msg.ExitCode(2)
		msg.Die("Failed to find %s file in directory tree: %s", gpath.GlideFile, err)
	}

	yml, err := ioutil.ReadFile(yamlpath)
	if err != nil {
		msg.ExitCode(2)
		msg.Die("Failed to load %s: %s", yamlpath, err)
	}
	conf, err := cfg.ConfigFromYaml(yml)
	if err != nil {
		msg.ExitCode(3)
		msg.Die("Failed to parse %s: %s", yamlpath, err)
	}

	b := filepath.Dir(yamlpath)
	buildContext, err := util.GetBuildContext()
	if err != nil {
		msg.Die("Failed to build an import context while ensuring config: %s", err)
	}
	cwd, err := os.Getwd()
	if err != nil {
		msg.Err("Unable to get the current working directory")
	} else {
		// Determining a package name requires a relative path
		b, err = filepath.Rel(b, cwd)
		if err == nil {
			name := buildContext.PackageName(b)
			if name != conf.Name {
				msg.Warn("The name listed in the config file (%s) does not match the current location (%s)", conf.Name, name)
			}
		} else {
			msg.Warn("Problem finding the config file path (%s) relative to the current directory (%s): %s", b, cwd, err)
		}
	}

	err = mirrors.Load()
	if err != nil {
		msg.Err("Unable to load mirrors: %s", err)
	}

	return conf
}
Example #4
0
// Tree prints a tree representing dependencies.
func Tree(basedir string, showcore bool) {
	buildContext, err := util.GetBuildContext()
	if err != nil {
		msg.Die("Failed to get a build context: %s", err)
	}
	myName := buildContext.PackageName(basedir)

	if basedir == "." {
		var err error
		basedir, err = os.Getwd()
		if err != nil {
			msg.Die("Could not get working directory")
		}
	}

	msg.Puts(myName)
	l := list.New()
	l.PushBack(myName)
	tree.Display(buildContext, basedir, myName, 1, showcore, l)
}
Example #5
0
// 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
	}

	basedir, err = checkForBasedirSymlink(basedir)

	if err != nil {
		return nil, err
	}

	vdir := filepath.Join(basedir, "vendor")

	buildContext, err := util.GetBuildContext()
	if err != nil {
		return nil, err
	}

	r := &Resolver{
		Handler:        &DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}},
		VersionHandler: &DefaultVersionHandler{},
		basedir:        basedir,
		VendorDir:      vdir,
		BuildContext:   buildContext,
		seen:           map[string]bool{},
		alreadyQ:       map[string]bool{},
		hadError:       map[string]bool{},
		findCache:      map[string]*PkgInfo{},

		// The config instance here should really be replaced with a real one.
		Config: &cfg.Config{},
	}

	// TODO: Make sure the build context is correctly set up. Especially in
	// regards to GOROOT, which is not always set.

	return r, nil
}
Example #6
0
// Tree prints a tree representing dependencies.
func Tree(basedir string, showcore bool) {
	msg.Warn("The tree command is deprecated and will be removed in a future version")
	buildContext, err := util.GetBuildContext()
	if err != nil {
		msg.Die("Failed to get a build context: %s", err)
	}
	myName := buildContext.PackageName(basedir)

	if basedir == "." {
		var err error
		basedir, err = os.Getwd()
		if err != nil {
			msg.Die("Could not get working directory")
		}
	}

	msg.Puts(myName)
	l := list.New()
	l.PushBack(myName)
	tree.Display(buildContext, basedir, myName, 1, showcore, l)
}
Example #7
0
// Tree prints a tree representing dependencies.
func Tree(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	buildContext, err := util.GetBuildContext()
	if err != nil {
		return nil, err
	}
	showcore := p.Get("showcore", false).(bool)
	basedir := p.Get("dir", ".").(string)
	myName := guessPackageName(buildContext, basedir)

	if basedir == "." {
		var err error
		basedir, err = os.Getwd()
		if err != nil {
			Error("Could not get working directory")
			return nil, err
		}
	}

	fmt.Println(myName)
	l := list.New()
	l.PushBack(myName)
	displayTree(buildContext, basedir, myName, 1, showcore, l)
	return nil, nil
}
Example #8
0
// guessDeps attempts to resolve all of the dependencies for a given project.
//
// base is the directory to start with.
// skipImport will skip running the automatic imports.
//
// FIXME: This function is likely a one-off that has a more standard alternative.
// It's also long and could use a refactor.
func guessDeps(base string, skipImport bool) *cfg.Config {
	buildContext, err := util.GetBuildContext()
	if err != nil {
		msg.Die("Failed to build an import context: %s", err)
	}
	name := buildContext.PackageName(base)

	msg.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 {
		guessImportDeps(base, config)
	}

	importLen := len(config.Imports)
	if importLen == 0 {
		msg.Info("Scanning code to look for dependencies")
	} else {
		msg.Info("Scanning code to look for dependencies not found in import")
	}

	// Resolve dependencies by looking at the tree.
	r, err := dependency.NewResolver(base)
	if err != nil {
		msg.Die("Error creating a dependency resolver: %s", err)
	}

	h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}}
	r.Handler = h

	sortable, err := r.ResolveLocal(false)
	if err != nil {
		msg.Die("Error resolving local dependencies: %s", 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, subpkg := util.NormalizeName(n)

		if !config.HasDependency(root) && root != config.Name {
			msg.Info("--> Found reference to %s\n", n)
			d := &cfg.Dependency{
				Name: root,
			}
			if len(subpkg) > 0 {
				d.Subpackages = []string{subpkg}
			}
			config.Imports = append(config.Imports, d)
		} else if config.HasDependency(root) {
			if len(subpkg) > 0 {
				subpkg = strings.TrimPrefix(subpkg, "/")
				d := config.Imports.Get(root)
				if !d.HasSubpackage(subpkg) {
					msg.Info("--> Adding sub-package %s to %s\n", subpkg, root)
					d.Subpackages = append(d.Subpackages, subpkg)
				}
			}
		}
	}

	if len(config.Imports) == importLen && importLen != 0 {
		msg.Info("--> Code scanning found no additional imports")
	}

	return config
}
Example #9
0
// IterativeScan attempts to obtain a list of imported dependencies from a
// package. This scanning is different from ImportDir as part of the go/build
// package. It looks over different permutations of the supported OS/Arch to
// try and find all imports. This is different from setting UseAllFiles to
// true on the build Context. It scopes down to just the supported OS/Arch.
//
// Note, there are cases where multiple packages are in the same directory. This
// usually happens with an example that has a main package and a +build tag
// of ignore. This is a bit of a hack. It causes UseAllFiles to have errors.
func IterativeScan(path string) ([]string, error) {

	// TODO(mattfarina): Add support for release tags.

	tgs, _ := readBuildTags(path)
	// Handle the case of scanning with no tags
	tgs = append(tgs, "")

	var pkgs []string
	for _, tt := range tgs {

		// split the tag combination to look at permutations.
		ts := strings.Split(tt, ",")
		var ttgs []string
		var arch string
		var ops string
		for _, ttt := range ts {
			dirty := false
			if strings.HasPrefix(ttt, "!") {
				dirty = true
				ttt = strings.TrimPrefix(ttt, "!")
			}
			if isSupportedOs(ttt) {
				if dirty {
					ops = getOsValue(ttt)
				} else {
					ops = ttt
				}
			} else if isSupportedArch(ttt) {
				if dirty {
					arch = getArchValue(ttt)
				} else {
					arch = ttt
				}
			} else {
				if !dirty {
					ttgs = append(ttgs, ttt)
				}
			}
		}

		// Handle the case where there are no tags but we need to iterate
		// on something.
		if len(ttgs) == 0 {
			ttgs = append(ttgs, "")
		}

		b, err := util.GetBuildContext()
		if err != nil {
			return []string{}, err
		}

		// Make sure use all files is off
		b.UseAllFiles = false

		// Set the OS and Arch for this pass
		b.GOARCH = arch
		b.GOOS = ops
		b.BuildTags = ttgs
		msg.Debug("Scanning with Arch(%s), OS(%s), and Build Tags(%v)", arch, ops, ttgs)

		pk, err := b.ImportDir(path, 0)

		// If there are no buildable souce with this permutation we skip it.
		if err != nil && strings.HasPrefix(err.Error(), "no buildable Go source files in") {
			continue
		} else if err != nil && strings.HasPrefix(err.Error(), "found packages ") {
			// A permutation may cause multiple packages to appear. For example,
			// an example file with an ignore build tag. If this happens we
			// ignore it.
			// TODO(mattfarina): Find a better way.
			msg.Debug("Found multiple packages while scanning %s: %s", path, err)
			continue
		} else if err != nil {
			msg.Debug("Problem parsing package at %s for %s %s", path, ops, arch)
			return []string{}, err
		}

		for _, dep := range pk.Imports {
			found := false
			for _, p := range pkgs {
				if p == dep {
					found = true
				}
			}
			if !found {
				pkgs = append(pkgs, dep)
			}
		}
	}

	return pkgs, nil
}
Example #10
0
// guessDeps attempts to resolve all of the dependencies for a given project.
//
// base is the directory to start with.
// skipImport will skip running the automatic imports.
//
// FIXME: This function is likely a one-off that has a more standard alternative.
// It's also long and could use a refactor.
func guessDeps(base string, skipImport bool) *cfg.Config {
	buildContext, err := util.GetBuildContext()
	if err != nil {
		msg.Die("Failed to build an import context: %s", err)
	}
	name := buildContext.PackageName(base)

	msg.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 {
		msg.Info("Attempting to import from other package managers (use --skip-import to skip)")
		deps := []*cfg.Dependency{}
		absBase, err := filepath.Abs(base)
		if err != nil {
			msg.Die("Failed to resolve location of %s: %s", base, err)
		}

		if d, ok := guessImportGodep(absBase); ok {
			msg.Info("Importing Godep configuration")
			msg.Warn("Godep uses commit id versions. Consider using Semantic Versions with Glide")
			deps = d
		} else if d, ok := guessImportGPM(absBase); ok {
			msg.Info("Importing GPM configuration")
			deps = d
		} else if d, ok := guessImportGB(absBase); ok {
			msg.Info("Importing GB configuration")
			deps = d
		}

		for _, i := range deps {
			msg.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 {
		msg.Die("Error creating a dependency resolver: %s", err)
	}

	h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}}
	r.Handler = h

	sortable, err := r.ResolveLocal(false)
	if err != nil {
		msg.Die("Error resolving local dependencies: %s", 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, subpkg := util.NormalizeName(n)

		if !config.HasDependency(root) {
			msg.Info("Found reference to %s\n", n)
			d := &cfg.Dependency{
				Name: root,
			}
			if len(subpkg) > 0 {
				d.Subpackages = []string{subpkg}
			}
			config.Imports = append(config.Imports, d)
		} else {
			if len(subpkg) > 0 {
				subpkg = strings.TrimPrefix(subpkg, "/")
				d := config.Imports.Get(root)
				if !d.HasSubpackage(subpkg) {
					msg.Info("Adding sub-package %s to %s\n", subpkg, root)
					d.Subpackages = append(d.Subpackages, subpkg)
				}
			}
		}
	}

	return config
}
Example #11
0
// 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
}
Example #12
0
// mergeGuess guesses dependencies and merges.
//
// 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, f *flattening, scanned map[string]bool) ([]string, bool) {
	deps := f.deps
	Info("Scanning %s for dependencies.", pkg)
	buildContext, err := util.GetBuildContext()
	if err != nil {
		Warn("Could not scan package %q: %s", pkg, err)
		return []string{}, false
	}

	res := []string{}

	if _, err := os.Stat(dir); err != nil {
		Warn("Directory is missing: %s", dir)
		return res, true
	}

	d := walkDeps(buildContext, dir, pkg)
	for _, oname := range d {
		if _, ok := scanned[oname]; ok {
			//Info("===> Scanned %s already. Skipping", name)
			continue
		}
		Debug("=> Scanning %s", oname)
		name, _ := NormalizeName(oname)
		//if _, ok := deps[name]; ok {
		//scanned[oname] = true
		//Debug("====> Seen %s already. Skipping", name)
		//continue
		//}
		if f.conf.HasIgnore(name) {
			Debug("==> Skipping %s because it is on the ignore list", name)
			continue
		}

		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,
			}
			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
			// but not be on vendor. We add any that are on $GOPATH.
			if _, ok := deps[name]; !ok {
				Debug("✨☆ GOPATH dependency: %s", name)
				nd := &cfg.Dependency{Name: name}
				deps[name] = nd
				res = append(res, name)
			}
			scanned[oname] = true
		}
	}

	return res, true
}