browser-ruler/config.go

119 lines
2.7 KiB
Go

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")
}