mirror of
https://github.com/offen/docker-volume-backup.git
synced 2024-11-24 22:20:28 +01:00
Use proper path expansion
This commit is contained in:
parent
4b3ca2ebb0
commit
060a6daa7a
21
.github/workflows/unit.yml
vendored
Normal file
21
.github/workflows/unit.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: Run Unit Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: '1.22.x'
|
||||||
|
- name: Install dependencies
|
||||||
|
run: go mod download
|
||||||
|
- name: Test with the Go CLI
|
||||||
|
run: go test -v ./...
|
@ -4,6 +4,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -11,6 +12,7 @@ import (
|
|||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"github.com/offen/docker-volume-backup/internal/errwrap"
|
"github.com/offen/docker-volume-backup/internal/errwrap"
|
||||||
"github.com/offen/envconfig"
|
"github.com/offen/envconfig"
|
||||||
|
shell "mvdan.cc/sh/v3/shell"
|
||||||
)
|
)
|
||||||
|
|
||||||
type configStrategy string
|
type configStrategy string
|
||||||
@ -99,11 +101,7 @@ func loadConfigsFromEnvFiles(directory string) ([]*Config, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p := filepath.Join(directory, item.Name())
|
p := filepath.Join(directory, item.Name())
|
||||||
f, err := os.ReadFile(p)
|
envFile, err := source(p)
|
||||||
if err != nil {
|
|
||||||
return nil, errwrap.Wrap(err, fmt.Sprintf("error reading %s", item.Name()))
|
|
||||||
}
|
|
||||||
envFile, err := godotenv.Unmarshal(os.ExpandEnv(string(f)))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errwrap.Wrap(err, fmt.Sprintf("error reading config file %s", p))
|
return nil, errwrap.Wrap(err, fmt.Sprintf("error reading config file %s", p))
|
||||||
}
|
}
|
||||||
@ -125,3 +123,39 @@ func loadConfigsFromEnvFiles(directory string) ([]*Config, error) {
|
|||||||
|
|
||||||
return configs, nil
|
return configs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// source tries to mimic the pre v2.37.0 behavior of calling
|
||||||
|
// `set +a; source $path; set -a` and returns the env vars as a map
|
||||||
|
func source(path string) (map[string]string, error) {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrap(err, fmt.Sprintf("error opening %s", path))
|
||||||
|
}
|
||||||
|
|
||||||
|
result := map[string]string{}
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
withExpansion, err := shell.Expand(line, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrap(err, "error expanding env")
|
||||||
|
}
|
||||||
|
m, err := godotenv.Unmarshal(withExpansion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrap(err, fmt.Sprintf("error sourcing %s", path))
|
||||||
|
}
|
||||||
|
for key, value := range m {
|
||||||
|
currentValue, currentOk := os.LookupEnv(key)
|
||||||
|
defer func() {
|
||||||
|
if currentOk {
|
||||||
|
os.Setenv(key, currentValue)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.Unsetenv(key)
|
||||||
|
}()
|
||||||
|
result[key] = value
|
||||||
|
os.Setenv(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
68
cmd/backup/config_provider_test.go
Normal file
68
cmd/backup/config_provider_test.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSource(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
expectError bool
|
||||||
|
expectedOutput map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"default",
|
||||||
|
"testdata/default.env",
|
||||||
|
false,
|
||||||
|
map[string]string{
|
||||||
|
"FOO": "bar",
|
||||||
|
"BAZ": "qux",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"not found",
|
||||||
|
"testdata/nope.env",
|
||||||
|
true,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"braces",
|
||||||
|
"testdata/braces.env",
|
||||||
|
false,
|
||||||
|
map[string]string{
|
||||||
|
"FOO": "qux",
|
||||||
|
"BAR": "xxx",
|
||||||
|
"BAZ": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expansion",
|
||||||
|
"testdata/expansion.env",
|
||||||
|
false,
|
||||||
|
map[string]string{
|
||||||
|
"BAR": "xxx",
|
||||||
|
"FOO": "xxx",
|
||||||
|
"BAZ": "xxx",
|
||||||
|
"QUX": "yyy",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Setenv("QUX", "yyy")
|
||||||
|
defer os.Unsetenv("QUX")
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
result, err := source(test.input)
|
||||||
|
if (err != nil) != test.expectError {
|
||||||
|
t.Errorf("Unexpected error value %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(test.expectedOutput, result) {
|
||||||
|
t.Errorf("Expected %v, got %v", test.expectedOutput, result)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
3
cmd/backup/testdata/braces.env
vendored
Normal file
3
cmd/backup/testdata/braces.env
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
FOO=${bar:-qux}
|
||||||
|
BAR=xxx
|
||||||
|
BAZ=$NOPE
|
2
cmd/backup/testdata/default.env
vendored
Normal file
2
cmd/backup/testdata/default.env
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
FOO=bar
|
||||||
|
BAZ=qux
|
4
cmd/backup/testdata/expansion.env
vendored
Normal file
4
cmd/backup/testdata/expansion.env
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
BAR=xxx
|
||||||
|
FOO=${BAR}
|
||||||
|
BAZ=$BAR
|
||||||
|
QUX=${QUX}
|
1
go.mod
1
go.mod
@ -32,6 +32,7 @@ require (
|
|||||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/protobuf v1.31.0 // indirect
|
||||||
|
mvdan.cc/sh/v3 v3.8.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
2
go.sum
2
go.sum
@ -1259,6 +1259,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
|
mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8=
|
||||||
|
mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
NAME="other"
|
NAME="other"
|
||||||
BACKUP_CRON_EXPRESSION="*/1 * * * *"
|
BACKUP_CRON_EXPRESSION="*/1 * * * *"
|
||||||
|
BACKUP_FILENAME="override-$NAME.tar.gz"
|
||||||
|
@ -20,7 +20,7 @@ if [ ! -f "$LOCAL_DIR/conf.tar.gz" ]; then
|
|||||||
fi
|
fi
|
||||||
pass "Config from file was used."
|
pass "Config from file was used."
|
||||||
|
|
||||||
if [ ! -f "$LOCAL_DIR/other.tar.gz" ]; then
|
if [ ! -f "$LOCAL_DIR/override-other.tar.gz" ]; then
|
||||||
fail "Run on same schedule did not succeed."
|
fail "Run on same schedule did not succeed."
|
||||||
fi
|
fi
|
||||||
pass "Run on same schedule succeeded."
|
pass "Run on same schedule succeeded."
|
||||||
|
Loading…
Reference in New Issue
Block a user