@@ -18,7 +18,7 @@ type PruneOptions uint8
1818
1919const (
2020 // PruneNestedVendorDirs indicates if nested vendor directories should be pruned.
21- PruneNestedVendorDirs = 1 << iota
21+ PruneNestedVendorDirs PruneOptions = 1 << iota
2222 // PruneUnusedPackages indicates if unused Go packages should be pruned.
2323 PruneUnusedPackages
2424 // PruneNonGoFiles indicates if non-Go files should be pruned.
@@ -57,12 +57,13 @@ var (
5757// on the PruneOptions passed.
5858//
5959// 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 {
6161 // TODO(ibrasho) allow passing specific options per project
62+
6263 for _ , lp := range l .Projects () {
6364 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 {
6667 return err
6768 }
6869 }
@@ -73,28 +74,31 @@ func Prune(baseDir string, options PruneOptions, l Lock, logger *log.Logger) err
7374// PruneProject remove excess files according to the options passed, from
7475// the lp directory in baseDir.
7576func 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+ }
7781
7882 if (options & PruneNestedVendorDirs ) != 0 {
79- if err := pruneNestedVendorDirs (projectDir ); err != nil {
83+ if err := pruneNestedVendorDirs (baseDir ); err != nil {
8084 return err
8185 }
8286 }
8387
8488 if (options & PruneUnusedPackages ) != 0 {
85- if err := pruneUnusedPackages (lp , projectDir , logger ); err != nil {
89+ if err := pruneUnusedPackages (lp , fs , logger ); err != nil {
8690 return errors .Wrap (err , "failed to prune unused packages" )
8791 }
8892 }
8993
9094 if (options & PruneNonGoFiles ) != 0 {
91- if err := pruneNonGoFiles (projectDir , logger ); err != nil {
95+ if err := pruneNonGoFiles (fs , logger ); err != nil {
9296 return errors .Wrap (err , "failed to prune non-Go files" )
9397 }
9498 }
9599
96100 if (options & PruneGoTestFiles ) != 0 {
97- if err := pruneGoTestFiles (projectDir , logger ); err != nil {
101+ if err := pruneGoTestFiles (fs , logger ); err != nil {
98102 return errors .Wrap (err , "failed to prune Go test files" )
99103 }
100104 }
@@ -107,152 +111,141 @@ func pruneNestedVendorDirs(baseDir string) error {
107111 return filepath .Walk (baseDir , stripVendor )
108112}
109113
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.
111145// 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 {
113147 pr := string (lp .Ident ().ProjectRoot )
114- logger . Printf ( "Calculating unused packages in %s to prune. \n " , pr )
148+ unusedPackages := calculateUnusedPackages ( lp , fs )
115149
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 )
120151
121- logger .Printf ("Found the following unused packages in %s:\n " , pr )
122152 for pkg := range unusedPackages {
123153 logger .Printf (" * %s\n " , filepath .Join (pr , pkg ))
124154 }
125155
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 ))
130159
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+ }
133166 }
134167
135168 return nil
136169}
137170
138171// 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 {} {
141173 unused := make (map [string ]struct {})
142174 imported := make (map [string ]struct {})
175+
143176 for _ , pkg := range lp .Packages () {
144177 imported [pkg ] = struct {}{}
145178 }
146179
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+ }
156184
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 )
161187
162- pkg = filepath .ToSlash (pkg )
163188 if _ , ok := imported [pkg ]; ! ok {
164189 unused [pkg ] = struct {}{}
165190 }
191+ }
166192
167- return nil
168- })
169-
170- return unused , err
193+ return unused
171194}
172195
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 {
175198 // TODO(ibrasho): is this useful?
176199 files := make ([]string , 0 , len (unusedPackages ))
177200
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
181205 }
182206
183- // Ignore directories.
184- if info .IsDir () {
185- return nil
186- }
207+ pkg := filepath .ToSlash (filepath .Dir (path ))
187208
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 )
199209 if _ , ok := unusedPackages [pkg ]; ok {
200- files = append (files , path )
210+ files = append (files , filepath . Join ( fs . root , path ) )
201211 }
212+ }
202213
203- return nil
204- })
205-
206- return files , err
214+ return files
207215}
208216
209- // pruneNonGoFiles delete all non-Go files existing within baseDir .
217+ // pruneNonGoFiles delete all non-Go files existing in fs .
210218// Files with names that are prefixed by any entry in preservedNonGoFiles
211219// 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
233228 }
234229
235- // Ignore directories .
236- if info . IsDir ( ) {
237- return nil
230+ // Ignore perserved files .
231+ if isPreservedFile ( filepath . Base ( path ) ) {
232+ continue
238233 }
239234
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+ }
244237
245- // Ignore perserved files.
246- if isPreservedFile (info .Name ()) {
247- return nil
248- }
238+ logger .Printf ("Deleting %d non-Go files:\n " , len (toDelete ))
249239
250- files = append (files , path )
240+ for _ , path := range toDelete {
241+ logger .Printf (" * %s\n " , path )
251242
252- return nil
253- })
243+ if err := os .Remove (path ); err != nil && ! os .IsNotExist (err ) {
244+ return err
245+ }
246+ }
254247
255- return files , err
248+ return nil
256249}
257250
258251// isPreservedFile checks if the file name indicates that the file should be
@@ -275,51 +268,26 @@ func isPreservedFile(name string) bool {
275268 return false
276269}
277270
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 )
296275
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 ))
310279 }
280+ }
311281
312- return nil
313- })
282+ logger .Printf ("Deleting %d Go test files:\n " , len (toDelete ))
314283
315- return files , err
316- }
284+ for _ , path := range toDelete {
285+ logger . Printf ( " * %s \n " , path )
317286
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 ) {
321288 return err
322289 }
323290 }
291+
324292 return nil
325293}
0 commit comments