diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | apply.go | 77 | ||||
| -rw-r--r-- | go.mod | 5 | ||||
| -rw-r--r-- | go.sum | 2 | ||||
| -rw-r--r-- | main.go | 28 | ||||
| -rw-r--r-- | template.go | 54 | 
6 files changed, 167 insertions, 0 deletions
| diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..32814ee --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +conf diff --git a/apply.go b/apply.go new file mode 100644 index 0000000..7ea5bf9 --- /dev/null +++ b/apply.go @@ -0,0 +1,77 @@ +package main + +import ( +	"fmt" +	"os" +	"path/filepath" +	"text/template" +) + +func apply(args []string) error { +	if len(args) != 0 { +		return applyFiles(args) +	} +	names, err := getFileNames() +	if err != nil { +		return err +	} +	return applyFiles(names) +} + +func applyFiles(names []string) error { +	for _, name := range names { +		fmt.Printf("applying %s\n", name) +		if err := applyFile(name); err != nil { +			return fmt.Errorf("could not apply %s: %v", name, err) +		} +	} +	return nil +} + +func applyFile(name string) error { +	src := filepath.Join(base, "templates", name) +	t, err := template.New(filepath.Base(name)).Funcs(buildFuncMap()).ParseFiles(src) +	if err != nil { +		return fmt.Errorf("could not build template: %v", err) +	} +	data, err := getTemplateData() +	if err != nil { +		return err +	} +	d := filepath.Join(dest, name) +	if err = os.MkdirAll(filepath.Dir(d), 0700); err != nil { +		return err +	} +	out, err := os.OpenFile(d, os.O_CREATE|os.O_WRONLY, 0600) +	if err != nil { +		return err +	} +	defer out.Close() +	if err = t.Execute(out, data); err != nil { +		return fmt.Errorf("could not execute template: %v", err) +	} +	return nil +} + +func getFileNames() ([]string, error) { +	var names []string +	d := filepath.Join(base, "templates") +	err := filepath.Walk(d, func(path string, info os.FileInfo, err error) error { +		if err != nil { +			return err +		} +		if info.IsDir() { +			return nil +		} +		name, err := filepath.Rel(d, path) +		if err != nil { +			return err +		} +		names = append(names, name) +		return nil +	}) +	if err != nil { +		return nil, err +	} +	return names, nil +} @@ -0,0 +1,5 @@ +module git.sr.ht/~benburwell/conf + +go 1.12 + +require github.com/BurntSushi/toml v0.3.1 @@ -0,0 +1,2 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -0,0 +1,28 @@ +package main + +import ( +	"fmt" +	"os" +) + +const ( +	base = "/Users/ben/dotfiles" +	dest = "/Users/ben" +) + +func main() { +	if len(os.Args) < 2 { +		fmt.Printf("usage: conf apply [files...]\n") +		os.Exit(1) +	} +	switch os.Args[1] { +	case "apply": +		if err := apply(os.Args[2:]); err != nil { +			fmt.Printf("%v\n", err) +			os.Exit(1) +		} +	default: +		fmt.Printf("unrecognized command: %s\n", os.Args[1]) +		os.Exit(1) +	} +} diff --git a/template.go b/template.go new file mode 100644 index 0000000..cb6dc2e --- /dev/null +++ b/template.go @@ -0,0 +1,54 @@ +package main + +import ( +	"bytes" +	"os" +	"os/exec" +	"path/filepath" +	"text/template" + +	"github.com/BurntSushi/toml" +) + +type TemplateData struct { +	Hostname string +	Vars     map[string]interface{} +} + +func buildFuncMap() template.FuncMap { +	return map[string]interface{}{ +		"pass": lookupPassword, +		"env":  os.Getenv, +	} +} + +func lookupPassword(name string) (string, error) { +	out, err := exec.Command("pass", name).CombinedOutput() +	if err != nil { +		return "", err +	} +	buf := bytes.NewBuffer(out) +	line, err := buf.ReadBytes('\n') +	if err != nil { +		return "", err +	} +	return string(line), nil +} + +func getTemplateData() (*TemplateData, error) { +	var data TemplateData +	vars, err := readVars() +	if err != nil { +		return nil, err +	} +	data.Vars = vars +	return &data, nil +} + +func readVars() (map[string]interface{}, error) { +	var vars map[string]interface{} +	if _, err := toml.DecodeFile(filepath.Join(base, "vars.toml"), &vars); err != nil { +		return nil, err +	} +	return vars, nil +} | 
