diff options
author | Victor Häggqvist <[email protected]> | 2022-09-14 23:47:31 +0200 |
---|---|---|
committer | Victor Häggqvist <[email protected]> | 2022-09-14 23:47:31 +0200 |
commit | 4e0fb944f18411381366e620ef5193f886957b6f (patch) | |
tree | fe64f7b10af9b9e7ad25d96a3a386a3079d84680 /main.go | |
parent | ca4f546cc3189d2635bd42d74be4332dd35761fe (diff) |
rename main.go
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 264 |
1 files changed, 264 insertions, 0 deletions
@@ -0,0 +1,264 @@ +package main + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "os/user" + "path/filepath" + "runtime" + "sort" + "strings" + + "github.com/gocarina/gocsv" + flag "github.com/spf13/pflag" + "gopkg.in/yaml.v2" +) + +var version = "0.0.0" // injected at build time + +type Runnable struct { + Cmd string `csv:"name"` + Count int `csv:"count"` +} + +type Config struct { + DmenuParams string `yaml:"dmenu_params"` + Ignore []string `yaml:"ignore,flow"` +} + +type CmdList []*Runnable + +func (c CmdList) Len() int { + return len(c) +} + +func (c CmdList) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +func (c CmdList) Less(i, j int) bool { + return c[i].Count > c[j].Count +} + +var ( + prePhase bool + postPhase bool + launcher bool + stats bool + gc bool + dbFilePath string + config Config +) + +func isInIgnoreList(item string) bool { + for _, i := range config.Ignore { + if i == item { + return true + } + } + return false +} + +func addIfNotContains(items []string, item string) []string { + for _, i := range items { + if i == item { + return items + } + } + return append(items, item) +} + +func openDB() map[string]int { + if _, err := os.Stat(dbFilePath); err != nil { + return make(map[string]int) + } + + list := CmdList{} + file, _ := os.Open(dbFilePath) + if err := gocsv.UnmarshalFile(file, &list); err != nil { + panic(err) + } + + itemSet := make(map[string]int) + for _, item := range list { + itemSet[item.Cmd] = item.Count + } + return itemSet +} + +func generatePath() []string { + sysPath := os.Getenv("PATH") + paths := strings.Split(sysPath, ":") + + pathItems := sort.StringSlice{} + + for _, p := range paths { + if _, err := os.Stat(p); err == nil { + files, _ := ioutil.ReadDir(p) + for _, f := range files { + if !isInIgnoreList(f.Name()) { + pathItems = addIfNotContains(pathItems, f.Name()) + } + } + } + } + + sort.Sort(pathItems) + return pathItems +} + +func rankPath(pathItems []string) CmdList { + itemSet := openDB() + + rankedItems := CmdList{} + for _, item := range pathItems { + count, exists := itemSet[item] + if !exists { + count = 0 + } + rankedItems = append(rankedItems, &Runnable{item, count}) + } + + sort.Sort(rankedItems) + return rankedItems +} + +func loadIni() { + usr, _ := user.Current() + configPath := filepath.Join(usr.HomeDir, ".goboom") + iniFile := filepath.Join(configPath, "config.yaml") + dbFilePath = filepath.Join(configPath, "rankdb.csv") + + if _, err := os.Stat(configPath); err != nil { + err := os.Mkdir(configPath, os.ModePerm) + if err != nil { + fmt.Println("failed to create config dir") + } + } + + config = Config{ + DmenuParams: "-b -i -nb black -nf orange -sb black -p \">\"", + Ignore: []string{"X", "su"}, + } + + if _, err := os.Stat(iniFile); err != nil { + buff, err := yaml.Marshal(config) + if err != nil { + panic(err) + } + if err := ioutil.WriteFile(iniFile, buff, 0644); err != nil { + panic(err) + } + } else { + buff, err := ioutil.ReadFile(iniFile) + if err != nil { + panic(err) + } + if err := yaml.Unmarshal(buff, &config); err != nil { + panic(err) + } + } +} + +func updateRank(runnable string) { + itemSet := openDB() + + count, exists := itemSet[runnable] + if !exists { + itemSet[runnable] = 1 + } else { + itemSet[runnable] = count + 1 + } + + writeDB(itemSet) +} + +func writeDB(itemSet map[string]int) { + items := CmdList{} + for runnable, count := range itemSet { + items = append(items, &Runnable{runnable, count}) + } + + file, err := os.OpenFile(dbFilePath, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) + if err != nil { + panic(err) + } + if err = gocsv.MarshalFile(&items, file); err != nil { + panic(err) + } +} + +func displayStats() { + items := openDB() + + sortedList := CmdList{} + for runnable, count := range items { + sortedList = append(sortedList, &Runnable{runnable, count}) + } + + sort.Sort(sortedList) + + fmt.Println("Name\tLaunch count") + for _, i := range sortedList { + fmt.Printf("%s\t%d\n", i.Cmd, i.Count) + } +} + +func runGC() int { + items := openDB() + + cleanItems := make(map[string]int) + removedCount := 0 + + for runnable, count := range items { + if count > 1 { + cleanItems[runnable] = count + } else { + removedCount = removedCount + 1 + } + } + + writeDB(cleanItems) + return removedCount +} + +func main() { + flag.BoolVar(&prePhase, "pre", false, "Generate dmenu in") + flag.BoolVar(&launcher, "launcher", false, "Output launcher command") + flag.BoolVar(&postPhase, "post", false, "Update ranking DB") + flag.BoolVar(&stats, "stats", false, "View DB stats") + flag.BoolVar(&gc, "gc", false, "Run garbage collection of the DB") + flag.Usage = func() { + fmt.Println(version + " " + runtime.Version()) + fmt.Print("\nTo actually use goboom execute goboom_run\n\n") + fmt.Println("Options: ") + flag.PrintDefaults() + } + flag.Parse() + + loadIni() + + if prePhase { + pathList := generatePath() + sortedList := rankPath(pathList) + for _, item := range sortedList { + fmt.Println(item.Cmd) + } + } else if postPhase { + scanner := bufio.NewScanner(os.Stdin) + scanner.Scan() + input := scanner.Text() + updateRank(input) + fmt.Print(input) + } else if launcher { + fmt.Print("dmenu " + config.DmenuParams) + } else if stats { + displayStats() + } else if gc { + fmt.Printf("Removed %d items\n", runGC()) + } else { + flag.Usage() + } +} |