dev
diff --git a/.licenserc.json b/.licenserc.json
new file mode 100644
index 0000000..3d262cc
--- /dev/null
+++ b/.licenserc.json
@@ -0,0 +1,48 @@
+{
+  "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"
+    ],
+    "extensions": [
+      "md",
+      "xml",
+      "json"
+    ],
+    "directories": [
+      "bin",
+      ".github",
+      ".git",
+      ".idea"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4e83903
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,69 @@
+# Copyright © 2020 Hoshea Jiang <hoshea@apache.org>
+#
+# Licensed 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.
+
+PROJECT = license-checker
+VERSION ?= latest
+OUT_DIR = bin
+CURDIR := $(shell pwd)
+FILES := $$(find .$$($(PACKAGE_DIRECTORIES)) -name "*.go")
+FAIL_ON_STDOUT := awk '{ print } END { if (NR > 0) { exit 1 } }'
+
+GO := GO111MODULE=on go
+GO_PATH = $$($(GO) env GOPATH)
+GO_BUILD = $(GO) build
+GO_GET = $(GO) get
+GO_TEST = $(GO) test
+GO_LINT = $(GO_PATH)/bin/golangci-lint
+GO_LICENSER = $(GO_PATH)/bin/go-licenser
+
+# Ensure GOPATH is set before running build process.
+ifeq "$(GOPATH)" ""
+  $(error Please set the environment variable GOPATH before running `make`)
+endif
+
+all: clean deps lint test build
+
+tools:
+	mkdir -p $(GO_PATH)/bin
+	$(GO_LINT) version || curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GO_PATH)/bin v1.21.0
+	$(GO_LICENSER) -version || GO111MODULE=off $(GO_GET) -u github.com/elastic/go-licenser
+
+deps: tools
+	$(GO_GET) -v -t -d ./...
+
+.PHONY: lint
+lint: tools
+	@gofmt -s -l -w $(FILES) 2>&1 | $(FAIL_ON_STDOUT)
+	$(GO_LINT) run -v ./...
+
+.PHONE: test
+test: clean lint
+	$(GO_TEST) ./...
+	@>&2 echo "Great, all tests passed."
+
+.PHONY: build
+build: deps
+	$(GO_BUILD) -o $(OUT_DIR)/$(PROJECT)
+
+#.PHONY: license
+#license: clean tools
+#	$(GO_LICENSER) -d -license='ASL2' .
+
+.PHONY: fix
+fix: tools
+	$(GO_LINT) run -v --fix ./...
+
+.PHONY: clean
+clean: tools
+	-rm -rf bin
diff --git a/cmd/root.go b/cmd/root.go
index 14c62b6..841fa46 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -1,5 +1,5 @@
 /*
-Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+Copyright © 2020 Hoshea Jiang <hoshea@apache.org>
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -16,23 +16,33 @@
 package cmd
 
 import (
+	"encoding/json"
 	"fmt"
 	"github.com/spf13/cobra"
+	"io/ioutil"
+	"license-checker/util"
 	"os"
-
-	homedir "github.com/mitchellh/go-homedir"
-	"github.com/spf13/viper"
+	"path/filepath"
 )
 
 var cfgFile string
+var checkPath string
+var loose bool
 
 // rootCmd represents the base command when called without any subcommands
 var rootCmd = &cobra.Command{
-	Use:   "license-checker",
-	Short: "A brief description of your application",
-
+	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) {
-		fmt.Println("Hello Cobra CLI!")
+		config, err := LoadConfig()
+		if err != nil {
+			fmt.Println(err)
+		}
+		//fmt.Println(config.TargetFiles)
+		if err := Walk(checkPath, config); err != nil {
+			fmt.Println(err)
+		}
 	},
 }
 
@@ -46,41 +56,77 @@
 }
 
 func init() {
-	cobra.OnInitialize(initConfig)
-
-	// Here you will define your flags and configuration settings.
-	// Cobra supports persistent flags, which, if defined here,
-	// will be global for your application.
-
-	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.license-checker.yaml)")
-
-	// Cobra also supports local flags, which will only run
-	// when this action is called directly.
-	rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+	rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", ".licenserc.json", "the config file")
+	rootCmd.PersistentFlags().StringVarP(&checkPath, "path", "p", "", "the path to check (required)")
+	rootCmd.PersistentFlags().BoolVarP(&loose, "loose", "l", false, "loose mode")
+	if err := rootCmd.MarkPersistentFlagRequired("path"); err != nil {
+		fmt.Println(err)
+	}
 }
 
-// initConfig reads in config file and ENV variables if set.
-func initConfig() {
-	if cfgFile != "" {
-		// Use config file from the flag.
-		viper.SetConfigFile(cfgFile)
-	} else {
-		// Find home directory.
-		home, err := homedir.Dir()
+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
+}
+
+func Walk(p string, cfg *Config) error {
+	inExcludeDir := util.InStrSliceMapKeyFunc(cfg.Exclude.Directories)
+	inExcludeExt := util.InStrSliceMapKeyFunc(cfg.Exclude.Extensions)
+	inExcludeFiles := util.InStrSliceMapKeyFunc(cfg.Exclude.Files)
+
+	err := filepath.Walk(p, func(path string, fi os.FileInfo, err error) error {
 		if err != nil {
-			fmt.Println(err)
-			os.Exit(1)
+			fmt.Println(err) // can't walk here,
+			return nil       // but continue walking elsewhere
 		}
 
-		// Search config in home directory with name ".license-checker" (without extension).
-		viper.AddConfigPath(home)
-		viper.SetConfigName(".license-checker")
-	}
+		if fi.IsDir() {
+			if inExcludeDir(fi.Name()) {
+				return filepath.SkipDir
+			}
+		} else {
+			ext := util.GetFileExtension(fi.Name())
+			if inExcludeFiles(fi.Name()) || inExcludeExt(ext) {
+				return nil
+			}
 
-	viper.AutomaticEnv() // read in environment variables that match
+			// TODO: open the file and check
+			fmt.Println(path)
+			//curDir := strings.Replace(path, fi.Name(), "", 1)
+			//fmt.Println(curDir)
+		}
 
-	// If a config file is found, read it in.
-	if err := viper.ReadInConfig(); err == nil {
-		fmt.Println("Using config file:", viper.ConfigFileUsed())
-	}
+		return nil
+	})
+
+	return err
 }
diff --git a/config.json b/config.json
deleted file mode 100644
index 10d2446..0000000
--- a/config.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "**/*.{java, go, py}": [
-    "You can put multiline headers like this",
-    "Copyright Foo, Inc. and other Bar contributors.",
-    "Permission is hereby granted, free of charge, to any person obtaining a",
-    "copy of this software and associated documentation files (the",
-    "\"Software\"), to deal in the Software without restriction, including",
-    "without limitation the rights to use, copy, modify, merge, publish,",
-    "distribute, sublicense, and/or sell copies of the Software, and to permit",
-    "persons to whom the Software is furnished to do so, subject to the",
-    "following conditions:",
-    "..."
-  ],
-
-  "ignore": [
-    "lib/vendor/jquery.js", // ignore this file
-    "vendor/" // ignore all files under vendor
-  ]
-}
\ No newline at end of file
diff --git a/config.yaml b/config.yaml
deleted file mode 100644
index 4845d7a..0000000
--- a/config.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-include:
-
-exclude:
\ No newline at end of file
diff --git a/main.go b/main.go
index d2e9d49..e9f9be6 100644
--- a/main.go
+++ b/main.go
@@ -1,5 +1,5 @@
 /*
-Copyright © 2020 NAME HERE <EMAIL ADDRESS>
+Copyright © 2020 Hoshea Jiang <hoshea@apache.org>
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/test/testcase.go b/test/testcase.go
new file mode 100644
index 0000000..4020ef8
--- /dev/null
+++ b/test/testcase.go
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+package test
diff --git a/test/testcase.java b/test/testcase.java
new file mode 100644
index 0000000..43a94f3
--- /dev/null
+++ b/test/testcase.java
@@ -0,0 +1,14 @@
+// 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.
diff --git a/test/testcase.md b/test/testcase.md
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/testcase.md
diff --git a/test/testcase3.py b/test/testcase3.py
new file mode 100644
index 0000000..a9fd83f
--- /dev/null
+++ b/test/testcase3.py
@@ -0,0 +1,16 @@
+#
+# 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.
+#
\ No newline at end of file
diff --git a/util/str.go b/util/str.go
new file mode 100644
index 0000000..b953e48
--- /dev/null
+++ b/util/str.go
@@ -0,0 +1,43 @@
+/*
+Copyright © 2020 Hoshea Jiang <hoshea@apache.org>
+
+Licensed 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 util
+
+import (
+	"strings"
+)
+
+func InStrSliceMapKeyFunc(strs []string) func(string) bool {
+	set := make(map[string]struct{})
+
+	for _, e := range strs {
+		set[e] = struct{}{}
+	}
+
+	return func(s string) bool {
+		_, ok := set[s]
+		return ok
+	}
+}
+
+func GetFileExtension(filename string) string {
+	i := strings.LastIndex(filename, ".")
+	if i != -1 {
+		if i+1 < len(filename) {
+			return filename[i+1:]
+		}
+	}
+	return ""
+}
diff --git a/util/str_test.go b/util/str_test.go
new file mode 100644
index 0000000..fce8965
--- /dev/null
+++ b/util/str_test.go
@@ -0,0 +1,58 @@
+/*
+Copyright © 2020 Hoshea Jiang <hoshea@apache.org>
+
+Licensed 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 util
+
+import "testing"
+
+func TestGetFileExtension(t *testing.T) {
+	type args struct {
+		filename string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "txt extension",
+			args: args{
+				filename: ".abc.txt",
+			},
+			want: "txt",
+		},
+		{
+			name: "no file extensions",
+			args: args{
+				filename: ".abc.txt.",
+			},
+			want: "",
+		},
+		{
+			name: "no file extensions",
+			args: args{
+				filename: "lkjsdl",
+			},
+			want: "",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := GetFileExtension(tt.args.filename); got != tt.want {
+				t.Errorf("GetFileExtension() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}