diff --git a/internal/file/finder.go b/internal/file/finder.go index 982decef..0b168aae 100644 --- a/internal/file/finder.go +++ b/internal/file/finder.go @@ -77,29 +77,20 @@ func (finder *Finder) GetConfigPath(rootPath string, exclusions []string, inclus return configPath } -// GetGroups return all file groups in specified path recursively. -func (finder *Finder) GetGroups(options DebrickedOptions) (Groups, error) { +func (finder *Finder) GetIncludedGroups(formats []*CompiledFormat, options DebrickedOptions) (Groups, error) { + // NOTE: inefficient because it walks into excluded directories var groups Groups - - formats, err := finder.GetSupportedFormats() - if err != nil { - return groups, err - } - if len(options.RootPath) == 0 { - options.RootPath = filepath.Base("") - } - - // Traverse files to find dependency file groups - err = filepath.Walk( + err := filepath.Walk( options.RootPath, func(path string, fileInfo os.FileInfo, err error) error { if err != nil { return err } - if !fileInfo.IsDir() && !Excluded(options.Exclusions, options.Inclusions, path) { + var excluded = Excluded(options.Exclusions, options.Inclusions, path) + + if !fileInfo.IsDir() && !excluded { for _, format := range formats { if groups.Match(format, path, options.LockFileOnly) { - break } } @@ -108,6 +99,66 @@ func (finder *Finder) GetGroups(options DebrickedOptions) (Groups, error) { return nil }, ) + return groups, err +} + +func (finder *Finder) GetExcludedGroups(formats []*CompiledFormat, options DebrickedOptions) (Groups, []string, error) { + var excludedGroups Groups + var excludedFiles []string + err := filepath.Walk( + options.RootPath, + func(path string, fileInfo os.FileInfo, err error) error { + if err != nil { + return err + } + if !fileInfo.IsDir() { + for _, format := range formats { + if excludedGroups.Match(format, path, options.LockFileOnly) { + excludedFiles = append(excludedFiles, path) + break + } + } + } + return nil + }, + ) + return excludedGroups, excludedFiles, err +} + +// GetGroups return all file groups in specified path recursively. +func (finder *Finder) GetGroups(options DebrickedOptions) (Groups, error) { + var groups Groups + var noGroupsFound bool + + formats, err := finder.GetSupportedFormats() + if err != nil { + return groups, err + } + if len(options.RootPath) == 0 { + options.RootPath = filepath.Base("") + } + + // Traverse files to find dependency file groups + groups, err = finder.GetIncludedGroups(formats, options) + noGroupsFound = len(groups.groups) == 0 + if noGroupsFound { + // No dependencies found. (should rarely happen) + // Traverse again to see if dependency files were excluded. + _, excludedFiles, excludedErr := finder.GetExcludedGroups(formats, options) + if len(excludedFiles) > 0 { + fmt.Println("The following files were excluded, resulting in no dependency files found.") + for _, file := range excludedFiles { + fmt.Println(file) + } + fmt.Println("Please change the inclusion and exclusion options if an important file or directory was missed.") + } else { + fmt.Println("No dependency file matches found with current configuration.") + fmt.Println("Please change the inclusion and exclusion options if an important file or directory was missed.") + } + if excludedErr != nil { + return groups, err + } + } groups.FilterGroupsByStrictness(options.Strictness) diff --git a/internal/file/finder_test.go b/internal/file/finder_test.go index d61e8c58..86630baa 100644 --- a/internal/file/finder_test.go +++ b/internal/file/finder_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "io" "net/http" + "os" "path" "path/filepath" "sort" @@ -185,6 +186,92 @@ func TestGetGroupsPIP(t *testing.T) { } +func TestGetGroupsAllExcluded(t *testing.T) { + setUp(true) + path := "testdata/misc" + const nbrOfGroups = 0 + + oldStdout := os.Stdout + read, write, _ := os.Pipe() + os.Stdout = write + + fileGroups, err := finder.GetGroups( + DebrickedOptions{ + RootPath: path, + Exclusions: []string{"**/**"}, + Inclusions: []string{}, + LockFileOnly: false, + Strictness: StrictAll, + }, + ) + + write.Close() + os.Stdout = oldStdout + var buf bytes.Buffer + io.Copy(&buf, read) + + assert.NoError(t, err) + assert.Equalf(t, nbrOfGroups, fileGroups.Size(), "failed to assert that %d groups were created. %d was found", nbrOfGroups, fileGroups.Size()) + + // Define the expected output + expectedStart := "The following files were excluded, resulting in no dependency files found." + expectedEnd := "Please change the inclusion and exclusion options if an important file or directory was missed." + expectedExcludedFile := "requirements.txt" + + // Compare the actual output to the expected output + actualString := buf.String() + if !strings.Contains(actualString, expectedStart) { + t.Errorf("Expected %q but got %q", expectedStart, actualString) + } + if !strings.Contains(actualString, expectedEnd) { + t.Errorf("Expected %q but got %q", expectedEnd, actualString) + } + if !strings.Contains(actualString, expectedExcludedFile) { + t.Errorf("Expected %q but got %q", expectedExcludedFile, actualString) + } +} + +func TestGetGroupsAllExcludedByStrictness(t *testing.T) { + setUp(true) + path := "testdata/misc" + const nbrOfGroups = 0 + + oldStdout := os.Stdout + read, write, _ := os.Pipe() + os.Stdout = write + + fileGroups, err := finder.GetGroups( + DebrickedOptions{ + RootPath: path, + Exclusions: []string{"**/composer.**"}, //the only manifest+lock pair in testdata/misc + Inclusions: []string{}, + LockFileOnly: false, + Strictness: StrictPairs, + }, + ) + + write.Close() + os.Stdout = oldStdout + var buf bytes.Buffer + io.Copy(&buf, read) + + assert.NoError(t, err) + assert.Equalf(t, nbrOfGroups, fileGroups.Size(), "failed to assert that %d groups were created. %d was found", nbrOfGroups, fileGroups.Size()) + + // Define the expected output + expectedStart := "The following files and directories were filtered out by strictness flag, resulting in no file matches." + expectedEnd := "Please change the inclusion and exclusion options if an important file or directory was missed." + + // Compare the actual output to the expected output + actualString := buf.String() + if !strings.Contains(actualString, expectedStart) { + t.Errorf("Expected %q but got %q", expectedStart, actualString) + } + if !strings.Contains(actualString, expectedEnd) { + t.Errorf("Expected %q but got %q", expectedEnd, actualString) + } +} + func TestGetGroupsWithOnlyLockFiles(t *testing.T) { setUp(true) path := "testdata/misc" diff --git a/internal/file/groups.go b/internal/file/groups.go index 328fa4be..0686e041 100644 --- a/internal/file/groups.go +++ b/internal/file/groups.go @@ -1,6 +1,7 @@ package file import ( + "fmt" "path/filepath" ) @@ -79,6 +80,14 @@ func (gs *Groups) FilterGroupsByStrictness(strictness int) { } } + if len(groups) == 0 && len(gs.groups) > 0 { + fmt.Println("The following files and directories were filtered out by strictness flag, resulting in no file matches.") + for _, group := range gs.groups { + fmt.Println(group.GetAllFiles()) + } + fmt.Println("Please change the inclusion and exclusion options if an important file or directory was missed.") + } + gs.groups = groups }