@@ -21,6 +21,7 @@ import (
21
21
"encoding/hex"
22
22
"fmt"
23
23
"io"
24
+ "io/fs"
24
25
"os"
25
26
"os/exec"
26
27
"path/filepath"
@@ -343,6 +344,39 @@ func (w *logWriter) Write(p []byte) (n int, err error) {
343
344
return len (p ), w .host .Log (w .ctx , w .severity , w .urn , string (p ))
344
345
}
345
346
347
+ type contextHash struct {
348
+ contextPath string
349
+ input bytes.Buffer
350
+ }
351
+
352
+ func newContextHash (contextPath string ) * contextHash {
353
+ return & contextHash {contextPath : contextPath }
354
+ }
355
+
356
+ func (ch * contextHash ) hashPath (path string , fileMode fs.FileMode ) error {
357
+ f , err := os .Open (filepath .Join (ch .contextPath , path ))
358
+ if err != nil {
359
+ return fmt .Errorf ("open %s: %w" , path , err )
360
+ }
361
+ defer f .Close ()
362
+ h := sha256 .New ()
363
+ _ , err = io .Copy (h , f )
364
+ if err != nil {
365
+ return fmt .Errorf ("read %s: %w" , path , err )
366
+ }
367
+ ch .input .Write ([]byte (path ))
368
+ ch .input .Write ([]byte (fileMode .String ()))
369
+ ch .input .Write (h .Sum (nil ))
370
+ ch .input .WriteByte (0 )
371
+ return nil
372
+ }
373
+
374
+ func (ch * contextHash ) hexSum () string {
375
+ h := sha256 .New ()
376
+ ch .input .WriteTo (h )
377
+ return hex .EncodeToString (h .Sum (nil ))
378
+ }
379
+
346
380
func hashContext (contextPath string , dockerfile string ) (string , error ) {
347
381
dockerIgnore , err := os .ReadFile (filepath .Join (contextPath , ".dockerignore" ))
348
382
if err != nil && ! os .IsNotExist (err ) {
@@ -356,7 +390,11 @@ func hashContext(contextPath string, dockerfile string) (string, error) {
356
390
if err != nil {
357
391
return "" , fmt .Errorf ("unable to load rules from .dockerignore: %w" , err )
358
392
}
359
- var hashInput []byte
393
+ ch := newContextHash (contextPath )
394
+ err = ch .hashPath (dockerfile , 0 )
395
+ if err != nil {
396
+ return "" , fmt .Errorf ("hashing dockerfile %q: %w" , dockerfile , err )
397
+ }
360
398
err = filepath .WalkDir (contextPath , func (path string , d os.DirEntry , err error ) error {
361
399
if err != nil {
362
400
return err
@@ -381,43 +419,18 @@ func hashContext(contextPath string, dockerfile string) (string, error) {
381
419
} else if d .IsDir () {
382
420
return nil
383
421
}
384
- f , err := os . Open ( filepath . Join ( contextPath , path ) )
422
+ info , err := d . Info ( )
385
423
if err != nil {
386
- return fmt .Errorf ("open %s : %w" , path , err )
424
+ return fmt .Errorf ("determining mode for %q : %w" , path , err )
387
425
}
388
- defer f .Close ()
389
- h := sha256 .New ()
390
- _ , err = io .Copy (h , f )
426
+ err = ch .hashPath (path , info .Mode ())
391
427
if err != nil {
392
- return fmt .Errorf ("read %s : %w" , path , err )
428
+ return fmt .Errorf ("hashing %q : %w" , path , err )
393
429
}
394
- hashInput = append (hashInput , path ... )
395
- hashInput = append (hashInput , h .Sum (nil )... )
396
- hashInput = append (hashInput , byte (0 ))
397
430
return nil
398
431
})
399
432
if err != nil {
400
433
return "" , fmt .Errorf ("unable to hash build context: %w" , err )
401
434
}
402
- // Add the Dockerfile hash directly, since it might not be in the build
403
- // context.
404
- {
405
- path := filepath .Join (contextPath , dockerfile )
406
- f , err := os .Open (path )
407
- if err != nil {
408
- return "" , fmt .Errorf ("open %s: %w" , path , err )
409
- }
410
- defer f .Close ()
411
- h := sha256 .New ()
412
- _ , err = io .Copy (h , f )
413
- if err != nil {
414
- return "" , fmt .Errorf ("read %s: %w" , path , err )
415
- }
416
- hashInput = append (hashInput , path ... )
417
- hashInput = append (hashInput , h .Sum (nil )... )
418
- hashInput = append (hashInput , byte (0 ))
419
- }
420
- h := sha256 .New ()
421
- h .Write (hashInput )
422
- return hex .EncodeToString (h .Sum (nil )), nil
435
+ return ch .hexSum (), nil
423
436
}
0 commit comments