diff --git a/Gopkg.lock b/Gopkg.lock index dbb0427c..2dfbec21 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -25,6 +25,18 @@ packages = ["."] revision = "88b7bfd34643dce0c28a6b797652d6b5026091af" +[[projects]] + name = "github.com/fatih/color" + packages = ["."] + revision = "507f6050b8568533fb3f5504de8e5205fa62a114" + version = "v1.6.0" + +[[projects]] + name = "github.com/fsnotify/fsnotify" + packages = ["."] + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + [[projects]] name = "github.com/go-ole/go-ole" packages = [ @@ -57,6 +69,65 @@ ] revision = "044f3332f2e8c38cfbb56bab29f65b4245bbe76b" +[[projects]] + branch = "master" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/printer", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token" + ] + revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168" + +[[projects]] + name = "github.com/inconshreveable/mousetrap" + packages = ["."] + revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + version = "v1.0" + +[[projects]] + name = "github.com/magiconair/properties" + packages = ["."] + revision = "c3beff4c2358b44d0493c7dda585e7db7ff28ae6" + version = "v1.7.6" + +[[projects]] + name = "github.com/mattn/go-colorable" + packages = ["."] + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + +[[projects]] + name = "github.com/mattn/go-isatty" + packages = ["."] + revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" + version = "v0.0.3" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/go-homedir" + packages = ["."] + revision = "b8bc1bf767474819792c23f32d8286a45736f1c6" + +[[projects]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + revision = "00c29f56e2386353d58c599509e8dc3801b0d716" + +[[projects]] + name = "github.com/pelletier/go-toml" + packages = ["."] + revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8" + version = "v1.1.0" + [[projects]] name = "github.com/pmezard/go-difflib" packages = ["difflib"] @@ -94,6 +165,49 @@ revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" version = "v1.0.5" +[[projects]] + name = "github.com/spf13/afero" + packages = [ + ".", + "mem" + ] + revision = "63644898a8da0bc22138abf860edaf5277b6102e" + version = "v1.1.0" + +[[projects]] + name = "github.com/spf13/cast" + packages = ["."] + revision = "8965335b8c7107321228e3e3702cab9832751bac" + version = "v1.2.0" + +[[projects]] + name = "github.com/spf13/cobra" + packages = [ + ".", + "cobra", + "cobra/cmd" + ] + revision = "a1f051bc3eba734da4772d60e2d677f47cf93ef4" + version = "v0.0.2" + +[[projects]] + branch = "master" + name = "github.com/spf13/jwalterweatherman" + packages = ["."] + revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394" + +[[projects]] + name = "github.com/spf13/pflag" + packages = ["."] + revision = "583c0c0531f06d5278b7d917446061adc344b5cd" + version = "v1.0.1" + +[[projects]] + name = "github.com/spf13/viper" + packages = ["."] + revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736" + version = "v1.0.2" + [[projects]] name = "github.com/stretchr/testify" packages = ["assert"] @@ -130,6 +244,25 @@ ] revision = "6f686a352de66814cdd080d970febae7767857a3" +[[projects]] + name = "golang.org/x/text" + packages = [ + "internal/gen", + "internal/triegen", + "internal/ucd", + "transform", + "unicode/cldr", + "unicode/norm" + ] + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + name = "gopkg.in/yaml.v2" + packages = ["."] + revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" + version = "v2.2.1" + [[projects]] branch = "master" name = "sourcegraph.com/sourcegraph/go-diff" @@ -145,6 +278,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "fc3abded9121a32e3fc9de887b9f1dd7a4d64ee58e169053e9120881d6c54658" + inputs-digest = "e734f3b5571fe0e9119d20d9e9a7f8ee2b2f316686cf194307a3e5fb3327c85b" solver-name = "gps-cdcl" solver-version = 1 diff --git a/cmd/golangci-lint/main.go b/cmd/golangci-lint/main.go index d04721e7..2dac78a9 100644 --- a/cmd/golangci-lint/main.go +++ b/cmd/golangci-lint/main.go @@ -1,43 +1,16 @@ package main import ( - "context" "log" - "os" - "path/filepath" - "github.com/golangci/golangci-lint/pkg/config" - "github.com/golangci/golangci-lint/pkg/golinters" - "github.com/golangci/golangci-shared/pkg/executors" + "github.com/golangci/golangci-lint/internal/commands" ) func main() { - if err := run(); err != nil { + log.SetFlags(0) // don't print time + + e := commands.NewExecutor() + if err := e.Execute(); err != nil { panic(err) } } - -func run() error { - var cfg config.Config - config.ReadFromCommandLine(&cfg) - - linters := golinters.GetSupportedLinters() - ctx := context.Background() - - ex, err := os.Executable() - if err != nil { - return err - } - exPath := filepath.Dir(ex) - exec := executors.NewShell(exPath) - - for _, linter := range linters { - res, err := linter.Run(ctx, exec) - if err != nil { - return err - } - log.Print(res) - } - - return nil -} diff --git a/internal/commands/executor.go b/internal/commands/executor.go new file mode 100644 index 00000000..c20694b9 --- /dev/null +++ b/internal/commands/executor.go @@ -0,0 +1,27 @@ +package commands + +import ( + "github.com/golangci/golangci-lint/pkg/config" + "github.com/spf13/cobra" +) + +type Executor struct { + rootCmd *cobra.Command + + cfg *config.Config +} + +func NewExecutor() *Executor { + e := &Executor{ + cfg: config.NewDefault(), + } + + e.initRoot() + e.initRun() + + return e +} + +func (e Executor) Execute() error { + return e.rootCmd.Execute() +} diff --git a/internal/commands/root.go b/internal/commands/root.go new file mode 100644 index 00000000..3cae660b --- /dev/null +++ b/internal/commands/root.go @@ -0,0 +1,18 @@ +package commands + +import ( + "github.com/spf13/cobra" +) + +func (e *Executor) initRoot() { + rootCmd := &cobra.Command{ + Use: "golangci-lint", + Short: "golangci-lint is a smart linters runner.", + Long: `Smart, fast linters runner. Run it in cloud for every GitHub pull request on https://golangci.com`, + Run: func(cmd *cobra.Command, args []string) { + _ = cmd.Help() + }, + } + rootCmd.PersistentFlags().BoolVarP(&e.cfg.Common.IsVerbose, "verbose", "v", false, "verbose output") + e.rootCmd = rootCmd +} diff --git a/internal/commands/run.go b/internal/commands/run.go new file mode 100644 index 00000000..532359ea --- /dev/null +++ b/internal/commands/run.go @@ -0,0 +1,92 @@ +package commands + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "path/filepath" + "strings" + + "github.com/fatih/color" + "github.com/golangci/golangci-lint/pkg/config" + "github.com/golangci/golangci-lint/pkg/golinters" + "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/golangci-shared/pkg/executors" + "github.com/spf13/cobra" +) + +func (e *Executor) initRun() { + var runCmd = &cobra.Command{ + Use: "run", + Short: "Run linters", + Run: e.executeRun, + } + e.rootCmd.AddCommand(runCmd) + + runCmd.Flags().StringVarP(&e.cfg.Run.OutFormat, "out-format", "", + config.OutFormatColoredLineNumber, + fmt.Sprintf("Format of output: %s", strings.Join(config.OutFormats, "|"))) +} + +func (e Executor) executeRun(cmd *cobra.Command, args []string) { + f := func() error { + linters := golinters.GetSupportedLinters() + ctx := context.Background() + + ex, err := os.Executable() + if err != nil { + return err + } + exPath := filepath.Dir(ex) + exec := executors.NewShell(exPath) + + issues := []result.Issue{} + for _, linter := range linters { + res, err := linter.Run(ctx, exec) + if err != nil { + return err + } + issues = append(issues, res.Issues...) + } + + if err = outputIssues(e.cfg.Run.OutFormat, issues); err != nil { + return fmt.Errorf("can't output %d issues: %s", len(issues), err) + } + + return nil + } + + if err := f(); err != nil { + panic(err) + } +} + +func outputIssues(format string, issues []result.Issue) error { + if format == config.OutFormatLineNumber || format == config.OutFormatColoredLineNumber { + if len(issues) == 0 { + outStr := "Congrats! No issues were found." + if format == config.OutFormatColoredLineNumber { + outStr = color.GreenString(outStr) + } + log.Print(outStr) + } + + for _, i := range issues { + log.Printf("%s:%d: %s", i.File, i.LineNumber, i.Text) + } + return nil + } + + if format == config.OutFormatJSON { + outputJSON, err := json.Marshal(issues) + if err != nil { + return err + } + log.Print(string(outputJSON)) + return nil + } + + return fmt.Errorf("unknown output format %q", format) +} diff --git a/pkg/config/command_line.go b/pkg/config/command_line.go deleted file mode 100644 index a99e47b5..00000000 --- a/pkg/config/command_line.go +++ /dev/null @@ -1,11 +0,0 @@ -package config - -import "flag" - -func ReadFromCommandLine(cfg *Config) { - flag.Parse() - paths := flag.Args() - if len(paths) != 0 { - cfg.Paths = paths - } -} diff --git a/pkg/config/config.go b/pkg/config/config.go index 90579090..99a18262 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1,5 +1,34 @@ package config -type Config struct { - Paths []string +type OutFormat string + +const ( + OutFormatJSON = "json" + OutFormatLineNumber = "line-number" + OutFormatColoredLineNumber = "colored-line-number" +) + +var OutFormats = []string{OutFormatColoredLineNumber, OutFormatLineNumber, OutFormatJSON} + +type Common struct { + IsVerbose bool +} + +type Run struct { + Paths []string + OutFormat string +} + +type Config struct { + Common Common + Run Run +} + +func NewDefault() *Config { + return &Config{ + Run: Run{ + Paths: []string{"./..."}, + OutFormat: OutFormatColoredLineNumber, + }, + } } diff --git a/pkg/golinters/utils.go b/pkg/golinters/utils.go index c44947d5..38f27d74 100644 --- a/pkg/golinters/utils.go +++ b/pkg/golinters/utils.go @@ -3,7 +3,6 @@ package golinters import ( "context" "fmt" - "log" "path" "path/filepath" @@ -38,7 +37,6 @@ func processPaths(root string, paths []string, maxPaths int) ([]string, error) { func getPathsForGoProject(root string) (*ProjectPaths, error) { excludeDirs := []string{"vendor", "testdata", "examples", "Godeps"} pr := fsutils.NewPathResolver(excludeDirs, []string{".go"}) - log.Printf("root is %q, paths are %q", root, path.Join(root, "...")) paths, err := pr.Resolve(path.Join(root, "...")) if err != nil { return nil, fmt.Errorf("can't resolve paths: %s", err)