diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..491cf7a9f --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,22 @@ +## Based on microsoft go devcontainer - https://github.com/microsoft/vscode-dev-containers/blob/v0.205.2/containers/go/.devcontainer/Dockerfile +# [Choice] Go version (use -bullseye variants on local arm64/Apple Silicon): 1, 1.16, 1.17, 1-bullseye, 1.16-bullseye, 1.17-bullseye, 1-buster, 1.16-buster, 1.17-buster +ARG VARIANT=1-bullseye +FROM mcr.microsoft.com/vscode/devcontainers/go:${VARIANT} + +# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10 +ARG NODE_VERSION="none" +RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi + +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends protobuf-compiler + +USER vscode + +RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \ + && go install github.com/bufbuild/buf/cmd/buf@v1.27.2 \ + && go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest \ + && go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \ + && go install connectrpc.com/connect/cmd/protoc-gen-connect-go@latest \ + && go install github.com/GeertJohan/go.rice/rice@latest \ + && go install github.com/goreleaser/goreleaser@latest \ + && npm install -g @bufbuild/protoc-gen-es @connectrpc/protoc-gen-connect-es diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..c65b0f6ae --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,49 @@ +{ + "name": "Go", + "build": { + "dockerfile": "Dockerfile", + "args": { + // Update the VARIANT arg to pick a version of Go: 1, 1.16, 1.17 + // Append -bullseye or -buster to pin to an OS version. + // Use -bullseye variants on local arm64/Apple Silicon. + "VARIANT": "1-1.21-bookworm", + // Options + "NODE_VERSION": "lts/*" + } + }, + "runArgs": [ + "--cap-add=SYS_PTRACE", + "--security-opt", + "seccomp=unconfined" + ], + "customizations": { + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + "go.toolsManagement.checkForUpdates": "local", + "go.useLanguageServer": true, + "go.gopath": "/go", + "go.goroot": "/usr/local/go", + "typescript.tsdk": "webui/node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true, + "gitlens.telemetry.enabled": false + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "golang.Go", + "ms-azuretools.vscode-docker", + "mhutchie.git-graph", + "eamodio.gitlens", + "donjayamanne.githistory", + "esbenp.prettier-vscode", + "iulian-radu-at.vscode-tasks-sidebar" + ] + } + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "go version", + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" +} \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..a74af7ffb --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +buy_me_a_coffee: garethgeorge +github: garethgeorge diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..fcc8ade04 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Bug report +about: Report an issue with Backrest +title: "" +labels: bug +assignees: "" +--- + +Note: if you have a question or need support please post in the [discussions area](https://github.com/garethgeorge/backrest/discussions). + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Platform Info** + +- OS and Architecture [e.g. Windows 10 x64, Darwin arm64] +- Backrest Version [e.g. 0.0.0] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..7c4af7e12 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,18 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "" +labels: enhancement +assignees: "" +--- + +Note: if you have a question or want discussion please post in the [discussions area](https://github.com/garethgeorge/backrest/discussions). + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..c0a8fd7ec --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,67 @@ +# This workflow will build a golang project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go + +name: Build Snapshot Release + +on: + push: + branches: ["main"] + paths-ignore: + - "docs/**" + - "*.md" + pull_request: + branches: ["main"] + paths-ignore: + - "docs/**" + - "*.md" + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: "1.23" + + - name: Setup NodeJS + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Build + uses: goreleaser/goreleaser-action@v5 + with: + distribution: goreleaser + version: latest + args: release --snapshot --clean + + - name: Upload Artifacts + uses: actions/upload-artifact@v3 + with: + name: backrest-snapshot-builds + path: | + dist/*.tar.gz + dist/*.zip + + - name: Generate Installers + run: | + mkdir -p dist-installers + ./scripts/generate-installers.sh ./dist-installers + + - name: Upload Installers + uses: actions/upload-artifact@v3 + with: + name: backrest-snapshot-installers + path: dist-installers/*.exe diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..847872cde --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,63 @@ +# This workflow will build a golang project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go + +name: Docs + +on: + push: + branches: ["main"] + paths: + - "docs/**" + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up NodeJS + uses: actions/setup-node@v2 + with: + node-version: "20" + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Install dependencies + run: pnpm install --prefix ./docs + + - name: Build + run: pnpm run generate --prefix ./docs + + - name: Fix permissions + run: | + chmod -c -R +rX "./docs/.output/public" | while read line; do + echo "::warning title=Invalid file permissions automatically fixed::$line" + done + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v2 + with: + path: ./docs/.output/public + + deploy: + needs: build + + permissions: + pages: write + id-token: write + actions: read + + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 000000000..5d93e8871 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,19 @@ +on: + push: + branches: + - main + +permissions: + contents: write + pull-requests: write + +name: Release Please + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: google-github-actions/release-please-action@v4 + with: + token: ${{ secrets.RELEASE_PLEASE_TOKEN }} + release-type: simple diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..d057fde4c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,90 @@ +name: Tagged Release + +on: + push: + tags: + - "*" + workflow_dispatch: + +permissions: + contents: write + +jobs: + tagged-release: + name: "Tagged Release" + runs-on: "ubuntu-latest" + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: "1.23" + + - name: Setup NodeJS + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v5 + with: + distribution: goreleaser + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HOMEBREW_GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_TOKEN }} + + - name: Upload Artifacts + uses: actions/upload-artifact@v3 + with: + name: release-artifacts + path: dist/* + + tagged-release-installers: + name: "Tagged Release Installers" + runs-on: "ubuntu-latest" + needs: tagged-release + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + # download dist artifacts from previous job + - name: Download Artifacts + uses: actions/download-artifact@v3 + with: + name: release-artifacts + path: dist + + - name: Generate Installers + run: | + mkdir -p dist-installers + ./scripts/generate-installers.sh ./dist-installers + + - name: Upload Assets + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: | + ./dist-installers/Backrest-setup-x86_64.exe + ./dist-installers/Backrest-setup-arm64.exe diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..41955156d --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,59 @@ +# This workflow will build a golang project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go + +name: Test + +on: + push: + branches: ["main"] + paths-ignore: + - "docs/**" + - "*.md" + pull_request: + branches: ["main"] + paths-ignore: + - "docs/**" + - "*.md" + workflow_dispatch: + +jobs: + test-nix: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: "1.23" + + - name: Create Fake WebUI Sources + run: | + mkdir -p webui/dist + touch webui/dist/index.html.gz + + - name: Build + run: go build ./... + + - name: Test + run: PATH=$(pwd):$PATH go test ./... --race + + test-win: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: "1.23" + + - name: Create Fake WebUI Sources + run: | + New-Item -Path .\webui\dist-windows\index.html -ItemType File -Force + + - name: Build + run: go build ./... + + - name: Test + run: go test ./... diff --git a/.github/workflows/update-restic.yml b/.github/workflows/update-restic.yml new file mode 100644 index 000000000..b5b7f08c5 --- /dev/null +++ b/.github/workflows/update-restic.yml @@ -0,0 +1,34 @@ +# This workflow will build a golang project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go + +name: Update Restic + +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update-restic-version: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Check for updates + run: | + ./scripts/update-restic-version.sh + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: update restic version" + title: "chore: update restic version" + body: Beep boop. Bot generated PR to update backrest to the latest restic version. + assignees: garethgeorge + branch: "update-restic-version" + base: "main" diff --git a/.gitignore b/.gitignore index 05077407b..a8443a841 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ -cmd/resticui/resticui +backrest-* +dist +__debug_bin +cmd/backrest/backrest +*.exe +.DS_Store diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 000000000..1c75af1a3 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,199 @@ +# This is an example .goreleaser.yml file with some sensible defaults. +# Make sure to check the documentation at https://goreleaser.com + +# The lines below are called `modelines`. See `:help modeline` +# Feel free to remove those if you don't want/need to use them. +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +# vim: set ts=2 sw=2 tw=0 fo=cnqoj + +version: 1 + +env: + - BACKREST_BUILD_VERSION={{.Version}} + +before: + hooks: + - go mod tidy + - pnpm --prefix webui install + - sh -c "GOOS=linux BACKREST_BUILD_VERSION={{.Version}} go generate ./..." + - sh -c "GOOS=windows BACKREST_BUILD_VERSION={{.Version}} go generate ./..." + +builds: + - id: other + main: ./cmd/backrest + env: + - CGO_ENABLED=0 + goos: + - darwin + - windows + - freebsd + goarch: + - amd64 + - arm64 + ldflags: + - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} + - id: linux + main: ./cmd/backrest + env: + - CGO_ENABLED=0 + goos: + - linux + goarch: + - amd64 + - arm64 + - arm + ldflags: + - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} + - id: backrestmon + main: ./cmd/backrestmon + binary: backrest-windows-tray + env: + - CGO_ENABLED=1 + - GO111MODULE=on + ldflags: -H=windowsgui + goos: + - windows + goarch: + - amd64 + - arm64 + +archives: + - format: tar.gz + name_template: >- + {{ .ProjectName }}_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}v{{ .Arm }}{{ end }} + format_overrides: + - goos: windows + format: zip + files: + - install.sh + - uninstall.sh + - LICENSE + - README.md + - CHANGELOG.md + allow_different_binary_count: true + +dockers: + - image_templates: + - garethgeorge/backrest:{{ .Tag }}-alpine-amd64 + dockerfile: Dockerfile.alpine + use: buildx + build_flag_templates: + - "--pull" + - "--platform=linux/amd64" + + - image_templates: + - garethgeorge/backrest:{{ .Tag }}-alpine-arm64 + dockerfile: Dockerfile.alpine + goarch: arm64 + use: buildx + build_flag_templates: + - "--pull" + - "--platform=linux/arm64/v8" + + - image_templates: + - garethgeorge/backrest:{{ .Tag }}-scratch-arm64 + dockerfile: Dockerfile.scratch + goarch: arm64 + use: buildx + build_flag_templates: + - "--pull" + - "--platform=linux/arm64/v8" + + - image_templates: + - garethgeorge/backrest:{{ .Tag }}-scratch-amd64 + dockerfile: Dockerfile.scratch + use: buildx + build_flag_templates: + - "--pull" + - "--platform=linux/amd64" + + - image_templates: + - garethgeorge/backrest:{{ .Tag }}-scratch-armv6 + dockerfile: Dockerfile.scratch + use: buildx + goarch: arm + goarm: 6 + build_flag_templates: + - "--pull" + - "--platform=linux/arm/v6" + +docker_manifests: + - name_template: "garethgeorge/backrest:latest" + image_templates: + - "garethgeorge/backrest:{{ .Tag }}-alpine-amd64" + - "garethgeorge/backrest:{{ .Tag }}-alpine-arm64" + - name_template: "garethgeorge/backrest:v{{ .Major }}" + image_templates: + - "garethgeorge/backrest:{{ .Tag }}-alpine-amd64" + - "garethgeorge/backrest:{{ .Tag }}-alpine-arm64" + - name_template: "garethgeorge/backrest:v{{ .Major }}.{{ .Minor }}" + image_templates: + - "garethgeorge/backrest:{{ .Tag }}-alpine-amd64" + - "garethgeorge/backrest:{{ .Tag }}-alpine-arm64" + - name_template: "garethgeorge/backrest:{{ .Tag }}" + image_templates: + - "garethgeorge/backrest:{{ .Tag }}-alpine-amd64" + - "garethgeorge/backrest:{{ .Tag }}-alpine-arm64" + - name_template: "garethgeorge/backrest:latest-alpine" + image_templates: + - "garethgeorge/backrest:{{ .Tag }}-alpine-amd64" + - "garethgeorge/backrest:{{ .Tag }}-alpine-arm64" + - name_template: "garethgeorge/backrest:scratch" + image_templates: + - "garethgeorge/backrest:{{ .Tag }}-scratch-amd64" + - "garethgeorge/backrest:{{ .Tag }}-scratch-arm64" + - "garethgeorge/backrest:{{ .Tag }}-scratch-armv6" + - name_template: "garethgeorge/backrest:v{{ .Major }}-scratch" + image_templates: + - "garethgeorge/backrest:{{ .Tag }}-scratch-amd64" + - "garethgeorge/backrest:{{ .Tag }}-scratch-arm64" + - "garethgeorge/backrest:{{ .Tag }}-scratch-armv6" + - name_template: "garethgeorge/backrest:v{{ .Major }}.{{ .Minor }}-scratch" + image_templates: + - "garethgeorge/backrest:{{ .Tag }}-scratch-amd64" + - "garethgeorge/backrest:{{ .Tag }}-scratch-arm64" + - "garethgeorge/backrest:{{ .Tag }}-scratch-armv6" + - name_template: "garethgeorge/backrest:{{ .Tag }}-scratch" + image_templates: + - "garethgeorge/backrest:{{ .Tag }}-scratch-amd64" + - "garethgeorge/backrest:{{ .Tag }}-scratch-arm64" + - "garethgeorge/backrest:{{ .Tag }}-scratch-armv6" + +brews: + - name: backrest + homepage: https://github.com/garethgeorge/backrest + description: "Backrest is a web UI and orchestrator for restic backup." + + url_template: "https://github.com/garethgeorge/backrest/releases/download/{{ .Tag }}/{{ .ArtifactName }}" + + commit_author: + name: goreleaserbot + email: bot@goreleaser.com + + repository: + owner: garethgeorge + name: homebrew-backrest-tap + branch: main + token: "{{ .Env.HOMEBREW_GITHUB_TOKEN }}" + + service: | + run opt_bin/"backrest" + error_log_path var/"log/backrest.log" + log_path var/"log/backrest.log" + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + +release: + github: + owner: garethgeorge + name: backrest diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..6893fe39c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug Go backend", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${workspaceFolder}/backrest.go", + "output": "__debug_bin", + "preLaunchTask": "Build Webui" + }, + { + "type": "chrome", + "request": "launch", + "preLaunchTask": "Parcel", + "postDebugTask": "Terminate Parcel", + "name": "Debug TS frontend", + "url": "http://localhost:1234", + "webRoot": "${workspaceFolder}/webui/src/", + "sourceMapPathOverrides": { + "../*": "${webRoot}/*" + } + } + ], + "compounds": [ + { + "name": "Debug Backrest (backend+frontend)", + "configurations": ["Debug Go backend", "Debug TS frontend"], + "stopAll": true + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..7301b866e --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,51 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "npm i", + "type": "shell", + "command": "cd webui && npm i" + }, + { + "label": "Parcel", + "type": "npm", + "script": "start", + "dependsOn": "npm i", + "isBackground": true, + "problemMatcher": { + "background": { + "activeOnStart": true, + "beginsPattern": "parcel serve", + "endsPattern": "Built in" + }, + "pattern": { + "regexp": ".*" + } + }, + "path": "webui" + }, + { + "label": "Build Webui", + "type": "npm", + "script": "build", + "path": "webui", + "group": "build", + "problemMatcher": [], + "dependsOn": "npm i" + }, + { + "label": "Terminate Parcel", + "command": "echo ${input:terminate}", + "type": "shell", + "problemMatcher": [] + } + ], + "inputs": [ + { + "id": "terminate", + "type": "command", + "command": "workbench.action.tasks.terminate", + "args": "Parcel" + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..82b157135 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,677 @@ +# Changelog + +## [1.6.2](https://github.com/garethgeorge/backrest/compare/v1.6.1...v1.6.2) (2024-11-26) + + +### Bug Fixes + +* allow 'run command' tasks to proceed in parallel to other repo operations ([3397a01](https://github.com/garethgeorge/backrest/commit/3397a011a3bbbdac2f7299ea4f869cd71b2d0a22)) +* allow for deleting individual operations from the list view ([aa39ead](https://github.com/garethgeorge/backrest/commit/aa39ead0e1f223e7fe7c0ce6fe4dbbc3c3050728)) +* better defaults in add repo / add plan views ([4d7be23](https://github.com/garethgeorge/backrest/commit/4d7be23e8cfd959e93f202eb52c8065446446d07)) +* crash on arm32 device due to bad libc dependency version for sqlite driver ([#559](https://github.com/garethgeorge/backrest/issues/559)) ([e60a4fb](https://github.com/garethgeorge/backrest/commit/e60a4fbcd7b695b03ae5402868ae3c4795cb04c6)) +* garbage collection with more sensible limits grouped by plan/repo ([#555](https://github.com/garethgeorge/backrest/issues/555)) ([492beb2](https://github.com/garethgeorge/backrest/commit/492beb29352ba5e5dc824d35dfaa58eed4422b8a)) +* improve memory pressure from getlogs ([592e4cf](https://github.com/garethgeorge/backrest/commit/592e4cf9dd60eaad1a660c4d69fb4ffea79c98cd)) +* improve windows installer and relocate backrest on Windows to %localappdata%\programs ([#568](https://github.com/garethgeorge/backrest/issues/568)) ([00b0c3e](https://github.com/garethgeorge/backrest/commit/00b0c3e1d256a552aa05a8a90ae05e60d35c5c96)) +* make cancel button more visible for a running operation ([51a6683](https://github.com/garethgeorge/backrest/commit/51a66839ff608fa0e3e60a6a48ca5d490628368e)) +* set etag header to cache webUI source ([0642f4b](https://github.com/garethgeorge/backrest/commit/0642f4b65a11daab379708d7ed813ca8d6a2140f)) +* substantially improve windows installer experience ([#578](https://github.com/garethgeorge/backrest/issues/578)) ([74eb869](https://github.com/garethgeorge/backrest/commit/74eb8692638c04f49004c8312ed57123ea4b5cc2)) +* tray app infers UI port from BACKREST_PORT or --bind-address if available ([c810d27](https://github.com/garethgeorge/backrest/commit/c810d27375c39a9938ad4bde433dfe5997d56bfa)) +* update resticinstaller to use the same binary name across versions and to use system restic install when possible ([5fea5fd](https://github.com/garethgeorge/backrest/commit/5fea5fdefdc2bad7fccb1f0cc0ea57fbe79bbcbb)) +* use command mode when executing powershell scripts on windows ([#569](https://github.com/garethgeorge/backrest/issues/569)) ([57f9aeb](https://github.com/garethgeorge/backrest/commit/57f9aeb72a6db240824998cff91c0921c68a336a)) +* webui may duplicate elements in a multi-instance repo ([bf77bab](https://github.com/garethgeorge/backrest/commit/bf77baba06c7296ade830e10238f1a02d0cea95c)) + +## [1.6.1](https://github.com/garethgeorge/backrest/compare/v1.6.0...v1.6.1) (2024-10-20) + + +### Bug Fixes + +* login form has no background ([4fc28d6](https://github.com/garethgeorge/backrest/commit/4fc28d68a60721d333be96df2030ce53b04fbf55)) +* stats operation occasionally runs twice in a row ([36543c6](https://github.com/garethgeorge/backrest/commit/36543c681ac1f138e4d207f96c143b1d1ffd84fe)) +* tarlog migration fails on new installs ([5617f3f](https://github.com/garethgeorge/backrest/commit/5617f3fbe2aa5278c2b8b1903997980a9e2e16b0)) + +## [1.6.0](https://github.com/garethgeorge/backrest/compare/v1.5.1...v1.6.0) (2024-10-20) + + +### Features + +* add a summary dashboard as the "main view" when backrest opens ([#518](https://github.com/garethgeorge/backrest/issues/518)) ([4b3c7e5](https://github.com/garethgeorge/backrest/commit/4b3c7e53d5b8110c179c486c3423ef9ff72feb8f)) +* add watchdog thread to reschedule tasks when system time changes ([66a5241](https://github.com/garethgeorge/backrest/commit/66a5241de8cf410d0766d7e70de9b8f87e6aaddd)) +* initial support for healthchecks.io notifications ([#480](https://github.com/garethgeorge/backrest/issues/480)) ([f6ee51f](https://github.com/garethgeorge/backrest/commit/f6ee51fce509808d8dde3d2af21d10994db381ca)) +* migrate oplog history from bbolt to sqlite store ([#515](https://github.com/garethgeorge/backrest/issues/515)) ([0806eb9](https://github.com/garethgeorge/backrest/commit/0806eb95a044fd5f1da44aff7713b0ca21f7aee5)) +* support --skip-if-unchanged ([afcecae](https://github.com/garethgeorge/backrest/commit/afcecaeb3064782788a4ff41fc31a541d93e844f)) +* track long running generic commands in the oplog ([#516](https://github.com/garethgeorge/backrest/issues/516)) ([28c3172](https://github.com/garethgeorge/backrest/commit/28c31720f249763e2baee43671475c128d17b020)) +* use react-router to enable linking to webUI pages ([#522](https://github.com/garethgeorge/backrest/issues/522)) ([fff3dbd](https://github.com/garethgeorge/backrest/commit/fff3dbd299163b916ae0c6819c9c0170e2e77dd9)) +* use sqlite logstore ([#514](https://github.com/garethgeorge/backrest/issues/514)) ([4d557a1](https://github.com/garethgeorge/backrest/commit/4d557a1146b064ee41d74c80667adcd78ed4240c)) + + +### Bug Fixes + +* expand env vars in flags i.e. of the form ${MY_ENV_VAR} ([d7704cf](https://github.com/garethgeorge/backrest/commit/d7704cf057989af4ed2f03e81e46a6a924f833cd)) +* gorelaeser docker image builds for armv6 and armv7 ([4fa30e3](https://github.com/garethgeorge/backrest/commit/4fa30e3f7ee7456d2bdf4afccb47918d01bdd32e)) +* plan/repo settings button hard to click ([ec89cfd](https://github.com/garethgeorge/backrest/commit/ec89cfde518e3c38697e6421fa7e1bca31040602)) + +## [1.5.1](https://github.com/garethgeorge/backrest/compare/v1.5.0...v1.5.1) (2024-09-18) + + +### Bug Fixes + +* **docs:** correct minor spelling and grammar errors ([#479](https://github.com/garethgeorge/backrest/issues/479)) ([df55681](https://github.com/garethgeorge/backrest/commit/df5568132b56d38f0ce155e546ff110a943ad87a)) +* prunepolicy.max_unused_percent should allow decimal values ([3056203](https://github.com/garethgeorge/backrest/commit/3056203127b4ced26e69da2a7540d4b139dcd8e9)) +* stats panel can fail to load when an incomplete operation is in the log ([d59c6fc](https://github.com/garethgeorge/backrest/commit/d59c6fc1bed06718c49fc87bfc5bf143a10ac5ed)) +* update to newest restic bugfix release 0.17.1 ([d2650fd](https://github.com/garethgeorge/backrest/commit/d2650fdd591f2bdb08dce8fe55afaba0a5659e31)) +* windows installation for restic 0.17.1 ([#474](https://github.com/garethgeorge/backrest/issues/474)) ([4da9d89](https://github.com/garethgeorge/backrest/commit/4da9d89749fd1bdfd9701c8efb83b69a7eef3395)) + +## [1.5.0](https://github.com/garethgeorge/backrest/compare/v1.4.0...v1.5.0) (2024-09-10) + + +### Features + +* add prometheus metrics ([#459](https://github.com/garethgeorge/backrest/issues/459)) ([daacf28](https://github.com/garethgeorge/backrest/commit/daacf28699c18b27256cb4bf2eb3d9caf94a5ce8)) +* compact the scheduling UI and use an enum for clock configuration ([#452](https://github.com/garethgeorge/backrest/issues/452)) ([9205da1](https://github.com/garethgeorge/backrest/commit/9205da1d2380410d1ccc4507008f28d4fa60dd32)) +* implement 'on error retry' policy ([#428](https://github.com/garethgeorge/backrest/issues/428)) ([038bc87](https://github.com/garethgeorge/backrest/commit/038bc87070361ff3b7d9a90c075787e9ff3948f7)) +* implement scheduling relative to last task execution ([#439](https://github.com/garethgeorge/backrest/issues/439)) ([6ed1280](https://github.com/garethgeorge/backrest/commit/6ed1280869bf42d1901ca09a5cc6b316a1cd8394)) +* support live logrefs for in-progress operations ([#456](https://github.com/garethgeorge/backrest/issues/456)) ([bfaad8b](https://github.com/garethgeorge/backrest/commit/bfaad8b69e95e13006d3f64e6daa956dc060833c)) + + +### Bug Fixes + +* apply oplog migrations correctly using new storage interface ([491a6a6](https://github.com/garethgeorge/backrest/commit/491a6a67254e40167b6937f6844123de704d5182)) +* backrest can erroneously show 'forget snapshot' button for restore entries ([bfde425](https://github.com/garethgeorge/backrest/commit/bfde425c2d03b0e4dc7c19381cb604dcba9d36e3)) +* broken refresh and sizing for mobile view in operation tree ([0d01c5c](https://github.com/garethgeorge/backrest/commit/0d01c5c31773de996465574e77bc90fa64586e59)) +* bugs in displaying repo / plan / activity status ([cceda4f](https://github.com/garethgeorge/backrest/commit/cceda4fdea5f6c2072e8641d33fffe160613dcf7)) +* double display of snapshot ID for 'Snapshots' in operation tree ([80dbe91](https://github.com/garethgeorge/backrest/commit/80dbe91729efebe88d4ad8e9c4160d48254d0fc1)) +* hide system operations in tree view ([8c1cf79](https://github.com/garethgeorge/backrest/commit/8c1cf791bbc2a5fc0ff279f9ba52d372c123f2d2)) +* misc bugs in restore operation view and activity bar view ([656ac9e](https://github.com/garethgeorge/backrest/commit/656ac9e1b2f2ce82f5afd4a20a729b710d19c541)) +* misc bugs related to new logref support ([97e3f03](https://github.com/garethgeorge/backrest/commit/97e3f03b78d9af644aaa9f4b2e4882514c85025a)) +* misc logging improvements ([1879ddf](https://github.com/garethgeorge/backrest/commit/1879ddfa7991f44bd54d3de9d14d7b7c03472c78)) +* new config validations make it harder to lock yourself out of backrest ([c419861](https://github.com/garethgeorge/backrest/commit/c4198619aa93fa216b9b2744cb7e4214e23c6ac6)) +* reformat tags row in operation list ([0eb560d](https://github.com/garethgeorge/backrest/commit/0eb560ddfb46f33d8404d0e7ac200d7574f64797)) +* remove migrations for fields that have been since backrest 1.0.0 ([#453](https://github.com/garethgeorge/backrest/issues/453)) ([546482f](https://github.com/garethgeorge/backrest/commit/546482f11533668b58d5f5eead581a053b19c28d)) +* restic cli commands through 'run command' are cancelled when closing dialogue ([bb00afa](https://github.com/garethgeorge/backrest/commit/bb00afa899b17c23f6375a5ee23d3c5354f5df4d)) +* simplify auth handling ([6894128](https://github.com/garethgeorge/backrest/commit/6894128d90c1d50c9da53276e4dd6b37c5357402)) +* test fixes for windows file restore ([44585ed](https://github.com/garethgeorge/backrest/commit/44585ede613b87189c38f5cd456a109e653cdf64)) +* UI quality of life improvements ([cc173aa](https://github.com/garethgeorge/backrest/commit/cc173aa7b1b9dda10cfb14ca179c9701d15f22f5)) +* use 'restic restore <snapshot id>:' for restore operations ([af09e47](https://github.com/garethgeorge/backrest/commit/af09e47cdda921eb11cab970939740adb1612af4)) +* write debug-level logs to data dir on all platforms ([a9eb786](https://github.com/garethgeorge/backrest/commit/a9eb786db90f977984b13c3bda7f764d6dadbbef)) + +## [1.4.0](https://github.com/garethgeorge/backrest/compare/v1.3.1...v1.4.0) (2024-08-15) + + +### Features + +* accept up to 2 decimals of precision for check % and prune % policies ([5374273](https://github.com/garethgeorge/backrest/commit/53742736f9dec217527ad50caed9a488da39ad45)) +* add UI support for new summary details introduced in restic 0.17.0 ([4859e52](https://github.com/garethgeorge/backrest/commit/4859e528c73853d4597c5ef54d3054406a5c7e44)) +* start tracking snapshot summary fields introduced in restic 0.17.0 ([505765d](https://github.com/garethgeorge/backrest/commit/505765dff978c5ecabe1986907b4c4c0c5112daf)) +* update to restic 0.17.0 ([#416](https://github.com/garethgeorge/backrest/issues/416)) ([500f2ee](https://github.com/garethgeorge/backrest/commit/500f2ee6c0d8bcf65a37462d3d03452cd9dff817)) + + +### Bug Fixes + +* activitybar does not reset correctly when an in-progress operation is deleted ([244fe7e](https://github.com/garethgeorge/backrest/commit/244fe7edd203b566709dc7f14091865bc9ed6700)) +* add condition_snapshot_success to .EventName ([#410](https://github.com/garethgeorge/backrest/issues/410)) ([c45f0f3](https://github.com/garethgeorge/backrest/commit/c45f0f3c668df44ba82e0d6faf73cfd8f39f0c2a)) +* backrest should only initialize repos explicitly added through WebUI ([62a97a3](https://github.com/garethgeorge/backrest/commit/62a97a335df3858a53eba34e7b7c0f69e3875d88)) +* forget snapshot by ID should not require a plan ([49e46b0](https://github.com/garethgeorge/backrest/commit/49e46b04a06eb75829df2f97726d850749e29b74)) +* hide cron options for hours/minutes/days of week for infrequent schedules ([7c091e0](https://github.com/garethgeorge/backrest/commit/7c091e05973addaa35850774320f5e49fe016437)) +* improve debug output when trying to configure a new repo ([11b3e99](https://github.com/garethgeorge/backrest/commit/11b3e9915211c8c4a06f9f6f0c30f07f005a0036)) +* possible race condition leading to rare panic in GetOperationEvents ([f250adf](https://github.com/garethgeorge/backrest/commit/f250adf4a025dcb64cb569a8cb26fa0443b56fae)) +* run list snapshots after updating repo config or adding new repo ([48626b9](https://github.com/garethgeorge/backrest/commit/48626b923ea5022d9c4f2075d5c2c1ec19089499)) +* use addrepo RPC to apply validations when updating repo config ([a67c29b](https://github.com/garethgeorge/backrest/commit/a67c29b57ac7154bda87a7a460af26adacf6d11b)) + +## [1.3.1](https://github.com/garethgeorge/backrest/compare/v1.3.0...v1.3.1) (2024-07-12) + + +### Bug Fixes + +* add docker-cli to alpine backrest image ([b6f9129](https://github.com/garethgeorge/backrest/commit/b6f9129d3042a3785106ecd24801a55b80b38146)) +* add major and major.minor semantic versioned docker releases ([8db2578](https://github.com/garethgeorge/backrest/commit/8db2578b95d50dcd4abaac851c8a1a5b6e9bf15c)) +* plan _system_ not found bug when running health operations ([c19665a](https://github.com/garethgeorge/backrest/commit/c19665ab063a32e2cb0ca73a4e0eaa4cee793601)) + +## [1.3.0](https://github.com/garethgeorge/backrest/compare/v1.2.1...v1.3.0) (2024-07-11) + + +### Features + +* improve hook UX and execution model ([#357](https://github.com/garethgeorge/backrest/issues/357)) ([4d0d13e](https://github.com/garethgeorge/backrest/commit/4d0d13e39802fcf18186723372608d96b9bd58b0)) + + +### Bug Fixes + +* cannot run path relative executable errors on Windows ([c3ec9ee](https://github.com/garethgeorge/backrest/commit/c3ec9eeb4b5aa37e66ad115528b6708d438e9459)) +* improve handling of restore operations ([620caed](https://github.com/garethgeorge/backrest/commit/620caed7e3570aa7f7cb5f7279c8b6bb277d95fc)) +* operation tree key conflicts ([2dc5595](https://github.com/garethgeorge/backrest/commit/2dc55951d7047e395c0b770bc8e4d1a80ffd32d7)) + +## [1.2.1](https://github.com/garethgeorge/backrest/compare/v1.2.0...v1.2.1) (2024-07-02) + + +### Bug Fixes + +* AddPlanModal and AddRepoModal should only be closeable explicitly ([15f92fc](https://github.com/garethgeorge/backrest/commit/15f92fcd901da8c06ebd94576b09879e68bf5bc5)) +* disable sorting for excludes and iexcludes ([d7425b5](https://github.com/garethgeorge/backrest/commit/d7425b589376595999d3e3f401bb7ef77ffde991)) +* github actions release flow for windows installers ([90e0656](https://github.com/garethgeorge/backrest/commit/90e0656fc41a2b90ee24d598023ccc6996a64b9c)) +* make instance ID required field ([7c8ded2](https://github.com/garethgeorge/backrest/commit/7c8ded2fcc4b597e21c24f451e02cc14ba9a015c)) +* operation tree UI bugs ([76ce3c1](https://github.com/garethgeorge/backrest/commit/76ce3c177b6a92c105c874e459bd57e1122b5ce8)) +* restore always uses ~/Downloads path ([955771e](https://github.com/garethgeorge/backrest/commit/955771e1cc6bb7b143ef5c51ef9e1e09509f76b1)) + +## [1.1.0](https://github.com/garethgeorge/backrest/compare/v1.0.0...v1.1.0) (2024-06-01) + + +### Features + +* add windows installer and tray app ([#294](https://github.com/garethgeorge/backrest/issues/294)) ([8a7543c](https://github.com/garethgeorge/backrest/commit/8a7543c7bf7f245d87fa079c477c50b333dfba37)) +* support nice/ionice as a repo setting ([#309](https://github.com/garethgeorge/backrest/issues/309)) ([0c9f366](https://github.com/garethgeorge/backrest/commit/0c9f366e439b57007259a2ca305ac00733638566)) +* support restic check operation ([#303](https://github.com/garethgeorge/backrest/issues/303)) ([ce42f68](https://github.com/garethgeorge/backrest/commit/ce42f68d0d563defabbaafce63313fcf3835d2dd)) + + +### Bug Fixes + +* collection of ui refresh timing bugs ([b218bc9](https://github.com/garethgeorge/backrest/commit/b218bc9409bf4a6c70da06e1f98760ff520afc37)) +* improve prune and check scheduling in new repos ([c58055e](https://github.com/garethgeorge/backrest/commit/c58055ec91ccc9a8afc5d3ff402f68da00a04e66)) +* release workflow ([290d018](https://github.com/garethgeorge/backrest/commit/290d018c7585a4032b5f5d7a26f06e4d74f8b5cb)) +* snapshot browser on Windows ([19ed611](https://github.com/garethgeorge/backrest/commit/19ed611477186af2702fb7ba403b0bac45ccc4aa)) +* UI refresh timing bugs ([ba005ae](https://github.com/garethgeorge/backrest/commit/ba005aee0beb0105948901330e9ab7f7290eec92)) + +## [1.0.0](https://github.com/garethgeorge/backrest/compare/v0.17.2...v1.0.0) (2024-05-20) + + +### ⚠ BREAKING CHANGES + +* redefine hostname as a required property that maps to --host ([#256](https://github.com/garethgeorge/backrest/issues/256)) + +### Features + +* add CONDITION_SNAPSHOT_WARNING hook triggered by any warning status at the completion of a snapshot ([f0ee20f](https://github.com/garethgeorge/backrest/commit/f0ee20f53de58e0a0a0a63137e203161d8acce4d)) +* add download link to create a zip archive of restored files ([a75a5c2](https://github.com/garethgeorge/backrest/commit/a75a5c2297df4eb89235a54efd38d9539b7c15e5)) +* add force kill signal handler that dumps stacks ([386f46a](https://github.com/garethgeorge/backrest/commit/386f46a090e6df28f28cbca15d992ce4ad6d5dd5)) +* add seek support to join iterator for better performance ([802146a](https://github.com/garethgeorge/backrest/commit/802146a6c023779d6e5e0879994ec7dc5479e304)) +* ensure instance ID is set for all operations ([65d4a1d](https://github.com/garethgeorge/backrest/commit/65d4a1df0e9e717f5f88d7c5bec37f18d877b876)) +* implement 'run command' button to execute arbitrary restic commands in a repo ([fbad981](https://github.com/garethgeorge/backrest/commit/fbad981a1d3ae75c1eeebf9fd3bf4cef4f72b4c4)) +* improve support for instance ID tag ([be0cdd5](https://github.com/garethgeorge/backrest/commit/be0cdd59be270e0393dc4d587bfa708c610ac0a5)) +* keep a rolling backup of the last 10 config versions ([1a053f2](https://github.com/garethgeorge/backrest/commit/1a053f274846e822ecfd3c76e0d1b4860fada58a)) +* overhaul task interface and introduce 'flow ID' for simpler grouping of operations ([#253](https://github.com/garethgeorge/backrest/issues/253)) ([7a10bdc](https://github.com/garethgeorge/backrest/commit/7a10bdca7b00f337a2c85780861e479b7aa35cb5)) +* redefine hostname as a required property that maps to --host ([#256](https://github.com/garethgeorge/backrest/issues/256)) ([4847010](https://github.com/garethgeorge/backrest/commit/484701007ff2f7f80fff308827b1af456a78cbb9)) +* support env variable substitution e.g. FOO=${MY_FOO_VAR} ([8448f4c](https://github.com/garethgeorge/backrest/commit/8448f4cc3aebd1b481fc695c2aa0d02e18689a20)) +* unified scheduling model ([#282](https://github.com/garethgeorge/backrest/issues/282)) ([531cd28](https://github.com/garethgeorge/backrest/commit/531cd286d87c8004b95bfd9b4512dffccc6d500d)) +* update snapshot management to track and filter on instance ID, migrate existing snapshots ([5a996d7](https://github.com/garethgeorge/backrest/commit/5a996d74b06dcf6c1439cac9134ec51ba7167c15)) +* validate plan ID and repo ID ([f314c7c](https://github.com/garethgeorge/backrest/commit/f314c7cced2db23a4008622c97a27697c832c664)) + + +### Bug Fixes + +* add virtual root node to snapshot browser ([6045c87](https://github.com/garethgeorge/backrest/commit/6045c87cdf5a68afd81203602ee5827eda5af8e7)) +* additional tooltips for add plan modal ([fcdf07d](https://github.com/garethgeorge/backrest/commit/fcdf07da6c330aed7fea017835cbbf56679b3749)) +* adjust task priorities ([756e64a](https://github.com/garethgeorge/backrest/commit/756e64a2002aead213d67c8d37d851688af51168)) +* center-right align settings icons for plans/repos ([982e2fb](https://github.com/garethgeorge/backrest/commit/982e2fb2cd84fe193a4b37bda8c21f75c8eb3382)) +* concurrency issues in run command handler ([411a4fb](https://github.com/garethgeorge/backrest/commit/411a4fb6f00fd46f1fbdb0b8e3a971d016a6e0f8)) +* date formatting ([b341146](https://github.com/garethgeorge/backrest/commit/b341146fce40ee8bdaf771c4c5269160198b6386)) +* downgrade omission of 'instance' field from an error to a warning ([6ae82f7](https://github.com/garethgeorge/backrest/commit/6ae82f70d456c05b3ad0ab01e901be8bd01bb9eb)) +* error formatting for repo init ([1a3ace9](https://github.com/garethgeorge/backrest/commit/1a3ace90141a48e949c6c796fa8445de134baa98)) +* hide successful hook executions in the backup view ([65bb8ef](https://github.com/garethgeorge/backrest/commit/65bb8ef14b77cfe07c2db26e0fcc8e0bbc1a9287)) +* improve cmd error formatting now that logs are available for all operations ([6eb704f](https://github.com/garethgeorge/backrest/commit/6eb704f07bfae1cfc25208bc1a20908d229f344e)) +* improve concurrency handling in RunCommand ([07b0950](https://github.com/garethgeorge/backrest/commit/07b09502b9554386afa7bd4c5487f9b8da3a59bb)) +* improve download speeds for restored files ([eb07931](https://github.com/garethgeorge/backrest/commit/eb079317c05946fb74a74e59592940ada9eef4ea)) +* install.sh was calling systemctl on Darwin ([#260](https://github.com/garethgeorge/backrest/issues/260)) ([f6d5837](https://github.com/garethgeorge/backrest/commit/f6d58376b76707de36d851808812d6b3384e2ca9)) +* minor bugs and tweak log rotation history to 14 days ([ad9a770](https://github.com/garethgeorge/backrest/commit/ad9a77029ce07a5bb7da2738b108d0f93cb57440)) +* miscellaneous bug fixes ([df4be0f](https://github.com/garethgeorge/backrest/commit/df4be0f7bc014a3862f14fcf79cffc53f45c6ea0)) +* prompt for user action to set an instance ID on upgrade ([294864f](https://github.com/garethgeorge/backrest/commit/294864fe433302571ba9ff9eb7c2dd475fa1c560)) +* rebase stats panel onto a better chart library ([b22028e](https://github.com/garethgeorge/backrest/commit/b22028eb4f185be96ff4407fccafa2d1cdf491a1)) +* reserve IDs starting and ending with '__' for internal use ([711064f](https://github.com/garethgeorge/backrest/commit/711064fb0017830bc148643617ca8da5aa0add41)) +* retention policy display may show default values for some fields ([9d6c1ba](https://github.com/garethgeorge/backrest/commit/9d6c1baf87c31b7a2cfb633fdd228d58021f7b0f)) +* run stats after every prune operation ([7fce593](https://github.com/garethgeorge/backrest/commit/7fce59311d531cb9058965cde780f8930cd98a9b)) +* schedule view bug ([0764804](https://github.com/garethgeorge/backrest/commit/0764804ea558df6edd5e65ca1ea9c843a75fc147)) +* secure download URLs when downloading tar archive of exported files ([a30d5ef](https://github.com/garethgeorge/backrest/commit/a30d5efe1c354dd6f6c91d3b1465a244077e1e47)) +* UI fixes for restore row and settings modal ([e9d6cbe](https://github.com/garethgeorge/backrest/commit/e9d6cbeaff03675928e036461a999cb4bde64e54)) +* use int64 for large values in structs for compatibility with 32bit devices ([#250](https://github.com/garethgeorge/backrest/issues/250)) ([84b4b68](https://github.com/garethgeorge/backrest/commit/84b4b68760ded53d9bda2fbc992646f309094f52)) +* use locale to properly format time ([89a49c1](https://github.com/garethgeorge/backrest/commit/89a49c1fa7c6cafedef30bdf695e76920e2c690c)) + +## [0.17.2](https://github.com/garethgeorge/backrest/compare/v0.17.1...v0.17.2) (2024-04-18) + +### Bug Fixes + +- add tini to docker images to reap rclone processes left behind by restic ([6408518](https://github.com/garethgeorge/backrest/commit/6408518582fb2a1b529f5c9fb0c595df230f3df6)) +- armv7 support for docker releases ([ec39533](https://github.com/garethgeorge/backrest/commit/ec39533e4cddf2f0354ec3fcb4c52ba37a9b00ec)) +- bug in new task queue implementation ([5d6074e](https://github.com/garethgeorge/backrest/commit/5d6074eb296e6737f1959fba913c67e09e60ef47)) +- improve restic pkg's output handling and buffering ([aacdf9b](https://github.com/garethgeorge/backrest/commit/aacdf9b7cd529a6f677cd7f1d9ed2fbbcadc9b8a)) +- Linux ./install.sh script fails when used for updating backrest ([#226](https://github.com/garethgeorge/backrest/issues/226)) ([be09303](https://github.com/garethgeorge/backrest/commit/be0930368b83ba8f159b28bc286300c56bd6a3a3)) +- use new orchestrator queue ([4a81889](https://github.com/garethgeorge/backrest/commit/4a81889d810d409ed42fcf07a0fa6a4ac97db72b)) + +## [0.17.1](https://github.com/garethgeorge/backrest/compare/v0.17.0...v0.17.1) (2024-04-12) + +### Bug Fixes + +- revert orchestrator changes ([07cffcb](https://github.com/garethgeorge/backrest/commit/07cffcb5d8dc018631fcd0d1f98cc01553a6574e)) + +## [0.17.0](https://github.com/garethgeorge/backrest/compare/v0.16.0...v0.17.0) (2024-04-12) + +### Features + +- add a Bash script to help Linux user manage Backrest ([#187](https://github.com/garethgeorge/backrest/issues/187)) ([d78bcfa](https://github.com/garethgeorge/backrest/commit/d78bcfab845a86523868a91fe200b2a3c4c07e07)) +- allow hook exit codes to control backup execution (e.g fail, skip, etc) ([c4ae5b3](https://github.com/garethgeorge/backrest/commit/c4ae5b3f2257d6c04ed08188cfc509023137b460)) +- release backrest as a homebrew tap ([16a7d0e](https://github.com/garethgeorge/backrest/commit/16a7d0e95ae51c9f86e2d38e2c494b324245a9db)) +- use amd64 restic for arm64 Windows ([#201](https://github.com/garethgeorge/backrest/issues/201)) ([3770966](https://github.com/garethgeorge/backrest/commit/3770966111f096c84b4702e6639397e8efab93a7)) +- use new task queue implementation in orchestrator ([1d04898](https://github.com/garethgeorge/backrest/commit/1d0489847e6fee5baed807117379738aceca4a2d)) + +### Bug Fixes + +- address minor data race in command output handling and enable --race in coverage ([3223138](https://github.com/garethgeorge/backrest/commit/32231385ed20c0dccda12361eaac7cc088ec15a0)) +- bugs in refactored task queue and improved coverage ([834b74f](https://github.com/garethgeorge/backrest/commit/834b74f0f3eec42055d1af6ecfe34d448f71d97b)) +- cannot set retention policy buckets to 0 ([7e9bf15](https://github.com/garethgeorge/backrest/commit/7e9bf15976006c7f3ff96948d2b2c291737c9e88)) +- **css:** fixing overflow issue ([#191](https://github.com/garethgeorge/backrest/issues/191)) ([1d9e43e](https://github.com/garethgeorge/backrest/commit/1d9e43e49b21adc4ed8ce1ec96199084981d709a)) +- default BACKREST_PORT to 127.0.0.1:9898 (localhost only) when using install.sh ([eb07230](https://github.com/garethgeorge/backrest/commit/eb07230cc0843643406fa44ca21c3a138baced77)) +- handle backpressure correctly in event stream ([4e2bf1f](https://github.com/garethgeorge/backrest/commit/4e2bf1f76c4d35d61fc48111baaa33b7b7a8c133)) +- improve tooltips on AddRepoModal ([e2be189](https://github.com/garethgeorge/backrest/commit/e2be189f9e4bb617a69e4b9c15da3d1920549349)) +- include ioutil helpers ([88a926b](https://github.com/garethgeorge/backrest/commit/88a926b0a3a52efb82da5df3423a001ed140639c)) +- limit cmd log length to 32KB per operation ([92d52be](https://github.com/garethgeorge/backrest/commit/92d52bed8e84d6cd8dd331a1fa52a6e2d30cb7a7)) +- misc UI and backend bug fixes ([e96f403](https://github.com/garethgeorge/backrest/commit/e96f4036df6849650d6e378c9a175fef86b2962b)) +- refactor priority ordered task queue implementation ([8b9280e](https://github.com/garethgeorge/backrest/commit/8b9280ed57b84b7da814e285542c57b7c14209ae)) +- spawn goroutine to update oplog with progress during backup/restore ([eab1c1b](https://github.com/garethgeorge/backrest/commit/eab1c1bffe2a1aec6afa9e054278ff98ca3047cf)) +- use C:\Program Files\backrest on both x64 and 32-bit ([#200](https://github.com/garethgeorge/backrest/issues/200)) ([7b0d3aa](https://github.com/garethgeorge/backrest/commit/7b0d3aa1be7bc93363b00154d09502b4e4e63ba5)) + +## [0.16.0](https://github.com/garethgeorge/backrest/compare/v0.15.1...v0.16.0) (2024-03-30) + +### Features + +- allow disabling authentication ([8429174](https://github.com/garethgeorge/backrest/commit/84291746af5fc863f90bcf7ae9ba5a2d3ca26cdd)) +- improve consistency of restic command execution and output capture ([16e22aa](https://github.com/garethgeorge/backrest/commit/16e22aa623c5a0a6e6b0e6df12a8e3d09c2ff31f)) +- improve observability by exposing restic command logs in UI ([eeb8c8e](https://github.com/garethgeorge/backrest/commit/eeb8c8e6b377f96c0c39bd2b169b86986933d570)) +- make hostname configurable in settings panel ([2e4e3cf](https://github.com/garethgeorge/backrest/commit/2e4e3cf9c78cac587a3a40635ec068726b3f4d2d)) +- sort lists in configuration ([6f330ac](https://github.com/garethgeorge/backrest/commit/6f330ac37b8ce621fbe82594c41d6f5091f03dfd)) +- support shoutrrr notification service ([fa6407c](https://github.com/garethgeorge/backrest/commit/fa6407cac25ed8f0a32cc9ed5fdd8454bc9abbe5)) +- switch alpine as the default base image for docker releases ([7425c9b](https://github.com/garethgeorge/backrest/commit/7425c9bb0e08cf650e596ae43a736507313e3f2f)) +- update macos install script to set PATH env var for use with rclone ([8cf43f2](https://github.com/garethgeorge/backrest/commit/8cf43f28921ef7182f1c655fa82470e74698d3ce)) + +### Bug Fixes + +- add new logs to orchestrator and increase clock change polling to every 5 minutes ([5b7e2b0](https://github.com/garethgeorge/backrest/commit/5b7e2b080d31a2f77a5f9b6737dfbb84cfb63cce)) +- api path relative to UI serving location to support reverse proxies with prefix stripping ([ac7f24e](https://github.com/garethgeorge/backrest/commit/ac7f24ed04679ed6cc3ea779325c0e0b49c9f526)) +- cleanup spacing and hook titles in AddRepoModal and AddPlanModal ([c32874c](https://github.com/garethgeorge/backrest/commit/c32874c1d6fc8292a2fb91f0b22c7146083bc468)) +- correctly auto-expand first 5 backups when opening plan/repo ([d7ca35b](https://github.com/garethgeorge/backrest/commit/d7ca35b66f61c12360905e98b775e3256210176e)) +- include error messages in restic logs ([b68f7c6](https://github.com/garethgeorge/backrest/commit/b68f7c69138d516f84f9fca3040003604bff24e6)) +- include restic binary in alpine and scratch docker images ([f7bd9f7](https://github.com/garethgeorge/backrest/commit/f7bd9f7d0a9c62baedd1a341eb76e836fb00cfa5)) +- incorrectly indicate AM/PM in formatted date strings ([5d34e0b](https://github.com/garethgeorge/backrest/commit/5d34e0bfb5cffd44d971b0e1052574fe640049e7)) +- make notification title optional on discord notifications ([e8bbe2c](https://github.com/garethgeorge/backrest/commit/e8bbe2c8f509de67181750f8451fae841b3fa195)) +- make tree view the default panel for repo overview ([3f9c9f4](https://github.com/garethgeorge/backrest/commit/3f9c9f4ff8bea0f79b03222609d7c302e241bab2)) +- tasks duplicated when config is updated during a running operation ([035684c](https://github.com/garethgeorge/backrest/commit/035684ca343b47dfb3f131c89e15f06e8155f550)) + +## [0.15.1](https://github.com/garethgeorge/backrest/compare/v0.15.0...v0.15.1) (2024-03-19) + +### Bug Fixes + +- forget operations failing with new retention policy format ([0a059bb](https://github.com/garethgeorge/backrest/commit/0a059bbb39ea6d5f6f989cc4a4541ec8aedbc071)) + +## [0.15.0](https://github.com/garethgeorge/backrest/compare/v0.13.0...v0.15.0) (2024-03-19) + +### Features + +- add 'compute stats' button to refresh stats on repo view ([1f42b6a](https://github.com/garethgeorge/backrest/commit/1f42b6ab4e0313bbb12e6bc22b561d7544504644)) +- add option to disable scheduled execution of a plan ([aea74c5](https://github.com/garethgeorge/backrest/commit/aea74c51c0fb3908ece57f813c9ae6190e1fd46b)) +- add release artifacts for arm32 ([a737371](https://github.com/garethgeorge/backrest/commit/a737371ed559f5b65e734b0d97c44dcb2749ce53)) +- automatically remove Apples quarantine flag ([#155](https://github.com/garethgeorge/backrest/issues/155)) ([3e76beb](https://github.com/garethgeorge/backrest/commit/3e76bebd054eb7bfc9f8da4681459b863ae50c55)) +- check for basic auth ([#110](https://github.com/garethgeorge/backrest/issues/110)) ([#129](https://github.com/garethgeorge/backrest/issues/129)) ([871c54f](https://github.com/garethgeorge/backrest/commit/871c54f35f8651632714ca7d3a3ab0e809549b51)) +- improved stats visualization with graphs and cleanup operation filtering ([5b362cc](https://github.com/garethgeorge/backrest/commit/5b362ccbb45e59954dad574b93848195d45b55ef)) +- pass through all env variables from parent process to restic ([24afd51](https://github.com/garethgeorge/backrest/commit/24afd514ad80f542e6e1862d1c42195c6fbe1b47)) +- support flag overrides for 'restic backup' in plan configuration ([56f5e40](https://github.com/garethgeorge/backrest/commit/56f5e405037a6309a3d1299356b363cd84281aef)) +- use disambiguated retention policy format ([5a5a229](https://github.com/garethgeorge/backrest/commit/5a5a229f456bf3d4d34cb4751c2a2ff3b6907511)) + +### Bug Fixes + +- alpine linux Dockerfile and add openssh ([3cb9d27](https://github.com/garethgeorge/backrest/commit/3cb9d2717c1bda7bb7ed4e029ac938c851b9f664)) +- backrest shows hidden operations in list view ([c013f06](https://github.com/garethgeorge/backrest/commit/c013f069ff5eab6177d2bde373f23efe34b1aa8d)) +- BackupInfoCollector handling of filtered events ([f1e4619](https://github.com/garethgeorge/backrest/commit/f1e4619e9d98416289fb0ee51d56ff48e163b85d)) +- bugs in env var validation and form field handling ([7e909c4](https://github.com/garethgeorge/backrest/commit/7e909c4a96b053e8093f3b4f3d26c46b1c618947)) +- compression progress ratio should be float64 ([1759b5d](https://github.com/garethgeorge/backrest/commit/1759b5dc55ab17a1c76d47adee7f4e21f7ef09f5)) +- handle timezone correctly with tzdata package on alpine ([0e94f30](https://github.com/garethgeorge/backrest/commit/0e94f308cde40059f9c4104ed21f8c701a349c57)) +- install rclone with apk for alpine image ([#138](https://github.com/garethgeorge/backrest/issues/138)) ([79715a9](https://github.com/garethgeorge/backrest/commit/79715a97b34af60ca90894065d89c9ae603f0a59)) +- proper display of retention policy ([38ff5fe](https://github.com/garethgeorge/backrest/commit/38ff5fecee3ff3cdff5c7ccecb48e600eb714511)) +- properly parse repo flags ([348ec46](https://github.com/garethgeorge/backrest/commit/348ec4690cab74c3089f2be33d889df3002a5a97)) +- stat operation interval for long running repos ([f2477ab](https://github.com/garethgeorge/backrest/commit/f2477ab06cbe571723cd7290e06e8890747f81aa)) +- stats chart titles invisible on light color theme ([746fd9c](https://github.com/garethgeorge/backrest/commit/746fd9cf768f0c87a25f0015bd20289716b08604)) + +### Miscellaneous Chores + +- bump version to 0.15.0 ([db4b76d](https://github.com/garethgeorge/backrest/commit/db4b76de8ed09c9eda6216e8dfe041518f5bbfc5)) + +## [0.13.0](https://github.com/garethgeorge/backrest/compare/v0.12.2...v0.13.0) (2024-02-21) + +### Features + +- add case insensitive excludes (iexcludes) ([#108](https://github.com/garethgeorge/backrest/issues/108)) ([bf6fb7e](https://github.com/garethgeorge/backrest/commit/bf6fb7e71402590961271e91ad6da63db27ff5ad)) +- add flags to configure backrest options e.g. --config-file, --data-dir, --restic-cmd, --bind-address ([41ddc8e](https://github.com/garethgeorge/backrest/commit/41ddc8e1a9d5501a92498c8cf3c72625bd181f8a)) +- add opt-in auto-unlock feature to remove locks on forget and prune ([#107](https://github.com/garethgeorge/backrest/issues/107)) ([c1ee33f](https://github.com/garethgeorge/backrest/commit/c1ee33f0cd65a23ec0090852ee0fc5fa50e72b64)) +- add rclone binary to docker image and arm64 support ([#105](https://github.com/garethgeorge/backrest/issues/105)) ([5a49f2f](https://github.com/garethgeorge/backrest/commit/5a49f2f063e887cba85bba0347ebce3efe15753e)) +- bundle rclone, busybox commands, and bash in default backrest docker image ([cec04f8](https://github.com/garethgeorge/backrest/commit/cec04f8f745d4bcfd49829c43367c61cb9778174)) +- display non-fatal errors in backup operations (e.g. unreadable files) in UI ([#100](https://github.com/garethgeorge/backrest/issues/100)) ([caac35a](https://github.com/garethgeorge/backrest/commit/caac35a5402d056b626b59d19084d6a699d4346d)) + +### Bug Fixes + +- improve error message when rclone config is missing ([663b430](https://github.com/garethgeorge/backrest/commit/663b430598e0890df74989af12ae81fae7922251)) +- improved sidebar status refresh interval during live operations ([3d192fd](https://github.com/garethgeorge/backrest/commit/3d192fd59d98c242ed583d00eeec37e68a4a2ff5)) +- live backup progress updates with partial-backup errors ([97a4948](https://github.com/garethgeorge/backrest/commit/97a494847ac5031866c31db0bb32219e6b2a0038)) +- migrate prune policy options to oneof ([ef41d34](https://github.com/garethgeorge/backrest/commit/ef41d34d5312b6a3bcc4af536f64275cd20da657)) +- restore operations should succeed for unassociated snapshots ([448107d](https://github.com/garethgeorge/backrest/commit/448107d22612f040fd45493246088277a4a72f63)) +- separate docker images for scratch and alpine linux base ([#106](https://github.com/garethgeorge/backrest/issues/106)) ([40e3e04](https://github.com/garethgeorge/backrest/commit/40e3e04a686f0a1749fa39e15821e6310e0ccf52)) + +## [0.12.2](https://github.com/garethgeorge/backrest/compare/v0.12.1...v0.12.2) (2024-02-16) + +### Bug Fixes + +- release-please automation ([63ddf15](https://github.com/garethgeorge/backrest/commit/63ddf15bf9799de30bda8548421e11e1bcd9ed05)) + +## [0.12.1](https://github.com/garethgeorge/backrest/compare/v0.12.0...v0.12.1) (2024-02-16) + +### Bug Fixes + +- delete event button in UI is hard to see on light theme ([8a05df8](https://github.com/garethgeorge/backrest/commit/8a05df87fcc44699c890f0cbe1065d79f49e1cc2)) +- use 'embed' to package WebUI sources instead of go.rice ([e3ba5cf](https://github.com/garethgeorge/backrest/commit/e3ba5cf12ebfedafaa2125687bd7522f29ccab51)) + +## [0.12.0](https://github.com/garethgeorge/backrest/compare/v0.11.1...v0.12.0) (2024-02-15) + +### Features + +- add button to forget individual snapshots ([276b1d2](https://github.com/garethgeorge/backrest/commit/276b1d2c602ad0f787958452070771af3e69f073)) +- add slack webhook ([8fa90ab](https://github.com/garethgeorge/backrest/commit/8fa90ab9ca48f0888ed0a5d263cb697758063188)) +- Add support for multiple sets of expected env vars per repo scheme ([#90](https://github.com/garethgeorge/backrest/issues/90)) ([da0551c](https://github.com/garethgeorge/backrest/commit/da0551c19a98fe675d278e34f8e3cc58ac9edaf5)) +- clear operations from history ([dc7a3a5](https://github.com/garethgeorge/backrest/commit/dc7a3a59a2400f97dd6b8140c6e70a34105496f9)) +- Windows WebUI uses correct path separator ([f5521e7](https://github.com/garethgeorge/backrest/commit/f5521e7b56e446fa2062a95560f315621b77d3e6)) + +### Bug Fixes + +- cleanup old versions of restic when upgrading ([79f529f](https://github.com/garethgeorge/backrest/commit/79f529f8edfb9bf893e74f7b1355bd7f2d7bdc3f)) +- hide delete operation button if operation is in progress or pending ([08c8762](https://github.com/garethgeorge/backrest/commit/08c876243febb99a68740c449055e850f37d740e)) +- retention policy configuration in add plan view ([dd24d90](https://github.com/garethgeorge/backrest/commit/dd24d9024f5ade62535956b1449dae75627ce493)) +- stats operations running at wrong interval ([05e5ae0](https://github.com/garethgeorge/backrest/commit/05e5ae0c455680bf9fbc9b4b2a9fbf96bcfdfc3b)) + +## [0.11.1](https://github.com/garethgeorge/backrest/compare/v0.11.0...v0.11.1) (2024-02-08) + +### Bug Fixes + +- backrest fails to create directory for jwt secrets ([0067edf](https://github.com/garethgeorge/backrest/commit/0067edf378b01147f0041c225994098cb9c452ab)) +- form bugs in UI e.g. awkward behavior when modifying hooks ([4fcf526](https://github.com/garethgeorge/backrest/commit/4fcf52602c114e2c639fc4302a9b8e8d51180a4d)) +- update restic version to 1.16.4 ([668a7cb](https://github.com/garethgeorge/backrest/commit/668a7cb5bb5c0955a0e3186b2dd9329cedddd96f)) +- wrong field names in hooks form ([3540904](https://github.com/garethgeorge/backrest/commit/354090497b73d40d8a9e705d1aa0c4662ffc4b0e)) +- wrong value passed to --max-unused when providing a custom prune policy ([34175f2](https://github.com/garethgeorge/backrest/commit/34175f273630f7d2324a4d6b5f9f2f7576dd6608)) + +## [0.11.0](https://github.com/garethgeorge/backrest/compare/v0.10.1...v0.11.0) (2024-02-04) + +### Features + +- add user configurable command hooks for backup lifecycle events ([#60](https://github.com/garethgeorge/backrest/issues/60)) ([9be413b](https://github.com/garethgeorge/backrest/commit/9be413bbcca796862f161a769991ab695a50b464)) +- authentication for WebUI ([#62](https://github.com/garethgeorge/backrest/issues/62)) ([4a1f326](https://github.com/garethgeorge/backrest/commit/4a1f3268a7de0533e0a979b9e97a7117b028358e)) +- implement discord hook type ([25924b6](https://github.com/garethgeorge/backrest/commit/25924b6197c870f9dfc1e04f5be39377251e7f2d)) +- implement gotify hook type ([e0ce655](https://github.com/garethgeorge/backrest/commit/e0ce6558c047f3aff068ee5d475fa1bdba380c4d)) +- support keep-all retention policy for append-only backups ([f163c02](https://github.com/garethgeorge/backrest/commit/f163c02d7d2c798b4057037a996de44e34de9f2b)) + +### Bug Fixes + +- add API test coverage and fix minor bugs ([f5bb74b](https://github.com/garethgeorge/backrest/commit/f5bb74bf246fcd5712dbbc85f4233169f7db4aa7)) +- add first time setup hint for user authentication ([4a565f2](https://github.com/garethgeorge/backrest/commit/4a565f2cdcd091e0eabc302ab91e53012f53eb26)) +- add test coverage for log rotation ([f1084ca](https://github.com/garethgeorge/backrest/commit/f1084cab4894751ba4a92f9be6b6b70d9084d0e6)) +- bugfixes for auth flow ([427792c](https://github.com/garethgeorge/backrest/commit/427792c7244fb712bbea0557d4a6c7ee07052534)) +- stats not displaying on long running repos ([f1ba1d9](https://github.com/garethgeorge/backrest/commit/f1ba1d91f37234f24ae5202d27114a33432366da)) +- store large log outputs in tar bundles of logs ([0cf01e0](https://github.com/garethgeorge/backrest/commit/0cf01e020640b0145bcd0d25a38cde1fce940aff)) +- windows install errors on decompressing zip archive ([5323b9f](https://github.com/garethgeorge/backrest/commit/5323b9ffc065bc3b28171575cdccc4358b69750b)) + +## [0.10.1](https://github.com/garethgeorge/backrest/compare/v0.10.0...v0.10.1) (2024-01-25) + +### Bug Fixes + +- chmod config 0600 such that only the creating user can read ([ecff0e5](https://github.com/garethgeorge/backrest/commit/ecff0e57c1fa4d65f35774d227a27222af8e7921)) +- install scripts handle working dir correctly ([dcff2ad](https://github.com/garethgeorge/backrest/commit/dcff2adf60222030043d7a227d27e74f555ab376)) +- relax name regex for plans and repos ([ee6134a](https://github.com/garethgeorge/backrest/commit/ee6134af76c3e90f542f67b89b2571f060db5590)) +- sftp support using public key authentication ([bedb302](https://github.com/garethgeorge/backrest/commit/bedb302a025438a58309f26b046c9b6d49316414)) +- typos in validation error messages in addrepomodel ([3b79afb](https://github.com/garethgeorge/backrest/commit/3b79afb2b18530deaa10cca08a60941a64c6fd9b)) + +## [0.10.0](https://github.com/garethgeorge/backrest/compare/v0.9.3...v0.10.0) (2024-01-15) + +### Features + +- make prune policy configurable in the addrepoview in the UI ([3fd08eb](https://github.com/garethgeorge/backrest/commit/3fd08eb8e4b455db656a0680318851824fdad2db)) +- update restic dependency to v0.16.3 ([ac8db31](https://github.com/garethgeorge/backrest/commit/ac8db31713d4db3c2240b7f7c006e518e9e0726c)) +- verify gpg signature when downloading and installing restic binary ([04106d1](https://github.com/garethgeorge/backrest/commit/04106d15d5ad73db6e670e84340ac1f9be200a23)) + +## [0.9.3](https://github.com/garethgeorge/backrest/compare/v0.9.2...v0.9.3) (2024-01-05) + +### Bug Fixes + +- correctly mark tasks as inprogress before execution ([b19438a](https://github.com/garethgeorge/backrest/commit/b19438afbd7b83dc964774347e64491143a3a5d2)) +- correctly select light/dark mode based on system colortheme ([b64199c](https://github.com/garethgeorge/backrest/commit/b64199c140db7d2a77b58219cee088d22ec81954)) + +## [0.9.2](https://github.com/garethgeorge/backrest/compare/v0.9.1...v0.9.2) (2024-01-01) + +### Bug Fixes + +- possible race condition in scheduled task heap ([30874c9](https://github.com/garethgeorge/backrest/commit/30874c9150f32a0fba5f1ea99bc77bcc978d8b03)) + +## [0.9.1](https://github.com/garethgeorge/backrest/compare/v0.9.0...v0.9.1) (2024-01-01) + +### Bug Fixes + +- failed forget operations are hidden in the UI ([9896446](https://github.com/garethgeorge/backrest/commit/9896446ccfbcb8475a21b5fb565ebb73cb6bac2c)) +- UI buttons spin while waiting for tasks to complete ([c767fa7](https://github.com/garethgeorge/backrest/commit/c767fa7476d76f1b4eb49443a19ee1cedb4eb70a)) + +## [0.9.0](https://github.com/garethgeorge/backrest/compare/v0.8.1...v0.9.0) (2023-12-31) + +### Features + +- add backrest logo ([5add0d8](https://github.com/garethgeorge/backrest/commit/5add0d8ffa829a71103520c94eacae17966f2a9f)) +- add mobile layout ([9c7f227](https://github.com/garethgeorge/backrest/commit/9c7f227ad0f5df34d66390c94b64e9f5181d24f0)) +- index snapshots created outside of backrest ([7711297](https://github.com/garethgeorge/backrest/commit/7711297a84170a733c5ccdb3e89617efc878cf69)) +- schedule index operations and stats refresh from repo view ([851bd12](https://github.com/garethgeorge/backrest/commit/851bd125b640e65a5b98b67d28d2f29e94411646)) + +### Bug Fixes + +- operations associated with incorrect ID when tasks are rescheduled ([25871c9](https://github.com/garethgeorge/backrest/commit/25871c99920d8717e91bf1a921109b9df82a59a1)) +- reduce stats refresh frequency ([adbe005](https://github.com/garethgeorge/backrest/commit/adbe0056d82a5d9f890ce79b1120f5084bdc7124)) +- stat never runs ([3f3252d](https://github.com/garethgeorge/backrest/commit/3f3252d47951270fbf5f21b0831effb121d3ba3f)) +- stats task priority ([6bfe769](https://github.com/garethgeorge/backrest/commit/6bfe769fe037a5f2d35947574a5ed7e26ba981a8)) +- tasks run late when laptops resume from sleep ([cb78298](https://github.com/garethgeorge/backrest/commit/cb78298cffb492560717d5f8bdcd5941f7976f2e)) +- UI and code quality improvements ([c5e435d](https://github.com/garethgeorge/backrest/commit/c5e435d640bc8e79ceacf7f64d4cf75644859204)) + +## [0.8.0](https://github.com/garethgeorge/backrest/compare/v0.7.0...v0.8.0) (2023-12-25) + +### Features + +- add repo stats to restic package ([26d4724](https://github.com/garethgeorge/backrest/commit/26d47243c1e31f17c4d8adc6227325551854ce1f)) +- add stats to repo view e.g. total size in storage ([adb0e3f](https://github.com/garethgeorge/backrest/commit/adb0e3f23050a86cd1c507d374e9d45f5eb5ee27)) +- display last operation status for each plan and repo in UI ([cc11197](https://github.com/garethgeorge/backrest/commit/cc111970ca2e61cf39804378808aa5b5f77f9581)) + +### Bug Fixes + +- crashing bug on partial backup ([#39](https://github.com/garethgeorge/backrest/issues/39)) ([fba6c8d](https://github.com/garethgeorge/backrest/commit/fba6c8da869d66b7b44f87a0dc1e3779924c31b7)) +- install scripts and improved asset compression ([b8c2e81](https://github.com/garethgeorge/backrest/commit/b8c2e813586f2b48c78d70e09a29c5052621caf1)) + +## [0.7.0](https://github.com/garethgeorge/backrest/compare/v0.6.0...v0.7.0) (2023-12-22) + +### Features + +- add activity bar to UI heading ([f5c3e76](https://github.com/garethgeorge/backrest/commit/f5c3e762ed4ed3c908e843d74985fb6c7b253db7)) +- add clear error history button ([48d80b9](https://github.com/garethgeorge/backrest/commit/48d80b9473db6619518924d0849b0eda78e62afa)) +- add repo view ([9522ac1](https://github.com/garethgeorge/backrest/commit/9522ac18deedc15311d3d464ee36c20e7f72e39f)) +- autoinstall required restic version ([b385c01](https://github.com/garethgeorge/backrest/commit/b385c011210087e6d6992a4e4b279fec4b22ab89)) +- basic forget support in backend and UI ([d22d9d1](https://github.com/garethgeorge/backrest/commit/d22d9d1a05831fae94ce397c0c73c6292d378cf5)) +- begin UI integration with backend ([cccdd29](https://github.com/garethgeorge/backrest/commit/cccdd297c15cd47268b2a1903e9624bdbca3dc68)) +- display queued operations ([0c818bb](https://github.com/garethgeorge/backrest/commit/0c818bb9452a944d8b1127e553142e1e60ed90af)) +- forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) +- forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) +- implement add plan UI ([9288589](https://github.com/garethgeorge/backrest/commit/92885898cf551a2dcb4bb315f130138cd7a8cc67)) +- implement backup scheduling in orchestrator ([eadb1a8](https://github.com/garethgeorge/backrest/commit/eadb1a82019f0cfc82edf8559adbad7730a4e86a)) +- implement basic plan view ([4c6f042](https://github.com/garethgeorge/backrest/commit/4c6f042250946a036e46225e669ee39e2433b198)) +- implement delete button for plan and repo UIs ([ffb0d85](https://github.com/garethgeorge/backrest/commit/ffb0d859f19f4af66a7521768dab083995f9672a)) +- implement forget and prune support in restic pkg ([ffb4573](https://github.com/garethgeorge/backrest/commit/ffb4573737a73cc32f325bc0b9c3feed764b7879)) +- implement forget operation ([ebccf3b](https://github.com/garethgeorge/backrest/commit/ebccf3bc3b78083aee635de7c6ae23b52ee88284)) +- implement garbage collection of old operations ([46456a8](https://github.com/garethgeorge/backrest/commit/46456a88870934506ede4b67c3dfaa2f2afcee14)) +- implement prune support ([#25](https://github.com/garethgeorge/backrest/issues/25)) ([a311b0a](https://github.com/garethgeorge/backrest/commit/a311b0a3fb5315f17d66361a3e72fa10b8a744a1)) +- implement repo unlocking and operation list implementation ([6665ad9](https://github.com/garethgeorge/backrest/commit/6665ad98d7f54bea30ea532932a8a3409717c913)) +- implement repo, edit, and supporting RPCs ([d282c32](https://github.com/garethgeorge/backrest/commit/d282c32c8bd3d8f5747e934d4af6a84faca1ec86)) +- implement restore operation through snapshot browser UI ([#27](https://github.com/garethgeorge/backrest/issues/27)) ([d758509](https://github.com/garethgeorge/backrest/commit/d758509797e21e3ec4bc67eff4d974604e4a5476)) +- implement snapshot browsing ([8ffffa0](https://github.com/garethgeorge/backrest/commit/8ffffa05e41ca31e2d38fde5427dae34ac4a1abb)) +- implement snapshot indexing ([a90b30e](https://github.com/garethgeorge/backrest/commit/a90b30e19f7107874bbfe244451b07f72c437213)) +- improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/backrest/issues/22)) ([51b4921](https://github.com/garethgeorge/backrest/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19)) +- initial oplog implementation ([dd9142c](https://github.com/garethgeorge/backrest/commit/dd9142c0e97e1175ff12f2861220af0e0d68b7d9)) +- initial optree implementation ([ba390a2](https://github.com/garethgeorge/backrest/commit/ba390a2ca1b5e9adaab36a7db0d988f54f5a6cdd)) +- initial Windows OS support ([f048cbf](https://github.com/garethgeorge/backrest/commit/f048cbf10dc60da51cd7f5aee4614a8750fd85b2)) +- match system color theme (darkmode support) ([a8762dc](https://github.com/garethgeorge/backrest/commit/a8762dca329927b93db40b01cc011c00e12891f0)) +- operations IDs are ordered by operation timestamp ([a1ed6f9](https://github.com/garethgeorge/backrest/commit/a1ed6f90ba1d608e00c53221db45b67251085aa7)) +- present list of operations on plan view ([6491dbe](https://github.com/garethgeorge/backrest/commit/6491dbed146967c0e12eee4392d1d12843dc7c5e)) +- repo can be created through UI ([9ccade5](https://github.com/garethgeorge/backrest/commit/9ccade5ccd97f4e485d52ad5c675be6b0a4a1049)) +- scaffolding basic UI structure ([1273f81](https://github.com/garethgeorge/backrest/commit/1273f8105a2549b0ccd0c7a588eb60646b66366e)) +- show snapshots in sidenav ([1a9a5b6](https://github.com/garethgeorge/backrest/commit/1a9a5b60d24dd75752e5a3f84dd87af3e38422bb)) +- snapshot items are viewable in the UI and minor element ordering fixes ([a333001](https://github.com/garethgeorge/backrest/commit/a33300175c645f31b95b3038de02821a1f3d5559)) +- support ImportSnapshotOperation in oplog ([89f95b3](https://github.com/garethgeorge/backrest/commit/89f95b351fe250534cd39ac27ff34b2b148256e1)) +- support task cancellation ([fc9c06d](https://github.com/garethgeorge/backrest/commit/fc9c06df00409b73dda23f4be031746f492b1a24)) +- update getting started guide ([2c421d6](https://github.com/garethgeorge/backrest/commit/2c421d661501fa4a3120aa3f39937cd58b29c2dc)) + +### Bug Fixes + +- backup ordering in tree view ([b9c8b3e](https://github.com/garethgeorge/backrest/commit/b9c8b3e378e88a0feff4d477d9d97eb5db075382)) +- build and test fixes ([4957496](https://github.com/garethgeorge/backrest/commit/49574967871494dcb5095e5699610097466f57f9)) +- connectivity issues with embedded server ([482cc8e](https://github.com/garethgeorge/backrest/commit/482cc8ebbc93b919991f6566b212247c5874f70f)) +- deadlock in snapshots ([93b2120](https://github.com/garethgeorge/backrest/commit/93b2120f74ea348e5084ab430573368bf4066eec)) +- forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) +- hide no-op prune operations ([20dd78c](https://github.com/garethgeorge/backrest/commit/20dd78cac4bdd6385cb7a0ea9ff0be75fde9135b)) +- improve error message formatting ([ae33b01](https://github.com/garethgeorge/backrest/commit/ae33b01de408af3b1d711a369298a2782a24ad1e)) +- improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) +- improve output detail collection for command failures ([c492f9b](https://github.com/garethgeorge/backrest/commit/c492f9ba63169942509349797ebe951879b53635)) +- improve UI performance ([8488d46](https://github.com/garethgeorge/backrest/commit/8488d461bd7ffec2e8171d67f83093c32c79073f)) +- improve Windows path handling ([426aad4](https://github.com/garethgeorge/backrest/commit/426aad4890d2de5d70cd2e0232c0d11c42606c92)) +- incorrrect handling of oplog events in UI ([95ca96a](https://github.com/garethgeorge/backrest/commit/95ca96a31f2e1ead2702164ec8675e4b4f54cf1d)) +- operation ordering in tree view ([2b4e1a2](https://github.com/garethgeorge/backrest/commit/2b4e1a2fdbf11b010ddbcd0b6fd2640d01e4dbc8)) +- operations marked as 'warn' rather than 'error' for partial backups ([fe92b62](https://github.com/garethgeorge/backrest/commit/fe92b625780481193e0ab63fbbdddb889bbda2a8)) +- ordering of operations when viewed from backup tree ([063f086](https://github.com/garethgeorge/backrest/commit/063f086a6e31df250dd9be42cdb5fa549307106f)) +- race condition in snapshot browser ([f239b91](https://github.com/garethgeorge/backrest/commit/f239b9170415e063ec8d60a5b5e14ae3610b9bad)) +- relax output parsing to skip over warnings ([8f85b74](https://github.com/garethgeorge/backrest/commit/8f85b747f57844bbc898668723eec50a1666aa39)) +- repo orchestrator tests ([d077fc8](https://github.com/garethgeorge/backrest/commit/d077fc83c97b7fbdbeda9702828c8780182b2616)) +- restic fails to detect summary event for very short backups ([46b2a85](https://github.com/garethgeorge/backrest/commit/46b2a8567706ddb21cfcf3e18b57e16d50809b56)) +- restic should initialize repo on backup operation ([e57abbd](https://github.com/garethgeorge/backrest/commit/e57abbdcb1864c362e6ae3c22850c0380671cb34)) +- restora should not init repos added manually e.g. without the UI ([68b50e1](https://github.com/garethgeorge/backrest/commit/68b50e1eb5a2ebd861c869f71f49d196cb5214f8)) +- snapshots out of order in UI ([b9bcc7e](https://github.com/garethgeorge/backrest/commit/b9bcc7e7c758abafa4878b6ef895adf2d2d0bc42)) +- standardize on fully qualified snapshot_id and decouple protobufs from restic package ([e6031bf](https://github.com/garethgeorge/backrest/commit/e6031bfa543a7300e622c1b0f56efc6320e7611e)) +- support more versions of restic ([0cdfd11](https://github.com/garethgeorge/backrest/commit/0cdfd115e29a0b08d5814e71c0f4a8f2baf52e90)) +- task cancellation ([d49b729](https://github.com/garethgeorge/backrest/commit/d49b72996ea7fd0543d55db3fc8e1127fe5a2476)) +- task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) +- time formatting in operation list ([53c7f12](https://github.com/garethgeorge/backrest/commit/53c7f1248f5284080fff872ac79b3996474412b3)) +- UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/backrest/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9)) +- unexpected config location on MacOS ([8d40576](https://github.com/garethgeorge/backrest/commit/8d40576c6526d6f180c96fbeb81d7f59f56b51b8)) +- use timezone offset when grouping operations in OperationTree ([06240bd](https://github.com/garethgeorge/backrest/commit/06240bd7adabd76424025030cfde2fb5e54c219f)) + +## [0.6.0](https://github.com/garethgeorge/backrest/compare/v0.5.0...v0.6.0) (2023-12-22) + +### Features + +- add activity bar to UI heading ([f5c3e76](https://github.com/garethgeorge/backrest/commit/f5c3e762ed4ed3c908e843d74985fb6c7b253db7)) +- add clear error history button ([48d80b9](https://github.com/garethgeorge/backrest/commit/48d80b9473db6619518924d0849b0eda78e62afa)) +- add repo view ([9522ac1](https://github.com/garethgeorge/backrest/commit/9522ac18deedc15311d3d464ee36c20e7f72e39f)) +- implement garbage collection of old operations ([46456a8](https://github.com/garethgeorge/backrest/commit/46456a88870934506ede4b67c3dfaa2f2afcee14)) +- support task cancellation ([fc9c06d](https://github.com/garethgeorge/backrest/commit/fc9c06df00409b73dda23f4be031746f492b1a24)) + +### Bug Fixes + +- backup ordering in tree view ([b9c8b3e](https://github.com/garethgeorge/backrest/commit/b9c8b3e378e88a0feff4d477d9d97eb5db075382)) +- hide no-op prune operations ([20dd78c](https://github.com/garethgeorge/backrest/commit/20dd78cac4bdd6385cb7a0ea9ff0be75fde9135b)) +- incorrrect handling of oplog events in UI ([95ca96a](https://github.com/garethgeorge/backrest/commit/95ca96a31f2e1ead2702164ec8675e4b4f54cf1d)) +- operation ordering in tree view ([2b4e1a2](https://github.com/garethgeorge/backrest/commit/2b4e1a2fdbf11b010ddbcd0b6fd2640d01e4dbc8)) +- operations marked as 'warn' rather than 'error' for partial backups ([fe92b62](https://github.com/garethgeorge/backrest/commit/fe92b625780481193e0ab63fbbdddb889bbda2a8)) +- race condition in snapshot browser ([f239b91](https://github.com/garethgeorge/backrest/commit/f239b9170415e063ec8d60a5b5e14ae3610b9bad)) +- restic should initialize repo on backup operation ([e57abbd](https://github.com/garethgeorge/backrest/commit/e57abbdcb1864c362e6ae3c22850c0380671cb34)) +- backrest should not init repos added manually e.g. without the UI ([68b50e1](https://github.com/garethgeorge/backrest/commit/68b50e1eb5a2ebd861c869f71f49d196cb5214f8)) +- task cancellation ([d49b729](https://github.com/garethgeorge/backrest/commit/d49b72996ea7fd0543d55db3fc8e1127fe5a2476)) +- use timezone offset when grouping operations in OperationTree ([06240bd](https://github.com/garethgeorge/backrest/commit/06240bd7adabd76424025030cfde2fb5e54c219f)) + +## [0.5.0](https://github.com/garethgeorge/backrest/compare/v0.4.0...v0.5.0) (2023-12-10) + +### Features + +- implement repo unlocking and operation list implementation ([6665ad9](https://github.com/garethgeorge/backrest/commit/6665ad98d7f54bea30ea532932a8a3409717c913)) +- initial Windows OS support ([f048cbf](https://github.com/garethgeorge/backrest/commit/f048cbf10dc60da51cd7f5aee4614a8750fd85b2)) +- match system color theme (darkmode support) ([a8762dc](https://github.com/garethgeorge/backrest/commit/a8762dca329927b93db40b01cc011c00e12891f0)) + +### Bug Fixes + +- improve output detail collection for command failures ([c492f9b](https://github.com/garethgeorge/backrest/commit/c492f9ba63169942509349797ebe951879b53635)) +- improve Windows path handling ([426aad4](https://github.com/garethgeorge/backrest/commit/426aad4890d2de5d70cd2e0232c0d11c42606c92)) +- ordering of operations when viewed from backup tree ([063f086](https://github.com/garethgeorge/backrest/commit/063f086a6e31df250dd9be42cdb5fa549307106f)) +- relax output parsing to skip over warnings ([8f85b74](https://github.com/garethgeorge/backrest/commit/8f85b747f57844bbc898668723eec50a1666aa39)) +- snapshots out of order in UI ([b9bcc7e](https://github.com/garethgeorge/backrest/commit/b9bcc7e7c758abafa4878b6ef895adf2d2d0bc42)) +- unexpected config location on MacOS ([8d40576](https://github.com/garethgeorge/backrest/commit/8d40576c6526d6f180c96fbeb81d7f59f56b51b8)) + +## [0.4.0](https://github.com/garethgeorge/backrest/compare/v0.3.0...v0.4.0) (2023-12-04) + +### Features + +- implement prune support ([#25](https://github.com/garethgeorge/backrest/issues/25)) ([a311b0a](https://github.com/garethgeorge/backrest/commit/a311b0a3fb5315f17d66361a3e72fa10b8a744a1)) +- implement restore operation through snapshot browser UI ([#27](https://github.com/garethgeorge/backrest/issues/27)) ([d758509](https://github.com/garethgeorge/backrest/commit/d758509797e21e3ec4bc67eff4d974604e4a5476)) + +## [0.3.0](https://github.com/garethgeorge/backrest/compare/v0.2.0...v0.3.0) (2023-12-03) + +### Features + +- autoinstall required restic version ([b385c01](https://github.com/garethgeorge/backrest/commit/b385c011210087e6d6992a4e4b279fec4b22ab89)) +- basic forget support in backend and UI ([d22d9d1](https://github.com/garethgeorge/backrest/commit/d22d9d1a05831fae94ce397c0c73c6292d378cf5)) +- begin UI integration with backend ([cccdd29](https://github.com/garethgeorge/backrest/commit/cccdd297c15cd47268b2a1903e9624bdbca3dc68)) +- display queued operations ([0c818bb](https://github.com/garethgeorge/backrest/commit/0c818bb9452a944d8b1127e553142e1e60ed90af)) +- forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) +- forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) +- implement add plan UI ([9288589](https://github.com/garethgeorge/backrest/commit/92885898cf551a2dcb4bb315f130138cd7a8cc67)) +- implement backup scheduling in orchestrator ([eadb1a8](https://github.com/garethgeorge/backrest/commit/eadb1a82019f0cfc82edf8559adbad7730a4e86a)) +- implement basic plan view ([4c6f042](https://github.com/garethgeorge/backrest/commit/4c6f042250946a036e46225e669ee39e2433b198)) +- implement delete button for plan and repo UIs ([ffb0d85](https://github.com/garethgeorge/backrest/commit/ffb0d859f19f4af66a7521768dab083995f9672a)) +- implement forget and prune support in restic pkg ([ffb4573](https://github.com/garethgeorge/backrest/commit/ffb4573737a73cc32f325bc0b9c3feed764b7879)) +- implement forget operation ([ebccf3b](https://github.com/garethgeorge/backrest/commit/ebccf3bc3b78083aee635de7c6ae23b52ee88284)) +- implement repo, edit, and supporting RPCs ([d282c32](https://github.com/garethgeorge/backrest/commit/d282c32c8bd3d8f5747e934d4af6a84faca1ec86)) +- implement snapshot browsing ([8ffffa0](https://github.com/garethgeorge/backrest/commit/8ffffa05e41ca31e2d38fde5427dae34ac4a1abb)) +- implement snapshot indexing ([a90b30e](https://github.com/garethgeorge/backrest/commit/a90b30e19f7107874bbfe244451b07f72c437213)) +- improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/backrest/issues/22)) ([51b4921](https://github.com/garethgeorge/backrest/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19)) +- initial oplog implementation ([dd9142c](https://github.com/garethgeorge/backrest/commit/dd9142c0e97e1175ff12f2861220af0e0d68b7d9)) +- initial optree implementation ([ba390a2](https://github.com/garethgeorge/backrest/commit/ba390a2ca1b5e9adaab36a7db0d988f54f5a6cdd)) +- operations IDs are ordered by operation timestamp ([a1ed6f9](https://github.com/garethgeorge/backrest/commit/a1ed6f90ba1d608e00c53221db45b67251085aa7)) +- present list of operations on plan view ([6491dbe](https://github.com/garethgeorge/backrest/commit/6491dbed146967c0e12eee4392d1d12843dc7c5e)) +- repo can be created through UI ([9ccade5](https://github.com/garethgeorge/backrest/commit/9ccade5ccd97f4e485d52ad5c675be6b0a4a1049)) +- scaffolding basic UI structure ([1273f81](https://github.com/garethgeorge/backrest/commit/1273f8105a2549b0ccd0c7a588eb60646b66366e)) +- show snapshots in sidenav ([1a9a5b6](https://github.com/garethgeorge/backrest/commit/1a9a5b60d24dd75752e5a3f84dd87af3e38422bb)) +- snapshot items are viewable in the UI and minor element ordering fixes ([a333001](https://github.com/garethgeorge/backrest/commit/a33300175c645f31b95b3038de02821a1f3d5559)) +- support ImportSnapshotOperation in oplog ([89f95b3](https://github.com/garethgeorge/backrest/commit/89f95b351fe250534cd39ac27ff34b2b148256e1)) +- update getting started guide ([2c421d6](https://github.com/garethgeorge/backrest/commit/2c421d661501fa4a3120aa3f39937cd58b29c2dc)) + +### Bug Fixes + +- build and test fixes ([4957496](https://github.com/garethgeorge/backrest/commit/49574967871494dcb5095e5699610097466f57f9)) +- connectivity issues with embedded server ([482cc8e](https://github.com/garethgeorge/backrest/commit/482cc8ebbc93b919991f6566b212247c5874f70f)) +- deadlock in snapshots ([93b2120](https://github.com/garethgeorge/backrest/commit/93b2120f74ea348e5084ab430573368bf4066eec)) +- forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) +- improve error message formatting ([ae33b01](https://github.com/garethgeorge/backrest/commit/ae33b01de408af3b1d711a369298a2782a24ad1e)) +- improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) +- improve UI performance ([8488d46](https://github.com/garethgeorge/backrest/commit/8488d461bd7ffec2e8171d67f83093c32c79073f)) +- repo orchestrator tests ([d077fc8](https://github.com/garethgeorge/backrest/commit/d077fc83c97b7fbdbeda9702828c8780182b2616)) +- restic fails to detect summary event for very short backups ([46b2a85](https://github.com/garethgeorge/backrest/commit/46b2a8567706ddb21cfcf3e18b57e16d50809b56)) +- standardize on fully qualified snapshot_id and decouple protobufs from restic package ([e6031bf](https://github.com/garethgeorge/backrest/commit/e6031bfa543a7300e622c1b0f56efc6320e7611e)) +- support more versions of restic ([0cdfd11](https://github.com/garethgeorge/backrest/commit/0cdfd115e29a0b08d5814e71c0f4a8f2baf52e90)) +- task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) +- time formatting in operation list ([53c7f12](https://github.com/garethgeorge/backrest/commit/53c7f1248f5284080fff872ac79b3996474412b3)) +- UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/backrest/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9)) + +## [0.2.0](https://github.com/garethgeorge/backrest/compare/v0.1.3...v0.2.0) (2023-12-03) + +### Features + +- forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) +- forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) +- improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/backrest/issues/22)) ([51b4921](https://github.com/garethgeorge/backrest/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19)) + +### Bug Fixes + +- forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) +- improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) +- task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) +- UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/backrest/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9)) + +## [0.2.0](https://github.com/garethgeorge/backrest/compare/v0.1.3...v0.2.0) (2023-12-02) + +### Features + +- forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/backrest/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e)) +- forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/backrest/commit/38bc107db394716e34245f1edefc5e4cf4a15333)) + +### Bug Fixes + +- forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/backrest/commit/b7c633d021d68d4880a5f442ce70a858002b4af2)) +- improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/backrest/issues/21)) ([b513b08](https://github.com/garethgeorge/backrest/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e)) +- task priority not taking effect ([af7462c](https://github.com/garethgeorge/backrest/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49)) diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 000000000..307eef682 --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,10 @@ +FROM alpine:latest +LABEL org.opencontainers.image.source="https://github.com/garethgeorge/backrest" +RUN apk --no-cache add tini ca-certificates curl bash rclone openssh tzdata docker-cli +RUN mkdir -p /tmp +COPY backrest /backrest +RUN /backrest --install-deps-only +RUN mkdir -p /bin && mv /root/.local/share/backrest/restic /bin/restic + +ENTRYPOINT ["/sbin/tini", "--"] +CMD ["/backrest", "--bind-address", ":9898"] diff --git a/Dockerfile.scratch b/Dockerfile.scratch new file mode 100644 index 000000000..cd11f9c1d --- /dev/null +++ b/Dockerfile.scratch @@ -0,0 +1,17 @@ +FROM alpine:latest AS alpine +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/restic /bin/restic + +FROM scratch +LABEL org.opencontainers.image.source="https://github.com/garethgeorge/backrest" +COPY --from=alpine /tmp-orig /tmp +COPY --from=alpine /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=alpine /bin /bin +COPY --from=alpine /sbin/tini-static /tini +COPY backrest /backrest + +ENTRYPOINT ["/tini", "--"] +CMD ["/backrest", "--bind-address", ":9898"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index d090b1b83..c4d36dd95 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,295 @@ -# ResticUI +

