1
- // Copyright 2021 The Hugo Authors. All rights reserved.
1
+ // Copyright 2024 The Hugo Authors. All rights reserved.
2
2
//
3
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
4
// you may not use this file except in compliance with the License.
@@ -159,9 +159,92 @@ func Uglify(in string) string {
159
159
return path .Clean (in )
160
160
}
161
161
162
+ // URLEscape escapes unicode letters.
163
+ func URLEscape (uri string ) string {
164
+ // escape unicode letters
165
+ u , err := url .Parse (uri )
166
+ if err != nil {
167
+ panic (err )
168
+ }
169
+ return u .String ()
170
+ }
171
+
172
+ // TrimExt trims the extension from a path..
173
+ func TrimExt (in string ) string {
174
+ return strings .TrimSuffix (in , path .Ext (in ))
175
+ }
176
+
177
+ // From https://github.com/golang/go/blob/e0c76d95abfc1621259864adb3d101cf6f1f90fc/src/cmd/go/internal/web/url.go#L45
178
+ func UrlFromFilename (filename string ) (* url.URL , error ) {
179
+ if ! filepath .IsAbs (filename ) {
180
+ return nil , fmt .Errorf ("filepath must be absolute" )
181
+ }
182
+
183
+ // If filename has a Windows volume name, convert the volume to a host and prefix
184
+ // per https://blogs.msdn.microsoft.com/ie/2006/12/06/file-uris-in-windows/.
185
+ if vol := filepath .VolumeName (filename ); vol != "" {
186
+ if strings .HasPrefix (vol , `\\` ) {
187
+ filename = filepath .ToSlash (filename [2 :])
188
+ i := strings .IndexByte (filename , '/' )
189
+
190
+ if i < 0 {
191
+ // A degenerate case.
192
+ // \\host.example.com (without a share name)
193
+ // becomes
194
+ // file://host.example.com/
195
+ return & url.URL {
196
+ Scheme : "file" ,
197
+ Host : filename ,
198
+ Path : "/" ,
199
+ }, nil
200
+ }
201
+
202
+ // \\host.example.com\Share\path\to\file
203
+ // becomes
204
+ // file://host.example.com/Share/path/to/file
205
+ return & url.URL {
206
+ Scheme : "file" ,
207
+ Host : filename [:i ],
208
+ Path : filepath .ToSlash (filename [i :]),
209
+ }, nil
210
+ }
211
+
212
+ // C:\path\to\file
213
+ // becomes
214
+ // file:///C:/path/to/file
215
+ return & url.URL {
216
+ Scheme : "file" ,
217
+ Path : "/" + filepath .ToSlash (filename ),
218
+ }, nil
219
+ }
220
+
221
+ // /path/to/file
222
+ // becomes
223
+ // file:///path/to/file
224
+ return & url.URL {
225
+ Scheme : "file" ,
226
+ Path : filepath .ToSlash (filename ),
227
+ }, nil
228
+ }
229
+
230
+ // UrlStringToFilename converts a URL string to a filename.
231
+ // Returns the filename and a boolean indicating success.
232
+ // If ParseRequestURI fails, the input is just converted to OS specific slashes and returned.
233
+ func UrlStringToFilename (s string ) (string , bool ) {
234
+ u , err := url .ParseRequestURI (s )
235
+ if err != nil {
236
+ return filepath .FromSlash (s ), false
237
+ }
238
+ u .Scheme = fileURLSchemeReplacer .Replace (u .Scheme )
239
+ return UrlToFilename (u )
240
+ }
241
+
242
+ // hugostdin is used in the Dart Sass integration.
243
+ var fileURLSchemeReplacer = strings .NewReplacer ("hugostdin" , "file" )
244
+
162
245
// UrlToFilename converts the URL s to a filename.
163
246
// If ParseRequestURI fails, the input is just converted to OS specific slashes and returned.
164
- func UrlToFilename (s string ) (string , bool ) {
247
+ func doUrlStringToFilename (s string ) (string , bool ) {
165
248
u , err := url .ParseRequestURI (s )
166
249
if err != nil {
167
250
return filepath .FromSlash (s ), false
@@ -184,12 +267,29 @@ func UrlToFilename(s string) (string, bool) {
184
267
return p , true
185
268
}
186
269
187
- // URLEscape escapes unicode letters.
188
- func URLEscape (uri string ) string {
189
- // escape unicode letters
190
- u , err := url .Parse (uri )
270
+ // Based on https://github.com/golang/go/blob/e0c76d95abfc1621259864adb3d101cf6f1f90fc/src/cmd/go/internal/web/url.go#L45
271
+ func UrlToFilename (u * url.URL ) (string , bool ) {
272
+ if u .Scheme != "file" {
273
+ return "" , false
274
+ }
275
+
276
+ checkAbs := func (path string ) (string , bool ) {
277
+ if ! filepath .IsAbs (path ) {
278
+ return "" , false
279
+ }
280
+ return path , true
281
+ }
282
+
283
+ if u .Path == "" {
284
+ if u .Host != "" || u .Opaque == "" {
285
+ return "" , false
286
+ }
287
+ return checkAbs (filepath .FromSlash (u .Opaque ))
288
+ }
289
+
290
+ path , err := convertFileURLPath (u .Host , u .Path )
191
291
if err != nil {
192
- panic ( err )
292
+ return path , false
193
293
}
194
- return u . String ( )
294
+ return checkAbs ( path )
195
295
}
0 commit comments