Пример #1
0
func parseFlags(checker *errcheck.Checker, args []string) ([]string, int) {
	flags := flag.NewFlagSet(args[0], flag.ContinueOnError)
	flags.BoolVar(&checker.Blank, "blank", false, "if true, check for errors assigned to blank identifier")
	flags.BoolVar(&checker.Asserts, "asserts", false, "if true, check for ignored type assertion results")
	flags.BoolVar(&checker.Verbose, "verbose", false, "produce more verbose logging")

	tags := tagsFlag{}
	flags.Var(&tags, "tags", "space-separated list of build tags to include")
	ignorePkg := flags.String("ignorepkg", "", "comma-separated list of package paths to ignore")
	ignore := ignoreFlag(map[string]*regexp.Regexp{
		"fmt": dotStar,
	})
	flags.Var(ignore, "ignore", "comma-separated list of pairs of the form pkg:regex\n"+
		"            the regex is used to ignore names within pkg")

	if err := flags.Parse(args[1:]); err != nil {
		return nil, exitFatalError
	}

	checker.Tags = tags
	for _, pkg := range strings.Split(*ignorePkg, ",") {
		if pkg != "" {
			ignore[pkg] = dotStar
		}
	}
	checker.Ignore = ignore

	ctx := gotool.Context{
		BuildContext: build.Default,
	}
	ctx.BuildContext.BuildTags = tags

	// ImportPaths normalizes paths and expands '...'
	return gotool.ImportPaths(flags.Args()), exitCodeOk
}
Пример #2
0
func main() {
	ignore := ignoreFlag(map[string]*regexp.Regexp{
		"fmt": dotStar,
	})
	flag.Var(ignore, "ignore", "comma-separated list of pairs of the form pkg:regex\n"+
		"            the regex is used to ignore names within pkg")
	ignorePkg := flag.String("ignorepkg", "", "comma-separated list of package paths to ignore")
	blank := flag.Bool("blank", false, "if true, check for errors assigned to blank identifier")
	flag.Parse()

	for _, pkg := range strings.Split(*ignorePkg, ",") {
		if pkg != "" {
			ignore[pkg] = dotStar
		}
	}

	var pkgPaths = gotool.ImportPaths(flag.Args())
	if err := errcheck.CheckPackages(pkgPaths, ignore, *blank); err != nil {
		if e, ok := err.(errcheck.UncheckedErrors); ok {
			for _, uncheckedError := range e.Errors {
				fmt.Println(uncheckedError)
			}
			os.Exit(1)
		} else if err == errcheck.ErrNoGoFiles {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(0)
		}
		Fatalf("failed to check package: %s", err)
	}
	os.Exit(0)
}
Пример #3
0
func main() {
	flag.Parse()

	importPaths := gotool.ImportPaths(flag.Args())
	if len(importPaths) == 0 {
		return
	}

	var conf loader.Config
	conf.Fset = fset
	for _, importPath := range importPaths {
		conf.Import(importPath)
	}
	prog, err := conf.Load()
	if err != nil {
		log.Fatal(err)
	}

	for _, pkg := range prog.InitialPackages() {
		for _, file := range pkg.Files {
			ast.Inspect(file, func(node ast.Node) bool {
				if s, ok := node.(*ast.StructType); ok {
					malign(node.Pos(), pkg.Types[s].Type.(*types.Struct))
				}
				return true
			})
		}
	}
}
Пример #4
0
func main() {
	flag.Parse()

	username, ok := os.LookupEnv(teamcityAPIUserEnv)
	if !ok {
		log.Fatalf("teamcity API username environment variable %s is not set", teamcityAPIUserEnv)
	}
	password, ok := os.LookupEnv(teamcityAPIPasswordEnv)
	if !ok {
		log.Fatalf("teamcity API password environment variable %s is not set", teamcityAPIPasswordEnv)
	}
	importPaths := gotool.ImportPaths([]string{"github.com/cockroachdb/cockroach/..."})

	client := teamcity.New("teamcity.cockroachdb.com", username, password)
	// Queue a build per configuration per package.
	for _, params := range []map[string]string{
		{}, // uninstrumented
		{"env.GOFLAGS": "-race"},
		{"env.TAGS": "deadlock"},
	} {
		for _, importPath := range importPaths {
			params["env.PKG"] = importPath
			build, err := client.QueueBuild(*buildTypeID, *branchName, params)
			if err != nil {
				log.Fatalf("failed to create teamcity build (*buildTypeID=%s *branchName=%s, params=%+v): %s", *buildTypeID, *branchName, params, err)
			}
			log.Printf("created teamcity build (*buildTypeID=%s *branchName=%s, params=%+v): %s", *buildTypeID, *branchName, params, build)
		}
	}
}
Пример #5
0
func runTC(queueBuildFn func(map[string]string)) {
	importPaths := gotool.ImportPaths([]string{"github.com/cockroachdb/cockroach/pkg/..."})

	// Queue a build per configuration per package.
	for _, properties := range []map[string]string{
		{}, // uninstrumented
		{"env.GOFLAGS": "-race"},
		{tagsKey: "deadlock"},
	} {
		if tags, ok := properties[tagsKey]; ok {
			properties[tagsKey] = strings.Join([]string{tags, stressTag}, " ")
		} else {
			properties[tagsKey] = stressTag
		}

		for _, propEvalKV := range []bool{true, false} {
			properties["env.COCKROACH_PROPOSER_EVALUATED_KV"] = strconv.FormatBool(propEvalKV)

			for _, importPath := range importPaths {
				properties["env.PKG"] = importPath

				queueBuildFn(properties)
			}
		}
	}
}
Пример #6
0
func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "%s\n", usage)
		flag.PrintDefaults()
		os.Exit(2)
	}
	flag.Parse()

	var err error
	cwd, err = os.Getwd()
	if err != nil {
		cwd = "."
	}
	pkgs := flag.Args()
	if len(pkgs) == 0 {
		pkgs = []string{"."}
	}
	exitStatus := 0
	pkgs = gotool.ImportPaths(pkgs)
	for _, pkg := range pkgs {
		if err := writeImports(pkg); err != nil {
			fmt.Fprintf(os.Stderr, "error: %v", err)
			exitStatus = 1
		}
	}
	os.Exit(exitStatus)
}
Пример #7
0
func main() {
	flag.Parse()
	exitStatus := 0
	importPaths := gotool.ImportPaths(flag.Args())
	if len(importPaths) == 0 {
		importPaths = []string{"."}
	}
	for _, pkgPath := range importPaths {
		visitor := &visitor{
			info: types.Info{
				Types:      make(map[ast.Expr]types.TypeAndValue),
				Defs:       make(map[*ast.Ident]types.Object),
				Selections: make(map[*ast.SelectorExpr]*types.Selection),
			},

			m:    make(map[types.Type]map[string]int),
			skip: make(map[types.Type]struct{}),
		}
		fset, astFiles := check.ASTFilesForPackage(pkgPath, *loadTestFiles)
		imp := importer.New()
		// Preliminary cgo support.
		imp.Config = importer.Config{UseGcFallback: true}
		config := types.Config{Import: imp.Import}
		var err error
		visitor.pkg, err = config.Check(pkgPath, fset, astFiles, &visitor.info)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s: %v\n", pkgPath, err)
			continue
		}
		for _, f := range astFiles {
			ast.Walk(visitor, f)
		}
		for t := range visitor.m {
			if _, skip := visitor.skip[t]; skip {
				continue
			}
			for fieldName, v := range visitor.m[t] {
				if !*reportExported && ast.IsExported(fieldName) {
					continue
				}
				if v == 0 {
					field, _, _ := types.LookupFieldOrMethod(t, false, visitor.pkg, fieldName)
					if fieldName == "XMLName" {
						if named, ok := field.Type().(*types.Named); ok && named.Obj().Pkg().Path() == "encoding/xml" {
							continue
						}
					}
					pos := fset.Position(field.Pos())
					fmt.Printf("%s: %s:%d:%d: %s.%s\n",
						pkgPath, pos.Filename, pos.Line, pos.Column,
						types.TypeString(t, nil), fieldName,
					)
					exitStatus = 1
				}
			}
		}
	}
	os.Exit(exitStatus)
}
Пример #8
0
func main() {
	// TODO(kaneda): Add a commandline flag for specifying a target type.
	targetPkg := "github.com/cockroachdb/cockroach/roachpb"
	targetTypeName := "Error"
	if err := returncheck.Run(gotool.ImportPaths(os.Args[1:]), targetPkg, targetTypeName); err != nil {
		os.Exit(1)
	}
}
Пример #9
0
func main() {
	if len(packages) == 0 {
		fmt.Fprintln(os.Stderr, "Need to specify at least one package to check.")
		flag.Usage()
		os.Exit(1)
	}

	if len(arguments)+len(returns) == 0 {
		fmt.Fprintln(os.Stderr, "Need at least one type to search for.")
		flag.Usage()
		os.Exit(1)
	}

	var typesToCheck []string
	typesToCheck = append(typesToCheck, arguments...)
	typesToCheck = append(typesToCheck, returns...)

	ctx := NewContext()
	funcs, errs := ctx.getFunctions(gotool.ImportPaths(packages))
	listErrors(errs)

	signatures := make(map[string][]string)

	for _, fnc := range funcs {
		sig, ok := fnc.Type().(*types.Signature)
		if !ok {
			// Skipping over builtins
			continue
		}

		anyArg, allArg := checkTypes(sig.Params(), arguments)
		anyRet, allRet := checkTypes(sig.Results(), returns)

		if (!and && (anyArg || anyRet)) || (and && allArg && allRet) {
			prefix := ""
			if sig.Recv() != nil {
				prefix = fmt.Sprintf("(%s %s) ", noDot(sig.Recv().Name()), sig.Recv().Type().String())
			}

			signatures[fnc.Pkg.Path()] = append(signatures[fnc.Pkg.Path()],
				fmt.Sprintf("%s%s(%s) (%s)",
					prefix,
					fnc.Name(),
					argsToString(sig.Params()),
					argsToString(sig.Results())))
		}
	}

	for _, path := range sortedKeys(signatures) {
		sigs := signatures[path]
		fmt.Println(path + ":")
		for _, sig := range sigs {
			fmt.Println("\t" + sig)
		}
		fmt.Println()
	}
}
Пример #10
0
func parseFlags(checker *errcheck.Checker, args []string) ([]string, int) {
	flags := flag.NewFlagSet(args[0], flag.ContinueOnError)
	flags.BoolVar(&checker.Blank, "blank", false, "if true, check for errors assigned to blank identifier")
	flags.BoolVar(&checker.Asserts, "asserts", false, "if true, check for ignored type assertion results")
	flags.BoolVar(&checker.WithoutTests, "ignoretests", false, "if true, checking of _test.go files is disabled")
	flags.BoolVar(&checker.Verbose, "verbose", false, "produce more verbose logging")

	flags.BoolVar(&abspath, "abspath", false, "print absolute paths to files")

	tags := tagsFlag{}
	flags.Var(&tags, "tags", "space-separated list of build tags to include")
	ignorePkg := flags.String("ignorepkg", "", "comma-separated list of package paths to ignore")
	ignore := ignoreFlag(map[string]*regexp.Regexp{
		"fmt": dotStar,
	})
	flags.Var(ignore, "ignore", "[deprecated] comma-separated list of pairs of the form pkg:regex\n"+
		"            the regex is used to ignore names within pkg.")

	var excludeFile string
	flags.StringVar(&excludeFile, "exclude", "", "Path to a file containing a list of functions to exclude from checking")

	if err := flags.Parse(args[1:]); err != nil {
		return nil, exitFatalError
	}

	if excludeFile != "" {
		exclude := make(map[string]bool)
		fh, err := os.Open(excludeFile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Could not read exclude file: %s\n", err)
			return nil, exitFatalError
		}
		scanner := bufio.NewScanner(fh)
		for scanner.Scan() {
			exclude[scanner.Text()] = true
		}
		if err := scanner.Err(); err != nil {
			fmt.Fprintf(os.Stderr, "Could not read exclude file: %s\n", err)
			return nil, exitFatalError
		}
		checker.SetExclude(exclude)
	}

	checker.Tags = tags
	for _, pkg := range strings.Split(*ignorePkg, ",") {
		if pkg != "" {
			ignore[pkg] = dotStar
		}
	}
	checker.Ignore = ignore

	// ImportPaths normalizes paths and expands '...'
	return gotool.ImportPaths(flags.Args()), exitCodeOk
}
Пример #11
0
// RemoveRepo removes go-gettable repo with no local changes (by moving it into trash).
// importPathPattern must match exactly with the repo root.
// For example, "github.com/user/repo/...".
func RemoveRepo(importPathPattern string) error {
	// TODO: Use an official Go package for `go list` functionality whenever possible.
	importPaths := gotool.ImportPaths([]string{importPathPattern})
	if len(importPaths) == 0 {
		return errors.New("no packages to remove")
	}

	var firstGoPackage *gist7480523.GoPackage
	for i, importPath := range importPaths {
		goPackage := gist7480523.GoPackageFromImportPath(importPath)
		if goPackage == nil {
			return errors.New("Import Path not found: " + importPath)
		}

		if goPackage.Bpkg.Goroot {
			return errors.New("can't remove packages from GOROOT")
		}

		goPackage.UpdateVcs()

		if goPackage.Dir.Repo == nil {
			return errors.New("can't get repo status")
		}

		if i == 0 {
			firstGoPackage = goPackage
		} else if firstGoPackage.Dir.Repo != goPackage.Dir.Repo {
			return errors.New("matched Go Packages span more than 1 repo: " + firstGoPackage.Dir.Repo.Vcs.RootPath() + " != " + goPackage.Dir.Repo.Vcs.RootPath())
		} else if !strings.HasPrefix(goPackage.Bpkg.Dir, firstGoPackage.Dir.Repo.Vcs.RootPath()) { // TODO: This is probably not neccessary...
			return errors.New("Go Package not inside repo: " + goPackage.Bpkg.Dir + " doesn't have prefix " + firstGoPackage.Dir.Repo.Vcs.RootPath())
		}
	}

	if repoImportPathPattern := gist7480523.GetRepoImportPathPattern(firstGoPackage.Dir.Repo.Vcs.RootPath(), firstGoPackage.Bpkg.SrcRoot); repoImportPathPattern != importPathPattern {
		return errors.New("importPathPattern not exact repo root match: " + importPathPattern + " != " + repoImportPathPattern)
	}

	firstGoPackage.UpdateVcsFields()

	cleanStatus := func(goPackage *gist7480523.GoPackage) bool {
		packageStatus := presenter(goPackage)[:4]
		return packageStatus == "    " || packageStatus == "  + " // Updates are okay to ignore.
	}

	if !cleanStatus(firstGoPackage) {
		return errors.New("non-clean status: " + presenter(firstGoPackage))
	}

	err := trash.MoveTo(firstGoPackage.Dir.Repo.Vcs.RootPath())
	return err

	// TODO: Clean up /pkg folder contents, if any, etc.
}
Пример #12
0
func main() {
	flag.Parse()

	serverURL, ok := os.LookupEnv(teamcityServerURLEnv)
	if !ok {
		log.Fatalf("teamcity server URL environment variable %s is not set", teamcityServerURLEnv)
	}
	u, err := url.Parse(serverURL)
	if err != nil {
		log.Fatal(err)
	}
	username, ok := os.LookupEnv(teamcityAPIUserEnv)
	if !ok {
		log.Fatalf("teamcity API username environment variable %s is not set", teamcityAPIUserEnv)
	}
	password, ok := os.LookupEnv(teamcityAPIPasswordEnv)
	if !ok {
		log.Fatalf("teamcity API password environment variable %s is not set", teamcityAPIPasswordEnv)
	}
	importPaths := gotool.ImportPaths([]string{"github.com/cockroachdb/cockroach/pkg/..."})

	client := teamcity.New(u.Host, username, password)
	// Queue a build per configuration per package.
	for _, params := range []map[string]string{
		{}, // uninstrumented
		{"env.GOFLAGS": "-race"},
		{tagsKey: "deadlock"},
	} {
		if tags, ok := params[tagsKey]; ok {
			params[tagsKey] = strings.Join([]string{tags, stressTag}, " ")
		} else {
			params[tagsKey] = stressTag
		}

		for _, propEvalKV := range []bool{true, false} {
			params["env.COCKROACH_PROPOSER_EVALUATED_KV"] = strconv.FormatBool(propEvalKV)

			for _, importPath := range importPaths {
				params["env.PKG"] = importPath

				build, err := client.QueueBuild(*buildTypeID, *branchName, params)
				if err != nil {
					log.Fatalf("failed to create teamcity build (*buildTypeID=%s *branchName=%s, params=%+v): %s", *buildTypeID, *branchName, params, err)
				}
				log.Printf("created teamcity build (*buildTypeID=%s *branchName=%s, params=%+v): %s", *buildTypeID, *branchName, params, build)
			}
		}
	}
}
Пример #13
0
func main() {
	flag.Parse()
	exitStatus = 0
	importPaths := gotool.ImportPaths(flag.Args())
	if len(importPaths) == 0 {
		importPaths = []string{"."}
	}
	for _, pkgPath := range importPaths {
		visitor := &visitor{pkgPath: pkgPath}
		fset, astFiles := check.ASTFilesForPackage(pkgPath, false)
		visitor.fset = fset
		for _, f := range astFiles {
			ast.Walk(visitor, f)
		}
	}
	os.Exit(exitStatus)
}
Пример #14
0
func expandPackages(spec []string) ([]string, error) {
	// expand "..."
	paths := gotool.ImportPaths(spec)

	var r []string
	for _, path := range paths {
		pkg, err := build.Import(path, ".", 0)
		if _, ok := err.(*build.NoGoError); ok {
			// directory with no Go source files in it
			continue
		}
		if err != nil {
			return nil, err
		}
		if pkg.ImportPath == "" {
			return nil, fmt.Errorf("no import path found: %v", path)
		}
		r = append(r, pkg.ImportPath)
	}
	return r, nil
}
Пример #15
0
func main() {
	dotStar := regexp.MustCompile(".*")

	ignore := ignoreFlag(make(map[string]*regexp.Regexp))
	flag.Var(ignore, "ignore", "comma-separated list of pairs of the form pkg:regex\n"+
		"            the regex is used to ignore names within pkg")
	ignorePkg := flag.String("ignorepkg", "", "comma-separated list of package paths to ignore")
	blank := flag.Bool("blank", false, "if true, check for errors assigned to blank identifier")
	flag.Parse()

	for _, pkg := range strings.Split(*ignorePkg, ",") {
		if pkg != "" {
			ignore[pkg] = dotStar
		}
	}

	if _, ok := ignore["fmt"]; !ok {
		ignore["fmt"] = dotStar
	}

	var exitStatus int
	for _, pkgPath := range gotool.ImportPaths(flag.Args()) {
		if err := errcheck.CheckPackage(pkgPath, ignore, *blank); err != nil {
			if e, ok := err.(errcheck.UncheckedErrors); ok {
				for _, uncheckedError := range e.Errors {
					fmt.Println(uncheckedError)
				}
				exitStatus = 1
				continue
			} else if err == errcheck.ErrNoGoFiles {
				fmt.Fprintln(os.Stderr, err)
				continue
			}
			Fatalf("failed to check package %s: %s", pkgPath, err)
		}
	}
	os.Exit(exitStatus)
}
Пример #16
0
func main() {
	flag.Usage = func() {
		os.Stderr.WriteString(helpMessage)
		flag.PrintDefaults()
		os.Exit(2)
	}
	flag.Parse()
	pkgs := flag.Args()
	if len(pkgs) == 0 {
		pkgs = []string{"."}
	}
	if d, err := os.Getwd(); err != nil {
		log.Fatalf("cannot get working directory: %v", err)
	} else {
		cwd = d
	}
	pkgs = gotool.ImportPaths(pkgs)
	allPkgs := make(map[string][]string)
	for _, pkg := range pkgs {
		if err := findImports(pkg, allPkgs); err != nil {
			log.Fatalf("cannot find imports from %q: %v", pkg, err)
		}
	}
	result := make([]string, 0, len(allPkgs))
	for name := range allPkgs {
		result = append(result, name)
	}
	sort.Strings(result)
	for _, r := range result {
		if *from {
			sort.Strings(allPkgs[r])
			fmt.Printf("%s %s\n", r, strings.Join(allPkgs[r], " "))
		} else {
			fmt.Println(r)
		}
	}
}
Пример #17
0
func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "%s\n", usage)
		flag.PrintDefaults()
		os.Exit(2)
	}
	flag.Parse()
	if *revFile != "" {
		if flag.NArg() != 0 {
			flag.Usage()
		}
		update(*revFile)
	} else {
		pkgs := flag.Args()
		if len(pkgs) == 0 {
			pkgs = []string{"."}
		}
		pkgs = gotool.ImportPaths(pkgs)
		for _, info := range list(pkgs, *testDeps) {
			fmt.Println(info)
		}
	}
	os.Exit(exitCode)
}
Пример #18
0
func multibuild(packages []string) (error, int) {
	// parse the names of the paths/packages provided on the command-line
	pkgs := gotool.ImportPaths(packages)

	// parse the main package: we need the package name and the path
	mainpkg, err := build.Import(pkgs[0], ".", 0)
	if err != nil {
		return fmt.Errorf("unable to import main package %s: %s", pkgs[0], err), -2
	}

	// create the linker file in the main package directory, so that it will be
	// compiled and linked with the main package when we `go build` is invoked
	// the linker file is a go file in the same package of the main package that
	// imports all additional packages (normally for their side-effects)
	tmpFile, err := ioutil.TempFile(mainpkg.Dir, "pluggo")
	if err != nil {
		return fmt.Errorf("unable to create temporary file: %s", err), -3
	}

	fmt.Fprintf(tmpFile, "package %s\n", mainpkg.Name)
	for _, pkgname := range pkgs[1:] {
		fmt.Fprintf(tmpFile, "import _ \"%s\"\n", pkgname)
	}

	tmpFile.Close()
	os.Rename(tmpFile.Name(), tmpFile.Name()+".go")
	defer os.Remove(tmpFile.Name() + ".go")

	// run go build on the main package
	output, err := exec.Command("go", "build", packages[0]).CombinedOutput()
	if err != nil {
		return fmt.Errorf("error executing go build: %s\ngo build output:\n%s", err, string(output)), -4
	}

	return nil, 0
}
Пример #19
0
func main() {
	flag.Usage = func() {
		os.Stderr.WriteString(helpMessage)
		flag.PrintDefaults()
		os.Exit(2)
	}
	flag.Parse()
	pkgs := flag.Args()
	if len(pkgs) == 0 {
		pkgs = []string{"."}
	}
	if d, err := os.Getwd(); err != nil {
		log.Fatalf("cannot get working directory: %v", err)
	} else {
		cwd = d
	}
	if *why != "" {
		*all = true
		*from = true
		if isStdlib(*why) {
			*std = true
		}
		whyMatch = matchPattern(*why)
	}

	pkgs = gotool.ImportPaths(pkgs)
	rootPkgs := make(map[string]bool)
	for _, pkg := range pkgs {
		p, err := build.Default.Import(pkg, cwd, build.FindOnly)
		if err != nil {
			log.Fatalf("cannot find %q: %v", pkg, err)
		}
		rootPkgs[p.ImportPath] = true
	}

	allPkgs := make(map[string][]string)
	for _, pkg := range pkgs {
		if err := findImports(pkg, allPkgs, rootPkgs); err != nil {
			log.Fatalf("cannot find imports from %q: %v", pkg, err)
		}
	}
	if !*files {
		// Delete packages specified directly on the command line.
		for pkg := range rootPkgs {
			delete(allPkgs, pkg)
		}
		if whyMatch != nil {
			// Delete all packages that don't directly or indirectly import *why.
			marked := make(map[string]bool)
			for pkg := range allPkgs {
				if whyMatch(pkg) {
					markImporters(pkg, allPkgs, marked)
				}
			}
			for pkg := range allPkgs {
				if !marked[pkg] {
					delete(allPkgs, pkg)
				}
			}
		}
	}

	result := make([]string, 0, len(allPkgs))
	for name := range allPkgs {
		result = append(result, name)
	}
	w := bufio.NewWriter(os.Stdout)
	defer w.Flush()
	sort.Strings(result)
	for _, r := range result {
		switch {
		case *files:
			pkg, _ := build.Default.Import(r, cwd, 0)
			showFiles(w, pkg, pkg.GoFiles)
			showFiles(w, pkg, pkg.CgoFiles)
			if rootPkgs[pkg.ImportPath] && !*noTestDeps {
				// It's a package specified directly on the command line.
				// Show its test files too.
				showFiles(w, pkg, pkg.TestGoFiles)
				showFiles(w, pkg, pkg.XTestGoFiles)
			}
		case *from:
			from := allPkgs[r]
			sort.Strings(from)
			from = uniq(from)
			fmt.Fprintf(w, "%s %s\n", r, strings.Join(from, " "))
		default:
			fmt.Fprintln(w, r)
		}
	}
}
Пример #20
0
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	flag.Usage = usage
	flag.Parse()

	// Get current directory.
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}

	shouldShow := func(goPackage *gist7480523.GoPackage) bool {
		// Check for notable status.
		return status.PorcelainPresenter(goPackage)[:4] != "    "
	}
	if *vFlag == true {
		shouldShow = func(_ *gist7480523.GoPackage) bool { return true }
	}

	var presenter gist7480523.GoPackageStringer = status.PorcelainPresenter
	if *debugFlag == true {
		presenter = status.DebugPresenter
	} else if *plumbingFlag == true {
		presenter = status.PlumbingPresenter
	}

	// A map of repos that have been checked, to avoid doing same repo more than once.
	var lock sync.Mutex
	checkedRepos := map[string]bool{}

	// Input: Go package Import Path
	// Output: If a valid Go package and not inside GOROOT, output a status string, else nil.
	reduceFunc := func(in string) interface{} {
		goPackage, err := gist7480523.GoPackageFromPath(in, wd)
		if err != nil {
			fmt.Fprintf(os.Stderr, "can't load package: %s\n", err)
			return nil
		}
		if goPackage == nil {
			return nil
		}
		if goPackage.Bpkg.Goroot {
			return nil
		}

		goPackage.UpdateVcs()
		// Check that the same repo hasn't already been done.
		if goPackage.Dir.Repo != nil {
			rootPath := goPackage.Dir.Repo.Vcs.RootPath()
			lock.Lock()
			if !checkedRepos[rootPath] {
				checkedRepos[rootPath] = true
				lock.Unlock()
			} else {
				lock.Unlock()
				// Skip repos that were done.
				return nil
			}
		}

		goPackage.UpdateVcsFields()

		if shouldShow(goPackage) == false {
			return nil
		}
		return presenter(goPackage)
	}

	// Run reduceFunc on all import paths in parallel.
	var outChan <-chan interface{}
	switch *stdinFlag {
	case false:
		importPathPatterns := flag.Args()
		importPaths := gotool.ImportPaths(importPathPatterns)
		outChan = gist7651991.GoReduceLinesFromSlice(importPaths, numWorkers, reduceFunc)
	case true:
		outChan = gist7651991.GoReduceLinesFromReader(os.Stdin, numWorkers, reduceFunc)
	}

	// Output results.
	for out := range outChan {
		fmt.Println(out.(string))
	}
}
Пример #21
0
// Natives augment the standard library with GopherJS-specific changes.
// This test ensures that none of the standard library packages are modified
// in a way that adds imports which the original upstream standard library package
// does not already import. Doing that can increase generated output size or cause
// other unexpected issues (since the cmd/go tool does not know about these extra imports),
// so it's best to avoid it.
//
// It checks all standard library packages. Each package is considered as a normal
// package, as a test package, and as an external test package.
func TestNativesDontImportExtraPackages(t *testing.T) {
	// Calculate the forward import graph for all standard library packages.
	// It's needed for populateImportSet.
	stdOnly := gobuild.Default
	stdOnly.GOPATH = "" // We only care about standard library, so skip all GOPATH packages.
	forward, _, err := importgraphutil.BuildNoTests(&stdOnly)
	if err != nil {
		t.Fatalf("importgraphutil.BuildNoTests: %v", err)
	}

	// populateImportSet takes a slice of imports, and populates set with those
	// imports, as well as their transitive dependencies. That way, the set can
	// be quickly queried to check if a package is in the import graph of imports.
	//
	// Note, this does not include transitive imports of test/xtest packages,
	// which could cause some false positives. It currently doesn't, but if it does,
	// then support for that should be added here.
	populateImportSet := func(imports []string, set *stringSet) {
		for _, p := range imports {
			(*set)[p] = struct{}{}
			switch p {
			case "sync":
				(*set)["github.com/gopherjs/gopherjs/nosync"] = struct{}{}
			}
			transitiveImports := forward.Search(p)
			for p := range transitiveImports {
				(*set)[p] = struct{}{}
			}
		}
	}

	// Check all standard library packages.
	//
	// The general strategy is to first import each standard library package using the
	// normal build.Import, which returns a *build.Package. That contains Imports, TestImports,
	// and XTestImports values that are considered the "real imports".
	//
	// That list of direct imports is then expanded to the transitive closure by populateImportSet,
	// meaning all packages that are indirectly imported are also added to the set.
	//
	// Then, github.com/gopherjs/gopherjs/build.parseAndAugment(*build.Package) returns []*ast.File.
	// Those augmented parsed Go files of the package are checked, one file at at time, one import
	// at a time. Each import is verified to belong in the set of allowed real imports.
	for _, pkg := range gotool.ImportPaths([]string{"std"}) {
		// Normal package.
		{
			// Import the real normal package, and populate its real import set.
			bpkg, err := gobuild.Import(pkg, "", gobuild.ImportComment)
			if err != nil {
				t.Fatalf("gobuild.Import: %v", err)
			}
			realImports := make(stringSet)
			populateImportSet(bpkg.Imports, &realImports)

			// Use parseAndAugment to get a list of augmented AST files.
			fset := token.NewFileSet()
			files, err := parseAndAugment(bpkg, false, fset)
			if err != nil {
				t.Fatalf("github.com/gopherjs/gopherjs/build.parseAndAugment: %v", err)
			}

			// Verify imports of normal augmented AST files.
			for _, f := range files {
				fileName := fset.File(f.Pos()).Name()
				normalFile := !strings.HasSuffix(fileName, "_test.go")
				if !normalFile {
					continue
				}
				for _, imp := range f.Imports {
					importPath, err := strconv.Unquote(imp.Path.Value)
					if err != nil {
						t.Fatalf("strconv.Unquote(%v): %v", imp.Path.Value, err)
					}
					if importPath == "github.com/gopherjs/gopherjs/js" {
						continue
					}
					if _, ok := realImports[importPath]; !ok {
						t.Errorf("augmented normal package %q imports %q in file %v, but real %q doesn't:\nrealImports = %v", bpkg.ImportPath, importPath, fileName, bpkg.ImportPath, realImports)
					}
				}
			}
		}

		// Test package.
		{
			// Import the real test package, and populate its real import set.
			bpkg, err := gobuild.Import(pkg, "", gobuild.ImportComment)
			if err != nil {
				t.Fatalf("gobuild.Import: %v", err)
			}
			realTestImports := make(stringSet)
			populateImportSet(bpkg.TestImports, &realTestImports)

			// Use parseAndAugment to get a list of augmented AST files.
			fset := token.NewFileSet()
			files, err := parseAndAugment(bpkg, true, fset)
			if err != nil {
				t.Fatalf("github.com/gopherjs/gopherjs/build.parseAndAugment: %v", err)
			}

			// Verify imports of test augmented AST files.
			for _, f := range files {
				fileName, pkgName := fset.File(f.Pos()).Name(), f.Name.String()
				testFile := strings.HasSuffix(fileName, "_test.go") && !strings.HasSuffix(pkgName, "_test")
				if !testFile {
					continue
				}
				for _, imp := range f.Imports {
					importPath, err := strconv.Unquote(imp.Path.Value)
					if err != nil {
						t.Fatalf("strconv.Unquote(%v): %v", imp.Path.Value, err)
					}
					if importPath == "github.com/gopherjs/gopherjs/js" {
						continue
					}
					if _, ok := realTestImports[importPath]; !ok {
						t.Errorf("augmented test package %q imports %q in file %v, but real %q doesn't:\nrealTestImports = %v", bpkg.ImportPath, importPath, fileName, bpkg.ImportPath, realTestImports)
					}
				}
			}
		}

		// External test package.
		{
			// Import the real external test package, and populate its real import set.
			bpkg, err := gobuild.Import(pkg, "", gobuild.ImportComment)
			if err != nil {
				t.Fatalf("gobuild.Import: %v", err)
			}
			realXTestImports := make(stringSet)
			populateImportSet(bpkg.XTestImports, &realXTestImports)

			// Add _test suffix to import path to cause parseAndAugment to use external test mode.
			bpkg.ImportPath += "_test"

			// Use parseAndAugment to get a list of augmented AST files, then check only the external test files.
			fset := token.NewFileSet()
			files, err := parseAndAugment(bpkg, true, fset)
			if err != nil {
				t.Fatalf("github.com/gopherjs/gopherjs/build.parseAndAugment: %v", err)
			}

			// Verify imports of external test augmented AST files.
			for _, f := range files {
				fileName, pkgName := fset.File(f.Pos()).Name(), f.Name.String()
				xTestFile := strings.HasSuffix(fileName, "_test.go") && strings.HasSuffix(pkgName, "_test")
				if !xTestFile {
					continue
				}
				for _, imp := range f.Imports {
					importPath, err := strconv.Unquote(imp.Path.Value)
					if err != nil {
						t.Fatalf("strconv.Unquote(%v): %v", imp.Path.Value, err)
					}
					if importPath == "github.com/gopherjs/gopherjs/js" {
						continue
					}
					if _, ok := realXTestImports[importPath]; !ok {
						t.Errorf("augmented external test package %q imports %q in file %v, but real %q doesn't:\nrealXTestImports = %v", bpkg.ImportPath, importPath, fileName, bpkg.ImportPath, realXTestImports)
					}
				}
			}
		}
	}
}
Пример #22
0
func main() {
	vPtr := flag.Bool("v", false, "verbose output (outputs recommended alignments)")
	flag.Parse()
	exitStatus := 0

	importPaths := gotool.ImportPaths(flag.Args())
	if len(importPaths) == 0 {
		importPaths = []string{"."}
	}

	ctx := build.Default
	loadcfg := loader.Config{
		Build: &ctx,
	}
	rest, err := loadcfg.FromArgs(importPaths, false)
	if err != nil {
		log.Fatalf("could not parse arguments: %s", err)
	}
	if len(rest) > 0 {
		log.Fatalf("unhandled extra arguments: %v", rest)
	}

	program, err := loadcfg.Load()
	if err != nil {
		log.Fatalf("could not type check: %s", err)
	}

	var lines []string

	for _, pkgInfo := range program.InitialPackages() {
		for _, obj := range pkgInfo.Defs {
			if obj == nil {
				continue
			}

			if _, ok := obj.(*types.TypeName); !ok {
				continue
			}

			typ, ok := obj.Type().(*types.Named)
			if !ok {
				continue
			}

			strukt, ok := typ.Underlying().(*types.Struct)
			if !ok {
				continue
			}

			structAlign := int(stdSizes.Alignof(strukt))
			structSize := int(stdSizes.Sizeof(strukt))
			if structSize%structAlign != 0 {
				structSize += structAlign - structSize%structAlign
			}

			fields := make(fieldList, 0, strukt.NumFields())
			minSize := 0
			for i := 0; i < strukt.NumFields(); i++ {
				field := strukt.Field(i)
				fieldType := field.Type()
				typeSize := int(stdSizes.Sizeof(fieldType))
				minSize += typeSize
				fields = append(fields, structField{
					name: field.Name(),
					size: typeSize,
				})
			}
			if minSize%structAlign != 0 {
				minSize += structAlign - minSize%structAlign
			}

			if minSize != structSize {
				pos := program.Fset.Position(obj.Pos())
				fieldLines := make([]string, 0, len(fields))
				sort.Sort(fields)
				for _, v := range fields {
					fieldLines = append(fieldLines, fmt.Sprintf(
						"\t\t%s (size %d)",
						v.name,
						v.size,
					))
				}
				line := fmt.Sprintf(
					"%s: %s:%d:%d: struct %s could have size %d (currently %d)",
					obj.Pkg().Path(),
					pos.Filename,
					pos.Line,
					pos.Column,
					obj.Name(),
					minSize,
					structSize,
				)
				if *vPtr {
					line = line + fmt.Sprintf(
						":\n\tRecommended alignment:\n%s",
						strings.Join(fieldLines, "\n"),
					)
				}
				lines = append(lines, line)
				exitStatus = 1
			}
		}
	}

	sort.Strings(lines)
	for _, line := range lines {
		fmt.Println(line)
	}

	os.Exit(exitStatus)
}
Пример #23
0
func main() {
	flag.Usage = usage
	flag.Parse()

	var shouldShow RepoFilter
	switch {
	default:
		shouldShow = func(r *Repo) bool {
			// Check for notable status.
			return PorcelainPresenter(r)[:4] != "    "
		}
	case *vFlag:
		shouldShow = func(*Repo) bool { return true }
	}

	var presenter RepoPresenter
	switch {
	case *debugFlag:
		presenter = DebugPresenter
	default:
		presenter = PorcelainPresenter
	}

	workspace := NewWorkspace(shouldShow, presenter)

	// Feed input into workspace processing pipeline.
	switch *stdinFlag {
	case false:
		go func() { // This needs to happen in the background because sending input will be blocked on processing and receiving output.
			importPathPatterns := flag.Args()
			importPaths := gotool.ImportPaths(importPathPatterns)
			for _, importPath := range importPaths {
				workspace.ImportPaths <- importPath
			}
			close(workspace.ImportPaths)
		}()
	case true:
		go func() { // This needs to happen in the background because sending input will be blocked on processing and receiving output.
			br := bufio.NewReader(os.Stdin)
			for line, err := br.ReadString('\n'); err == nil; line, err = br.ReadString('\n') {
				importPath := line[:len(line)-1] // Trim last newline.
				workspace.ImportPaths <- importPath
			}
			close(workspace.ImportPaths)
		}()
	}

	// Output results.
	for workspace.Statuses != nil || workspace.Errors != nil {
		select {
		case status, ok := <-workspace.Statuses:
			if !ok {
				workspace.Statuses = nil
				continue
			}
			fmt.Println(status)
		case error, ok := <-workspace.Errors:
			if !ok {
				workspace.Errors = nil
				continue
			}
			fmt.Fprintln(os.Stderr, error)
		}
	}
}
Пример #24
0
func main() {
	flag.Parse()
	exitStatus := 0

	importPaths := gotool.ImportPaths(flag.Args())
	if len(importPaths) == 0 {
		importPaths = []string{"."}
	}

	ctx := build.Default
	loadcfg := loader.Config{
		Build: &ctx,
	}
	rest, err := loadcfg.FromArgs(importPaths, false)
	if err != nil {
		log.Fatalf("could not parse arguments: %s", err)
	}
	if len(rest) > 0 {
		log.Fatalf("unhandled extra arguments: %v", rest)
	}

	program, err := loadcfg.Load()
	if err != nil {
		log.Fatalf("could not type check: %s", err)
	}

	var lines []string

	for _, pkgInfo := range program.InitialPackages() {
		for _, obj := range pkgInfo.Defs {
			if obj == nil {
				continue
			}

			if _, ok := obj.(*types.TypeName); !ok {
				continue
			}

			typ, ok := obj.Type().(*types.Named)
			if !ok {
				continue
			}

			strukt, ok := typ.Underlying().(*types.Struct)
			if !ok {
				continue
			}

			structAlign := int(stdSizes.Alignof(strukt))
			structSize := int(stdSizes.Sizeof(strukt))
			if structSize%structAlign != 0 {
				structSize += structAlign - structSize%structAlign
			}

			minSize := 0
			for i := 0; i < strukt.NumFields(); i++ {
				field := strukt.Field(i)
				fieldType := field.Type()
				typeSize := int(stdSizes.Sizeof(fieldType))
				minSize += typeSize
			}
			if minSize%structAlign != 0 {
				minSize += structAlign - minSize%structAlign
			}

			if minSize != structSize {
				pos := program.Fset.Position(obj.Pos())
				lines = append(lines, fmt.Sprintf(
					"%s: %s:%d:%d: struct %s could have size %d (currently %d)",
					obj.Pkg().Path(),
					pos.Filename,
					pos.Line,
					pos.Column,
					obj.Name(),
					minSize,
					structSize,
				))
				exitStatus = 1
			}
		}
	}

	sort.Strings(lines)
	for _, line := range lines {
		fmt.Println(line)
	}

	os.Exit(exitStatus)
}
Пример #25
0
func main() {
	flag.Parse()
	exitStatus := 0
	importPaths := gotool.ImportPaths(flag.Args())
	if len(importPaths) == 0 {
		importPaths = []string{"."}
	}

	ctx := build.Default
	loadcfg := loader.Config{
		Build: &ctx,
	}
	rest, err := loadcfg.FromArgs(importPaths, true)
	if err != nil {
		log.Fatalf("could not parse arguments: %s", err)
	}
	if len(rest) > 0 {
		log.Fatalf("unhandled extra arguments: %v", rest)
	}

	program, err := loadcfg.Load()
	if err != nil {
		log.Fatalf("could not type check: %s", err)
	}

	uses := make(map[object]int)
	positions := make(map[object]token.Position)

	for _, pkgInfo := range program.InitialPackages() {
		if pkgInfo.Pkg.Path() == "unsafe" {
			continue
		}

		v := &visitor{
			prog:      program,
			pkg:       pkgInfo,
			uses:      uses,
			positions: positions,
		}

		for _, f := range v.pkg.Files {
			ast.Walk(v, f)
		}
	}

	var lines []string

	for obj, useCount := range uses {
		if useCount == 0 && (*reportExported || !ast.IsExported(obj.name)) {
			pos := positions[obj]
			lines = append(lines, fmt.Sprintf("%s: %s:%d:%d: %s", obj.pkgPath, pos.Filename, pos.Line, pos.Column, obj.name))
			exitStatus = 1
		}
	}

	sort.Strings(lines)
	for _, line := range lines {
		fmt.Println(line)
	}

	os.Exit(exitStatus)
}
Пример #26
0
func main() {
	flag.Parse()
	exitStatus := 0
	importPaths := gotool.ImportPaths(flag.Args())
	if len(importPaths) == 0 {
		importPaths = []string{"."}
	}
	ctx := build.Default
	for _, pkgPath := range importPaths {
		visitor := &visitor{
			m:    make(map[types.Type]map[string]int),
			skip: make(map[types.Type]struct{}),
		}
		loadcfg := loader.Config{
			Build: &ctx,
		}
		rest, err := loadcfg.FromArgs([]string{pkgPath}, *loadTestFiles)
		if err != nil {
			fmt.Fprintf(os.Stderr, "could not parse arguments: %s", err)
			continue
		}
		if len(rest) > 0 {
			fmt.Fprintf(os.Stderr, "unhandled extra arguments: %v", rest)
			continue
		}

		program, err := loadcfg.Load()
		if err != nil {
			fmt.Fprintf(os.Stderr, "could not type check: %s", err)
			continue
		}

		pkg := program.InitialPackages()[0]
		visitor.prog = program
		visitor.pkg = pkg
		for _, f := range pkg.Files {
			ast.Walk(visitor, f)
		}

		for t := range visitor.m {
			if _, skip := visitor.skip[t]; skip {
				continue
			}
			for fieldName, v := range visitor.m[t] {
				if !*reportExported && ast.IsExported(fieldName) {
					continue
				}
				if v == 0 {
					field, _, _ := types.LookupFieldOrMethod(t, false, pkg.Pkg, fieldName)
					if fieldName == "XMLName" {
						if named, ok := field.Type().(*types.Named); ok && named.Obj().Pkg().Path() == "encoding/xml" {
							continue
						}
					}
					pos := program.Fset.Position(field.Pos())
					fmt.Printf("%s: %s:%d:%d: %s.%s\n",
						pkgPath, pos.Filename, pos.Line, pos.Column,
						types.TypeString(t, nil), fieldName,
					)
					exitStatus = 1
				}
			}
		}
	}
	os.Exit(exitStatus)
}