// forEachRepository calls found for each repository it finds in all GOPATH workspaces.
func forEachRepository(found func(Repo)) {
	for _, workspace := range filepath.SplitList(build.Default.GOPATH) {
		srcRoot := filepath.Join(workspace, "src")
		if _, err := os.Stat(srcRoot); os.IsNotExist(err) {
			continue
		}
		// TODO: Confirm that ignoring filepath.Walk error is correct/desired behavior.
		_ = filepath.Walk(srcRoot, func(path string, fi os.FileInfo, err error) error {
			if err != nil {
				log.Printf("can't stat file %s: %v\n", path, err)
				return nil
			}
			if !fi.IsDir() {
				return nil
			}
			if strings.HasPrefix(fi.Name(), ".") || strings.HasPrefix(fi.Name(), "_") || fi.Name() == "testdata" {
				return filepath.SkipDir
			}
			// Determine repo root. This is potentially somewhat slow.
			vcsCmd, root, err := vcs.FromDir(path, srcRoot)
			if err != nil {
				// Directory not under VCS.
				return nil
			}
			found(Repo{Path: path, Root: root, VCS: vcsCmd})
			return filepath.SkipDir // No need to descend inside repositories.
		})
	}
}
Example #2
0
// uniqueWorker finds unique repos out of all input Go packages.
func (w *workspace) uniqueWorker(wg *sync.WaitGroup) {
	defer wg.Done()
	for importPath := range w.ImportPaths {
		// Determine repo root.
		// This is potentially somewhat slow.
		bpkg, err := build.Import(importPath, wd, build.FindOnly)
		if err != nil {
			w.Errors <- err
			continue
		}
		if bpkg.Goroot {
			// gostatus has no support for printing status of packages in GOROOT, so skip those.
			continue
		}
		vcsCmd, root, err := vcs.FromDir(bpkg.Dir, bpkg.SrcRoot)
		if err != nil {
			// Go package not under VCS.
			var pkg *Repo
			w.reposMu.Lock()
			if _, ok := w.repos[bpkg.ImportPath]; !ok {
				pkg = &Repo{
					Path: bpkg.Dir,
					Root: bpkg.ImportPath,
					vcs:  nil,
				}
				w.repos[bpkg.ImportPath] = pkg
			}
			w.reposMu.Unlock()

			// If new package, send off to next stage.
			if pkg != nil {
				w.unique <- pkg
			}
			continue
		}
		vcs, err := vcsstate.NewVCS(vcsCmd)
		if err != nil {
			w.Errors <- fmt.Errorf("repo %v not supported by vcsstate: %v", root, err)
			continue
		}

		var repo *Repo
		w.reposMu.Lock()
		if _, ok := w.repos[root]; !ok {
			repo = &Repo{
				Path: bpkg.Dir,
				Root: root,
				vcs:  vcs,
			}
			w.repos[root] = repo
		}
		w.reposMu.Unlock()

		// If new repo, send off to next stage.
		if repo != nil {
			w.unique <- repo
		}
	}
}
Example #3
0
func FromDir(dir, srcRoot string) (*VCS, string, error) {
	vcscmd, reporoot, err := vcs.FromDir(dir, srcRoot)
	if err != nil {
		return nil, "", fmt.Errorf("error while inspecting %q: %v", dir, err)
	}
	vcsext := cmd[vcscmd]
	if vcsext == nil {
		return nil, "", fmt.Errorf("%s is unsupported: %s", vcscmd.Name, dir)
	}
	return vcsext, reporoot, nil
}
Example #4
0
// ResolveRepo on a local resolver may return an error if:
// *  The local package is not present (no directory) in LocalPath
// *  The local "package" is a file in localpath
// *  There was an error stating the directory for the localPkg
func (lr *LocalRepoResolver) ResolveRepo(pkg string, dep *CanticleDependency) (VCS, error) {
	LogVerbose("Finding local vcs for package: %s\n", pkg)
	fullPath := PackageSource(lr.LocalPath, getResolvePath(pkg))
	s, err := os.Stat(fullPath)
	switch {
	case err != nil:
		LogVerbose("Error stating local copy of package: %s %s\n", fullPath, err.Error())
		return nil, err
	case s != nil && s.IsDir():
		cmd, root, err := vcs.FromDir(fullPath, lr.LocalPath)
		if err != nil {
			LogVerbose("Error with local vcs: %s", err.Error())
			return nil, err
		}
		root, _ = PackageName(lr.LocalPath, path.Join(lr.LocalPath, root))
		v := NewLocalVCS(root, root, lr.LocalPath, cmd)
		LogVerbose("Created vcs for local pkg: %+v", v)
		return v, nil
	default:
		LogVerbose("Could not resolve local vcs for package: %s", fullPath)
		return nil, NewResolutionFailureError(pkg, "local")
	}
}
Example #5
0
// RepoInfo attempts to find the repo information for the caller, and returns
// the path to the top of the repo, the commit ID, and the tag.
func RepoInfo() (repoRoot string, repoRevision string, repoTag string) {
	var vcsCmd *vcs.Cmd

	// Walk up the call stack until we find main.main
	for i := 1; ; i++ {
		caller, file, _, ok := runtime.Caller(i)
		if !ok {
			break
		}

		f := runtime.FuncForPC(caller)
		if f == nil {
			continue
		}
		if path.Base(f.Name()) == "main.main" {
			repoRoot = path.Dir(file)
			break
		}

		// see if we're in testing
		if path.Base(f.Name()) == "testing.tRunner" {
			// go back up one level
			_, file, _, _ := runtime.Caller(i - 1)
			repoRoot = path.Dir(file)
			break
		}
	}

	// Try and find the root of the VCS repo using repoRoot as a starting point.
	if repoRoot != "" {
		// walk up the dir until we get to the first directory in root.
		// This is an unfortunately necessity to use vcs.FromDir()
		topDir := repoRoot
		for dir := path.Dir(topDir); dir != "." && dir[len(dir)-1] != '/' && dir != topDir; dir = path.Dir(topDir) {
			topDir = dir
		}

		var vcsRoot string
		vcsCmd, vcsRoot, _ = vcs.FromDir(path.Dir(repoRoot), topDir)
		if len(vcsRoot) > 0 {
			if vcsRoot[0] != '/' {
				vcsRoot = topDir + "/" + vcsRoot
			}
			repoRoot = vcsRoot
		}
	}

	if vcsCmd != nil && vcsCmd.Name == "Git" {
		execCmd := exec.Command("git", "describe", "--dirty", "--match", "", "--always")
		execCmd.Dir = repoRoot
		output, err := execCmd.Output()
		if err == nil {
			repoRevision = string(bytes.TrimRight(output, "\n"))
		}

		execCmd = exec.Command("git", "describe", "--dirty", "--tags", "--always")
		execCmd.Dir = repoRoot
		output, err = execCmd.Output()
		if err == nil {
			repoTag = string(bytes.TrimRight(output, "\n"))
		}
	}

	return
}
Example #6
0
// LoadDependencies is not done
func LoadDependencies(pkgs []string, ignores []string) ([]Dependency, error) {

	stdlib, err := golist.Std()
	if err != nil {
		return nil, err
	}

	pkgs, err = golist.Deps(pkgs...)
	if err != nil {
		return nil, err
	}

	// faster to remove stdlib
	pkgs = removeIfEquals(pkgs, stdlib)
	pkgs = removeIfSubstring(pkgs, ignores)

	deps, err := golist.Packages(pkgs...)
	if err != nil {
		return nil, err
	}

	visited := make(map[string]string, len(deps))

	out := make([]Dependency, 0, len(deps))
	for _, v := range deps {
		src := filepath.Join(v.Root, "src")
		path := filepath.Join(src, filepath.FromSlash(v.ImportPath))
		cmd, _, err := vcs.FromDir(path, src)
		if err != nil {
			log.Printf("error computing vcs %s: %s", path, err)
			continue
		}
		rr, err := vcs.RepoRootForImportPath(v.ImportPath, false)
		if err != nil {
			log.Printf("error computing repo for %s: %s", v.ImportPath, err)
			continue
		}
		e := Dependency{
			Package: v,
		}
		e.Project.Repo = rr.Repo
		e.Project.VcsName = cmd.Name
		e.Project.VcsCmd = cmd.Cmd
		e.License = GetLicense(path)
		visited[v.ImportPath] = e.License.Type

		// if child have no license, parent has license, continue
		// if child has no license, parent has no license, carry on
		if e.License.Type == "" {
			lic, ok := visited[rr.Root]
			if ok && lic != "" {
				// case is child has no license, but parent does
				// => just ignore this package
				continue
			}
			// if ok && lic = "" => dont look up parent

			if !ok {
				// first time checking parent
				parentpkg, err := golist.GetPackage(rr.Root)
				if err == nil {
					parent := Dependency{
						Package: parentpkg,
						Project: e.Project,
					}
					path = filepath.Join(src, filepath.FromSlash(rr.Root))
					parent.License = GetLicense(path)
					visited[rr.Root] = parent.License.Type
					if parent.License.Type != "" {
						// case child has no license, parent does
						//  ignore child and use parent
						e = parent
					}
				}
			}
		}
		commit, err := GetLastCommit(path)
		if err == nil {
			e.Commit = commit
		}

		e.Project.LicenseLink = LinkToFile(e.ImportPath, e.License.File, e.Commit.Rev)

		out = append(out, e)
	}
	return out, err
}