@@ -18,7 +18,7 @@ type PruneOptions uint8
18
18
19
19
const (
20
20
// PruneNestedVendorDirs indicates if nested vendor directories should be pruned.
21
- PruneNestedVendorDirs = 1 << iota
21
+ PruneNestedVendorDirs PruneOptions = 1 << iota
22
22
// PruneUnusedPackages indicates if unused Go packages should be pruned.
23
23
PruneUnusedPackages
24
24
// PruneNonGoFiles indicates if non-Go files should be pruned.
@@ -57,12 +57,13 @@ var (
57
57
// on the PruneOptions passed.
58
58
//
59
59
// A Lock must be passed if PruneUnusedPackages is toggled on.
60
- func Prune (baseDir string , options PruneOptions , l Lock , logger * log.Logger ) error {
60
+ func Prune (baseDir string , l Lock , options PruneOptions , logger * log.Logger ) error {
61
61
// TODO(ibrasho) allow passing specific options per project
62
+
62
63
for _ , lp := range l .Projects () {
63
64
projectDir := filepath .Join (baseDir , string (lp .Ident ().ProjectRoot ))
64
- err := PruneProject ( projectDir , lp , options , logger )
65
- if err != nil {
65
+
66
+ if err := PruneProject ( projectDir , lp , options , logger ); err != nil {
66
67
return err
67
68
}
68
69
}
@@ -73,28 +74,31 @@ func Prune(baseDir string, options PruneOptions, l Lock, logger *log.Logger) err
73
74
// PruneProject remove excess files according to the options passed, from
74
75
// the lp directory in baseDir.
75
76
func PruneProject (baseDir string , lp LockedProject , options PruneOptions , logger * log.Logger ) error {
76
- projectDir := filepath .Join (baseDir , string (lp .Ident ().ProjectRoot ))
77
+ fs , err := deriveFilesystemState (baseDir )
78
+ if err != nil {
79
+ return errors .Wrap (err , "could not derive filesystem state" )
80
+ }
77
81
78
82
if (options & PruneNestedVendorDirs ) != 0 {
79
- if err := pruneNestedVendorDirs (projectDir ); err != nil {
83
+ if err := pruneNestedVendorDirs (baseDir ); err != nil {
80
84
return err
81
85
}
82
86
}
83
87
84
88
if (options & PruneUnusedPackages ) != 0 {
85
- if err := pruneUnusedPackages (lp , projectDir , logger ); err != nil {
89
+ if err := pruneUnusedPackages (lp , fs , logger ); err != nil {
86
90
return errors .Wrap (err , "failed to prune unused packages" )
87
91
}
88
92
}
89
93
90
94
if (options & PruneNonGoFiles ) != 0 {
91
- if err := pruneNonGoFiles (projectDir , logger ); err != nil {
95
+ if err := pruneNonGoFiles (fs , logger ); err != nil {
92
96
return errors .Wrap (err , "failed to prune non-Go files" )
93
97
}
94
98
}
95
99
96
100
if (options & PruneGoTestFiles ) != 0 {
97
- if err := pruneGoTestFiles (projectDir , logger ); err != nil {
101
+ if err := pruneGoTestFiles (fs , logger ); err != nil {
98
102
return errors .Wrap (err , "failed to prune Go test files" )
99
103
}
100
104
}
@@ -107,152 +111,141 @@ func pruneNestedVendorDirs(baseDir string) error {
107
111
return filepath .Walk (baseDir , stripVendor )
108
112
}
109
113
110
- // pruneUnusedPackages deletes unimported packages found within baseDir.
114
+ // pruneVendorDirs deletes all nested vendor directories within baseDir.
115
+ // func pruneVendorDirs(fs filesystemState, logger *log.Logger) error {
116
+ // toDelete := collectNestedVendorDirs(fs)
117
+
118
+ // for _, path := range toDelete {
119
+ // logger.Printf(" * %s", path)
120
+
121
+ // if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
122
+ // return err
123
+ // }
124
+ // }
125
+
126
+ // return nil
127
+ // }
128
+
129
+ // func collectNestedVendorDirs(fs filesystemState) []string {
130
+ // toDelete := make([]string, 0, len(fs.dirs)/4)
131
+
132
+ // for _, dir := range fs.dirs {
133
+ // if filepath.Base(dir)
134
+ // toDelete = append(toDelete, dir)
135
+ // }
136
+
137
+ // for _, link := range fs.links {
138
+ // toDelete = append(toDelete)
139
+ // }
140
+
141
+ // return files
142
+ // }
143
+
144
+ // pruneUnusedPackages deletes unimported packages found in fs.
111
145
// Determining whether packages are imported or not is based on the passed LockedProject.
112
- func pruneUnusedPackages (lp LockedProject , projectDir string , logger * log.Logger ) error {
146
+ func pruneUnusedPackages (lp LockedProject , fs filesystemState , logger * log.Logger ) error {
113
147
pr := string (lp .Ident ().ProjectRoot )
114
- logger . Printf ( "Calculating unused packages in %s to prune. \n " , pr )
148
+ unusedPackages := calculateUnusedPackages ( lp , fs )
115
149
116
- unusedPackages , err := calculateUnusedPackages (lp , projectDir )
117
- if err != nil {
118
- return errors .Wrapf (err , "could not calculate unused packages in %s" , pr )
119
- }
150
+ logger .Printf ("Found %d unused packages in %s:\n " , len (unusedPackages ), pr )
120
151
121
- logger .Printf ("Found the following unused packages in %s:\n " , pr )
122
152
for pkg := range unusedPackages {
123
153
logger .Printf (" * %s\n " , filepath .Join (pr , pkg ))
124
154
}
125
155
126
- unusedPackagesFiles , err := collectUnusedPackagesFiles (projectDir , unusedPackages )
127
- if err != nil {
128
- return errors .Wrapf (err , "could not collect unused packages' files in %s" , pr )
129
- }
156
+ toDelete := collectUnusedPackagesFiles (fs , unusedPackages )
157
+
158
+ logger .Printf ("Deleting %d files in unused packages:" , len (toDelete ))
130
159
131
- if err := deleteFiles (unusedPackagesFiles ); err != nil {
132
- return errors .Wrapf (err , "" )
160
+ for _ , path := range toDelete {
161
+ logger .Printf (" * %s\n " , path )
162
+
163
+ if err := os .Remove (path ); err != nil && ! os .IsNotExist (err ) {
164
+ return err
165
+ }
133
166
}
134
167
135
168
return nil
136
169
}
137
170
138
171
// calculateUnusedPackages generates a list of unused packages in lp.
139
- func calculateUnusedPackages (lp LockedProject , projectDir string ) (map [string ]struct {}, error ) {
140
- // TODO(ibrasho): optimize this...
172
+ func calculateUnusedPackages (lp LockedProject , fs filesystemState ) map [string ]struct {} {
141
173
unused := make (map [string ]struct {})
142
174
imported := make (map [string ]struct {})
175
+
143
176
for _ , pkg := range lp .Packages () {
144
177
imported [pkg ] = struct {}{}
145
178
}
146
179
147
- err := filepath .Walk (projectDir , func (path string , info os.FileInfo , err error ) error {
148
- if err != nil {
149
- return err
150
- }
151
-
152
- // Ignore anything that's not a directory.
153
- if ! info .IsDir () {
154
- return nil
155
- }
180
+ // Add the root package if it's not imported.
181
+ if _ , ok := imported ["." ]; ! ok {
182
+ unused ["." ] = struct {}{}
183
+ }
156
184
157
- pkg , err := filepath .Rel (projectDir , path )
158
- if err != nil {
159
- return errors .Wrap (err , "unexpected error while calculating unused packages" )
160
- }
185
+ for _ , dirPath := range fs .dirs {
186
+ pkg := filepath .ToSlash (dirPath )
161
187
162
- pkg = filepath .ToSlash (pkg )
163
188
if _ , ok := imported [pkg ]; ! ok {
164
189
unused [pkg ] = struct {}{}
165
190
}
191
+ }
166
192
167
- return nil
168
- })
169
-
170
- return unused , err
193
+ return unused
171
194
}
172
195
173
- // collectUnusedPackagesFiles returns a slice of all files in the unused packages in projectDir .
174
- func collectUnusedPackagesFiles (projectDir string , unusedPackages map [string ]struct {}) ( []string , error ) {
196
+ // collectUnusedPackagesFiles returns a slice of all files in the unused packages based on fs .
197
+ func collectUnusedPackagesFiles (fs filesystemState , unusedPackages map [string ]struct {}) []string {
175
198
// TODO(ibrasho): is this useful?
176
199
files := make ([]string , 0 , len (unusedPackages ))
177
200
178
- err := filepath .Walk (projectDir , func (path string , info os.FileInfo , err error ) error {
179
- if err != nil {
180
- return err
201
+ for _ , path := range fs .files {
202
+ // Keep perserved files.
203
+ if isPreservedFile (filepath .Base (path )) {
204
+ continue
181
205
}
182
206
183
- // Ignore directories.
184
- if info .IsDir () {
185
- return nil
186
- }
207
+ pkg := filepath .ToSlash (filepath .Dir (path ))
187
208
188
- // Ignore perserved files.
189
- if isPreservedFile (info .Name ()) {
190
- return nil
191
- }
192
-
193
- pkg , err := filepath .Rel (projectDir , filepath .Dir (path ))
194
- if err != nil {
195
- return errors .Wrap (err , "unexpected error while calculating unused packages" )
196
- }
197
-
198
- pkg = filepath .ToSlash (pkg )
199
209
if _ , ok := unusedPackages [pkg ]; ok {
200
- files = append (files , path )
210
+ files = append (files , filepath . Join ( fs . root , path ) )
201
211
}
212
+ }
202
213
203
- return nil
204
- })
205
-
206
- return files , err
214
+ return files
207
215
}
208
216
209
- // pruneNonGoFiles delete all non-Go files existing within baseDir .
217
+ // pruneNonGoFiles delete all non-Go files existing in fs .
210
218
// Files with names that are prefixed by any entry in preservedNonGoFiles
211
219
// are not deleted.
212
- func pruneNonGoFiles (baseDir string , logger * log.Logger ) error {
213
- files , err := collectNonGoFiles (baseDir , logger )
214
- if err != nil {
215
- return errors .Wrap (err , "could not collect non-Go files" )
216
- }
217
-
218
- if err := deleteFiles (files ); err != nil {
219
- return errors .Wrap (err , "could not prune Go test files" )
220
- }
221
-
222
- return nil
223
- }
224
-
225
- // collectNonGoFiles returns a slice containing all non-Go files in baseDir.
226
- // Files meeting the checks in isPreservedFile are not returned.
227
- func collectNonGoFiles (baseDir string , logger * log.Logger ) ([]string , error ) {
228
- files := make ([]string , 0 )
229
-
230
- err := filepath .Walk (baseDir , func (path string , info os.FileInfo , err error ) error {
231
- if err != nil {
232
- return err
220
+ func pruneNonGoFiles (fs filesystemState , logger * log.Logger ) error {
221
+ // TODO(ibrasho) detemine a sane capacity
222
+ toDelete := make ([]string , 0 , len (fs .files )/ 4 )
223
+
224
+ for _ , path := range fs .files {
225
+ // Ignore Go files.
226
+ if strings .HasSuffix (path , ".go" ) {
227
+ continue
233
228
}
234
229
235
- // Ignore directories .
236
- if info . IsDir ( ) {
237
- return nil
230
+ // Ignore perserved files .
231
+ if isPreservedFile ( filepath . Base ( path ) ) {
232
+ continue
238
233
}
239
234
240
- // Ignore all Go files.
241
- if strings .HasSuffix (info .Name (), ".go" ) {
242
- return nil
243
- }
235
+ toDelete = append (toDelete , filepath .Join (fs .root , path ))
236
+ }
244
237
245
- // Ignore perserved files.
246
- if isPreservedFile (info .Name ()) {
247
- return nil
248
- }
238
+ logger .Printf ("Deleting %d non-Go files:\n " , len (toDelete ))
249
239
250
- files = append (files , path )
240
+ for _ , path := range toDelete {
241
+ logger .Printf (" * %s\n " , path )
251
242
252
- return nil
253
- })
243
+ if err := os .Remove (path ); err != nil && ! os .IsNotExist (err ) {
244
+ return err
245
+ }
246
+ }
254
247
255
- return files , err
248
+ return nil
256
249
}
257
250
258
251
// isPreservedFile checks if the file name indicates that the file should be
@@ -275,51 +268,26 @@ func isPreservedFile(name string) bool {
275
268
return false
276
269
}
277
270
278
- // pruneGoTestFiles deletes all Go test files (*_test.go) within baseDir.
279
- func pruneGoTestFiles (baseDir string , logger * log.Logger ) error {
280
- files , err := collectGoTestFiles (baseDir )
281
- if err != nil {
282
- return errors .Wrap (err , "could not collect Go test files" )
283
- }
284
-
285
- if err := deleteFiles (files ); err != nil {
286
- return errors .Wrap (err , "could not prune Go test files" )
287
- }
288
-
289
- return nil
290
- }
291
-
292
- // collectGoTestFiles returns a slice contains all Go test files (any files
293
- // prefixed with _test.go) in baseDir.
294
- func collectGoTestFiles (baseDir string ) ([]string , error ) {
295
- files := make ([]string , 0 )
271
+ // pruneGoTestFiles deletes all Go test files (*_test.go) in fs.
272
+ func pruneGoTestFiles (fs filesystemState , logger * log.Logger ) error {
273
+ // TODO(ibrasho) detemine a sane capacity
274
+ toDelete := make ([]string , 0 , len (fs .files )/ 2 )
296
275
297
- err := filepath .Walk (baseDir , func (path string , info os.FileInfo , err error ) error {
298
- if err != nil {
299
- return err
300
- }
301
-
302
- // Ignore directories.
303
- if info .IsDir () {
304
- return nil
305
- }
306
-
307
- // Ignore any files that is not a Go test file.
308
- if strings .HasSuffix (info .Name (), "_test.go" ) {
309
- files = append (files , path )
276
+ for _ , path := range fs .files {
277
+ if strings .HasSuffix (path , "_test.go" ) {
278
+ toDelete = append (toDelete , filepath .Join (fs .root , path ))
310
279
}
280
+ }
311
281
312
- return nil
313
- })
282
+ logger .Printf ("Deleting %d Go test files:\n " , len (toDelete ))
314
283
315
- return files , err
316
- }
284
+ for _ , path := range toDelete {
285
+ logger . Printf ( " * %s \n " , path )
317
286
318
- func deleteFiles (paths []string ) error {
319
- for _ , path := range paths {
320
- if err := os .Remove (path ); err != nil {
287
+ if err := os .Remove (path ); err != nil && ! os .IsNotExist (err ) {
321
288
return err
322
289
}
323
290
}
291
+
324
292
return nil
325
293
}
0 commit comments