From 30d1521b25a11e23d458759164227d0c0273f75e Mon Sep 17 00:00:00 2001 From: Artur Rychlewicz <8393226+artuross@users.noreply.github.com> Date: Thu, 16 Feb 2023 18:18:15 +0100 Subject: [PATCH] add flag for skipping files inside vendor directory Signed-off-by: Artur Rychlewicz <8393226+artuross@users.noreply.github.com> --- README.md | 94 ++++++++++++++++++++++++++----------------- cmd/gci/gcicommand.go | 4 +- cmd/gci/root.go | 1 + pkg/config/config.go | 1 + pkg/gci/gci.go | 4 +- pkg/gci/gci_test.go | 2 +- pkg/io/file.go | 9 ++++- pkg/io/search.go | 38 +++++++++++++++-- 8 files changed, 105 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 8181194..944ae78 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The isolated comment blocks like below: ``` import ( - "fmt" + "fmt" // this line is isolated comment // those lines belong to one @@ -28,6 +28,7 @@ import ( ``` GCI splits all import blocks into different sections, now support five section type: + - standard: Go official imports, like "fmt" - custom: Custom section, use full and the longest match (match full string first, if multiple matches, use the longest one) - default: All rest import blocks @@ -64,14 +65,14 @@ go install github.com/daixiang0/gci@v0.6.0 Now GCI provides two command line methods, mainly for backward compatibility. ### New style + GCI supports three modes of operation > **Note** -> -> Since v0.10.0, the `-s` and `--section` flag can only be used multiple times to specify multiple sections. -> For example, you could use `-s standard,default` before, but now you must use `-s standard -s default`. -> This breaking change makes it possible for the project to support specifying multiple custom prefixes. (Please see below.) - +> +> Since v0.10.0, the `-s` and `--section` flag can only be used multiple times to specify multiple sections. +> For example, you could use `-s standard,default` before, but now you must use `-s standard -s default`. +> This breaking change makes it possible for the project to support specifying multiple custom prefixes. (Please see below.) ```shell $ gci print -h @@ -84,15 +85,17 @@ Aliases: print, output Flags: - -d, --debug Enables debug output from the formatter - -h, --help help for write - -s, --section strings Sections define how inputs will be processed. Section names are case-insensitive and may contain parameters in (). The section order is standard > default > custom > blank > dot. The default value is [standard,default]. - standard - standard section that Go provides officially, like "fmt" - Prefix(github.com/daixiang0) - custom section, groups all imports with the specified Prefix. Imports will be matched to the longest Prefix. Multiple custom prefixes may be provided, they will be rendered as distinct sections separated by newline. You can regroup multiple prefixes by separating them with comma: Prefix(github.com/daixiang0,gitlab.com/daixiang0,daixiang0) - default - default section, contains all rest imports - blank - blank section, contains all blank imports. - --skip-generated Skip generated files - --custom-order Enable custom order of sections. If specified, make the section order the same as your configuration order. The default order is standard > default > custom > blank > dot. + --custom-order Enable custom order of sections + -d, --debug Enables debug output from the formatter + -h, --help help for print + -s, --section stringArray Sections define how inputs will be processed. Section names are case-insensitive and may contain parameters in (). The section order is standard > default > custom > blank > dot. The default value is [standard,default]. + standard - standard section that Go provides officially, like "fmt" + Prefix(github.com/daixiang0) - custom section, groups all imports with the specified Prefix. Imports will be matched to the longest Prefix. Multiple custom prefixes may be provided, they will be rendered as distinct sections separated by newline. You can regroup multiple prefixes by separating them with comma: Prefix(github.com/daixiang0,gitlab.com/daixiang0,daixiang0) + default - default section, contains all rest imports + blank - blank section, contains all blank imports. + dot - dot section, contains all dot imports. (default [standard,default]) + --skip-generated Skip generated files + --skip-vendor Skip files inside vendor directory ``` ```shell @@ -106,19 +109,19 @@ Aliases: write, overwrite Flags: - -d, --debug Enables debug output from the formatter - -h, --help help for write - -s, --section strings Sections define how inputs will be processed. Section names are case-insensitive and may contain parameters in (). The section order is standard > default > custom > blank > dot. The default value is [standard,default]. - standard - standard section that Go provides officially, like "fmt" - Prefix(github.com/daixiang0) - custom section, groups all imports with the specified Prefix. Imports will be matched to the longest Prefix. Multiple custom prefixes may be provided, they will be rendered as distinct sections separated by newline. You can regroup multiple prefixes by separating them with comma: Prefix(github.com/daixiang0,gitlab.com/daixiang0,daixiang0) - default - default section, contains all rest imports - blank - blank section, contains all blank imports. - dot - dot section, contains all dot imports. - --skip-generated Skip generated files - --custom-order Enable custom order of sections. If specified, make the section order the same as your configuration order. The default order is standard > default > custom > blank > dot. + --custom-order Enable custom order of sections + -d, --debug Enables debug output from the formatter + -h, --help help for write + -s, --section stringArray Sections define how inputs will be processed. Section names are case-insensitive and may contain parameters in (). The section order is standard > default > custom > blank > dot. The default value is [standard,default]. + standard - standard section that Go provides officially, like "fmt" + Prefix(github.com/daixiang0) - custom section, groups all imports with the specified Prefix. Imports will be matched to the longest Prefix. Multiple custom prefixes may be provided, they will be rendered as distinct sections separated by newline. You can regroup multiple prefixes by separating them with comma: Prefix(github.com/daixiang0,gitlab.com/daixiang0,daixiang0) + default - default section, contains all rest imports + blank - blank section, contains all blank imports. + dot - dot section, contains all dot imports. (default [standard,default]) + --skip-generated Skip generated files + --skip-vendor Skip files inside vendor directory ``` - ```shell $ gci list -h Prints the filenames that need to be formatted. If you want to show the diff use diff instead, and if you want to apply the changes use write instead @@ -137,6 +140,7 @@ Flags: blank - blank section, contains all blank imports. dot - dot section, contains all dot imports. (default [standard,default]) --skip-generated Skip generated files + --skip-vendor Skip files inside vendor directory ``` ```shell @@ -147,23 +151,36 @@ Usage: gci diff path... [flags] Flags: - -d, --debug Enables debug output from the formatter - -h, --help help for write - -s, --section strings Sections define how inputs will be processed. Section names are case-insensitive and may contain parameters in (). The section order is standard > default > custom > blank > dot. The default value is [standard,default]. - standard - standard section that Go provides officially, like "fmt" - Prefix(github.com/daixiang0) - custom section, groups all imports with the specified Prefix. Imports will be matched to the longest Prefix. Multiple custom prefixes may be provided, they will be rendered as distinct sections separated by newline. You can regroup multiple prefixes by separating them with comma: Prefix(github.com/daixiang0,gitlab.com/daixiang0,daixiang0) - default - default section, contains all rest imports - blank - blank section, contains all blank imports. - dot - dot section, contains all dot imports. - --skip-generated Skip generated files - --custom-order Enable custom order of sections. If specified, make the section order the same as your configuration order. The default order is standard > default > custom > blank > dot. + --custom-order Enable custom order of sections + -d, --debug Enables debug output from the formatter + -h, --help help for diff + -s, --section stringArray Sections define how inputs will be processed. Section names are case-insensitive and may contain parameters in (). The section order is standard > default > custom > blank > dot. The default value is [standard,default]. + standard - standard section that Go provides officially, like "fmt" + Prefix(github.com/daixiang0) - custom section, groups all imports with the specified Prefix. Imports will be matched to the longest Prefix. Multiple custom prefixes may be provided, they will be rendered as distinct sections separated by newline. You can regroup multiple prefixes by separating them with comma: Prefix(github.com/daixiang0,gitlab.com/daixiang0,daixiang0) + default - default section, contains all rest imports + blank - blank section, contains all blank imports. + dot - dot section, contains all dot imports. (default [standard,default]) + --skip-generated Skip generated files + --skip-vendor Skip files inside vendor directory ``` ### Old style ```shell +Gci enables automatic formatting of imports in a deterministic manner +If you want to integrate this as part of your CI take a look at golangci-lint. + Usage: gci [-diff | -write] [--local localPackageURLs] path... [flags] + gci [command] + +Available Commands: + completion Generate the autocompletion script for the specified shell + diff Prints a git style diff to STDOUT + help Help about any command + list Prints filenames that need to be formatted to STDOUT + print Outputs the formatted file to STDOUT + write Formats the specified files in-place Flags: -d, --diff display diffs instead of rewriting files @@ -172,6 +189,7 @@ Flags: -v, --version version for gci -w, --write write result to (source) file instead of stdout +Use "gci [command] --help" for more information about a command. ``` **Note**:: @@ -188,9 +206,9 @@ Run `gci write -s standard -s default -s "prefix(github.com/daixiang0/gci)" main package main import ( "golang.org/x/tools" - + "fmt" - + "github.com/daixiang0/gci" ) ``` diff --git a/cmd/gci/gcicommand.go b/cmd/gci/gcicommand.go index 4cae03d..5a7b679 100644 --- a/cmd/gci/gcicommand.go +++ b/cmd/gci/gcicommand.go @@ -12,7 +12,7 @@ import ( type processingFunc = func(args []string, gciCfg config.Config) error func (e *Executor) newGciCommand(use, short, long string, aliases []string, stdInSupport bool, processingFunc processingFunc) *cobra.Command { - var noInlineComments, noPrefixComments, skipGenerated, customOrder, debug *bool + var noInlineComments, noPrefixComments, skipGenerated, skipVendor, customOrder, debug *bool var sectionStrings, sectionSeparatorStrings *[]string cmd := cobra.Command{ Use: use, @@ -26,6 +26,7 @@ func (e *Executor) newGciCommand(use, short, long string, aliases []string, stdI NoPrefixComments: *noPrefixComments, Debug: *debug, SkipGenerated: *skipGenerated, + SkipVendor: *skipVendor, CustomOrder: *customOrder, } gciCfg, err := config.YamlConfig{Cfg: fmtCfg, SectionStrings: *sectionStrings, SectionSeparatorStrings: *sectionSeparatorStrings}.Parse() @@ -55,6 +56,7 @@ blank - blank section, contains all blank imports. dot - dot section, contains all dot imports.` skipGenerated = cmd.Flags().Bool("skip-generated", false, "Skip generated files") + skipVendor = cmd.Flags().Bool("skip-vendor", false, "Skip files inside vendor directory") customOrder = cmd.Flags().Bool("custom-order", false, "Enable custom order of sections") sectionStrings = cmd.Flags().StringArrayP("section", "s", section.DefaultSections().String(), sectionHelp) diff --git a/cmd/gci/root.go b/cmd/gci/root.go index e231e4b..41fa27c 100644 --- a/cmd/gci/root.go +++ b/cmd/gci/root.go @@ -68,6 +68,7 @@ func (e *Executor) runInCompatibilityMode(cmd *cobra.Command, args []string) err NoPrefixComments: false, Debug: false, SkipGenerated: false, + SkipVendor: false, }, Sections: sections, SectionSeparators: sectionSeparators, diff --git a/pkg/config/config.go b/pkg/config/config.go index b32148b..120e787 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -23,6 +23,7 @@ type BoolConfig struct { NoPrefixComments bool `yaml:"no-prefixComments"` Debug bool `yaml:"-"` SkipGenerated bool `yaml:"skipGenerated"` + SkipVendor bool `yaml:"skipVendor"` CustomOrder bool `yaml:"customOrder"` } diff --git a/pkg/gci/gci.go b/pkg/gci/gci.go index 81aa977..e84a166 100644 --- a/pkg/gci/gci.go +++ b/pkg/gci/gci.go @@ -86,11 +86,11 @@ func DiffFormattedFilesToArray(paths []string, cfg config.Config, diffs *[]strin type fileFormattingFunc func(filePath string, unmodifiedFile, formattedFile []byte) error func processStdInAndGoFilesInPaths(paths []string, cfg config.Config, fileFunc fileFormattingFunc) error { - return ProcessFiles(io.StdInGenerator.Combine(io.GoFilesInPathsGenerator(paths)), cfg, fileFunc) + return ProcessFiles(io.StdInGenerator.Combine(io.GoFilesInPathsGenerator(paths, cfg.SkipVendor)), cfg, fileFunc) } func processGoFilesInPaths(paths []string, cfg config.Config, fileFunc fileFormattingFunc) error { - return ProcessFiles(io.GoFilesInPathsGenerator(paths), cfg, fileFunc) + return ProcessFiles(io.GoFilesInPathsGenerator(paths, cfg.SkipVendor), cfg, fileFunc) } func ProcessFiles(fileGenerator io.FileGeneratorFunc, cfg config.Config, fileFunc fileFormattingFunc) error { diff --git a/pkg/gci/gci_test.go b/pkg/gci/gci_test.go index 5b4a944..608cdb0 100644 --- a/pkg/gci/gci_test.go +++ b/pkg/gci/gci_test.go @@ -21,7 +21,7 @@ func init() { var testFilesPath = "internal/testdata" -func isTestInputFile(file os.FileInfo) bool { +func isTestInputFile(_ string, file os.FileInfo) bool { return !file.IsDir() && strings.HasSuffix(file.Name(), ".in.go") } diff --git a/pkg/io/file.go b/pkg/io/file.go index f92d16e..7995079 100644 --- a/pkg/io/file.go +++ b/pkg/io/file.go @@ -39,8 +39,13 @@ func (a FileGeneratorFunc) Combine(b FileGeneratorFunc) FileGeneratorFunc { } } -func GoFilesInPathsGenerator(paths []string) FileGeneratorFunc { - return FilesInPathsGenerator(paths, isGoFile) +func GoFilesInPathsGenerator(paths []string, skipVendor bool) FileGeneratorFunc { + checkFunc := isGoFile + if skipVendor { + checkFunc = checkChains(isGoFile, isOutsideVendorDir) + } + + return FilesInPathsGenerator(paths, checkFunc) } func FilesInPathsGenerator(paths []string, fileCheckFun fileCheckFunction) FileGeneratorFunc { diff --git a/pkg/io/search.go b/pkg/io/search.go index 04f0058..cd82158 100644 --- a/pkg/io/search.go +++ b/pkg/io/search.go @@ -6,7 +6,7 @@ import ( "path/filepath" ) -type fileCheckFunction func(file os.FileInfo) bool +type fileCheckFunction func(path string, file os.FileInfo) bool func FindFilesForPath(path string, fileCheckFun fileCheckFunction) ([]string, error) { switch entry, err := os.Stat(path); { @@ -14,7 +14,7 @@ func FindFilesForPath(path string, fileCheckFun fileCheckFunction) ([]string, er return nil, err case entry.IsDir(): return findFilesForDirectory(path, fileCheckFun) - case fileCheckFun(entry): + case fileCheckFun(path, entry): return []string{filepath.Clean(path)}, nil default: return []string{}, nil @@ -31,7 +31,7 @@ func findFilesForDirectory(dirPath string, fileCheckFun fileCheckFunction) ([]st if err != nil { return err } - if !entry.IsDir() && fileCheckFun(file) { + if !entry.IsDir() && fileCheckFun(path, file) { filePaths = append(filePaths, filepath.Clean(path)) } return nil @@ -42,6 +42,36 @@ func findFilesForDirectory(dirPath string, fileCheckFun fileCheckFunction) ([]st return filePaths, nil } -func isGoFile(file os.FileInfo) bool { +func isGoFile(_ string, file os.FileInfo) bool { return !file.IsDir() && filepath.Ext(file.Name()) == ".go" } + +func isOutsideVendorDir(path string, _ os.FileInfo) bool { + for { + base := filepath.Base(path) + if base == "vendor" { + return false + } + + prevPath := path + path = filepath.Dir(path) + + if prevPath == path { + break + } + } + + return true +} + +func checkChains(funcs ...fileCheckFunction) fileCheckFunction { + return func(path string, file os.FileInfo) bool { + for _, checkFunc := range funcs { + if !checkFunc(path, file) { + return false + } + } + + return true + } +}