package main import ( "fmt" "net/url" "os" "path/filepath" "github.com/antonmedv/expr" "github.com/hashicorp/hcl/v2/hclsimple" ) func fileExists(path string) bool { if _, err := os.Stat(path); os.IsNotExist(err) { return false } return true } // Config is the full set of configuration required type Config struct { DefaultBrowserCommand []string `hcl:"default_browser_cmd"` Rules []BrowserRuleConfig `hcl:"rule,block"` } // BrowserRuleConfig represents a BrowserRule type BrowserRuleConfig struct { Name string `hcl:"name,label"` BrowserCommand []string `hcl:"browser_cmd"` MatchExpr string `hcl:"match"` } func MakeMatchFunc(rule string) MatchFunc { return func(dest url.URL) bool { env := map[string]interface{}{ // Prebuilt match functions "matchAny": matchAny, "matchHostRegexp": matchHostRegexp, "matchHostname": matchHostname, "matchNever": matchNever, "matchRegexp": matchRegexp, // Helpers for building custom matchers "MatchFunc": func(foundMatch bool) MatchFunc { return func(_ url.URL) bool { return foundMatch } }, "fullUrl": dest.String(), "hostname": dest.Hostname(), "url": dest, } matchFuncExpr, err := expr.Eval(rule, env) if err != nil { fmt.Printf("Error evaluating rule %s: %v", rule, err) return false } matchFunc, ok := matchFuncExpr.(MatchFunc) if !ok { fmt.Printf("Error evaluating rule %s. Did not evaluate to a MatchFunc.", rule) return false } return matchFunc(dest) } } func LoadConfig(path string) ([]BrowserRule, error) { rules := []BrowserRule{} var config Config err := hclsimple.DecodeFile(path, nil, &config) if err != nil { return nil, err } for _, rule := range config.Rules { rules = append(rules, BrowserRule{ command: rule.BrowserCommand[0], args: rule.BrowserCommand[1:], matcher: MakeMatchFunc(rule.MatchExpr), }) } // Add default browser rule to the end rules = append(rules, BrowserRule{ command: config.DefaultBrowserCommand[0], args: config.DefaultBrowserCommand[1:], matcher: defaultBrowser, }) return rules, nil } func DefaultConfigPath() (string, error) { appName := "browser-ruler" // Check XDG_CONFIG_HOME dir, err := os.UserConfigDir() if err == nil { configPath := filepath.Join(dir, appName, "config.hcl") if fileExists(configPath) { return configPath, nil } } dir, err = os.UserHomeDir() if err != nil { return "", fmt.Errorf("Could not find a config dir or home dir to look for config file. Specify one with -config: %w", err) } configPath := filepath.Join(dir, "."+appName+".hcl") if fileExists(configPath) { return configPath, nil } return "", fmt.Errorf("no config file found in config dir or home dir") }