Created
June 19, 2025 22:04
-
-
Save dims/f9adba9ec5f92b72c269c6a4ddcd93d8 to your computer and use it in GitHub Desktop.
imports analysis
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"go/parser" | |
"go/token" | |
"os" | |
"path/filepath" | |
"sort" | |
"strings" | |
) | |
// PackageImport represents an import with its count | |
type PackageImport struct { | |
Name string | |
Count int | |
} | |
// Known standard library packages | |
var stdlibPackages = map[string]bool{ | |
"archive": true, "bufio": true, "builtin": true, "bytes": true, "compress": true, | |
"container": true, "context": true, "crypto": true, "database": true, "debug": true, | |
"embed": true, "encoding": true, "errors": true, "expvar": true, "flag": true, | |
"fmt": true, "go": true, "hash": true, "html": true, "image": true, "index": true, | |
"io": true, "log": true, "math": true, "mime": true, "net": true, "os": true, | |
"path": true, "plugin": true, "reflect": true, "regexp": true, "runtime": true, | |
"sort": true, "strconv": true, "strings": true, "sync": true, "syscall": true, | |
"testing": true, "text": true, "time": true, "unicode": true, "unsafe": true, | |
} | |
func main() { | |
// Maps to store import counts by category | |
stdlibImports := make(map[string]int) | |
k8sImports := make(map[string]int) | |
thirdPartyImports := make(map[string]int) | |
// Map to store raw imports for debugging | |
rawImports := make(map[string]int) | |
// Walk through all directories | |
err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error { | |
if err != nil { | |
return err | |
} | |
// Skip vendor directory, .git, and third_party | |
if strings.Contains(path, "/vendor/") || | |
strings.Contains(path, "/.git/") || | |
strings.Contains(path, "/third_party/") { | |
return filepath.SkipDir | |
} | |
// Only process .go files | |
if !info.IsDir() && strings.HasSuffix(path, ".go") { | |
// Parse the Go file | |
fset := token.NewFileSet() | |
node, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly) | |
if err != nil { | |
// Just skip files with errors | |
return nil | |
} | |
// Extract imports | |
for _, imp := range node.Imports { | |
// Remove quotes from import path | |
importPath := strings.Trim(imp.Path.Value, "\"") | |
// Store raw import for debugging | |
rawImports[importPath]++ | |
// Map to parent package | |
parentPkg := mapToParentPackage(importPath) | |
// Categorize the import | |
parts := strings.Split(parentPkg, "/") | |
if isStdLib(parts[0]) { | |
stdlibImports[parentPkg]++ | |
} else if strings.HasPrefix(parentPkg, "k8s.io/") || strings.HasPrefix(parentPkg, "sigs.k8s.io/") { | |
k8sImports[parentPkg]++ | |
} else { | |
thirdPartyImports[parentPkg]++ | |
} | |
} | |
} | |
return nil | |
}) | |
if err != nil { | |
fmt.Printf("Error walking the path: %v\n", err) | |
return | |
} | |
// Calculate total imports by category | |
var totalStdlibImports, totalK8sImports, totalThirdPartyImports int | |
for _, count := range stdlibImports { | |
totalStdlibImports += count | |
} | |
for _, count := range k8sImports { | |
totalK8sImports += count | |
} | |
for _, count := range thirdPartyImports { | |
totalThirdPartyImports += count | |
} | |
totalImports := totalStdlibImports + totalK8sImports + totalThirdPartyImports | |
// Print statistics by category | |
fmt.Println("=== IMPORT ANALYSIS RESULTS ===") | |
fmt.Printf("\n=== STANDARD LIBRARY PACKAGES ===\n") | |
fmt.Printf("Total imports: %d (%.1f%% of all imports)\n", | |
totalStdlibImports, float64(totalStdlibImports)*100/float64(totalImports)) | |
printPackageStats(stdlibImports, totalStdlibImports) | |
fmt.Printf("\n=== KUBERNETES ECOSYSTEM PACKAGES ===\n") | |
fmt.Printf("Total imports: %d (%.1f%% of all imports)\n", | |
totalK8sImports, float64(totalK8sImports)*100/float64(totalImports)) | |
printPackageStats(k8sImports, totalK8sImports) | |
fmt.Printf("\n=== THIRD-PARTY PACKAGES ===\n") | |
fmt.Printf("Total imports: %d (%.1f%% of all imports)\n", | |
totalThirdPartyImports, float64(totalThirdPartyImports)*100/float64(totalImports)) | |
printPackageStats(thirdPartyImports, totalThirdPartyImports) | |
// Print overall statistics | |
totalPackages := len(stdlibImports) + len(k8sImports) + len(thirdPartyImports) | |
fmt.Printf("\n=== SUMMARY ===\n") | |
fmt.Printf("Standard library packages: %d (%.1f%%)\n", | |
len(stdlibImports), float64(len(stdlibImports))*100/float64(totalPackages)) | |
fmt.Printf("Kubernetes ecosystem packages: %d (%.1f%%)\n", | |
len(k8sImports), float64(len(k8sImports))*100/float64(totalPackages)) | |
fmt.Printf("Third-party packages: %d (%.1f%%)\n", | |
len(thirdPartyImports), float64(len(thirdPartyImports))*100/float64(totalPackages)) | |
fmt.Printf("Total unique packages: %d\n", totalPackages) | |
fmt.Printf("Total imports: %d\n", totalImports) | |
fmt.Printf("Total raw imports: %d\n", len(rawImports)) | |
} | |
// printPackageStats prints statistics for a category of packages | |
func printPackageStats(imports map[string]int, totalForCategory int) { | |
// Convert map to slice for sorting | |
var pkgImports []PackageImport | |
for name, count := range imports { | |
pkgImports = append(pkgImports, PackageImport{Name: name, Count: count}) | |
} | |
// Sort by count (descending) | |
sort.Slice(pkgImports, func(i, j int) bool { | |
return pkgImports[i].Count > pkgImports[j].Count | |
}) | |
// Print most used packages (top 10) | |
fmt.Println("Most Used Packages:") | |
limit := 10 | |
if len(pkgImports) < limit { | |
limit = len(pkgImports) | |
} | |
for i := 0; i < limit; i++ { | |
percentage := float64(pkgImports[i].Count) * 100 / float64(totalForCategory) | |
fmt.Printf(" %s: %d (%.1f%%)\n", pkgImports[i].Name, pkgImports[i].Count, percentage) | |
} | |
// Sort by count (ascending) | |
sort.Slice(pkgImports, func(i, j int) bool { | |
return pkgImports[i].Count < pkgImports[j].Count | |
}) | |
// Print least used packages (bottom 10) | |
fmt.Println("\nLeast Used Packages:") | |
limit = 10 | |
if len(pkgImports) < limit { | |
limit = len(pkgImports) | |
} | |
for i := 0; i < limit; i++ { | |
percentage := float64(pkgImports[i].Count) * 100 / float64(totalForCategory) | |
fmt.Printf(" %s: %d (%.1f%%)\n", pkgImports[i].Name, pkgImports[i].Count, percentage) | |
} | |
} | |
// mapToParentPackage maps an import path to its parent package | |
func mapToParentPackage(importPath string) string { | |
// Handle standard library packages | |
parts := strings.Split(importPath, "/") | |
if isStdLib(parts[0]) { | |
return parts[0] | |
} | |
// Handle golang.org packages | |
if strings.HasPrefix(importPath, "golang.org/x/") { | |
if len(parts) >= 3 { | |
return "golang.org/x/" + parts[2] | |
} | |
} | |
// Handle k8s.io packages | |
if strings.HasPrefix(importPath, "k8s.io/") { | |
if len(parts) >= 2 { | |
return "k8s.io/" + parts[1] | |
} | |
} | |
// Handle sigs.k8s.io packages | |
if strings.HasPrefix(importPath, "sigs.k8s.io/") { | |
if len(parts) >= 2 { | |
return "sigs.k8s.io/" + parts[1] | |
} | |
} | |
// Handle github.com, gopkg.in and other external packages | |
if len(parts) >= 3 { | |
return parts[0] + "/" + parts[1] + "/" + parts[2] | |
} | |
return importPath | |
} | |
// isStdLib checks if a package is part of the Go standard library | |
func isStdLib(pkg string) bool { | |
return stdlibPackages[pkg] || strings.HasPrefix(pkg, "internal/") | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"go/parser" | |
"go/token" | |
"os" | |
"path/filepath" | |
"sort" | |
"strings" | |
) | |
// PackageImport represents an import with its count and files | |
type PackageImport struct { | |
Name string | |
Count int | |
Files map[string]bool | |
} | |
// Known standard library packages | |
var stdlibPackages = map[string]bool{ | |
"archive": true, "bufio": true, "builtin": true, "bytes": true, "compress": true, | |
"container": true, "context": true, "crypto": true, "database": true, "debug": true, | |
"embed": true, "encoding": true, "errors": true, "expvar": true, "flag": true, | |
"fmt": true, "go": true, "hash": true, "html": true, "image": true, "index": true, | |
"io": true, "log": true, "math": true, "mime": true, "net": true, "os": true, | |
"path": true, "plugin": true, "reflect": true, "regexp": true, "runtime": true, | |
"sort": true, "strconv": true, "strings": true, "sync": true, "syscall": true, | |
"testing": true, "text": true, "time": true, "unicode": true, "unsafe": true, | |
} | |
func main() { | |
// Maps to store import counts and files by category | |
stdlibImports := make(map[string]*PackageImport) | |
k8sImports := make(map[string]*PackageImport) | |
thirdPartyImports := make(map[string]*PackageImport) | |
// Map to store raw imports for debugging | |
rawImports := make(map[string]int) | |
// Walk through all directories | |
err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error { | |
if err != nil { | |
return err | |
} | |
// Skip vendor directory, .git, and third_party | |
if strings.Contains(path, "/vendor/") || | |
strings.Contains(path, "/.git/") || | |
strings.Contains(path, "/third_party/") { | |
return filepath.SkipDir | |
} | |
// Only process .go files | |
if !info.IsDir() && strings.HasSuffix(path, ".go") { | |
// Parse the Go file | |
fset := token.NewFileSet() | |
node, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly) | |
if err != nil { | |
// Just skip files with errors | |
return nil | |
} | |
// Extract imports | |
for _, imp := range node.Imports { | |
// Remove quotes from import path | |
importPath := strings.Trim(imp.Path.Value, "\"") | |
// Store raw import for debugging | |
rawImports[importPath]++ | |
// Map to parent package | |
parentPkg := mapToParentPackage(importPath) | |
// Categorize the import | |
parts := strings.Split(parentPkg, "/") | |
if isStdLib(parts[0]) { | |
addImport(stdlibImports, parentPkg, path) | |
} else if strings.HasPrefix(parentPkg, "k8s.io/") || strings.HasPrefix(parentPkg, "sigs.k8s.io/") { | |
addImport(k8sImports, parentPkg, path) | |
} else { | |
addImport(thirdPartyImports, parentPkg, path) | |
} | |
} | |
} | |
return nil | |
}) | |
if err != nil { | |
fmt.Printf("Error walking the path: %v\n", err) | |
return | |
} | |
// Calculate total imports by category | |
var totalStdlibImports, totalK8sImports, totalThirdPartyImports int | |
for _, imp := range stdlibImports { | |
totalStdlibImports += imp.Count | |
} | |
for _, imp := range k8sImports { | |
totalK8sImports += imp.Count | |
} | |
for _, imp := range thirdPartyImports { | |
totalThirdPartyImports += imp.Count | |
} | |
totalImports := totalStdlibImports + totalK8sImports + totalThirdPartyImports | |
// Print third-party packages with single usage | |
fmt.Println("=== LEAST USED THIRD-PARTY PACKAGES ===") | |
printSingleUsePackages(thirdPartyImports) | |
// Print overall statistics | |
totalPackages := len(stdlibImports) + len(k8sImports) + len(thirdPartyImports) | |
fmt.Printf("\n=== SUMMARY ===\n") | |
fmt.Printf("Standard library packages: %d (%.1f%%)\n", | |
len(stdlibImports), float64(len(stdlibImports))*100/float64(totalPackages)) | |
fmt.Printf("Kubernetes ecosystem packages: %d (%.1f%%)\n", | |
len(k8sImports), float64(len(k8sImports))*100/float64(totalPackages)) | |
fmt.Printf("Third-party packages: %d (%.1f%%)\n", | |
len(thirdPartyImports), float64(len(thirdPartyImports))*100/float64(totalPackages)) | |
fmt.Printf("Total unique packages: %d\n", totalPackages) | |
fmt.Printf("Total imports: %d\n", totalImports) | |
fmt.Printf("Total raw imports: %d\n", len(rawImports)) | |
} | |
// addImport adds an import to the map with its file | |
func addImport(imports map[string]*PackageImport, pkg string, file string) { | |
if _, exists := imports[pkg]; !exists { | |
imports[pkg] = &PackageImport{ | |
Name: pkg, | |
Count: 0, | |
Files: make(map[string]bool), | |
} | |
} | |
imports[pkg].Count++ | |
imports[pkg].Files[file] = true | |
} | |
// printSingleUsePackages prints packages that are used only once | |
func printSingleUsePackages(imports map[string]*PackageImport) { | |
// Convert map to slice for sorting | |
var singleUseImports []*PackageImport | |
for _, imp := range imports { | |
if imp.Count == 1 { | |
singleUseImports = append(singleUseImports, imp) | |
} | |
} | |
// Sort by name | |
sort.Slice(singleUseImports, func(i, j int) bool { | |
return singleUseImports[i].Name < singleUseImports[j].Name | |
}) | |
// Print packages used only once | |
fmt.Printf("Found %d third-party packages used only once:\n\n", len(singleUseImports)) | |
for _, imp := range singleUseImports { | |
fmt.Printf("Package: %s\n", imp.Name) | |
for file := range imp.Files { | |
fmt.Printf(" Used in: %s\n", file) | |
} | |
fmt.Println() | |
} | |
} | |
// mapToParentPackage maps an import path to its parent package | |
func mapToParentPackage(importPath string) string { | |
// Handle standard library packages | |
parts := strings.Split(importPath, "/") | |
if isStdLib(parts[0]) { | |
return parts[0] | |
} | |
// Handle golang.org packages | |
if strings.HasPrefix(importPath, "golang.org/x/") { | |
if len(parts) >= 3 { | |
return "golang.org/x/" + parts[2] | |
} | |
} | |
// Handle k8s.io packages | |
if strings.HasPrefix(importPath, "k8s.io/") { | |
if len(parts) >= 2 { | |
return "k8s.io/" + parts[1] | |
} | |
} | |
// Handle sigs.k8s.io packages | |
if strings.HasPrefix(importPath, "sigs.k8s.io/") { | |
if len(parts) >= 2 { | |
return "sigs.k8s.io/" + parts[1] | |
} | |
} | |
// Handle github.com, gopkg.in and other external packages | |
if len(parts) >= 3 { | |
return parts[0] + "/" + parts[1] + "/" + parts[2] | |
} | |
return importPath | |
} | |
// isStdLib checks if a package is part of the Go standard library | |
func isStdLib(pkg string) bool { | |
return stdlibPackages[pkg] || strings.HasPrefix(pkg, "internal/") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment