[
  {
    "path": "README.md",
    "content": "# GoImportDot\n\n## What is GoImportDot ?\n\nGoImportDot is a tiny tool to generate a `dot` file (used for Graphviz) of imports of golang package.It has two purpose.\n\n* Help people quickly understand how a package organization without going into details of code.\n* Help people find out whether a package is too confusing and needs to be refactored.\n\n## Quick Start\n\n```\ngo get -u github.com/yqylovy/goimportdot\ngoimportdot -pkg=yourpackagename > pkg.dot \ndot -Tsvg pkg.dot >pkg.svg\n```\n\n## Example\n\nInstall `go.uber.org/zap`\n\n```\ngo get go.uber.org/zap\n```\n\nGet a graph of `go.uber.org/zap`\n\n```\ngoimportdot -pkg=go.uber.org/zap > zap.dot\ndot -Tpng zap.dot > zap.png\n```\n\n![zap](./docs/zap.png)\n\n\nOnly get a graph of zapcore in `go.uber.org/zap`\n\n```\ngoimportdot -pkg=go.uber.org/zap -root=go.uber.org/zap/zapcore > zapcore.dot\ndot -Tpng zapcore.dot > zapcore.png\n```\n\n![zap](./docs/zapcore.png)\n"
  },
  {
    "path": "core/file_filter.go",
    "content": "package core\n\nimport (\n\t\"os\"\n\t\"strings\"\n)\n\ntype FileFilter struct {\n\tIsBlack bool\n\tFunc    func(fp string, info os.FileInfo, err error) bool\n}\n\nfunc NameContains(isblack bool, str string) FileFilter {\n\treturn FileFilter{\n\t\tIsBlack: isblack,\n\t\tFunc: func(fp string, _ os.FileInfo, _ error) bool {\n\t\t\treturn strings.Contains(fp, str)\n\t\t},\n\t}\n}\nfunc HasSuffix(isblack bool, suffixs ...string) FileFilter {\n\treturn FileFilter{\n\t\tIsBlack: isblack,\n\t\tFunc: func(fp string, _ os.FileInfo, _ error) bool {\n\t\t\tfor _, sf := range suffixs {\n\t\t\t\tif sf == \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif sf[0] != '.' {\n\t\t\t\t\tsf = \".\" + sf\n\t\t\t\t}\n\t\t\t\tif strings.HasSuffix(fp, sf) {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "core/imps.go",
    "content": "package core\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nfunc GetImports(pkg string, filters ...FileFilter) (pkgimports map[string]StrSet, err error) {\n\tfullpath := \"\"\n\n\tgoPath := os.Getenv(\"GOPATH\")\n\tgopaths := strings.Split(goPath, \":\")\n\tfor _, gp := range gopaths {\n\t\tfp := filepath.Join(gp, \"src\", pkg)\n\t\tif _, err := os.Stat(fp); err == nil {\n\t\t\tfullpath = fp\n\t\t}\n\t}\n\tif fullpath == \"\" {\n\t\terr = fmt.Errorf(\"Can not find package [%s] in GOPATH [%s]\", pkg, goPath)\n\t\treturn\n\t}\n\tpkgimports = make(map[string]StrSet)\n\tfilepath.Walk(fullpath, func(fp string, info os.FileInfo, err error) error {\n\t\tif info.IsDir() {\n\t\t\treturn nil\n\t\t}\n\t\tfor _, filter := range filters {\n\t\t\tif !filter.IsBlack {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif filter.Func(fp, info, err) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfor _, filter := range filters {\n\t\t\tif filter.IsBlack {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif !filter.Func(fp, info, err) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tpkg := PkgOfFile(fp)\n\t\tif _, ok := pkgimports[pkg]; !ok {\n\t\t\tpkgimports[pkg] = NewStrSet()\n\t\t}\n\t\tss, err := ParseGoImport(fp)\n\t\tif err != nil {\n\t\t\t// TODO: better err\n\t\t\tpanic(err)\n\t\t}\n\t\tpkgimports[pkg].Merge(ss)\n\t\treturn nil\n\t})\n\treturn\n}\n\nfunc WriteDot(pkgimports map[string]StrSet, writer io.Writer) (err error) {\n\tnodes := NewStrSet()\n\tedges := [][2]string{}\n\tfor pkg, imps := range pkgimports {\n\t\tnodes.Put(pkg)\n\t\tfor imp := range imps {\n\t\t\tnodes.Put(imp)\n\t\t\tedges = append(edges, [2]string{pkg, imp})\n\t\t}\n\t}\n\tbuf := bytes.NewBuffer([]byte{})\n\tbuf.WriteString(\"digraph G {\\n\")\n\tfor _, edge := range edges {\n\t\tbuf.WriteString(fmt.Sprintf(`\"%s\"->\"%s\";`, edge[0], edge[1]))\n\t\tbuf.WriteByte('\\n')\n\t}\n\tfor pkg, _ := range nodes {\n\t\tbuf.WriteString(fmt.Sprintf(`\"%s\";`, pkg))\n\t\tbuf.WriteByte('\\n')\n\t}\n\tbuf.WriteString(\"}\\n\")\n\t_, err = writer.Write(buf.Bytes())\n\treturn\n}\n"
  },
  {
    "path": "core/imps_test.go",
    "content": "package core\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/smartystreets/goconvey/convey\"\n)\n\nfunc TestGetImports(t *testing.T) {\n\tConvey(\"Test GetImports\", t, func() {\n\t\t_, err := GetImports(\"go.uber.org/zap\",\n\t\t\tNameContains(true, \".git\"),\n\t\t\tNameContains(true, \"_test.go\"),\n\t\t\tHasSuffix(false, \".go\"))\n\t\tSo(err, ShouldBeNil)\n\t})\n}\n"
  },
  {
    "path": "core/pkg_filter.go",
    "content": "package core\n\nimport (\n\t\"regexp\"\n\n\t\"strings\"\n)\n\ntype PkgFilter func(map[string]StrSet) map[string]StrSet\n\nfunc RootFilter(root string) PkgFilter {\n\treturn func(imps map[string]StrSet) (ret map[string]StrSet) {\n\t\tret = make(map[string]StrSet)\n\t\tcur := []string{root}\n\t\tfor len(cur) > 0 {\n\t\t\tnewcur := NewStrSet()\n\t\t\tfor _, pkg := range cur {\n\t\t\t\tif pkgimp, ok := imps[pkg]; ok {\n\t\t\t\t\tret[pkg] = pkgimp\n\t\t\t\t\tnewcur.Merge(pkgimp)\n\t\t\t\t}\n\t\t\t}\n\t\t\tcur = newcur.Array()\n\t\t}\n\t\treturn ret\n\t}\n}\n\nfunc PkgWildcardFilter(isBlack bool, pkgs ...string) PkgFilter {\n\tregs := []*regexp.Regexp{}\n\tfor _, pkg := range pkgs {\n\t\trgp := regexp.MustCompile(\"^\" + strings.Replace(pkg, \"*\", \".*\", -1) + \"$\")\n\t\tregs = append(regs, rgp)\n\t}\n\treturn func(imps map[string]StrSet) (ret map[string]StrSet) {\n\t\tret = make(map[string]StrSet)\n\tBIG:\n\t\tfor pkg, imps := range imps {\n\t\t\tfor _, rgp := range regs {\n\t\t\t\tif isBlack == rgp.MatchString(pkg) {\n\t\t\t\t\tcontinue BIG\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor k := range imps {\n\t\t\t\tfor _, rgp := range regs {\n\t\t\t\t\tif isBlack == rgp.MatchString(k) {\n\t\t\t\t\t\timps.Del(k)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tret[pkg] = imps\n\t\t}\n\t\treturn ret\n\t}\n}\n\nfunc ParsePkgWildcardStr(str string) (fs []PkgFilter, err error) {\n\tif str == \"\" {\n\t\treturn\n\t}\n\tstrArr := strings.Split(str, \";\")\n\tfor _, str := range strArr {\n\t\tstr = strings.TrimSpace(str)\n\t\twb_pkgs := strings.SplitN(str, \":\", 2)\n\t\tfs = append(fs, PkgWildcardFilter(wb_pkgs[0] == \"b\", strings.Split(wb_pkgs[1], \",\")...))\n\t}\n\treturn\n}\n\nfunc PkgLevelFilter(level int) PkgFilter {\n\treturn func(imps map[string]StrSet) (ret map[string]StrSet) {\n\t\tif level < 0 {\n\t\t\treturn imps\n\t\t}\n\t\t// find the root\n\t\t// which are not pointed to\n\t\tallTarget := NewStrSet()\n\t\tfor _, targets := range imps {\n\t\t\tallTarget.Merge(targets)\n\t\t}\n\t\tlevelMap := map[string]int{}\n\t\tfor pkg := range imps {\n\t\t\tif !allTarget.Contains(pkg) {\n\t\t\t\tlevelMap[pkg] = 0\n\t\t\t}\n\t\t}\n\t\tfor i := 0; i < level; i++ {\n\t\t\tnextLevel := NewStrSet()\n\t\t\tfor pkg, pkgLevel := range levelMap {\n\t\t\t\tif pkgLevel != i {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfor target := range imps[pkg] {\n\t\t\t\t\tnextLevel.Put(target)\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor next := range nextLevel {\n\t\t\t\tlevelMap[next] = i + 1\n\t\t\t}\n\t\t}\n\n\t\tret = make(map[string]StrSet, len(levelMap))\n\t\tfor pkg, lvl := range levelMap {\n\t\t\tret[pkg] = imps[pkg]\n\t\t\tif lvl == level {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\treturn ret\n\t}\n}\n"
  },
  {
    "path": "core/pkg_filter_test.go",
    "content": "package core\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/smartystreets/goconvey/convey\"\n)\n\nfunc TestPkgRegex(t *testing.T) {\n\tConvey(\"Test PkgRegex\", t, func() {\n\t\timps := map[string]StrSet{\n\t\t\t\"a/b/c\": NewStrSet(\n\t\t\t\t\"test/subt\",\n\t\t\t),\n\t\t}\n\t\tfilter := PkgWildcardFilter(true, \"test*\")\n\t\timps = filter(imps)\n\t\tSo(imps[\"a/b/c\"], ShouldBeEmpty)\n\t})\n}\n\nfunc TestParsePkgWildcardStr(t *testing.T) {\n\tConvey(\"Test ParsePkgWildcardStr\", t, func() {\n\t\tstr := \"w:a*,*b;b:c\"\n\t\tfs, err := ParsePkgWildcardStr(str)\n\t\tSo(err, ShouldBeNil)\n\t\tSo(len(fs), ShouldEqual, 2)\n\t})\n}\n"
  },
  {
    "path": "core/util.go",
    "content": "package core\n\nimport (\n\t\"go/parser\"\n\t\"go/token\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nfunc ParseGoImport(gofile string) (ss StrSet, err error) {\n\tfset := token.NewFileSet() // positions are relative to fset\n\tf, err := parser.ParseFile(fset, gofile, nil, parser.ImportsOnly)\n\tif err != nil {\n\t\treturn\n\t}\n\tss = NewStrSet()\n\tfor _, s := range f.Imports {\n\t\tss.Put(strings.Trim(s.Path.Value, `\"`))\n\t}\n\treturn\n}\nfunc PkgOfFile(gofile string) (pkg string) {\n\treturn strings.SplitN(filepath.Dir(gofile), \"/src/\", 2)[1]\n}\n\ntype StrSet map[string]bool\n\nfunc NewStrSet(strs ...string) StrSet {\n\tss := StrSet(make(map[string]bool))\n\tfor _, str := range strs {\n\t\tss.Put(str)\n\t}\n\treturn ss\n}\nfunc (this StrSet) Put(str string)                { this[str] = true }\nfunc (this StrSet) Del(str string)                { delete(this, str) }\nfunc (this StrSet) Contains(str string) (ok bool) { _, ok = this[str]; return ok }\nfunc (this StrSet) Merge(that StrSet) {\n\tfor str := range that {\n\t\tthis[str] = true\n\t}\n}\nfunc (this StrSet) Array() []string {\n\tret := make([]string, 0, len(this))\n\tfor str := range this {\n\t\tret = append(ret, str)\n\t}\n\treturn ret\n}\n"
  },
  {
    "path": "docs/examples-cn/cronsun.dot",
    "content": "digraph G {\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/node/cron\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/utils\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/bin/web\"->\"github.com/shunfei/cronsun\";\n\"github.com/shunfei/cronsun/bin/web\"->\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun/bin/web\"->\"github.com/shunfei/cronsun/event\";\n\"github.com/shunfei/cronsun/bin/web\"->\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/bin/web\"->\"github.com/shunfei/cronsun/web\";\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/node/cron\";\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/db\";\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/web\"->\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun/web\"->\"github.com/shunfei/cronsun\";\n\"github.com/shunfei/cronsun/web\"->\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/bin/node\"->\"github.com/shunfei/cronsun\";\n\"github.com/shunfei/cronsun/bin/node\"->\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun/bin/node\"->\"github.com/shunfei/cronsun/event\";\n\"github.com/shunfei/cronsun/bin/node\"->\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/bin/node\"->\"github.com/shunfei/cronsun/node\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/db\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/utils\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/event\";\n\"github.com/shunfei/cronsun\";\n\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/bin/web\";\n\"github.com/shunfei/cronsun/bin/node\";\n\"github.com/shunfei/cronsun/db/mid\";\n\"github.com/shunfei/cronsun/node\";\n\"github.com/shunfei/cronsun/node/cron\";\n\"github.com/shunfei/cronsun/utils\";\n\"github.com/shunfei/cronsun/event\";\n\"github.com/shunfei/cronsun/web\";\n\"github.com/shunfei/cronsun/db\";\n}\n"
  },
  {
    "path": "docs/examples-cn/cronsun.node.core.dot",
    "content": "digraph G {\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/db\";\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/node/cron\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/db\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/event\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/node/cron\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun\";\n\"github.com/shunfei/cronsun/node/cron\";\n\"github.com/shunfei/cronsun\";\n\"github.com/shunfei/cronsun/db\";\n\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun/event\";\n\"github.com/shunfei/cronsun/node\";\n}\n"
  },
  {
    "path": "docs/examples-cn/cronsun.node.dot",
    "content": "digraph G {\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/db\";\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/node/cron\";\n\"github.com/shunfei/cronsun\"->\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/db\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/event\";\n\"github.com/shunfei/cronsun/conf\"->\"github.com/shunfei/cronsun/utils\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/utils\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/conf\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/node\"->\"github.com/shunfei/cronsun/node/cron\";\n\"github.com/shunfei/cronsun/node/cron\";\n\"github.com/shunfei/cronsun/log\";\n\"github.com/shunfei/cronsun/event\";\n\"github.com/shunfei/cronsun/utils\";\n\"github.com/shunfei/cronsun/node\";\n\"github.com/shunfei/cronsun\";\n\"github.com/shunfei/cronsun/db\";\n\"github.com/shunfei/cronsun/conf\";\n}\n"
  },
  {
    "path": "docs/examples-cn/goimportdot_guide.md",
    "content": "# goimportdot : 一个帮你迅速了解 golang 项目结构的工具\n\n## 简介\n\n很多时候，当我们想熟悉一个 `golang` 项目时，都需要能快速地对代码的整体结构有个宏观了解，初步明白项目是如何组织构成的。在有了大体的概念后，再选择适当的切入点，专注于代码的核心部分进行研究，达到熟悉项目的目的。 `goimportdot` 就是一个根据 `golang` 中 `import` 生成调用关系，再配合 `Graphviz` 生成调用图的工具。\n\n\n## 安装 \n\n```\ngo get -u github.com/yqylovy/goimportdot\n```\n\n在安装后会在 `$GOPATH/bin` 路径中生成 `goimportdot` 文件。\n\n---\n\n## 使用示例\n\n以 `github.com/shunfei/cronsun` 作为示例，这是一个分布式任务系统，类似于 `crontab`。首先我们把代码下载下来。\n\n```\ngo get github.com/shunfei/cronsun\n```\n\n使用 `goimportdot` 对项目结构进行解析。再通过 dot 把 解析结构转化为 `png` 图片。\n\n```\ngoimportdot -pkg=github.com/shunfei/cronsun > cronsun.dot\ndot -Tpng cronsun.dot > cronsun.png\n```\n\n打开 `cronsun.png`,图片如下：\n\n![cronsun](./cronsun.png)\n\n可以看到现在项目整体结构一目了然，存在两个入口 `github.com/shunfei/cronsun/bin/node` 和 `github.com/shunfei/cronsun/bin/web`。\n\n`cronsun` 还是个轻量级、整洁的项目，可以一目了然。作者在分析更复杂的项目的时候，发现生成的调用图非常复杂，看上去像一团乱麻，难以入手。这时候需要减少信息量，逐步分析。依旧以 `cronsun` 为例。如果我们只想分析 `cronsun` 的 `node` 部分：\n\n```\ngoimportdot -pkg=github.com/shunfei/cronsun -root=github.com/shunfei/cronsun/node > cronsun.node.dot\ndot -Tpng cronsun.node.dot > cronsun.node.png\n```\n\n图片结果：\n\n![cronsun.node](./cronsun.node.png)\n\n项目中通常会存在一些辅助工具，如 `log` 包，被大量地引用，在分析时可以通过指定黑名单来达到忽略某些包的目的:\n\n```\n# 忽略其中的 log、utils\ngoimportdot -pkg=github.com/shunfei/cronsun -root=github.com/shunfei/cronsun/node -filter=b:*utils,*log > cronsun.node.core.dot\ndot -Tpng cronsun.node.core.dot > cronsun.node.core.png\n```\n\n图片结果：\n\n![cronsun.node.core](./cronsun.node.core.png)\n\n\n通过指定 `root` 和 `filter`,可以有效地减少输出，快速地把握核心。\n\n## 结语\n\n`goimportdot`是个刚推出的小工具，还有很多不成熟的地方，欢迎提出建议。\n项目地址： [https://github.com/yqylovy/goimportdot](https://github.com/yqylovy/goimportdot) \n\n\n\n"
  },
  {
    "path": "docs/zap.dot",
    "content": "digraph G {\n\"go.uber.org/zap/internal/multierror\"->\"go.uber.org/zap/internal/bufferpool\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/internal/bufferpool\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/internal/exit\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/internal/color\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/buffer\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/internal/multierror\";\n\"go.uber.org/zap/internal/bufferpool\"->\"go.uber.org/zap/buffer\";\n\"go.uber.org/zap/zapgrpc\"->\"go.uber.org/zap\";\n\"go.uber.org/zap/zaptest/observer\"->\"go.uber.org/zap/zapcore\";\n\"go.uber.org/zap\"->\"go.uber.org/zap/zapcore\";\n\"go.uber.org/zap\"->\"go.uber.org/zap/internal/bufferpool\";\n\"go.uber.org/zap\"->\"go.uber.org/zap/internal/multierror\";\n\"go.uber.org/zap/internal/readme\";\n\"go.uber.org/zap/buffer\";\n\"go.uber.org/zap\";\n\"go.uber.org/zap/zaptest/observer\";\n\"go.uber.org/zap/benchmarks\";\n\"go.uber.org/zap/internal/multierror\";\n\"go.uber.org/zap/zaptest\";\n\"go.uber.org/zap/internal/exit\";\n\"go.uber.org/zap/zapgrpc\";\n\"go.uber.org/zap/internal/bufferpool\";\n\"go.uber.org/zap/internal/color\";\n\"go.uber.org/zap/zapcore\";\n}\n"
  },
  {
    "path": "docs/zapcore.dot",
    "content": "digraph G {\n\"go.uber.org/zap/internal/multierror\"->\"go.uber.org/zap/internal/bufferpool\";\n\"go.uber.org/zap/internal/bufferpool\"->\"go.uber.org/zap/buffer\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/buffer\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/internal/multierror\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/internal/exit\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/internal/bufferpool\";\n\"go.uber.org/zap/zapcore\"->\"go.uber.org/zap/internal/color\";\n\"go.uber.org/zap/internal/exit\";\n\"go.uber.org/zap/zapcore\";\n\"go.uber.org/zap/internal/color\";\n\"go.uber.org/zap/buffer\";\n\"go.uber.org/zap/internal/multierror\";\n\"go.uber.org/zap/internal/bufferpool\";\n}\n"
  },
  {
    "path": "goimportdot.go",
    "content": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/yqylovy/goimportdot/core\"\n)\n\nfunc main() {\n\tvar ignoreGit = true\n\tvar ignoreTest = true\n\tvar onlySelfPkg = true\n\n\tvar packageName = \"\"\n\tvar root = \"\"\n\tvar filters = \"\"\n\n\tvar level = -1\n\n\tflag.BoolVar(&ignoreGit, \"ignoregit\", ignoreGit, \"ignore files in git\")\n\tflag.BoolVar(&ignoreTest, \"ignoretest\", ignoreTest, \"ignore test files\")\n\tflag.BoolVar(&onlySelfPkg, \"only\", onlySelfPkg, \"only to draw the input package\")\n\tflag.StringVar(&filters, \"filter\", \"\", \"filter to (ignore/only include) package match wildcard,example: -filter=w:a*,*b;b:c means only include package start with a and ends with b, ignore package named c\")\n\tflag.StringVar(&root, \"root\", root, \"only draw package with the graph start from root\")\n\tflag.IntVar(&level, \"level\", level, \"show how many level , -1 for all\")\n\tflag.StringVar(&packageName, \"pkg\", packageName, \"the package to draw\")\n\tflag.Parse()\n\n\tif packageName == \"\" {\n\t\tfmt.Println(\"You must specify the packge name with -pkg \")\n\t\treturn\n\t}\n\n\tfileFilter := []core.FileFilter{\n\t\tcore.HasSuffix(false, \".go\"),\n\t}\n\tif ignoreGit {\n\t\tfileFilter = append(fileFilter, core.NameContains(true, \".git\"))\n\t}\n\tif ignoreTest {\n\t\tfileFilter = append(fileFilter, core.NameContains(true, \"_test.go\"))\n\t}\n\n\tpkgAndImports, err := core.GetImports(packageName, fileFilter...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tpkgFilters := []core.PkgFilter{}\n\tif onlySelfPkg {\n\t\tpkgFilters = append(pkgFilters, core.PkgWildcardFilter(false, packageName+\"*\"))\n\t}\n\tif root != \"\" {\n\t\tpkgFilters = append(pkgFilters, core.RootFilter(root))\n\t}\n\tmoreFilters, err := core.ParsePkgWildcardStr(filters)\n\tif err != nil {\n\t\tfmt.Printf(\"No right filter [%s], please check!\", filters)\n\t\treturn\n\t}\n\tpkgFilters = append(pkgFilters, moreFilters...)\n\n\tif level >= 0 {\n\t\tpkgFilters = append(pkgFilters, core.PkgLevelFilter(level))\n\t}\n\n\tfor _, f := range pkgFilters {\n\t\tpkgAndImports = f(pkgAndImports)\n\t}\n\tcore.WriteDot(pkgAndImports, os.Stdout)\n}\n"
  }
]