Reorganize code into individual tool files
This commit is contained in:
132
tool_analyze_dependencies.go
Normal file
132
tool_analyze_dependencies.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Dependency analysis types
|
||||
type DependencyInfo struct {
|
||||
Package string `json:"package"`
|
||||
Dir string `json:"dir"`
|
||||
Dependencies []string `json:"dependencies"`
|
||||
Dependents []string `json:"dependents,omitempty"`
|
||||
Cycles [][]string `json:"cycles,omitempty"`
|
||||
}
|
||||
|
||||
func analyzeDependencies(dir string) ([]DependencyInfo, error) {
|
||||
depMap := make(map[string]*DependencyInfo)
|
||||
|
||||
// First pass: collect all packages and their imports
|
||||
err := walkGoFiles(dir, func(path string, src []byte, file *ast.File, fset *token.FileSet) error {
|
||||
pkgDir := filepath.Dir(path)
|
||||
if _, exists := depMap[pkgDir]; !exists {
|
||||
depMap[pkgDir] = &DependencyInfo{
|
||||
Package: file.Name.Name,
|
||||
Dir: pkgDir,
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// Add imports
|
||||
for _, imp := range file.Imports {
|
||||
importPath := strings.Trim(imp.Path.Value, `"`)
|
||||
if !contains(depMap[pkgDir].Dependencies, importPath) {
|
||||
depMap[pkgDir].Dependencies = append(depMap[pkgDir].Dependencies, importPath)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build dependency graph and find cycles
|
||||
var deps []DependencyInfo
|
||||
for _, dep := range depMap {
|
||||
// Find internal dependencies
|
||||
for _, imp := range dep.Dependencies {
|
||||
// Check if this is an internal package
|
||||
for otherDir, otherDep := range depMap {
|
||||
if strings.HasSuffix(imp, otherDep.Package) && otherDir != dep.Dir {
|
||||
otherDep.Dependents = append(otherDep.Dependents, dep.Package)
|
||||
}
|
||||
}
|
||||
}
|
||||
deps = append(deps, *dep)
|
||||
}
|
||||
|
||||
// Simple cycle detection (could be enhanced)
|
||||
for i := range deps {
|
||||
deps[i].Cycles = findCycles(&deps[i], depMap)
|
||||
}
|
||||
|
||||
return deps, nil
|
||||
}
|
||||
|
||||
func contains(slice []string, str string) bool {
|
||||
for _, s := range slice {
|
||||
if s == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func findCycles(dep *DependencyInfo, depMap map[string]*DependencyInfo) [][]string {
|
||||
// Simple DFS-based cycle detection
|
||||
var cycles [][]string
|
||||
visited := make(map[string]bool)
|
||||
recStack := make(map[string]bool)
|
||||
path := []string{}
|
||||
|
||||
var dfs func(pkg string) bool
|
||||
dfs = func(pkg string) bool {
|
||||
visited[pkg] = true
|
||||
recStack[pkg] = true
|
||||
path = append(path, pkg)
|
||||
|
||||
// Find dependencies for this package
|
||||
for _, d := range depMap {
|
||||
if d.Package == pkg {
|
||||
for _, imp := range d.Dependencies {
|
||||
for _, otherDep := range depMap {
|
||||
if strings.HasSuffix(imp, otherDep.Package) {
|
||||
if !visited[otherDep.Package] {
|
||||
if dfs(otherDep.Package) {
|
||||
return true
|
||||
}
|
||||
} else if recStack[otherDep.Package] {
|
||||
// Found a cycle
|
||||
cycleStart := -1
|
||||
for i, p := range path {
|
||||
if p == otherDep.Package {
|
||||
cycleStart = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if cycleStart >= 0 {
|
||||
cycle := append([]string{}, path[cycleStart:]...)
|
||||
cycles = append(cycles, cycle)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
path = path[:len(path)-1]
|
||||
recStack[pkg] = false
|
||||
return false
|
||||
}
|
||||
|
||||
dfs(dep.Package)
|
||||
return cycles
|
||||
}
|
||||
Reference in New Issue
Block a user