feat: autoinstall required restic version

This commit is contained in:
Gareth George
2023-11-28 01:02:32 -08:00
committed by garethgeorge
parent 48837b0aa2
commit b385c01121
15 changed files with 222 additions and 69 deletions
+16 -33
View File
@@ -3,7 +3,7 @@ package main
import (
"context"
"errors"
"io/fs"
"flag"
"net/http"
"os"
"os/signal"
@@ -11,19 +11,18 @@ import (
"sync"
"syscall"
rice "github.com/GeertJohan/go.rice"
"github.com/garethgeorge/resticui/internal/api"
"github.com/garethgeorge/resticui/internal/config"
"github.com/garethgeorge/resticui/internal/envopts"
"github.com/garethgeorge/resticui/internal/oplog"
"github.com/garethgeorge/resticui/internal/orchestrator"
static "github.com/garethgeorge/resticui/webui"
"github.com/mattn/go-colorable"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
_ "embed"
)
var flagAutoInstallRestic = flag.Bool("auto-install-restic", true, "Automatically install restic if $RESTICUI_")
func main() {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
@@ -40,10 +39,15 @@ func main() {
// Configure the HTTP mux
mux := http.NewServeMux()
mux.Handle("/", http.FileServer(http.FS(&SubdirFilesystem{FS: static.FS, subdir: "dist"})))
if box, err := rice.FindBox("webui/dist"); err == nil {
mux.Handle("/", http.FileServer(box.HTTPBox()))
} else {
zap.S().Warnf("Error loading static assets, not serving UI: %v", err)
}
// Create and serve API server
oplogFile := path.Join(dataPath(), "oplog.boltdb")
oplogFile := path.Join(config.DataDir(), "oplog.boltdb")
oplog, err := oplog.NewOpLog(oplogFile)
if err != nil {
zap.S().Warnf("Operation log may be corrupted, if errors recur delete the file %q and restart. Your backups stored in your repos are safe.", oplogFile)
@@ -84,7 +88,7 @@ func main() {
// Serve the HTTP gateway
server := &http.Server{
Addr: envopts.BindAddress(),
Addr: config.BindAddress(),
Handler: mux,
}
@@ -123,7 +127,7 @@ func init() {
func createConfigProvider() config.ConfigStore {
return &config.CachingValidatingStore{
ConfigStore: &config.JsonFileStore{Path: envopts.ConfigFilePath()},
ConfigStore: &config.JsonFileStore{Path: config.ConfigFilePath()},
}
}
@@ -134,30 +138,9 @@ func onterm(callback func()) {
callback()
}
type SubdirFilesystem struct {
fs.FS
subdir string
}
func findResticBin() {
resticBin := config.ResticBinPath()
if resticBin != "" {
var _ fs.FS = &SubdirFilesystem{}
var _ fs.ReadDirFS = &SubdirFilesystem{}
func (s *SubdirFilesystem) Open(name string) (fs.File, error) {
return s.FS.Open(path.Join(s.subdir, name))
}
func (s *SubdirFilesystem) ReadDir(name string) ([]fs.DirEntry, error) {
readDirFS := s.FS.(fs.ReadDirFS)
if readDirFS == nil {
return nil, &fs.PathError{Op: "readdir", Path: name, Err: errors.New("not implemented")}
}
return readDirFS.ReadDir(path.Join(s.subdir, name))
}
func dataPath() string {
datahome := os.Getenv("XDG_DATA_HOME")
if datahome == "" {
datahome = path.Join(os.Getenv("HOME") + "/.local/share")
}
return path.Join(datahome, "resticui")
}
+7 -5
View File
@@ -3,6 +3,7 @@ module github.com/garethgeorge/resticui
go 1.21.3
require (
github.com/GeertJohan/go.rice v1.0.3
github.com/gitploy-io/cronexpr v0.2.2
github.com/google/renameio v1.0.1
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1
@@ -11,19 +12,20 @@ require (
github.com/mattn/go-colorable v0.1.13
go.etcd.io/bbolt v1.3.8
go.uber.org/zap v1.26.0
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17
google.golang.org/genproto/googleapis/api v0.0.0-20231127180814-3a041ad873d4
google.golang.org/grpc v1.59.0
google.golang.org/protobuf v1.31.0
)
require (
github.com/daaku/go.zipexe v1.0.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/sys v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect
)
+20
View File
@@ -1,3 +1,9 @@
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.3 h1:k5viR+xGtIhF61125vCE1cmJ5957RQGXG6dmbaWZSmI=
github.com/GeertJohan/go.rice v1.0.3/go.mod h1:XVdrU4pW00M4ikZed5q56tPf1v2KwnIKeIdc9CBYNt4=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/daaku/go.zipexe v1.0.2 h1:Zg55YLYTr7M9wjKn8SY/WcpuuEi+kR2u4E8RhvpyXmk=
github.com/daaku/go.zipexe v1.0.2/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzUZbt3Bw8=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gitploy-io/cronexpr v0.2.2 h1:Au+wK6FqmOLAF7AkW6q4gnrNXTe3rEW97XFZ4chy0xs=
@@ -19,15 +25,19 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
@@ -38,19 +48,29 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4 h1:W12Pwm4urIbRdGhMEg2NM9O3TWKjNcxQhs46V0ypf/k=
google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/genproto/googleapis/api v0.0.0-20231127180814-3a041ad873d4 h1:ZcOkrmX74HbKFYnpPY8Qsw93fC29TbJXspYKaBkSXDQ=
google.golang.org/genproto/googleapis/api v0.0.0-20231127180814-3a041ad873d4/go.mod h1:k2dtGpRrbsSyKcNPKKI5sstZkrNCZwpU/ns96JoHbGg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
Regular → Executable
+6 -3
View File
@@ -1,5 +1,8 @@
#! /bin/sh
set -x
(cd proto && ./build.sh)
go build ./..
(cd proto && ./update.sh)
(cd webui && npm run build)
rm -f resticui
go build ./cmd/resticui
rice append --exec resticui
Regular → Executable
+2 -1
View File
@@ -1,5 +1,6 @@
#! /bin/sh
set -x
go install github.com/GeertJohan/go.rice/rice@latest
go install github.com/GeertJohan/go.rice@latest
pip install lastversion
python -m pip install lastversion
Executable
+4
View File
@@ -0,0 +1,4 @@
#! /bin/sh
set -x
DEBUG=1 go run ./cmd/resticui
+1
View File
@@ -31,6 +31,7 @@ var _ v1.ResticUIServer = &Server{}
func NewServer(config config.ConfigStore, orchestrator *orchestrator.Orchestrator, oplog *oplog.OpLog) *Server {
s := &Server{
config: config,
orchestrator: orchestrator,
oplog: oplog,
}
@@ -1,4 +1,4 @@
package envopts
package config
import (
"fmt"
@@ -7,8 +7,15 @@ import (
"strings"
)
var (
EnvVarConfigPath = "RESTICUI_CONFIG_PATH"
EnvVarDataDir = "RESTICUI_DATA_DIR"
EnvVarBindAddress = "RESTICUI_PORT"
EnvVarBinPath = "RESTICUI_RESTIC_BIN_PATH"
)
func ConfigFilePath() string {
if val := os.Getenv("RESTICUI_CONFIG_PATH"); val != "" {
if val := os.Getenv(EnvVarConfigPath); val != "" {
return val
}
if val := os.Getenv("XDG_CONFIG_HOME"); val != "" {
@@ -18,7 +25,7 @@ func ConfigFilePath() string {
}
func DataDir() string {
if val := os.Getenv("RESTICUI_DATA_DIR"); val != "" {
if val := os.Getenv(EnvVarDataDir); val != "" {
return val
}
if val := os.Getenv("XDG_DATA_HOME"); val != "" {
@@ -28,7 +35,7 @@ func DataDir() string {
}
func BindAddress() string {
if val := os.Getenv("RESTICUI_PORT"); val != "" {
if val := os.Getenv(EnvVarBindAddress); val != "" {
if !strings.Contains(val, ":") {
return ":" + val
}
@@ -37,6 +44,13 @@ func BindAddress() string {
return ":9898"
}
func ResticBinPath() string {
if val := os.Getenv("RESTICUI_RESTIC_BIN_PATH"); val != "" {
return val
}
return ""
}
func getHomeDir() string {
home, err := os.UserHomeDir()
if err != nil {
+1 -1
View File
@@ -6,8 +6,8 @@ import (
"testing"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
test "github.com/garethgeorge/resticui/internal/test/helpers"
"github.com/garethgeorge/resticui/pkg/restic"
test "github.com/garethgeorge/resticui/test/helpers"
)
func TestBackup(t *testing.T) {
+117
View File
@@ -0,0 +1,117 @@
package resticinstaller
import (
"compress/bzip2"
"errors"
"fmt"
"io"
"net/http"
"os"
"path"
"runtime"
"strings"
"sync"
"github.com/garethgeorge/resticui/internal/config"
)
var (
ErrResticNotFound = errors.New("no restic binary")
)
var (
RequiredResticVersion = "0.16.2"
findResticMu sync.Mutex
didTryInstall bool
)
func resticDownloadURL(version string) string {
return fmt.Sprintf("https://github.com/restic/restic/releases/download/v%v/restic_%v_%v_%v.bz2", version, version, runtime.GOOS, runtime.GOARCH)
}
func downloadFile(url string, path string) error {
// Download ur as a file and save it to path
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("http GET %v: %w", url, err)
}
defer resp.Body.Close()
var body io.Reader = resp.Body
if strings.HasSuffix(url, ".bz2") {
body = bzip2.NewReader(resp.Body)
}
out, err := os.Create(path)
if err != nil {
return fmt.Errorf("create file %v: %w", path, err)
}
defer out.Close()
if err != nil {
return fmt.Errorf("create file %v: %w", path, err)
}
_, err = io.Copy(out, body)
if err != nil {
return fmt.Errorf("copy response body to file %v: %w", path, err)
}
return nil
}
func downloadExecutable(url string, path string) error {
if err := downloadFile(url, path + ".tmp"); err != nil {
return err
}
if err := os.Chmod(path + ".tmp", 0755); err != nil {
return fmt.Errorf("chmod executable %v: %w", path, err)
}
if err := os.Rename(path + ".tmp", path); err != nil {
return fmt.Errorf("rename %v.tmp to %v: %w", path, path, err)
}
return nil
}
// FindOrInstallResticBinary first tries to find the restic binary if provided as an environment variable. Otherwise it downloads restic if not already installed.
func FindOrInstallResticBinary() (string, error) {
findResticMu.Lock()
defer findResticMu.Unlock()
// Check if restic is provided.
resticBin := config.ResticBinPath()
if resticBin != "" {
if _, err := os.Stat(resticBin); err != nil {
if !errors.Is(err, os.ErrNotExist) {
return "", fmt.Errorf("stat(%v): %w", resticBin, err)
}
return "", fmt.Errorf("no binary found at path %v: %w", resticBin, ErrResticNotFound)
}
return resticBin, nil
}
// Check for restic installation in data directory.
resticInstallPath := path.Join(config.DataDir(), fmt.Sprintf("restic-%v", RequiredResticVersion))
if _, err := os.Stat(resticInstallPath); err != nil {
if !errors.Is(err, os.ErrNotExist) {
return "", fmt.Errorf("could not stat restic binary at %v: %w", resticBin, err)
}
if didTryInstall {
return "", fmt.Errorf("already tried to install: %w", ErrResticNotFound)
}
didTryInstall = true
if err := os.MkdirAll(path.Dir(resticInstallPath), 0755); err != nil {
return "", fmt.Errorf("create restic install directory %v: %w", path.Dir(resticInstallPath), err)
}
if err := downloadExecutable(resticDownloadURL(RequiredResticVersion), resticInstallPath); err != nil {
return "", fmt.Errorf("download restic version %v: %w", RequiredResticVersion, err)
}
}
return resticInstallPath, nil
}
+2 -2
View File
@@ -27,14 +27,14 @@ type Repo struct {
}
// NewRepo instantiates a new repository. TODO: should not accept a v1.Repo, should instead be configured by parameters.
func NewRepo(repo *v1.Repo, opts ...GenericOption) *Repo {
func NewRepo(resticBin string, repo *v1.Repo, opts ...GenericOption) *Repo {
opt := &GenericOpts{}
for _, o := range opts {
o(opt)
}
return &Repo{
cmd: "restic", // TODO: configurable binary path
cmd: resticBin, // TODO: configurable binary path
repo: repo,
initialized: false,
extraArgs: opt.extraArgs,
+11 -11
View File
@@ -10,14 +10,14 @@ import (
"testing"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
test "github.com/garethgeorge/resticui/internal/test/helpers"
"github.com/garethgeorge/resticui/test/helpers"
)
func TestResticInit(t *testing.T) {
t.Parallel()
repo := t.TempDir()
r := NewRepo(&v1.Repo{
r := NewRepo(helpers.ResticBinary(t), &v1.Repo{
Id: "test",
Uri: repo,
Password: "test",
@@ -33,7 +33,7 @@ func TestResticBackup(t *testing.T) {
repo := t.TempDir()
// create a new repo with cache disabled for testing
r := NewRepo(&v1.Repo{
r := NewRepo(helpers.ResticBinary(t), &v1.Repo{
Id: "test",
Uri: repo,
Password: "test",
@@ -42,8 +42,8 @@ func TestResticBackup(t *testing.T) {
t.Fatalf("failed to init repo: %v", err)
}
testData := test.CreateTestData(t)
testData2 := test.CreateTestData(t)
testData := helpers.CreateTestData(t)
testData2 := helpers.CreateTestData(t)
var tests = []struct {
name string
@@ -107,7 +107,7 @@ func TestSnapshot(t *testing.T) {
repo := t.TempDir()
r := NewRepo(&v1.Repo{
r := NewRepo(helpers.ResticBinary(t), &v1.Repo{
Id: "test",
Uri: repo,
Password: "test",
@@ -116,7 +116,7 @@ func TestSnapshot(t *testing.T) {
t.Fatalf("failed to init repo: %v", err)
}
testData := test.CreateTestData(t)
testData := helpers.CreateTestData(t)
for i := 0; i < 10; i++ {
_, err := r.Backup(context.Background(), nil, WithBackupPaths(testData), WithBackupTags(fmt.Sprintf("tag%d", i)))
@@ -167,7 +167,7 @@ func TestLs(t *testing.T) {
t.Parallel()
repo := t.TempDir()
r := NewRepo(&v1.Repo{
r := NewRepo(helpers.ResticBinary(t), &v1.Repo{
Id: "test",
Uri: repo,
Password: "test",
@@ -176,7 +176,7 @@ func TestLs(t *testing.T) {
t.Fatalf("failed to init repo: %v", err)
}
testData := test.CreateTestData(t)
testData := helpers.CreateTestData(t)
snapshot, err := r.Backup(context.Background(), nil, WithBackupPaths(testData))
if err != nil {
@@ -198,7 +198,7 @@ func TestResticForget(t *testing.T) {
t.Parallel()
repo := t.TempDir()
r := NewRepo(&v1.Repo{
r := NewRepo(helpers.ResticBinary(t), &v1.Repo{
Id: "test",
Uri: repo,
Password: "test",
@@ -207,7 +207,7 @@ func TestResticForget(t *testing.T) {
t.Fatalf("failed to init repo: %v", err)
}
testData := test.CreateTestData(t)
testData := helpers.CreateTestData(t)
ids := make([]string, 0)
for i := 0; i < 10; i++ {
+16
View File
@@ -0,0 +1,16 @@
package helpers
import (
"testing"
"github.com/garethgeorge/resticui/internal/resticinstaller"
)
func ResticBinary(t *testing.T) string {
binPath, err := resticinstaller.FindOrInstallResticBinary()
if err != nil {
t.Fatalf("find restic binary: %v", err)
}
return binPath
}
@@ -1,4 +1,4 @@
package test
package helpers
import (
"fmt"
-8
View File
@@ -1,8 +0,0 @@
package static
import (
"embed"
)
//go:embed dist/*.js dist/*.css dist/*.html
var FS embed.FS