Eliminates command-line args, and drives from rules file.
2 files changed, 69 insertions(+), 37 deletions(-)

M main.go
M rules.json
M main.go +64 -35
@@ 1,31 1,38 @@ 
 package main
 
 import (
+	"encoding/json"
 	"flag"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"os"
 	"os/exec"
 	"os/signal"
-	"strings"
+	"regexp"
 	"syscall"
 
 	"github.com/pilebones/go-udev/netlink"
 )
 
+var Version string
+
 func main() {
-	var devices Strings
-	flag.Var(&devices, "d", "One (or more) regular expressions matching device names to watch for")
 	help := flag.Bool("h", false, "Print help and exit")
+	version := flag.Bool("v", false, "Print version and exit")
 	flag.Parse()
-	if len(devices) < 1 || flag.NArg() < 1 {
+	if *version {
+		fmt.Println(Version)
+		os.Exit(0)
+	}
+	if flag.NArg() < 1 {
 		flag.PrintDefaults()
-		fmt.Printf("Remaining arguments is the command to run.")
+		fmt.Printf("The only argument is the path to the rules file.")
 		os.Exit(1)
 	}
 	if *help {
 		flag.PrintDefaults()
-		fmt.Printf("Remaining arguments is the command to run.")
+		fmt.Printf("The only argument is the path to the rules file.")
 		os.Exit(0)
 	}
 	conn := new(netlink.UEventConn)

          
@@ 37,17 44,12 @@ func main() {
 	queue := make(chan netlink.UEvent)
 	errors := make(chan error)
 	matcher := new(netlink.RuleDefinitions)
-	add := "add"
-	for _, d := range devices {
-		log.Printf("Adding rule for %s", d)
-		matcher.AddRule(netlink.RuleDefinition{
-			Action: &add,
-			Env: map[string]string{
-				"ACTION":    "add",
-				"SUBSYSTEM": "input",
-				"NAME":      ".*Goldtouch.*Keyboard.*",
-			},
-		})
+	rules, err := ioutil.ReadFile(flag.Arg(0))
+	if err != nil {
+		panic(err)
+	}
+	if err := json.Unmarshal(rules, &matcher); err != nil {
+		log.Fatalf("Wrong rule syntax in \"%s\", err: %s", flag.Arg(0), err.Error())
 	}
 	quit := conn.Monitor(queue, errors, matcher)
 	// Signal handler to quit properly monitor mode

          
@@ 60,22 62,30 @@ func main() {
 		os.Exit(0)
 	}()
 
+	var ruleset Ruleset
+	if err := json.Unmarshal(rules, &ruleset); err != nil {
+		log.Fatalf("Wrong rule syntax in \"%s\", err: %s", flag.Arg(0), err.Error())
+	}
 	// Handling message from queue
-	log.Printf("monitoring for connection events")
+	log.Printf("monitoring for connection events for %d rules", len(ruleset.Rules))
 	for {
 		select {
 		case evt := <-queue:
-			var cmd *exec.Cmd
-			if flag.NArg() > 1 {
-				args := flag.Args()
-				cmd = exec.Command(args[0], args[1:]...)
-			} else {
-				cmd = exec.Command(flag.Args()[0])
-			}
-			log.Printf("%s: %s\n", evt.Env["NAME"], strings.Join(flag.Args(), " "))
-			err := cmd.Run()
-			if err != nil {
-				panic(err)
+			rule := ruleset.MatchRule(evt)
+			if rule != nil {
+				var cmd *exec.Cmd
+				for _, cx := range rule.Run {
+					if flag.NArg() > 1 {
+						cmd = exec.Command(cx[0], cx[1:]...)
+					} else {
+						cmd = exec.Command(cx[0])
+					}
+					log.Printf("%s: %v\n", evt.Env["NAME"], cx)
+					err := cmd.Run()
+					if err != nil {
+						panic(err)
+					}
+				}
 			}
 		case err := <-errors:
 			log.Printf("ERROR: %v", err)

          
@@ 83,12 93,31 @@ func main() {
 	}
 }
 
-type Strings []string
+type Ruleset struct {
+	Rules []Rule
+}
+type Rule struct {
+	Action string
+	Env    map[string]string
+	Run    [][]string
+}
 
-func (s *Strings) String() string {
-	return "strings"
-}
-func (s *Strings) Set(v string) error {
-	*s = append(*s, v)
+// Return first matching rule
+func (rs Ruleset) MatchRule(e netlink.UEvent) *Rule {
+	for _, rule := range rs.Rules {
+		if rule.Action == e.Action.String() {
+			var match bool = true
+			for rk, rv := range rule.Env {
+				re := regexp.MustCompile(rv)
+				if !re.Match([]byte(e.Env[rk])) {
+					match = false
+					break
+				}
+			}
+			if match {
+				return &rule
+			}
+		}
+	}
 	return nil
 }

          
M rules.json +5 -2
@@ 5,8 5,11 @@ 
 			"env": {
 				"ACTION": "add",
 				"SUBSYSTEM": "input",
-				"NAME": ".*Goldtouch.*Keyboard.*"
-			}
+				"NAME": ".*Goldtouch.*Keyboard.*System Control"
+			},
+			"run": [
+				["setxkbmap", "-layout","us","-variant","dvorak","-geometry","kinesis","-option","caps:super","-option","compose:lwin"]
+			]
 		}
 	]
 }