From 80c6be4f7d28557d0f00f30a3b5c42a32f5f0987 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 8 Sep 2023 11:50:05 +0700 Subject: [PATCH] feat: add a path option --- cmd/licensei/root.go | 51 +++++++++++++-------------- internal/cmd/licensei/cache.go | 13 ++++--- internal/cmd/licensei/check.go | 11 +++--- internal/cmd/licensei/cmd.go | 12 +++---- internal/cmd/licensei/header.go | 18 ++++++---- internal/cmd/licensei/list.go | 11 +++--- internal/cmd/licensei/options.go | 7 ++++ internal/cmd/licensei/stat.go | 11 +++--- internal/licensei/cache.go | 6 ++-- internal/licensei/list_test.go | 6 ++-- internal/licensei/source_aggregate.go | 11 +++--- internal/licensei/source_dep.go | 11 ++++-- internal/licensei/source_gomod.go | 10 +++--- 13 files changed, 105 insertions(+), 73 deletions(-) create mode 100644 internal/cmd/licensei/options.go diff --git a/cmd/licensei/root.go b/cmd/licensei/root.go index d3a57d5..880cf4d 100644 --- a/cmd/licensei/root.go +++ b/cmd/licensei/root.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "log" "os" "github.com/spf13/cobra" @@ -11,61 +12,59 @@ import ( "github.com/goph/licensei/internal/cmd/licensei" ) -// nolint: gochecknoglobals -var config string - -// nolint: gochecknoglobals -var debug bool - -// nolint: gochecknoinits -func init() { - cobra.OnInitialize(initConfig) +func newRootCommand(options *licensei.GlobalOptions) *cobra.Command { + cmd := &cobra.Command{ + Use: "licensei", + Short: "License master", + PersistentPreRunE: func(_ *cobra.Command, _ []string) error { + return initConfig(options) + }, + } - rootCmd.PersistentFlags().StringVar(&config, "config", "", "config file (default is $PWD/.licensei.yaml)") - rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "enable debug logging") + cmd.PersistentFlags().StringVar(&options.Config, "config", "", "config file (default is $PWD/.licensei.yaml)") + cmd.PersistentFlags().StringVar(&options.Path, "path", "", "path to project (the current directory is used by default)") + cmd.PersistentFlags().BoolVar(&options.Debug, "debug", false, "enable debug logging") - licensei.AddCommands(rootCmd) + return cmd } -func initConfig() { +func initConfig(options *licensei.GlobalOptions) error { viper.AutomaticEnv() - if config != "" { + if options.Config != "" { // Use config file from the flag. - viper.SetConfigFile(config) + viper.SetConfigFile(options.Config) } else { viper.AddConfigPath(".") viper.SetConfigName(".licensei") } if err := viper.ReadInConfig(); err != nil { - fmt.Println("can't read config:", err) - os.Exit(1) + return fmt.Errorf("can't read config: %w", err) } logHandler := slog.HandlerOptions{ - AddSource: debug, + AddSource: options.Debug, Level: slog.InfoLevel, } - if debug { + if options.Debug { logHandler.Level = slog.DebugLevel } logger := slog.New(logHandler.NewTextHandler(os.Stderr)) slog.SetDefault(logger) -} -// nolint: gochecknoglobals -var rootCmd = &cobra.Command{ - Use: "licensei", - Short: "License master", + return nil } func Execute() { + globalOptions := &licensei.GlobalOptions{} + rootCmd := newRootCommand(globalOptions) + licensei.AddCommands(rootCmd, globalOptions) + if err := rootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) + log.Fatalln(err) } } diff --git a/internal/cmd/licensei/cache.go b/internal/cmd/licensei/cache.go index 6c963b6..2e5850b 100644 --- a/internal/cmd/licensei/cache.go +++ b/internal/cmd/licensei/cache.go @@ -16,7 +16,7 @@ type cacheOptions struct { githubToken string } -func NewCacheCommand() *cobra.Command { +func NewCacheCommand(globalOptions *GlobalOptions) *cobra.Command { var options cacheOptions cmd := &cobra.Command{ @@ -25,7 +25,7 @@ func NewCacheCommand() *cobra.Command { RunE: func(_ *cobra.Command, _ []string) error { options.githubToken = viper.GetString("github_token") - return runCache(options) + return runCache(globalOptions, options) }, } @@ -36,7 +36,7 @@ func NewCacheCommand() *cobra.Command { return cmd } -func runCache(options cacheOptions) error { +func runCache(globalOptions *GlobalOptions, options cacheOptions) error { logger := slog.Default() logger.Debug("start cache") @@ -46,10 +46,13 @@ func runCache(options cacheOptions) error { // Invalidate cache data if options.update { - source := licensei.NewAggregatedDependencySource(logger) + source := licensei.NewAggregatedDependencySource(logger, globalOptions.Path) dependencies, err = source.Dependencies() } else { - source := licensei.NewCacheProjectSource(licensei.NewAggregatedDependencySource(logger), logger) + source := licensei.NewCacheProjectSource( + licensei.NewAggregatedDependencySource(logger, globalOptions.Path), + logger, + ) dependencies, err = source.Dependencies() } if err != nil { diff --git a/internal/cmd/licensei/check.go b/internal/cmd/licensei/check.go index 3a3d2c2..9569126 100644 --- a/internal/cmd/licensei/check.go +++ b/internal/cmd/licensei/check.go @@ -19,7 +19,7 @@ type checkOptions struct { githubToken string } -func NewCheckCommand() *cobra.Command { +func NewCheckCommand(globalOptions *GlobalOptions) *cobra.Command { var options checkOptions cmd := &cobra.Command{ @@ -31,13 +31,13 @@ func NewCheckCommand() *cobra.Command { options.githubToken = viper.GetString("github_token") - return runCheck(options) + return runCheck(globalOptions, options) }, } return cmd } -func runCheck(options checkOptions) error { +func runCheck(globalOptions *GlobalOptions, options checkOptions) error { logger := slog.Default() logger.Debug("start check") @@ -48,7 +48,10 @@ func runCheck(options checkOptions) error { return nil } - source := licensei.NewCacheProjectSource(licensei.NewAggregatedDependencySource(logger), logger) + source := licensei.NewCacheProjectSource( + licensei.NewAggregatedDependencySource(logger, globalOptions.Path), + logger, + ) dependencies, err := source.Dependencies() if err != nil { return err diff --git a/internal/cmd/licensei/cmd.go b/internal/cmd/licensei/cmd.go index 098c9d4..e04c5b2 100644 --- a/internal/cmd/licensei/cmd.go +++ b/internal/cmd/licensei/cmd.go @@ -5,12 +5,12 @@ import ( ) // AddCommands adds licensei commands to a Cobra command. -func AddCommands(cmd *cobra.Command) { +func AddCommands(cmd *cobra.Command, globalOptions *GlobalOptions) { cmd.AddCommand( - NewListCommand(), - NewCheckCommand(), - NewCacheCommand(), - NewHeaderCommand(), - NewStatCommand(), + NewListCommand(globalOptions), + NewCheckCommand(globalOptions), + NewCacheCommand(globalOptions), + NewHeaderCommand(globalOptions), + NewStatCommand(globalOptions), ) } diff --git a/internal/cmd/licensei/header.go b/internal/cmd/licensei/header.go index 027ff05..ac0102f 100644 --- a/internal/cmd/licensei/header.go +++ b/internal/cmd/licensei/header.go @@ -17,7 +17,7 @@ type headerOptions struct { authors []string } -func NewHeaderCommand() *cobra.Command { +func NewHeaderCommand(globalOptions *GlobalOptions) *cobra.Command { var options headerOptions cmd := &cobra.Command{ @@ -29,24 +29,28 @@ func NewHeaderCommand() *cobra.Command { options.ignoreFiles = viper.GetStringSlice("header.ignoreFiles") options.authors = viper.GetStringSlice("header.authors") - return runHeader(options) + return runHeader(globalOptions, options) }, } return cmd } -func runHeader(options headerOptions) error { - wd, err := os.Getwd() - if err != nil { - return err +func runHeader(globalOptions *GlobalOptions, options headerOptions) (err error) { + target := globalOptions.Path + + if target == "" { + target, err = os.Getwd() + if err != nil { + return err + } } violations, err := licensei.HeaderChecker{ IgnorePaths: options.ignorePaths, IgnoreFiles: options.ignoreFiles, Authors: options.authors, - }.Check(wd, options.template) + }.Check(target, options.template) if err != nil { return err } diff --git a/internal/cmd/licensei/list.go b/internal/cmd/licensei/list.go index 7956dec..223604d 100644 --- a/internal/cmd/licensei/list.go +++ b/internal/cmd/licensei/list.go @@ -21,7 +21,7 @@ type listView interface { Render(model licensei.ListViewModel) error } -func NewListCommand() *cobra.Command { +func NewListCommand(globalOptions *GlobalOptions) *cobra.Command { var options listOptions cmd := &cobra.Command{ @@ -30,7 +30,7 @@ func NewListCommand() *cobra.Command { RunE: func(_ *cobra.Command, _ []string) error { options.githubToken = viper.GetString("github_token") - return runList(options) + return runList(globalOptions, options) }, } @@ -41,7 +41,7 @@ func NewListCommand() *cobra.Command { return cmd } -func runList(options listOptions) error { +func runList(globalOptions *GlobalOptions, options listOptions) error { logger := slog.Default() logger.Debug("start list") @@ -57,7 +57,10 @@ func runList(options listOptions) error { return errors.New("unsupported format: " + options.format) } - source := licensei.NewCacheProjectSource(licensei.NewAggregatedDependencySource(logger), logger) + source := licensei.NewCacheProjectSource( + licensei.NewAggregatedDependencySource(logger, globalOptions.Path), + logger, + ) dependencies, err := source.Dependencies() if err != nil { return err diff --git a/internal/cmd/licensei/options.go b/internal/cmd/licensei/options.go new file mode 100644 index 0000000..78ca3dc --- /dev/null +++ b/internal/cmd/licensei/options.go @@ -0,0 +1,7 @@ +package licensei + +type GlobalOptions struct { + Config string + Debug bool + Path string +} diff --git a/internal/cmd/licensei/stat.go b/internal/cmd/licensei/stat.go index 7d75b36..2db0e12 100644 --- a/internal/cmd/licensei/stat.go +++ b/internal/cmd/licensei/stat.go @@ -17,7 +17,7 @@ type statOptions struct { githubToken string } -func NewStatCommand() *cobra.Command { +func NewStatCommand(globalOptions *GlobalOptions) *cobra.Command { var options statOptions cmd := &cobra.Command{ @@ -26,19 +26,22 @@ func NewStatCommand() *cobra.Command { RunE: func(cmd *cobra.Command, _ []string) error { options.githubToken = viper.GetString("github_token") - return runStat(options, cmd.OutOrStderr()) + return runStat(globalOptions, options, cmd.OutOrStderr()) }, } return cmd } -func runStat(options statOptions, stdout io.Writer) error { +func runStat(globalOptions *GlobalOptions, options statOptions, stdout io.Writer) error { logger := slog.Default() logger.Debug("start stat") - source := licensei.NewCacheProjectSource(licensei.NewAggregatedDependencySource(logger), logger) + source := licensei.NewCacheProjectSource( + licensei.NewAggregatedDependencySource(logger, globalOptions.Path), + logger, + ) dependencies, err := source.Dependencies() if err != nil { return err diff --git a/internal/licensei/cache.go b/internal/licensei/cache.go index 96af0e8..2774b5f 100644 --- a/internal/licensei/cache.go +++ b/internal/licensei/cache.go @@ -58,6 +58,10 @@ func (s *cacheDependencySource) Dependencies() ([]Dependency, error) { logger.Debug("load cache file") cacheFile, err := os.Open(".licensei.cache") + defer func() { + _ = cacheFile.Close() + }() + if err == nil { p, err := ReadCache(cacheFile) if err != nil { @@ -71,8 +75,6 @@ func (s *cacheDependencySource) Dependencies() ([]Dependency, error) { return nil, err } - _ = cacheFile.Close() - logger.Debug("load dependencies") sourceDependencies, err := s.delegatedDependencySource.Dependencies() diff --git a/internal/licensei/list_test.go b/internal/licensei/list_test.go index 264c379..235adfe 100644 --- a/internal/licensei/list_test.go +++ b/internal/licensei/list_test.go @@ -2,7 +2,7 @@ package licensei_test import ( "bytes" - "io/ioutil" + "os" "testing" . "github.com/goph/licensei/internal/licensei" @@ -23,7 +23,7 @@ func TestJsonListView_Render(t *testing.T) { }, } - result, err := ioutil.ReadFile("testdata/list/golden0.json") + result, err := os.ReadFile("testdata/list/golden0.json") if err != nil { t.Fatal(err) } @@ -53,7 +53,7 @@ func TestTableListView_Render(t *testing.T) { }, } - result, err := ioutil.ReadFile("testdata/list/golden0.table") + result, err := os.ReadFile("testdata/list/golden0.table") if err != nil { t.Fatal(err) } diff --git a/internal/licensei/source_aggregate.go b/internal/licensei/source_aggregate.go index f813b91..3189fb2 100644 --- a/internal/licensei/source_aggregate.go +++ b/internal/licensei/source_aggregate.go @@ -1,16 +1,17 @@ package licensei import ( - "github.com/goph/licensei/pkg/pkgmgr" "golang.org/x/exp/slog" + + "github.com/goph/licensei/pkg/pkgmgr" ) type aggregatedDependencySource struct { dependencySources []dependencySource } -func NewAggregatedDependencySource(logger *slog.Logger) *aggregatedDependencySource { - pkgmgrs, err := pkgmgr.DetectPackageManagers(".") +func NewAggregatedDependencySource(logger *slog.Logger, path string) *aggregatedDependencySource { + pkgmgrs, err := pkgmgr.DetectPackageManagers(path) if err != nil { panic(err) } @@ -20,11 +21,11 @@ func NewAggregatedDependencySource(logger *slog.Logger) *aggregatedDependencySou } if pkgmgrs.Dep { - source.dependencySources = append(source.dependencySources, NewDepDependencySource()) + source.dependencySources = append(source.dependencySources, NewDepDependencySource(path)) } if pkgmgrs.GoMod { - source.dependencySources = append(source.dependencySources, NewGoModDependencySource(logger)) + source.dependencySources = append(source.dependencySources, NewGoModDependencySource(logger, path)) } return source diff --git a/internal/licensei/source_dep.go b/internal/licensei/source_dep.go index 863c216..0dd076a 100644 --- a/internal/licensei/source_dep.go +++ b/internal/licensei/source_dep.go @@ -2,6 +2,7 @@ package licensei import ( "os" + "path/filepath" "github.com/pkg/errors" @@ -9,17 +10,21 @@ import ( ) type depDependencySource struct { + path string } -func NewDepDependencySource() *depDependencySource { - return new(depDependencySource) +func NewDepDependencySource(path string) *depDependencySource { + return &depDependencySource{ + path: path, + } } func (s *depDependencySource) Dependencies() ([]Dependency, error) { - lockFile, err := os.Open("Gopkg.lock") + lockFile, err := os.Open(filepath.Join(s.path, "Gopkg.lock")) if err != nil { return nil, errors.Wrap(err, "could not open dep lock file") } + defer lockFile.Close() lock, err := gopkg.ReadLock(lockFile) if err != nil { diff --git a/internal/licensei/source_gomod.go b/internal/licensei/source_gomod.go index 5a37b16..d1efde7 100644 --- a/internal/licensei/source_gomod.go +++ b/internal/licensei/source_gomod.go @@ -1,19 +1,21 @@ package licensei import ( - "github.com/goph/licensei/pkg/pkgmgr/gomod" + "github.com/pkg/errors" "golang.org/x/exp/slog" - "github.com/pkg/errors" + "github.com/goph/licensei/pkg/pkgmgr/gomod" ) type gomodDependencySource struct { logger *slog.Logger + path string } -func NewGoModDependencySource(logger *slog.Logger) *gomodDependencySource { +func NewGoModDependencySource(logger *slog.Logger, path string) *gomodDependencySource { return &gomodDependencySource{ logger: logger, + path: path, } } @@ -22,7 +24,7 @@ func (s *gomodDependencySource) Dependencies() ([]Dependency, error) { logger.Debug("listing go modules") - deps, err := gomod.ListDeps("") + deps, err := gomod.ListDeps(s.path) if err != nil { return nil, errors.Wrap(err, "failed to list dependencies") }