44 "crypto/sha256"
55 "encoding/hex"
66 "fmt"
7+ "io"
78 "os"
89 "path/filepath"
910 "sort"
@@ -373,6 +374,7 @@ func evalEndsWith(args []Node, ctx *EvaluationContext) (bool, error) {
373374
374375// evalHashFiles evaluates the hashFiles(pattern...) function.
375376// Returns the SHA256 hash of the contents of files matching the patterns.
377+ // Uses streaming hash to avoid loading all file contents into memory.
376378func evalHashFiles (args []Node , ctx * EvaluationContext ) (string , error ) {
377379 if len (args ) == 0 {
378380 return "" , nil
@@ -387,7 +389,9 @@ func evalHashFiles(args []Node, ctx *EvaluationContext) (string, error) {
387389 }
388390 }
389391
390- var allBytes []byte
392+ h := sha256 .New ()
393+ hasContent := false
394+
391395 for _ , arg := range args {
392396 patternVal , err := evaluateNode (arg , ctx )
393397 if err != nil {
@@ -409,20 +413,26 @@ func evalHashFiles(args []Node, ctx *EvaluationContext) (string, error) {
409413 if err != nil || info .IsDir () {
410414 continue
411415 }
412- data , err := os .ReadFile (match )
416+
417+ f , err := os .Open (match )
418+ if err != nil {
419+ continue
420+ }
421+
422+ _ , err = io .Copy (h , f )
423+ f .Close ()
413424 if err != nil {
414425 continue
415426 }
416- allBytes = append ( allBytes , data ... )
427+ hasContent = true
417428 }
418429 }
419430
420- if len ( allBytes ) == 0 {
431+ if ! hasContent {
421432 return "" , nil
422433 }
423434
424- hash := sha256 .Sum256 (allBytes )
425- return hex .EncodeToString (hash [:]), nil
435+ return hex .EncodeToString (h .Sum (nil )), nil
426436}
427437
428438// toBool converts a value to a boolean.
0 commit comments