Skip to content

Commit

Permalink
Feature/restic version checks (#23)
Browse files Browse the repository at this point in the history
* parse exact restic version numbers when resolving the program

* return a verbose error when folder dunps are not possible
- to do so, check if the installed restic version is >= 0.12.0

* increase dump error notification duration
  • Loading branch information
emuell authored Aug 20, 2022
1 parent 5a5ed6a commit b251c2f
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 30 deletions.
11 changes: 10 additions & 1 deletion backend/restic/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,19 @@ func (r *Repository) RestoreFile(snapshot *Snapshot, file *File, targetPath stri

func (r *Repository) DumpFile(snapshot *Snapshot, file *File, targetPath string) (string, error) {

// zip compression for folders and -a option was added in restic 0.12.0
hasZipDumpSupport := r.restic.Version[0] > 1 ||
(r.restic.Version[0] == 0 && r.restic.Version[1] >= 12)

if file.Type == "dir" && !hasZipDumpSupport {
return "", fmt.Errorf("your version of restic does not support folder dumps. " +
"Please upgrade restic to version >= 0.12.0 to restore folders")
}

// open the target file for writing
targetFileName := filepath.Join(targetPath, file.Name)
if file.Type == "dir" {
targetFileName = targetFileName + ".zip"
targetFileName += ".zip"
}
if fs.FileExists(targetFileName) {
return "", fmt.Errorf("target file '%s' already exists", targetFileName)
Expand Down
69 changes: 44 additions & 25 deletions backend/restic/restic.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import (
"os"
"path/filepath"
"runtime"
"strconv"
"strings"

"restic-browser/backend/program"
)

// Restic holds information about the Restic Binary
type Restic struct {
VersionString string
Version string
restic *program.Program
Version [3]int // major, minor, rev
restic *program.Program
}

// Run restic program and return stdout and err, exitCode and error.
Expand All @@ -41,6 +41,37 @@ func ResticProgramName() string {
return programName
}

// resticVersionNumber gets the restic version from the restic program
func resticVersionNumber(resticProgram *program.Program) ([3]int, error) {
versionstring, _, code, _ := resticProgram.Run("version")
if code != 0 {
return [3]int{0, 0, 0}, fmt.Errorf("failed to fetch restic version from %s", resticProgram.Path)
}
version := [3]int{0, 0, 0}
splitVersion := strings.Split(versionstring, " ") // "restic x.y.z some other info"
if len(splitVersion) > 2 {
versionSplits := strings.Split(splitVersion[1], ".") // "x.y.z"
if len(versionSplits) > 2 {
major, err := strconv.ParseInt(versionSplits[0], 10, 32)
if err != nil {
major = 0
}
minor, err := strconv.ParseInt(versionSplits[1], 10, 32)
if err != nil {
minor = 0
}
rev, err := strconv.ParseInt(versionSplits[2], 10, 32)
if err != nil {
rev = 0
}
version[0] = int(major)
version[1] = int(minor)
version[2] = int(rev)
}
}
return version, nil
}

// NewRestic creates a new Restic struct
func NewRestic() (restic *Restic, err error) {

Expand All @@ -52,20 +83,14 @@ func NewRestic() (restic *Restic, err error) {
}

// Get the version
versionstring, _, code, _ := resticProgram.Run("version")
if code != 0 {
return nil, fmt.Errorf("failed to fetch restic version from %s", resticProgram.Path)
}
version := "unknown"
splitVersion := strings.Split(versionstring, " ")
if len(splitVersion) > 2 {
version = splitVersion[1]
version, err := resticVersionNumber(resticProgram)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to fetch restic version from %s: %s", resticProgram.Path, err.Error())
}

restic = &Restic{
VersionString: versionstring,
Version: version,
restic: resticProgram,
Version: version,
restic: resticProgram,
}

return restic, nil
Expand Down Expand Up @@ -95,20 +120,14 @@ func NewResticFromPath(path string) (restic *Restic, err error) {
}

// Get the version
versionstring, _, code, _ := resticProgram.Run("version")
if code != 0 {
return nil, fmt.Errorf("failed to fetch restic version from %s", resticProgram.Path)
}
version := "unknown"
splitVersion := strings.Split(versionstring, " ")
if len(splitVersion) > 2 {
version = splitVersion[1]
version, err := resticVersionNumber(resticProgram)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to fetch restic version from %s: %s", resticProgram.Path, err.Error())
}

restic = &Restic{
VersionString: versionstring,
Version: version,
restic: resticProgram,
Version: version,
restic: resticProgram,
}

return restic, nil
Expand Down
7 changes: 4 additions & 3 deletions backend/restic/restic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"math/rand"
"os"
"path/filepath"
"strings"
"testing"
)

Expand Down Expand Up @@ -57,8 +56,10 @@ func TestResticProgram(t *testing.T) {
if err != nil {
t.Fatal("failed to resolve restic binary", err)
}
if len(strings.Split(restic.Version, ".")) != 3 {
t.Error("unexpected restic version number")
if restic.Version[0] == 0 &&
restic.Version[1] == 0 &&
restic.Version[2] == 0 {
t.Error("failed to parse restic version number")
}
}

Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/file-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ export class ResticBrowserFileList extends MobxLitElement {
.catch((err) => {
Notification.show(`Failed to restore file: ${err.message || err}`, {
position: 'middle',
theme: "error"
theme: "error",
duration: 10000
});
});
}
Expand Down

0 comments on commit b251c2f

Please sign in to comment.