馃Ч Dependency Scanner and Pruner
go
dependency
dependencies
1package main
2
3import (
4 "io/fs"
5 "os"
6 "path/filepath"
7 "runtime"
8 "sync"
9)
10
11var knownDependencyDirectories = map[string]bool{
12 "node_modules": true,
13 "target": true,
14 ".next": true,
15 ".nuxt": true,
16 "__pycache__": true,
17 ".venv": true,
18 "venv": true,
19 ".gradle": true,
20 "Pods": true,
21 ".zig-cache": true,
22 "zig-cache": true,
23 "zig-out": true,
24 "_build": true,
25 ".dart_tool": true,
26}
27var ignoredDirectories = map[string]bool{
28 ".git": true,
29 ".hg": true,
30 ".svn": true,
31}
32
33type DependencyDirectory struct {
34 Path string
35 RelativePath string
36 SizeBytes int64
37 DirectoryType string
38}
39
40func scanForDependencies(rootPath string) ([]DependencyDirectory, error) {
41 var foundDirectories []DependencyDirectory
42
43 walkError := filepath.WalkDir(rootPath, func(currentPath string, entry fs.DirEntry, accessError error) error {
44 if accessError != nil {
45 return filepath.SkipDir
46 }
47
48 if !entry.IsDir() {
49 return nil
50 }
51
52 if ignoredDirectories[entry.Name()] {
53 return filepath.SkipDir
54 }
55
56 if knownDependencyDirectories[entry.Name()] {
57 relativePath, _ := filepath.Rel(rootPath, currentPath)
58 foundDirectories = append(foundDirectories, DependencyDirectory{
59 Path: currentPath,
60 RelativePath: relativePath,
61 DirectoryType: entry.Name(),
62 })
63
64 return filepath.SkipDir
65 }
66
67 return nil
68 })
69
70 if walkError != nil {
71 return nil, walkError
72 }
73
74 var waitGroup sync.WaitGroup
75
76 semaphore := make(chan struct{}, runtime.NumCPU())
77
78 for directoryIndex := range foundDirectories {
79 waitGroup.Add(1)
80
81 go func(targetIndex int) {
82 defer waitGroup.Done()
83
84 semaphore <- struct{}{}
85
86 defer func() { <-semaphore }()
87
88 foundDirectories[targetIndex].SizeBytes = calculateDirectorySize(foundDirectories[targetIndex].Path)
89 }(directoryIndex)
90 }
91
92 waitGroup.Wait()
93
94 return foundDirectories, nil
95}
96
97func calculateDirectorySize(directoryPath string) int64 {
98 var totalSize int64
99
100 _ = filepath.WalkDir(directoryPath, func(_ string, entry fs.DirEntry, walkError error) error {
101 if walkError != nil || entry.IsDir() {
102 return nil
103 }
104
105 fileInformation, informationError := entry.Info()
106
107 if informationError == nil {
108 totalSize += fileInformation.Size()
109 }
110
111 return nil
112 })
113
114 return totalSize
115}
116
117func deleteDependencies(dependencies []DependencyDirectory, selected map[int]bool) (int64, int) {
118 var freedBytes int64
119 var deletedCount int
120
121 for dependencyIndex, dependency := range dependencies {
122 if !selected[dependencyIndex] {
123 continue
124 }
125
126 if removeError := os.RemoveAll(dependency.Path); removeError == nil {
127 freedBytes += dependency.SizeBytes
128
129 deletedCount++
130 }
131 }
132
133 return freedBytes, deletedCount
134}