diff --git a/cmd/porto/main.go b/cmd/porto/main.go index 706f6cd..a7d9853 100644 --- a/cmd/porto/main.go +++ b/cmd/porto/main.go @@ -19,6 +19,7 @@ func main() { flagSkipDefaultDirs := flag.Bool("skip-dirs-use-default", true, "Use default skip directory list") flagIncludeInternal := flag.Bool("include-internal", false, "Include internal folders") flagRestrictToFiles := flag.String("restrict-to-files", "", "Regexps of files to restrict the inspection on. It takes precedence over -skip-files") + flagRestrictToDirs := flag.String("restrict-to-dirs", "", "Regexps of dirs to restrict the inspection on. It takes precedence over -skip-dirs") flag.Parse() baseDir := flag.Arg(0) @@ -54,6 +55,11 @@ Add import path to a folder log.Fatalf("failed to build files regexes to include: %v", err) } + restrictToDirsRegex, err := porto.GetRegexpList(*flagRestrictToDirs) + if err != nil { + log.Fatalf("failed to build dirs regexes to include: %v", err) + } + var skipDirsRegex = []*regexp.Regexp{} if *flagSkipDefaultDirs { skipDirsRegex = append(skipDirsRegex, porto.StdExcludeDirRegexps...) @@ -68,7 +74,6 @@ Add import path to a folder WriteResultToFile: *flagWriteOutputToFile, ListDiffFiles: *flagListDiff, IncludeInternal: *flagIncludeInternal, - SkipDirsRegexes: skipDirsRegex, } if len(restrictToFilesRegex) > 0 { @@ -77,6 +82,12 @@ Add import path to a folder opts.SkipFilesRegexes = skipFilesRegex } + if len(restrictToFilesRegex) > 0 { + opts.RestrictToDirsRegexes = restrictToDirsRegex + } else { + opts.SkipDirsRegexes = skipDirsRegex + } + diffCount, err := porto.FindAndAddVanityImportForDir(workingDir, baseAbsDir, opts) if err != nil { log.Fatal(err) diff --git a/import.go b/import.go index 00449e9..d7e742f 100644 --- a/import.go +++ b/import.go @@ -94,7 +94,7 @@ func isUnexportedModule(moduleName string, includeInternal bool) bool { strings.HasSuffix(moduleName, "/internal")) } -func findAndAddVanityImportForModuleDir(workingDir, absDir string, moduleName string, opts Options) (int, error) { +func findAndAddVanityImportForModuleDir(workingDir, baseAbsDir, absDir string, moduleName string, opts Options) (int, error) { if isUnexportedModule(moduleName, opts.IncludeInternal) { return 0, nil } @@ -107,25 +107,35 @@ func findAndAddVanityImportForModuleDir(workingDir, absDir string, moduleName st gc := 0 for _, f := range files { if isDir, dirName := f.IsDir(), f.Name(); isDir { - if matchesAny(opts.SkipDirsRegexes, dirName) { - continue - } - var ( c int err error ) + + relDir := "" + if baseAbsDir != absDir { + relDir, err = filepath.Rel(baseAbsDir, absDir) + if err != nil { + return 0, fmt.Errorf("failed to resolve relative path: %v", err) + } + relDir += pathSeparator + } + if isUnexportedDir(dirName, opts.IncludeInternal) { continue + } else if len(opts.RestrictToDirsRegexes) > 0 && !matchesAny(opts.RestrictToDirsRegexes, relDir+dirName) { + continue + } else if len(opts.SkipDirsRegexes) > 0 && matchesAny(opts.SkipDirsRegexes, relDir+dirName) { + continue } else if newModuleName, ok := findGoModule(absDir + pathSeparator + dirName); ok { // if folder contains go.mod we use it from now on to build the vanity import - c, err = findAndAddVanityImportForModuleDir(workingDir, absDir+pathSeparator+dirName, newModuleName, opts) + c, err = findAndAddVanityImportForModuleDir(workingDir, baseAbsDir, absDir+pathSeparator+dirName, newModuleName, opts) if err != nil { return 0, err } } else { // if not, we add the folder name to the vanity import - if c, err = findAndAddVanityImportForModuleDir(workingDir, absDir+pathSeparator+dirName, moduleName+"/"+dirName, opts); err != nil { + if c, err = findAndAddVanityImportForModuleDir(workingDir, baseAbsDir, absDir+pathSeparator+dirName, moduleName+"/"+dirName, opts); err != nil { return 0, err } } @@ -163,6 +173,8 @@ func findAndAddVanityImportForModuleDir(workingDir, absDir string, moduleName st if err != nil { return 0, fmt.Errorf("failed to resolve relative path: %v", err) } + // TODO(jcchavezs): make this pluggable to allow different output formats + // and test assertions. fmt.Printf("%s: missing right vanity import\n", relFilepath) gc++ } else { @@ -195,7 +207,7 @@ func matchesAny(regexes []*regexp.Regexp, str string) bool { return false } -func findAndAddVanityImportForNonModuleDir(workingDir, absDir string, opts Options) (int, error) { +func findAndAddVanityImportForNonModuleDir(workingDir, baseAbsDir, absDir string, opts Options) (int, error) { files, err := os.ReadDir(absDir) if err != nil { return 0, fmt.Errorf("failed to read %q: %v", absDir, err) @@ -219,11 +231,11 @@ func findAndAddVanityImportForNonModuleDir(workingDir, absDir string, opts Optio absDirName := absDir + pathSeparator + dirName if moduleName, ok := findGoModule(absDirName); ok { - if c, err = findAndAddVanityImportForModuleDir(workingDir, dirName, moduleName, opts); err != nil { + if c, err = findAndAddVanityImportForModuleDir(workingDir, baseAbsDir, dirName, moduleName, opts); err != nil { return 0, err } } else { - if c, err = findAndAddVanityImportForNonModuleDir(workingDir, absDirName, opts); err != nil { + if c, err = findAndAddVanityImportForNonModuleDir(workingDir, baseAbsDir, absDirName, opts); err != nil { return 0, err } } @@ -248,13 +260,15 @@ type Options struct { IncludeInternal bool // Set of regex for matching files to be included RestrictToFilesRegexes []*regexp.Regexp + // Set of regex for matching dirs to be included + RestrictToDirsRegexes []*regexp.Regexp } // FindAndAddVanityImportForDir scans all files in a folder and based on go.mod files // encountered decides wether add a vanity import or not. func FindAndAddVanityImportForDir(workingDir, absDir string, opts Options) (int, error) { if moduleName, ok := findGoModule(absDir); ok { - return findAndAddVanityImportForModuleDir(workingDir, absDir, moduleName, opts) + return findAndAddVanityImportForModuleDir(workingDir, absDir, absDir, moduleName, opts) } files, err := os.ReadDir(absDir) @@ -281,11 +295,11 @@ func FindAndAddVanityImportForDir(workingDir, absDir string, opts Options) (int, ) absDirName := absDir + pathSeparator + dirName if moduleName, ok := findGoModule(absDirName); ok { - if c, err = findAndAddVanityImportForModuleDir(workingDir, dirName, moduleName, opts); err != nil { + if c, err = findAndAddVanityImportForModuleDir(workingDir, absDir, dirName, moduleName, opts); err != nil { return 0, err } } else { - if c, err = findAndAddVanityImportForNonModuleDir(workingDir, absDirName, opts); err != nil { + if c, err = findAndAddVanityImportForNonModuleDir(workingDir, absDir, absDirName, opts); err != nil { return 0, err } } diff --git a/import_test.go b/import_test.go index 64e7cb9..9778d54 100644 --- a/import_test.go +++ b/import_test.go @@ -48,6 +48,7 @@ func TestFindFilesWithVanityImport(t *testing.T) { c, err := findAndAddVanityImportForModuleDir( cwd, cwd+"/testdata/leftpad", + cwd+"/testdata/leftpad", "github.com/jcchavezs/porto-integration-leftpad", Options{ ListDiffFiles: true, @@ -62,6 +63,7 @@ func TestFindFilesWithVanityImport(t *testing.T) { c, err := findAndAddVanityImportForModuleDir( cwd, cwd+"/testdata/nopad", + cwd+"/testdata/nopad", "github.com/jcchavezs/porto-integration/nopad", Options{ ListDiffFiles: true, @@ -76,6 +78,7 @@ func TestFindFilesWithVanityImport(t *testing.T) { c, err := findAndAddVanityImportForModuleDir( cwd, cwd+"/testdata/leftpad", + cwd+"/testdata/leftpad", "github.com/jcchavezs/porto-integration-leftpad", Options{ ListDiffFiles: true, @@ -91,6 +94,7 @@ func TestFindFilesWithVanityImport(t *testing.T) { c, err := findAndAddVanityImportForModuleDir( cwd, cwd+"/testdata", + cwd+"/testdata", "github.com/jcchavezs/porto/integration", Options{ ListDiffFiles: true, @@ -103,13 +107,14 @@ func TestFindFilesWithVanityImport(t *testing.T) { ) require.NoError(t, err) - assert.Equal(t, 1, c) + assert.Equal(t, 2, c) }) t.Run("restrict to files", func(t *testing.T) { c, err := findAndAddVanityImportForModuleDir( cwd, cwd+"/testdata/leftpad", + cwd+"/testdata/leftpad", "github.com/jcchavezs/porto-integration-leftpad", Options{ ListDiffFiles: true, @@ -121,10 +126,27 @@ func TestFindFilesWithVanityImport(t *testing.T) { assert.Equal(t, 1, c) }) + t.Run("restrict to dir", func(t *testing.T) { + c, err := findAndAddVanityImportForModuleDir( + cwd, + cwd+"/testdata", + cwd+"/testdata", + "github.com/jcchavezs/porto/integration", + Options{ + ListDiffFiles: true, + RestrictToDirsRegexes: []*regexp.Regexp{regexp.MustCompile(`^withoutgomod`)}, + }, + ) + + require.NoError(t, err) + assert.Equal(t, 2, c) + }) + t.Run("skip and include file", func(t *testing.T) { c, err := findAndAddVanityImportForModuleDir( cwd, cwd+"/testdata/leftpad", + cwd+"/testdata/leftpad", "github.com/jcchavezs/porto-integration-leftpad", Options{ ListDiffFiles: true, diff --git a/testdata/withoutgomod/more/doc.go b/testdata/withoutgomod/more/doc.go new file mode 100644 index 0000000..59a3870 --- /dev/null +++ b/testdata/withoutgomod/more/doc.go @@ -0,0 +1 @@ +package more