Skip to content

Commit

Permalink
apply rules to directories
Browse files Browse the repository at this point in the history
  • Loading branch information
incu6us committed Aug 3, 2022
1 parent 03343c5 commit 10c64a0
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 17 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ Use additional options `-rm-unused` to remove unused imports and `-set-alias` to
goimports-reviser -rm-unused -set-alias -format ./reviser/reviser.go
```

You can also apply rules to a dir or recursively apply using ./... as a target:
```bash
goimports-reviser -rm-unused -set-alias -format -recursive reviser
```

```bash
goimports-reviser -rm-unused -set-alias -format ./...
```

### Example, to configure it with JetBrains IDEs (via file watcher plugin):
![example](./images/image.png)

Expand All @@ -60,6 +69,8 @@ Usage of goimports-reviser:
Can be "file", "write" or "stdout". Whether to write the formatted content back to the file or to stdout. When "write" together with "-list-diff" will list the file name and write back to the file. Optional parameter. (default "file")
-project-name string
Your project name(ex.: github.com/incu6us/goimports-reviser). Optional parameter.
-recursive
Apply rules recursively if target is a directory. In case of ./... execution will be recursively applied by default. Optional parameter.
-rm-unused
Remove unused imports. Optional parameter.
-set-alias
Expand Down
40 changes: 30 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
formatArg = "format"
listDiffFileNameArg = "list-diff"
setExitStatusArg = "set-exit-status"
recursiveArg = "recursive"

// Deprecated options
localArg = "local"
Expand All @@ -44,13 +45,14 @@ var (
shouldFormat *bool
listFileName *bool
setExitStatus *bool
isRecursive *bool
)

var (
projectName, filePath, companyPkgPrefixes, output, importsOrder string
projectName, companyPkgPrefixes, output, importsOrder string

// Deprecated
localPkgPrefixes string
localPkgPrefixes, filePath string
)

func init() {
Expand Down Expand Up @@ -132,6 +134,12 @@ Optional parameter.`,
"Option will perform additional formatting. Optional parameter.",
)

isRecursive = flag.Bool(
recursiveArg,
false,
"Apply rules recursively if target is a directory. In case of ./... execution will be recursively applied by default. Optional parameter.",
)

