chore: fix resticinstaller for windows tests

This commit is contained in:
Gareth George
2024-11-26 00:23:27 -08:00
parent 74eb869263
commit 4f03427c91
4 changed files with 69 additions and 58 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ RUN apk --no-cache add tini ca-certificates curl bash rclone openssh tzdata dock
RUN mkdir -p /tmp
COPY backrest /backrest
RUN /backrest --install-deps-only
RUN mkdir -p /bin && mv /root/.local/share/backrest/* /bin
RUN mkdir -p /bin && mv /root/.local/share/backrest/restic /bin/restic
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/backrest", "--bind-address", ":9898"]
+1 -1
View File
@@ -3,7 +3,7 @@ RUN apk add --no-cache ca-certificates tini-static
RUN mkdir /tmp-orig
COPY backrest /backrest
RUN /backrest --install-deps-only
RUN mkdir -p /bin && mv /root/.local/share/backrest/* /bin
RUN mkdir -p /bin && mv /root/.local/share/backrest/restic /bin/restic
FROM scratch
LABEL org.opencontainers.image.source="https://github.com/garethgeorge/backrest"
+10 -15
View File
@@ -62,7 +62,7 @@ Download options
Backrest is accessible from a web browser. By default it binds to `127.0.0.1:9898` and can be accessed at `http://localhost:9898`. Change the port with the `BACKREST_PORT` environment variable e.g. `BACKREST_PORT=0.0.0.0:9898 backrest` to listen on all network interfaces. On first startup backrest will prompt you to create a default username and password, this can be changed later in the settings page.
> [!Note]
> Backrest installs a specific restic version to ensure that it is compatible. If you wish to use a different version of restic OR if you would prefer to install restic manually, use the `BACKREST_RESTIC_COMMAND` environment variable to specify the path of your restic install.
> Backrest will use your system install of restic if it is available and matches Backrest's required version. Otherwise it will download and install a compatible version of restic in its data directory. Backrest will keep restic up to date with the latest version. You force use of a specific restic binary (or non-standard version) by setting the `BACKREST_RESTIC_COMMAND` environment variable to the path of your restic binary.
## Running with Docker Compose
@@ -142,7 +142,7 @@ Create a systemd service file at `/etc/systemd/system/backrest.service` with the
```ini
[Unit]
Description=ResticWeb
Description=Backrest
After=network.target
[Service]
@@ -189,15 +189,14 @@ Backrest is provided as a [homebrew tap](https://github.com/garethgeorge/homebre
brew tap garethgeorge/homebrew-backrest-tap
brew install backrest
brew services start backrest
# optionally, install restic
brew install restic
```
This tap uses [Brew services](https://github.com/Homebrew/homebrew-services) to launch and manage Backrest's lifecycle. Backrest will launch on startup and run on port ':9898` by default.
> [!NOTE]
> You may need to grant Full Disk Access to your restic install. To do this, go to `System Preferences > Security & Privacy > Privacy > Full Disk Access` and add the path to your restic install which is typically ~/.local/share/backrest/restic .
> [!NOTE]
> You may optionally install `restic` through homebrew as well, but you may need to regrant Full Disk Access to the homebrew managed binary on each update. You should ensure that you update backrest and restic together if using homebrew to manage both dependencies.
> You may need to grant Full Disk Access to backrest. To do this, go to `System Preferences > Security & Privacy > Privacy > Full Disk Access` and add the path to backrest (typically /usr/local/bin/backrest).
#### Manually using the install script
@@ -220,19 +219,15 @@ The install script will:
Read the script before running it to make sure you are comfortable with these operations.
#### Manually
If setting up Backrest manually, it is recommended to install the binary to `/usr/local/bin` and run it manually. You can also create a launch agent to run it on startup or may run it manually when needed.
## Running on Windows
Download a Windows release from the [releases page](https://github.com/garethgeorge/backrest/releases) and install it to `C:\Program Files\Backrest\backrest.exe` (create the path if it does not exist). The binary should be run as administrator on first launch, otherwise the restic installation will fail and the process will terminate.
#### Windows Installer
To run the binary on login, create a shortcut to the binary and place it in the `shell:startup` folder. See [this windows support article](https://support.microsoft.com/en-us/windows/add-an-app-to-run-automatically-at-startup-in-windows-10-150da165-dcd9-7230-517b-cf3c295d89dd) for more details.
Download a the Windows installer for your architecture from the [releases page](https://github.com/garethgeorge/backrest/releases). The installer is named Backrest-setup-[arch].exe. Run the installer and follow the prompts.
> [!WARNING]
> * If you receive filesystem errors, you may need to run Backrest as an administrator for full filesystem access.
> * Backrest is **not** tested on Windows to the same extent as Linux and macOS. Some features may not work as expected.
The installer will place backrest and a GUI tray application to monitor backrest in `%localappdata%\Programs\Backrest\`. The GUI tray application will start on login by default.
> [!NOTE] You can optionally override the default port of the installation by using PowerShell to run the installer with the `BACKREST_PORT` environment variable set to the desired port. E.g. to run backrest on port 8080, run the following command in PowerShell: `BACKREST_PORT=:8080 .\Backrest-setup-x86_64.exe`
# Configuration
+57 -41
View File
@@ -24,8 +24,9 @@ var (
var (
RequiredResticVersion = "0.17.3"
findResticMu sync.Mutex
didTryInstall bool
tryFindRestic sync.Once
findResticErr error
foundResticPath string
)
func getResticVersion(binary string) (string, error) {
@@ -94,12 +95,6 @@ func verify(sha256 string) error {
}
func installResticIfNotExists(resticInstallPath string) error {
lock := flock.New(filepath.Join(filepath.Dir(resticInstallPath), "install.lock"))
if err := lock.Lock(); err != nil {
return fmt.Errorf("lock %v: %w", lock.Path(), err)
}
defer lock.Unlock()
if _, err := os.Stat(resticInstallPath); err == nil {
// file is now installed, probably by another process. We can return.
return nil
@@ -148,25 +143,40 @@ func removeOldVersions(installDir string) {
}
}
// 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()
func installResticHelper(resticInstallPath string) {
if _, err := os.Stat(resticInstallPath); err == nil {
zap.S().Infof("replacing restic binary in data dir due to failed check: %w", err)
if err := os.Remove(resticInstallPath); err != nil {
zap.S().Errorf("failed to remove old restic binary %v: %v", resticInstallPath, err)
}
}
zap.S().Infof("downloading restic %v to %v...", RequiredResticVersion, resticInstallPath)
if err := installResticIfNotExists(resticInstallPath); err != nil {
zap.S().Errorf("failed to install restic %v: %v", RequiredResticVersion, err)
return
}
zap.S().Infof("installed restic %v", RequiredResticVersion)
// TODO: this check is no longer needed, remove it after a few releases.
removeOldVersions(path.Dir(resticInstallPath))
}
func tryFindOrInstall() (string, error) {
// Check if restic is provided.
resticBin := env.ResticBinPath()
if resticBin != "" {
if err := assertResticVersion(resticBin); err != nil {
zap.S().Warnf("restic binary %q may not be supported by backrest", resticBin, err)
resticBinOverride := env.ResticBinPath()
if resticBinOverride != "" {
if err := assertResticVersion(resticBinOverride); err != nil {
zap.S().Warnf("restic binary %q may not be supported by backrest: %v", resticBinOverride, err)
}
if _, err := os.Stat(resticBin); err != nil {
if _, err := os.Stat(resticBinOverride); err != nil {
if !errors.Is(err, os.ErrNotExist) {
return "", fmt.Errorf("stat(%v): %w", resticBin, err)
return "", fmt.Errorf("check if restic binary exists at %v: %v", resticBinOverride, err)
}
return "", fmt.Errorf("no binary found at path %v: %w", resticBin, ErrResticNotFound)
return "", fmt.Errorf("no restic binary found at %v", resticBinOverride)
}
return resticBin, nil
return resticBinOverride, nil
}
// Search the PATH for the specific restic version.
@@ -180,40 +190,46 @@ func FindOrInstallResticBinary() (string, error) {
}
// Check for restic installation in data directory.
resticInstallPath := path.Join(env.DataDir(), "restic")
var resticInstallPath string
if runtime.GOOS == "windows" {
// on windows use a path relative to the executable.
resticInstallPath, _ = filepath.Abs(path.Join(path.Dir(os.Args[0]), "restic"))
resticInstallPath, _ = filepath.Abs(path.Join(path.Dir(os.Args[0]), "restic.exe"))
} else {
resticInstallPath = filepath.Join(env.DataDir(), "restic")
}
if err := os.MkdirAll(path.Dir(resticInstallPath), 0700); err != nil {
if err := os.MkdirAll(filepath.Dir(resticInstallPath), 0700); err != nil {
return "", fmt.Errorf("create restic install directory %v: %w", path.Dir(resticInstallPath), err)
}
// Install restic if not found OR if the version is not the required version
if err := assertResticVersion(resticInstallPath); err != nil {
if _, err := os.Stat(resticInstallPath); err == nil {
zap.S().Infof("reinstalling restic binary in data dir due to failed checks: %w", err)
if err := os.Remove(resticInstallPath); err != nil {
return "", fmt.Errorf("remove old restic binary %v: %w", resticInstallPath, err)
}
lock := flock.New(filepath.Join(filepath.Dir(resticInstallPath), "install.lock"))
if err := lock.Lock(); err != nil {
return "", fmt.Errorf("acquire lock on restic install dir %v: %v", lock.Path(), err)
}
defer lock.Unlock()
if didTryInstall {
return "", fmt.Errorf("already tried to install: %w", ErrResticNotFound)
// Check again after acquiring the lock.
if err := assertResticVersion(resticInstallPath); err != nil {
installResticHelper(resticInstallPath)
}
didTryInstall = true
zap.S().Infof("downloading restic %v to %v...", RequiredResticVersion, resticInstallPath)
if err := installResticIfNotExists(resticInstallPath); err != nil {
return "", fmt.Errorf("install restic: %w", err)
}
zap.S().Infof("installed restic %v", RequiredResticVersion)
// TODO: this check is no longer needed, remove it after a few releases.
removeOldVersions(path.Dir(resticInstallPath))
}
zap.S().Infof("restic binary %v in data dir will be used as no system install matching required version %v is found", resticInstallPath, RequiredResticVersion)
return resticInstallPath, 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) {
tryFindRestic.Do(func() {
foundResticPath, findResticErr = tryFindOrInstall()
})
if findResticErr != nil {
return "", findResticErr
}
if foundResticPath == "" {
return "", ErrResticNotFound
}
return foundResticPath, nil
}