Exemple #1
0
func scanPackage(ctxt *build.Context, t *build.Tree, arg, importPath, dir string, stk *importStack) *Package {
	// Read the files in the directory to learn the structure
	// of the package.
	p := &Package{
		ImportPath: importPath,
		Dir:        dir,
		Standard:   t.Goroot && !strings.Contains(importPath, "."),
		t:          t,
	}
	packageCache[dir] = p
	packageCache[importPath] = p

	info, err := ctxt.ScanDir(dir)
	if err != nil {
		p.Error = &PackageError{
			ImportStack: stk.copy(),
			Err:         err.Error(),
		}
		p.Incomplete = true
		return p
	}

	p.info = info
	p.Name = info.Package
	p.Doc = firstSentence(info.PackageComment.Text())
	p.Imports = info.Imports
	p.GoFiles = info.GoFiles
	p.TestGoFiles = info.TestGoFiles
	p.XTestGoFiles = info.XTestGoFiles
	p.CFiles = info.CFiles
	p.HFiles = info.HFiles
	p.SFiles = info.SFiles
	p.CgoFiles = info.CgoFiles
	p.CgoCFLAGS = info.CgoCFLAGS
	p.CgoLDFLAGS = info.CgoLDFLAGS

	if info.Package == "main" {
		_, elem := filepath.Split(importPath)
		p.target = filepath.Join(t.BinDir(), elem)
		if ctxt.GOOS == "windows" {
			p.target += ".exe"
		}
	} else {
		p.target = filepath.Join(t.PkgDir(), filepath.FromSlash(importPath)+".a")
	}

	var built time.Time
	if fi, err := os.Stat(p.target); err == nil {
		built = fi.ModTime()
	}

	// Build list of full paths to all Go files in the package,
	// for use by commands like go fmt.
	for _, f := range info.GoFiles {
		p.gofiles = append(p.gofiles, filepath.Join(dir, f))
	}
	for _, f := range info.CgoFiles {
		p.gofiles = append(p.gofiles, filepath.Join(dir, f))
	}
	for _, f := range info.TestGoFiles {
		p.gofiles = append(p.gofiles, filepath.Join(dir, f))
	}
	for _, f := range info.XTestGoFiles {
		p.gofiles = append(p.gofiles, filepath.Join(dir, f))
	}

	sort.Strings(p.gofiles)

	srcss := [][]string{
		p.GoFiles,
		p.CFiles,
		p.HFiles,
		p.SFiles,
		p.CgoFiles,
	}
Stale:
	for _, srcs := range srcss {
		for _, src := range srcs {
			if fi, err := os.Stat(filepath.Join(p.Dir, src)); err != nil || fi.ModTime().After(built) {
				//println("STALE", p.ImportPath, "needs", src, err)
				p.Stale = true
				break Stale
			}
		}
	}

	importPaths := p.Imports
	// Packages that use cgo import runtime/cgo implicitly,
	// except runtime/cgo itself.
	if len(info.CgoFiles) > 0 && (!p.Standard || p.ImportPath != "runtime/cgo") {
		importPaths = append(importPaths, "runtime/cgo")
	}
	// Everything depends on runtime, except runtime and unsafe.
	if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
		importPaths = append(importPaths, "runtime")
	}

	// Record package under both import path and full directory name.
	packageCache[dir] = p
	packageCache[importPath] = p

	// Build list of imported packages and full dependency list.
	imports := make([]*Package, 0, len(p.Imports))
	deps := make(map[string]bool)
	for _, path := range importPaths {
		if path == "C" {
			continue
		}
		deps[path] = true
		p1 := loadPackage(path, stk)
		imports = append(imports, p1)
		for _, dep := range p1.Deps {
			deps[dep] = true
		}
		if p1.Stale {
			p.Stale = true
		}
		if p1.Incomplete {
			p.Incomplete = true
		}
		// p1.target can be empty only if p1 is not a real package,
		// such as package unsafe or the temporary packages
		// created during go test.
		if !p.Stale && p1.target != "" {
			if fi, err := os.Stat(p1.target); err != nil || fi.ModTime().After(built) {
				//println("STALE", p.ImportPath, "needs", p1.target, err)
				//println("BUILT", built.String(), "VS", fi.ModTime().String())
				p.Stale = true
			}
		}
	}
	p.imports = imports

	p.Deps = make([]string, 0, len(deps))
	for dep := range deps {
		p.Deps = append(p.Deps, dep)
	}
	sort.Strings(p.Deps)
	for _, dep := range p.Deps {
		p1 := packageCache[dep]
		if p1 == nil {
			panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
		}
		p.deps = append(p.deps, p1)
		if p1.Error != nil {
			p.DepsErrors = append(p.DepsErrors, p1.Error)
		}
	}

	// unsafe is a fake package and is never out-of-date.
	if p.Standard && p.ImportPath == "unsafe" {
		p.Stale = false
		p.target = ""
	}

	return p
}
Exemple #2
0
func scanPackage(ctxt *build.Context, t *build.Tree, arg, importPath, dir string, stk *importStack, useAllFiles bool) *Package {
	// Read the files in the directory to learn the structure
	// of the package.
	p := &Package{
		ImportPath: importPath,
		Dir:        dir,
		Standard:   t.Goroot && !strings.Contains(importPath, "."),
		t:          t,
	}
	packageCache[dir] = p
	packageCache[importPath] = p

	ctxt.UseAllFiles = useAllFiles
	info, err := ctxt.ScanDir(dir)
	useAllFiles = false // flag does not apply to dependencies
	if err != nil {
		p.Error = &PackageError{
			ImportStack: stk.copy(),
			Err:         err.Error(),
		}
		// Look for parser errors.
		if err, ok := err.(scanner.ErrorList); ok {
			// Prepare error with \n before each message.
			// When printed in something like context: %v
			// this will put the leading file positions each on
			// its own line.  It will also show all the errors
			// instead of just the first, as err.Error does.
			var buf bytes.Buffer
			for _, e := range err {
				buf.WriteString("\n")
				buf.WriteString(e.Error())
			}
			p.Error.Err = buf.String()
		}
		p.Incomplete = true
		return p
	}

	p.info = info
	p.Name = info.Package
	p.Doc = doc.Synopsis(info.PackageComment.Text())
	p.Imports = info.Imports
	p.GoFiles = info.GoFiles
	p.TestGoFiles = info.TestGoFiles
	p.XTestGoFiles = info.XTestGoFiles
	p.CFiles = info.CFiles
	p.HFiles = info.HFiles
	p.SFiles = info.SFiles
	p.CgoFiles = info.CgoFiles
	p.CgoCFLAGS = info.CgoCFLAGS
	p.CgoLDFLAGS = info.CgoLDFLAGS

	if info.Package == "main" {
		_, elem := filepath.Split(importPath)
		full := ctxt.GOOS + "_" + ctxt.GOARCH + "/" + elem
		if t.Goroot && isGoTool[p.ImportPath] {
			p.target = filepath.Join(t.Path, "pkg/tool", full)
		} else {
			if ctxt.GOOS != toolGOOS || ctxt.GOARCH != toolGOARCH {
				// Install cross-compiled binaries to subdirectories of bin.
				elem = full
			}
			p.target = filepath.Join(t.BinDir(), elem)
		}
		if ctxt.GOOS == "windows" {
			p.target += ".exe"
		}
	} else {
		dir := t.PkgDir()
		// For gccgo, rewrite p.target with the expected library name.
		if _, ok := buildToolchain.(gccgoToolchain); ok {
			dir = filepath.Join(filepath.Dir(dir), "gccgo", filepath.Base(dir))
		}
		p.target = buildToolchain.pkgpath(dir, p)
	}

	var built time.Time
	if fi, err := os.Stat(p.target); err == nil {
		built = fi.ModTime()
	}

	// Build list of full paths to all Go files in the package,
	// for use by commands like go fmt.
	for _, f := range info.GoFiles {
		p.gofiles = append(p.gofiles, filepath.Join(dir, f))
	}
	for _, f := range info.CgoFiles {
		p.gofiles = append(p.gofiles, filepath.Join(dir, f))
	}
	for _, f := range info.TestGoFiles {
		p.gofiles = append(p.gofiles, filepath.Join(dir, f))
	}
	for _, f := range info.XTestGoFiles {
		p.gofiles = append(p.gofiles, filepath.Join(dir, f))
	}

	sort.Strings(p.gofiles)

	srcss := [][]string{
		p.GoFiles,
		p.CFiles,
		p.HFiles,
		p.SFiles,
		p.CgoFiles,
	}
Stale:
	for _, srcs := range srcss {
		for _, src := range srcs {
			if fi, err := os.Stat(filepath.Join(p.Dir, src)); err != nil || fi.ModTime().After(built) {
				//println("STALE", p.ImportPath, "needs", src, err)
				p.Stale = true
				break Stale
			}
		}
	}

	importPaths := p.Imports
	// Packages that use cgo import runtime/cgo implicitly,
	// except runtime/cgo itself.
	if len(info.CgoFiles) > 0 && (!p.Standard || p.ImportPath != "runtime/cgo") {
		importPaths = append(importPaths, "runtime/cgo")
	}
	// Everything depends on runtime, except runtime and unsafe.
	if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
		importPaths = append(importPaths, "runtime")
	}

	// Record package under both import path and full directory name.
	packageCache[dir] = p
	packageCache[importPath] = p

	// Build list of imported packages and full dependency list.
	imports := make([]*Package, 0, len(p.Imports))
	deps := make(map[string]bool)
	for _, path := range importPaths {
		if path == "C" {
			continue
		}
		deps[path] = true
		p1 := loadPackage(path, stk)
		if p1.Error != nil {
			if info.ImportPos != nil && len(info.ImportPos[path]) > 0 {
				pos := info.ImportPos[path][0]
				p1.Error.Pos = pos.String()
			}
		}
		imports = append(imports, p1)
		for _, dep := range p1.Deps {
			deps[dep] = true
		}
		if p1.Stale {
			p.Stale = true
		}
		if p1.Incomplete {
			p.Incomplete = true
		}
		// p1.target can be empty only if p1 is not a real package,
		// such as package unsafe or the temporary packages
		// created during go test.
		if !p.Stale && p1.target != "" {
			if fi, err := os.Stat(p1.target); err != nil || fi.ModTime().After(built) {
				//println("STALE", p.ImportPath, "needs", p1.target, err)
				//println("BUILT", built.String(), "VS", fi.ModTime().String())
				p.Stale = true
			}
		}
	}
	p.imports = imports

	p.Deps = make([]string, 0, len(deps))
	for dep := range deps {
		p.Deps = append(p.Deps, dep)
	}
	sort.Strings(p.Deps)
	for _, dep := range p.Deps {
		p1 := packageCache[dep]
		if p1 == nil {
			panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
		}
		p.deps = append(p.deps, p1)
		if p1.Error != nil {
			p.DepsErrors = append(p.DepsErrors, p1.Error)
		}
	}

	// unsafe is a fake package and is never out-of-date.
	if p.Standard && p.ImportPath == "unsafe" {
		p.Stale = false
		p.target = ""
	}

	p.Target = p.target

	return p
}