if Tag != "" {
shouldShowVersion = flag.Bool(
versionArg,
Expand Down Expand Up @@ -169,23 +177,23 @@ func main() {
return
}

originFilePath := flag.Arg(0)
originPath := flag.Arg(0)
if filePath != "" {
deprecatedMessagesCh <- fmt.Sprintf("-%s is deprecated. Put file name as last argument to the command(Example: goimports-reviser -rm-unused -set-alias -format goimports-reviser/main.go)", filePathArg)
originFilePath = filePath
originPath = filePath
}

if originFilePath == "" {
originFilePath = reviser.StandardInput
if originPath == "" {
originPath = reviser.StandardInput
}

if err := validateRequiredParam(originFilePath); err != nil {
if err := validateRequiredParam(originPath); err != nil {
fmt.Printf("%s\n\n", err)
printUsage()
os.Exit(1)
}

var options reviser.Options
var options reviser.SourceFileOptions
if shouldRemoveUnusedImports != nil && *shouldRemoveUnusedImports {
options = append(options, reviser.WithRemovingUnusedImports)
}
Expand Down Expand Up @@ -219,7 +227,7 @@ func main() {
options = append(options, reviser.WithImportsOrder(order))
}

originProjectName, err := helper.DetermineProjectName(projectName, originFilePath)
originProjectName, err := helper.DetermineProjectName(projectName, originPath)
if err != nil {
fmt.Printf("%s\n\n", err)
printUsage()
Expand All @@ -228,11 +236,23 @@ func main() {

close(deprecatedMessagesCh)

formattedOutput, hasChange, err := reviser.NewSourceFile(originProjectName, originFilePath).Fix(options...)
if _, ok := reviser.IsDir(originPath); ok {
err := reviser.NewSourceDir(originProjectName, originPath, *isRecursive).Fix(options...)
if err != nil {
log.Fatalf("%+v", errors.WithStack(err))
}
return
}

formattedOutput, hasChange, err := reviser.NewSourceFile(originProjectName, originPath).Fix(options...)
if err != nil {
log.Fatalf("%+v", errors.WithStack(err))
}

resultPostProcess(hasChange, deprecatedMessagesCh, originPath, formattedOutput)
}

func resultPostProcess(hasChange bool, deprecatedMessagesCh chan string, originFilePath string, formattedOutput []byte) {
if !hasChange && *listFileName {
printDeprecations(deprecatedMessagesCh)
return
Expand Down
88 changes: 88 additions & 0 deletions reviser/dir.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package reviser

import (
"io/fs"
"os"
"path/filepath"

"github.com/pkg/errors"
)

const (
goExtension = ".go"
recursivePath = "./..."
)

var (
ErrPathIsNotDir = errors.New("path is not a directory")
)

// SourceDir to validate and fix import
type SourceDir struct {
projectName string
dir string
isRecursive bool
}

func NewSourceDir(projectName string, path string, isRecursive bool) *SourceDir {
if path == recursivePath {
isRecursive = true
}
return &SourceDir{projectName: projectName, dir: path, isRecursive: isRecursive}
}

func (d *SourceDir) Fix(options ...SourceFileOption) error {
var ok bool
d.dir, ok = IsDir(d.dir)
if !ok {
return ErrPathIsNotDir
}

err := filepath.WalkDir(d.dir, d.walk(options...))
if err != nil {
return errors.WithStack(err)
}

return nil
}

func (d *SourceDir) walk(options ...SourceFileOption) fs.WalkDirFunc {
return func(path string, dirEntry fs.DirEntry, err error) error {
if !d.isRecursive && dirEntry.IsDir() && filepath.Base(d.dir) != dirEntry.Name() {
return filepath.SkipDir
}
if isGoFile(path) && !dirEntry.IsDir() {
_, _, err := NewSourceFile(d.projectName, path).Fix(options...)
if err != nil {
return errors.WithStack(err)
}
}
return nil
}
}

func IsDir(path string) (string, bool) {
if path == recursivePath {
var err error
path, err = os.Getwd()
if err != nil {
return path, false
}
}

dir, err := os.Open(path)
if err != nil {
return path, false
}

dirStat, err := dir.Stat()
if err != nil {
return path, false
}

return path, dirStat.IsDir()
}

func isGoFile(path string) bool {
return filepath.Ext(path) == goExtension
}
2 changes: 1 addition & 1 deletion reviser/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func NewSourceFile(projectName, filePath string) *SourceFile {
}

// Fix is for revise imports and format the code
func (f *SourceFile) Fix(options ...Option) ([]byte, bool, error) {
func (f *SourceFile) Fix(options ...SourceFileOption) ([]byte, bool, error) {
for _, option := range options {
err := option(f)
if err != nil {
Expand Down
12 changes: 6 additions & 6 deletions reviser/option.go → reviser/file_option.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package reviser

import "strings"

// Option is an int alias for options
type Option func(f *SourceFile) error
// SourceFileOption is an int alias for options
type SourceFileOption func(f *SourceFile) error

// Options is a slice of executing options
type Options []Option
// SourceFileOptions is a slice of executing options
type SourceFileOptions []SourceFileOption

// WithRemovingUnusedImports is an option to remove unused imports
func WithRemovingUnusedImports(f *SourceFile) error {
Expand All @@ -27,7 +27,7 @@ func WithCodeFormatting(f *SourceFile) error {
}

// WithCompanyPackagePrefixes option for 3d group(by default), like inter-org or company package prefixes
func WithCompanyPackagePrefixes(s string) Option {
func WithCompanyPackagePrefixes(s string) SourceFileOption {
return func(f *SourceFile) error {
prefixes := strings.Split(s, stringValueSeparator)
for _, prefix := range prefixes {
Expand All @@ -38,7 +38,7 @@ func WithCompanyPackagePrefixes(s string) Option {
}

// WithImportsOrder will sort by needed order. Default order is "std,general,company,project"
func WithImportsOrder(orders []ImportsOrder) Option {
func WithImportsOrder(orders []ImportsOrder) SourceFileOption {
return func(f *SourceFile) error {
f.importsOrders = orders
return nil
Expand Down

0 comments on commit 10c64a0

Please sign in to comment.