@@ -13,6 +13,7 @@ import (
13
13
"path"
14
14
"path/filepath"
15
15
"strings"
16
+ "time"
16
17
17
18
"github.com/cheggaaa/pb/v3"
18
19
"github.com/containerd/continuity/fs"
@@ -44,6 +45,8 @@ const (
44
45
type Result struct {
45
46
Status Status
46
47
CachePath string // "/Users/foo/Library/Caches/lima/download/by-url-sha256/<SHA256_OF_URL>/data"
48
+ LastModified time.Time
49
+ ContentType string
47
50
ValidatedDigest bool
48
51
}
49
52
@@ -118,6 +121,38 @@ func WithExpectedDigest(expectedDigest digest.Digest) Opt {
118
121
}
119
122
}
120
123
124
+ func readFile (path string ) string {
125
+ if path == "" {
126
+ return ""
127
+ }
128
+ if _ , err := os .Stat (path ); err != nil {
129
+ return ""
130
+ }
131
+ b , err := os .ReadFile (path )
132
+ if err != nil {
133
+ return ""
134
+ }
135
+ return string (b )
136
+ }
137
+
138
+ func readTime (path string ) time.Time {
139
+ if path == "" {
140
+ return time.Time {}
141
+ }
142
+ if _ , err := os .Stat (path ); err != nil {
143
+ return time.Time {}
144
+ }
145
+ b , err := os .ReadFile (path )
146
+ if err != nil {
147
+ return time.Time {}
148
+ }
149
+ t , err := time .Parse (http .TimeFormat , string (b ))
150
+ if err != nil {
151
+ return time.Time {}
152
+ }
153
+ return t
154
+ }
155
+
121
156
// Download downloads the remote resource into the local path.
122
157
//
123
158
// Download caches the remote resource if WithCache or WithCacheDir option is specified.
@@ -175,7 +210,7 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result,
175
210
}
176
211
177
212
if o .cacheDir == "" {
178
- if err := downloadHTTP (ctx , localPath , remote , o .description , o .expectedDigest ); err != nil {
213
+ if err := downloadHTTP (ctx , localPath , "" , "" , remote , o .description , o .expectedDigest ); err != nil {
179
214
return nil , err
180
215
}
181
216
res := & Result {
@@ -187,6 +222,8 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result,
187
222
188
223
shad := cacheDirectoryPath (o .cacheDir , remote )
189
224
shadData := filepath .Join (shad , "data" )
225
+ shadTime := filepath .Join (shad , "time" )
226
+ shadType := filepath .Join (shad , "type" )
190
227
shadDigest , err := cacheDigestPath (shad , o .expectedDigest )
191
228
if err != nil {
192
229
return nil , err
@@ -210,6 +247,8 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result,
210
247
res := & Result {
211
248
Status : StatusUsedCache ,
212
249
CachePath : shadData ,
250
+ LastModified : readTime (shadTime ),
251
+ ContentType : readFile (shadType ),
213
252
ValidatedDigest : o .expectedDigest != "" ,
214
253
}
215
254
return res , nil
@@ -224,7 +263,7 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result,
224
263
if err := os .WriteFile (shadURL , []byte (remote ), 0o644 ); err != nil {
225
264
return nil , err
226
265
}
227
- if err := downloadHTTP (ctx , shadData , remote , o .description , o .expectedDigest ); err != nil {
266
+ if err := downloadHTTP (ctx , shadData , shadTime , shadType , remote , o .description , o .expectedDigest ); err != nil {
228
267
return nil , err
229
268
}
230
269
// no need to pass the digest to copyLocal(), as we already verified the digest
@@ -239,6 +278,8 @@ func Download(ctx context.Context, local, remote string, opts ...Opt) (*Result,
239
278
res := & Result {
240
279
Status : StatusDownloaded ,
241
280
CachePath : shadData ,
281
+ LastModified : readTime (shadTime ),
282
+ ContentType : readFile (shadType ),
242
283
ValidatedDigest : o .expectedDigest != "" ,
243
284
}
244
285
return res , nil
@@ -266,6 +307,8 @@ func Cached(remote string, opts ...Opt) (*Result, error) {
266
307
267
308
shad := cacheDirectoryPath (o .cacheDir , remote )
268
309
shadData := filepath .Join (shad , "data" )
310
+ shadTime := filepath .Join (shad , "time" )
311
+ shadType := filepath .Join (shad , "type" )
269
312
shadDigest , err := cacheDigestPath (shad , o .expectedDigest )
270
313
if err != nil {
271
314
return nil , err
@@ -285,6 +328,8 @@ func Cached(remote string, opts ...Opt) (*Result, error) {
285
328
res := & Result {
286
329
Status : StatusUsedCache ,
287
330
CachePath : shadData ,
331
+ LastModified : readTime (shadTime ),
332
+ ContentType : readFile (shadType ),
288
333
ValidatedDigest : o .expectedDigest != "" ,
289
334
}
290
335
return res , nil
@@ -293,6 +338,8 @@ func Cached(remote string, opts ...Opt) (*Result, error) {
293
338
// cacheDirectoryPath returns the cache subdirectory path.
294
339
// - "url" file contains the url
295
340
// - "data" file contains the data
341
+ // - "time" file contains the time (Last-Modified header)
342
+ // - "type" file contains the type (Content-Type header)
296
343
func cacheDirectoryPath (cacheDir , remote string ) string {
297
344
return filepath .Join (cacheDir , "download" , "by-url-sha256" , fmt .Sprintf ("%x" , sha256 .Sum256 ([]byte (remote ))))
298
345
}
@@ -470,7 +517,7 @@ func validateLocalFileDigest(localPath string, expectedDigest digest.Digest) err
470
517
return nil
471
518
}
472
519
473
- func downloadHTTP (ctx context.Context , localPath , url , description string , expectedDigest digest.Digest ) error {
520
+ func downloadHTTP (ctx context.Context , localPath , lastModified , contentType , url , description string , expectedDigest digest.Digest ) error {
474
521
if localPath == "" {
475
522
return fmt .Errorf ("downloadHTTP: got empty localPath" )
476
523
}
@@ -489,6 +536,18 @@ func downloadHTTP(ctx context.Context, localPath, url, description string, expec
489
536
if err != nil {
490
537
return err
491
538
}
539
+ if lastModified != "" {
540
+ lm := resp .Header .Get ("Last-Modified" )
541
+ if err := os .WriteFile (lastModified , []byte (lm ), 0o644 ); err != nil {
542
+ return err
543
+ }
544
+ }
545
+ if contentType != "" {
546
+ ct := resp .Header .Get ("Content-Type" )
547
+ if err := os .WriteFile (contentType , []byte (ct ), 0o644 ); err != nil {
548
+ return err
549
+ }
550
+ }
492
551
defer resp .Body .Close ()
493
552
bar , err := progressbar .New (resp .ContentLength )
494
553
if err != nil {
0 commit comments