11
11
// See the License for the specific language governing permissions and
12
12
// limitations under the License.
13
13
14
+ // Package filecache provides a file based cache for Hugo.
14
15
package filecache
15
16
16
17
import (
@@ -21,110 +22,111 @@ import (
21
22
"time"
22
23
23
24
"github.com/gohugoio/hugo/common/maps"
24
-
25
25
"github.com/gohugoio/hugo/config"
26
26
27
- "github.com/gohugoio/hugo/helpers"
28
-
29
27
"errors"
30
28
31
29
"github.com/mitchellh/mapstructure"
32
30
"github.com/spf13/afero"
33
31
)
34
32
35
33
const (
36
- cachesConfigKey = "caches"
37
-
38
34
resourcesGenDir = ":resourceDir/_gen"
39
35
cacheDirProject = ":cacheDir/:project"
40
36
)
41
37
42
- var defaultCacheConfig = Config {
38
+ var defaultCacheConfig = FileCacheConfig {
43
39
MaxAge : - 1 , // Never expire
44
40
Dir : cacheDirProject ,
45
41
}
46
42
47
43
const (
48
- cacheKeyGetJSON = "getjson"
49
- cacheKeyGetCSV = "getcsv"
50
- cacheKeyImages = "images"
51
- cacheKeyAssets = "assets"
52
- cacheKeyModules = "modules"
53
- cacheKeyGetResource = "getresource"
44
+ CacheKeyGetJSON = "getjson"
45
+ CacheKeyGetCSV = "getcsv"
46
+ CacheKeyImages = "images"
47
+ CacheKeyAssets = "assets"
48
+ CacheKeyModules = "modules"
49
+ CacheKeyGetResource = "getresource"
54
50
)
55
51
56
- type Configs map [string ]Config
52
+ type Configs map [string ]FileCacheConfig
57
53
54
+ // For internal use.
58
55
func (c Configs ) CacheDirModules () string {
59
- return c [cacheKeyModules ]. Dir
56
+ return c [CacheKeyModules ]. DirCompiled
60
57
}
61
58
62
59
var defaultCacheConfigs = Configs {
63
- cacheKeyModules : {
60
+ CacheKeyModules : {
64
61
MaxAge : - 1 ,
65
62
Dir : ":cacheDir/modules" ,
66
63
},
67
- cacheKeyGetJSON : defaultCacheConfig ,
68
- cacheKeyGetCSV : defaultCacheConfig ,
69
- cacheKeyImages : {
64
+ CacheKeyGetJSON : defaultCacheConfig ,
65
+ CacheKeyGetCSV : defaultCacheConfig ,
66
+ CacheKeyImages : {
70
67
MaxAge : - 1 ,
71
68
Dir : resourcesGenDir ,
72
69
},
73
- cacheKeyAssets : {
70
+ CacheKeyAssets : {
74
71
MaxAge : - 1 ,
75
72
Dir : resourcesGenDir ,
76
73
},
77
- cacheKeyGetResource : Config {
74
+ CacheKeyGetResource : FileCacheConfig {
78
75
MaxAge : - 1 , // Never expire
79
76
Dir : cacheDirProject ,
80
77
},
81
78
}
82
79
83
- type Config struct {
80
+ type FileCacheConfig struct {
84
81
// Max age of cache entries in this cache. Any items older than this will
85
82
// be removed and not returned from the cache.
86
- // a negative value means forever, 0 means cache is disabled.
83
+ // A negative value means forever, 0 means cache is disabled.
84
+ // Hugo is leninent with what types it accepts here, but we recommend using
85
+ // a duration string, a sequence of decimal numbers, each with optional fraction and a unit suffix,
86
+ // such as "300ms", "1.5h" or "2h45m".
87
+ // Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
87
88
MaxAge time.Duration
88
89
89
90
// The directory where files are stored.
90
- Dir string
91
+ Dir string
92
+ DirCompiled string `json:"-"`
91
93
92
94
// Will resources/_gen will get its own composite filesystem that
93
95
// also checks any theme.
94
- isResourceDir bool
96
+ IsResourceDir bool
95
97
}
96
98
97
99
// GetJSONCache gets the file cache for getJSON.
98
100
func (f Caches ) GetJSONCache () * Cache {
99
- return f [cacheKeyGetJSON ]
101
+ return f [CacheKeyGetJSON ]
100
102
}
101
103
102
104
// GetCSVCache gets the file cache for getCSV.
103
105
func (f Caches ) GetCSVCache () * Cache {
104
- return f [cacheKeyGetCSV ]
106
+ return f [CacheKeyGetCSV ]
105
107
}
106
108
107
109
// ImageCache gets the file cache for processed images.
108
110
func (f Caches ) ImageCache () * Cache {
109
- return f [cacheKeyImages ]
111
+ return f [CacheKeyImages ]
110
112
}
111
113
112
114
// ModulesCache gets the file cache for Hugo Modules.
113
115
func (f Caches ) ModulesCache () * Cache {
114
- return f [cacheKeyModules ]
116
+ return f [CacheKeyModules ]
115
117
}
116
118
117
119
// AssetsCache gets the file cache for assets (processed resources, SCSS etc.).
118
120
func (f Caches ) AssetsCache () * Cache {
119
- return f [cacheKeyAssets ]
121
+ return f [CacheKeyAssets ]
120
122
}
121
123
122
124
// GetResourceCache gets the file cache for remote resources.
123
125
func (f Caches ) GetResourceCache () * Cache {
124
- return f [cacheKeyGetResource ]
126
+ return f [CacheKeyGetResource ]
125
127
}
126
128
127
- func DecodeConfig (fs afero.Fs , cfg config.Provider ) (Configs , error ) {
129
+ func DecodeConfig (fs afero.Fs , bcfg config.BaseConfig , m map [ string ] any ) (Configs , error ) {
128
130
c := make (Configs )
129
131
valid := make (map [string ]bool )
130
132
// Add defaults
@@ -133,8 +135,6 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
133
135
valid [k ] = true
134
136
}
135
137
136
- m := cfg .GetStringMap (cachesConfigKey )
137
-
138
138
_ , isOsFs := fs .(* afero.OsFs )
139
139
140
140
for k , v := range m {
@@ -170,22 +170,19 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
170
170
c [name ] = cc
171
171
}
172
172
173
- // This is a very old flag in Hugo, but we need to respect it.
174
- disabled := cfg .GetBool ("ignoreCache" )
175
-
176
173
for k , v := range c {
177
174
dir := filepath .ToSlash (filepath .Clean (v .Dir ))
178
175
hadSlash := strings .HasPrefix (dir , "/" )
179
176
parts := strings .Split (dir , "/" )
180
177
181
178
for i , part := range parts {
182
179
if strings .HasPrefix (part , ":" ) {
183
- resolved , isResource , err := resolveDirPlaceholder (fs , cfg , part )
180
+ resolved , isResource , err := resolveDirPlaceholder (fs , bcfg , part )
184
181
if err != nil {
185
182
return c , err
186
183
}
187
184
if isResource {
188
- v .isResourceDir = true
185
+ v .IsResourceDir = true
189
186
}
190
187
parts [i ] = resolved
191
188
}
@@ -195,33 +192,29 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
195
192
if hadSlash {
196
193
dir = "/" + dir
197
194
}
198
- v .Dir = filepath .Clean (filepath .FromSlash (dir ))
195
+ v .DirCompiled = filepath .Clean (filepath .FromSlash (dir ))
199
196
200
- if ! v .isResourceDir {
201
- if isOsFs && ! filepath .IsAbs (v .Dir ) {
202
- return c , fmt .Errorf ("%q must resolve to an absolute directory" , v .Dir )
197
+ if ! v .IsResourceDir {
198
+ if isOsFs && ! filepath .IsAbs (v .DirCompiled ) {
199
+ return c , fmt .Errorf ("%q must resolve to an absolute directory" , v .DirCompiled )
203
200
}
204
201
205
202
// Avoid cache in root, e.g. / (Unix) or c:\ (Windows)
206
- if len (strings .TrimPrefix (v .Dir , filepath .VolumeName (v .Dir ))) == 1 {
207
- return c , fmt .Errorf ("%q is a root folder and not allowed as cache dir" , v .Dir )
203
+ if len (strings .TrimPrefix (v .DirCompiled , filepath .VolumeName (v .DirCompiled ))) == 1 {
204
+ return c , fmt .Errorf ("%q is a root folder and not allowed as cache dir" , v .DirCompiled )
208
205
}
209
206
}
210
207
211
- if ! strings .HasPrefix (v .Dir , "_gen" ) {
208
+ if ! strings .HasPrefix (v .DirCompiled , "_gen" ) {
212
209
// We do cache eviction (file removes) and since the user can set
213
210
// his/hers own cache directory, we really want to make sure
214
211
// we do not delete any files that do not belong to this cache.
215
212
// We do add the cache name as the root, but this is an extra safe
216
213
// guard. We skip the files inside /resources/_gen/ because
217
214
// that would be breaking.
218
- v .Dir = filepath .Join (v .Dir , filecacheRootDirname , k )
215
+ v .DirCompiled = filepath .Join (v .DirCompiled , FilecacheRootDirname , k )
219
216
} else {
220
- v .Dir = filepath .Join (v .Dir , k )
221
- }
222
-
223
- if disabled {
224
- v .MaxAge = 0
217
+ v .DirCompiled = filepath .Join (v .DirCompiled , k )
225
218
}
226
219
227
220
c [k ] = v
@@ -231,17 +224,15 @@ func DecodeConfig(fs afero.Fs, cfg config.Provider) (Configs, error) {
231
224
}
232
225
233
226
// Resolves :resourceDir => /myproject/resources etc., :cacheDir => ...
234
- func resolveDirPlaceholder (fs afero.Fs , cfg config.Provider , placeholder string ) (cacheDir string , isResource bool , err error ) {
235
- workingDir := cfg .GetString ("workingDir" )
227
+ func resolveDirPlaceholder (fs afero.Fs , bcfg config.BaseConfig , placeholder string ) (cacheDir string , isResource bool , err error ) {
236
228
237
229
switch strings .ToLower (placeholder ) {
238
230
case ":resourcedir" :
239
231
return "" , true , nil
240
232
case ":cachedir" :
241
- d , err := helpers .GetCacheDir (fs , cfg )
242
- return d , false , err
233
+ return bcfg .CacheDir , false , nil
243
234
case ":project" :
244
- return filepath .Base (workingDir ), false , nil
235
+ return filepath .Base (bcfg . WorkingDir ), false , nil
245
236
}
246
237
247
238
return "" , false , fmt .Errorf ("%q is not a valid placeholder (valid values are :cacheDir or :resourceDir)" , placeholder )
0 commit comments