-WIP project to build a UI for restic. +

+ + + +

-Project goals +--- - * Single binary for easy and _very lightweight_ deployment with or without containerization. - * WebUI supporting - * Backup plan creation and configuration - * Backup status - * Snapshot browsing and restore +**Overview** -# Dependencies +Backrest is a web-accessible backup solution built on top of [restic](https://restic.net/). Backrest provides a WebUI which wraps the restic CLI and makes it easy to create repos, browse snapshots, and restore files. Additionally, Backrest can run in the background and take an opinionated approach to scheduling snapshots and orchestrating repo health operations. -## Dev +By building on restic, Backrest leverages restic's mature feature set. Restic provides fast, reliable, and secure backup operations. + +Backrest itself is built in Golang (matching restic's implementation) and is shipped as a self-contained and light weight binary with no dependencies other than restic. This project aims to be the easiest way to setup and get started with backups on any system. You can expect to be able to perform all operations from the web interface but should you ever need more control, you are free to browse your repo and perform operations using the [restic cli](https://restic.readthedocs.io/en/latest/manual_rest.html). Additionally, Backrest can safely detect and import your existing snapshots (or externally created snapshots on an ongoing basis). + +**Preview** + +

+ + +

+ +**Platform Support** + +- [Docker](https://hub.docker.com/r/garethgeorge/backrest) +- Linux +- macOS +- Windows +- FreeBSD + +**Features** + +- WebUI supports local and remote access (e.g. run on a NAS and access from your desktop) +- Multi-platform support (Linux, macOS, Windows, FreeBSD, [Docker](https://hub.docker.com/r/garethgeorge/backrest)) +- Import your existing restic repositories +- Cron scheduled backups and health operations (e.g. prune, check, forget) +- UI for browsing and restoring files from snapshots +- Configurable backup notifications (e.g. Discord, Slack, Shoutrrr, Gotify, Healthchecks) +- Add shell command hooks to run before and after backup operations. +- Compatible with rclone remotes +- Backup to any restic supported storage (e.g. S3, B2, Azure, GCS, local, SFTP, and all [rclone remotes](https://rclone.org/)) + +--- + +# User Guide + +[See the Backrest docs](https://garethgeorge.github.io/backrest/introduction/getting-started). + +# Installation + +Backrest is packaged as a single executable. It can be run directly on Linux, macOS, and Windows. [restic](https://github.com/restic/restic) will be downloaded and installed on first run. + +Download options + +- Download and run a release from the [releases page](https://github.com/garethgeorge/backrest/releases). +- Build from source ([see below](#building)). +- Run with docker: `garethgeorge/backrest:latest` ([see on dockerhub](https://hub.docker.com/r/garethgeorge/backrest)) for an image that includes rclone and common unix utilities or `garethgeorge/backrest:scratch` for a minimal image. + +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 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 + +Docker image: https://hub.docker.com/r/garethgeorge/backrest + +Example compose file: + +```yaml +version: "3.2" +services: + backrest: + image: garethgeorge/backrest:latest + container_name: backrest + hostname: backrest + volumes: + - ./backrest/data:/data + - ./backrest/config:/config + - ./backrest/cache:/cache + - /MY-BACKUP-DATA:/userdata # [optional] mount local paths to backup here. + - /MY-REPOS:/repos # [optional] mount repos if using local storage, not necessary for remotes e.g. B2, S3, etc. + environment: + - BACKREST_DATA=/data # path for backrest data. restic binary and the database are placed here. + - BACKREST_CONFIG=/config/config.json # path for the backrest config file. + - XDG_CACHE_HOME=/cache # path for the restic cache which greatly improves performance. + - TZ=America/Los_Angeles # set the timezone for the container, used as the timezone for cron jobs. + restart: unless-stopped + ports: + - 9898:9898 +``` + +## Running on Linux + +### All Linux Platforms + +Download a release from the [releases page](https://github.com/garethgeorge/backrest/releases) + +#### Using systemd with the install script (Recommended) + +Extract the release you downloaded and run the install script: + +``` +# Extract the release to a subfolder of the current directory +mkdir backrest && tar -xzvf backrest_Linux_x86_64.tar.gz -C backrest +# Run the install script +cd backrest && ./install.sh +``` + +The install script will: + +- Move the Backrest binary to `/usr/local/bin` +- Create a systemd service file at `/etc/systemd/system/backrest.service` +- Enable and start the service + +Read the script before running it to make sure you are comfortable with these operations. + +#### Run on startup with cron (Basic) + +Move the Backrest binary to `/usr/local/bin`: + +```sh +sudo mv backrest /usr/local/bin/backrest +``` + +Add the following line to your crontab (e.g. `crontab -e`): + +```sh +@reboot /usr/local/bin/backrest +``` + +#### Run on startup with systemd manually + +```sh +sudo mv backrest /usr/local/bin/backrest +``` + +Create a systemd service file at `/etc/systemd/system/backrest.service` with the following contents: + +```ini +[Unit] +Description=Backrest +After=network.target + +[Service] +Type=simple +User= +Group= +ExecStart=/usr/local/bin/backrest +Environment="BACKREST_PORT=127.0.0.1:9898" + +[Install] +WantedBy=multi-user.target +``` + +Then run the following commands to enable and start the service: + +```sh +sudo systemctl enable backrest +sudo systemctl start backrest +``` + +> [!NOTE] +> You can set the Linux user and group to your primary user (e.g. `whoami` when logged in). + +### Arch Linux + +> [!Note] +> [Backrest on AUR](https://aur.archlinux.org/packages/backrest) is not maintained by the Backrest official and has made minor adjustments to the recommended services. Please refer to [here](https://aur.archlinux.org/cgit/aur.git/tree/backrest@.service?h=backrest) for details. In [backrest@.service](https://aur.archlinux.org/cgit/aur.git/tree/backrest@.service?h=backrest), use `restic` from the Arch Linux official repository by setting `BACKREST_RESTIC_COMMAND`. And for information on enable/starting/stopping services, please refer to [Systemd#Using_units](https://wiki.archlinux.org/title/Systemd#Using_units). + +```shell +## Install Backrest from AUR +paru -Sy backrest # or: yay -Sy backrest + +## Enable Backrest service for current user +sudo systemctl enable --now backrest@$USER.service +``` + +## Running on macOS + +#### Using Homebrew + +Backrest is provided as a [homebrew tap](https://github.com/garethgeorge/homebrew-backrest-tap). To install with brew run: + +```sh +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 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 + +Download a Darwin release from the [releases page](https://github.com/garethgeorge/backrest/releases) and install it to `/usr/local/bin`. + +Extract the release you downloaded and run the install script: + +``` +# extract the release to a subfolder of the current directory +mkdir backrest && tar -xzvf backrest_Darwin_arm64.tar.gz -C backrest +# run the install script +cd backrest && ./install.sh +``` + +The install script will: + +- Move the Backrest binary to `/usr/local/bin` +- Create a launch agent file at `~/Library/LaunchAgents/com.backrest.plist` +- Load the launch agent + +Read the script before running it to make sure you are comfortable with these operations. + +## Running on Windows + +#### Windows Installer + +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. + +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 + +## Environment Variables (Unix) + +| Variable | Description | Default | +| ------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| `BACKREST_PORT` | Port to bind to | 127.0.0.1:9898 (or 0.0.0.0:9898 for the docker images) | +| `BACKREST_CONFIG` | Path to config file | `$HOME/.config/backrest/config.json`
(or, if `$XDG_CONFIG_HOME` is set, `$XDG_CONFIG_HOME/backrest/config.json`) | +| `BACKREST_DATA` | Path to the data directory | `$HOME/.local/share/backrest`
(or, if `$XDG_DATA_HOME` is set, `$XDG_DATA_HOME/backrest`) | +| `BACKREST_RESTIC_COMMAND` | Path to restic binary | Defaults to a Backrest managed version of restic at `$XDG_DATA_HOME/backrest/restic-x.x.x` | +| `XDG_CACHE_HOME` | Path to the cache directory | | + +## Environment Variables (Windows) + +| Variable | Description | Default | +| ------------------------- | --------------------------- | ------------------------------------------------------------------------------------------ | +| `BACKREST_PORT` | Port to bind to | 127.0.0.1:9898 | +| `BACKREST_CONFIG` | Path to config file | `%appdata%\backrest` | +| `BACKREST_DATA` | Path to the data directory | `%appdata%\backrest\data` | +| `BACKREST_RESTIC_COMMAND` | Path to restic binary | Defaults to a Backrest managed version of restic in `C:\Program Files\restic\restic-x.x.x` | +| `XDG_CACHE_HOME` | Path to the cache directory | | + +# Contributing + +Contributions are welcome! See the [issues](https://github.com/garethgeorge/backrest/issues) or feel free to open a new issue to discuss a project. Beyond the core codebase, contributions to [documentation](https://garethgeorge.github.io/backrest/introduction/getting-started), [cookbooks](https://garethgeorge.github.io/backrest/cookbooks/command-hook-examples), and testing are always welcome. + +## Build Depedencies + +- [Node.js](https://nodejs.org/en) for UI development +- [Go](https://go.dev/) 1.21 or greater for server development +- [goreleaser](https://github.com/goreleaser/goreleaser) `go install github.com/goreleaser/goreleaser@latest` + +**(Optional) To Edit Protobuffers** ```sh apt install -y protobuf-compiler -go install \ - github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest \ - github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest -go install github.com/grpc-ecosystem/protoc-gen-grpc-gateway-ts@latest -go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest -go install github.com/bufbuild/buf/cmd/buf@v1.27.2 +go install github.com/bufbuild/buf/cmd/buf@v1.47.2 +go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest +go install google.golang.org/protobuf/cmd/protoc-gen-go@latest +go install connectrpc.com/connect/cmd/protoc-gen-connect-go@latest +npm install -g @bufbuild/protoc-gen-es +``` + +## Compiling + +```sh +(cd webui && npm i && npm run build) +(cd cmd/backrest && go build .) ``` + +## Using VSCode Dev Containers + +You can also use VSCode with [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension to quickly get up and running with a working development and debugging environment. + +0. Make sure Docker and VSCode with [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension is installed +1. Clone this repository +2. Open this folder in VSCode +3. When prompted, click on `Open in Container` button, or run `> Dev Containers: Rebuild and Reopen in Containers` command +4. When container is started, go to `Run and Debug`, choose `Debug Backrest (backend+frontend)` and run it + +> [!NOTE] +> Provided launch configuration has hot reload for typescript frontend. diff --git a/build/windows/icon.ico b/build/windows/icon.ico new file mode 100644 index 000000000..6a4440a3b Binary files /dev/null and b/build/windows/icon.ico differ diff --git a/build/windows/install.nsi b/build/windows/install.nsi new file mode 100644 index 000000000..fa2ed2a3b --- /dev/null +++ b/build/windows/install.nsi @@ -0,0 +1,194 @@ +!define BUILD_DIR "." +!define OUT_DIR "." +!define APP_NAME "Backrest" +!define COMP_NAME "garethgeorge" +!define WEB_SITE "https://github.com/garethgeorge/backrest" +!define COPYRIGHT "garethgeorge 2024" +!define DESCRIPTION "${APP_NAME} installer" +!define LICENSE_TXT "${BUILD_DIR}\LICENSE" +!define INSTALLER_NAME "${OUT_DIR}\Backrest-setup.exe" +!define MAIN_APP_EXE "backrest-windows-tray.exe" +!define INSTALL_TYPE "SetShellVarContext current" +!define REG_ROOT "HKCU" +!define REG_UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" +!define REG_START_MENU "Start Menu Folder" +# Extract version from the changelog. +!searchparse /file "${BUILD_DIR}\CHANGELOG.md" `## [` VERSION_LOG `]` +# NSIS requires X.X.X.X format in VIProductVersion. Use it everywhere for consistency. +!define VERSION "${VERSION_LOG}.0" +# User variables. +Var SM_folder +Var UIPort +Var WelcomePortNote +Var Prev_version + +###################################################################### +# Installer file properties +VIProductVersion "${VERSION}" +VIAddVersionKey "ProductName" "${APP_NAME}" +VIAddVersionKey "CompanyName" "${COMP_NAME}" +VIAddVersionKey "LegalCopyright" "${COPYRIGHT}" +VIAddVersionKey "FileDescription" "${DESCRIPTION}" +VIAddVersionKey "FileVersion" "${VERSION}" +VIAddVersionKey "ProductVersion" "${VERSION}" + +###################################################################### +# Installer settings +RequestExecutionLevel user +SetCompressor LZMA +Name "${APP_NAME}" +OutFile "${INSTALLER_NAME}" +XPStyle on +InstallDirRegKey "${REG_ROOT}" "${REG_UNINSTALL_PATH}" "" +InstallDir "$LOCALAPPDATA\Programs\Backrest" +ManifestDPIAware true +ShowInstDetails show +ShowUninstDetails show +# Include NSIS scripts used by this script. +!include "MUI2.nsh" +!include "LogicLib.nsh" +!include "StrFunc.nsh" +# Declare used built-in functions. +${StrStr} + +###################################################################### +# GUI pages +# Interface configuration, applies to all pages. +!define MUI_ABORTWARNING +!define MUI_UNABORTWARNING +!define MUI_COMPONENTSPAGE_NODESC + +!define MUI_TEXT_WELCOME_INFO_TEXT "Setup will guide you through the installation of Backrest.$\r$\n$\r$\nBackrest binds to 127.0.0.1:9898 for web UI. You may change the port using BACKREST_PORT environment variable (see installation documentation). If setting the variable, exit and re-run this installer to have it pick up the new value.$\r$\n$\r$\nYou must use a custom port if there are other Backrest instances running concurrently on this system.$WelcomePortNote$\r$\n$\r$\n$_CLICK" +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "${LICENSE_TXT}" +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_DIRECTORY + +!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${REG_ROOT}" +!define MUI_STARTMENUPAGE_REGISTRY_KEY "${REG_UNINSTALL_PATH}" +!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${REG_START_MENU}" +# Get Start Menu folder name from the dialog screen and store it in a variable. +!insertmacro MUI_PAGE_STARTMENU "Application" $SM_folder +!insertmacro MUI_PAGE_INSTFILES + +!define MUI_FINISHPAGE_RUN "$INSTDIR\${MAIN_APP_EXE}" +!define MUI_FINISHPAGE_RUN_TEXT "Start ${APP_NAME} (runs in the system tray)" +# Use the built-in readme option to open the app URL. +!define MUI_FINISHPAGE_SHOWREADME http://localhost:$UIPort/ +!define MUI_FINISHPAGE_SHOWREADME_TEXT "Open Backrest user interface" +!insertmacro MUI_PAGE_FINISH + +# Uninstall pages. +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH + +!insertmacro MUI_LANGUAGE "English" + +###################################################################### +# Functions +# Have to define the function this way to allow re-using it in the uninstall section. +!macro KillProc UN +Function ${UN}KillProc +DetailPrint "Stopping Backrest if it is running..." +# Gracefully attempt to stop Backrest process in the current session. +# Do it 5 times 1 second apart, then kill forcefully. +nsExec::ExecToLog 'powershell.exe -Command "while ((Get-Process -Name backrest-windows-tray -ea SilentlyContinue | where { $$_.SessionId -eq (Get-Process -Id $$PID).SessionId }) -and ($$count -ne 5)) { $$count++ ; taskkill /FI """USERNAME eq $$([Environment]::UserName)""" /IM backrest-windows-tray.exe; sleep 1 }; if ($$count -eq 5) { Stop-Process -Name backrest-windows-tray }" ' +FunctionEnd +!macroend +!insertmacro KillProc "" +!insertmacro KillProc "un." + +Function .onInit +# Old pre-1.6.2 installer installed into C:\Program Files; override the default path when upgrading. +# $R0, $R1 etc are registers; used here as local temp variables. +ReadRegStr $Prev_version ${REG_ROOT} "${REG_UNINSTALL_PATH}" "DisplayVersion" +${If} "$Prev_version" == "00.00.00.00" +StrCpy $INSTDIR "$LOCALAPPDATA\Programs\Backrest" +${EndIf} +# Read BACKREST_PORT environment variable. +ReadEnvStr $R1 BACKREST_PORT +${If} "$R1" == "" + # Use the default port and welcome text if the var is empty. + StrCpy $UIPort "9898" + StrCpy $WelcomePortNote "" +${Else} + # Extract substring starting with a colon, assign to $R2. + ${StrStr} $R2 $R1 ":" + # Assign the value to $UIPort, omitting the first character (:). + StrCpy $UIPort $R2 "" 1 + StrCpy $WelcomePortNote "$\r$\n$\r$\nNOTE: detected BACKREST_PORT variable present. Will use port $UIPort for shortcuts." +${EndIf} +FunctionEnd + +###################################################################### +# Sections +Section "Application files" +SectionIn RO +${INSTALL_TYPE} +Call KillProc +# Clean up remnants from the old installer (except for items in "Program Files" which would require elevation). +${If} "$Prev_version" == "00.00.00.00" + Delete "$DESKTOP\${APP_NAME} Console.lnk" + Delete "$SMPROGRAMS\$SM_Folder\${APP_NAME} Website.lnk" + Delete "$SMPROGRAMS\${APP_NAME}\Uninstall ${APP_NAME}.lnk" + DeleteRegKey ${REG_ROOT} "Software\Microsoft\Windows\CurrentVersion\App Paths\${MAIN_APP_EXE}" +${EndIf} + +SetOverwrite ifnewer +SetOutPath "$INSTDIR" +File "${BUILD_DIR}\backrest.exe" +File "${BUILD_DIR}\backrest-windows-tray.exe" +File "${BUILD_DIR}\LICENSE" +File "${BUILD_DIR}\icon.ico" +WriteUninstaller "$INSTDIR\uninstall.exe" + +# Start Menu shortcuts +!insertmacro MUI_STARTMENU_WRITE_BEGIN "Application" +CreateDirectory "$SMPROGRAMS\$SM_folder" +CreateShortCut "$SMPROGRAMS\$SM_folder\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}" "" "$INSTDIR\icon.ico" 0 +CreateShortCut "$SMPROGRAMS\$SM_folder\${APP_NAME} UI.lnk" "http://localhost:$UIPort/" "" "$INSTDIR\icon.ico" 0 +WriteIniStr "$SMPROGRAMS\$SM_folder\${APP_NAME} website.url" "InternetShortcut" "URL" "${WEB_SITE}" +!insertmacro MUI_STARTMENU_WRITE_END + +# Registry entries +WriteRegStr ${REG_ROOT} "${REG_UNINSTALL_PATH}" "DisplayName" "${APP_NAME}" +WriteRegStr ${REG_ROOT} "${REG_UNINSTALL_PATH}" "UninstallString" "$INSTDIR\uninstall.exe" +WriteRegStr ${REG_ROOT} "${REG_UNINSTALL_PATH}" "DisplayIcon" "$INSTDIR\icon.ico" +WriteRegStr ${REG_ROOT} "${REG_UNINSTALL_PATH}" "DisplayVersion" "${VERSION}" +WriteRegStr ${REG_ROOT} "${REG_UNINSTALL_PATH}" "Publisher" "${COMP_NAME}" +WriteRegStr ${REG_ROOT} "${REG_UNINSTALL_PATH}" "URLInfoAbout" "${WEB_SITE}" +SectionEnd + +Section "Run application at startup (recommended)" +CreateDirectory $SMSTARTUP +CreateShortcut "$SMSTARTUP\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}" "" "$INSTDIR\icon.ico" 0 +SectionEnd + +Section "Desktop shortcut" +CreateShortCut "$DESKTOP\${APP_NAME} UI.lnk" "http://localhost:$UIPort/" "" "$INSTDIR\icon.ico" 0 +SectionEnd + +Section "Uninstall" +${INSTALL_TYPE} +Call un.KillProc +Delete "$INSTDIR\LICENSE" +Delete "$INSTDIR\icon.ico" +Delete "$INSTDIR\install.lock" +Delete "$INSTDIR\restic*.exe" +Delete "$INSTDIR\backrest.exe" +Delete "$INSTDIR\backrest-windows-tray.exe" +Delete "$INSTDIR\uninstall.exe" +RmDir "$INSTDIR" +# Get Start Menu folder name from the registry and delete shortcuts. +!insertmacro MUI_STARTMENU_GETFOLDER "Application" $SM_folder +Delete "$SMPROGRAMS\$SM_folder\${APP_NAME}.lnk" +Delete "$SMPROGRAMS\$SM_folder\${APP_NAME} UI.lnk" +Delete "$SMPROGRAMS\$SM_folder\${APP_NAME} website.url" +RmDir "$SMPROGRAMS\$SM_folder" +# Startup and desktop shortcuts +Delete "$SMSTARTUP\${APP_NAME}.lnk" +Delete "$DESKTOP\${APP_NAME} UI.lnk" +# Registry +DeleteRegKey ${REG_ROOT} "${REG_UNINSTALL_PATH}" +SectionEnd diff --git a/cmd/backrest/backrest.go b/cmd/backrest/backrest.go new file mode 100644 index 000000000..2610cea8d --- /dev/null +++ b/cmd/backrest/backrest.go @@ -0,0 +1,296 @@ +package main + +import ( + "context" + "crypto/rand" + "errors" + "flag" + "net/http" + "os" + "os/signal" + "path" + "path/filepath" + "runtime" + "sync" + "sync/atomic" + "syscall" + + v1 "github.com/garethgeorge/backrest/gen/go/v1" + "github.com/garethgeorge/backrest/gen/go/v1/v1connect" + "github.com/garethgeorge/backrest/internal/api" + "github.com/garethgeorge/backrest/internal/auth" + "github.com/garethgeorge/backrest/internal/config" + "github.com/garethgeorge/backrest/internal/env" + "github.com/garethgeorge/backrest/internal/logstore" + "github.com/garethgeorge/backrest/internal/metric" + "github.com/garethgeorge/backrest/internal/oplog" + "github.com/garethgeorge/backrest/internal/oplog/bboltstore" + "github.com/garethgeorge/backrest/internal/oplog/sqlitestore" + "github.com/garethgeorge/backrest/internal/orchestrator" + "github.com/garethgeorge/backrest/internal/resticinstaller" + "github.com/garethgeorge/backrest/webui" + "github.com/mattn/go-colorable" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" + "gopkg.in/natefinch/lumberjack.v2" +) + +var InstallDepsOnly = flag.Bool("install-deps-only", false, "install dependencies and exit") +var ( + version = "unknown" + commit = "unknown" +) + +func main() { + flag.Parse() + installLoggers() + + resticPath, err := resticinstaller.FindOrInstallResticBinary() + if err != nil { + zap.S().Fatalf("error finding or installing restic: %v", err) + } + + if *InstallDepsOnly { + zap.S().Info("dependencies installed, exiting") + return + } + + ctx, cancel := context.WithCancel(context.Background()) + go onterm(os.Interrupt, cancel) + go onterm(os.Interrupt, newForceKillHandler()) + + // Load the configuration + configStore := createConfigProvider() + cfg, err := configStore.Get() + if err != nil { + zap.S().Fatalf("error loading config: %v", err) + } + + var wg sync.WaitGroup + + // Create / load the operation log + oplogFile := path.Join(env.DataDir(), "oplog.sqlite") + opstore, err := sqlitestore.NewSqliteStore(oplogFile) + if errors.Is(err, sqlitestore.ErrLocked) { + zap.S().Fatalf("oplog is locked by another instance of backrest that is using the same data directory %q, kill that instance before starting another one.", env.DataDir()) + } else 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) + zap.S().Fatalf("error creating oplog: %v", err) + } + defer opstore.Close() + + log, err := oplog.NewOpLog(opstore) + if err != nil { + zap.S().Fatalf("error creating oplog: %v", err) + } + migrateBboltOplog(opstore) + + // Create rotating log storage + logStore, err := logstore.NewLogStore(filepath.Join(env.DataDir(), "tasklogs")) + if err != nil { + zap.S().Fatalf("error creating task log store: %v", err) + } + logstore.MigrateTarLogsInDir(logStore, filepath.Join(env.DataDir(), "rotatinglogs")) + deleteLogsForOp := func(ops []*v1.Operation, event oplog.OperationEvent) { + if event != oplog.OPERATION_DELETED { + return + } + for _, op := range ops { + if err := logStore.DeleteWithParent(op.Id); err != nil { + zap.S().Warnf("error deleting logs for operation %q: %v", op.Id, err) + } + } + } + log.Subscribe(oplog.Query{}, &deleteLogsForOp) + defer func() { + if err := logStore.Close(); err != nil { + zap.S().Warnf("error closing log store: %v", err) + } + log.Unsubscribe(&deleteLogsForOp) + }() + + // Create orchestrator and start task loop. + orchestrator, err := orchestrator.NewOrchestrator(resticPath, cfg, log, logStore) + if err != nil { + zap.S().Fatalf("error creating orchestrator: %v", err) + } + + wg.Add(1) + go func() { + orchestrator.Run(ctx) + wg.Done() + }() + + // Create and serve the HTTP gateway + apiBackrestHandler := api.NewBackrestHandler( + configStore, + orchestrator, + log, + logStore, + ) + + authenticator := auth.NewAuthenticator(getSecret(), configStore) + apiAuthenticationHandler := api.NewAuthenticationHandler(authenticator) + + mux := http.NewServeMux() + mux.Handle(v1connect.NewAuthenticationHandler(apiAuthenticationHandler)) + backrestHandlerPath, backrestHandler := v1connect.NewBackrestHandler(apiBackrestHandler) + mux.Handle(backrestHandlerPath, auth.RequireAuthentication(backrestHandler, authenticator)) + mux.Handle("/", webui.Handler()) + mux.Handle("/download/", http.StripPrefix("/download", api.NewDownloadHandler(log))) + mux.Handle("/metrics", auth.RequireAuthentication(metric.GetRegistry().Handler(), authenticator)) + + // Serve the HTTP gateway + server := &http.Server{ + Addr: env.BindAddress(), + Handler: h2c.NewHandler(mux, &http2.Server{}), // h2c is HTTP/2 without TLS for grpc-connect support. + } + + zap.S().Infof("starting web server %v", server.Addr) + go func() { + <-ctx.Done() + server.Shutdown(context.Background()) + }() + if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { + zap.L().Error("error starting server", zap.Error(err)) + } + zap.L().Info("HTTP gateway shutdown") + + wg.Wait() +} + +func createConfigProvider() config.ConfigStore { + return &config.CachingValidatingStore{ + ConfigStore: &config.JsonFileStore{Path: env.ConfigFilePath()}, + } +} + +func onterm(s os.Signal, callback func()) { + sigchan := make(chan os.Signal, 1) + signal.Notify(sigchan, s, syscall.SIGTERM) + for { + <-sigchan + callback() + } +} + +func getSecret() []byte { + secretFile := path.Join(env.DataDir(), "jwt-secret") + data, err := os.ReadFile(secretFile) + if err == nil { + zap.L().Debug("loading auth secret from file") + return data + } + + zap.L().Info("generating new auth secret") + secret := make([]byte, 64) + if n, err := rand.Read(secret); err != nil || n != 64 { + zap.S().Fatalf("error generating secret: %v", err) + } + if err := os.MkdirAll(env.DataDir(), 0700); err != nil { + zap.S().Fatalf("error creating data directory: %v", err) + } + if err := os.WriteFile(secretFile, secret, 0600); err != nil { + zap.S().Fatalf("error writing secret to file: %v", err) + } + return secret +} + +func newForceKillHandler() func() { + var times atomic.Int32 + return func() { + if times.Load() > 0 { + buf := make([]byte, 1<<16) + runtime.Stack(buf, true) + os.Stderr.Write(buf) + zap.S().Fatal("dumped all running coroutine stack traces, forcing termination") + } + times.Add(1) + zap.S().Warn("attempting graceful shutdown, to force termination press Ctrl+C again") + } +} + +func installLoggers() { + // Pretty logging for console + c := zap.NewDevelopmentEncoderConfig() + c.EncodeLevel = zapcore.CapitalColorLevelEncoder + c.EncodeTime = zapcore.ISO8601TimeEncoder + pretty := zapcore.NewCore( + zapcore.NewConsoleEncoder(c), + zapcore.AddSync(colorable.NewColorableStdout()), + zapcore.InfoLevel, + ) + + // JSON logging to log directory + logsDir := env.LogsPath() + if err := os.MkdirAll(logsDir, 0755); err != nil { + zap.ReplaceGlobals(zap.New(pretty)) + zap.S().Errorf("error creating logs directory %q, will only log to console for now: %v", err) + return + } + + writer := &lumberjack.Logger{ + Filename: filepath.Join(logsDir, "backrest.log"), + MaxSize: 5, // megabytes + MaxBackups: 3, + MaxAge: 14, + Compress: true, + } + + ugly := zapcore.NewCore( + zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), + zapcore.AddSync(writer), + zapcore.DebugLevel, + ) + + zap.ReplaceGlobals(zap.New(zapcore.NewTee(pretty, ugly))) + zap.S().Infof("backrest version %v@%v, using log directory: %v", version, commit, logsDir) +} + +// migrateBboltOplog migrates the old bbolt oplog to the new sqlite oplog. +// It is careful to ensure that all migrations are applied before copying +// operations directly to the sqlite logstore. +func migrateBboltOplog(logstore oplog.OpStore) { + oldBboltOplogFile := path.Join(env.DataDir(), "oplog.boltdb") + if _, err := os.Stat(oldBboltOplogFile); err != nil { + return + } + + zap.S().Warnf("found old bbolt oplog file %q, migrating to sqlite", oldBboltOplogFile) + oldOpstore, err := bboltstore.NewBboltStore(oldBboltOplogFile) + if err != nil { + zap.S().Fatalf("error opening old bolt opstore: %v", oldBboltOplogFile, err) + } + oldOplog, err := oplog.NewOpLog(oldOpstore) + if err != nil { + zap.S().Fatalf("error opening old bolt oplog: %v", oldBboltOplogFile, err) + } + + var errs []error + var count int + if err := oldOplog.Query(oplog.Query{}, func(op *v1.Operation) error { + if err := logstore.Add(op); err != nil { + errs = append(errs, err) + zap.L().Warn("failed to migrate operation", zap.Error(err), zap.Any("operation", op)) + } else { + count++ + } + return nil + }); err != nil { + zap.S().Warnf("couldn't migrate all operations from the old bbolt oplog, if this recurs delete the file %q and restart", oldBboltOplogFile) + zap.S().Fatalf("error migrating old bbolt oplog: %v", err) + } + + if len(errs) > 0 { + zap.S().Errorf("encountered %d errors migrating old bbolt oplog, see logs for details.", len(errs), oldBboltOplogFile) + } + if err := oldOpstore.Close(); err != nil { + zap.S().Warnf("error closing old bbolt oplog: %v", err) + } + if err := os.Rename(oldBboltOplogFile, oldBboltOplogFile+".deprecated"); err != nil { + zap.S().Warnf("error removing old bbolt oplog: %v", err) + } + zap.S().Infof("migrated %d operations from old bbolt oplog to sqlite", count) +} diff --git a/cmd/backrestmon/backrestmon.go b/cmd/backrestmon/backrestmon.go new file mode 100644 index 000000000..cc85821e6 --- /dev/null +++ b/cmd/backrestmon/backrestmon.go @@ -0,0 +1,141 @@ +//go:build windows +// +build windows + +package main + +import ( + "context" + "fmt" + "net" + "os" + "os/exec" + "path/filepath" + "runtime" + "syscall" + + "github.com/garethgeorge/backrest/internal/env" + "github.com/getlantern/systray" + "github.com/ncruces/zenity" + + _ "embed" +) + +//go:embed icon.ico +var icon []byte + +func main() { + backrest, err := findBackrest() + if err != nil { + reportError(err) + return + } + + ctx, cancel := context.WithCancel(context.Background()) + + cmd := exec.CommandContext(ctx, backrest) + cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} + cmd.Env = os.Environ() + cmd.Env = append(cmd.Env, "ENV=production") + + if err := cmd.Start(); err != nil { + reportError(err) + cancel() + return + } + + systray.Run(func() { + systray.SetTitle("Backrest Tray") + systray.SetTooltip("Manage backrest") + systray.SetIcon(icon) + + // First item: open the WebUI in the default browser. + mOpenUI := systray.AddMenuItem("Open WebUI", "Open the Backrest WebUI in your default browser") + mOpenUI.ClickedCh = make(chan struct{}) + go func() { + for range mOpenUI.ClickedCh { + bindaddr := env.BindAddress() + if bindaddr == "" { + bindaddr = ":9898" + } + _, port, err := net.SplitHostPort(bindaddr) + if err != nil { + port = "9898" // try the default + } + if err := openBrowser(fmt.Sprintf("http://localhost:%v", port)); err != nil { + reportError(err) + } + } + }() + + // Second item: open the log file in the file explorer + mOpenLog := systray.AddMenuItem("Open Log Dir", "Open the Backrest log directory") + mOpenLog.ClickedCh = make(chan struct{}) + go func() { + for range mOpenLog.ClickedCh { + cmd := exec.Command(`explorer`, `/select,`, env.LogsPath()) + cmd.Start() + go cmd.Wait() + } + }() + + // Last item: quit button to stop the backrest process. + mQuit := systray.AddMenuItem("Quit", "Kills the backrest process and exits the tray app") + mQuit.ClickedCh = make(chan struct{}) + go func() { + <-mQuit.ClickedCh + cancel() + systray.Quit() + }() + }, func() { + cancel() + }) + + if err := cmd.Wait(); err != nil { + systray.Quit() + if ctx.Err() != context.Canceled { + reportError(fmt.Errorf("backrest process exited unexpectedly with error: %w", err)) + } + return + } +} + +func findBackrest() (string, error) { + // Backrest binary must be installed in the same directory as the backresttray binary. + ex, err := os.Executable() + if err != nil { + return "", err + } + dir := filepath.Dir(ex) + + wantPath := filepath.Join(dir, backrestBinName()) + + if stat, err := os.Stat(wantPath); err == nil && !stat.IsDir() { + return wantPath, nil + } + return "", fmt.Errorf("backrest binary not found at %s", wantPath) +} + +func backrestBinName() string { + if runtime.GOOS == "windows" { + return "backrest.exe" + } else { + return "backrest" + } +} + +func openBrowser(url string) error { + switch runtime.GOOS { + case "linux": + return exec.Command("xdg-open", url).Start() + case "windows": + return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() + case "darwin": + return exec.Command("open", url).Start() + default: + return fmt.Errorf("unsupported platform") + } +} + +func reportError(err error) { + zenity.Error(err.Error(), zenity.Title("Backrest Error")) +} diff --git a/cmd/backrestmon/icon.ico b/cmd/backrestmon/icon.ico new file mode 100644 index 000000000..6a4440a3b Binary files /dev/null and b/cmd/backrestmon/icon.ico differ diff --git a/cmd/devtools/oplogexport/main.go b/cmd/devtools/oplogexport/main.go new file mode 100644 index 000000000..e17de767a --- /dev/null +++ b/cmd/devtools/oplogexport/main.go @@ -0,0 +1,77 @@ +package main + +import ( + "bytes" + "compress/gzip" + "flag" + "log" + "os" + "path" + + v1 "github.com/garethgeorge/backrest/gen/go/v1" + "github.com/garethgeorge/backrest/internal/env" + "github.com/garethgeorge/backrest/internal/oplog" + "github.com/garethgeorge/backrest/internal/oplog/bboltstore" + "google.golang.org/protobuf/encoding/prototext" +) + +var ( + outpath = flag.String("export-oplog-path", "", "path to export the oplog as a compressed textproto e.g. .textproto.gz") +) + +func main() { + flag.Parse() + + if *outpath == "" { + flag.Usage() + return + } + + oplogFile := path.Join(env.DataDir(), "oplog.boltdb") + opstore, err := bboltstore.NewBboltStore(oplogFile) + if err != nil { + log.Fatalf("error creating oplog : %v", err) + } + defer opstore.Close() + + output := &v1.OperationList{} + + l, err := oplog.NewOpLog(opstore) + if err != nil { + log.Fatalf("error creating oplog: %v", err) + } + l.Query(oplog.Query{}, func(op *v1.Operation) error { + output.Operations = append(output.Operations, op) + return nil + }) + log.Printf("exporting %d operations", len(output.Operations)) + + bytes, err := prototext.MarshalOptions{Multiline: true}.Marshal(output) + if err != nil { + log.Fatalf("error marshalling operations: %v", err) + } + + bytes, err = compress(bytes) + if err != nil { + log.Fatalf("error compressing operations: %v", err) + } + + if err := os.WriteFile(*outpath, bytes, 0644); err != nil { + log.Fatalf("error writing to file: %v", err) + } +} + +func compress(data []byte) ([]byte, error) { + var buf bytes.Buffer + zw := gzip.NewWriter(&buf) + + if _, err := zw.Write(data); err != nil { + return nil, err + } + + if err := zw.Close(); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/cmd/devtools/oplogimport/main.go b/cmd/devtools/oplogimport/main.go new file mode 100644 index 000000000..0c7b67f45 --- /dev/null +++ b/cmd/devtools/oplogimport/main.go @@ -0,0 +1,70 @@ +package main + +import ( + "bytes" + "compress/gzip" + "flag" + "log" + "os" + "path" + + v1 "github.com/garethgeorge/backrest/gen/go/v1" + "github.com/garethgeorge/backrest/internal/env" + "github.com/garethgeorge/backrest/internal/oplog/bboltstore" + "go.uber.org/zap" + "google.golang.org/protobuf/encoding/prototext" +) + +var ( + outpath = flag.String("import-oplog-path", "", "path to import the oplog from compressed textproto e.g. .textproto.gz") +) + +func main() { + flag.Parse() + + if *outpath == "" { + flag.Usage() + return + } + + // create a reader from the file + f, err := os.Open(*outpath) + if err != nil { + log.Fatalf("error opening file: %v", err) + } + defer f.Close() + + cr, err := gzip.NewReader(f) + if err != nil { + log.Fatalf("error creating gzip reader: %v", err) + } + defer cr.Close() + + // read into a buffer + var buf bytes.Buffer + if _, err := buf.ReadFrom(cr); err != nil { + log.Printf("error reading from gzip reader: %v", err) + } + + log.Printf("importing operations from %q", *outpath) + + output := &v1.OperationList{} + if err := prototext.Unmarshal(buf.Bytes(), output); err != nil { + log.Fatalf("error unmarshalling operations: %v", err) + } + + zap.S().Infof("importing %d operations", len(output.Operations)) + + oplogFile := path.Join(env.DataDir(), "oplog.boltdb") + opstore, err := bboltstore.NewBboltStore(oplogFile) + if err != nil { + log.Fatalf("error creating oplog : %v", err) + } + defer opstore.Close() + + for _, op := range output.Operations { + if err := opstore.Add(op); err != nil { + log.Printf("error adding operation to oplog: %v", err) + } + } +} diff --git a/cmd/devtools/oplogimport/testdata/v1.4.0-config.json b/cmd/devtools/oplogimport/testdata/v1.4.0-config.json new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/devtools/oplogimport/testdata/v1.4.0-ops.v04log.textproto.gz b/cmd/devtools/oplogimport/testdata/v1.4.0-ops.v04log.textproto.gz new file mode 100644 index 000000000..ec77d3188 Binary files /dev/null and b/cmd/devtools/oplogimport/testdata/v1.4.0-ops.v04log.textproto.gz differ diff --git a/cmd/resticui/resticui.go b/cmd/resticui/resticui.go deleted file mode 100644 index 3f83f2b64..000000000 --- a/cmd/resticui/resticui.go +++ /dev/null @@ -1,77 +0,0 @@ -package main - -import ( - "context" - "errors" - "net/http" - "os" - "os/signal" - "sync" - "syscall" - - "github.com/garethgeorge/resticui/internal/api" - "github.com/garethgeorge/resticui/static" - "go.uber.org/zap" - - _ "embed" -) - -func main() { - ctx := context.Background() - ctx, cancel := context.WithCancel(ctx) - go onterm(cancel) - - var wg sync.WaitGroup - - // Configure the HTTP mux - mux := http.NewServeMux() - mux.Handle("/", http.FileServer(http.FS(static.FS))) - - server := &http.Server{ - Addr: ":9090", - Handler: mux, - } - - // Serve the API - wg.Add(1) - go func() { - defer wg.Done() - err := api.ServeAPI(ctx, mux) - if err != nil { - zap.S().Fatal("Error serving API", zap.Error(err)) - } - cancel() // cancel the context when the API server exits (e.g. on fatal error) - }() - - // Serve the HTTP gateway - wg.Add(1) - go func() { - defer wg.Done() - zap.S().Infof("HTTP binding to address %v", server.Addr) - go func() { - <-ctx.Done() - server.Shutdown(context.Background()) - }() - if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { - zap.S().Error("Error starting server", zap.Error(err)) - } - zap.S().Info("HTTP gateway shutdown") - cancel() // cancel the context when the HTTP server exits (e.g. on fatal error) - }() - - wg.Wait() -} - -func init() { - zap.ReplaceGlobals(zap.Must(zap.NewProduction())) - if os.Getenv("DEBUG") != "" { - zap.ReplaceGlobals(zap.Must(zap.NewDevelopmentConfig().Build())) - } -} - -func onterm(callback func()) { - sigchan := make(chan os.Signal, 1) - signal.Notify(sigchan, os.Interrupt, syscall.SIGTERM) - <-sigchan - callback() -} \ No newline at end of file diff --git a/docs/.eslintrc.cjs b/docs/.eslintrc.cjs new file mode 100644 index 000000000..45b86ae35 --- /dev/null +++ b/docs/.eslintrc.cjs @@ -0,0 +1,9 @@ +module.exports = { + root: true, + extends: ["@nuxt/eslint-config"], + ignorePatterns: ["dist", "node_modules", ".output", ".nuxt"], + rules: { + "vue/max-attributes-per-line": "off", + "vue/multi-word-component-names": "off", + }, +}; diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100755 index 000000000..69f6b69d0 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,12 @@ +node_modules +*.iml +.idea +*.log* +.nuxt +.vscode +.DS_Store +coverage +dist +sw.* +.env +.output diff --git a/docs/.npmrc b/docs/.npmrc new file mode 100644 index 000000000..cf0404245 --- /dev/null +++ b/docs/.npmrc @@ -0,0 +1,2 @@ +shamefully-hoist=true +strict-peer-dependencies=false diff --git a/docs/.prettierignore b/docs/.prettierignore new file mode 100644 index 000000000..f59ec20aa --- /dev/null +++ b/docs/.prettierignore @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/docs/app.config.ts b/docs/app.config.ts new file mode 100644 index 000000000..2c02cd477 --- /dev/null +++ b/docs/app.config.ts @@ -0,0 +1,33 @@ +// https://github.com/nuxt-themes/docus/blob/main/nuxt.schema.ts +export default defineAppConfig({ + docus: { + title: "Backrest", + description: "Backrest is a web UI and orchestrator for restic backup.", + // image: 'https://user-images.githubusercontent.com/904724/185365452-87b7ca7b-6030-4813-a2db-5e65c785bf88.png', + socials: { + github: "garethgeorge/backrest", + }, + github: { + dir: "docs/content", + branch: "main", + repo: "backrest", + owner: "garethgeorge", + edit: true, + }, + aside: { + level: 0, + collapsed: false, + exclude: [], + }, + main: { + padded: true, + fluid: true, + }, + header: { + logo: false, + showLinkIcon: true, + exclude: [], + fluid: true, + }, + }, +}); diff --git a/docs/content/0.index.md b/docs/content/0.index.md new file mode 100644 index 000000000..fd3b0a769 --- /dev/null +++ b/docs/content/0.index.md @@ -0,0 +1,73 @@ +--- +title: Home +navigation: false +layout: page +main: + fluid: false +--- + +:ellipsis{right=0px width=75% blur=150px} + +::block-hero +--- +cta: + - Get started + - /introduction/getting-started +secondary: + - Open on GitHub → + - https://github.com/garethgeorge/backrest +--- + +#title +Web UI and orchestrator for [Restic](https://restic.net) backup. + +#description + +Backrest is a web-accessible backup solution built on top of [restic](https://restic.net/) and providing a WebUI which wraps the restic CLI and makes it easy to create repos, browse snapshots, and restore files. Additionally, Backrest can run in the background and take an opinionated approach to scheduling snapshots and orchestrating repo health operations. + + +#extra + ::list + - Import your existing restic repositories + - Cron scheduled backups and health operations (e.g. prune and forget) + - UI for browing and restoring files from snapshots + - Configurable backup notifications (e.g. Discord, Slack, Shoutrrr, Gotify) + - Add shell command hooks to run before and after backup operations. + - Compatible with rclone remotes + - Cross-platform support (Linux, macOS, Windows, FreeBSD, [Docker](https://hub.docker.com/r/garethgeorge/backrest)) + - Backup to any restic supported storage (e.g. S3, B2, Azure, GCS, local, SFTP, and all [rclone remotes](https://rclone.org/)) + :: + +#support +::code-group +```bash [MacOS] +brew tap garethgeorge/homebrew-backrest-tap +brew install backrest +brew services start backrest +``` +```bash [Arch Linux] +paru -Sy backrest +sudo systemctl enable --now backrest@$USER.service +``` +```yaml [docker-compose] +version: "3.2" +services: + backrest: + image: garethgeorge/backrest + container_name: backrest + hostname: backrest + volumes: + - ./backrest/data:/data + - ./backrest/config:/config + - ./backrest/cache:/cache + environment: + - BACKREST_DATA=/data + - BACKREST_CONFIG=/config/config.json + - XDG_CACHE_HOME=/cache + - TZ=America/Los_Angeles + restart: unless-stopped + ports: + - 9898:9898 +``` +:: +:: \ No newline at end of file diff --git a/docs/content/1.introduction/1.getting-started.md b/docs/content/1.introduction/1.getting-started.md new file mode 100644 index 000000000..29706738d --- /dev/null +++ b/docs/content/1.introduction/1.getting-started.md @@ -0,0 +1,111 @@ +# Getting Started + +This guide will walk you through the basic steps to setup a new [Backrest](https://github.com/garethgeorge/backrest) instance. + +## Installation + +See the Github README for installation instructions for your platform. + +## Terminology + +- **Restic Repo** Backrest uses [restic](https://restic.net) under-the-hood to manage backups. A restic repo is a location where restic will store your backup data, this detail is typically abstracted away from the user by Backrest but is important to understand as it means you have the option to use the restic CLI to interact with snapshots created by Backrest directly if you wish. +- **Repo** A Backrest repo (called a Repo from here on) is configuration data which identifies a location where your backup data will be stored (forwarded to restic), the credentials that will encrypt your backup data, hooks, and any options needed by backrest to orchestrate your backups. +- **Plan** A Backrest plan (called a Plan from here on) is configuration data that describes a schedule for taking snapshots, forgetting old snapshots, and running prune operations. Multiple plans can write data to the same Backrest repo. +- **Operations** + - A **Backup** creates a restic snapshot and send it to a repo. + - A **Forget** operation marks old snapshots for deletion but does not remove data from storage. + - A **Prune** operation removes data from storage that is no longer referenced by any snapshot (see [restic docs on forget and prune](https://restic.readthedocs.io/en/latest/060_forget.html)). + - A **Restore** operation retrieves files from a snapshot and writes them to a location on disk. + +## Configuration + +::alert{type="info"} +Once backrest is installed, you can access the web interface at `http://localhost:9898` (or the port you configured). Backrest will immediately prompt you for required initial configuration of an instance ID and a default user and password. +:: + +Instance ID + + * The instance ID is a unique identifier for your Backrest instance. This is used to tag snapshots created by Backrest so that you can distinguish them from snapshots created by other instances. This is useful if you have multiple Backrest instances backing up to the same repo. + * *Notably the instance ID cannot be changed after initial configuration as it is stored in your snapshots. Choose a value carefully.* + +Username and password + + * Username and password is set on first launch of Backrest. If you lose your password you can reset it by deleting the `"users"` key from the `~/.config/backrest/config.json` file (or `%appdata%\backrest\config.json` on Windows) and restarting the Backrest service. + * If you don't want to use authentication (e.g. a local only installation or if you're using an authenticating reverse proxy) you can disabled authentication. + + +#### Add a new repository + +A Backrest repository is implemented as a restic repository under-the-hood (more on this later). A Repo is a configuration object which identifies a storage location and the credentials that will be used to encrypt snapshots sent to that storage. You can either add an existing repo that you created on the restic CLI or create a new one in the Backrest UI. In either case, click the "Add Repo" button in the UI to configure Backrest to use your backup location. + +The primary properties of a repository are: + +- **Repo Name** A human-readable name for the repository. This is used to identify the repository in the UI and is immutable after creation. + +- **Repo URI** identifies the location where the repo's data is stored. This corresponds to the URI used by restic. See [the restic docs](https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html) for the repo types that restic supports. For common storage providers this looks like: + + - Backblaze: `b2:yourbucket` or `b2:yourbucket/pathprefix` + - AWS S3 (or S3 compatible storage): `s3:yourbucket` or `s3:yourbucket/pathprefix` + - SFTP e.g. `sftp:user@host:/path/to/repo` (note `sftp://` is known to have issues in some cases, do not include a double slash prefix). + - Local path: `/mnt/backupdisk/repo1`. + - Rclone remote: `rclone:remote:path`. See the [rclone docs](https://rclone.org/docs/) for more information. To use rclone remotes, you must first install and configure rclone and ensure that the rclone config (e.g. `~/.config/rclone/rclone.conf`) is available to the backrest process. + +- **Environment Variables** environment variables provide additional configuration to restic (typically related to credentials for the storage provider). Common examples are + + - For S3 storage set: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` + - For B2 storage set: `B2_ACCOUNT_ID` and `B2_ACCOUNT_KEY` + +- **Flags** additional flags to provide to restic. At the moment only presence flags are supported. Common usage might include: + + - `-o sftp.args="-i /path/to/key"` will pass an SSH key to restic for use with SFTP repositories. + - `--no-lock` will disable the use of locks in the restic repository. This can be useful for read-only repos. + - `--limit-upload 1000` will limit the upload speed to a speed in kilobytes per second (e.g. 1000KB/s). This can be useful to avoid saturating a network connection. + - `--limit-download 1000` will limit the download speed to a speed in kilobytes per second (e.g. 1000KB/s). This can be useful to avoid saturating a network connection. + +- **Hooks** are actions triggered by backup lifecycle events, repo hooks will apply to actions run by any plan that writes to the repo. Hooks can also be configured at the plan level. See the [hooks documentation](/docs/hooks) for more information. + +- **Prune Policy** the policy that determines when prune operations will run. Prune operations clean up unreferenced data in your repo (freeing up storage in your repo over time). See the [prune documentation](/docs/operations#prune) for more information. +- **Check Policy** the policy that determines when check operations will run. Check operations periodically verify the integrity of your backups. See the [check documentation](/docs/operations#check) for more information. + +::alert{type="info"} +Once you've added your repo you're ready to import snapshots (click Index Snapshots) if you have existing data. Go on to configure a backup plan to start creating new snapshots. +:: + +#### Configure a backup plan + +A Backrest plan is a configuration object which describes a schedule for taking snapshots, retention of old snapshots, and running prune operations. Multiple plans can write data to the same Backrest repo. To create a new plan, click the "Add Plan" button in the UI and populate the plan configuration: + +The primary properties of a plan are: + +- **Plan Name** the plan name is immutable after creation, choose carefully. Organizationally it can help to choose a name that includes the type of storage or a short form of the name of the repo that will be used. E.g. to backup "Documents" directory to "b2storage" you might create a plan named "b2-documents" or similar. + +- **Repository** the repository that this plan will operate on. This is immutable after creation. + +- **Paths** a list of paths to include in backups. + +- **Excludes** a list of paths to exclude from backup operations. These can be fully qualified paths (e.g. /foo/bar/baz) or wildcard paths (e.g. `*node_modules*`). See the [restic docs](https://restic.readthedocs.io/en/latest/040_backup.html#excluding-files) on excluding files for more details. Files listed in excludes map to restic's `--excludes` flag. + +- **Schedule** the schedule on which backups will run. + + - This can be specified as an interval in hours, interval in days, or as a cron providing detailed control over when backups run (e.g. `0 0 * * *` for midnight every day). + - A clock can also be configured which determines the time the schedule is checked against. UTC or Local use the current wall-clock time but will evaluate differently when using cron expressions where the timezone matters. Last Run Time evaluates the schedule relative to the last time the task ran rather than the current wall time, this can be useful for ensuring tasks aren't skipped if the schedule is missed for some reason (e.g. on a laptop that is frequently asleep). + +- **Retention Policy** the duration that snapshots are retained for. This is enforced by running `restic forget` after each backup operation if a retention policy is specified. This can be set to none for append only repos or if you'd like to manage your own retention (e.g. run forget manually). Setting some retention policy is recommended to avoid the snapshot history growing without bound. Retention may be configured either based on count or bucketed by time period. See [the restic docs](https://restic.readthedocs.io/en/latest/060_forget.html#removing-snapshots-according-to-a-policy) to understand more about these policy options. Supported modes are: + + - **By Count** - keeps a fixed number of snapshots. E.g. keep the last 7 snapshots. + - **By Time Period** - keeps snapshots in a time-based bucket. E.g. keep 1 snapshot per day for the last 7 days, 1 snapshot per week for the last 4 weeks, and 1 snapshot per month for the last 12 months. + - **None** - no retention policy is enforced. This is useful for append-only repos or if you'd like to manage retention manually e.g. in an external script. Note that care should be taken not to allow snapshots to grow without bound (though Backrest will typically scale and perform well with hundreds to thousands of snapshots). + +- **Hooks** hooks are actions that can be configured in response to backup lifecycle events. See the [hooks documentation](/docs/hooks) for more information and the [hooks cookbook](/cookbooks/command-hook-examples) for examples. +- **Backup Flags** flags that are specific to the backup command (e.g. `--force` to force a full scan of all files rather than relying on metadata). These flags are passed directly to the restic command. + - `--one-file-system` will prevent restic crossing filesystem boundaries. + - `--force` will force rereading all files on each backup rather than relying on metadata (e.g. last modified time). This can be much slower. + - `--skip-if-unchanged` will skip creating a new snapshot if nothing has changed on the filesystem. Note that the backup task will still appear in the 'Full Operation History' but not in the tree view. Snapshots will still be created if any file or folder metadata changes (e.g. permissions, access times, etc). + +::alert{type="success"} +Success! Now that Backrest is configured you can sit back and let it manage your backups. You can monitor the status of your backups in the UI and restore files from snapshots as needed. +:: + +::alert{type="warning"} +Make sure that you save a copy of your repo credentials and any encryption keys (e.g. the password) in a safe place. If you lose these you will not be able to restore your data. It can be a good idea to store your entire Backrest config (typically located at `~/.config/backrest/config.json`) in a secure location e.g. a password manager or encrypted storage. +:: diff --git a/docs/content/1.introduction/_dir.yml b/docs/content/1.introduction/_dir.yml new file mode 100644 index 000000000..ff0894dab --- /dev/null +++ b/docs/content/1.introduction/_dir.yml @@ -0,0 +1,2 @@ +icon: ph:star-duotone +navigation.redirect: /introduction/getting-started diff --git a/docs/content/2.docs/1.operations.md b/docs/content/2.docs/1.operations.md new file mode 100644 index 000000000..d15fd5aa4 --- /dev/null +++ b/docs/content/2.docs/1.operations.md @@ -0,0 +1,94 @@ +# Operation Details + +This section describes the operations that Backrest can be configured to perform on your behalf in detail. + +## Overview + +Backrest executes commands by forking the [restic](https://restic.net) binary. Each Backrest version is validated against a specific version of restic. On startup Backrest searches for a versioned restic in its data directory (typically `~/.local/share/backrest`), followed by `/bin/`. The restic binary must be named `restic-{VERSION}`. You can override restic command by setting `BACKREST_RESTIC_COMMAND` env variable when starting Backrest. Otherwise, if no binary is found Backrest will download and install a recent version of restic from [restic's github releases](https://github.com/restic/restic/releases/tag/v0.16.4). When downloading a restic binary, the download is verified by checking the sha256sum of the downloaded binary against the sha256sum provided by restic and signed by the restic maintainers GPG key. + +When running restic commands, Backrest injects the environment variables configured in the repo into the environment of the restic process and it appends the flags configured in the repo to the command line arguments of the restic process. Logs are collected for each command. In the case of an error, Backrest captures the last ~500 bytes of output and displays this directly in the error message (the first and last 250 bytes are shown if the output is longer than 500 bytes). Logs of the command are typically also available by clicking \[View Logs\] next to an operation, these logs are truncated to 32KB (with the first and last 16KB shown if the log is longer than 32KB). + +## Scheduling Operations + +Operations run on configurable schedules and all support the same collection of scheduling policies that provide flexible behavior. + +Available scheduling **policies** are: + + * **Disabled** - the operation is disabled and will not run. + * **Cron** - a cron expression specifying when to run the operation, this allows you to specify tasks that run at specific times down to the minute with detailed control e.g. `0 0 * * *` to run daily at midnight. See [Cron Syntax](https://en.wikipedia.org/wiki/Cron#Syntax) for more information. + * **Interval Days** - the interval in days at which the operation should be run. This is useful for running tasks at a regular interval when you don't care about the exact run time. Tasks will run no more frequently than the specified interval. + * **Interval Hours** - the interval in hours at which the operation should be run. This is useful for running tasks at a regular interval when you don't care about the exact run time. Tasks will run no more frequently than the specified interval. + +In addition to the scheduling policy, a schedule also specifies a **clock** which the policy is evaluated relative to: + + * **Local** - the schedule is evaluated against the current wall-clock time in the local timezone. + * **UTC** - the schedule is evaluated against the current wall-clock time in UTC. (Only behaves differently from Local when using cron expressions). + * **Last Run Time** - the schedule is evaluated relative to the last time the task ran. This can be useful for ensuring tasks aren't skipped if the schedule is missed for some reason (e.g. on a laptop that is frequently asleep). It also important to use this clock for tasks that run _very_ infrequently (e.g. check and prune health check operations) to ensure they aren't skipped. + +::alert{type="info"} +**Backup** operations are scheduled under plan settings in the UI. Good practice is to use the "Local" clock if running hourly or more frequently. Use the "Last Run Time" clock if running daily or less frequently. +

+**Prune** and **Check** operations are scheduled under repo settings in the UI. Good practice is to run these operations infrequently (e.g. every 30 days if using "Interval Days" or on the 3rd of the month, for example, if using "cron" scheduling"). Because health operations will be infrequent, it is recommended to use the "Last Run Time" clock to ensure they are not skipped. +:: + +## Types of Operations + +#### Backup + +[Restic docs on backup](https://restic.readthedocs.io/en/latest/040_backup.html) + +Backups are scheduled under plan settings in the UI. A backup operation creates a snapshot of your data and sends it to a repository. The snapshot is created using the `restic backup` command. + +As the backup runs Backrest will display the progress of the backup operation in the UI. The progress information is parsed from the JSON output of the `restic backup` command. + +The backup flow is as follows + +- Hook trigger: `CONDITION_SNAPSHOT_START`, if any hooks are configured for this event they will run. + - If any hook exits with a non-zero status, the hook's failure policy will be applied (e.g. cancelling or failing the backup operation). +- The `restic backup` command is run. The newly created snapshot is tagged with the ID of the plan creating it e.g. `plan:{PLAN_ID}`. +- On backup completion + - The summary event is parsed from the backup and is stored in the operation's metadata. This includes: files added, files changed, files unmodified, total files processed, bytes added, bytes processed, and most importantly the snapshot ID. + - If an error occurred: hook trigger `CONDITION_SNAPSHOT_ERROR`, if any hooks are configured for this event they will run. + - If successful: hook trigger `CONDITION_SNAPSHOT_SUCCESS`, if any hooks are configured for this event they will run. + - Finally `CONDITION_SNAPSHOT_END` is triggered irrespective of success or failure, if any hooks are configured for this event they will run. This condition is always triggered even if the backup failed. + - If a retention policy is set (e.g. not `None`) a forget operation is triggered for the backup plan. + +Created backups are tagged with some Backrest specific metadata: + + - `plan:{PLAN_ID}` - the ID of the plan that created the snapshot. This is used to group snapshots by plan in the UI. + - `created-by:{INSTANCE_ID}` - the unique ID of the Backrest instance that created the snapshot. This is used to group snapshots by instance in the UI. Notably, this not necessarily the same as the hostname tracked by restic in the snapshot. + +#### Forget + +[Restic docs on forget](https://restic.readthedocs.io/en/latest/060_forget.html) + +Forget operations are scheduled by the "forget policy" configured in plan settings in the UI. Forget operations run after backups. A forget operation marks old snapshots for deletion but does not remove data from storage until a prune runs. The forget operation is run using the `restic forget --tag plan:{PLAN_ID}` command. + +Retention policies are mapped to forget arguments: + +- **By Count** maps to `--keep-last {COUNT}` +- **By Time Period** maps to the `--keep-{hourly,daily,weekly,monthly,yearly} {COUNT}` flags + +#### Prune + +[Restic docs on prune](https://restic.readthedocs.io/en/latest/060_forget.html) + +Prune operations are scheduled under repo settings in the UI. A prune operation removes data from storage that is no longer referenced by any snapshot. The prune operation is run using the `restic prune` command. Prune operations apply to the entire repo and will show up under the `_system_` plan in the Backrest UI. + +Prunes are run in compliance with a prune policy which configures a *schedule* and a *max unused percent*. The max unused percent is the percentage of data that may remain unreferenced after a prune operation. The prune operation will repack or delete unreferenced data until the repo falls under this limit, if it already is it's possible that a prune will complete immediately. + +::alert{type="info"} +Prune operations are costly and may read a significant portion of your repo. Prune costs are mitigated by running them infrequently (e.g. monthly or every 30 days), and by using a higher *max unused percent* value (e.g. 5% or 10%). A higher *max unused percent* value will result in more data being retained in the repo, but will reduce the need to repack partially unreferenced data. +:: + +#### Check + +[Restic docs on check](https://restic.readthedocs.io/en/latest/080_check.html) + +Check operations are scheduled under repo settings in the UI. A check operation verifies the integrity of the repository. The check operation is run using the `restic check` command. Check operations apply to the entire repo and will show up under the `_system_` plan in the Backrest UI. + +Checks are configured by a *schdule* determining when they run, and a single argument *read data %* which determines the percentage of the repository that should be read during a check operation. Irrespective of *read data%*, the structure of the repo will always be verified in entirety. Reading data back verifies the hashes of pack files on disk and may detect unreliable storage (e.g. an HDD running without parity). It typically does not provide much value for a reliable cloud storage provider and can be set to a low percentage or disabled. + +::alert{type="warning"} +A value of 100% for *read data%* will read/download every pack file in your repository. This can be very slow and, if your provider bills for egress bandwidth, can be expensive. It is recommended to set this to 0% or a low value (e.g. 10%) for most use cases. +:: \ No newline at end of file diff --git a/docs/content/2.docs/2.hooks.md b/docs/content/2.docs/2.hooks.md new file mode 100644 index 000000000..e8d8dc4e5 --- /dev/null +++ b/docs/content/2.docs/2.hooks.md @@ -0,0 +1,102 @@ +# Hook Details + +## Hook Types + +Backrest supports hooks in response to operation lifecycle events e.g. in response to the commands it runs on your behalf. + +Available event types are + +- `CONDITION_ANY_ERROR` any operation has failed. +- `CONDITION_SNAPSHOT_START` the start of a backup operation (e.g. corresponds to a call to `restic backup`, supports error behavior) +- `CONDITION_SNAPSHOT_END` the end of a backup operation (e.g. corresponds to `restic backup` completing). Note that Snapshot End will still be called if a backup failed. +- `CONDITION_SNAPSHOT_ERROR` an error occurred during a backup operation (e.g. `restic backup` returned a non-zero exit code OR invalid output). +- `CONDITION_SNAPSHOT_WARNING` a warning occurred during a backup operation (e.g. a file was partially read). +- `CONDITION_SNAPSHOT_SUCCESS` a backup operation completed successfully. +- Prune hooks: + - `CONDITION_PRUNE_START` the start of a prune operation (e.g. corresponds to a call to `restic prune`, supports error behavior) + - `CONDITION_PRUNE_SUCCESS` the end of a prune operation e.g. `restic prune` completed successfully. + - `CONDITION_PRUNE_ERROR` an error occurred during a prune operation (e.g. `restic prune` returned a non-zero exit code). +- Check hooks: + - `CONDITION_CHECK_START` the start of a check operation (e.g. corresponds to a call to `restic check`, supports error behavior) + - `CONDITION_CHECK_SUCCESS` the end of a check operation e.g. `restic check` completed successfully. + - `CONDITION_CHECK_ERROR` an error occurred during a check operation (e.g. `restic check` returned a non-zero exit code). + +## Notification Services + +| Service | Docs | +| -------- | ------------------------------------------------------------------------- | +| Discord | https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks | +| Slack | https://api.slack.com/messaging/webhooks | +| Gotify | https://github.com/gotify/server | +| Shoutrrr | https://containrrr.dev/shoutrrr/v0.8/ | +| Command | See command cookbook | + + +## Error Behavior + +Some hooks can specify an error behavior (today this is only command hooks). This determines what happens when the hook generates an error. + +The available error behaviors are: + +- `ON_ERROR_IGNORE` - ignore the error and continue running hooks and the operation. +- `ON_ERROR_CANCEL` - cancel the operation and do not run any further hooks. The operation is marked as cancelled. +- `ON_ERROR_FATAL` - cancel the operation and do not run any further hooks. The operation is marked as failed and error handler hooks may be triggered. + +## Using Templates + +Most hooks will generate either a notification or execute a script. The script / notification is typically formatted as a Go template. The https://pkg.go.dev/text/template docs provide a very technical overview of Go template capabilities. See below for info about the available variables and for some examples. + +Variables + +- `Event:v1.Hook_Condition` - the event that triggered the backup. This is an enum. Values are one of: Hook_CONDITION_SNAPSHOT_START, Hook_CONDITION_SNAPSHOT_END, Hook_CONDITION_ANY_ERROR, Hook_CONDITION_SNAPSHOT_ERROR . +- `Task:string` - the name of the task that triggered the hook (e.g. `one time backup for plan "foo"` +- `Repo:v1.Repo` - the repo that triggered the backup. This is a struct. Access the name as `{{ .Repo.Id }}` +- `Plan:v1.Plan` - the plan that triggered the backup. This is a struct. Access the name as `{{ .Plan.Id }}` +- `SnapshotId:string` - the snapshot ID associated with the operation or empty string if none is associated. +- `SnapshotStats:restic.BackupProgressEntry` - summary of the current backup operation. This is a struct. See examples below for details. +- `CurTime:time.Time` - the current time. This is a struct. Format as `{{ .FormatTime .CurTime }}`. +- `Duration:time.Duration` - the duration of the triggering operation. Format as `{{ .FormatDuration .Duration }}`. +- `Error:string` - the error message if an error occurred, or empty string if successful. + +Functions + +- `.Summary` - prints a default summary of the current event. +- `.FormatTime