@@ -33,6 +33,7 @@ import (
3333 oci "github.com/fluxcd/pkg/oci/client"
3434 "github.com/fluxcd/pkg/tar"
3535 sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
36+ "github.com/go-git/go-git/v5/plumbing/format/gitignore"
3637 "github.com/gonvenience/ytbx"
3738 "github.com/google/shlex"
3839 "github.com/hexops/gotextdiff"
@@ -177,6 +178,16 @@ func diffArtifactCmdRun(cmd *cobra.Command, args []string) error {
177178 return fmt .Errorf ("%q and %q: %w" , from , to , ErrDiffArtifactChanged )
178179}
179180
181+ func newMatcher (ignorePaths []string ) gitignore.Matcher {
182+ var patterns []gitignore.Pattern
183+
184+ for _ , path := range ignorePaths {
185+ patterns = append (patterns , gitignore .ParsePattern (path , nil ))
186+ }
187+
188+ return gitignore .NewMatcher (patterns )
189+ }
190+
180191func diffArtifact (ctx context.Context , client * oci.Client , from , to string , flags diffArtifactFlags ) (string , error ) {
181192 fromDir , fromCleanup , err := loadArtifact (ctx , client , from )
182193 if err != nil {
@@ -190,7 +201,7 @@ func diffArtifact(ctx context.Context, client *oci.Client, from, to string, flag
190201 }
191202 defer toCleanup ()
192203
193- return flags .differ .Diff (ctx , fromDir , toDir )
204+ return flags .differ .Diff (ctx , fromDir , toDir , flags . ignorePaths )
194205}
195206
196207// loadArtifact ensures that the artifact is in a local directory that can be
@@ -279,6 +290,7 @@ func extractTo(archivePath, destDir string) error {
279290 if err != nil {
280291 return err
281292 }
293+ defer archiveFH .Close ()
282294
283295 if err := tar .Untar (archiveFH , destDir ); err != nil {
284296 return fmt .Errorf ("Untar(%q, %q): %w" , archivePath , destDir , err )
@@ -303,21 +315,25 @@ func copyFile(from io.Reader, to string) error {
303315
304316type differ interface {
305317 // Diff compares the two local directories "to" and "from" and returns their differences, or an empty string if they are equal.
306- Diff (ctx context.Context , from , to string ) (string , error )
318+ Diff (ctx context.Context , from , to string , ignorePaths [] string ) (string , error )
307319}
308320
309321type unifiedDiff struct {}
310322
311- func (d unifiedDiff ) Diff (_ context.Context , fromDir , toDir string ) (string , error ) {
312- fromFiles , err := filesInDir (fromDir )
323+ func (d unifiedDiff ) Diff (_ context.Context , fromDir , toDir string , ignorePaths []string ) (string , error ) {
324+ matcher := newMatcher (ignorePaths )
325+
326+ fromFiles , err := filesInDir (fromDir , matcher )
313327 if err != nil {
314328 return "" , err
315329 }
330+ fmt .Fprintf (os .Stderr , "fromFiles = %v\n " , fromFiles )
316331
317- toFiles , err := filesInDir (toDir )
332+ toFiles , err := filesInDir (toDir , matcher )
318333 if err != nil {
319334 return "" , err
320335 }
336+ fmt .Fprintf (os .Stderr , "toFiles = %v\n " , toFiles )
321337
322338 allFiles := fromFiles .Union (toFiles )
323339
@@ -338,13 +354,19 @@ func (d unifiedDiff) Diff(_ context.Context, fromDir, toDir string) (string, err
338354func (d unifiedDiff ) diffFiles (fromDir , toDir , relPath string ) (string , error ) {
339355 fromPath := filepath .Join (fromDir , relPath )
340356 fromData , err := d .readFile (fromPath )
341- if err != nil {
357+ switch {
358+ case errors .Is (err , fs .ErrNotExist ):
359+ return fmt .Sprintf ("Only in %s: %s\n " , toDir , relPath ), nil
360+ case err != nil :
342361 return "" , fmt .Errorf ("readFile(%q): %w" , fromPath , err )
343362 }
344363
345364 toPath := filepath .Join (toDir , relPath )
346365 toData , err := d .readFile (toPath )
347- if err != nil {
366+ switch {
367+ case errors .Is (err , fs .ErrNotExist ):
368+ return fmt .Sprintf ("Only in %s: %s\n " , fromDir , relPath ), nil
369+ case err != nil :
348370 return "" , fmt .Errorf ("readFile(%q): %w" , toPath , err )
349371 }
350372
@@ -355,30 +377,41 @@ func (d unifiedDiff) diffFiles(fromDir, toDir, relPath string) (string, error) {
355377func (d unifiedDiff ) readFile (path string ) ([]byte , error ) {
356378 file , err := os .Open (path )
357379 if err != nil {
358- return nil , fmt . Errorf ( "os.Open(%q): %w" , path , err )
380+ return nil , err
359381 }
360382 defer file .Close ()
361383
362384 return io .ReadAll (file )
363385}
364386
365- func filesInDir (root string ) (stringset.Set , error ) {
387+ func splitPath (path string ) []string {
388+ return strings .Split (path , string ([]rune {filepath .Separator }))
389+ }
390+
391+ func filesInDir (root string , matcher gitignore.Matcher ) (stringset.Set , error ) {
366392 var files stringset.Set
367393
368394 err := filepath .WalkDir (root , func (path string , d fs.DirEntry , err error ) error {
369395 if err != nil {
370396 return err
371397 }
372398
373- if ! d .Type ().IsRegular () {
374- return nil
375- }
376-
377399 relPath , err := filepath .Rel (root , path )
378400 if err != nil {
379401 return fmt .Errorf ("filepath.Rel(%q, %q): %w" , root , path , err )
380402 }
381403
404+ if matcher .Match (splitPath (relPath ), d .IsDir ()) {
405+ if d .IsDir () {
406+ return fs .SkipDir
407+ }
408+ return nil
409+ }
410+
411+ if ! d .Type ().IsRegular () {
412+ return nil
413+ }
414+
382415 files .Add (relPath )
383416 return nil
384417 })
@@ -395,7 +428,7 @@ type externalDiff struct{}
395428// externalDiffVar is the environment variable users can use to overwrite the external diff command.
396429const externalDiffVar = "FLUX_EXTERNAL_DIFF"
397430
398- func (externalDiff ) Diff (ctx context.Context , fromDir , toDir string ) (string , error ) {
431+ func (externalDiff ) Diff (ctx context.Context , fromDir , toDir string , ignorePaths [] string ) (string , error ) {
399432 cmdline := os .Getenv (externalDiffVar )
400433 if cmdline == "" {
401434 return "" , fmt .Errorf ("the required %q environment variable is unset" , externalDiffVar )
@@ -409,6 +442,10 @@ func (externalDiff) Diff(ctx context.Context, fromDir, toDir string) (string, er
409442 var executable string
410443 executable , args = args [0 ], args [1 :]
411444
445+ for _ , path := range ignorePaths {
446+ args = append (args , "--exclude" , path )
447+ }
448+
412449 args = append (args , fromDir , toDir )
413450
414451 cmd := exec .CommandContext (ctx , executable , args ... )
@@ -435,7 +472,7 @@ type dyffBuiltin struct {
435472 opts []dyff.CompareOption
436473}
437474
438- func (d dyffBuiltin ) Diff (ctx context.Context , fromDir , toDir string ) (string , error ) {
475+ func (d dyffBuiltin ) Diff (ctx context.Context , fromDir , toDir string , _ [] string ) (string , error ) {
439476 fromFile , err := ytbx .LoadDirectory (fromDir )
440477 if err != nil {
441478 return "" , fmt .Errorf ("ytbx.LoadDirectory(%q): %w" , fromDir , err )
0 commit comments