aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Burwell <ben@benburwell.com>2019-08-13 12:24:10 -0400
committerBen Burwell <ben@benburwell.com>2019-08-13 12:51:10 -0400
commit8df0e5aa7d4dc43b1384d91a820c9a748ccbea6b (patch)
tree35c444471794fe82a4d5a036a6174627b5ef61fa
initial commit
-rw-r--r--.gitignore1
-rw-r--r--apply.go77
-rw-r--r--go.mod5
-rw-r--r--go.sum2
-rw-r--r--main.go28
-rw-r--r--template.go54
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
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..5d984d3
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module git.sr.ht/~benburwell/conf
+
+go 1.12
+
+require github.com/BurntSushi/toml v0.3.1
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..9cb2df8
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..27a4abb
--- /dev/null
+++ b/main.go
@@ -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
+}