github.com/kristoff-it/hugo@v0.47.1/hugolib/prune_resources.go (about) 1 // Copyright 2017-present The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package hugolib 15 16 import ( 17 "fmt" 18 "io" 19 "os" 20 "strings" 21 22 "github.com/gohugoio/hugo/helpers" 23 24 "github.com/spf13/afero" 25 ) 26 27 // GC requires a build first. 28 func (h *HugoSites) GC() (int, error) { 29 s := h.Sites[0] 30 fs := h.PathSpec.BaseFs.Resources.Fs 31 32 imageCacheDir := s.ResourceSpec.GenImagePath 33 if len(imageCacheDir) < 10 { 34 panic("invalid image cache") 35 } 36 assetsCacheDir := s.ResourceSpec.GenAssetsPath 37 if len(assetsCacheDir) < 10 { 38 panic("invalid assets cache") 39 } 40 41 isImageInUse := func(filename string) bool { 42 key := strings.TrimPrefix(filename, imageCacheDir) 43 for _, site := range h.Sites { 44 if site.ResourceSpec.IsInImageCache(key) { 45 return true 46 } 47 } 48 49 return false 50 } 51 52 isAssetInUse := func(filename string) bool { 53 key := strings.TrimPrefix(filename, assetsCacheDir) 54 // These assets are stored in tuplets with an added extension to the key. 55 key = strings.TrimSuffix(key, helpers.Ext(key)) 56 for _, site := range h.Sites { 57 if site.ResourceSpec.ResourceCache.Contains(key) { 58 return true 59 } 60 } 61 62 return false 63 } 64 65 walker := func(dirname string, inUse func(filename string) bool) (int, error) { 66 counter := 0 67 err := afero.Walk(fs, dirname, func(path string, info os.FileInfo, err error) error { 68 if info == nil { 69 return nil 70 } 71 72 if !strings.HasPrefix(path, dirname) { 73 return fmt.Errorf("Invalid state, walk outside of resource dir: %q", path) 74 } 75 76 if info.IsDir() { 77 f, err := fs.Open(path) 78 if err != nil { 79 return nil 80 } 81 defer f.Close() 82 _, err = f.Readdirnames(1) 83 if err == io.EOF { 84 // Empty dir. 85 s.Fs.Source.Remove(path) 86 } 87 88 return nil 89 } 90 91 inUse := inUse(path) 92 if !inUse { 93 err := fs.Remove(path) 94 if err != nil && !os.IsNotExist(err) { 95 s.Log.ERROR.Printf("Failed to remove %q: %s", path, err) 96 } else { 97 counter++ 98 } 99 } 100 return nil 101 }) 102 103 return counter, err 104 } 105 106 imageCounter, err1 := walker(imageCacheDir, isImageInUse) 107 assetsCounter, err2 := walker(assetsCacheDir, isAssetInUse) 108 totalCount := imageCounter + assetsCounter 109 110 if err1 != nil { 111 return totalCount, err1 112 } 113 114 return totalCount, err2 115 116 }