Skip to content

Commit

Permalink
feat: add templating to copy mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
gszr committed Mar 3, 2024
1 parent b3fa7a4 commit 157ed32
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 5 deletions.
50 changes: 50 additions & 0 deletions dot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"gopkg.in/yaml.v3"
"os"
"testing"
"runtime"
)

func isSymlink(path string) bool {
Expand Down Expand Up @@ -72,6 +73,27 @@ func TestDoCopy(t *testing.T) {
toContents, err = os.ReadFile(m.To)
assert.Nil(t, err)
assert.Equal(t, fromContents, toContents)

// copies a file with template
m = FileMapping{
From: "fixtures/gpg-agent.conf.input",
To: "out/gpg-agent.conf",
With: map[string]string {
"PinentryPath": "/foo/bar",
},
}

err = m.doCopy()
assert.Nil(t, err)
assert.False(t, isSymlink(m.To))

// correct contents

fromContents, err = os.ReadFile("fixtures/gpg-agent.conf.output")
assert.Nil(t, err)
toContents, err = os.ReadFile(m.To)
assert.Nil(t, err)
assert.Equal(t, fromContents, toContents)
}

func TestUnmap(t *testing.T) {
Expand Down Expand Up @@ -341,3 +363,31 @@ func TestGetHomeDir(t *testing.T) {
assert.Equal(t, got, want)
}
}

func TestEvalTemplateString(t *testing.T) {
cases := map[string]string {
"{{ .v1 }}": "a value",
"{{ .v2 }}": "<no value>",
}
env := map[string]string {
"v1": "a value",
}
for templ, want := range cases {
got := evalTemplateString(templ, env)
assert.Equal(t, want, got)
}
}

func TestEvalTemplate(t *testing.T) {
curOs := runtime.GOOS
with := map[string]string {
"t1": "{{if eq .Os \"" + curOs + "\"}}it works{{end}}",
"t2": "{{if eq .Os \"linux\"}}must not be this{{end}}",
"t3": "{{if eq .Os \"linux\"}}must not be this{{else}}else{{end}}",
}

res := evalTemplate(with)
assert.Equal(t, "it works", res["t1"])
assert.Equal(t, "", res["t2"], "")
assert.Equal(t, "else", res["t3"])
}
20 changes: 20 additions & 0 deletions examples/04-dots-copy-templating.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# to, os, as

map:
gitconfig:
to: out/gitconfig
os: all # all, linux, macos
zshrc:
to: out/zshrc
as: copy
os: linux
gpg-agent.conf:
to: out/gpg-agent.conf
as: copy
os: macos
with:
PinentryPath: '{{if eq .Os "darwin"}}/opt/homebrew/bin{{else}}/usr/bin{{end}}'

opt:
cd: examples/

4 changes: 4 additions & 0 deletions examples/gpg-agent.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default-cache-ttl 1800
max-cache-ttl 3600
enable-ssh-support
pinentry-program {{ .PinentryPath }}/pinentry-tty
4 changes: 4 additions & 0 deletions fixtures/gpg-agent.conf.input
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default-cache-ttl 1800
max-cache-ttl 3600
enable-ssh-support
pinentry-program {{ .PinentryPath }}/pinentry-tty
4 changes: 4 additions & 0 deletions fixtures/gpg-agent.conf.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
default-cache-ttl 1800
max-cache-ttl 3600
enable-ssh-support
pinentry-program /foo/bar/pinentry-tty
55 changes: 50 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

goversion "github.com/caarlos0/go-version"
"gopkg.in/yaml.v3"
"text/template"
)

/*
Expand Down Expand Up @@ -81,6 +82,7 @@ type FileMapping struct {
To string
As string
Os string
With map[string]string
}

func (m FileMapping) doLink() error {
Expand All @@ -92,19 +94,32 @@ func (m FileMapping) doLink() error {
}

func (m FileMapping) doCopy() error {
fin, err := os.Open(m.From)
if err != nil {
return err
var inReader io.Reader
if len(m.With) > 0 {
for v, m := range m.With {
logger.Printf("%s %s\n", v, m)
}
in, err := os.ReadFile(m.From)
if err != nil {
panic(err)
}
inReader = strings.NewReader(evalTemplateString(string(in), m.With))
} else {
fin, err := os.Open(m.From)
if err != nil {
return err
}
defer fin.Close()
inReader = fin
}
defer fin.Close()

fout, err := os.Create(m.To)
if err != nil {
return err
}
defer fout.Close()

_, err = io.Copy(fout, fin)
_, err = io.Copy(fout, inReader)
if err != nil {
return err
}
Expand Down Expand Up @@ -196,6 +211,10 @@ func (dots Dots) validate() []error {
} else if isDirectory(mapping.From) && mapping.As == "copy" {
errs = append(errs, fmt.Errorf("%s: cannot use copy type with directory", mapping.From))
}

if mapping.As != "copy" && len(mapping.With) > 0 {
errs = append(errs, fmt.Errorf("%s: templating is only supported in `copy` mode ]", mapping.From));
}
}
return errs
}
Expand All @@ -208,6 +227,28 @@ func inferDestination(file string) string {
}
}

func evalTemplateString(templStr string, env map[string]string) string {
templ, err := template.New("template").Parse(templStr)
if err != nil {
logger.Fatalf("failed creating template from %s, %v", templStr, err)
}
var templOut bytes.Buffer
err = templ.Execute(&templOut, env)
if err != nil {
logger.Fatalf("failed executing template, %v", err)
}
return templOut.String()
}

func evalTemplate(with map[string]string) map[string]string {
newMap := make(map[string]string, len(with))
for variable, templ := range with {
env := map[string]string{ "Os": runtime.GOOS }
newMap[variable] = evalTemplateString(templ, env)
}
return newMap
}

func (dots Dots) transform() Dots {
opts := dots.Opts
mappings := dots.FileMappings
Expand All @@ -226,6 +267,10 @@ func (dots Dots) transform() Dots {
mapping.To = inferDestination(mapping.From)
}

if len(mapping.With) > 0 {
mapping.With = evalTemplate(mapping.With)
}

if len(opts.Cd) > 0 {
// Cd set: add prefix to From
mapping.From = path.Join(opts.Cd, mapping.From)
Expand Down

0 comments on commit 157ed32

Please sign in to comment.