Commit d8932a2e authored by ale's avatar ale
Browse files

Work around restic issue 3104

This issue prevents "restic init" from understanding the
--repository-file option in restic versions prior to 0.12, so we just
pass the --repo option as is in that case.

Also fixes handling of exclude / exclude_files options.
parent bb885562
Pipeline #24121 failed with stages
in 40 seconds
......@@ -21,23 +21,33 @@ import (
type resticRepository struct {
bin string
uri string
version *version.Version
uri string
tmpDir string
passwordFile string
repositoryFile string
excludes []string
excludeFiles []string
autoPrune bool
cacheMgr cacheManager
cacheMgr cacheManager
initialized sync.Once
}
func (r *resticRepository) resticCmd(cmd string) string {
args := []string{r.bin, cmd}
if r.repositoryFile != "" {
args = append(args, "--repository-file", r.repositoryFile)
// Work around https://github.com/restic/restic/issues/3104
// ("restic init" does not respect --repository-file in Restic
// versions prior to 0.12).
if cmd == "init" && r.version.LessThan(resticFixedIssue3104Version) {
args = append(args, "--repo", r.uri)
} else {
args = append(args, "--repository-file", r.repositoryFile)
}
}
if r.passwordFile != "" {
args = append(args, "--password-file", r.passwordFile)
}
......@@ -58,29 +68,22 @@ func (r *resticRepository) excludeArgs() string {
// We need to check that we're running at least restic 0.9, or the
// restore functionality won't work as expected.
var (
resticVersionRx = regexp.MustCompile(`^restic ([0-9.]+)`)
resticMinGoodVersion = "0.9"
resticVersionRx = regexp.MustCompile(`^restic ([0-9.]+)`)
resticMinGoodVersion = version.Must(version.NewVersion("0.9"))
resticFixedIssue3104Version = version.Must(version.NewVersion("0.12"))
)
func checkResticVersion(bin string) error {
func getResticVersion(bin string) (*version.Version, error) {
output, err := exec.Command(bin, "version").Output() // #nosec
if err != nil {
return err
return nil, err
}
m := resticVersionRx.FindStringSubmatch(string(output))
if len(m) < 2 {
return errors.New("could not parse restic version")
return nil, errors.New("could not parse restic version")
}
v, err := version.NewVersion(m[1])
if err != nil {
return err
}
log.Printf("detected restic version %s", v)
minV, _ := version.NewVersion(resticMinGoodVersion) // nolint
if v.LessThan(minV) {
return fmt.Errorf("restic should be at least version %s (is %s)", minV, v)
}
return nil
return version.NewVersion(m[1])
}
// newResticRepository returns a restic repository.
......@@ -98,9 +101,16 @@ func newResticRepository(params Params) (Repository, error) {
if s := params.Get("restic_binary"); s != "" {
bin = s
}
if err := checkResticVersion(bin); err != nil {
resticVersion, err := getResticVersion(bin)
if err != nil {
return nil, err
}
if resticVersion.LessThan(resticMinGoodVersion) {
return nil, fmt.Errorf(
"restic version %s is older than the minimum supported version %s",
resticVersion, resticMinGoodVersion)
}
log.Printf("detected restic version %s", resticVersion)
// Create a temporary directory and write repository URL and
// password in files therein.
......@@ -129,6 +139,7 @@ func newResticRepository(params Params) (Repository, error) {
return &resticRepository{
bin: bin,
version: resticVersion,
uri: uri,
tmpDir: tmpDir,
passwordFile: passwordFile,
......@@ -136,7 +147,7 @@ func newResticRepository(params Params) (Repository, error) {
excludes: params.GetList("exclude"),
excludeFiles: params.GetList("exclude_files"),
autoPrune: autoPrune,
cacheMgr: cmgr,
cacheMgr: cmgr,
}, nil
}
......@@ -175,8 +186,9 @@ func resticBackupTags(backup *Backup, ds *Dataset) string {
func (r *resticRepository) backupCmd(cc cache, backup *Backup, ds *Dataset, inputFile string, exclude []string) string {
cmd := fmt.Sprintf(
"%s %s --json --exclude-caches --one-file-system %s --files-from %s",
"%s %s %s --json --exclude-caches --one-file-system %s --files-from %s",
r.resticCmd("backup"),
r.excludeArgs(),
cc.Args(),
resticBackupTags(backup, ds),
inputFile,
......
......@@ -41,8 +41,14 @@ func createTempDirWithData(t *testing.T) string {
// nolint: gocyclo
func runResticTest(t *testing.T, tmpdir string, source *SourceSpec, restorePattern string, checkFn func(testing.TB, string)) {
// Check that we can actually run restic.
if err := checkResticVersion("restic"); err != nil {
t.Skip("can't run restic: ", err)
resticVersion, err := getResticVersion("restic")
if err != nil {
t.Skip("can't find restic: ", err)
}
if resticVersion.LessThan(resticMinGoodVersion) {
t.Skip("restic version ", resticVersion,
" is older than the minimum supported version ",
resticMinGoodVersion)
}
// Temporary cache dir.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment