Skip to content

Visualize (app-internal) Go package dependencies #17

@joonas-fi

Description

@joonas-fi
func main() {
   p := args[0]
   mainPath := args[1]
   if mainPath == "" {
           bi, ok := debug.ReadBuildInfo()
           if !ok {
                   return errors.New("could not read build info")
           }

           mainPath = bi.Main.Path
   }

   type Package struct {
           ImportPath string   // the package path
           Imports    []string // direct imports
   }

   // produce with: $ go list -json ./... > golist.json
   f, err := os.Open(p)
   if err != nil {
           panic(err)
   }
   defer f.Close()
   dec := json.NewDecoder(f)
   for {
           pkg := Package{}
           if err := dec.Decode(&pkg); err != nil {
                   if errors.Is(err, io.EOF) {
                           break
                   } else {
                           return err
                   }
           }

           mainPathWithSlash := mainPath + "/"
           pkgCleanedPath := cleanupModulePath(pkg.ImportPath, mainPathWithSlash)
           // fmt.Printf("%s %v\n", pkgCleanedPath, nonStdImports(pkg.Imports, mainPath))

           for _, import_ := range nonStdImports(pkg.Imports, mainPathWithSlash) {
                   fmt.Printf("%s -> %s\n", pkgCleanedPath, import_)
           }
   }
}

func nonStdImports(imports []string, mainPath string) []string {
       return lo.FilterMap(imports, func(import_ string, _ int) (string, bool) {
               trimmed := cleanupModulePath(import_, mainPath)
               didTrim := len(trimmed) != len(import_)
               return trimmed, didTrim
       })
}

func cleanupModulePath(in string, mainPath string) string {
       trimmed := strings.TrimPrefix(in, mainPath)
       // trimmed = strings.ReplaceAll(trimmed, "/", ".")
       trimmed = strings.Replace(trimmed, "/", ".", 2)
       return trimmed
}

When fed to D2, we get something like this for a large application:

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions