main.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package main
  2. import (
  3. "fmt"
  4. "go/ast"
  5. "go/parser"
  6. "go/token"
  7. "log"
  8. "os"
  9. "os/exec"
  10. "path/filepath"
  11. "sort"
  12. "strings"
  13. )
  14. func pkgName(f string) string {
  15. file, err := parser.ParseFile(token.NewFileSet(), f, nil, parser.PackageClauseOnly)
  16. if err != nil || file == nil {
  17. return ""
  18. }
  19. return file.Name.Name
  20. }
  21. func isGoFile(dir os.FileInfo) bool {
  22. return !dir.IsDir() &&
  23. !strings.HasPrefix(dir.Name(), ".") && // ignore .files
  24. filepath.Ext(dir.Name()) == ".go"
  25. }
  26. func isPkgFile(dir os.FileInfo) bool {
  27. return isGoFile(dir) && !strings.HasSuffix(dir.Name(), "_test.go") // ignore test files
  28. }
  29. func parseDir(p string) (map[string]*ast.Package, error) {
  30. isGoFile := func(d os.FileInfo) bool {
  31. return !d.IsDir() && !strings.HasSuffix(d.Name(), "_test.go") && !strings.HasPrefix(d.Name(), "example_")
  32. }
  33. pkgs, err := parser.ParseDir(token.NewFileSet(), p, isGoFile, parser.ParseComments)
  34. if err != nil {
  35. return nil, err
  36. }
  37. return pkgs, nil
  38. }
  39. func main() {
  40. pkg := "flag"
  41. if len(os.Args) == 2 {
  42. pkg = os.Args[1]
  43. }
  44. b, err := exec.Command("go", "env", "GOROOT").CombinedOutput()
  45. if err != nil {
  46. log.Fatal(err)
  47. }
  48. paths := []string{filepath.Join(strings.TrimSpace(string(b)), "src")}
  49. b, err = exec.Command("go", "env", "GOPATH").CombinedOutput()
  50. if err != nil {
  51. log.Fatal(err)
  52. }
  53. for _, p := range strings.Split(strings.TrimSpace(string(b)), string(filepath.ListSeparator)) {
  54. paths = append(paths, filepath.Join(p, "src"))
  55. }
  56. for _, p := range paths {
  57. pp := filepath.Join(p, pkg)
  58. pkgs, err := parseDir(pp)
  59. if err != nil || len(pkgs) == 0 {
  60. continue
  61. }
  62. names := map[string]bool{}
  63. pn := pkg
  64. for _, pp := range pkgs {
  65. pn = pp.Name
  66. for _, f := range pp.Files {
  67. for _, d := range f.Decls {
  68. switch decl := d.(type) {
  69. case *ast.GenDecl:
  70. for _, spec := range decl.Specs {
  71. if vspec, ok := spec.(*ast.ValueSpec); ok {
  72. for _, n := range vspec.Names {
  73. c := n.Name[0]
  74. if c < 'A' || c > 'Z' {
  75. continue
  76. }
  77. names[n.Name] = true
  78. }
  79. }
  80. }
  81. case *ast.FuncDecl:
  82. if decl.Recv != nil {
  83. continue
  84. }
  85. c := decl.Name.Name[0]
  86. if c < 'A' || c > 'Z' {
  87. continue
  88. }
  89. names[decl.Name.Name] = true
  90. }
  91. }
  92. }
  93. }
  94. keys := []string{}
  95. for k := range names {
  96. keys = append(keys, k)
  97. }
  98. sort.Strings(keys)
  99. fmt.Printf(`// Package %s implements %s interface for anko script.
  100. package %s
  101. import (
  102. "%s"
  103. )
  104. func init() {
  105. Packages["%s"] = map[string]interface{}{
  106. `, pn, pkg, pn, pkg, pn)
  107. for _, k := range keys {
  108. fmt.Printf(` "%s": %s.%s,`+"\n", k, pn, k)
  109. }
  110. fmt.Println(` }
  111. }`)
  112. }
  113. }