This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-eyes.git

commit a62044de52cc10ae8a1c165b780a2e4265423132
Author: kezhenxu94 <[email protected]>
AuthorDate: Sun Dec 20 15:58:20 2020 +0800

    Reshape the header check command
---
 .licenserc.json                               |  50 --------
 .licenserc.yaml                               |  21 +++
 cmd/root.go                                   | 177 +++-----------------------
 commands/header/check.go                      |  58 +++++++++
 commands/header/header.go                     |  15 +++
 go.mod                                        |  16 +--
 go.sum                                        |  40 ++----
 internal/logger/log.go                        |  38 ++++++
 main.go                                       |  11 +-
 pkg/header/check.go                           | 124 ++++++++++++++++++
 pkg/header/model.go                           |  12 ++
 {util => pkg/util}/str.go                     |   0
 {util => pkg/util}/str_test.go                |   0
 test/include_test/without_license/testcase.md |  19 +++
 14 files changed, 326 insertions(+), 255 deletions(-)

diff --git a/.licenserc.json b/.licenserc.json
deleted file mode 100644
index a15366c..0000000
--- a/.licenserc.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "licenseStrict": [
-    "Licensed to the Apache Software Foundation (ASF) under one or more",
-    "contributor license agreements.  See the NOTICE file distributed with",
-    "this work for additional information regarding copyright ownership.",
-    "The ASF licenses this file to You under the Apache License, Version 2.0",
-    "(the \"License\"); you may not use this file except in compliance with",
-    "the License.  You may obtain a copy of the License at",
-    "http://www.apache.org/licenses/LICENSE-2.0";,
-    "Unless required by applicable law or agreed to in writing, software",
-    "distributed under the License is distributed on an \"AS IS\" BASIS,",
-    "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",
-    "See the License for the specific language governing permissions and",
-    "limitations under the License."
-  ],
-  "licenseLoose": [
-    "Apache License, Version 2.0"
-  ],
-  "targetFiles": [
-    "java",
-    "go",
-    "py",
-    "sh",
-    "graphql",
-    "yaml",
-    "yml"
-  ],
-  "exclude": {
-    "files": [
-      ".gitignore",
-      "NOTICE",
-      "go.mod",
-      "go.sum",
-      ".DS_Store",
-      "LICENSE"
-    ],
-    "extensions": [
-      "md",
-      "xml",
-      "json"
-    ],
-    "directories": [
-      "bin",
-      ".github",
-      ".git",
-      ".idea",
-      "test"
-    ]
-  }
-}
\ No newline at end of file
diff --git a/.licenserc.yaml b/.licenserc.yaml
new file mode 100644
index 0000000..c23a250
--- /dev/null
+++ b/.licenserc.yaml
@@ -0,0 +1,21 @@
+mode: strict
+
+license: >
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+  http://www.apache.org/licenses/LICENSE-2.0
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+paths:
+  - 'test/include_test'
+
+paths-ignore:
+  - '**/*.md'
diff --git a/cmd/root.go b/cmd/root.go
index ef8abdf..68cc5eb 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -16,179 +16,38 @@ limitations under the License.
 package cmd
 
 import (
-       "bufio"
-       "encoding/json"
-       "fmt"
+       "github.com/sirupsen/logrus"
        "github.com/spf13/cobra"
-       "io/ioutil"
-       "license-checker/util"
-       "os"
-       "path/filepath"
-       "strings"
+       headercommand "license-checker/commands/header"
+       "license-checker/internal/logger"
 )
 
 var (
-       // cfgFile is the path to the config file.
-       cfgFile string
-       // checkPath is the path to check license.
-       checkPath string
-       // loose is flag to enable loose mode.
-       loose bool
-       // verbose is flag to enable verbose mode.
-       verbose bool
+       verbosity string
 )
 
 // rootCmd represents the base command when called without any subcommands
 var rootCmd = &cobra.Command{
-       Use: "license-checker [flags]",
-       Long: `license-checker walks the specified path recursively and checks 
-if the specified files have the license header in the config file.`,
-       Run: func(cmd *cobra.Command, args []string) {
-               config, err := LoadConfig()
-               if err != nil {
-                       fmt.Println(err)
-               }
-
-               res, err := WalkAndCheck(checkPath, config)
-               if err != nil {
-                       fmt.Println(err)
+       Use:           "license-checker command [flags]",
+       Long:          "license-checker walks the specified path recursively 
and checks if the specified files have the license header in the config file.",
+       SilenceUsage:  true,
+       SilenceErrors: true,
+       PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+               if level, err := logrus.ParseLevel(verbosity); err != nil {
+                       return err
+               } else {
+                       logger.Log.SetLevel(level)
                }
-               printResult(res)
+               return nil
        },
 }
 
 // Execute sets flags to the root command appropriately.
 // This is called by main.main(). It only needs to happen once to the rootCmd.
-func Execute() {
-       rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", 
".licenserc.json", "the config file")
-       rootCmd.PersistentFlags().StringVarP(&checkPath, "path", "p", ".", "the 
path to check")
-       rootCmd.PersistentFlags().BoolVarP(&loose, "loose", "l", false, "loose 
mode")
-       rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, 
"verbose mode")
-
-       if err := rootCmd.Execute(); err != nil {
-               fmt.Println(err)
-               os.Exit(1)
-       }
-}
-
-type excludeConfig struct {
-       Files       []string `json:"files"`
-       Extensions  []string `json:"extensions"`
-       Directories []string `json:"directories"`
-}
-
-type Config struct {
-       LicenseStrict []string      `json:"licenseStrict"`
-       LicenseLoose  []string      `json:"licenseLoose"`
-       TargetFiles   []string      `json:"targetFiles"`
-       Exclude       excludeConfig `json:"exclude"`
-}
-
-type Result struct {
-       Success []string `json:"success"`
-       Failure []string `json:"failure"`
-}
-
-// LoadConfig reads in config file.
-func LoadConfig() (*Config, error) {
-       var config Config
-       bytes, err := ioutil.ReadFile(cfgFile)
-       if err != nil {
-               return nil, err
-       }
-
-       err = json.Unmarshal(bytes, &config)
-       if err != nil {
-               return nil, err
-       }
-
-       return &config, nil
-}
-
-// WalkAndCheck traverses the path p and check every target file's license.
-func WalkAndCheck(p string, cfg *Config) (*Result, error) {
-       var license []string
-       if loose {
-               license = cfg.LicenseLoose
-       } else {
-               license = cfg.LicenseStrict
-       }
-
-       inExcludeDir := util.InStrSliceMapKeyFunc(cfg.Exclude.Directories)
-       inExcludeExt := util.InStrSliceMapKeyFunc(cfg.Exclude.Extensions)
-       inExcludeFiles := util.InStrSliceMapKeyFunc(cfg.Exclude.Files)
-
-       var result Result
-       err := filepath.Walk(p, func(path string, fi os.FileInfo, err error) 
error {
-               if err != nil {
-                       fmt.Println(err) // can't walk here,
-                       return nil       // but continue walking elsewhere
-               }
-
-               if fi.IsDir() {
-                       if inExcludeDir(fi.Name()) ||
-                               inExcludeDir(util.CleanPathPrefixes(path, 
[]string{p, string(os.PathSeparator)})) {
-                               return filepath.SkipDir
-                       }
-               } else {
-                       ext := util.GetFileExtension(fi.Name())
-                       if inExcludeFiles(fi.Name()) || inExcludeExt(ext) {
-                               return nil
-                       }
-
-                       ok, err := CheckLicense(path, license)
-                       if err != nil {
-                               return err
-                       }
-
-                       if ok {
-                               result.Success = append(result.Success, 
fmt.Sprintf("[Pass]: %s", path))
-                       } else {
-                               result.Failure = append(result.Failure, 
fmt.Sprintf("[No Specified License]: %s", path))
-                       }
-               }
-
-               return nil
-       })
-
-       return &result, err
-}
-
-// CheckLicense checks license of single file.
-func CheckLicense(filePath string, license []string) (bool, error) {
-       file, err := os.Open(filePath)
-       if err != nil {
-               return false, err
-       }
-       defer file.Close()
-
-       index := 0
-       scanner := bufio.NewScanner(file)
-       for scanner.Scan() && index < len(license) {
-               line := scanner.Text()
-               if strings.Contains(line, license[index]) {
-                       index++
-               }
-       }
-
-       if index != len(license) {
-               return false, nil
-       }
-       return true, nil
-}
-
-// printResult prints license check result.
-func printResult(r *Result) {
-       if verbose {
-               for _, s := range r.Success {
-                       fmt.Println(s)
-               }
-       }
+func Execute() error {
+       rootCmd.PersistentFlags().StringVarP(&verbosity, "verbosity", "v", 
logrus.InfoLevel.String(), "Log level (debug, info, warn, error, fatal, panic")
 
-       for _, s := range r.Failure {
-               fmt.Println(s)
-       }
+       rootCmd.AddCommand(headercommand.Header)
 
-       fmt.Printf("Total check %d files, success: %d, failure: %d\n",
-               len(r.Success)+len(r.Failure), len(r.Success), len(r.Failure))
+       return rootCmd.Execute()
 }
diff --git a/commands/header/check.go b/commands/header/check.go
new file mode 100644
index 0000000..24d316b
--- /dev/null
+++ b/commands/header/check.go
@@ -0,0 +1,58 @@
+package header
+
+import (
+       "github.com/spf13/cobra"
+       "gopkg.in/yaml.v3"
+       "io/ioutil"
+       "license-checker/internal/logger"
+       "license-checker/pkg/header"
+       "strings"
+)
+
+var (
+       // cfgFile is the config path to the config file of header command.
+       cfgFile string
+)
+
+var CheckCommand = &cobra.Command{
+       Use:     "check",
+       Long:    "`check` command walks the specified paths recursively and 
checks if the specified files have the license header in the config file.",
+       Aliases: []string{"c"},
+       RunE: func(cmd *cobra.Command, args []string) error {
+               var config header.Config
+               if err := loadConfig(&config); err != nil {
+                       return err
+               }
+               return header.Check(&config)
+       },
+}
+
+func init() {
+       CheckCommand.Flags().StringVarP(&cfgFile, "config", "c", 
".licenserc.yaml", "the config file")
+}
+
+// loadConfig reads and parses the header check configurations in config file.
+func loadConfig(config *header.Config) error {
+       logger.Log.Infoln("Loading configuration from file:", cfgFile)
+
+       bytes, err := ioutil.ReadFile(cfgFile)
+       if err != nil {
+               return err
+       }
+
+       if err = yaml.Unmarshal(bytes, config); err != nil {
+               return err
+       }
+
+       var lines []string
+       for _, line := range strings.Split(config.License, "\n") {
+               if len(line) > 0 {
+                       lines = append(lines, strings.Trim(line, 
header.CommentChars))
+               }
+       }
+       config.License = strings.Join(lines, "\n")
+
+       logger.Log.Infoln("License header is:", config.License)
+
+       return nil
+}
diff --git a/commands/header/header.go b/commands/header/header.go
new file mode 100644
index 0000000..5879a40
--- /dev/null
+++ b/commands/header/header.go
@@ -0,0 +1,15 @@
+package header
+
+import (
+       "github.com/spf13/cobra"
+)
+
+var Header = &cobra.Command{
+       Use:     "header",
+       Long:    "`header` command walks the specified paths recursively and 
checks if the specified files have the license header in the config file.",
+       Aliases: []string{"h"},
+}
+
+func init() {
+       Header.AddCommand(CheckCommand)
+}
diff --git a/go.mod b/go.mod
index ebaf77e..1ac37cf 100644
--- a/go.mod
+++ b/go.mod
@@ -3,18 +3,8 @@ module license-checker
 go 1.13
 
 require (
-       github.com/fsnotify/fsnotify v1.4.9 // indirect
-       github.com/magiconair/properties v1.8.4 // indirect
-       github.com/mitchellh/go-homedir v1.1.0
-       github.com/mitchellh/mapstructure v1.3.3 // indirect
-       github.com/pelletier/go-toml v1.8.1 // indirect
-       github.com/spf13/afero v1.4.1 // indirect
-       github.com/spf13/cast v1.3.1 // indirect
+       github.com/bmatcuk/doublestar/v2 v2.0.4
+       github.com/sirupsen/logrus v1.7.0
        github.com/spf13/cobra v1.1.1
-       github.com/spf13/jwalterweatherman v1.1.0 // indirect
-       github.com/spf13/viper v1.7.1
-       golang.org/x/sys v0.0.0-20201117222635-ba5294a509c7 // indirect
-       golang.org/x/text v0.3.4 // indirect
-       gopkg.in/ini.v1 v1.62.0 // indirect
-       gopkg.in/yaml.v2 v2.3.0 // indirect
+       gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
 )
diff --git a/go.sum b/go.sum
index cd8c883..fda907d 100644
--- a/go.sum
+++ b/go.sum
@@ -23,6 +23,9 @@ github.com/beorn7/perks 
v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
 github.com/beorn7/perks v1.0.0/go.mod 
h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/bgentry/speakeasy v0.1.0/go.mod 
h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod 
h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/bmatcuk/doublestar v1.3.4 
h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
+github.com/bmatcuk/doublestar/v2 v2.0.4 
h1:6I6oUiT/sU27eE2OFcWqBhL1SwjyvQuOssxT4a1yidI=
+github.com/bmatcuk/doublestar/v2 v2.0.4/go.mod 
h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw=
 github.com/cespare/xxhash v1.1.0/go.mod 
h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/client9/misspell v0.3.4/go.mod 
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/coreos/bbolt v1.3.2/go.mod 
h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@@ -38,8 +41,6 @@ github.com/dgryski/go-sip13 
v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
 github.com/fatih/color v1.7.0/go.mod 
h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fsnotify/fsnotify v1.4.7 
h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod 
h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsnotify/fsnotify v1.4.9 
h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
-github.com/fsnotify/fsnotify v1.4.9/go.mod 
h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/ghodss/yaml v1.0.0/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod 
h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-kit/kit v0.8.0/go.mod 
h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -102,15 +103,12 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod 
h1:SYymIcj16QtmaHHD7aYtjjsJG7V
 github.com/kisielk/errcheck v1.1.0/go.mod 
h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/gotool v1.0.0/go.mod 
h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod 
h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod 
h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod 
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/magiconair/properties v1.8.1 
h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod 
h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/magiconair/properties v1.8.4 
h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY=
-github.com/magiconair/properties v1.8.4/go.mod 
h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/mattn/go-colorable v0.0.9/go.mod 
h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-isatty v0.0.3/go.mod 
h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod 
h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -125,8 +123,6 @@ github.com/mitchellh/iochan v1.0.0/go.mod 
h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2 
h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod 
h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.3.3 
h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
-github.com/mitchellh/mapstructure v1.3.3/go.mod 
h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.1/go.mod 
h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod 
h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -134,11 +130,8 @@ github.com/oklog/ulid v1.3.1/go.mod 
h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod 
h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pelletier/go-toml v1.2.0 
h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
 github.com/pelletier/go-toml v1.2.0/go.mod 
h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pelletier/go-toml v1.8.1 
h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
-github.com/pelletier/go-toml v1.8.1/go.mod 
h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
 github.com/pkg/errors v0.8.0/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/sftp v1.10.1/go.mod 
h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
 github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod 
h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/prometheus/client_golang v0.9.1/go.mod 
h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -157,36 +150,29 @@ github.com/ryanuber/columnize 
v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod 
h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod 
h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod 
h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.7.0 
h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
+github.com/sirupsen/logrus v1.7.0/go.mod 
h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod 
h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/goconvey v1.6.4/go.mod 
h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/soheilhy/cmux v0.1.4/go.mod 
h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod 
h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
 github.com/spf13/afero v1.1.2/go.mod 
h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/afero v1.4.1 h1:asw9sl74539yqavKaglDM5hFpdJVK0Y5Dr/JOgQ89nQ=
-github.com/spf13/afero v1.4.1/go.mod 
h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
 github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
 github.com/spf13/cast v1.3.0/go.mod 
h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
-github.com/spf13/cast v1.3.1/go.mod 
h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
 github.com/spf13/cobra v1.1.1/go.mod 
h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
 github.com/spf13/jwalterweatherman v1.0.0 
h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod 
h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/jwalterweatherman v1.1.0 
h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
-github.com/spf13/jwalterweatherman v1.1.0/go.mod 
h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v1.0.3/go.mod 
h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
 github.com/spf13/viper v1.7.0/go.mod 
h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
-github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
-github.com/spf13/viper v1.7.1/go.mod 
h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
 github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod 
h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod 
h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod 
h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/subosito/gotenv v1.2.0 
h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod 
h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod 
h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -202,7 +188,6 @@ golang.org/x/crypto 
v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod 
h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -257,16 +242,12 @@ golang.org/x/sys 
v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 
h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201117222635-ba5294a509c7 
h1:s330+6z/Ko3J0o6rvOcwXe5nzs7UT9tLKHoOXYn6uE0=
-golang.org/x/sys v0.0.0-20201117222635-ba5294a509c7/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 
h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod 
h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
-golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -314,17 +295,14 @@ gopkg.in/check.v1 
v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
-gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/resty.v1 v1.12.0/go.mod 
h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod 
h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 
h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod 
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/internal/logger/log.go b/internal/logger/log.go
new file mode 100644
index 0000000..4803978
--- /dev/null
+++ b/internal/logger/log.go
@@ -0,0 +1,38 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package logger
+
+import (
+       "os"
+
+       "github.com/sirupsen/logrus"
+)
+
+var Log *logrus.Logger
+
+func init() {
+       if Log == nil {
+               Log = logrus.New()
+       }
+       Log.Level = logrus.DebugLevel
+       Log.SetOutput(os.Stdout)
+       Log.SetFormatter(&logrus.TextFormatter{
+               DisableTimestamp:       true,
+               DisableLevelTruncation: true,
+       })
+}
diff --git a/main.go b/main.go
index e9f9be6..3f262a7 100644
--- a/main.go
+++ b/main.go
@@ -15,8 +15,15 @@ limitations under the License.
 */
 package main
 
-import "license-checker/cmd"
+import (
+       "license-checker/cmd"
+       "license-checker/internal/logger"
+       "os"
+)
 
 func main() {
-       cmd.Execute()
+       if err := cmd.Execute(); err != nil {
+               logger.Log.Errorln(err)
+               os.Exit(1)
+       }
 }
diff --git a/pkg/header/check.go b/pkg/header/check.go
new file mode 100644
index 0000000..aef1c8e
--- /dev/null
+++ b/pkg/header/check.go
@@ -0,0 +1,124 @@
+package header
+
+import (
+       "bufio"
+       "fmt"
+       "github.com/bmatcuk/doublestar/v2"
+       "license-checker/internal/logger"
+       "os"
+       "path/filepath"
+       "strings"
+)
+
+const CommentChars = "/*#- "
+
+// Check checks the license headers of the specified paths/globs.
+func Check(config *Config) error {
+       var result Result
+
+       for _, pattern := range config.Paths {
+               if err := checkPattern(pattern, &result, config); err != nil {
+                       return err
+               }
+       }
+
+       if len(result.Failure) > 0 {
+               return fmt.Errorf(
+                       "The following files don't have a valid license header: 
\n%v",
+                       strings.Join(result.Failure, "\n"),
+               )
+       }
+
+       return nil
+}
+
+func checkPattern(pattern string, result *Result, config *Config) error {
+       paths, err := doublestar.Glob(pattern)
+
+       if err != nil {
+               return err
+       }
+
+       logger.Log.Infoln("Checking matched paths:", paths)
+
+       for _, path := range paths {
+               logger.Log.Debugln("Checking path:", path)
+
+               if err = checkPath(path, result, config); err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func checkPath(path string, result *Result, config *Config) error {
+       pathInfo, err := os.Stat(path)
+
+       if err != nil {
+               return err
+       }
+
+       switch mode := pathInfo.Mode(); {
+       case mode.IsDir():
+               if err := filepath.Walk(path, func(p string, info os.FileInfo, 
err error) error {
+                       if info.IsDir() {
+                               return nil
+                       }
+                       if err := checkPath(p, result, config); err != nil {
+                               return err
+                       }
+                       return nil
+               }); err != nil {
+                       return err
+               }
+       case mode.IsRegular():
+               return checkFile(path, result, config)
+       }
+       return nil
+}
+
+func checkFile(file string, result *Result, config *Config) error {
+       skip := false
+       for _, ignorePattern := range config.PathsIgnore {
+               logger.Log.Debugln("Checking ignore pattern:", ignorePattern)
+
+               if ignored, err := doublestar.Match(ignorePattern, file); 
ignored || err != nil {
+                       logger.Log.Infoln("Ignoring path:", file)
+                       skip = ignored
+                       break
+               }
+       }
+       if skip {
+               return nil
+       }
+
+       logger.Log.Debugln("Checking file:", file)
+
+       reader, err := os.Open(file)
+
+       if err != nil {
+               return nil
+       }
+
+       var lines []string
+
+       scanner := bufio.NewScanner(reader)
+       for scanner.Scan() {
+               line := strings.Trim(scanner.Text(), CommentChars)
+               if len(line) > 0 {
+                       lines = append(lines, line)
+               }
+       }
+
+       if content := strings.Join(lines, " "); !strings.Contains(content, 
config.License) {
+               logger.Log.Debugln("Content is:", content)
+               logger.Log.Debugln("License is:", config.License)
+
+               result.Failure = append(result.Failure, file)
+       } else {
+               result.Success = append(result.Success, file)
+       }
+
+       return nil
+}
diff --git a/pkg/header/model.go b/pkg/header/model.go
new file mode 100644
index 0000000..8401cae
--- /dev/null
+++ b/pkg/header/model.go
@@ -0,0 +1,12 @@
+package header
+
+type Config struct {
+       License     string   `yaml:"license"`
+       Paths       []string `yaml:"paths"`
+       PathsIgnore []string `yaml:"paths-ignore"`
+}
+
+type Result struct {
+       Success []string `yaml:"success"`
+       Failure []string `yaml:"failure"`
+}
diff --git a/util/str.go b/pkg/util/str.go
similarity index 100%
rename from util/str.go
rename to pkg/util/str.go
diff --git a/util/str_test.go b/pkg/util/str_test.go
similarity index 100%
rename from util/str_test.go
rename to pkg/util/str_test.go
diff --git a/test/include_test/without_license/testcase.md 
b/test/include_test/without_license/testcase.md
new file mode 100644
index 0000000..95d8ce5
--- /dev/null
+++ b/test/include_test/without_license/testcase.md
@@ -0,0 +1,19 @@
+<!--
+Esse enim dolore adipisicing in cillum eiusmod excepteur quis nisi sit dolor 
anim anim id id nostrud nostrud tempor.
+ Elit sit enim cillum adipisicing non magna aute nostrud ullamco dolor dolore 
consequat ut ea occaecat veniam incididunt
+  occaecat consectetur eiusmod sint eiusmod aute eu duis fugiat dolore in 
laboris enim eiusmod aliquip nisi aliqua irure
+  nulla proident ut ut aliqua et in ad deserunt nisi anim non dolore ut 
commodo excepteur ut eiusmod ex exercitation
+  in sunt cillum ullamco dolor magna ex proident elit in mollit incididunt 
excepteur dolor pariatur consectetur
+  exercitation qui ut cupidatat dolor do esse tempor commodo magna ad in duis 
voluptate est nisi in pariatur
+  duis mollit eiusmod est magna in velit aute anim ullamco nostrud adipisicing 
cupidatat non fugiat proident
+   commodo minim sint minim pariatur nostrud sit mollit cillum dolor minim 
quis nisi id officia veniam
+   mollit tempor exercitation dolore duis cillum sunt esse nostrud deserunt 
amet ad quis reprehenderit
+   do in proident est incididunt voluptate et ullamco nisi dolore commodo 
mollit elit sint aute in occaecat
+   excepteur do pariatur laborum occaecat ad et nisi ut est in consequat 
commodo consectetur consequat ullamco m
+   ollit aute dolor velit do deserunt eu velit reprehenderit incididunt 
commodo duis anim dolor velit nostrud eu
+   irure dolor mollit labore sunt consectetur ullamco sed consectetur sed sint 
consectetur eu fugiat amet nostrud
+   elit reprehenderit sunt ullamco fugiat eiusmod elit est est in duis quis 
occaecat proident aliquip adipisicing
+    eu sint pariatur ullamco adipisicing cupidatat sed ut pariatur ut in amet 
deserunt laboris consectetur in
+    consectetur mollit voluptate magna ut ullamco pariatur proident esse 
commodo consectetur minim in do eu
+     consequat ea eiusmod proident incididunt ut qui sunt consequat officia 
amet amet amet dolore fugiat ex.
+-->

Reply via email to