Compare commits

..

3 Commits

Author SHA1 Message Date
Boris Bera
0a94869fc6 Merge 51a8298f2a into 6424c64304 2024-10-10 16:30:39 -04:00
Boris Bera
51a8298f2a doc(lockfile): Document --lockfile-path flag 2024-07-02 21:15:00 -04:00
Boris Bera
f6aa45fd6c feat(lockfile): allow changing the lockfile path 2024-07-02 21:12:26 -04:00
16 changed files with 186 additions and 221 deletions

View File

@@ -1,4 +1,4 @@
FROM golang:1.25-alpine as builder
FROM golang:1.23-alpine as builder
WORKDIR /app
COPY go.* .
@@ -6,7 +6,7 @@ RUN go mod download
COPY . .
RUN go build
FROM restic/restic:0.17.3
FROM restic/restic:0.17.1
RUN apk add --no-cache rclone bash curl docker-cli
COPY --from=builder /app/autorestic /usr/bin/autorestic
ENTRYPOINT []

View File

@@ -18,11 +18,9 @@ var backupCmd = &cobra.Command{
err := lock.Lock()
CheckErr(err)
defer lock.Unlock()
dry, _ := cmd.Flags().GetBool("dry-run")
selected, err := internal.GetAllOrSelected(cmd, false)
CheckErr(err)
errors := 0
for _, name := range selected {
var splitted = strings.Split(name, "@")
@@ -31,7 +29,7 @@ var backupCmd = &cobra.Command{
specificBackend = splitted[1]
}
location, _ := internal.GetLocation(splitted[0])
errs := location.Backup(false, dry, specificBackend)
errs := location.Backup(false, specificBackend)
for _, err := range errs {
colors.Error.Printf("%s\n\n", err)
errors++
@@ -46,5 +44,4 @@ var backupCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(backupCmd)
internal.AddFlagsToCommand(backupCmd, false)
backupCmd.Flags().Bool("dry-run", false, "do not write changes, show what would be affected")
}

View File

@@ -42,6 +42,7 @@ func init() {
rootCmd.PersistentFlags().BoolVarP(&flags.VERBOSE, "verbose", "v", false, "verbose mode")
rootCmd.PersistentFlags().StringVar(&flags.RESTIC_BIN, "restic-bin", "restic", "specify custom restic binary")
rootCmd.PersistentFlags().StringVar(&flags.DOCKER_IMAGE, "docker-image", "cupcakearmy/autorestic:"+internal.VERSION, "specify a custom docker image")
rootCmd.PersistentFlags().StringVar(&flags.LOCKFILE_PATH, "lockfile-path", "", "specify a custom path for the lockfile (defaults to .autorestic.lock.yml next to the loaded autorestic config file)")
cobra.OnInitialize(initConfig)
}

View File

@@ -5,7 +5,7 @@
"start": "NEXT_TELEMETRY_DISABLED=1 next start"
},
"dependencies": {
"next": "^14.2.32",
"next": "^14.2.7",
"nextra": "^2.13.4",
"nextra-theme-docs": "^2.13.4",
"react": "^18.3.1",

View File

@@ -1,14 +1,11 @@
# Backup
```bash
autorestic backup [-l, --location] [-a, --all] [--dry-run]
autorestic backup [-l, --location] [-a, --all]
```
Performs a backup of all locations if the `-a` flag is passed. To only backup some locations pass one or more `-l` or `--location` flags.
The `--dry-run` flag will do a dry run showing what would have been deleted, but won't touch the actual data.
```bash
# All
autorestic backup -a

View File

@@ -34,3 +34,11 @@ With `--restic-bin` you can specify to run a specific restic binary. This can be
```bash
autorestic --restic-bin /some/path/to/my/custom/restic/binary
```
## `--lockfile-path`
Specify the path for the lockfile used by `autorestic`. If omitted, this will default to `.autorestic.lock.yml` next to the loaded config file.
```bash
autorestic --lockfile-path /path/to/my/.autorestic.lock.yml
```

157
docs/pnpm-lock.yaml generated
View File

@@ -9,14 +9,14 @@ importers:
.:
dependencies:
next:
specifier: ^14.2.32
version: 14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
specifier: ^14.2.7
version: 14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nextra:
specifier: ^2.13.4
version: 2.13.4(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
version: 2.13.4(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nextra-theme-docs:
specifier: ^2.13.4
version: 2.13.4(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
version: 2.13.4(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react:
specifier: ^18.3.1
version: 18.3.1
@@ -136,59 +136,59 @@ packages:
resolution: {integrity: sha512-jMxvwzkKzd3cXo2EB9GM2ic0eYo2rP/BS6gJt6HnWbsDO1O8GSD4k7o2Cpr2YERtMpGF/MGcDfsfj2EbQPtrXw==}
engines: {node: '>= 10'}
'@next/env@14.2.32':
resolution: {integrity: sha512-n9mQdigI6iZ/DF6pCTwMKeWgF2e8lg7qgt5M7HXMLtyhZYMnf/u905M18sSpPmHL9MKp9JHo56C6jrD2EvWxng==}
'@next/env@14.2.7':
resolution: {integrity: sha512-OTx9y6I3xE/eih+qtthppwLytmpJVPM5PPoJxChFsbjIEFXIayG0h/xLzefHGJviAa3Q5+Fd+9uYojKkHDKxoQ==}
'@next/swc-darwin-arm64@14.2.32':
resolution: {integrity: sha512-osHXveM70zC+ilfuFa/2W6a1XQxJTvEhzEycnjUaVE8kpUS09lDpiDDX2YLdyFCzoUbvbo5r0X1Kp4MllIOShw==}
'@next/swc-darwin-arm64@14.2.7':
resolution: {integrity: sha512-UhZGcOyI9LE/tZL3h9rs/2wMZaaJKwnpAyegUVDGZqwsla6hMfeSj9ssBWQS9yA4UXun3pPhrFLVnw5KXZs3vw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@next/swc-darwin-x64@14.2.32':
resolution: {integrity: sha512-P9NpCAJuOiaHHpqtrCNncjqtSBi1f6QUdHK/+dNabBIXB2RUFWL19TY1Hkhu74OvyNQEYEzzMJCMQk5agjw1Qg==}
'@next/swc-darwin-x64@14.2.7':
resolution: {integrity: sha512-ys2cUgZYRc+CbyDeLAaAdZgS7N1Kpyy+wo0b/gAj+SeOeaj0Lw/q+G1hp+DuDiDAVyxLBCJXEY/AkhDmtihUTA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@next/swc-linux-arm64-gnu@14.2.32':
resolution: {integrity: sha512-v7JaO0oXXt6d+cFjrrKqYnR2ubrD+JYP7nQVRZgeo5uNE5hkCpWnHmXm9vy3g6foMO8SPwL0P3MPw1c+BjbAzA==}
'@next/swc-linux-arm64-gnu@14.2.7':
resolution: {integrity: sha512-2xoWtE13sUJ3qrC1lwE/HjbDPm+kBQYFkkiVECJWctRASAHQ+NwjMzgrfqqMYHfMxFb5Wws3w9PqzZJqKFdWcQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@next/swc-linux-arm64-musl@14.2.32':
resolution: {integrity: sha512-tA6sIKShXtSJBTH88i0DRd6I9n3ZTirmwpwAqH5zdJoQF7/wlJXR8DkPmKwYl5mFWhEKr5IIa3LfpMW9RRwKmQ==}
'@next/swc-linux-arm64-musl@14.2.7':
resolution: {integrity: sha512-+zJ1gJdl35BSAGpkCbfyiY6iRTaPrt3KTl4SF/B1NyELkqqnrNX6cp4IjjjxKpd64/7enI0kf6b9O1Uf3cL0pw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@next/swc-linux-x64-gnu@14.2.32':
resolution: {integrity: sha512-7S1GY4TdnlGVIdeXXKQdDkfDysoIVFMD0lJuVVMeb3eoVjrknQ0JNN7wFlhCvea0hEk0Sd4D1hedVChDKfV2jw==}
'@next/swc-linux-x64-gnu@14.2.7':
resolution: {integrity: sha512-m6EBqrskeMUzykBrv0fDX/28lWIBGhMzOYaStp0ihkjzIYJiKUOzVYD1gULHc8XDf5EMSqoH/0/TRAgXqpQwmw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@next/swc-linux-x64-musl@14.2.32':
resolution: {integrity: sha512-OHHC81P4tirVa6Awk6eCQ6RBfWl8HpFsZtfEkMpJ5GjPsJ3nhPe6wKAJUZ/piC8sszUkAgv3fLflgzPStIwfWg==}
'@next/swc-linux-x64-musl@14.2.7':
resolution: {integrity: sha512-gUu0viOMvMlzFRz1r1eQ7Ql4OE+hPOmA7smfZAhn8vC4+0swMZaZxa9CSIozTYavi+bJNDZ3tgiSdMjmMzRJlQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@next/swc-win32-arm64-msvc@14.2.32':
resolution: {integrity: sha512-rORQjXsAFeX6TLYJrCG5yoIDj+NKq31Rqwn8Wpn/bkPNy5rTHvOXkW8mLFonItS7QC6M+1JIIcLe+vOCTOYpvg==}
'@next/swc-win32-arm64-msvc@14.2.7':
resolution: {integrity: sha512-PGbONHIVIuzWlYmLvuFKcj+8jXnLbx4WrlESYlVnEzDsa3+Q2hI1YHoXaSmbq0k4ZwZ7J6sWNV4UZfx1OeOlbQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@next/swc-win32-ia32-msvc@14.2.32':
resolution: {integrity: sha512-jHUeDPVHrgFltqoAqDB6g6OStNnFxnc7Aks3p0KE0FbwAvRg6qWKYF5mSTdCTxA3axoSAUwxYdILzXJfUwlHhA==}
'@next/swc-win32-ia32-msvc@14.2.7':
resolution: {integrity: sha512-BiSY5umlx9ed5RQDoHcdbuKTUkuFORDqzYKPHlLeS+STUWQKWziVOn3Ic41LuTBvqE0TRJPKpio9GSIblNR+0w==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
'@next/swc-win32-x64-msvc@14.2.32':
resolution: {integrity: sha512-2N0lSoU4GjfLSO50wvKpMQgKd4HdI2UHEhQPPPnlgfBJlOgJxkjpkYBqzk08f1gItBB6xF/n+ykso2hgxuydsA==}
'@next/swc-win32-x64-msvc@14.2.7':
resolution: {integrity: sha512-pxsI23gKWRt/SPHFkDEsP+w+Nd7gK37Hpv0ngc5HpWy2e7cKx9zR/+Q2ptAUqICNTecAaGWvmhway7pj/JLEWA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -319,8 +319,8 @@ packages:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
caniuse-lite@1.0.30001739:
resolution: {integrity: sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==}
caniuse-lite@1.0.30001653:
resolution: {integrity: sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==}
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@@ -789,7 +789,6 @@ packages:
lodash.get@4.4.2:
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
deprecated: This package is deprecated. Use the optional chaining (?.) operator instead.
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
@@ -1001,8 +1000,8 @@ packages:
ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
@@ -1027,8 +1026,8 @@ packages:
react: '*'
react-dom: '*'
next@14.2.32:
resolution: {integrity: sha512-fg5g0GZ7/nFc09X8wLe6pNSU8cLWbLRG3TZzPJ1BJvi2s9m7eF991se67wliM9kR5yLHRkyGKU49MMx58s3LJg==}
next@14.2.7:
resolution: {integrity: sha512-4Qy2aK0LwH4eQiSvQWyKuC7JXE13bIopEQesWE0c/P3uuNRnZCQanI0vsrMLmUQJLAto+A+/8+sve2hd+BQuOQ==}
engines: {node: '>=18.17.0'}
hasBin: true
peerDependencies:
@@ -1102,8 +1101,8 @@ packages:
periscopic@3.1.0:
resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
postcss@8.4.31:
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
@@ -1211,8 +1210,8 @@ packages:
resolution: {integrity: sha512-Pdz01AvCAottHTPQGzndktFNdbRA75BgOfeT1hH+AMnJFv8lynkPi42rfeEhpx1saTEI3YNMWxfqu0sFD1G8pw==}
engines: {node: '>=12'}
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
source-map-js@1.2.0:
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
engines: {node: '>=0.10.0'}
source-map@0.7.4:
@@ -1281,8 +1280,8 @@ packages:
resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
engines: {node: '>=6.10'}
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
tslib@2.7.0:
resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
type-fest@1.4.0:
resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==}
@@ -1503,33 +1502,33 @@ snapshots:
'@napi-rs/simple-git-win32-arm64-msvc': 0.1.19
'@napi-rs/simple-git-win32-x64-msvc': 0.1.19
'@next/env@14.2.32': {}
'@next/env@14.2.7': {}
'@next/swc-darwin-arm64@14.2.32':
'@next/swc-darwin-arm64@14.2.7':
optional: true
'@next/swc-darwin-x64@14.2.32':
'@next/swc-darwin-x64@14.2.7':
optional: true
'@next/swc-linux-arm64-gnu@14.2.32':
'@next/swc-linux-arm64-gnu@14.2.7':
optional: true
'@next/swc-linux-arm64-musl@14.2.32':
'@next/swc-linux-arm64-musl@14.2.7':
optional: true
'@next/swc-linux-x64-gnu@14.2.32':
'@next/swc-linux-x64-gnu@14.2.7':
optional: true
'@next/swc-linux-x64-musl@14.2.32':
'@next/swc-linux-x64-musl@14.2.7':
optional: true
'@next/swc-win32-arm64-msvc@14.2.32':
'@next/swc-win32-arm64-msvc@14.2.7':
optional: true
'@next/swc-win32-ia32-msvc@14.2.32':
'@next/swc-win32-ia32-msvc@14.2.7':
optional: true
'@next/swc-win32-x64-msvc@14.2.32':
'@next/swc-win32-x64-msvc@14.2.7':
optional: true
'@popperjs/core@2.11.8': {}
@@ -1539,7 +1538,7 @@ snapshots:
'@swc/helpers@0.5.5':
dependencies:
'@swc/counter': 0.1.3
tslib: 2.8.1
tslib: 2.7.0
'@tanstack/react-virtual@3.10.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@@ -1651,7 +1650,7 @@ snapshots:
dependencies:
streamsearch: 1.1.0
caniuse-lite@1.0.30001739: {}
caniuse-lite@1.0.30001653: {}
ccount@2.0.1: {}
@@ -2688,7 +2687,7 @@ snapshots:
ms@2.1.2: {}
nanoid@3.3.11: {}
nanoid@3.3.7: {}
next-mdx-remote@4.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
@@ -2701,44 +2700,44 @@ snapshots:
transitivePeerDependencies:
- supports-color
next-seo@6.5.0(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
next-seo@6.5.0(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
next: 14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next: 14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
next-themes@0.2.1(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
next-themes@0.2.1(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
next: 14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next: 14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@next/env': 14.2.32
'@next/env': 14.2.7
'@swc/helpers': 0.5.5
busboy: 1.6.0
caniuse-lite: 1.0.30001739
caniuse-lite: 1.0.30001653
graceful-fs: 4.2.11
postcss: 8.4.31
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
styled-jsx: 5.1.1(react@18.3.1)
optionalDependencies:
'@next/swc-darwin-arm64': 14.2.32
'@next/swc-darwin-x64': 14.2.32
'@next/swc-linux-arm64-gnu': 14.2.32
'@next/swc-linux-arm64-musl': 14.2.32
'@next/swc-linux-x64-gnu': 14.2.32
'@next/swc-linux-x64-musl': 14.2.32
'@next/swc-win32-arm64-msvc': 14.2.32
'@next/swc-win32-ia32-msvc': 14.2.32
'@next/swc-win32-x64-msvc': 14.2.32
'@next/swc-darwin-arm64': 14.2.7
'@next/swc-darwin-x64': 14.2.7
'@next/swc-linux-arm64-gnu': 14.2.7
'@next/swc-linux-arm64-musl': 14.2.7
'@next/swc-linux-x64-gnu': 14.2.7
'@next/swc-linux-x64-musl': 14.2.7
'@next/swc-win32-arm64-msvc': 14.2.7
'@next/swc-win32-ia32-msvc': 14.2.7
'@next/swc-win32-x64-msvc': 14.2.7
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
nextra-theme-docs@2.13.4(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
nextra-theme-docs@2.13.4(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@headlessui/react': 1.7.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@popperjs/core': 2.11.8
@@ -2749,16 +2748,16 @@ snapshots:
git-url-parse: 13.1.1
intersection-observer: 0.12.2
match-sorter: 6.3.4
next: 14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-seo: 6.5.0(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-themes: 0.2.1(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nextra: 2.13.4(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next: 14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-seo: 6.5.0(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-themes: 0.2.1(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nextra: 2.13.4(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
scroll-into-view-if-needed: 3.1.0
zod: 3.23.8
nextra@2.13.4(next@14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
nextra@2.13.4(next@14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@headlessui/react': 1.7.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@mdx-js/mdx': 2.3.0
@@ -2772,7 +2771,7 @@ snapshots:
gray-matter: 4.0.3
katex: 0.16.11
lodash.get: 4.4.2
next: 14.2.32(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next: 14.2.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
next-mdx-remote: 4.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
p-limit: 3.1.0
react: 18.3.1
@@ -2839,13 +2838,13 @@ snapshots:
estree-walker: 3.0.3
is-reference: 3.0.2
picocolors@1.1.1: {}
picocolors@1.0.1: {}
postcss@8.4.31:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
nanoid: 3.3.7
picocolors: 1.0.1
source-map-js: 1.2.0
property-information@6.5.0: {}
@@ -2981,7 +2980,7 @@ snapshots:
dependencies:
is-plain-obj: 4.1.0
source-map-js@1.2.1: {}
source-map-js@1.2.0: {}
source-map@0.7.4: {}
@@ -3030,7 +3029,7 @@ snapshots:
ts-dedent@2.2.0: {}
tslib@2.8.1: {}
tslib@2.7.0: {}
type-fest@1.4.0: {}

View File

@@ -1,5 +1,5 @@
#!/bin/bash
set -e -o pipefail
shopt -s nocaseglob
OUT_FILE=/usr/local/bin/autorestic

View File

@@ -14,19 +14,19 @@ import (
)
type BackendRest struct {
User string `mapstructure:"user,omitempty" yaml:"user,omitempty"`
Password string `mapstructure:"password,omitempty" yaml:"password,omitempty"`
User string `mapstructure:"user,omitempty"`
Password string `mapstructure:"password,omitempty"`
}
type Backend struct {
name string
Type string `mapstructure:"type,omitempty" yaml:"type,omitempty"`
Path string `mapstructure:"path,omitempty" yaml:"path,omitempty"`
Key string `mapstructure:"key,omitempty" yaml:"key,omitempty"`
RequireKey bool `mapstructure:"requireKey,omitempty" yaml:"requireKey,omitempty"`
Env map[string]string `mapstructure:"env,omitempty" yaml:"env,omitempty"`
Rest BackendRest `mapstructure:"rest,omitempty" yaml:"rest,omitempty"`
Options Options `mapstructure:"options,omitempty" yaml:"options,omitempty"`
Type string `mapstructure:"type,omitempty"`
Path string `mapstructure:"path,omitempty"`
Key string `mapstructure:"key,omitempty"`
RequireKey bool `mapstructure:"requireKey,omitempty"`
Env map[string]string `mapstructure:"env,omitempty"`
Rest BackendRest `mapstructure:"rest,omitempty"`
Options Options `mapstructure:"options,omitempty"`
}
func GetBackend(name string) (Backend, bool) {

View File

@@ -23,11 +23,11 @@ type OptionMap map[string][]interface{}
type Options map[string]OptionMap
type Config struct {
Version string `mapstructure:"version" yaml:"version"`
Extras interface{} `mapstructure:"extras" yaml:"extras"`
Locations map[string]Location `mapstructure:"locations" yaml:"locations"`
Backends map[string]Backend `mapstructure:"backends" yaml:"backends"`
Global Options `mapstructure:"global" yaml:"global"`
Version string `mapstructure:"version"`
Extras interface{} `mapstructure:"extras"`
Locations map[string]Location `mapstructure:"locations"`
Backends map[string]Backend `mapstructure:"backends"`
Global Options `mapstructure:"global"`
}
var once sync.Once
@@ -188,34 +188,18 @@ func CheckConfig() error {
if !CheckIfResticIsCallable() {
return fmt.Errorf(`%s was not found. Install either with "autorestic install" or manually`, flags.RESTIC_BIN)
}
cwd, _ := GetPathRelativeToConfig(".")
for name, location := range c.Locations {
location.name = name
// Hooks before location validation
options := ExecuteOptions{
Command: "bash",
Dir: cwd,
Envs: map[string]string{
"AUTORESTIC_LOCATION": location.name,
},
}
if err := location.ExecuteHooks(location.Hooks.PreValidate, options); err != nil {
return err
}
if err := location.validate(); err != nil {
return err
}
}
for name, backend := range c.Backends {
backend.name = name
if err := backend.validate(); err != nil {
return err
}
}
for name, location := range c.Locations {
location.name = name
if err := location.validate(); err != nil {
return err
}
}
return nil
}

View File

@@ -1,15 +1,10 @@
package internal
import (
"path"
"reflect"
"strconv"
"strings"
"sync"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
)
func TestOptionToString(t *testing.T) {
@@ -148,48 +143,6 @@ func TestGetOptionsMultipleKeys(t *testing.T) {
reflect.DeepEqual(result, expected)
}
func TestSaveConfigProducesReadableConfig(t *testing.T) {
workDir := t.TempDir()
viper.SetConfigFile(path.Join(workDir, ".autorestic.yml"))
// Required to appease the config reader
viper.Set("version", 2)
c := Config{
Version: "2",
Locations: map[string]Location{
"test": {
Type: "local",
name: "test",
From: []string{"in-dir"},
To: []string{"test"},
// ForgetOption & ConfigOption have previously marshalled in a way that
// can't get read correctly
ForgetOption: "foo",
CopyOption: map[string][]string{"foo": {"bar"}},
},
},
Backends: map[string]Backend{
"test": {
name: "test",
Type: "local",
Path: "backup-target",
Key: "supersecret",
},
},
}
err := c.SaveConfig()
assert.NoError(t, err)
// Ensure we the config reading logic actually runs
config = nil
once = sync.Once{}
readConfig := GetConfig()
assert.NotNil(t, readConfig)
assert.Equal(t, c, *readConfig)
}
func assertEqual[T comparable](t testing.TB, result, expected T) {
t.Helper()

View File

@@ -1,22 +1,12 @@
package internal
import (
"errors"
"fmt"
)
func RunCron() error {
c := GetConfig()
var errs []error
for name, l := range c.Locations {
l.name = name
if err := l.RunCron(); err != nil {
errs = append(errs, err)
return err
}
}
if len(errs) > 0 {
return fmt.Errorf("Encountered errors during cron process:\n%w", errors.Join(errs...))
}
return nil
}

View File

@@ -1,9 +1,10 @@
package flags
var (
CI bool = false
VERBOSE bool = false
CRON_LEAN bool = false
RESTIC_BIN string
DOCKER_IMAGE string
CI bool = false
VERBOSE bool = false
CRON_LEAN bool = false
RESTIC_BIN string
DOCKER_IMAGE string
LOCKFILE_PATH string
)

View File

@@ -1,7 +1,6 @@
package internal
import (
"errors"
"fmt"
"io/ioutil"
"os"
@@ -34,26 +33,26 @@ const (
)
type Hooks struct {
Dir string `mapstructure:"dir" yaml:"dir"`
PreValidate HookArray `mapstructure:"prevalidate,omitempty" yaml:"prevalidate,omitempty"`
Before HookArray `mapstructure:"before,omitempty" yaml:"before,omitempty"`
After HookArray `mapstructure:"after,omitempty" yaml:"after,omitempty"`
Success HookArray `mapstructure:"success,omitempty" yaml:"success,omitempty"`
Failure HookArray `mapstructure:"failure,omitempty" yaml:"failure,omitempty"`
Dir string `mapstructure:"dir"`
PreValidate HookArray `mapstructure:"prevalidate,omitempty"`
Before HookArray `mapstructure:"before,omitempty"`
After HookArray `mapstructure:"after,omitempty"`
Success HookArray `mapstructure:"success,omitempty"`
Failure HookArray `mapstructure:"failure,omitempty"`
}
type LocationCopy = map[string][]string
type Location struct {
name string `mapstructure:",omitempty" yaml:",omitempty"`
From []string `mapstructure:"from,omitempty" yaml:"from,omitempty"`
Type string `mapstructure:"type,omitempty" yaml:"type,omitempty"`
To []string `mapstructure:"to,omitempty" yaml:"to,omitempty"`
Hooks Hooks `mapstructure:"hooks,omitempty" yaml:"hooks,omitempty"`
Cron string `mapstructure:"cron,omitempty" yaml:"cron,omitempty"`
Options Options `mapstructure:"options,omitempty" yaml:"options,omitempty"`
ForgetOption LocationForgetOption `mapstructure:"forget,omitempty" yaml:"forget,omitempty"`
CopyOption LocationCopy `mapstructure:"copy,omitempty" yaml:"copy,omitempty"`
name string `mapstructure:",omitempty"`
From []string `mapstructure:"from,omitempty"`
Type string `mapstructure:"type,omitempty"`
To []string `mapstructure:"to,omitempty"`
Hooks Hooks `mapstructure:"hooks,omitempty"`
Cron string `mapstructure:"cron,omitempty"`
Options Options `mapstructure:"options,omitempty"`
ForgetOption LocationForgetOption `mapstructure:"forget,omitempty"`
CopyOption LocationCopy `mapstructure:"copy,omitempty"`
}
func GetLocation(name string) (Location, bool) {
@@ -168,7 +167,7 @@ func (l Location) getLocationTags() string {
return buildTag("location", l.name)
}
func (l Location) Backup(cron bool, dry bool, specificBackend string) []error {
func (l Location) Backup(cron bool, specificBackend string) []error {
var errors []error
var backends []string
colors.PrimaryPrint(" Backing up location \"%s\" ", l.name)
@@ -228,9 +227,6 @@ func (l Location) Backup(cron bool, dry bool, specificBackend string) []error {
if cron {
cmd = append(cmd, "--tag", buildTag("cron"))
}
if dry {
cmd = append(cmd, "--dry-run")
}
cmd = append(cmd, "--tag", l.getLocationTags())
backupOptions := ExecuteOptions{
Envs: env,
@@ -450,10 +446,7 @@ func (l Location) RunCron() error {
now := time.Now()
if now.After(next) {
lock.SetCron(l.name, now.Unix())
errs := l.Backup(true, false, "")
if len(errs) > 0 {
return fmt.Errorf("Failed to backup location \"%s\":\n%w", l.name, errors.Join(errs...))
}
l.Backup(true, "")
} else {
if !flags.CRON_LEAN {
colors.Body.Printf("Skipping \"%s\", not due yet.\n", l.name)

View File

@@ -18,18 +18,28 @@ const (
RUNNING = "running"
)
// getLockfilePath returns the path to the lockfile. If flags.LOCKFILE_PATH is
// set, its value is used, otherwise the path is generated relative to the
// config file.
func getLockfilePath() string {
if flags.LOCKFILE_PATH != "" {
return flags.LOCKFILE_PATH
} else {
p := viper.ConfigFileUsed()
if p == "" {
colors.Error.Println("cannot lock before reading config location")
os.Exit(1)
}
return path.Join(path.Dir(p), ".autorestic.lock.yml")
}
}
func getLock() *viper.Viper {
if lock == nil {
once.Do(func() {
lock = viper.New()
lock.SetDefault("running", false)
p := viper.ConfigFileUsed()
if p == "" {
colors.Error.Println("cannot lock before reading config location")
os.Exit(1)
}
file = path.Join(path.Dir(p), ".autorestic.lock.yml")
file = getLockfilePath()
if !flags.CRON_LEAN {
colors.Faint.Println("Using lock:\t", file)
}

View File

@@ -7,6 +7,7 @@ import (
"strconv"
"testing"
"github.com/cupcakearmy/autorestic/internal/flags"
"github.com/spf13/viper"
)
@@ -28,6 +29,37 @@ func setup(t *testing.T) {
})
}
func TestGetLockfilePath(t *testing.T) {
t.Run("when flags.LOCKFILE_PATH is set", func(t *testing.T) {
flags.LOCKFILE_PATH = "/path/to/my/autorestic.lock.yml"
defer func() { flags.LOCKFILE_PATH = "" }()
p := getLockfilePath()
if p != "/path/to/my/autorestic.lock.yml" {
t.Errorf("got %v, want %v", p, "/path/to/my/autorestic.lock.yml")
}
})
t.Run("when flags.LOCKFILE_PATH is set", func(t *testing.T) {
d, err := os.MkdirTemp("", testDirectory)
if err != nil {
log.Fatalf("error creating temp dir: %v", err)
return
}
viper.SetConfigFile(d + "/.autorestic.yml")
defer viper.Reset()
flags.LOCKFILE_PATH = ""
p := getLockfilePath()
if p != d+"/.autorestic.lock.yml" {
t.Errorf("got %v, want %v", p, d+"/.autorestic.lock.yml")
}
})
}
func TestLock(t *testing.T) {
setup(t)