diff --git a/README.md b/README.md index a2a2018..590595b 100644 --- a/README.md +++ b/README.md @@ -22,45 +22,50 @@ brew install heptapod ### Usage +To print help; ``` heptapod -h heptapod -h ``` -Will print help! +Move (and use) the default ruleset; ``` mkdir -p ~/.heptapod/rules cp -R $(brew --prefix heptapod)/rules ~/.heptapod ``` -This will move the currently added ruleset to `~/.heptapod/rules` +Lists all the rules (you get 4 tables, enabled, disabled, parseable but unrunable and unparsable). ``` -heptapod ls -a +heptapod rules ls -a +``` + +Enable/disable rules (by name), or add/remove ignore folders; +``` +heptapod rules disable node bower +heptapod rules enable bower +heptapod rules ignoreAdd ~/.Trash ~/.yarn/cache ~/Library +heptapod rules ignoreRemove ~/.Trash ``` -Lists all the rules (you get 4 tables, enabled, disabled, parseable but unrunable and unparsable). +List all the currently excluded TM paths; ``` -heptapod lse +heptapod tm ls ``` -Could list all the currently excluded TM paths. +Dryrun the current rules, in verbose mode, also log speed and debug informations. (Potentially list nonexistent directories and files!) ``` heptapod -v run -d ``` -Will dryrun the current rules, will log speed informations. (Potentially list nonexistent directories and files!) +To run the current rules, and add the dirs to the TM exclude list. Also writes exclude logs to `~/.heptapod/logs` (or the given `--logDir dir`) for easier revert. ``` heptapod run ``` -Will run the current rules, and add them to the TM exclude list. Also writes exclude logs to `~/.heptapod/logs` (or the given `--logDir dir`) for easier revert. +To revert all the previously added paths from the run-exclude-logs. (`prune -h` could tell you the other useful revert options). ``` heptapod prune -a ``` -Will revert all the previously added paths from the run-exclude-logs. (`prune -h` could tell you the other useful revert options). - - - ### Notes for TM migrating to a new machine When you try to migrate your TM state to a new machine @@ -117,6 +122,7 @@ done: - we should write down what paths excluded by us, and include them back - brew package - ghactions +- rule manage commands (list/enable/disable/ignoreAdd/ignoreRemove) todos: - handle global deps (m2, ivy, nvm, npm) diff --git a/main.go b/main.go index 57288cf..778e3f4 100644 --- a/main.go +++ b/main.go @@ -1,16 +1,11 @@ package main import ( - "fmt" - "github.com/olekukonko/tablewriter" - "github.com/tg44/heptapod/pkg" - "github.com/tg44/heptapod/pkg/parser" - "github.com/tg44/heptapod/pkg/tmutil" + cli_utils "github.com/tg44/heptapod/pkg/cli-utils" "github.com/urfave/cli/v2" "log" "os" "sort" - "strings" ) var version string = "local-build" @@ -18,179 +13,21 @@ var commit string = "" var date string = "" func main() { - var rulePath string - var logDir string - var file string - var all bool - var dry bool - var current bool - var verbose bool - var par int - var buffer int - app := &cli.App{ Name: "heptapod", Usage: "Fine-tune your TimeMachine excludes!", Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "rules", - Aliases: []string{"r"}, - Value: "~/.heptapod/rules", - Usage: "the directory containing rule yamls", - Destination: &rulePath, - }, - &cli.StringFlag{ - Name: "logDir", - Aliases: []string{"ld"}, - Value: "~/.heptapod/logs", - Usage: "the directory where excluded dirs logged for reliable prune/uninstall", - Destination: &logDir, - }, - &cli.BoolFlag{ - Name: "verbose", - Aliases: []string{"v"}, - Value: false, - Usage: "prints out performance logs (and other logs in general)", - Destination: &verbose, - }, - &cli.IntFlag{ - Name: "parallelism", - Aliases: []string{"p", "par"}, - Value: 4, - Usage: "number of workers where the code is multithreaded", - Destination: &par, - }, - &cli.IntFlag{ - Name: "bufferSize", - Aliases: []string{"b", "buffer"}, - Value: 2048, - Usage: "number of elements buffered, can cause deadlocks", - Destination: &buffer, - }, + cli_utils.RulesPathFlag, + cli_utils.LogDirFlag, + cli_utils.VerboseFlag, + cli_utils.ParallelismFlag, + cli_utils.BufferSizeFlag, }, Commands: []*cli.Command{ - { - Name: "version", - Aliases: []string{"v"}, - Usage: "version info", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "verbose", - Aliases: []string{"v"}, - Value: false, - Usage: "more detaild version info", - Destination: &verbose, - }, - }, - Action: func(c *cli.Context) error { - if verbose { - fmt.Println("version: ", version) - fmt.Println("commit: ", commit) - fmt.Println("date: ", date) - } else { - fmt.Println(version) - } - return nil - }, - }, - { - Name: "list", - Aliases: []string{"ls"}, - Usage: "list the rules", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "all", - Aliases: []string{"a"}, - Value: false, - Usage: "show all tables", - Destination: &all, - }, - }, - Action: func(c *cli.Context) error { - return ruleTable(rulePath, all) - }, - }, - { - Name: "run", - Aliases: []string{}, - Usage: "run the exclude detection, and also exclude the dirs", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "dry", - Aliases: []string{"d"}, - Value: false, - Usage: "only prints the paths we should exclude (if exists)", - Destination: &dry, - }, - }, - Action: func(c *cli.Context) error { - if dry { - res := pkg.GetExcludedPaths(rulePath, par, buffer, verbose) - fmt.Println("-----") - fmt.Print(strings.Join(res,"\r\n")) - fmt.Print("\n") - } else { - res := pkg.GetExcludedPaths(rulePath, par, buffer, verbose) - tmutil.AddPathsToTM(res, logDir, buffer, verbose) - if verbose { - log.Printf("total %d paths found\n", len(res)) - } - } - return nil - }, - }, - { - Name: "excluded", - Aliases: []string{"lse"}, - Usage: "lists all the excluded dirs from tmutil", - Flags: []cli.Flag{}, - Action: func(c *cli.Context) error { - res := tmutil.GetExcludeList() - fmt.Println(res) - return nil - }, - }, - { - Name: "prune", - Aliases: []string{}, - Usage: "removes excludes from TM", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "all", - Aliases: []string{"a"}, - Value: false, - Usage: "remove all previously added exclude paths from the log dir", - Destination: &all, - }, - &cli.StringFlag{ - Name: "file", - Aliases: []string{"f"}, - Value: "", - Usage: "remove previously added exclude paths from the file in the log dir", - Destination: &file, - }, - &cli.BoolFlag{ - Name: "run", - Aliases: []string{"r"}, - Value: false, - Usage: "remove previously added exclude paths based on the current rules", - Destination: ¤t, - }, - }, - Action: func(c *cli.Context) error { - if current { - res := pkg.GetExcludedPaths(rulePath, par, buffer, verbose) - tmutil.RemovePathsFromTM(res, buffer, verbose) - } else if all { - tmutil.RemoveAllFromLogs(logDir, buffer, verbose) - } else if file != "" { - tmutil.RemoveFileFromLogs(logDir, file, buffer, verbose) - } else { - log.Fatal("one of the options is mandatory, please add current, all, or a file") - } - return nil - }, - }, + cli_utils.VersionCommand(version, commit, date), + cli_utils.RuleCommands, + cli_utils.RunCommand, + cli_utils.TmCommands, }, } @@ -202,64 +39,3 @@ func main() { log.Fatal(err) } } - -func ruleTable(path string, all bool) error { - list, err := parser.ParseRulesFromDir(path) - if err != nil { - return err - } - fmt.Println("Enabled rules:") - writeRules(list.Enabled) - if all { - fmt.Println("Disabled rules:") - writeRules(list.Disabled) - } - if all { - fmt.Println("Errors:") - writeErrorRules(list.FileErrors) - } - if all { - fmt.Println("Type parse errors:") - writeTypeErrorRules(list.TypeErrors) - } - return nil -} - -func writeErrorRules(paths []string) { - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"nonparseable files"}) - table.SetBorder(false) - - for _, row := range paths { - table.Append([]string{row}) - } - - table.SetAutoMergeCells(false) - table.Render() -} - -func writeTypeErrorRules(tes map[string]parser.Rule) { - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"path", "name", "type"}) - table.SetBorder(false) - - for k, v := range tes { - table.Append([]string{k, v.Name, v.RuleType}) - } - - table.SetAutoMergeCells(false) - table.Render() -} - -func writeRules(tes map[string]parser.Rule) { - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"path", "name", "type", "search", "ignore"}) - table.SetBorder(false) - - for k, v := range tes { - table.Append([]string{k, v.Name, v.RuleType, strings.Join(v.SearchPaths, ", "), strings.Join(v.IgnorePaths, ", ")}) - } - - table.SetAutoMergeCells(false) - table.Render() -} diff --git a/pkg/cli-utils/global-flags.go b/pkg/cli-utils/global-flags.go new file mode 100644 index 0000000..b9f6461 --- /dev/null +++ b/pkg/cli-utils/global-flags.go @@ -0,0 +1,51 @@ +package cli_utils + +import ( + "github.com/urfave/cli/v2" +) + +var rulePath string +var logDir string +var verbose bool +var par int +var buffer int + +var RulesPathFlag = &cli.StringFlag{ + Name: "rules", + Aliases: []string{"r"}, + Value: "~/.heptapod/rules", + Usage: "the directory containing rule yamls", + Destination: &rulePath, +} + +var LogDirFlag = &cli.StringFlag{ + Name: "logDir", + Aliases: []string{"ld"}, + Value: "~/.heptapod/logs", + Usage: "the directory where excluded dirs logged for reliable prune/uninstall", + Destination: &logDir, +} + +var VerboseFlag = &cli.BoolFlag{ + Name: "verbose", + Aliases: []string{"v"}, + Value: false, + Usage: "prints out performance logs (and other logs in general)", + Destination: &verbose, +} + +var ParallelismFlag = &cli.IntFlag{ + Name: "parallelism", + Aliases: []string{"p", "par"}, + Value: 4, + Usage: "number of workers where the code is multithreaded", + Destination: &par, +} + +var BufferSizeFlag = &cli.IntFlag{ + Name: "bufferSize", + Aliases: []string{"b", "buffer"}, + Value: 2048, + Usage: "number of elements buffered, can cause deadlocks", + Destination: &buffer, +} diff --git a/pkg/cli-utils/rule-command.go b/pkg/cli-utils/rule-command.go new file mode 100644 index 0000000..0c216a5 --- /dev/null +++ b/pkg/cli-utils/rule-command.go @@ -0,0 +1,266 @@ +package cli_utils + +import ( + "fmt" + "github.com/olekukonko/tablewriter" + "github.com/tg44/heptapod/pkg/parser" + "github.com/tg44/heptapod/pkg/utils" + "github.com/urfave/cli/v2" + "io/ioutil" + "os" + "path/filepath" + "strings" +) + +var RuleCommands = &cli.Command{ + Name: "rules", + Aliases: []string{}, + Usage: "rule related functions", + Subcommands: []*cli.Command{ + RuleList, + RuleAddGlobalIgnore, + RuleRemoveGlobalIgnore, + RuleEnable, + RuleDisable, + }, +} + +var RuleAddGlobalIgnore = &cli.Command{ + Name: "ignoreAdd", + Aliases: []string{}, + Usage: "add dir as ignored for all rules", + Action: func(c *cli.Context) error { + return ruleIgnoreAddAll(rulePath, c.Args().Slice()) + }, +} + +var RuleRemoveGlobalIgnore = &cli.Command{ + Name: "ignoreRemove", + Aliases: []string{}, + Usage: "remove ignored dir from all rules", + Action: func(c *cli.Context) error { + return ruleIgnoreRemoveAll(rulePath, c.Args().Slice()) + }, +} + +var RuleEnable = &cli.Command{ + Name: "enable", + Aliases: []string{}, + Usage: "enables the given rules", + Action: func(c *cli.Context) error { + return ruleEnable(rulePath, c.Args().Slice()) + }, +} + +var RuleDisable = &cli.Command{ + Name: "disable", + Aliases: []string{}, + Usage: "disables the given rules", + Action: func(c *cli.Context) error { + return ruleDisable(rulePath, c.Args().Slice()) + }, +} + +var RuleList = &cli.Command{ + Name: "list", + Aliases: []string{"ls"}, + Usage: "list the rules", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Aliases: []string{"a"}, + Value: false, + Usage: "show all tables", + Destination: &all, + }, + }, + Action: func(c *cli.Context) error { + return ruleTable(rulePath, all) + }, +} + +func ruleEnable(pathIn string, enables []string) error { + path, err := utils.FixupPathsToHandleHome(pathIn) + if err != nil { + fmt.Println("Path error.") + return err + } + files, err := ioutil.ReadDir(path) + if err != nil { + fmt.Println("Dir read error.") + return err + } + for _, file := range files { + if strings.HasSuffix(file.Name(), ".yml") || strings.HasSuffix(file.Name(), ".yaml") { + fp := filepath.Join(path, file.Name()) + rule, err := parser.RuleParse(fp) + if err != nil { + continue + } + if !rule.Enabled && utils.ContainsSA(enables, rule.Name) { + rule.Enabled = true + err2 := parser.RuleWrite(*rule, fp) + if err2 != nil { + fmt.Println("Rule write error: ", fp) + continue + } + fmt.Println("Enable: ", fp) + } + } + } + return nil +} + + +func ruleDisable(pathIn string, enables []string) error { + path, err := utils.FixupPathsToHandleHome(pathIn) + if err != nil { + fmt.Println("Path error.") + return err + } + files, err := ioutil.ReadDir(path) + if err != nil { + fmt.Println("Dir read error.") + return err + } + for _, file := range files { + if strings.HasSuffix(file.Name(), ".yml") || strings.HasSuffix(file.Name(), ".yaml") { + fp := filepath.Join(path, file.Name()) + rule, err := parser.RuleParse(fp) + if err != nil { + continue + } + if rule.Enabled && utils.ContainsSA(enables, rule.Name) { + rule.Enabled = false + err2 := parser.RuleWrite(*rule, fp) + if err2 != nil { + fmt.Println("Rule write error: ", fp) + continue + } + fmt.Println("Disable: ", fp) + } + } + } + return nil +} + +func ruleIgnoreAddAll(pathIn string, excludePaths []string) error { + path, err := utils.FixupPathsToHandleHome(pathIn) + if err != nil { + fmt.Println("Path error.") + return err + } + files, err := ioutil.ReadDir(path) + if err != nil { + fmt.Println("Dir read error.") + return err + } + for _, file := range files { + if strings.HasSuffix(file.Name(), ".yml") || strings.HasSuffix(file.Name(), ".yaml") { + fp := filepath.Join(path, file.Name()) + rule, err := parser.RuleParse(fp) + if err != nil { + continue + } + rule.IgnorePaths = append(rule.IgnorePaths, excludePaths...) + err2 := parser.RuleWrite(*rule, fp) + if err2 != nil { + fmt.Println("Rule write error: ", fp) + continue + } + } + } + return nil +} + +func ruleIgnoreRemoveAll(pathIn string, excludePaths []string) error { + path, err := utils.FixupPathsToHandleHome(pathIn) + if err != nil { + fmt.Println("Path error.") + return err + } + files, err := ioutil.ReadDir(path) + if err != nil { + fmt.Println("Dir read error.") + return err + } + for _, file := range files { + if strings.HasSuffix(file.Name(), ".yml") || strings.HasSuffix(file.Name(), ".yaml") { + fp := filepath.Join(path, file.Name()) + rule, err := parser.RuleParse(fp) + if err != nil { + continue + } + for _, n := range excludePaths { + rule.IgnorePaths = utils.Filter(rule.IgnorePaths, func(s string) bool {return s == n}) + } + err2 := parser.RuleWrite(*rule, fp) + if err2 != nil { + fmt.Println("Rule write error: ", fp) + continue + } + } + } + return nil +} + +func ruleTable(path string, all bool) error { + list, err := parser.ParseRulesFromDir(path) + if err != nil { + return err + } + fmt.Println("Enabled rules:") + writeRules(list.Enabled) + if all { + fmt.Println("Disabled rules:") + writeRules(list.Disabled) + } + if all { + fmt.Println("Errors:") + writeErrorRules(list.FileErrors) + } + if all { + fmt.Println("Type parse errors:") + writeTypeErrorRules(list.TypeErrors) + } + return nil +} + +func writeErrorRules(paths []string) { + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"nonparseable files"}) + table.SetBorder(false) + + for _, row := range paths { + table.Append([]string{row}) + } + + table.SetAutoMergeCells(false) + table.Render() +} + +func writeTypeErrorRules(tes map[string]parser.Rule) { + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"path", "name", "type"}) + table.SetBorder(false) + + for k, v := range tes { + table.Append([]string{k, v.Name, v.RuleType}) + } + + table.SetAutoMergeCells(false) + table.Render() +} + +func writeRules(tes map[string]parser.Rule) { + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"path", "name", "type", "search", "ignore"}) + table.SetBorder(false) + + for k, v := range tes { + table.Append([]string{k, v.Name, v.RuleType, strings.Join(v.SearchPaths, ", "), strings.Join(v.IgnorePaths, ", ")}) + } + + table.SetAutoMergeCells(false) + table.Render() +} diff --git a/pkg/cli-utils/run-command.go b/pkg/cli-utils/run-command.go new file mode 100644 index 0000000..3067724 --- /dev/null +++ b/pkg/cli-utils/run-command.go @@ -0,0 +1,42 @@ +package cli_utils + +import ( + "fmt" + "github.com/tg44/heptapod/pkg" + "github.com/tg44/heptapod/pkg/tmutil" + "github.com/urfave/cli/v2" + "log" + "strings" +) + +var dry bool + +var RunCommand = &cli.Command{ + Name: "run", + Aliases: []string{}, + Usage: "run the exclude detection, and also exclude the dirs", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "dry", + Aliases: []string{"d"}, + Value: false, + Usage: "only prints the paths we should exclude (if exists)", + Destination: &dry, + }, + }, + Action: func(c *cli.Context) error { + if dry { + res := pkg.GetExcludedPaths(rulePath, par, buffer, verbose) + fmt.Println("-----") + fmt.Print(strings.Join(res, "\r\n")) + fmt.Print("\n") + } else { + res := pkg.GetExcludedPaths(rulePath, par, buffer, verbose) + tmutil.AddPathsToTM(res, logDir, buffer, verbose) + if verbose { + log.Printf("total %d paths found\n", len(res)) + } + } + return nil + }, +} diff --git a/pkg/cli-utils/tm-command.go b/pkg/cli-utils/tm-command.go new file mode 100644 index 0000000..7480c4b --- /dev/null +++ b/pkg/cli-utils/tm-command.go @@ -0,0 +1,77 @@ +package cli_utils + +import ( + "fmt" + "github.com/tg44/heptapod/pkg" + "github.com/tg44/heptapod/pkg/tmutil" + "github.com/urfave/cli/v2" + "log" +) + +var file string +var all bool +var current bool + +var TmCommands = &cli.Command{ + Name: "timeMachine", + Aliases: []string{"tm"}, + Usage: "timeMachine related functions", + Subcommands: []*cli.Command{ + TmListExcluded, + TmPrune, + }, +} + +var TmListExcluded = &cli.Command{ +Name: "excluded", +Aliases: []string{"ls"}, +Usage: "lists all the excluded dirs from tmutil", +Flags: []cli.Flag{}, +Action: func(c *cli.Context) error { + res := tmutil.GetExcludeList() + fmt.Println(res) + return nil +}, +} + +var TmPrune = &cli.Command{ + Name: "prune", + Aliases: []string{}, + Usage: "removes excludes from TM", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Aliases: []string{"a"}, + Value: false, + Usage: "remove all previously added exclude paths from the log dir", + Destination: &all, + }, + &cli.StringFlag{ + Name: "file", + Aliases: []string{"f"}, + Value: "", + Usage: "remove previously added exclude paths from the file in the log dir", + Destination: &file, + }, + &cli.BoolFlag{ + Name: "run", + Aliases: []string{"r"}, + Value: false, + Usage: "remove previously added exclude paths based on the current rules", + Destination: ¤t, + }, + }, + Action: func(c *cli.Context) error { + if current { + res := pkg.GetExcludedPaths(rulePath, par, buffer, verbose) + tmutil.RemovePathsFromTM(res, buffer, verbose) + } else if all { + tmutil.RemoveAllFromLogs(logDir, buffer, verbose) + } else if file != "" { + tmutil.RemoveFileFromLogs(logDir, file, buffer, verbose) + } else { + log.Fatal("one of the options is mandatory, please add current, all, or a file") + } + return nil + }, +} diff --git a/pkg/cli-utils/version-command.go b/pkg/cli-utils/version-command.go new file mode 100644 index 0000000..476f280 --- /dev/null +++ b/pkg/cli-utils/version-command.go @@ -0,0 +1,33 @@ +package cli_utils + +import ( + "fmt" + "github.com/urfave/cli/v2" +) + +func VersionCommand(version string, commit string, date string) *cli.Command { + return &cli.Command{ + Name: "version", + Aliases: []string{"v"}, + Usage: "version info", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "verbose", + Aliases: []string{"v"}, + Value: false, + Usage: "more detaild version info", + Destination: &verbose, + }, + }, + Action: func(c *cli.Context) error { + if verbose { + fmt.Println("version: ", version) + fmt.Println("commit: ", commit) + fmt.Println("date: ", date) + } else { + fmt.Println(version) + } + return nil + }, + } +} diff --git a/pkg/parser/file-trigger_test.go b/pkg/parser/file-trigger_test.go index 3f6dfc5..6b5442b 100644 --- a/pkg/parser/file-trigger_test.go +++ b/pkg/parser/file-trigger_test.go @@ -3,7 +3,7 @@ package parser import "testing" func TestFileTriggerSettingsParse(t *testing.T) { - rule, err := ruleParse("../../test-rules/git.yaml") + rule, err := RuleParse("../../test-rules/git.yaml") if err != nil { t.Errorf("Rule parser can't parse testRule!") } diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index 16e2d39..6bba5f6 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -44,7 +44,7 @@ func ParseRulesFromDir(pathIn string) (*RuleGroups, error) { for _, file := range files { if strings.HasSuffix(file.Name(), ".yml") || strings.HasSuffix(file.Name(), ".yaml") { fp := filepath.Join(path, file.Name()) - rule, err := ruleParse(fp) + rule, err := RuleParse(fp) if err != nil { errors = append(errors, file.Name()) continue @@ -73,7 +73,7 @@ func Parse(ruleFiles []string) []walker.WalkJob { } func parse(ruleFile string) []walker.WalkJob { - rule, err := ruleParse(ruleFile) + rule, err := RuleParse(ruleFile) if err != nil { log.Println(err) return []walker.WalkJob{} diff --git a/pkg/parser/rule.go b/pkg/parser/rule.go index 48cba9b..9d6fbb1 100644 --- a/pkg/parser/rule.go +++ b/pkg/parser/rule.go @@ -1,6 +1,7 @@ package parser import ( + "github.com/tg44/heptapod/pkg/utils" "gopkg.in/yaml.v2" "io/ioutil" ) @@ -14,7 +15,7 @@ type Rule struct { RuleSettings map[string]interface{} `yaml:"ruleSettings"` } -func ruleParse(fileName string) (*Rule, error) { +func RuleParse(fileName string) (*Rule, error) { yfile, err := ioutil.ReadFile(fileName) if err != nil { @@ -31,3 +32,18 @@ func ruleParse(fileName string) (*Rule, error) { return &rule, nil } + +func RuleWrite(rule Rule, file string) error { + + rule.IgnorePaths = utils.Unique(rule.IgnorePaths) + data, err := yaml.Marshal(&rule) + if err != nil { + return err + } + + err2 := ioutil.WriteFile(file, data, 0) + if err2 != nil { + return err2 + } + return nil +} diff --git a/pkg/parser/rule_test.go b/pkg/parser/rule_test.go index ff0f63d..c91b660 100644 --- a/pkg/parser/rule_test.go +++ b/pkg/parser/rule_test.go @@ -5,7 +5,7 @@ import ( ) func TestRuleParse(t *testing.T) { - res, err := ruleParse("../../test-rules/git.yaml") + res, err := RuleParse("../../test-rules/git.yaml") //t.Log(res) if err != nil { t.Errorf("Rule parser can't parse testRule!") diff --git a/pkg/utils/array-utils.go b/pkg/utils/array-utils.go index ce39d4c..a596c02 100644 --- a/pkg/utils/array-utils.go +++ b/pkg/utils/array-utils.go @@ -19,3 +19,29 @@ func ContainsSA(a []string, s string) bool { } return false } + +func Unique(arr []string) []string { + keys := make(map[string]bool) + list := []string{} + for _, entry := range arr { + if _, value := keys[entry]; !value { + keys[entry] = true + list = append(list, entry) + } + } + return list +} + +//based on https://stackoverflow.com/a/48123201 +func Filter(arr []string, f func(string)bool) []string { + j := 0 + q := make([]string, len(arr)) + for _, n := range arr { + if f(n) { + q[j] = n + j++ + } + } + q = q[:j] + return q +} diff --git a/pkg/walker/walker.go b/pkg/walker/walker.go index 9485f19..9696bef 100644 --- a/pkg/walker/walker.go +++ b/pkg/walker/walker.go @@ -78,6 +78,11 @@ func walk(runnerId int, rootpath string, walkers []Walker, alreadyFiltered []str path, err := utils.FixupPathsToHandleHome(rootpath) if err != nil { end <- []string{} + return + } + if len(walkers) == 0 { + end <- []string{} + return } l := &utils.List{path, nil} for hasNext { @@ -85,14 +90,14 @@ func walk(runnerId int, rootpath string, walkers []Walker, alreadyFiltered []str files, err := ioutil.ReadDir(l.Data) if err != nil { if (verbose) { - fmt.Println("!!! There was an error reading ", l.Data, " - ", err.Error()) + fmt.Println("!!! There was an error: ", err.Error()) } if next == nil { hasNext = false } else { l = next } - break + continue } ignores := []WalkerIgnores{}