Compare commits

..

673 Commits

Author SHA1 Message Date
Alexander Neumann
fe9f142b52 Add version for 0.16.5 2024-07-01 21:25:34 +02:00
Alexander Neumann
6ae760751a Generate CHANGELOG.md for 0.16.5 2024-07-01 21:25:33 +02:00
Alexander Neumann
2fa1b42706 Prepare changelog for 0.16.5 2024-07-01 21:25:33 +02:00
Michael Eischer
ca04a88e65 Merge pull request #4879 from restic/backport-azure-cli-option
Backport azure cli option
2024-06-26 21:07:16 +02:00
Michael Eischer
12e858b7af azure: deduplicate cli and default credentials case 2024-06-26 20:59:51 +02:00
Maik Riechert
834f08fe2d Azure: add option to force use of CLI credential 2024-06-26 20:59:51 +02:00
Michael Eischer
814ef4901f Merge pull request #4878 from restic/patch-deps-bump
Bump dependencies
2024-06-26 20:58:29 +02:00
Michael Eischer
84bc9432de update release verification script for latest docker 2024-06-26 20:49:23 +02:00
Michael Eischer
e9d711422a bump azure, golang and gcs dependencies 2024-06-26 20:49:23 +02:00
Alexander Neumann
0f9fa44de5 Set development version for 0.16.4 2024-02-04 19:50:56 +01:00
Alexander Neumann
3786536dc1 Add version for 0.16.4 2024-02-04 19:50:52 +01:00
Alexander Neumann
811be5984d Update manpages and auto-completion 2024-02-04 19:50:51 +01:00
Alexander Neumann
b0ead75de5 Generate CHANGELOG.md for 0.16.4 2024-02-04 19:50:34 +01:00
Alexander Neumann
6cd2804bff Prepare changelog for 0.16.4 2024-02-04 19:50:34 +01:00
Michael Eischer
a72c2b74f3 Apply changelog entry / documentation improvements from review 2024-02-04 19:10:06 +01:00
Michael Eischer
261b1455c7 add documentation for --no-extra-verify option 2024-02-04 19:10:06 +01:00
Michael Eischer
2a0bd2b637 rename --no-verify-pack to --no-extra-verify 2024-02-04 19:10:05 +01:00
Michael Eischer
4589da7eb9 add data verification changelog entry 2024-02-04 19:09:49 +01:00
Michael Eischer
75e72d826c pack: verify integrity of pack file header 2024-02-04 19:09:49 +01:00
Michael Eischer
d8916bc3d9 repository: ask users to report corrupted data while saving blobs 2024-02-04 19:09:49 +01:00
Michael Eischer
dc11d012bb Make --no-verify-pack globally available
Verifying all blobs before upload comes with a notable performance
impact. Allow users to skip it if necessary.
2024-02-04 19:09:49 +01:00
Michael Eischer
8ef5425351 repository: test verification of blobs/unpacked data 2024-02-04 19:09:46 +01:00
Michael Eischer
885431ec2b repository: Allow skipping verification for tests
Some tests have to explicitly create pack files with blobs that don't
match their ID. For those blobs the builtin verification of the
repository must be disabled.
2024-02-04 19:08:30 +01:00
Michael Eischer
cb85fb46dd backup: verify unpacked files before upload 2024-02-04 19:07:48 +01:00
Michael Eischer
2f30c940b2 backup: verify blobs before upload
This only covers the blobs themselves, the pack header is not verified
so far. Unpacked files are also not covered by the integrity check.
2024-02-04 19:07:48 +01:00
Michael Eischer
0ea62b5ac6 repository: make repo.Options configurable for test repos 2024-02-04 19:07:46 +01:00
Michael Eischer
29e1caf825 add changelog draft for data corruption on max compression 2024-02-04 19:05:51 +01:00
Michael Eischer
0164f5310d Downgrade klauspost/compress to fix data corruption at max. compression 2024-02-04 19:05:50 +01:00
Alexander Neumann
0ec9383ba2 Set development version for 0.16.3 2024-01-14 20:21:45 +01:00
Alexander Neumann
abca112404 Add version for 0.16.3 2024-01-14 20:21:45 +01:00
Alexander Neumann
b70b94507a Generate CHANGELOG.md for 0.16.3 2024-01-14 20:21:19 +01:00
Alexander Neumann
d987582594 Prepare changelog for 0.16.3 2024-01-14 20:21:19 +01:00
Leo R. Lundgren
ef2e473b99 doc: Polish changelogs 2024-01-10 00:19:07 +01:00
Michael Eischer
e4bbde7036 rclone: Workaround for incorrect "not found" errors while listing files
rclone returns a "not found" error if an internal error occurs while
listing a folder. Ignoring this error lets restic erroneously think that
there are no files, which can cause `prune` to wipe the whole
repository.
2024-01-09 18:28:17 +01:00
Michael Eischer
ec0fb46f6c add changelog for reliable restores 2024-01-09 18:27:48 +01:00
Michael Eischer
103beb96bc restore: separately restore blobs that are frequently referenced
Writing these blobs to their files can take a long time and consequently
cause the backend connection to time out. Avoid that by retrieving these
blobs separately.
2024-01-09 18:27:48 +01:00
Michael Eischer
f0f89d7f27 restore: split error reporting from downloadPack 2024-01-09 18:27:48 +01:00
Michael Eischer
cf352ccafb restore: cleanup downloadPack 2024-01-09 18:27:48 +01:00
Michael Eischer
b856e9489a restore: split downloadPack into smaller methods 2024-01-09 18:27:48 +01:00
Michael Eischer
ce7db90e08 sync CI and go dependencies with master branch 2024-01-08 21:33:05 +01:00
Michael Eischer
620518aec6 add changelog for better restore error reporting 2024-01-08 21:33:05 +01:00
Michael Eischer
f2fafbffaa restore: only report errors for blobs that actually failed to load
Previously, errors would be reported for all blobs of a packfile that
failed to stream. Now, only the not yet processed blobs are reported.
2024-01-08 21:33:05 +01:00
Michael Eischer
7a3a884874 repository: test that StreamPack only delivers blobs once 2024-01-08 21:33:05 +01:00
Michael Eischer
772a907533 repository: StreamPack delivers blobs at most once
If an error occurred while streaming a pack file, this could result in
passing some of the blobs multiple times to the callback function. This
significantly complicates using StreamPack correctly and is unnecessary.
Retries do not change the content of a blob and thus only deliver the
same result over and over again.
2024-01-08 21:33:05 +01:00
Michael Eischer
a9446c1184 add changelog for irregular files on windows 2024-01-08 21:33:05 +01:00
Michael Eischer
1bab29c336 archiver: Add filepath to error message if it is not included yet 2024-01-08 21:33:05 +01:00
Michael Eischer
e886c3f6b2 archiver: improve error message for irregular files
Since Go 1.21, most reparse points are considered as irregular files.
Depending on the underlying driver these can exhibit nearly arbitrary
behavior. When encountering such a file, restic returned an
indecipherable error message: `error: invalid node type ""`.

Add the filepath to the error message and state that the file type is
not supported.
2024-01-08 21:33:05 +01:00
Michael Eischer
c95de54726 restic: cleanup node type determination
os.ModeCharDevice is already included in os.ModeType
2024-01-08 21:33:05 +01:00
Michael Eischer
d4b8abd3e2 fix deduplicated files on windows 2024-01-08 21:33:05 +01:00
Joram Berger
948ab3ccaf Add a note that the oldest snapshot may be kept additionally
Documentation enhancement.
2024-01-08 21:33:05 +01:00
Markus Zoppelt
bb0c923298 docs: add pkgx install option
PR in pkgx pantry: https://github.com/pkgxdev/pantry/pull/4098

restic pkg:
https://pkgx.dev/pkgs/restic.net/restic/
2024-01-08 21:33:05 +01:00
Michael Eischer
ff0c975443 regenerate changelog 2024-01-08 21:33:05 +01:00
Michael Eischer
7e61e117d6 cleanup changelog whitespace 2024-01-08 21:33:05 +01:00
mmattel
220a28582e Add a table of contents (TOC) to the changelog template 2024-01-08 21:33:05 +01:00
Giuseppe D'Andrea
f44fd73230 docs: fix typo in working with repos
When using the `copy` command, `--from-password-file` and `--from-password-command` flags are used to specify the password of the source repository, not of the destination repository.
2024-01-08 21:33:05 +01:00
Joda Stößer
76bd975e03 docs(scripting): correct stats output comment to be about the correct command
not about the snapshots command
2024-01-08 21:33:05 +01:00
Quang-Linh LE
64b7aed362 docs: Mention progress for restore command. This is available after https://github.com/restic/restic/pull/3991 2024-01-08 21:33:05 +01:00
Michael Kuhn
3fa6b2de4a Fix repository not being printed when using repository file
When using `RESTIC_REPOSITORY_FILE` in combination with `restic init`,
the repository is missing in the output:
```
$ restic init
created restic repository 3c872be20f at
[...]
```
This is due to the code using `gopts.Repo`, which is empty in this case.
2024-01-08 21:33:05 +01:00
Michael Eischer
5cd000f4b0 CI: update golangci-lint
Necessary to properly support Go 1.21.
2024-01-08 21:33:05 +01:00
Alexander Neumann
59fe24cb2b Set development version for 0.16.2 2023-10-29 19:50:12 +01:00
Alexander Neumann
1a5efcf680 Add version for 0.16.2 2023-10-29 19:50:07 +01:00
Alexander Neumann
d33fe6dd3c Generate CHANGELOG.md for 0.16.2 2023-10-29 19:50:04 +01:00
Alexander Neumann
c8dd95f104 Prepare changelog for 0.16.2 2023-10-29 19:50:04 +01:00
Leo R. Lundgren
7d980b469d doc: Polish changelogs 2023-10-29 00:44:53 +02:00
Michael Eischer
d863234e3e add changelog for missing documentation 2023-10-28 20:25:24 +02:00
Michael Eischer
4be45de1c2 Restore support for ARMv5 platforms 2023-10-27 19:52:14 +02:00
Leo R. Lundgren
8c1125fe13 doc: Correct two typos 2023-10-27 19:48:00 +02:00
Martin Michlmayr
0b6ccea461 Fix typos 2023-10-27 19:48:00 +02:00
Martin Michlmayr
de6135351e Format option correctly 2023-10-27 19:48:00 +02:00
Michael Eischer
d47581b25e verify-release-binaries.sh: don't show warning if binaries are correct 2023-10-27 19:48:00 +02:00
Michael Eischer
69dec02a14 Remove readthedocs special case from docs configuration
Apparently it's now required to bring your own theme.
2023-10-27 19:47:19 +02:00
Michael Eischer
826d880614 Fix doc path typo in readthedocs configuration 2023-10-27 19:47:15 +02:00
Michael Eischer
dbf7ef72b9 Add read the docs config file version 2
The config file is by now necessary to build documentation:
https://blog.readthedocs.com/migrate-configuration-v2/
2023-10-27 19:47:11 +02:00
Alexander Neumann
27ec320eae Set development version for 0.16.1 2023-10-24 20:02:58 +02:00
Alexander Neumann
baca3f6303 Add version for 0.16.1 2023-10-24 20:02:55 +02:00
Alexander Neumann
524c2721b4 Update manpages and auto-completion 2023-10-24 20:02:55 +02:00
Alexander Neumann
be1b978ac8 Generate CHANGELOG.md for 0.16.1 2023-10-24 20:02:29 +02:00
Alexander Neumann
d4d9c1b8f1 Prepare changelog for 0.16.1 2023-10-24 20:02:29 +02:00
Michael Eischer
ead8dd0173 Merge pull request #4524 from MichaelEischer/fix-autocompletion
Don't load password when autocompleting CLI commands
2023-10-23 20:06:53 +00:00
Michael Eischer
cd09ef4614 don't load password when autocompleting CLI commands 2023-10-23 21:44:22 +02:00
Michael Eischer
d399e32590 Merge pull request #4535 from MichaelEischer/fix-cat-command
Only show index loading progress bar if stdout is a terminal
2023-10-23 21:28:13 +02:00
Michael Eischer
54a4034ec0 Only show index progress bar if stdout is a terminal
This ensures that there is no interference when using restic for
scripting use cases.
2023-10-23 21:16:52 +02:00
rawtaz
138b7b3328 Merge pull request #4534 from MichaelEischer/polish-changelogs
Polish changelogs
2023-10-23 19:00:01 +00:00
Leo R. Lundgren
6d19e0260d doc: Polish changelogs 2023-10-23 20:45:15 +02:00
Michael Eischer
85abceb99c doc: update minimum required Go version 2023-10-23 19:02:20 +02:00
Michael Eischer
85c15e6fa3 polish changelogs 2023-10-23 19:01:45 +02:00
Michael Eischer
d6917c7e00 Merge pull request #4533 from MichaelEischer/update-dependencies
update dependencies
2023-10-23 19:01:03 +02:00
Michael Eischer
8c20301172 update dependencies 2023-10-23 18:48:13 +02:00
Michael Eischer
4b4f916bdc Merge pull request #4532 from MichaelEischer/update-zstd
Update klauspost/compress to fix data corruption at maximum compression
2023-10-23 18:45:35 +02:00
Michael Eischer
9707956375 Merge pull request #4530 from MichaelEischer/repair-packs
Add `repair packs` command to simplify recovery from damaged pack
2023-10-23 18:44:42 +02:00
Michael Eischer
d1d4510974 repair packs: Add stub feature flag implementation 2023-10-23 18:36:28 +02:00
Michael Eischer
a28940ea29 check: Suggest usage of restic repair packs for corrupted blobs
For now, the guide is only shown if the blob content does not match its
hash. The main intended usage is to handle data corruption errors when
using maximum compression in restic 0.16.0
2023-10-23 18:36:28 +02:00
Michael Eischer
db26dc75e1 repair packs: add experimental command
This allows recovering a repository from several cases of damaged blobs.
2023-10-23 18:36:28 +02:00
Michael Eischer
efef38d0e8 drop support for Go 1.18 2023-10-23 18:30:38 +02:00
Michael Eischer
d00e72fed4 Update klauspost/compress to fix data corruption at maximum compression 2023-10-23 18:30:38 +02:00
Michael Eischer
62af0d769a Merge pull request #4528 from adamantike/misc/run-tests-with-go-1.21
Run tests with Go 1.21
2023-10-22 16:00:27 +00:00
Michael Eischer
ae83a9002a Merge pull request #4531 from MichaelEischer/silence-automaxprocs
Disable log output from automaxprocs library
2023-10-22 17:43:36 +02:00
Michael Eischer
ceff4af1ac Disable log output from automaxprocs library 2023-10-22 17:09:46 +02:00
Michael Manganiello
b15ba553a4 Run tests with Go 1.21 2023-10-22 10:47:42 -03:00
Michael Eischer
46cb1df1bc Merge pull request #4505 from MichaelEischer/verify-release-binaries
Add script to verify release binaries
2023-10-21 20:00:25 +02:00
Michael Eischer
bd3816fa14 CI: Ensure that github containers match the official binaries
The binaries accidentally included VCS information whereas binaries
built from the release tarball do not. For consistency remove the .git
directory before building the container on Github.
2023-10-21 19:44:59 +02:00
Michael Eischer
b2b0856908 Add helper script to verify release binaries
The script checks that the released binaries and the container binaries
can be reproduced.
2023-10-21 19:44:59 +02:00
Michael Eischer
7f05af02b9 Merge pull request #4480 from AgathaSorceress/add-rest-auth-env
Support reading basic auth credentials for REST server from environment variables
2023-10-21 17:41:08 +00:00
Michael Eischer
eabc177a42 Merge pull request #4442 from Refutable4890/copy-doc
Add a description of the resumption of `copy`
2023-10-21 17:38:15 +00:00
Michael Eischer
ab6defbace Merge pull request #4519 from adamantike/backend/sftp/add-args-option
backend/sftp: Add sftp.args option
2023-10-21 17:37:46 +00:00
Michael Eischer
fe1f61570b Merge pull request #4518 from adamantike/backend/b2/switch-to-official-library
backend/b2: Switch to official library `Backblaze/blazer`
2023-10-21 17:29:19 +00:00
Michael Eischer
baf9b54891 sftp: simplify documentation for sftp.args 2023-10-21 19:28:27 +02:00
Michael Eischer
6a4d6d5da4 sftp: test that Args and Command options cannot be set at the same time 2023-10-21 19:26:39 +02:00
Michael Manganiello
41f70f1f4f backend/sftp: Add sftp.args option
Allow setting custom arguments for the `sftp` backend, by using the
`sftp.args` option. This is similar to the approach already implemented
in the `rclone` backend, to support new arguments without requiring
future code changes for each different SSH argument.

Closes #4241
2023-10-21 19:25:44 +02:00
Michael Eischer
6c7560e537 backend/b2: Switch to official library Backblaze/blazer
According to https://github.com/kurin/blazer Readme, the repository is
no longer maintained, and the official one at
https://github.com/Backblaze/blazer took over.

Closes #4148
2023-10-21 19:18:13 +02:00
Agatha V. Lovelace
0f97356b21 docs: add new REST server env variables 2023-10-20 13:04:58 +02:00
Agatha V. Lovelace
2089c54310 changelog: add unreleased entry 2023-10-20 13:04:58 +02:00
Agatha V. Lovelace
f1877e721e feat: support reading REST credentials from env 2023-10-20 13:04:58 +02:00
Michael Eischer
17f2301cc2 Merge pull request #4514 from grembo/key-list-no-lock
Make `key list` command honor `--no-lock`
2023-10-19 20:50:56 +00:00
Michael Eischer
79deb99605 Merge pull request #4500 from MichaelEischer/simplify-issue-template
Simplify issue template
2023-10-19 20:48:36 +00:00
Michael Eischer
643180b415 simplify issue template 2023-10-19 22:16:38 +02:00
Michael Eischer
d27cfd10a9 Merge pull request #4487 from lbausch/tweak-restore-summary
Tweak restore summary
2023-10-19 20:14:14 +00:00
Michael Gmelin
34f3b13b7c Make key list command honor --no-lock
Fixes #4513
2023-10-19 22:09:35 +02:00
Michael Eischer
495982232c Merge pull request #4511 from dnnr/inode-in-json
Include inode in JSON output for find and ls
2023-10-17 21:06:34 +00:00
Michael Eischer
d173d1c532 Merge pull request #4486 from MichaelEischer/separate-large-blobs
repository: store oversized blobs in separate pack files
2023-10-17 23:03:52 +02:00
Michael Eischer
f955222750 Merge pull request #4502 from MichaelEischer/replace-ratelimit
backend/limiter: replace juju/ratelimit with x/time/rate
2023-10-17 23:03:17 +02:00
Michael Eischer
cb9cbe55d9 repository: store oversized blobs in separate pack files
Store oversized blobs in separate pack files as the blobs is large
enough to warrant its own pack file. This simplifies the garbage
collection of such blobs and keeps the cache smaller, as oversize (tree)
blobs only have to be downloaded if they are actually used.
2023-10-17 22:52:16 +02:00
Michael Eischer
f750aa8dfb backend/limiter: replace juju/ratelimit with x/time/rate 2023-10-17 22:49:25 +02:00
Michael Eischer
c635e30e3f Merge pull request #4485 from MichaelEischer/uber-automaxprocs
Automatically adjust GOMAXPROCS when run in a cpu-constrained container
2023-10-17 22:47:10 +02:00
Michael Eischer
f5d5e8fd0a automatically adjust GOMAXPROCS when run in a cpu-constrained container 2023-10-17 20:31:57 +02:00
Daniel Danner
a858ab254b Include inode in JSON output for find and ls
This introduces the inode attribute to the JSON output emitted for nodes
in `ls` and matches in `find`. There doesn't seem to be any discernible
reason to omit the inode and it can be useful in scripting scenarios.
2023-10-11 21:10:01 +02:00
Michael Eischer
4087c3aff7 Merge pull request #4498 from PeterDaveHello/ImproveDockerfile
Remove additional `--update` for apk in Dockerfile
2023-10-09 20:53:49 +00:00
Refutable4890
aa86c76aab Add a description of the resumption of copy 2023-10-08 12:07:40 +08:00
Michael Eischer
76ef94d15c Merge pull request #4419 from arjunajesh/issue#299
Progress Bar when loading index files
2023-10-01 18:06:35 +00:00
Michael Eischer
91aef00df3 check: add index loading progress bar 2023-10-01 19:55:29 +02:00
Michael Eischer
b0da0f152f deduplicate index progress bar setup 2023-10-01 19:53:26 +02:00
Michael Eischer
75f6bd89ed hide index loading progress for JSON output 2023-10-01 19:53:26 +02:00
Michael Eischer
3fd0ad7448 repository: list index files only once 2023-10-01 19:53:26 +02:00
arjunajesh
b6593ad7df changelog 2023-10-01 19:53:26 +02:00
arjunajesh
ed65a7dbca implement progress bar for index loading 2023-10-01 19:52:59 +02:00
Michael Eischer
eac1c4a8d0 Merge pull request #4471 from jalseth/master
docs(examples): Use restic binary from system path
2023-10-01 12:31:28 +00:00
Michael Eischer
f519454f33 Merge pull request #4493 from restic/dependabot/go_modules/cloud.google.com/go/storage-1.33.0
build(deps): bump cloud.google.com/go/storage from 1.31.0 to 1.33.0
2023-10-01 12:09:43 +00:00
Michael Eischer
54ae8a0c40 Merge pull request #4492 from restic/dependabot/github_actions/docker/login-action-b4bedf8053341df3b5a9f9e0f2cf4e79e27360c6
build(deps): bump docker/login-action from cf8514a65188af1d4f94f8c28a7a4153af1088ce to b4bedf8053341df3b5a9f9e0f2cf4e79e27360c6
2023-10-01 12:08:10 +00:00
Michael Eischer
a36b5b6391 Merge pull request #4491 from restic/dependabot/github_actions/docker/setup-buildx-action-3
build(deps): bump docker/setup-buildx-action from 2 to 3
2023-10-01 12:03:48 +00:00
Michael Eischer
5e36e4da96 Merge pull request #4489 from restic/dependabot/github_actions/docker/setup-qemu-action-3
build(deps): bump docker/setup-qemu-action from 2 to 3
2023-10-01 12:03:19 +00:00
Michael Eischer
8ee08e5d09 Merge pull request #4490 from restic/dependabot/github_actions/actions/checkout-4
build(deps): bump actions/checkout from 3 to 4
2023-10-01 12:03:09 +00:00
Michael Eischer
9f9f736ec2 Merge pull request #4495 from restic/dependabot/go_modules/golang.org/x/oauth2-0.12.0
build(deps): bump golang.org/x/oauth2 from 0.11.0 to 0.12.0
2023-10-01 12:01:12 +00:00
Michael Eischer
af98c3ccbe Merge pull request #4496 from restic/dependabot/go_modules/github.com/hashicorp/golang-lru/v2-2.0.7
build(deps): bump github.com/hashicorp/golang-lru/v2 from 2.0.6 to 2.0.7
2023-10-01 11:59:38 +00:00
Peter Dave Hello
6edfc73879 Remove additional --update for apk in Dockerfile 2023-10-01 18:00:15 +08:00
dependabot[bot]
d985ed27d1 build(deps): bump github.com/hashicorp/golang-lru/v2 from 2.0.6 to 2.0.7
Bumps [github.com/hashicorp/golang-lru/v2](https://github.com/hashicorp/golang-lru) from 2.0.6 to 2.0.7.
- [Release notes](https://github.com/hashicorp/golang-lru/releases)
- [Commits](https://github.com/hashicorp/golang-lru/compare/v2.0.6...v2.0.7)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/golang-lru/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 01:45:19 +00:00
dependabot[bot]
4278ec6553 build(deps): bump golang.org/x/oauth2 from 0.11.0 to 0.12.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.11.0 to 0.12.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 01:45:07 +00:00
dependabot[bot]
15cb498c47 build(deps): bump cloud.google.com/go/storage from 1.31.0 to 1.33.0
Bumps [cloud.google.com/go/storage](https://github.com/googleapis/google-cloud-go) from 1.31.0 to 1.33.0.
- [Release notes](https://github.com/googleapis/google-cloud-go/releases)
- [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-cloud-go/compare/pubsub/v1.31.0...pubsub/v1.33.0)

---
updated-dependencies:
- dependency-name: cloud.google.com/go/storage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 01:44:54 +00:00
dependabot[bot]
59e217b003 build(deps): bump docker/login-action
Bumps [docker/login-action](https://github.com/docker/login-action) from cf8514a65188af1d4f94f8c28a7a4153af1088ce to b4bedf8053341df3b5a9f9e0f2cf4e79e27360c6.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](cf8514a651...b4bedf8053)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 01:24:15 +00:00
dependabot[bot]
3457f50c8c build(deps): bump docker/setup-buildx-action from 2 to 3
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 01:24:10 +00:00
dependabot[bot]
bbe2f1ecf2 build(deps): bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 01:24:05 +00:00
dependabot[bot]
362917afb9 build(deps): bump docker/setup-qemu-action from 2 to 3
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 01:24:01 +00:00
Michael Eischer
b92ab458b0 Merge pull request #4459 from restic/dependabot/go_modules/github.com/go-ole/go-ole-1.3.0
build(deps): bump github.com/go-ole/go-ole from 1.2.6 to 1.3.0
2023-09-28 20:42:14 +00:00
Lorenz Bausch
2657217574 Tweak restore summary 2023-09-20 10:59:55 +02:00
James Alseth
02ab511c2f docs(examples): Use restic binary from system path
Signed-off-by: James Alseth <james@jalseth.me>
2023-09-17 19:39:45 -07:00
Michael Eischer
6e586b64e4 Merge pull request #4450 from MichaelEischer/cleanup-master-index-test
master_index: fix inconsistent length blob length in test
2023-09-06 22:55:48 +02:00
Michael Eischer
fb4d458cce Merge pull request #4452 from lbausch/docs/add-current-key-hint
docs: explain meaning of asterisk when managing repository keys
2023-09-06 20:28:33 +00:00
Michael Eischer
c7b5ddc012 Merge pull request #4451 from greatroar/bh-string
internal/restic: Return summary from BlobSet.String
2023-09-06 20:27:26 +00:00
Michael Eischer
3eb825e47c Merge pull request #4464 from restic/dependabot/go_modules/golang.org/x/term-0.12.0
build(deps): bump golang.org/x/term from 0.11.0 to 0.12.0
2023-09-06 20:18:34 +00:00
dependabot[bot]
4d60011030 build(deps): bump golang.org/x/term from 0.11.0 to 0.12.0
Bumps [golang.org/x/term](https://github.com/golang/term) from 0.11.0 to 0.12.0.
- [Commits](https://github.com/golang/term/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: golang.org/x/term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-05 21:43:28 +00:00
Michael Eischer
507ed32469 Merge pull request #4457 from restic/dependabot/go_modules/google.golang.org/api-0.138.0
build(deps): bump google.golang.org/api from 0.134.0 to 0.138.0
2023-09-05 21:32:34 +00:00
dependabot[bot]
22fdfe1ffe build(deps): bump github.com/go-ole/go-ole from 1.2.6 to 1.3.0
Bumps [github.com/go-ole/go-ole](https://github.com/go-ole/go-ole) from 1.2.6 to 1.3.0.
- [Release notes](https://github.com/go-ole/go-ole/releases)
- [Changelog](https://github.com/go-ole/go-ole/blob/master/ChangeLog.md)
- [Commits](https://github.com/go-ole/go-ole/compare/v1.2.6...v1.3.0)

---
updated-dependencies:
- dependency-name: github.com/go-ole/go-ole
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-05 21:17:03 +00:00
Michael Eischer
e05cd9abca Merge pull request #4462 from restic/dependabot/github_actions/docker/login-action-cf8514a65188af1d4f94f8c28a7a4153af1088ce
build(deps): bump docker/login-action from a9794064588be971151ec5e7144cb535bcb56e36 to cf8514a65188af1d4f94f8c28a7a4153af1088ce
2023-09-05 21:07:57 +00:00
Michael Eischer
ea55ca5303 Merge pull request #4458 from restic/dependabot/go_modules/github.com/hashicorp/golang-lru/v2-2.0.6
build(deps): bump github.com/hashicorp/golang-lru/v2 from 2.0.4 to 2.0.6
2023-09-05 21:05:45 +00:00
Michael Eischer
df53f4782b Merge pull request #4453 from lbausch/docs/fix-table
docs: fix malformed table
2023-09-05 20:37:30 +00:00
Michael Eischer
35055adbc4 Merge pull request #4454 from lbausch/tweak-readme
README: add Mastodon link
2023-09-05 20:36:32 +00:00
dependabot[bot]
bd9eb528c0 build(deps): bump docker/login-action
Bumps [docker/login-action](https://github.com/docker/login-action) from a9794064588be971151ec5e7144cb535bcb56e36 to cf8514a65188af1d4f94f8c28a7a4153af1088ce.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](a979406458...cf8514a651)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 01:45:03 +00:00
dependabot[bot]
02032f3109 build(deps): bump github.com/hashicorp/golang-lru/v2 from 2.0.4 to 2.0.6
Bumps [github.com/hashicorp/golang-lru/v2](https://github.com/hashicorp/golang-lru) from 2.0.4 to 2.0.6.
- [Release notes](https://github.com/hashicorp/golang-lru/releases)
- [Commits](https://github.com/hashicorp/golang-lru/compare/v2.0.4...v2.0.6)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/golang-lru/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 01:41:13 +00:00
dependabot[bot]
cfff1367c1 build(deps): bump google.golang.org/api from 0.134.0 to 0.138.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.134.0 to 0.138.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.134.0...v0.138.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 01:40:56 +00:00
Lorenz Bausch
353265a329 README: add Mastodon link 2023-08-27 10:52:12 +02:00
Lorenz Bausch
84a1170dee docs: remove trailing whitespace 2023-08-27 10:49:34 +02:00
Lorenz Bausch
0b4d9c9a51 docs: add missing whitespace to avoid malformed table warning 2023-08-27 10:46:55 +02:00
Lorenz Bausch
5422a7daa5 docs: explain meaning of asterisk when managing repository keys 2023-08-27 10:40:55 +02:00
greatroar
691c01963b internal/restic: Return summary from BlobSet.String
Fixes #4449: error messages from prune were too long to fit in scroll
buffers.
2023-08-25 21:41:30 +02:00
Michael Eischer
2bec99dc6f master_index: fix inconsistent length blob length in test
Two blobs with the same hash must always have the same content length.
2023-08-19 20:04:25 +02:00
Michael Eischer
e60c5b2d7f Merge pull request #4436 from MichaelEischer/add-snapshot-subfolder-syntax-to-help-text
Add snapshot subfolder syntax in help output of diff/dump/restore
2023-08-13 19:36:38 +02:00
Michael Eischer
a04964bb86 Merge pull request #4446 from 2000yeshu/feat-cat
Check for arguments before opening remote connection in cat command
2023-08-13 17:25:37 +00:00
Michael Eischer
fe54912a46 cat: extract parameter validation and add a test 2023-08-13 19:17:46 +02:00
Michael Eischer
feb6abb7bb Merge pull request #4394 from greatroar/acl
dump: Rewrite Linux ACL handling
2023-08-13 17:01:31 +00:00
greatroar
aaf5254e26 dump: Rewrite Linux ACL handling
The old version was taken from an MPL-licensed library. This is a
cleanroom implementation. The code is shorter and it's now explicit that
only Linux ACLs are supported.
2023-08-13 13:37:11 +02:00
Yakul Garg
705556f134 Check for arguments before opening remote connection in cat command
Signed-off-by: Yakul Garg <2000yeshu@gmail.com>
2023-08-12 23:54:40 +05:30
Michael Eischer
c23eebc225 Merge pull request #4428 from MichaelEischer/fix-restore-help
restore: Fix help text for `--iinclude` and `--iexclude`
2023-08-12 20:21:22 +02:00
Refutable4890
e09f6f540f Add a description of the resumption of copy 2023-08-08 12:51:40 +08:00
Michael Eischer
0fca028491 restore: Fix help text for --iinclude and --iexclude 2023-08-05 18:21:03 +02:00
Michael Eischer
57a08291f5 Merge pull request #4429 from restic/dependabot/github_actions/docker/login-action-a9794064588be971151ec5e7144cb535bcb56e36
build(deps): bump docker/login-action from 65b78e6e13532edd9afa3aa52ac7964289d1a9c1 to a9794064588be971151ec5e7144cb535bcb56e36
2023-08-05 13:41:08 +00:00
Michael Eischer
2117ce4cfb Merge pull request #4434 from lbausch/docs-fix-wording
docs: fix `percent_done` description
2023-08-05 13:39:02 +00:00
Michael Eischer
3a478bc522 unify snapshotID spelling in command parameters 2023-08-05 12:35:45 +02:00
Michael Eischer
9a7704fa2b diff/dump/restore: describe snapshot:subfolder syntax in help text 2023-08-05 12:35:08 +02:00
Lorenz Bausch
9a69f44de2 docs: fix percent_done description 2023-08-04 16:15:18 +02:00
dependabot[bot]
7a6339180b build(deps): bump docker/login-action
Bumps [docker/login-action](https://github.com/docker/login-action) from 65b78e6e13532edd9afa3aa52ac7964289d1a9c1 to a9794064588be971151ec5e7144cb535bcb56e36.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](65b78e6e13...a979406458)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 01:19:51 +00:00
Alexander Neumann
82e6e28781 Set development version for 0.16.0 2023-07-31 20:24:29 +02:00
Alexander Neumann
eb33e564c9 Add version for 0.16.0 2023-07-31 20:23:24 +02:00
Alexander Neumann
62680af734 Update manpages and auto-completion 2023-07-31 20:23:24 +02:00
Alexander Neumann
68460fd3d1 Generate CHANGELOG.md for 0.16.0 2023-07-31 20:22:50 +02:00
Alexander Neumann
9459328d8d Prepare changelog for 0.16.0 2023-07-31 20:22:50 +02:00
rawtaz
9d71990c26 Merge pull request #4424 from MichaelEischer/tweak-changelog
Tweak changelog entries
2023-07-29 11:29:30 +00:00
rawtaz
9219b6a0ef Merge pull request #4427 from MichaelEischer/changelog-template
Extend style guide in changelog template
2023-07-29 11:15:17 +00:00
Michael Eischer
9a0ec05145 Extend style guide in changelog template 2023-07-29 12:55:56 +02:00
Michael Eischer
2a5b6af2e9 extend gc tweak changelog 2023-07-29 12:51:05 +02:00
Leo R. Lundgren
51e4e5ef82 doc: Polish changelog 2023-07-29 12:51:04 +02:00
Michael Eischer
e998314088 tweak changelog entries 2023-07-29 12:50:01 +02:00
Michael Eischer
be03c1a457 Merge pull request #4422 from MichaelEischer/document-non-utf-symlinks
Document `linktarget_raw` field for non utf symlinks
2023-07-28 23:14:08 +02:00
Michael Eischer
95050117eb Merge pull request #4426 from MichaelEischer/consistent-forget-policy
forget: replace `--keep-* -1` with `--keep-* unlimited`
2023-07-28 19:06:00 +00:00
Michael Eischer
21a3a41b69 Merge pull request #4423 from MichaelEischer/update-dependencies
Update dependencies
2023-07-28 19:25:02 +02:00
Michael Eischer
3f919f2371 forget: simplify test 2023-07-28 19:21:40 +02:00
Michael Eischer
50b43fbac0 forget: replace --keep-* -1 with --keep-* unlimited
This ensures consistency with the `prune --max-unused unlimited` option.
2023-07-28 19:21:40 +02:00
Michael Eischer
f689e2638d reenable aix builds 2023-07-27 21:27:31 +02:00
Michael Eischer
f9ef2b1e44 update all dependencies 2023-07-27 21:26:44 +02:00
Michael Eischer
b87a37f318 doc: Fix typos 2023-07-25 20:14:56 +02:00
Michael Eischer
647ebf352a doc: Describe linktarget_raw field 2023-07-25 20:14:47 +02:00
Michael Eischer
62d3ef4a93 Merge pull request #4417 from MichaelEischer/fix-flaky-list-cancel-test
backend: Fix unreliable TestListCancel/Timeout test
2023-07-23 18:04:11 +02:00
Michael Eischer
6c5fc32967 Merge pull request #3225 from wojas/restic-cmd-more-help
Extend help output with short overview
2023-07-23 15:43:03 +00:00
Michael Eischer
ae13cf15c1 doc: move quickstart to docs 2023-07-23 17:32:37 +02:00
Michael Eischer
1fe1ec40a2 Merge pull request #4409 from arjunajesh/issue#1495
snapshots sorted by timestamp in restic find
2023-07-23 11:00:41 +00:00
arjunajesh
32f5ee6f4e snapshots sorted by timestamp 2023-07-23 12:49:23 +02:00
Konrad Wojas
5bd8a6d7eb Extend help output with short overview
The list of subcommands can be confusing for first time users. This
adds a short overview of the most important commands to help get people
started.
2023-07-23 12:01:40 +02:00
Michael Eischer
4a33370072 backend: Fix unreliable TestListCancel/Timeout test
The test uses `WithTimeout` to create a context that cancels the List
operation after a given delay. Several backends internally use a derived
child context created using WithCancel.

The cancellation of a context first closes the done channel of the
context (here: the `WithTimeout` context) and _afterwards_ propagates
the cancellation to child contexts (here: the `WithCancel` context).
Therefor if the List implementation uses a child context, then it may
take a moment until that context is also cancelled. Thus give the
context cancellation a moment to propagate.
2023-07-23 11:47:56 +02:00
Michael Eischer
98fb56baa6 Merge pull request #3802 from MichaelEischer/support-non-utf-symlinks
Support non utf symlink targets
2023-07-23 00:15:01 +02:00
Michael Eischer
f12bbd9229 restic: check that Node.LinkTarget can handle non-utf8 characters 2023-07-23 00:05:14 +02:00
Michael Eischer
6adb629608 Add support for non-utf8 symlink targets 2023-07-23 00:05:14 +02:00
Michael Eischer
25ff9fa893 Merge pull request #4334 from MichaelEischer/snapshot-subtree-syntax
Add support for snapshot:path syntax
2023-07-22 23:59:26 +02:00
Michael Eischer
bdaec8fdb8 Merge pull request #4374 from MichaelEischer/try-refresh-stale-locks
Try to refresh stale locks
2023-07-22 23:50:52 +02:00
Michael Eischer
55b440b520 tweak snapshot:subfolder docs 2023-07-22 23:50:17 +02:00
Michael Eischer
3f63b53090 lock: Shrink critical section in RefreshStaleLock
A cleaning up after a failed lock refresh attempt does not require a
mutex.
2023-07-22 23:29:14 +02:00
Michael Eischer
76253b2a20 Hopefully fix flaky TestLockWaitCancel test 2023-07-22 23:23:17 +02:00
Michael Eischer
20e82d1fcf lock: add changelog for stale lock refresh 2023-07-22 23:23:17 +02:00
Michael Eischer
96eada3d5f backend/sema: add test for freeze functionality 2023-07-22 23:23:17 +02:00
Michael Eischer
b8f4267a36 lock: add more debug information to flaky test 2023-07-22 23:23:17 +02:00
Michael Eischer
1f6883a05c lock: test stale lock refresh 2023-07-22 23:23:17 +02:00
Michael Eischer
8154f6a77a Ensure consistent naming for <snapshot>:<subfolder> syntax 2023-07-22 19:55:57 +02:00
Michael Eischer
184b7616ba document snapshot:subfolder syntax 2023-07-22 19:55:57 +02:00
Michael Eischer
67f237b4f3 add changelog for snapshot:path syntax 2023-07-22 19:55:57 +02:00
Michael Eischer
090f9d6237 restic: Cleanup and simplify TestCreateSnapshot 2023-07-22 19:55:57 +02:00
Michael Eischer
321cc35cde restic: add test for FindTreeDirectory 2023-07-22 19:55:57 +02:00
Michael Eischer
a97915642c restic: Ensure snapshots created by TestCreateSnapshot are valid
All nodes in a tree must be sorted by node name. Otherwise functionality
like searching for a specific tree node will break.
2023-07-22 19:55:57 +02:00
Michael Eischer
c64d81063e test snapshot filtering with snapshot:path syntax 2023-07-22 19:55:57 +02:00
Michael Eischer
233b841ad9 Add cat tree snapshot:subpath command
This command prints the tree for the given path.
2023-07-22 19:55:57 +02:00
Michael Eischer
85860e6e97 Add support for snapshot:subpath syntax
This snapshot specification syntax is supported by the cat, diff, dump,
ls and restore command.
2023-07-22 19:55:57 +02:00
Michael Eischer
2dd6769429 lock: Fix possible deadlock during refresh of stale lock
A delayed lock refresh could send a signal on the `refreshed` channel
while the `monitorLockRefresh` goroutine waits for a reply to its
`refreshLockRequest`. As the channels are unbuffered, this resulted in a
deadlock.
2023-07-22 19:55:44 +02:00
Michael Eischer
5d9b0d894e lock: add unit test for RefreshStaleLock 2023-07-22 19:55:44 +02:00
Michael Eischer
d4bf7a3cb1 restic: cleanup lock test 2023-07-22 19:55:44 +02:00
Michael Eischer
24c8a33da9 restic: reduce sleeps in lock tests 2023-07-22 19:55:44 +02:00
Michael Eischer
399f8e84a1 lock: use mem backend for locking tests
This hopefully fixes the timing related test failures which appear to be
caused by very slow fsync calls.
2023-07-22 19:55:44 +02:00
Michael Eischer
6a436d731d lock: rename test helper function 2023-07-22 19:55:44 +02:00
Michael Eischer
b2fcbc21cb lock: rework stale lock refresh to avoid data race 2023-07-22 19:55:44 +02:00
Michael Eischer
05e5e29a8c backup: don't pretend to lock repo for dry run
The dry run did not actually create lock files, but still ran all other
parts of the lock processing.
2023-07-22 19:55:44 +02:00
Michael Eischer
f490288738 lock: freeze backend operations while refreshing stale lock
Freeze new backend operations while trying to refresh a stale lock.
2023-07-22 19:55:44 +02:00
Michael Eischer
51718ec561 restic: generic implemention of AsBackend 2023-07-22 19:55:44 +02:00
Michael Eischer
11eb88a2ea lock: cleanup 2023-07-22 19:55:44 +02:00
Michael Eischer
bee3231ed4 lock: try refreshing of stale locks
A stale lock may be refreshed if it continues to exist until after a
replacement lock has been created. This ensures that a repository was
not unlocked in the meantime.
2023-07-22 19:55:44 +02:00
Michael Eischer
60d8066568 Merge pull request #4407 from MichaelEischer/simpler-required-ci
CI: Add check that verifies the results of other checks
2023-07-22 19:55:06 +02:00
Michael Eischer
08dea911bd CI: Add check that verifies the results of other checks
To properly use merge queues, it is necessary to mark certain checks as
"required" in the branch protection rules. However, this doesn't scale
with matrix jobs and would require manual tweaks of the CI jobs change.
The new analyze job simplifies this by allowing the branch protection
rule just check for that job. All further dependencies are then
configured within the CI config.
2023-07-16 14:13:41 +02:00
Michael Eischer
47206a6579 Merge pull request #4351 from kenny-y-dev/human-readable-ls
Add --human-readable to ls and find output
2023-07-16 11:44:41 +00:00
Michael Eischer
594689db32 Merge pull request #4400 from MichaelEischer/rest-handle-missing-dirs
rest: Ignore missing directories
2023-07-14 23:29:37 +02:00
Michael Eischer
5705326bb8 add changelog 2023-07-14 22:39:38 +02:00
Michael Eischer
978ebaac49 rest: use http status code constants 2023-07-14 22:39:38 +02:00
Michael Eischer
307aeb6849 rest: Don't return error if listing non-existent directory
When transferring a repository from S3 to, for example, a local disk
then all empty folders will be missing.

When saving files, the missing intermediate folders are created
automatically. Therefore, missing directories can be ignored by the
`List()` operation.
2023-07-14 22:39:38 +02:00
Michael Eischer
9cd85d5956 Merge pull request #4029 from ekarlso/add-azure-workload-identity-support
add azure workload identity support
2023-07-09 19:06:59 +00:00
Michael Eischer
c9f506925c azure: Document additional auth options 2023-07-09 20:56:21 +02:00
Michael Eischer
e990d3d483 azure: Support authentication using managed / workload identity
See https://github.com/Azure/azure-sdk-for-go/tree/sdk/azidentity/v1.3.0/sdk/azidentity
2023-07-09 14:47:03 +02:00
Michael Eischer
7042190807 Merge pull request #4403 from MichaelEischer/fix-certificate-env-handling
Fix certificate env handling
2023-07-09 14:46:38 +02:00
Michael Eischer
c158741e2e CI: add minimal CLI test
Just create a repository and run a minimal backup.
2023-07-09 14:29:43 +02:00
Michael Eischer
89fbd39e59 Don't print stacktrace on invalid cacert option 2023-07-09 14:23:54 +02:00
Michael Eischer
1ce599d2ae Fix handling of empty cacert environment variable
This resulted in a "empty filename for root certificate supplied" error.
2023-07-09 14:23:54 +02:00
Michael Eischer
789fec3da7 Merge pull request #4402 from MichaelEischer/merge-queue-setup
CI: Enable missing CI tests for Github merge queue
2023-07-09 13:57:10 +02:00
Michael Eischer
8a120c8800 CI: Enable missing CI tests for Github merge queue 2023-07-08 23:51:39 +02:00
Michael Eischer
41395e83c5 Merge pull request #2740 from metalsp0rk/document-json
Add JSON documentation
2023-07-08 21:34:02 +00:00
Michael Eischer
2a193195b0 Merge pull request #4364 from MichaelEischer/multiplatform-docker
Setup multiplatform docker builds
2023-07-08 23:31:58 +02:00
Michael Eischer
229c7b24a4 doc: add program_version field of snapshot JSON output 2023-07-08 23:31:20 +02:00
Michael Eischer
b34ce57dd4 doc: describe JSON output of restore command 2023-07-08 23:31:20 +02:00
Michael Eischer
1ce839228e doc: Expand JSON documentation 2023-07-08 23:31:20 +02:00
Kyle Brennan
fb1170c1d6 doc tweaks 2023-07-08 23:21:41 +02:00
Kyle Brennan
e457fe22bc Documentation improvement 2023-07-08 23:21:41 +02:00
Kyle Brennan
39299e36ef add json documentation 2023-07-08 23:21:41 +02:00
Michael Eischer
0512f292e8 Merge pull request #4361 from MichaelEischer/stats-repo-debug-info
stats: Add `debug` mode to collect repository statistics
2023-07-08 23:20:23 +02:00
Michael Eischer
3a93e28605 CI: Remove .dockerignore to ensure reproducible builds
Since go 1.18, built binaries also include VCS information such as the
built commit. This information is also included in the official
binaries. To ensure that the Docker container recreates the same
binaries, the .git folder must also be transferred into the container.
Thus, remove the .dockerignore file.

The copied files must also be owned by the current user within the
container, as git refuses to work otherwise.
2023-07-08 23:16:14 +02:00
Michael Eischer
6b82cce1bd add changelog for multiplatform containers 2023-07-08 23:16:14 +02:00
Michael Eischer
31e07cecbb docker: update to Go 1.20 for custom container builds 2023-07-08 23:05:39 +02:00
Michael Eischer
c181b51360 doc: Update docker build process 2023-07-08 23:05:38 +02:00
Michael Eischer
ccd19b7e88 CI: run cloud backend tests only on restic/restic 2023-07-08 23:05:02 +02:00
Michael Eischer
b0987ff570 CI: only build containers on restic/restic 2023-07-08 23:05:02 +02:00
Michael Eischer
eff3124f15 CI: Setup automatic container builds for ghcr.io
Containers are built for new tags and pushes to the master branch.
2023-07-08 23:05:02 +02:00
Michael Eischer
43fa051546 Directly build restic binary in release Docker container 2023-07-08 23:05:02 +02:00
Michael Eischer
2293835242 Release multi-platform docker containers 2023-07-08 23:05:02 +02:00
Michael Eischer
0fcb6c7f94 ask for debug statistics in resource usage issues 2023-07-08 23:04:47 +02:00
Michael Eischer
325fa916b5 stats: Add debug mode to collect repository statistics 2023-07-08 23:04:47 +02:00
Michael Eischer
170e495334 Merge pull request #4401 from MichaelEischer/fix-windows-build
fuse: fix windows build
2023-07-08 23:01:22 +02:00
Michael Eischer
9d44682e3e fuse: fix windows build 2023-07-08 22:40:22 +02:00
Michael Eischer
4d43509423 Merge pull request #4379 from chenxiaolong/symlink_xattrs
Add support for extended attributes on symlinks
2023-07-08 16:56:51 +00:00
Michael Eischer
ea9ad77e05 restic: refactor node test 2023-07-08 18:54:56 +02:00
Michael Eischer
cc84884d2e restic: basic xattr test for files/dirs 2023-07-08 18:49:21 +02:00
Michael Eischer
4a5ae2ba84 restic: test NodeFromFileInfo for symlinks 2023-07-08 18:18:13 +02:00
Michael Eischer
1f1e50f49e fuse: add test for symlink xattr 2023-07-08 18:02:17 +02:00
Michael Eischer
f3c3b0f377 fuse: deduplicate xattr code 2023-07-08 17:41:45 +02:00
Michael Eischer
7e2be9e081 Merge pull request #4384 from arjunajesh/issue#1926
certificates can be passed through env vars
2023-07-08 07:46:31 +00:00
Michael Eischer
cc3c218baf small cleanups for certificate environment variables 2023-07-08 09:44:59 +02:00
arjunajesh
c1578a2035 certificates can be passed through env vars 2023-07-08 09:44:59 +02:00
Michael Eischer
678b983300 Merge pull request #4360 from Refutable4890/master
Add an description of `check` temporary cache directory location
2023-07-07 21:51:52 +00:00
Michael Eischer
1b3870dc43 Merge pull request #4378 from MichaelEischer/add-version-to-snapshot
Add program version to snapshot
2023-07-07 23:50:44 +02:00
Michael Eischer
ef40aee2bd Merge pull request #4373 from MichaelEischer/performance-issue-help
document how to analyze performance / memory usage issues
2023-07-07 23:50:27 +02:00
Michael Eischer
3a32c4e59f document how to analyze performance / memory usage issues 2023-07-07 23:38:53 +02:00
Michael Eischer
e703e89e9b add changelog for program version 2023-07-07 23:36:57 +02:00
Michael Eischer
389f6ee74c backup: add minimal test for program versioni 2023-07-07 23:33:23 +02:00
Michael Eischer
bbac74b172 add program version to snapshot 2023-07-07 23:27:10 +02:00
Michael Eischer
a280b7364e Merge pull request #4395 from greatroar/parsebytes
cmd, ui: Move size parsing code and make it more robust
2023-07-07 21:24:47 +00:00
Michael Eischer
825651a135 Merge pull request #4387 from arjunajesh/issue#2468
azure domain can be overridden with env variable
2023-07-07 21:17:01 +00:00
Michael Eischer
e36d17a6f8 azure: tweak documentation for endpoint suffix 2023-07-07 23:10:26 +02:00
arjunajesh
068b115abc added azure domain parameter 2023-07-07 23:10:26 +02:00
greatroar
41a5bf357f cmd, ui: Move size parsing code and make it more robust 2023-07-02 21:44:50 +02:00
Michael Eischer
f96896a9c0 Merge pull request #4383 from LouisMT/add-docker-hostname
Add hostname flag to Docker docs
2023-07-01 18:58:43 +02:00
dependabot[bot]
2ab9a3b9c3 Merge pull request #4389 from restic/dependabot/go_modules/google.golang.org/api-0.129.0 2023-07-01 16:57:18 +00:00
Louis Matthijssen
dbe2eef80c Add hostname flag to Docker docs
Fixes #4380
2023-07-01 18:46:31 +02:00
dependabot[bot]
6e7c6674ad build(deps): bump google.golang.org/api from 0.116.0 to 0.129.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.116.0 to 0.129.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.116.0...v0.129.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 16:11:44 +00:00
Michael Eischer
7fe830ee1e Merge pull request #4392 from restic/dependabot/go_modules/github.com/Azure/azure-sdk-for-go/sdk/azcore-1.6.1
build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.6.0 to 1.6.1
2023-07-01 18:10:47 +02:00
Michael Eischer
a07c7166ba Merge pull request #4390 from restic/dependabot/go_modules/golang.org/x/oauth2-0.9.0
build(deps): bump golang.org/x/oauth2 from 0.8.0 to 0.9.0
2023-07-01 18:10:38 +02:00
dependabot[bot]
d2f8f9de23 build(deps): bump golang.org/x/oauth2 from 0.8.0 to 0.9.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.8.0 to 0.9.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 15:32:55 +00:00
dependabot[bot]
d5fe5107c8 Merge pull request #4391 from restic/dependabot/go_modules/golang.org/x/sys-0.9.0 2023-07-01 15:31:42 +00:00
dependabot[bot]
f08ba1a005 build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore
Bumps [github.com/Azure/azure-sdk-for-go/sdk/azcore](https://github.com/Azure/azure-sdk-for-go) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.6.0...sdk/azcore/v1.6.1)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/azcore
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 01:23:19 +00:00
dependabot[bot]
70fb554854 build(deps): bump golang.org/x/sys from 0.8.0 to 0.9.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.8.0 to 0.9.0.
- [Commits](https://github.com/golang/sys/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 01:23:05 +00:00
Andrew Gunnerson
8c02ebb029 Add support for extended attributes on symlinks
Linux allows the use of non-`user.` extended attributes on symlinks. One
of the main users of this functionality is SELinux's `security.selinux`
xattr for storing a path's label. By storing symlink xattrs, restic is
now suitable for backing up the root filesystem on Linux distributions
that use SELinux.

This commit adds support for symlink xattrs when backing up data,
restoring data, and mounting snapshots via a fuse mount. All calls to
the xattr library have been updated to the use `L` variants of the
various functions, which always operate on the path given, without
following symlinks.

Fixes: #4375

Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
2023-06-19 14:37:31 -04:00
Michael Eischer
8dcb0c4a9d doc: improve description of caching behavior of the check command 2023-06-17 22:18:50 +02:00
Michael Eischer
74ca82a6f8 Merge pull request #4362 from restic/unified-backend-factory
Unified backend initialization
2023-06-17 15:52:37 +02:00
Michael Eischer
9cbc2502c6 Merge pull request #4366 from gautammenghani/master
Issue #3624: Preserve oldest snapshot when keep-* values are not sati…
2023-06-17 15:41:17 +02:00
Michael Eischer
93038ed8f4 s3: restore retries for minio tests 2023-06-17 15:25:08 +02:00
Gautam Menghani
8da5a6649b Preserve oldest snapshot when keep-within* does not collect enough 2023-06-17 15:17:20 +02:00
Michael Eischer
3888c21a27 reword changelog 2023-06-17 15:16:58 +02:00
Michael Eischer
1257c2c075 forget: Add comments to snapshot policy 2023-06-17 15:16:58 +02:00
Gautam Menghani
182b9796e4 Issue #3624: Preserve oldest snapshot when keep-* values are not satisfied 2023-06-17 15:16:58 +02:00
Michael Eischer
cbf87fbdb3 init: don't include password in debug log 2023-06-17 15:15:58 +02:00
Michael Eischer
b5511e8e4c Fix linter warnings 2023-06-17 15:15:58 +02:00
Michael Eischer
50e0d5e6b5 backend: Hardcode backend scheme in Factory
Our ParseConfig implementations always expect a specific scheme, thus no
other scheme would work.
2023-06-17 15:15:58 +02:00
Michael Eischer
705ad51bcc backend: check that StripPassword can be called 2023-06-17 15:15:58 +02:00
Michael Eischer
13a8b5822f backend: Adjust tests to use the Factory to instantiate the backend
This drastically reduces the amount of duplicated test code.
2023-06-17 15:15:58 +02:00
Michael Eischer
3d3bb88745 b2: remove duplicate check for config file during repository creation
No other backend implements that check. The check that a repository is
not yet initialized is handled by the Repository later on.
2023-06-17 15:15:58 +02:00
Michael Eischer
3a3cf608f5 b2/s3: Move config validation from ApplyEnvironment to Open/Create
Conceptually the backend configuration should be validated when creating
or opening the backend, but not when filling in information from
environment variables into the configuration.
2023-06-17 15:15:58 +02:00
Michael Eischer
19ac12d95b location: make genericBackendFactory private 2023-06-17 15:15:58 +02:00
Michael Eischer
3325a7c862 location: extract backend specific part of StripPassword
The tests for the rest backend now reside there.
2023-06-17 15:15:58 +02:00
Michael Eischer
555be49a79 location: Make ParseConfig-test backend agnostic
The backend specific parts of the test are now directly handled by the
respective backend. Duplicate tests were removed.
2023-06-17 15:15:58 +02:00
Michael Eischer
9aa9e0d1ec local/sftp: move limiter setup into backend 2023-06-17 15:15:58 +02:00
Michael Eischer
7d12c29286 backend: Unify backend construction using factory and registry
This unified construction removes most backend-specific code from
global.go. The backend registry will also enable integration tests to
use custom backends if necessary.
2023-06-17 15:15:57 +02:00
Michael Eischer
56836364a4 backend: pass context into every backend constructor 2023-06-17 15:15:57 +02:00
Michael Eischer
4df77e9f26 Merge pull request #4314 from MichaelEischer/restore-json
Add JSON support for the restore progress bar
2023-06-16 23:53:17 +02:00
Michael Eischer
2545c84321 Merge pull request #4365 from MichaelEischer/ci-rework-build-tests
CI: rework build tests
2023-06-16 23:29:39 +02:00
Michael Eischer
191c47d30e Merge pull request #4353 from MichaelEischer/tune-gc
Tune Go garbage collector
2023-06-16 23:24:39 +02:00
Michael Eischer
dd1ef13c1c Merge pull request #4352 from MichaelEischer/pointerless-index
index: optimize go GC performance
2023-06-16 23:23:14 +02:00
Michael Eischer
4d5ee987a7 add changelog about missing AIX builds 2023-06-16 23:19:36 +02:00
Michael Eischer
b2ed42cec4 index: add basic hat test 2023-06-16 23:12:30 +02:00
Michael Eischer
61042a77a4 building on aix is currently not possible 2023-06-09 13:35:35 +02:00
Michael Eischer
4e9e2c3229 CI: Use build-release-binaries to run the cross-compilation tests
gox silently ignored linux/mips and aix/ppc64. This change also removes
the duplicate platform list.
2023-06-09 13:27:57 +02:00
Michael Eischer
faec0ff816 build-release-binaries: support building a subset of all platforms 2023-06-09 13:27:33 +02:00
Michael Eischer
07d1f8047e restore: More descriptive field names for the JSON output 2023-06-09 12:07:55 +02:00
Michael Eischer
b2b0760eb0 restore: add test for json output 2023-06-09 12:03:33 +02:00
Michael Eischer
cf16239058 restore: print output via termStatus 2023-06-09 12:03:33 +02:00
Michael Eischer
1531eab746 mention restore json support in changelog 2023-06-09 12:03:33 +02:00
Michael Eischer
d54176ce5d restore: add basic json progress 2023-06-09 12:03:33 +02:00
Michael Eischer
a9aff885d6 restore: reorganize progress bar code
The structure is now much more similar to that of the backup command.
2023-06-09 12:03:33 +02:00
Michael Eischer
bb20078641 restore: pass termStatus to restore in tests 2023-06-09 12:03:33 +02:00
Michael Eischer
237f32c651 Merge pull request #3261 from DRON-666/prealloc-packs
Prevent local backend file fragmentation by file preallocation.
2023-06-09 11:50:46 +02:00
DRON-666
74e4656850 Update changelog 2023-06-09 11:49:06 +03:00
DRON-666
c37d587f81 Use PreallocateFile in local backend 2023-06-09 11:49:06 +03:00
DRON-666
ffc6b3d887 Move PreallocateFile to fs package 2023-06-09 11:49:06 +03:00
Michael Eischer
88c63a029c Merge pull request #3563 from matta/improve-eta
Improve the ETA displayed during backup
2023-06-08 20:49:19 +02:00
Michael Eischer
0b908bb1fb Address review comments 2023-06-08 20:24:21 +02:00
Matt Armstrong
0372c7ef04 Improve the ETA displayed during backup
The ETA restic displays was based on a rate computed across the entire
backup operation. Often restic can progress at uneven rates. In the worst
case, restic progresses over most of the backup at a very high rate and
then finds new data to back up. The displayed ETA is then unrealistic and
never adapts.

Restic now estimates the transfer rate based on a sliding window, with the
goal of adapting to observed changes in rate. To avoid wild changes in the
estimate, several heuristics are used to keep the sliding window wide
enough to be relatively stable.
2023-06-08 20:05:56 +02:00
Michael Eischer
9464c63550 Make formatNode test timezone independent
formatNode formats the timestamp according to the current time zone. Pin
the local timezone to UTC to ensure the test works everywhere.
2023-06-08 19:18:30 +02:00
Michael Eischer
6ebf2dd235 Reduce duplicate code in test for fomatNode 2023-06-08 19:16:16 +02:00
Michael Eischer
5f153109ba Refactor formatNode 2023-06-08 19:12:49 +02:00
Michael Eischer
2beaa74892 tweak changelog 2023-06-08 19:12:26 +02:00
Michael Eischer
55c21846b1 Revert "index: remove redundant storage of indexmap size"
This reverts commit f1c388c623.

For an uninitialized indexmap the returned size was `-1` which is
unexpected and could cause problems.
2023-06-08 18:08:46 +02:00
Michael Eischer
0f80b6a137 add changelog for gc tuning 2023-06-08 18:02:46 +02:00
Michael Eischer
e14ccb1142 Merge pull request #4298 from restic/backend-parseconfig-cleanup
Unified and slightly type-safer backend config parsing
2023-06-08 12:02:27 +02:00
Michael Eischer
609367195a backend: Fix test compilation with Go 1.18 and 1.19 2023-06-07 22:31:15 +02:00
Michael Eischer
18eb1d3ab0 backend: test cleanup 2023-06-07 22:31:15 +02:00
Michael Eischer
32a6b66267 backend: add standardized Config.ApplyEnvironment
This removes the backend specific special cases while parsing the
configuration in `global.go`.
2023-06-07 22:31:15 +02:00
Michael Eischer
f903db492c backend: let ParseConfig return a Config pointer
In order to change the backend initialization in `global.go` to be able
to generically call cfg.ApplyEnvironment() for supported backends, the
`interface{}` returned by `ParseConfig` must contain a pointer to the
configuration.

An alternative would be to use reflection to convert the type from
`interface{}(Config)` to `interface{}(*Config)` (from value to pointer
type). However, this would just complicate the type mess further.
2023-06-07 22:31:15 +02:00
Michael Eischer
25a0be7f26 backend: fix linter warnings 2023-06-07 22:31:15 +02:00
Michael Eischer
a27b7f1370 backend: use generic instead of any type for test suite 2023-06-07 22:31:14 +02:00
Michael Eischer
fa361dbfbd backend: use generic implementation for ParseConfig tests 2023-06-07 22:30:35 +02:00
Michael Eischer
5260d38980 backend: let ParseConfig return concrete type 2023-06-07 22:30:35 +02:00
Michael Eischer
2f7b4ceae1 backend: Move environment based configuration into backend 2023-06-07 22:30:35 +02:00
Refutable4890
aea7538936 Add an description of check temporary cache directory location 2023-06-07 22:35:33 +08:00
Michael Eischer
49a6a4f5bf Merge pull request #4356 from MichaelEischer/fix-unlock-hint
lock: fix missing hint to unlock command if repository is locked
2023-06-06 21:03:06 +02:00
Michael Eischer
237d00000e lock: fix missing hint to unlock command if repository is locked 2023-06-02 23:16:49 +02:00
dependabot[bot]
0c727f6ad1 Merge pull request #4355 from restic/dependabot/go_modules/github.com/minio/minio-go/v7-7.0.56 2023-06-02 20:51:26 +00:00
Michael Eischer
4e7d3efad4 Merge pull request #4345 from DanielGibson/patch-1
restic restore docs: Mention that restic restore is fastest
2023-06-02 22:44:38 +02:00
Michael Eischer
17446da5fd Merge pull request #4343 from greatroar/cache
cache: Restructure New to remove redundant operations
2023-06-02 22:41:17 +02:00
dependabot[bot]
a3cee840d2 build(deps): bump github.com/minio/minio-go/v7 from 7.0.52 to 7.0.56
Bumps [github.com/minio/minio-go/v7](https://github.com/minio/minio-go) from 7.0.52 to 7.0.56.
- [Release notes](https://github.com/minio/minio-go/releases)
- [Commits](https://github.com/minio/minio-go/compare/v7.0.52...v7.0.56)

---
updated-dependencies:
- dependency-name: github.com/minio/minio-go/v7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-02 20:35:42 +00:00
dependabot[bot]
c76f3a1e27 Merge pull request #4348 from restic/dependabot/go_modules/github.com/spf13/cobra-1.7.0 2023-06-02 20:34:38 +00:00
dependabot[bot]
1e9714088d Merge pull request #4347 from restic/dependabot/go_modules/golang.org/x/sync-0.2.0 2023-06-02 20:32:27 +00:00
Michael Eischer
58e3f5955c Merge pull request #4350 from restic/dependabot/go_modules/github.com/Azure/azure-sdk-for-go/sdk/azcore-1.6.0
build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.4.0 to 1.6.0
2023-06-02 22:26:55 +02:00
dependabot[bot]
dd8d8b1ae0 build(deps): bump github.com/spf13/cobra from 1.6.1 to 1.7.0
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.6.1 to 1.7.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.6.1...v1.7.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-02 20:22:39 +00:00
dependabot[bot]
e1ac0f0e0c build(deps): bump golang.org/x/sync from 0.1.0 to 0.2.0
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.1.0 to 0.2.0.
- [Commits](https://github.com/golang/sync/compare/v0.1.0...v0.2.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-02 20:22:36 +00:00
Michael Eischer
a88d90b8e5 Merge pull request #4346 from restic/dependabot/go_modules/golang.org/x/oauth2-0.8.0
build(deps): bump golang.org/x/oauth2 from 0.7.0 to 0.8.0
2023-06-02 22:21:22 +02:00
Michael Eischer
2fcb3947df prune: trigger GC after prune planning 2023-06-02 21:57:40 +02:00
Michael Eischer
eef0ee7a85 repository: trigger GC after loading the index
Loading the index requires some scratch space, thus make sure that this
memory does not factor into the targeted gc memory usage limit.
2023-06-02 21:56:14 +02:00
Michael Eischer
f1b73c9301 Reduce GOGC to 50
The index used by restic consumes a major part of the total memory
usage. This leads to an unnecessarily large amount of memory that
contains ephemeral objects that are only used for a short time.
2023-06-02 21:51:50 +02:00
Michael Eischer
ac1dfc99bb index: fix blocklist size 2023-06-02 19:39:12 +02:00
Kenny Y
098de3554c Add pull request link 2023-06-01 21:30:51 -04:00
Kenny Y
8812dcd56a Add --human-readable to ls and find output
Modifies format module to add options for human readable storage size formatting, using size parsing already in ui/format.
Cmd flag --human-readable added to ls and find commands.
Additional option added to formatNode to support printing size in regular or new human readable format
2023-06-01 21:18:18 -04:00
dependabot[bot]
379282299a build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore
Bumps [github.com/Azure/azure-sdk-for-go/sdk/azcore](https://github.com/Azure/azure-sdk-for-go) from 1.4.0 to 1.6.0.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.4.0...sdk/azcore/v1.6.0)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/azcore
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-01 01:59:16 +00:00
dependabot[bot]
0c796dbd9b build(deps): bump golang.org/x/oauth2 from 0.7.0 to 0.8.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.7.0 to 0.8.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-01 01:58:29 +00:00
Daniel Gibson
f9dded83b3 doc/050_restore.rst: Mention that restic restore is fastest
Especially with lots of files (like when backing up git repos),
restic mount + cp -r can be really slow.
2023-05-31 22:44:36 +02:00
Michael Eischer
88a10a368f Merge pull request #4342 from greatroar/errors
cmd: Don't check for errno == 0
2023-05-31 22:17:07 +02:00
Michael Eischer
9a7056a479 index: implement indexmap.grow() without random access 2023-05-30 20:13:33 +02:00
Michael Eischer
fc05e35a08 index: let indexmap.Each iterate in allocation order
Iterating through the indexmap according to the bucket order has the
problem that all indexEntries are accessed in random order which is
rather cache inefficient.

As we already keep a list of all allocated blocks, just iterate through
it. This allows iterating through a batch of indexEntries without random
memory accesses. In addition, the packID will likely remain similar
across multiple blobs as all blobs of a pack file are added as a single
batch.
2023-05-30 20:12:36 +02:00
Michael Eischer
f1c388c623 index: remove redundant storage of indexmap size 2023-05-30 20:11:53 +02:00
Michael Eischer
12141afbad index: Allow inlining of HAT 2023-05-30 20:11:14 +02:00
Michael Eischer
fed33295c3 index: store indexEntries in hashed array tree
This data structure reduces the wasted memory to O(sqrt(n)). The
top-layer of the hashed array tree (HAT) also has a size of O(sqrt(n)),
which makes it cache efficient. The top-layer should be small enough to
easily fit into the CPU cache and thus only adds little overhead
compared to directly accessing an index entry via a pointer.
2023-05-29 00:24:15 +02:00
Michael Eischer
b217f38ee7 index: Remove pointers from within indexentrys
The indexEntry objects are now allocated in a separate array. References
to an indexEntry are now stored as array indices. This has the benefit
of allowing the garbage collector to ignore the indexEntry objects as
these do not contain pointers and are part of a single large allocation.
2023-05-29 00:24:15 +02:00
Michael Eischer
0c1240360d index: add garbage collection benchmark
Allocates an index and repeatedly triggers the GC.
2023-05-29 00:23:04 +02:00
Michael Eischer
ffca602315 repository: Fix panic in benchmarkLoadIndex 2023-05-28 23:55:47 +02:00
greatroar
da419be43c cache: Restructure New to remove redundant operations
New and its helpers used to create the cache directories several times
over. They now only do so once. The added test ensures that the cache is
produced in a consistent state when parts are deleted.
2023-05-27 10:32:08 +02:00
greatroar
8f1ca8fabe cmd: Don't check for errno == 0
Maybe term.Restore's predecessor could return this, but the current
implementation never does.
2023-05-27 08:52:37 +02:00
Michael Eischer
f74dad2afb Merge pull request #4340 from restic/least-privilege-ci
CI: least privilege for workflows
2023-05-26 20:29:05 +02:00
Michael Eischer
3e287afdbf Merge pull request #4226 from Sohalt/gcs-region
gs: support other regions than us
2023-05-26 20:28:52 +02:00
Michael Eischer
06894484a1 shorten changelog title 2023-05-26 20:05:49 +02:00
Michael Eischer
6e5b42d5c4 CI: least privilege for workflows 2023-05-26 19:58:02 +02:00
sohalt
ed5b2c2c9b gs: support other regions than us 2023-05-26 19:54:42 +02:00
Michael Eischer
13c32b0fbe Merge pull request #4328 from MichaelEischer/cleanup-integration-tests
Cleanup integration tests
2023-05-26 19:49:16 +02:00
Michael Eischer
9747cef338 fix linter warnings 2023-05-26 19:38:44 +02:00
Michael Eischer
8e913e6d3a repair index: always read Quiet flags from GlobalOptions passed as parameter 2023-05-26 19:38:44 +02:00
Michael Eischer
b93459cbb0 repair snapshots: use local copy of globalOptions to open repository 2023-05-26 19:38:44 +02:00
Michael Eischer
692f81ede8 cleanup prune integration test 2023-05-26 19:38:44 +02:00
Michael Eischer
7a268e4aba always access stdout/stderr via globalOptions 2023-05-26 19:38:44 +02:00
Michael Eischer
4b3a0b4104 read JSON/Quiet flag from the passed in globalOptions 2023-05-26 19:38:44 +02:00
Michael Eischer
cebce52c16 test: add helper to capture stdout for integration tests 2023-05-26 19:38:44 +02:00
Michael Eischer
675a49a95b Restructure integration tests
The tests are now split into individual files for each command. The
separation isn't perfect as many tests make use of multiple commands. In
particular `init`, `backup`, `check` and `list` are used by a larger
number of test cases.

Most tests now reside in files name cmd_<name>_integration_test.go. This
provides a certain indication which commands have significant test
coverage.
2023-05-26 19:38:43 +02:00
Michael Eischer
e2dba9f5c7 test: cleanup a some check calls 2023-05-26 19:34:57 +02:00
Michael Eischer
06fd6b54d7 test: print log output if testRunCheck fails 2023-05-26 19:34:57 +02:00
Michael Eischer
419e6f26b1 tests: Simplify checks that a specific number of snapshots exists 2023-05-26 19:34:57 +02:00
Michael Eischer
c3212ab6a6 test: use standard logging methods from testing for the test helpers
Use the logging methods from testing.TB to make use of tb.Helper(). This
allows the tests to log the filename and line number in which the test
helper was called. Previously the test helper was logged which is rarely
useful.
2023-05-26 19:34:57 +02:00
Michael Eischer
658aa4c0f7 Merge pull request #4339 from greatroar/ioctl
backend, termstatus: fix ioctl calls for 64-bit big-endian platforms
2023-05-26 19:34:14 +02:00
Michael Eischer
998cf5a7f8 Merge pull request #4333 from MichaelEischer/staticcheck
Update golangci-lint and resolve all errors
2023-05-26 19:34:00 +02:00
Michael Eischer
7eec91f841 add changelog 2023-05-26 19:23:51 +02:00
greatroar
51dc80be5b backend: Use IoctlSetPointerInt for tcsetpgrp
This function casts its argument to int32 before passing it to the
system call, so that big-endian CPUs read the lower rather than the
upper 32 bits of the pid.

This also gets rid of the last import of "unsafe" in the Unix build.
I changed syscall to x/sys/unix while I was at it, to remove one more
import line. The constants and types there are aliases for their syscall
counterparts.
2023-05-25 17:31:51 +02:00
greatroar
ddbc0c1b37 termstatus: Fix IsProcessBackground for 64-bit big-endian Linux
Fixes #4223. Verified with QEMU on linux/amd64.
2023-05-25 17:20:42 +02:00
Michael Eischer
ecbf8e055c CI: upgrade golangci-lint and check full codebase 2023-05-18 21:17:53 +02:00
Michael Eischer
16ba237d8b azure: Fix missing rate limiting 2023-05-18 21:17:53 +02:00
Michael Eischer
a466e945d9 stats: pass StatsOptions via parameter 2023-05-18 21:17:53 +02:00
Michael Eischer
03b9764bce init/generate: check that no parameters are passed 2023-05-18 21:17:53 +02:00
Michael Eischer
22c9276719 rest: remove unused parameter 2023-05-18 21:17:53 +02:00
Michael Eischer
1e33b285c1 lock: remove unused parameter 2023-05-18 21:17:53 +02:00
Michael Eischer
c05f96e6b9 repair index: remove no longer used paramter 2023-05-18 21:17:53 +02:00
Michael Eischer
94752b7ee2 backup: Remove unused parameters from rejectFunc collection 2023-05-18 21:17:53 +02:00
Michael Eischer
0058745881 test: use parameter instead of hardcoded constant 2023-05-18 21:17:53 +02:00
Michael Eischer
a719d10e22 termstatus: remove unused parameter from helpers 2023-05-18 21:17:53 +02:00
Michael Eischer
b0a01ae68a ui/backup: remove unused parameter from ProgressPrinter interface 2023-05-18 21:17:53 +02:00
Michael Eischer
472bf5184f Replace lots of unused parameters with _
The parameters are required by the implemented function signature or interface.
2023-05-18 21:17:53 +02:00
Michael Eischer
d1a5ec7839 Rename unused testing parameter to _
The parameter is an additional marker that the test helper must only be
used for tests.
2023-05-18 21:17:53 +02:00
Michael Eischer
1514593f22 Remove unused context or testing parameters 2023-05-18 21:17:53 +02:00
Michael Eischer
5e4e268bdc Use _ as parameter name for unused Context
The context is required by the implemented interface.
2023-05-18 21:15:45 +02:00
Michael Eischer
3252f60df5 Ignore deprecated imports for poly1305 and openpgp 2023-05-18 21:15:45 +02:00
Michael Eischer
2fa8b96843 Don't shadow builtins 2023-05-18 21:15:45 +02:00
Michael Eischer
7a01bd3b67 Remove unnecessary else block 2023-05-18 21:15:45 +02:00
Michael Eischer
319087c056 Remove redundant if ...; err != nil; return pattern 2023-05-18 21:15:45 +02:00
Michael Eischer
6ed73ed408 CI: remove deprecated linters 2023-05-18 21:15:45 +02:00
Michael Eischer
c832a492ac fuse: use syscall errnos directly to fix deprecations 2023-05-18 21:15:45 +02:00
Michael Eischer
e01baeabba Use either test or rtest to refer to internal test helpers
A single test file should not use both names.
2023-05-18 21:15:45 +02:00
Michael Eischer
bfc9c6c971 Merge pull request #4331 from MichaelEischer/fix-mount-failures
Hopefully fix `TestMount` failures
2023-05-18 20:22:57 +02:00
Michael Eischer
5773b86d02 repository: Push all usage of errors.Fatal out of the package
As the `Fatal` error type only includes a string, it becomes impossible
to inspect the contained error. This is for a example a problem for the
fuse implementation, which must be able to detect context.Canceled
errors.

Co-authored-by: greatroar <61184462+greatroar@users.noreply.github.com>
2023-05-18 17:27:41 +02:00
Michael Eischer
a013014c24 backup: return normal error if --group-by cannot be parsed
Co-authored-by: greatroar <61184462+greatroar@users.noreply.github.com>
2023-05-18 17:23:31 +02:00
Michael Eischer
f9850b79b5 rest/sftp: Remove redundant fatal from error message
This caused restic to exit with error messages like
`Fatal: parsing repository location failed: Fatal: sftp path [...]`
`Fatal: create repository at rest:http://localhost:12345/ failed: Fatal: config file already exists`
2023-05-18 17:22:26 +02:00
Michael Eischer
2f518b7241 Merge pull request #4304 from MichaelEischer/unlimited-lock-refresh
lock: Do not limit backend concurrency for lock files
2023-05-13 21:40:29 +02:00
Michael Eischer
49be202cb0 Merge pull request #4315 from MichaelEischer/restore-hardlink-progress
restore: Correctly account for hardlinks in progress bar
2023-05-13 21:37:40 +02:00
Michael Eischer
19ebc1b786 restore: Add basic test for progress bar accounting of hardlinks 2023-05-08 20:51:49 +02:00
Michael Eischer
23a122a901 restore: count files in the same way as the stats command 2023-05-08 20:51:49 +02:00
Michael Eischer
e77002f841 restore: correctly count hardlinks in progress bar
For hardlinked files, only the first instance of that file increases the
amount of bytes to restore. All later instances only increase the file
count but not the restore size.
2023-05-08 20:51:49 +02:00
Michael Eischer
d05f6211d1 lock: Do not limit backend concurrency for lock files
restic must be able to refresh lock files in time. However, large
uploads over slow connections can cause the lock refresh to be stuck
behind the large uploads and thus time out.
2023-05-08 19:04:46 +02:00
Michael Eischer
ee3c55ea3d Merge pull request #2876 from aawsome/new-repair-command
Add repair command
2023-05-05 23:22:24 +02:00
Michael Eischer
db046c0acc Merge pull request #4318 from MichaelEischer/status-output-truncation
Fix status output truncation
2023-05-05 23:09:59 +02:00
Michael Eischer
3e6a26e2e9 Merge pull request #4317 from MichaelEischer/debug-test-mount-failures
mount: enable debug logging for the flaky TestMount test
2023-05-05 23:08:03 +02:00
greatroar
65c5e511a1 ui/termstatus: Add test for Terminal.SetStatus 2023-05-05 22:51:41 +02:00
Michael Eischer
6d10c655a0 termstatus: test status line sanitization 2023-05-05 22:51:41 +02:00
Michael Eischer
bb40e49e75 ui/termstatus: Fix truncation of status output
The last line was not truncated as expected
2023-05-05 22:45:52 +02:00
Michael Eischer
fefe15d7a1 Merge pull request #4316 from MichaelEischer/fix-check-modified-data
Fix flaky TestCheckerModifiedData test
2023-05-05 22:38:28 +02:00
Michael Eischer
78e5aa6d30 repair snapshots: add basic tests 2023-05-04 23:00:46 +02:00
Michael Eischer
1cb11ad8ad mount: enable debug logging for the flaky TestMount test
The test case fails from time to time with an Input/Output error while
trying to access the snapshots directory.
2023-05-01 18:03:17 +02:00
Michael Eischer
90a663c94f Merge pull request #4308 from greatroar/tar-header
dump: Report filename with tar.ErrFieldTooLong
2023-05-01 17:30:31 +02:00
Michael Eischer
88a7231217 report snapshot id if loading failed 2023-05-01 17:24:13 +02:00
Michael Eischer
c0627dc80d check: Fix flaky TestCheckerModifiedData
The test had a 4% chance of not modified the data read from the
repository, in which case the test would fail. Change the data
manipulation to just modified each read operation.
2023-05-01 17:18:19 +02:00
Michael Eischer
e71367e6b9 repair snapshots: update changelog 2023-05-01 16:06:17 +02:00
Michael Eischer
5aa37acdaa repair snapshots: cleanup command help 2023-05-01 16:06:17 +02:00
Michael Eischer
9c64a95df8 doc: rewrite troubleshooting section 2023-05-01 16:06:17 +02:00
Michael Eischer
7c8dd61e8c repair snapshots: cleanup warnings 2023-05-01 15:22:30 +02:00
Michael Eischer
f6cc10578d repair snapshots: Always sanitize file nodes
If the node for a file is intact, this is a no-op.
2023-05-01 15:22:18 +02:00
Michael Eischer
4ce87a7f64 repair snapshots: port to filterAndReplaceSnapshot
The previous approach of rewriting all snapshots first, then flushing
the repository data and finally removing old snapshots has the downside
that an interrupted command execution leaves behind broken snapshots as
not all new data is already flushed.
2023-05-01 15:22:03 +02:00
Michael Eischer
e17ee40a31 repair snapshots: Port to use walker.TreeRewriter 2023-05-01 15:20:36 +02:00
Michael Eischer
1bd1f3008d walker: extend TreeRewriter to support snapshot repairing
This adds support for caching already rewritten trees, handling of load
errors and disabling the check that the serialization doesn't lead to
data loss.
2023-05-01 15:20:24 +02:00
Michael Eischer
38dac78180 walker: restructure FilterTree into TreeRewriter
The more generic RewriteNode callback replaces the SelectByName and
PrintExclude functions. The main part of this change is a preparation to
allow using the TreeRewriter for the `repair snapshots` command.
2023-05-01 15:20:12 +02:00
Michael Eischer
bc2399fbd9 walker: recurse into directory based on node type
A broken directory might also not have a subtree.
2023-05-01 15:20:00 +02:00
Michael Eischer
1a9705fc95 walker: Simplify change detection in FilterTree
Now the rewritten tree is always serialized which makes sure that we
don't accidentally miss any relevant changes.
2023-05-01 15:19:48 +02:00
Michael Eischer
8c4caf09a8 repair snapshots: Do not rename repaired files
The files in a tree must be sorted in lexical order. However, this
cannot be guaranteed when appending a filename suffix. For two files

file, file.rep

where "file" is broken, this would result in

file.repaired, file.rep

which is no longer sorted.

In addition, adding a filename suffix is also prone to filename
collisions which would require a rather complex search for a
collision-free name in order to work reliably.
2023-05-01 15:19:36 +02:00
Michael Eischer
375189488c rewrite: prepare for code sharing with rewrite snapshots 2023-05-01 15:19:24 +02:00
Michael Eischer
903651c719 repair snapshots: partially synchronize code with rewrite command
Simplify CLI options:
* Rename "DeleteSnapshots" to "Forget"
* Replace "AddTag" and "Append" with hardcoded values

Change output and snapshot modifications to be more in line with the
"rewrite" command.
2023-05-01 15:19:11 +02:00
Michael Eischer
118d599d0a Rename 'rebuild-index' to 'repair index'
The old name still works, but is deprecated.
2023-05-01 15:16:44 +02:00
Michael Eischer
db459eda21 move to subcommand 2023-05-01 15:15:48 +02:00
Michael Eischer
a14a63cd29 modernize code 2023-05-01 15:12:09 +02:00
Alexander Weiss
947f0c345e correct typos 2023-05-01 14:56:42 +02:00
Alexander Weiss
d23a2e1925 better error handling and correct nil tree behavior 2023-05-01 14:56:42 +02:00
Alexander Weiss
08ae708b3b make linter happy 2023-05-01 14:56:42 +02:00
Alexander Weiss
99a05d5ab2 Update troubleshooting documentation 2023-05-01 14:56:42 +02:00
Alexander Weiss
6557f36f61 Add changelog and docu for #2876 2023-05-01 14:56:42 +02:00
Alexander Weiss
5f58797ba7 Add repair command 2023-05-01 14:56:42 +02:00
Alexander Weiss
9cef6b4c69 Add troubleshooting documentation 2023-05-01 14:56:42 +02:00
Michael Eischer
8a78a042db Merge pull request #4310 from restic/dependabot/go_modules/github.com/klauspost/compress-1.16.5
build(deps): bump github.com/klauspost/compress from 1.16.0 to 1.16.5
2023-05-01 14:35:57 +02:00
Michael Eischer
b491af2b57 Merge pull request #4311 from restic/dependabot/go_modules/golang.org/x/crypto-0.8.0
build(deps): bump golang.org/x/crypto from 0.7.0 to 0.8.0
2023-05-01 14:35:37 +02:00
dependabot[bot]
d747a9c401 build(deps): bump golang.org/x/crypto from 0.7.0 to 0.8.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.7.0 to 0.8.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.7.0...v0.8.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 11:15:38 +00:00
dependabot[bot]
888c1ae63a build(deps): bump github.com/klauspost/compress from 1.16.0 to 1.16.5
Bumps [github.com/klauspost/compress](https://github.com/klauspost/compress) from 1.16.0 to 1.16.5.
- [Release notes](https://github.com/klauspost/compress/releases)
- [Changelog](https://github.com/klauspost/compress/blob/master/.goreleaser.yml)
- [Commits](https://github.com/klauspost/compress/compare/v1.16.0...v1.16.5)

---
updated-dependencies:
- dependency-name: github.com/klauspost/compress
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 11:07:29 +00:00
Michael Eischer
5eeb257c95 Merge pull request #4312 from restic/dependabot/go_modules/github.com/minio/minio-go/v7-7.0.52
build(deps): bump github.com/minio/minio-go/v7 from 7.0.50 to 7.0.52
2023-05-01 13:00:48 +02:00
Michael Eischer
ae6729cf89 Merge pull request #4309 from restic/dependabot/go_modules/golang.org/x/oauth2-0.7.0
build(deps): bump golang.org/x/oauth2 from 0.6.0 to 0.7.0
2023-05-01 12:58:55 +02:00
dependabot[bot]
6abd494915 build(deps): bump github.com/minio/minio-go/v7 from 7.0.50 to 7.0.52
Bumps [github.com/minio/minio-go/v7](https://github.com/minio/minio-go) from 7.0.50 to 7.0.52.
- [Release notes](https://github.com/minio/minio-go/releases)
- [Commits](https://github.com/minio/minio-go/compare/v7.0.50...v7.0.52)

---
updated-dependencies:
- dependency-name: github.com/minio/minio-go/v7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 01:59:50 +00:00
dependabot[bot]
7147a54ceb build(deps): bump golang.org/x/oauth2 from 0.6.0 to 0.7.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/oauth2/releases)
- [Commits](https://github.com/golang/oauth2/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 01:59:10 +00:00
Michael Eischer
8d971172c4 Merge pull request #4306 from MichaelEischer/document-restic-compression-env
Document that the compression mode can be set via $RESTIC_COMPRESSION
2023-04-30 18:26:10 +02:00
Michael Eischer
37d0e323eb doc: update help output in manual_rest.rst 2023-04-30 16:12:29 +02:00
Michael Eischer
face5bd7f7 Document that the compression mode can be set via $RESTIC_COMPRESSION 2023-04-30 16:11:53 +02:00
Michael Eischer
1daf928a77 Merge pull request #4305 from MichaelEischer/stracktrace-for-windows
Print stacktrace in SIGINT handler if RESTIC_DEBUG_STACKTRACE_SIGINT set
2023-04-30 16:08:58 +02:00
Michael Eischer
37bab08181 Merge pull request #4302 from MichaelEischer/logging-cleanup
Tweak debug logs
2023-04-30 16:08:08 +02:00
Michael Eischer
6dc2324d2e Merge pull request #4301 from MichaelEischer/less-restore-memory
restore: slightly reduce memory usage while restoring files
2023-04-30 16:07:43 +02:00
Michael Eischer
850cd9aace Merge pull request #4299 from MichaelEischer/update-scripting-docs
doc: recommend `cat config` to check if a repository exists
2023-04-30 16:04:59 +02:00
greatroar
b50ff04cf3 dump: Report filename with tar.ErrFieldTooLong
Updates #4307.
2023-04-27 11:45:41 +02:00
Michael Eischer
c8641f4479 Merge branch 'patch-release' 2023-04-24 20:44:38 +02:00
Alexander Neumann
ac7ac0cb97 Set development version for 0.15.2 2023-04-24 20:28:37 +02:00
Michael Eischer
306a29980a Print stacktrace in SIGINT handler if RESTIC_DEBUG_STACKTRACE_SIGINT set
The builtin mechanism to capture a stacktrace in Go is to send a SIGQUIT
to the running process. However, this mechanism is not avaiable on
Windows. Thus, tweak the SIGINT handler to dump a stacktrace if the
environment variable `RESTIC_DEBUG_STACKTRACE_SIGINT` is set.
2023-04-23 15:50:40 +02:00
Michael Eischer
41cc320145 Merge pull request #4166 from MichaelEischer/cache-mkdirall
cache: Create missing intermediate directories when caching a file
2023-04-23 11:44:18 +02:00
Michael Eischer
cdb0fb9c06 tweak debug logs 2023-04-23 11:38:06 +02:00
Michael Eischer
94cbc6392d restore: slightly reduce memory usage while restoring files
The information which target files are contained in a pack file is no
longer necessary after processing a pack.
2023-04-23 11:33:21 +02:00
Michael Eischer
78a1757e5a Cancel current command if cache becomes unusable
If the cache suddenly disappears, the current command will now fail.
2023-04-23 11:31:15 +02:00
Michael Eischer
22562d2132 Merge pull request #4300 from MichaelEischer/less-flaky-tests
Increase timeouts for lock refresh tests
2023-04-23 11:24:59 +02:00
Michael Eischer
51d823348d Merge pull request #4286 from MichaelEischer/backend-cleanup-logging
Normalize backend logging and connection limiting
2023-04-23 11:24:26 +02:00
Michael Eischer
831f593b87 backend/sema: Add tests 2023-04-22 13:20:20 +02:00
Michael Eischer
179e11c2ae Increase timeouts for lock refresh tests
When saving files to the local backend, in some cases the used fsync
calls are slow enough to cause the tests to time out. Thus, increase the
test timeouts as a stopgap measure until we can use the mem backend for
these tests.
2023-04-22 12:45:59 +02:00
Michael Eischer
ebba233a3a backend/sema: rename constructor to NewBackend 2023-04-22 12:32:57 +02:00
rawtaz
8479390d7c Merge pull request #3939 from Fabien-jrt/resticprofile
doc: Add resticprofile to scheduling section
2023-04-22 01:24:34 +02:00
Fabien-Jrt
756f43d5f9 doc: Add resticprofile to scheduling section 2023-04-22 01:04:48 +02:00
Michael Eischer
affd04c125 doc: recommend cat config to check if a repository exists
This will be much faster if a large number of snapshots exists.
2023-04-21 22:56:31 +02:00
Michael Eischer
f27750e270 backend/sema: rename type to connectionLimitedBackend 2023-04-21 22:53:09 +02:00
Michael Eischer
1dd873b706 Merge pull request #4293 from MichaelEischer/fix-groups-by
Fix parent snapshot selection for relative paths
2023-04-21 22:47:03 +02:00
Michael Eischer
7a60d9e54f Merge pull request #4288 from MichaelEischer/log-warnings-to-debug-log
Add warnings via Warnf to the debug log
2023-04-21 22:39:00 +02:00
Michael Eischer
3001dd8c2b Add test to verify that the backup parent is correctly selected 2023-04-21 22:35:02 +02:00
Michael Eischer
4503aea0df Merge pull request #4296 from MichaelEischer/rewrite-reorder-output
rewrite: log snapshot saved before removal of the old snapshot
2023-04-19 22:00:32 +02:00
Michael Eischer
09cddb8927 rewrite: log snapshot saved before removal of the old snapshot
The snapshot was already saved before removing the old snapshot. Only
the log messages were printed in the wrong order.
2023-04-17 21:00:45 +02:00
Michael Eischer
913eab3361 Merge pull request #4234 from thndrbrrr/forget-opts-neg1-means-forever-issue-2565
restic forget --keep-* options will interpret -1 as "forever"
2023-04-14 23:18:47 +02:00
Michael Eischer
a9c7c12276 Merge pull request #4265 from HeikoSchlittermann/chg/progress-to-stderr
generate: do not write progress to STDOUT
2023-04-14 23:18:23 +02:00
Michael Eischer
85eef232e6 Merge pull request #4232 from thndrbrrr/copy-chunker-params-verbose-msg
init: Add --copy-chunker-params verbose msg
2023-04-14 23:17:56 +02:00
Michael Eischer
a06d927dce Merge pull request #4291 from greatroar/widechars
ui/termstatus: Optimize Truncate
2023-04-14 22:48:34 +02:00
Michael Eischer
fd3ed9e2f4 Merge pull request #4192 from greatroar/quote
ui/termstatus: Quote funny filenames
2023-04-14 22:39:09 +02:00
Michael Eischer
6042df075f migrations: Fix S3 backend detection 2023-04-14 22:32:16 +02:00
Michael Eischer
c934c99d41 gs: replace usage of context.Background() 2023-04-14 22:32:15 +02:00
Michael Eischer
616926d2c1 gs: use IsNotExist to check error 2023-04-14 22:32:15 +02:00
Michael Eischer
05abc6d6f5 backend: deduplicate implementation of Delete() method 2023-04-14 22:32:15 +02:00
Michael Eischer
45244fdf68 backend: remove parameter validation tests
These parameter validations have been factored out into
SemaphoreBackend.
2023-04-14 22:32:15 +02:00
Michael Eischer
803640ba4b backend: remove a few unnecessary debug logs 2023-04-14 22:32:15 +02:00
Michael Eischer
8e1e3844aa backend: factor out connection limiting and parameter validation
The SemaphoreBackend now uniformly enforces the limit of concurrent
backend operations. In addition, it unifies the parameter validation.

The List() methods no longer uses a semaphore. Restic already never runs
multiple list operations in parallel.

By managing the semaphore in a wrapper backend, the sections that hold a
semaphore token grow slightly. However, the main bottleneck is IO, so
this shouldn't make much of a difference.

The key insight that enables the SemaphoreBackend is that all of the
complex semaphore handling in `openReader()` still happens within the
original call to `Load()`. Thus, getting and releasing the semaphore
tokens can be refactored to happen directly in `Load()`. This eliminates
the need for wrapping the reader in `openReader()` to release the token.
2023-04-14 22:32:15 +02:00
Michael Eischer
8b5ab5b59f dryrun: fix outdated comments 2023-04-14 22:32:15 +02:00
Michael Eischer
4703473ec5 backend: extract most debug logs into logger backend 2023-04-14 22:32:15 +02:00
Michael Eischer
8bfc2519d7 backend: Deduplicate sanity checks for parameters of Load() method
The check is now handled by backend.DefaultLoad. This also guarantees
consistent behavior across all backends.
2023-04-14 22:32:15 +02:00
Michael Eischer
ba16904eed backup: Add test to verify parent snapshot selection for relative paths 2023-04-14 22:21:43 +02:00
Michael Eischer
2841a87cc6 Fix snapshot filtering for relative paths in the backup command
The snapshot filtering internally converts relative paths to absolute
ones to ensure that the parent snapshots selection works for backups of
relative paths.
2023-04-14 21:53:55 +02:00
Michael Eischer
fab4a8a4d2 Properly initialize the --group-by option for backup tests 2023-04-14 21:53:01 +02:00
Torben Giesselmann
6d6c04abef forget: Simplify usage text 2023-04-14 10:05:23 -07:00
greatroar
49e32f3f8a ui/termstatus: Optimize Truncate
x/text/width.LookupRune has to re-encode its argument as UTF-8,
while LookupString operates on the UTF-8 directly.
The uint casts get rid of a bounds check.

Benchmark results, with b.ResetTimer introduced first:

name               old time/op  new time/op  delta
TruncateASCII-8    69.7ns ± 1%  55.2ns ± 1%  -20.90%  (p=0.000 n=20+18)
TruncateUnicode-8   350ns ± 1%   171ns ± 1%  -51.05%  (p=0.000 n=20+19)
2023-04-14 11:13:39 +02:00
greatroar
9412f37e50 ui/termstatus: Quote funny filenames
Fixes #2260, #4191.
2023-04-14 09:36:02 +02:00
Heiko Schlittermann (HS12-RIPE)
087cf7e114 generate: write progress to STDOUT if this is a terminal
This allows usage as:

  eval "$(restic generated --bash-completion /dev/stdout)"
2023-04-12 22:39:59 +02:00
Michael Eischer
e604939e72 Debug log status code if execution is interrupted
Currently, there is no clear indication in the debug log whether restic
exited or not.
2023-04-12 21:58:35 +02:00
Michael Eischer
37aca6bec0 Add warnings via Warnf to the debug log 2023-04-12 21:37:37 +02:00
Michael Eischer
bdcafbc11c Merge pull request #4282 from TorstenC/patch-1
040_backup.rst line 228 - #4280 --exclude-caches
2023-04-11 22:34:16 +02:00
Torsten C
ba33e41068 040_backup.rst line 228 - #4280 --exclude-caches
Proposal for issue #4280
2023-04-11 22:33:10 +02:00
Michael Eischer
4661f45a8c Merge pull request #4220 from Skaronator/master
Add jq to container image
2023-04-11 22:26:02 +02:00
Michael Eischer
2091fc0dde Merge pull request #4107 from jooola/feature-wait-for-unlock
Add a global option --retry-lock
2023-04-11 22:21:01 +02:00
Michael Eischer
9238dcc81a Merge pull request #4201 from restic/dependabot/go_modules/github.com/Azure/azure-sdk-for-go/sdk/storage/azblob-1.0.0
build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/storage/azblob from 0.5.1 to 1.0.0
2023-04-11 22:20:38 +02:00
Torben Giesselmann
71537da4b0 init: Add --copy-chunker-params verbose msg 2023-04-09 14:59:07 -07:00
Torben Giesselmann
ce51d2f3c0 forget: Update usage text 2023-04-09 12:59:15 -07:00
Torben Giesselmann
403b7ca2be forget: Update documentation 2023-04-09 12:57:37 -07:00
Torben Giesselmann
309cf0586a Add changelog entry 2023-04-09 12:05:15 -07:00
Torben Giesselmann
9f9e91eb0d Fix comment to comply with linter 2023-04-09 11:47:10 -07:00
Michael Eischer
1f43003cc1 Merge branch 'master' into feature-wait-for-unlock 2023-04-07 20:32:21 +02:00
Michael Eischer
8ce5f29758 lock: increase test timeout tolerances to avoid test failures 2023-04-07 20:07:05 +02:00
Michael Eischer
8afc117aa3 Merge pull request #4285 from MichaelEischer/debug-lock-refresh-failures
lock: Improve debug logging in the test
2023-04-07 20:06:15 +02:00
Michael Eischer
cf1cc1fb72 lock: Print stacktrace if TestLockSuccessfulRefresh fails 2023-04-07 19:51:31 +02:00
Michael Eischer
64233ca0a7 lock: Improve debug logging in the test 2023-04-07 19:43:00 +02:00
jo
ea59896bd6 Add a global option --retry-lock
Fixes restic#719

If the option is passed, restic will wait the specified duration of time
and retry locking the repo every 10 seconds (or more often if the total
timeout is relatively small).

- Play nice with json output
- Reduce wait time in lock tests
- Rework timeout last attempt
- Reduce test wait time to 0.1s
- Use exponential back off for the retry lock
- Don't pass gopts to lockRepo functions
- Use global variable for retry sleep setup
- Exit retry lock on cancel
- Better wording for flag help
- Reorder debug statement
- Refactor tests
- Lower max sleep time to 1m
- Test that we cancel/timeout in time
- Use non blocking sleep function
- Refactor into minDuration func

Co-authored-by: Julian Brost <julian@0x4a42.net>
2023-04-07 16:24:14 +02:00
Michael Eischer
806a0cdce3 bump minimum go version on Solaris to 1.20 2023-04-07 15:40:57 +02:00
Michael Eischer
faa83db9e4 azure: Adapt code to API change 2023-04-07 15:05:55 +02:00
dependabot[bot]
9358a5fb37 build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/storage/azblob
Bumps [github.com/Azure/azure-sdk-for-go/sdk/storage/azblob](https://github.com/Azure/azure-sdk-for-go) from 0.5.1 to 1.0.0.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/armcore/v0.5.1...v1.0)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/storage/azblob
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-07 11:03:25 +00:00
Michael Eischer
71c9516b26 Merge pull request #4247 from restic/dependabot/go_modules/github.com/Azure/azure-sdk-for-go/sdk/azcore-1.4.0
build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.3.1 to 1.4.0
2023-04-07 13:01:04 +02:00
Michael Eischer
17ac91fba3 Merge pull request #4283 from restic/dependabot/go_modules/google.golang.org/api-0.116.0
build(deps): bump google.golang.org/api from 0.114.0 to 0.116.0
2023-04-07 12:58:54 +02:00
Michael Eischer
26a3c47c5c Merge pull request #4255 from greatroar/fuse-hash
fuse: Mix inode hashes in a non-symmetric way
2023-04-07 12:56:57 +02:00
Michael Eischer
7896e50301 Merge pull request #4271 from restic/dependabot/go_modules/github.com/minio/minio-go/v7-7.0.50
build(deps): bump github.com/minio/minio-go/v7 from 7.0.49 to 7.0.50
2023-04-07 12:47:30 +02:00
dependabot[bot]
9584cbda90 build(deps): bump google.golang.org/api from 0.114.0 to 0.116.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.114.0 to 0.116.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.114.0...v0.116.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-07 10:27:38 +00:00
dependabot[bot]
cacc48fc09 build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore
Bumps [github.com/Azure/azure-sdk-for-go/sdk/azcore](https://github.com/Azure/azure-sdk-for-go) from 1.3.1 to 1.4.0.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.3.1...sdk/azcore/v1.4.0)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/azcore
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-07 10:27:30 +00:00
Michael Eischer
7fbaca577b Merge pull request #4272 from restic/dependabot/go_modules/cloud.google.com/go/storage-1.30.1
build(deps): bump cloud.google.com/go/storage from 1.29.0 to 1.30.1
2023-04-07 12:26:20 +02:00
Michael Eischer
1f9dd84d1e Merge pull request #3991 from mark-herrmann/feature/restore-progress
restore: show progress
2023-04-07 12:24:55 +02:00
Michael Eischer
c8ff5592b8 Merge pull request #4273 from ducalex/gitignore-restic-exe
Added restic.exe to the .gitignore
2023-04-07 12:10:09 +02:00
Mark Herrmann
f875a8843d restore: Add progress bar
Co-authored-by: Mark Herrmann <mark.herrmann@mailbox.org>
2023-04-07 12:08:23 +02:00
Alex Duchesne
0ed5c20c57 Added restic.exe to the .gitignore 2023-03-28 23:07:25 -04:00
dependabot[bot]
21edbdc3ac build(deps): bump cloud.google.com/go/storage from 1.29.0 to 1.30.1
Bumps [cloud.google.com/go/storage](https://github.com/googleapis/google-cloud-go) from 1.29.0 to 1.30.1.
- [Release notes](https://github.com/googleapis/google-cloud-go/releases)
- [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-cloud-go/compare/pubsub/v1.29.0...spanner/v1.30.1)

---
updated-dependencies:
- dependency-name: cloud.google.com/go/storage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-26 20:14:09 +00:00
dependabot[bot]
220d937975 build(deps): bump github.com/minio/minio-go/v7 from 7.0.49 to 7.0.50
Bumps [github.com/minio/minio-go/v7](https://github.com/minio/minio-go) from 7.0.49 to 7.0.50.
- [Release notes](https://github.com/minio/minio-go/releases)
- [Commits](https://github.com/minio/minio-go/compare/v7.0.49...v7.0.50)

---
updated-dependencies:
- dependency-name: github.com/minio/minio-go/v7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-26 20:13:34 +00:00
rawtaz
5f13bbc118 Merge pull request #4270 from MichaelEischer/monthly-dependabot
Switch back to monthly dependabot updates
2023-03-26 22:09:21 +02:00
Michael Eischer
9672670756 Merge pull request #4240 from greatroar/fuse-blocks
fuse: Report fuse.Attr.Blocks correctly
2023-03-26 21:57:53 +02:00
Michael Eischer
5ac24a9744 Switch back to monthly dependabot updates 2023-03-26 21:55:27 +02:00
Michael Eischer
99e247caa6 Merge pull request #4259 from restic/dependabot/github_actions/actions/setup-go-4
build(deps): bump actions/setup-go from 3 to 4
2023-03-26 21:53:47 +02:00
Michael Eischer
0c705e07db Merge pull request #4249 from restic/dependabot/go_modules/golang.org/x/oauth2-0.6.0
build(deps): bump golang.org/x/oauth2 from 0.5.0 to 0.6.0
2023-03-26 10:38:53 +02:00
Michael Eischer
024d01d85b Merge pull request #4266 from restic/linkfix
doc: Correct broken links
2023-03-22 22:59:54 +01:00
Leo R. Lundgren
0666fa11b8 doc: Correct broken links 2023-03-22 17:37:58 +01:00
rawtaz
caa0e89114 Merge pull request #4246 from greatroar/doc
doc: Fix links, focus less on implementation details
2023-03-22 14:47:31 +01:00
rawtaz
46a7072f3f Merge pull request #4264 from GuitarBilly/patch-1
Update 110_talks.rst - Add changelog podcast.
2023-03-22 14:13:40 +01:00
GuitarBilly
1f12915b0c Update 110_talks.rst
Update 110_talks.rst

align date to 2nd of April as agreed.
( match podcast publication date )
2023-03-22 13:54:27 +01:00
greatroar
a0885d5d69 fuse: Mix inode hashes in a non-symmetric way
Since 0.15 (#4020), inodes are generated as hashes of names, xor'd with
the parent inode. That means that the inode of a/b/b is

	h(a/b/b) = h(a) ^ h(b) ^ h(b) = h(a).

I.e., the grandchild has the same inode as the grandparent. GNU find
trips over this because it thinks it has encountered a loop in the
filesystem, and fails to search a/b/b. This happens more generally when
the same name occurs an even number of times.

Fix this by multiplying the parent by a large prime, so the combining
operation is not longer symmetric in its arguments. This is what the FNV
hash does, which we used prior to 0.15. The hash is now

	h(a/b/b) = h(b) ^ p*(h(b) ^ p*h(a))

Note that we already ensure that h(x) is never zero.

Collisions can still occur, but they should be much less likely to occur
within a single path.

Fixes #4253.
2023-03-21 17:33:18 +01:00
dependabot[bot]
5dccab701a build(deps): bump actions/setup-go from 3 to 4
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 02:18:58 +00:00
Torben Giesselmann
5069c9edd9 Represent -1 as "all" in ExpirePolicy's Stringer 2023-03-15 15:07:51 -07:00
Torben Giesselmann
1a584cb16e Refactor policy sum calculation & duration parsing
- Convert policy sum calculation to function and move to tests.
- Remove parseDuration(...) and use ParseDurationOrPanic(...) instead.
2023-03-14 19:29:08 -07:00
Torben Giesselmann
84ede6ad7a forget: Prevent neg. values in --keep-within* opts 2023-03-14 19:20:03 -07:00
Torben Giesselmann
b7f03d01b8 Add helper function for Duration parsing
Tests in cmd_forget_test.go need the same convenience function
that was implemented in snapshot_policy_test.go.

Function parseDuration(...) was moved to testing.go  and renamed to
ParseDurationOrPanic(...).
2023-03-14 19:16:24 -07:00
dependabot[bot]
eaceaca113 build(deps): bump golang.org/x/oauth2 from 0.5.0 to 0.6.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/golang/oauth2/releases)
- [Commits](https://github.com/golang/oauth2/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 02:07:39 +00:00
greatroar
a7ac9a4769 doc: Fix some links, focus less on implementation details
The godoc for filepath.Match has the syntax, which is what is important
for writing patterns. Use pkg.go.dev instead of golang.org/pkg.

For #4245. Not all links fixed yet.
2023-03-13 00:23:15 +01:00
Michael Eischer
23ed03a267 Merge pull request #4243 from restic/update-go
Run tests with Go 1.20
2023-03-12 18:15:54 +01:00
Alexander Neumann
aac8c5a7ca Merge pull request #4244 from MichaelEischer/fix-doc-typos
Fix documentation typos and build with Sphinx 6
2023-03-12 15:04:26 +01:00
Michael Eischer
7c8a401d97 Merge pull request #4176 from LXGaming/fix/impostor
Fix scan_finished JSON MessageType
2023-03-12 12:14:40 +01:00
Alexander Neumann
d83332315c Update golangci-lint 2023-03-12 12:05:59 +01:00
Alexander Neumann
c2703e5024 Increase timeout for golangci-lint 2023-03-12 12:02:22 +01:00
Michael Eischer
eb7dbc88b5 Merge pull request #4210 from aawsome/patch-1
docs: Corrections/extra information in design.rst
2023-03-12 12:00:25 +01:00
Michael Eischer
e02aadf1d2 doc: use extlink for links to issues 2023-03-12 11:55:36 +01:00
Michael Eischer
c4e6b198ae doc: fix building with Sphinx 6 2023-03-12 11:45:26 +01:00
Michael Eischer
f47c8eebb7 doc: fix broken link in rewrite command docs 2023-03-12 11:44:56 +01:00
Alexander Neumann
996e2ac7c5 Run tests with Go 1.20 2023-03-12 11:41:22 +01:00
Michael Eischer
a67d3781a3 doc: apply review comments and improve link formatting 2023-03-12 11:37:37 +01:00
Michael Eischer
153a73ebba Merge pull request #4242 from MichaelEischer/fix-mixed-index-in-design-docs
doc: Remove mixed pack files from index example
2023-03-12 11:24:21 +01:00
Michael Eischer
f9d6e3a035 Merge pull request #4236 from restic/dependabot/go_modules/golang.org/x/crypto-0.7.0
build(deps): bump golang.org/x/crypto from 0.5.0 to 0.7.0
2023-03-11 20:42:38 +01:00
dependabot[bot]
51656e8764 build(deps): bump golang.org/x/crypto from 0.5.0 to 0.7.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.5.0 to 0.7.0.
- [Release notes](https://github.com/golang/crypto/releases)
- [Commits](https://github.com/golang/crypto/compare/v0.5.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-11 19:17:59 +00:00
Michael Eischer
9e23200bff Merge pull request #4219 from ianmuge/feat_upgrade_minio_for_new_region
(feat) Upgrade Minio to 7.0.49
2023-03-11 20:17:03 +01:00
Michael Eischer
b884643b40 Merge pull request #4224 from restic/dependabot/go_modules/github.com/klauspost/compress-1.16.0
build(deps): bump github.com/klauspost/compress from 1.15.15 to 1.16.0
2023-03-11 20:14:55 +01:00
Ian Muge
5be4845710 added changelog 2023-03-11 20:04:12 +01:00
Ian Muge
cfa3c6abc5 upgrade Minio to 7.0.49 2023-03-11 20:04:12 +01:00
Michael Eischer
f499e66032 Merge pull request #4235 from restic/dependabot/go_modules/google.golang.org/api-0.111.0
build(deps): bump google.golang.org/api from 0.109.0 to 0.111.0
2023-03-11 20:02:03 +01:00
Michael Eischer
00575ecffe doc: Remove mixed pack files from index example
The example given for the format of an index shows a mixed pack file.
Mixing tree and data blobs has been deprecated for a long time. Thus,
change the pack to only contain "data" blobs.
2023-03-11 19:10:31 +01:00
greatroar
cb5694d136 fuse: Report fuse.Attr.Blocks correctly
Fixes #4239.
2023-03-07 22:14:07 +01:00
dependabot[bot]
100b06d806 build(deps): bump google.golang.org/api from 0.109.0 to 0.111.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.109.0 to 0.111.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.109.0...v0.111.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 02:11:38 +00:00
Torben Giesselmann
667536cea4 forget: Allow neg. values in "--keep-within*" opts 2023-03-05 14:18:08 -08:00
Torben Giesselmann
ba183c44c3 forget: Add test with regular and "forever" opts 2023-03-05 13:56:16 -08:00
Torben Giesselmann
32e6a438be forget: Add test for "keep all hourly snapshots" 2023-03-04 22:13:34 -08:00
Torben Giesselmann
b77b0749fa forget: Treat -1 as forever for all "last n" opts 2023-03-04 19:01:37 -08:00
Torben Giesselmann
6aca7dac21 forget: Verify forget opts 2023-03-03 19:10:11 -08:00
Torben Giesselmann
8161605f1b snapshot_group: Fix typo 2023-03-03 19:07:57 -08:00
dependabot[bot]
b78607c9d8 build(deps): bump github.com/klauspost/compress from 1.15.15 to 1.16.0
Bumps [github.com/klauspost/compress](https://github.com/klauspost/compress) from 1.15.15 to 1.16.0.
- [Release notes](https://github.com/klauspost/compress/releases)
- [Changelog](https://github.com/klauspost/compress/blob/master/.goreleaser.yml)
- [Commits](https://github.com/klauspost/compress/compare/v1.15.15...v1.16.0)

---
updated-dependencies:
- dependency-name: github.com/klauspost/compress
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 02:52:10 +00:00
Niklas Wagner
c1101ede19 Add jq to container image 2023-02-21 14:01:43 +01:00
Michael Eischer
f646406822 Merge pull request #4182 from BenWiederhake/dev-with-cache-description
check: Document behavior of --with-cache a bit better
2023-02-19 19:41:38 +01:00
Ben Wiederhake
9888443f5c check: Document behavior of --with-cache a bit better
Also see https://forum.restic.net/t/how-to-speed-up-tiny-incremental-checks/5905
2023-02-19 17:45:47 +01:00
Michael Eischer
cf6dfd6d36 Merge pull request #4212 from greatroar/snapshotfilter
cmd, restic: Refactor and fix snapshot filtering
2023-02-19 15:20:18 +01:00
greatroar
a7786c67f1 cmd, restic: Refactor and fix snapshot filtering
This turns snapshotFilterOptions from cmd into a restic.SnapshotFilter
type and makes restic.FindFilteredSnapshot and FindFilteredSnapshots
methods on that type. This fixes #4211 by ensuring that hosts and paths
are named struct fields instead of unnamed function arguments in long
lists of such.

Timestamp limits are also included in the new type. To avoid too much
pointer handling, the convention is that time zero means no limit.
That's January 1st, year 1, 00:00 UTC, which is so unlikely a date that
we can sacrifice it for simpler code.
2023-02-19 15:04:25 +01:00
Michael Eischer
15b7d9c80b Merge pull request #4213 from restic/dependabot/go_modules/golang.org/x/net-0.7.0
build(deps): bump golang.org/x/net from 0.6.0 to 0.7.0
2023-02-19 12:42:01 +01:00
dependabot[bot]
ee4128281e build(deps): bump golang.org/x/net from 0.6.0 to 0.7.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-19 11:32:55 +00:00
Michael Eischer
3c8aefa0cb Merge pull request #4205 from restic/dependabot/go_modules/golang.org/x/oauth2-0.5.0
build(deps): bump golang.org/x/oauth2 from 0.4.0 to 0.5.0
2023-02-19 12:31:43 +01:00
aawsome
e2df73b0ac Update doc/design.rst
Co-authored-by: greatroar <61184462+greatroar@users.noreply.github.com>
2023-02-17 10:07:53 +01:00
aawsome
f4329a20f6 docs: Corrections/extra information in design.rst 2023-02-16 22:41:30 +01:00
dependabot[bot]
11ebc0c5db build(deps): bump golang.org/x/oauth2 from 0.4.0 to 0.5.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/oauth2/releases)
- [Commits](https://github.com/golang/oauth2/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 02:54:09 +00:00
Michael Eischer
f137be42fe Merge pull request #4081 from MichaelEischer/backup-group-by
Add support for `--group-by` to the backup command
2023-02-11 11:38:13 +01:00
Michael Eischer
0ce182f044 document backup --group-by 2023-02-11 00:55:11 +01:00
Alex Thomson
1b50faf03e Add changelog 2023-02-10 23:45:20 +01:00
Alex Thomson
4cbbf5d952 Fix scan_finished JSON MessageType
Corrected the scan_finished JSON MessageType from status to verbose_status
2023-02-10 23:45:20 +01:00
Michael Eischer
2885db7902 backup: add group-by option 2023-02-10 23:18:14 +01:00
Michael Eischer
acb40d2b94 Refactor group-by to parse options into a struct 2023-02-10 23:18:14 +01:00
Michael Eischer
fa73b50b45 Merge pull request #4198 from MichaelEischer/better-verbose-description
Make help for --verbose less confusing
2023-02-09 22:28:18 +01:00
Michael Eischer
2d700c3887 Make help for --verbose less confusing
The output is now
```
-v, --verbose                    be verbose (specify multiple times or a level using --verbose=n, max level/times is 2)
```
instead of
```
-v, --verbose n                  be verbose (specify multiple times or a level using --verbose=n, max level/times is 2)
```
2023-02-06 22:11:21 +01:00
Michael Eischer
91251f2d57 Merge pull request #4196 from restic/dependabot/github_actions/docker/build-push-action-4
build(deps): bump docker/build-push-action from 3 to 4
2023-02-06 21:54:06 +01:00
Michael Eischer
3df4ec7c61 Merge pull request #4195 from restic/dependabot/go_modules/github.com/Azure/azure-sdk-for-go/sdk/azcore-1.3.1
build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.3.0 to 1.3.1
2023-02-06 21:20:33 +01:00
Michael Eischer
b1d3a1a5e3 Merge pull request #4194 from restic/dependabot/go_modules/google.golang.org/api-0.109.0
build(deps): bump google.golang.org/api from 0.108.0 to 0.109.0
2023-02-06 21:17:57 +01:00
dependabot[bot]
4f31c2699d build(deps): bump docker/build-push-action from 3 to 4
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 02:13:17 +00:00
dependabot[bot]
96b1ff5e38 build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore
Bumps [github.com/Azure/azure-sdk-for-go/sdk/azcore](https://github.com/Azure/azure-sdk-for-go) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.3.0...sdk/azcore/v1.3.1)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/azcore
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 02:07:34 +00:00
dependabot[bot]
6b5ffce9dc build(deps): bump google.golang.org/api from 0.108.0 to 0.109.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.108.0 to 0.109.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.108.0...v0.109.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 02:06:57 +00:00
Michael Eischer
590eb9efd7 Merge pull request #4180 from MichaelEischer/add-riscv
Add linux/riscv64 builds
2023-01-30 22:57:39 +01:00
Michael Eischer
55c4ca66f7 add linux/riscv64 builds 2023-01-30 22:24:12 +01:00
Michael Eischer
56ad761b19 Merge pull request #4177 from greatroar/loadunpacked
repository: Reuse buffers in Repository.LoadUnpacked
2023-01-30 22:12:13 +01:00
greatroar
d129baba7a repository: Reuse buffers in Repository.LoadUnpacked
This method had a buffer argument, but that was nil at all call sites.
That's removed, and instead LoadUnpacked now reuses whatever it
allocates inside its retry loop.
2023-01-30 22:01:01 +01:00
Alexander Neumann
febb32b5b4 Set development version for 0.15.1 2023-01-30 20:43:52 +01:00
384 changed files with 19576 additions and 7158 deletions

View File

@@ -1,12 +0,0 @@
# Folders
.git/
.github/
changelog/
doc/
docker/
helpers/
# Files
.gitignore
.golangci.yml
*.md

View File

@@ -32,23 +32,30 @@ Output of `restic version`
--------------------------
How did you run restic exactly?
-------------------------------
What backend/service did you use to store the repository?
---------------------------------------------------------
Problem description / Steps to reproduce
----------------------------------------
<!--
This section should include at least:
* A description of the problem you are having with restic.
* The complete command line and any environment variables you used to
configure restic's backend access. Make sure to replace sensitive values!
* The output of the commands, what restic prints gives may give us much
information to diagnose the problem!
* The more time you spend describing an easy way to reproduce the behavior (if
this is possible), the easier it is for the project developers to fix it!
-->
What backend/server/service did you use to store the repository?
----------------------------------------------------------------
Expected behavior
-----------------
@@ -65,22 +72,12 @@ In this section, please try to concentrate on observations, so only describe
what you observed directly.
-->
Steps to reproduce the behavior
-------------------------------
<!--
The more time you spend describing an easy way to reproduce the behavior (if
this is possible), the easier it is for the project developers to fix it!
-->
Do you have any idea what may have caused this?
-----------------------------------------------
Do you have an idea how to solve the issue?
-------------------------------------------
<!--
Did something noteworthy happen on your system, Internet connection, backend services, etc?
-->
Did restic help you today? Did it make you happy in any way?

View File

@@ -4,10 +4,10 @@ updates:
- package-ecosystem: "gomod"
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
interval: "monthly"
# Dependencies listed in .github/workflows/*.yml
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
interval: "monthly"

66
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: Create and publish a Docker image
on:
push:
tags:
- 'v*'
branches:
- 'master'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-image:
if: github.repository == 'restic/restic'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@3d58c274f17dffee475a5520cbe67f0a882c4dbb
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Set up QEMU
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226
- name: Ensure consistent binaries
run: |
echo "removing git directory for consistency with release binaries"
rm -rf .git
# remove VCS information from release builds, keep VCS for nightly builds on master
if: github.ref != 'refs/heads/master'
- name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
push: true
context: .
file: docker/Dockerfile.release
platforms: linux/386,linux/amd64,linux/arm,linux/arm64
pull: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@@ -7,9 +7,13 @@ on:
# run tests for all pull requests
pull_request:
merge_group:
permissions:
contents: read
env:
latest_go: "1.19.x"
latest_go: "1.21.x"
GO111MODULE: on
jobs:
@@ -19,29 +23,34 @@ jobs:
# list of jobs to run:
include:
- job_name: Windows
go: 1.19.x
go: 1.21.x
os: windows-latest
- job_name: macOS
go: 1.19.x
go: 1.21.x
os: macOS-latest
test_fuse: false
- job_name: Linux
go: 1.19.x
go: 1.21.x
os: ubuntu-latest
test_cloud_backends: true
test_fuse: true
check_changelog: true
- job_name: Linux (race)
go: 1.19.x
go: 1.21.x
os: ubuntu-latest
test_fuse: true
test_opts: "-race"
- job_name: Linux
go: 1.18.x
go: 1.20.x
os: ubuntu-latest
test_fuse: true
- job_name: Linux
go: 1.19.x
os: ubuntu-latest
test_fuse: true
@@ -53,7 +62,7 @@ jobs:
steps:
- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
@@ -126,12 +135,20 @@ jobs:
if: matrix.os == 'windows-latest'
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Build with build.go
run: |
go run build.go
- name: Minimal test
run: |
./restic init
./restic backup .
env:
RESTIC_REPOSITORY: ../testrepo
RESTIC_PASSWORD: password
- name: Run local Tests
env:
RESTIC_TEST_FUSE: ${{ matrix.test_fuse }}
@@ -179,7 +196,7 @@ jobs:
# own repo, otherwise the secrets are not available
# Skip for Dependabot pull requests as these are run without secrets
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions#responding-to-events
if: (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository) && (github.actor != 'dependabot[bot]') && matrix.test_cloud_backends
if: ((github.repository == 'restic/restic' && github.event_name == 'push') || github.event.pull_request.head.repo.full_name == github.repository) && (github.actor != 'dependabot[bot]') && matrix.test_cloud_backends
- name: Check changelog files with calens
run: |
@@ -193,69 +210,52 @@ jobs:
cross_compile:
strategy:
# ATTENTION: the list of architectures must be in sync with helpers/build-release-binaries/main.go!
matrix:
# run cross-compile in three batches parallel so the overall tests run faster
targets:
- "linux/386 linux/amd64 linux/arm linux/arm64 linux/ppc64le linux/mips linux/mipsle linux/mips64 linux/mips64le linux/riscv64 linux/s390x"
- "openbsd/386 openbsd/amd64 \
freebsd/386 freebsd/amd64 freebsd/arm \
aix/ppc64 \
darwin/amd64 darwin/arm64"
- "netbsd/386 netbsd/amd64 \
windows/386 windows/amd64 \
solaris/amd64"
subset:
- "0/3"
- "1/3"
- "2/3"
env:
GOPROXY: https://proxy.golang.org
runs-on: ubuntu-latest
name: Cross Compile for ${{ matrix.targets }}
name: Cross Compile for subset ${{ matrix.subset }}
steps:
- name: Set up Go ${{ env.latest_go }}
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: ${{ env.latest_go }}
- name: Install gox
run: |
go install github.com/mitchellh/gox@latest
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Cross-compile with gox for ${{ matrix.targets }}
env:
GOFLAGS: "-trimpath"
GOX_ARCHS: "${{ matrix.targets }}"
- name: Cross-compile for subset ${{ matrix.subset }}
run: |
mkdir build-output
gox -parallel 2 -verbose -osarch "$GOX_ARCHS" -output "build-output/{{.Dir}}_{{.OS}}_{{.Arch}}" ./cmd/restic
gox -parallel 2 -verbose -osarch "$GOX_ARCHS" -tags debug -output "build-output/{{.Dir}}_{{.OS}}_{{.Arch}}_debug" ./cmd/restic
mkdir build-output build-output-debug
go run ./helpers/build-release-binaries/main.go -o build-output -s . --platform-subset ${{ matrix.subset }}
go run ./helpers/build-release-binaries/main.go -o build-output-debug -s . --platform-subset ${{ matrix.subset }} --tags debug
lint:
name: lint
runs-on: ubuntu-latest
steps:
- name: Set up Go ${{ env.latest_go }}
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: ${{ env.latest_go }}
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.49
# Optional: show only new issues if it's a pull request. The default value is `false`.
only-new-issues: true
version: v1.55.2
args: --verbose --timeout 5m
# only run golangci-lint for pull requests, otherwise ALL hints get
@@ -269,12 +269,27 @@ jobs:
go mod tidy
git diff --exit-code go.mod go.sum
analyze:
name: Analyze results
needs: [test, cross_compile, lint]
if: always()
permissions: # no need to access code
contents: none
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
with:
jobs: ${{ toJSON(needs) }}
docker:
name: docker
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Docker meta
id: meta
@@ -294,14 +309,14 @@ jobs:
type=sha
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Build and push
id: docker_build
uses: docker/build-push-action@v3
uses: docker/build-push-action@v4
with:
push: false
context: .

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
/restic
/restic.exe
/.vagrant
/.vscode

View File

@@ -10,13 +10,10 @@ linters:
# make sure all errors returned by functions are handled
- errcheck
# find unused code
- deadcode
# show how code can be simplified
- gosimple
# # make sure code is formatted
# make sure code is formatted
- gofmt
# examine code and report suspicious constructs, such as Printf calls whose
@@ -35,12 +32,6 @@ linters:
# find unused variables, functions, structs, types, etc.
- unused
# find unused struct fields
- structcheck
# find unused global variables
- varcheck
# parse and typecheck code
- typecheck
@@ -57,3 +48,6 @@ issues:
- don't use ALL_CAPS in Go names; use CamelCase
# revive: lots of packages don't have such a comment
- "package-comments: should have a package comment"
# staticcheck: there's no easy way to replace these packages
- "SA1019: \"golang.org/x/crypto/poly1305\" is deprecated"
- "SA1019: \"golang.org/x/crypto/openpgp\" is deprecated"

18
.readthedocs.yaml Normal file
View File

@@ -0,0 +1,18 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.11"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: doc/conf.py
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: doc/requirements.txt

File diff suppressed because it is too large Load Diff

View File

@@ -58,6 +58,19 @@ Please be aware that the debug log file will contain potentially sensitive
things like file and directory names, so please either redact it before
uploading it somewhere or post only the parts that are really relevant.
If restic gets stuck, please also include a stacktrace in the description.
On non-Windows systems, you can send a SIGQUIT signal to restic or press
`Ctrl-\` to achieve the same result. This causes restic to print a stacktrace
and then exit immediatelly. This will not damage your repository, however,
it might be necessary to manually clean up stale lock files using
`restic unlock`.
On Windows, please set the environment variable `RESTIC_DEBUG_STACKTRACE_SIGINT`
to `true` and press `Ctrl-C` to create a stacktrace.
If you think restic uses too much memory or a too large cache directory, then
please include the output of `restic stats --mode debug`.
Development Environment
=======================
@@ -78,10 +91,40 @@ Then use the `go` tool to build restic:
$ ./restic version
restic 0.14.0-dev (compiled manually) compiled with go1.19 on linux/amd64
To create a debug build use:
$ go build -tags debug ./cmd/restic
You can run all tests with the following command:
$ go test ./...
Performance and Memory Usage Issues
===================================
Debug builds of restic support the `--block-profile`, `--cpu-profile`,
`--mem-profile`, and `--trace-profile` options which collect performance data
that later on can be analyzed using the go tools:
$ restic --cpu-profile . [...]
$ go tool pprof -http localhost:12345 cpu.pprof
To analyze a trace profile use `go tool trace -http=localhost:12345 trace.out`.
As the memory usage of restic changes over time, it may be useful to capture a
snapshot of the current heap. This is possible using then `--listen-profile`
option. Then while restic runs you can query and afterwards analyze the heap statistics.
$ restic --listen-profile localhost:12345 [...]
$ curl http://localhost:12345/debug/pprof/heap -o heap.pprof
$ go tool pprof -http localhost:12345 heap.pprof
Further useful tools are setting the environment variable `GODEBUG=gctrace=1`,
which provides information about garbage collector runs. For a graphical variant
combine this with gcvis.
Providing Patches
=================

View File

@@ -95,7 +95,7 @@ release. Instructions on how to do that are contained in the
News
----
You can follow the restic project on Twitter [@resticbackup](https://twitter.com/resticbackup) or by subscribing to
You can follow the restic project on Mastodon [@resticbackup](https://fosstodon.org/@restic) or by subscribing to
the [project blog](https://restic.net/blog/).
License

View File

@@ -1 +1 @@
0.15.2
0.16.5

View File

@@ -380,6 +380,12 @@ func main() {
}
}
solarisMinVersion := GoVersion{Major: 1, Minor: 20, Patch: 0}
if env["GOARCH"] == "solaris" && !goVersion.AtLeast(solarisMinVersion) {
fmt.Fprintf(os.Stderr, "Detected version %s is too old, restic requires at least %s for Solaris\n", goVersion, solarisMinVersion)
os.Exit(1)
}
verbosePrintf("detected Go version %v\n", goVersion)
preserveSymbols := false

View File

@@ -3,7 +3,7 @@ Enhancement: Allow limiting IO concurrency for local and SFTP backend
Restic did not support limiting the IO concurrency / number of connections for
accessing repositories stored using the local or SFTP backends. The number of
connections is now limited as for other backends, and can be configured via the
the `-o local.connections=2` and `-o sftp.connections=5` options. This ensures
that restic does not overwhelm the backend with concurrent IO operations.
`-o local.connections=2` and `-o sftp.connections=5` options. This ensures that
restic does not overwhelm the backend with concurrent IO operations.
https://github.com/restic/restic/pull/3475

View File

@@ -0,0 +1,7 @@
Enhancement: Sort snapshots by timestamp in `restic find`
The `find` command used to print snapshots in an arbitrary order. Restic now
prints snapshots sorted by timestamp.
https://github.com/restic/restic/issues/1495
https://github.com/restic/restic/pull/4409

View File

@@ -0,0 +1,21 @@
Enhancement: Add `repair index` and `repair snapshots` commands
The `rebuild-index` command has been renamed to `repair index`. The old name
will still work, but is deprecated.
When a snapshot was damaged, the only option up to now was to completely forget
the snapshot, even if only some unimportant files in it were damaged and other
files were still fine.
Restic now has a `repair snapshots` command, which can salvage any non-damaged
files and parts of files in the snapshots by removing damaged directories and
missing file contents. Please note that the damaged data may still be lost
and see the "Troubleshooting" section in the documentation for more details.
https://github.com/restic/restic/issues/1759
https://github.com/restic/restic/issues/1714
https://github.com/restic/restic/issues/1798
https://github.com/restic/restic/issues/2334
https://github.com/restic/restic/pull/2876
https://forum.restic.net/t/corrupted-repo-how-to-repair/799
https://forum.restic.net/t/recovery-options-for-damaged-repositories/1571

View File

@@ -0,0 +1,8 @@
Enhancement: Allow certificate paths to be passed through environment variables
Restic will now read paths to certificates from the environment variables
`RESTIC_CACERT` or `RESTIC_TLS_CLIENT_CERT` if `--cacert` or `--tls-client-cert`
are not specified.
https://github.com/restic/restic/issues/1926
https://github.com/restic/restic/pull/4384

View File

@@ -0,0 +1,11 @@
Enhancement: Provide multi-platform Docker images
The official Docker images are now built for the architectures linux/386,
linux/amd64, linux/arm and linux/arm64.
As an alternative to the Docker Hub, the Docker images are also
available on ghcr.io, the GitHub Container Registry.
https://github.com/restic/restic/issues/2359
https://github.com/restic/restic/issues/4269
https://github.com/restic/restic/pull/4364

View File

@@ -0,0 +1,10 @@
Enhancement: Add support for non-global Azure clouds
The `azure` backend previously only supported storages using the global domain
`core.windows.net`. This meant that backups to other domains such as Azure
China (`core.chinacloudapi.cn`) or Azure Germany (`core.cloudapi.de`) were
not supported. Restic now allows overriding the global domain using the
environment variable `AZURE_ENDPOINT_SUFFIX`.
https://github.com/restic/restic/issues/2468
https://github.com/restic/restic/pull/4387

View File

@@ -0,0 +1,10 @@
Bugfix: Support "unlimited" in `forget --keep-*` options
Restic would previously forget snapshots that should have been kept when a
negative value was passed to the `--keep-*` options. Negative values are now
forbidden. To keep all snapshots, the special value `unlimited` is now
supported. For example, `--keep-monthly unlimited` will keep all monthly
snapshots.
https://github.com/restic/restic/issues/2565
https://github.com/restic/restic/pull/4234

View File

@@ -0,0 +1,12 @@
Bugfix: Support non-UTF8 paths as symlink target
Earlier restic versions did not correctly `backup` and `restore` symlinks that
contain a non-UTF8 target. Note that this only affected systems that still use
a non-Unicode encoding for filesystem paths.
The repository format is now extended to add support for such symlinks. Please
note that snapshots must have been created with at least restic version 0.16.0
for `restore` to correctly handle non-UTF8 symlink targets when restoring them.
https://github.com/restic/restic/issues/3311
https://github.com/restic/restic/pull/3802

View File

@@ -0,0 +1,9 @@
Enhancement: Reduce memory usage by up to 25%
The in-memory index has been optimized to be more garbage collection friendly.
Restic now defaults to `GOGC=50` to run the Go garbage collector more
frequently.
https://github.com/restic/restic/issues/3328
https://github.com/restic/restic/pull/4352
https://github.com/restic/restic/pull/4353

View File

@@ -0,0 +1,11 @@
Enhancement: Improve accuracy of ETA displayed during backup
Restic's `backup` command displayed an ETA that did not adapt when the rate of
progress made during the backup changed during the course of the backup.
Restic now uses recent progress when computing the ETA. It is important to
realize that the estimate may still be wrong, because restic cannot predict
the future, but the hope is that the ETA will be more accurate in most cases.
https://github.com/restic/restic/issues/3397
https://github.com/restic/restic/pull/3563

View File

@@ -0,0 +1,9 @@
Enhancement: Keep oldest snapshot when there are not enough snapshots
The `forget` command now additionally preserves the oldest snapshot if fewer
snapshots than allowed by the `--keep-*` parameters would otherwise be kept.
This maximizes the amount of history kept within the specified limits.
https://github.com/restic/restic/issues/3624
https://github.com/restic/restic/pull/4366
https://forum.restic.net/t/keeping-yearly-snapshots-policy-when-backup-began-during-the-year/4670/2

View File

@@ -0,0 +1,8 @@
Enhancement: Add support for Managed / Workload Identity to `azure` backend
Restic now additionally supports authenticating to Azure using Workload
Identity or Managed Identity credentials, which are automatically injected in
several environments such as a managed Kubernetes cluster.
https://github.com/restic/restic/issues/3698
https://github.com/restic/restic/pull/4029

View File

@@ -0,0 +1,22 @@
Enhancement: Support `<snapshot>:<subfolder>` syntax to select subfolders
Commands like `diff` or `restore` always worked with the full snapshot. This
did not allow comparing only a specific subfolder or only restoring that folder
(`restore --include subfolder` filters the restored files, but still creates the
directories included in `subfolder`).
The commands `diff`, `dump`, `ls` and `restore` now support the
`<snapshot>:<subfolder>` syntax, where `snapshot` is the ID of a snapshot (or
the string `latest`) and `subfolder` is a path within the snapshot. The
commands will then only work with the specified path of the snapshot. The
`subfolder` must be a path to a folder as returned by `ls`. Two examples:
`restic restore -t target latest:/some/path`
`restic diff 12345678:/some/path 90abcef:/some/path`
For debugging purposes, the `cat` command now supports `cat tree
<snapshot>:<subfolder>` to return the directory metadata for the given
subfolder.
https://github.com/restic/restic/issues/3871
https://github.com/restic/restic/pull/4334

View File

@@ -0,0 +1,17 @@
Enhancement: Support `--group-by` for backup parent selection
Previously, the `backup` command by default selected the parent snapshot based
on the hostname and the backup targets. When the backup path list changed, the
`backup` command was unable to determine a suitable parent snapshot and had to
read all files again.
The new `--group-by` option for the `backup` command allows filtering snapshots
for the parent selection by `host`, `paths` and `tags`. It defaults to
`host,paths` which selects the latest snapshot with hostname and paths matching
those of the backup run. This matches the behavior of prior restic versions.
The new `--group-by` option should be set to the same value as passed to
`forget --group-by`.
https://github.com/restic/restic/issues/3941
https://github.com/restic/restic/pull/4081

View File

@@ -0,0 +1,9 @@
Enhancement: Cancel current command if cache becomes unusable
If the cache directory was removed or ran out of space while restic was
running, this would previously cause further caching attempts to fail and
thereby drastically slow down the command execution. Now, the currently running
command is instead canceled.
https://github.com/restic/restic/issues/4130
https://github.com/restic/restic/pull/4166

View File

@@ -0,0 +1,12 @@
Enhancement: Add `--human-readable` option to `ls` and `find` commands
Previously, when using the `-l` option with the `ls` and `find` commands, the
displayed size was always in bytes, without an option for a more human readable
format such as MiB or GiB.
The new `--human-readable` option will convert longer size values into more
human friendly values with an appropriate suffix depending on the output size.
For example, a size of `14680064` will be shown as `14.000 MiB`.
https://github.com/restic/restic/issues/4159
https://github.com/restic/restic/pull/4351

View File

@@ -0,0 +1,8 @@
Enhancement: Include restic version in snapshot metadata
The restic version used to backup a snapshot is now included in its metadata
and shown when inspecting a snapshot using `restic cat snapshot <snapshotID>`
or `restic snapshots --json`.
https://github.com/restic/restic/issues/4188
https://github.com/restic/restic/pull/4378

View File

@@ -0,0 +1,9 @@
Bugfix: Avoid lock refresh issues on slow network connections
On network connections with a low upload speed, backups and other operations
could fail with the error message `Fatal: failed to refresh lock in time`.
This has now been fixed by reworking the lock refresh handling.
https://github.com/restic/restic/issues/4199
https://github.com/restic/restic/pull/4304

View File

@@ -0,0 +1,14 @@
Enhancement: Show progress bar during restore
The `restore` command now shows a progress report while restoring files.
Example: `[0:42] 5.76% 23 files 12.98 MiB, total 3456 files 23.54 GiB`
JSON output is now also supported.
https://github.com/restic/restic/issues/426
https://github.com/restic/restic/issues/3413
https://github.com/restic/restic/issues/3627
https://github.com/restic/restic/pull/3991
https://github.com/restic/restic/pull/4314
https://forum.restic.net/t/progress-bar-for-restore/5210

View File

@@ -0,0 +1,11 @@
Bugfix: Improve lock refresh handling after standby
If the restic process was stopped or the host running restic entered standby
during a long running operation such as a backup, this previously resulted in
the operation failing with `Fatal: failed to refresh lock in time`.
This has now been fixed such that restic first checks whether it is safe to
continue the current operation and only throws an error if not.
https://github.com/restic/restic/issues/4274
https://github.com/restic/restic/pull/4374

View File

@@ -0,0 +1,8 @@
Enhancement: Add support for extended attributes on symlinks
Restic now supports extended attributes on symlinks when backing up,
restoring, or FUSE-mounting snapshots. This includes, for example, the
`security.selinux` xattr on Linux distributions that use SELinux.
https://github.com/restic/restic/issues/4375
https://github.com/restic/restic/pull/4379

View File

@@ -0,0 +1,8 @@
Enhancement: Add `--retry-lock` option
This option allows specifying a duration for which restic will wait if the
repository is already locked.
https://github.com/restic/restic/issues/719
https://github.com/restic/restic/pull/2214
https://github.com/restic/restic/pull/4107

View File

@@ -0,0 +1,8 @@
Enhancement: Reduce file fragmentation for local backend
Before this change, local backend files could become fragmented.
Now restic will try to preallocate space for pack files to avoid
their fragmentation.
https://github.com/restic/restic/issues/2679
https://github.com/restic/restic/pull/3261

View File

@@ -0,0 +1,7 @@
Change: Fix JSON message type of `scan_finished` for the `backup` command
Restic incorrectly set the `message_type` of the `scan_finished` message to
`status` instead of `verbose_status`. This has now been corrected so that
the messages report the correct type.
https://github.com/restic/restic/pull/4176

View File

@@ -0,0 +1,7 @@
Change: Require Go 1.20 for Solaris builds
Building restic on Solaris now requires Go 1.20, as the library used to access
Azure uses the mmap syscall, which is only available on Solaris starting from
Go 1.20. All other platforms however continue to build with Go 1.18.
https://github.com/restic/restic/pull/4201

View File

@@ -0,0 +1,6 @@
Enhancement: Add `jq` binary to Docker image
The Docker image now contains `jq`, which can be useful to process JSON data
output by restic.
https://github.com/restic/restic/pull/4220

View File

@@ -0,0 +1,7 @@
Enhancement: Allow specifying region of new buckets in the `gs` backend
Previously, buckets used by the Google Cloud Storage backend would always get
created in the "us" region. It is now possible to specify the region where a
bucket should be created by using the `-o gs.region=us` option.
https://github.com/restic/restic/pull/4226

View File

@@ -0,0 +1,8 @@
Bugfix: Correctly clean up status bar output of the `backup` command
Due to a regression in restic 0.15.2, the status bar of the `backup` command
could leave some output behind. This happened if filenames were printed that
are wider than the current terminal width. This has now been fixed.
https://github.com/restic/restic/issues/4319
https://github.com/restic/restic/pull/4318

View File

@@ -0,0 +1,3 @@
Bugfix: `generate` and `init` no longer silently ignore unexpected arguments
https://github.com/restic/restic/pull/4333

View File

@@ -0,0 +1,8 @@
Bugfix: Ignore missing folders in `rest` backend
If a repository accessed via the REST backend was missing folders, then restic
would fail with an error while trying to list the data in the repository. This
has been now fixed.
https://github.com/restic/restic/pull/4400
https://github.com/restic/rest-server/issues/235

View File

@@ -0,0 +1,9 @@
Enhancement: Automatically set `GOMAXPROCS` in resource-constrained containers
When running restic in a Linux container with CPU-usage limits, restic now
automatically adjusts `GOMAXPROCS`. This helps to reduce the memory consumption
on hosts with many CPU cores.
https://github.com/restic/restic/issues/4128
https://github.com/restic/restic/pull/4485
https://github.com/restic/restic/pull/4531

View File

@@ -0,0 +1,8 @@
Bugfix: Make `key list` command honor `--no-lock`
The `key list` command now supports the `--no-lock` options. This allows
determining which keys a repo can be accessed by without the need for having
write access (e.g., read-only sftp access, filesystem snapshot).
https://github.com/restic/restic/issues/4513
https://github.com/restic/restic/pull/4514

View File

@@ -0,0 +1,8 @@
Bugfix: Do not try to load password on command line autocomplete
The command line autocompletion previously tried to load the repository
password. This could cause the autocompletion not to work. Now, this step gets
skipped.
https://github.com/restic/restic/issues/4516
https://github.com/restic/restic/pull/4526

View File

@@ -0,0 +1,22 @@
Bugfix: Update zstd library to fix possible data corruption at max. compression
In restic 0.16.0, backups where the compression level was set to `max` (using
`--compression max`) could in rare and very specific circumstances result in
data corruption due to a bug in the library used for compressing data.
Restic now uses the latest version of the library used to compress data, which
includes a fix for this issue. Please note that the `auto` compression level
(which restic uses by default) was never affected, and even if you used `max`
compression, chances of being affected by this issue were very small.
To check a repository for any corruption, run `restic check --read-data`. This
will download and verify the whole repository and can be used at any time to
completely verify the integrity of a repository. If the `check` command detects
anomalies, follow the suggested steps.
To simplify any needed repository repair and minimize data loss, there is also
a new and experimental `repair packs` command that salvages all valid data from
the affected pack files (see `restic help repair packs` for more information).
https://github.com/restic/restic/issues/4523
https://github.com/restic/restic/pull/4530

View File

@@ -0,0 +1,7 @@
Enhancement: Show progress bar while loading the index
Restic did not provide any feedback while loading index files. Now, there is a
progress bar that shows the index loading progress.
https://github.com/restic/restic/issues/229
https://github.com/restic/restic/pull/4419

View File

@@ -0,0 +1,11 @@
Enhancement: Allow setting REST password and username via environment variables
Previously, it was only possible to specify the REST-server username and
password in the repository URL, or by using the `--repository-file` option.
This meant it was not possible to use authentication in contexts where the
repository URL is stored in publicly accessible way.
Restic now allows setting the username and password using the
`RESTIC_REST_USERNAME` and `RESTIC_REST_PASSWORD` variables.
https://github.com/restic/restic/pull/4480

View File

@@ -0,0 +1,7 @@
Enhancement: Include inode numbers in JSON output for `find` and `ls` commands
Restic used to omit the inode numbers in the JSON messages emitted for nodes by
the `ls` command as well as for matches by the `find` command. It now includes
those values whenever they are available.
https://github.com/restic/restic/pull/4511

View File

@@ -0,0 +1,12 @@
Enhancement: Add config option to set SFTP command arguments
When using the `sftp` backend, scenarios where a custom identity file was
needed for the SSH connection, required the full command to be specified:
`-o sftp.command='ssh user@host:port -i /ssh/my_private_key -s sftp'`
Now, the `-o sftp.args=...` option can be passed to restic to specify
custom arguments for the SSH command executed by the SFTP backend.
This simplifies the above example to `-o sftp.args='-i /ssh/my_private_key'`.
https://github.com/restic/restic/pull/4519
https://github.com/restic/restic/issues/4241

View File

@@ -0,0 +1,8 @@
Change: Update dependencies and require Go 1.19 or newer
We have updated all dependencies. Since some libraries require newer Go
standard library features, support for Go 1.18 has been dropped, which means
that restic now requires at least Go 1.19 to build.
https://github.com/restic/restic/pull/4532
https://github.com/restic/restic/pull/4533

View File

@@ -0,0 +1,9 @@
Bugfix: Restore ARMv5 support for ARM binaries
The official release binaries for restic 0.16.1 were accidentally built to
require ARMv7. The build process is now updated to restore support for ARMv5.
Please note that restic 0.17.0 will drop support for ARMv5 and require at least
ARMv6.
https://github.com/restic/restic/issues/4540

View File

@@ -0,0 +1,8 @@
Bugfix: Repair documentation build on Read the Docs
For restic 0.16.1, no documentation was available at
https://restic.readthedocs.io/ .
The documentation build process is now updated to work again.
https://github.com/restic/restic/pull/4545

View File

@@ -0,0 +1,14 @@
Bugfix: Improve errors for irregular files on Windows
Since Go 1.21, most filesystem reparse points on Windows are considered to be
irregular files. This caused restic to show an `error: invalid node type ""`
error message for those files.
This error message has now been improved and includes the relevant file path:
`error: nodeFromFileInfo path/to/file: unsupported file type "irregular"`.
As irregular files are not required to behave like regular files, it is not
possible to provide a generic way to back up those files.
https://github.com/restic/restic/issues/4560
https://github.com/restic/restic/pull/4620
https://forum.restic.net/t/windows-backup-error-invalid-node-type/6875

View File

@@ -0,0 +1,11 @@
Bugfix: Support backup of deduplicated files on Windows again
With the official release builds of restic 0.16.1 and 0.16.2, it was not
possible to back up files that were deduplicated by the corresponding
Windows Server feature. This also applied to restic versions built using
Go 1.21.0-1.21.4.
The Go version used to build restic has now been updated to fix this.
https://github.com/restic/restic/issues/4574
https://github.com/restic/restic/pull/4621

View File

@@ -0,0 +1,11 @@
Bugfix: Improve error handling for `rclone` backend
Since restic 0.16.0, if rclone encountered an error while listing files,
this could in rare circumstances cause restic to assume that there are no
files. Although unlikely, this situation could result in data loss if it
were to happen right when the `prune` command is listing existing snapshots.
Error handling has now been improved to detect and work around this case.
https://github.com/restic/restic/issues/4612
https://github.com/restic/restic/pull/4618

View File

@@ -0,0 +1,11 @@
Bugfix: Correct `restore` progress information if an error occurs
If an error occurred while restoring a snapshot, this could cause the `restore`
progress bar to show incorrect information. In addition, if a data file could
not be loaded completely, then errors would also be reported for some already
restored files.
Error reporting of the `restore` command has now been made more accurate.
https://github.com/restic/restic/pull/4624
https://forum.restic.net/t/errors-restoring-with-restic-on-windows-server-s3/6943

View File

@@ -0,0 +1,11 @@
Bugfix: Improve reliability of restoring large files
In some cases restic failed to restore large files that frequently contain the
same file chunk. In combination with certain backends, this could result in
network connection timeouts that caused incomplete restores.
Restic now includes special handling for such file chunks to ensure reliable
restores.
https://github.com/restic/restic/pull/4626
https://forum.restic.net/t/errors-restoring-with-restic-on-windows-server-s3/6943

View File

@@ -0,0 +1,18 @@
Enhancement: Add extra verification of data integrity before upload
Hardware issues, or a bug in restic or its dependencies, could previously cause
corruption in the files restic created and stored in the repository. Detecting
such corruption previously required explicitly running the `check --read-data`
or `check --read-data-subset` commands.
To further ensure data integrity, even in the case of hardware issues or
software bugs, restic now performs additional verification of the files about
to be uploaded to the repository.
These extra checks will increase CPU usage during backups. They can therefore,
if absolutely necessary, be disabled using the `--no-extra-verify` global
option. Please note that this should be combined with more active checking
using the previously mentioned check commands.
https://github.com/restic/restic/issues/4529
https://github.com/restic/restic/pull/4681

View File

@@ -0,0 +1,19 @@
Bugfix: Downgrade zstd library to fix rare data corruption at max. compression
In restic 0.16.3, backups where the compression level was set to `max` (using
`--compression max`) could in rare and very specific circumstances result in
data corruption due to a bug in the library used for compressing data. Restic
0.16.1 and 0.16.2 were not affected.
Restic now uses the previous version of the library used to compress data, the
same version used by restic 0.16.2. Please note that the `auto` compression
level (which restic uses by default) was never affected, and even if you used
`max` compression, chances of being affected by this issue are small.
To check a repository for any corruption, run `restic check --read-data`. This
will download and verify the whole repository and can be used at any time to
completely verify the integrity of a repository. If the `check` command detects
anomalies, follow the suggested steps.
https://github.com/restic/restic/issues/4677
https://github.com/restic/restic/pull/4679

View File

@@ -0,0 +1,6 @@
Enhancement: Update dependencies
A few potentially vulnerable dependencies were updated.
https://github.com/restic/restic/issues/4873
https://github.com/restic/restic/pull/4878

View File

@@ -0,0 +1,5 @@
Enhancement: Add option to force use of Azure CLI credential
A new environment variable `AZURE_FORCE_CLI_CREDENTIAL=true` allows forcing the use of Azure CLI credential, ignoring other credentials like managed identity.
https://github.com/restic/restic/pull/4799

View File

@@ -1,18 +1,21 @@
{{- range $changes := . }}{{ with $changes -}}
Changelog for restic {{ .Version }} ({{ .Date }})
=======================================
# Table of Contents
{{ range . -}}
* [Changelog for {{ .Version }}](#changelog-for-restic-{{ .Version | replace "." ""}}-{{ .Date | lower -}})
{{ end -}}
{{- range $changes := . }}{{ with $changes }}
# Changelog for restic {{ .Version }} ({{ .Date }})
The following sections list the changes in restic {{ .Version }} relevant to
restic users. The changes are ordered by importance.
Summary
-------
## Summary
{{ range $entry := .Entries }}{{ with $entry }}
* {{ .TypeShort }} #{{ .PrimaryID }}: {{ .Title }}
{{- end }}{{ end }}
Details
-------
## Details
{{ range $entry := .Entries }}{{ with $entry }}
* {{ .Type }} #{{ .PrimaryID }}: {{ .Title }}
{{ range $par := .Paragraphs }}
@@ -27,6 +30,5 @@ Details
{{ range $url := .OtherURLs }}
{{ $url -}}
{{ end }}
{{ end }}{{ end }}
{{ end }}{{ end -}}
{{ end }}{{ end -}}

View File

@@ -1,16 +1,17 @@
# The first line must start with Bugfix:, Enhancement: or Change:,
# including the colon. Use present tense. Remove lines starting with '#'
# from this template.
# including the colon. Use present tense and the imperative mood. Remove
# lines starting with '#' from this template.
Enhancement: Allow custom bar in the foo command
# Describe the problem in the past tense, the new behavior in the present
# tense. Mention the affected commands, backends, operating systems, etc.
# Focus on user-facing behavior, not the implementation.
# Use "Restic now ..." instead of "We have changed ...".
Restic foo always used the system-wide bar when deciding how to frob an
item in the baz backend. It now permits selecting the bar with --bar or
the environment variable RESTIC_BAR. The system-wide bar is still the
default.
item in the `baz` backend. It now permits selecting the bar with `--bar`
or the environment variable `RESTIC_BAR`. The system-wide bar is still
the default.
# The last section is a list of issue, PR and forum URLs.
# The first issue ID determines the filename for the changelog entry:

View File

@@ -62,6 +62,12 @@ func CleanupHandler(c <-chan os.Signal) {
debug.Log("signal %v received, cleaning up", s)
Warnf("%ssignal %v received, cleaning up\n", clearLine(0), s)
if val, _ := os.LookupEnv("RESTIC_DEBUG_STACKTRACE_SIGINT"); val != "" {
_, _ = os.Stderr.WriteString("\n--- STACKTRACE START ---\n\n")
_, _ = os.Stderr.WriteString(debug.DumpStacktrace())
_, _ = os.Stderr.WriteString("\n--- STACKTRACE END ---\n")
}
code := 0
if s == syscall.SIGINT {
@@ -78,5 +84,6 @@ func CleanupHandler(c <-chan os.Signal) {
// given exit code.
func Exit(code int) {
code = RunCleanupHandlers(code)
debug.Log("exiting with status code %d", code)
os.Exit(code)
}

View File

@@ -89,6 +89,7 @@ type BackupOptions struct {
excludePatternOptions
Parent string
GroupBy restic.SnapshotGroupByOptions
Force bool
ExcludeOtherFS bool
ExcludeIfPresent []string
@@ -120,7 +121,9 @@ func init() {
cmdRoot.AddCommand(cmdBackup)
f := cmdBackup.Flags()
f.StringVar(&backupOptions.Parent, "parent", "", "use this parent `snapshot` (default: last snapshot in the repository that has the same target files/directories, and is not newer than the snapshot time)")
f.StringVar(&backupOptions.Parent, "parent", "", "use this parent `snapshot` (default: latest snapshot in the group determined by --group-by and not newer than the timestamp determined by --time)")
backupOptions.GroupBy = restic.SnapshotGroupByOptions{Host: true, Path: true}
f.VarP(&backupOptions.GroupBy, "group-by", "g", "`group` snapshots by host, paths and/or tags, separated by comma (disable grouping with '')")
f.BoolVarP(&backupOptions.Force, "force", "f", false, `force re-reading the target files/directories (overrides the "parent" flag)`)
initExcludePatternOptions(f, &backupOptions.excludePatternOptions)
@@ -305,7 +308,7 @@ func (opts BackupOptions) Check(gopts GlobalOptions, args []string) error {
// collectRejectByNameFuncs returns a list of all functions which may reject data
// from being saved in a snapshot based on path only
func collectRejectByNameFuncs(opts BackupOptions, repo *repository.Repository, targets []string) (fs []RejectByNameFunc, err error) {
func collectRejectByNameFuncs(opts BackupOptions, repo *repository.Repository) (fs []RejectByNameFunc, err error) {
// exclude restic cache
if repo.Cache != nil {
f, err := rejectResticCache(repo)
@@ -340,7 +343,7 @@ func collectRejectByNameFuncs(opts BackupOptions, repo *repository.Repository, t
// collectRejectFuncs returns a list of all functions which may reject data
// from being saved in a snapshot based on path and file info
func collectRejectFuncs(opts BackupOptions, repo *repository.Repository, targets []string) (fs []RejectFunc, err error) {
func collectRejectFuncs(opts BackupOptions, targets []string) (fs []RejectFunc, err error) {
// allowed devices
if opts.ExcludeOtherFS && !opts.Stdin {
f, err := rejectByDevice(targets)
@@ -439,13 +442,18 @@ func findParentSnapshot(ctx context.Context, repo restic.Repository, opts Backup
if snName == "" {
snName = "latest"
}
f := restic.SnapshotFilter{
Hosts: []string{opts.Host},
Paths: targets,
TimestampLimit: timeStampLimit,
f := restic.SnapshotFilter{TimestampLimit: timeStampLimit}
if opts.GroupBy.Host {
f.Hosts = []string{opts.Host}
}
if opts.GroupBy.Path {
f.Paths = targets
}
if opts.GroupBy.Tag {
f.Tags = []restic.TagList{opts.Tags.Flatten()}
}
sn, err := f.FindLatest(ctx, repo.Backend(), repo, snName)
sn, _, err := f.FindLatest(ctx, repo.Backend(), repo, snName)
// Snapshot not found is ok if no explicit parent was set
if opts.Parent == "" && errors.Is(err, restic.ErrNoSnapshotFound) {
err = nil
@@ -498,20 +506,23 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
if !gopts.JSON {
progressPrinter.V("lock repository")
}
lock, ctx, err := lockRepo(ctx, repo)
defer unlockRepo(lock)
if err != nil {
return err
if !opts.DryRun {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
// rejectByNameFuncs collect functions that can reject items from the backup based on path only
rejectByNameFuncs, err := collectRejectByNameFuncs(opts, repo, targets)
rejectByNameFuncs, err := collectRejectByNameFuncs(opts, repo)
if err != nil {
return err
}
// rejectFuncs collect functions that can reject items from the backup based on path and file info
rejectFuncs, err := collectRejectFuncs(opts, repo, targets)
rejectFuncs, err := collectRejectFuncs(opts, targets)
if err != nil {
return err
}
@@ -535,7 +546,10 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
if !gopts.JSON {
progressPrinter.V("load index files")
}
err = repo.LoadIndex(ctx)
bar := newIndexTerminalProgress(gopts.Quiet, gopts.JSON, term)
err = repo.LoadIndex(ctx, bar)
if err != nil {
return err
}
@@ -637,6 +651,7 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
Time: timeStamp,
Hostname: opts.Host,
ParentSnapshot: parentSnapshot,
ProgramVersion: "restic " + version,
}
if !gopts.JSON {

View File

@@ -0,0 +1,569 @@
package main
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
"github.com/restic/restic/internal/ui/termstatus"
)
func testRunBackupAssumeFailure(t testing.TB, dir string, target []string, opts BackupOptions, gopts GlobalOptions) error {
return withTermStatus(gopts, func(ctx context.Context, term *termstatus.Terminal) error {
t.Logf("backing up %v in %v", target, dir)
if dir != "" {
cleanup := rtest.Chdir(t, dir)
defer cleanup()
}
opts.GroupBy = restic.SnapshotGroupByOptions{Host: true, Path: true}
return runBackup(ctx, opts, gopts, term, target)
})
}
func testRunBackup(t testing.TB, dir string, target []string, opts BackupOptions, gopts GlobalOptions) {
err := testRunBackupAssumeFailure(t, dir, target, opts, gopts)
rtest.Assert(t, err == nil, "Error while backing up")
}
func TestBackup(t *testing.T) {
testBackup(t, false)
}
func TestBackupWithFilesystemSnapshots(t *testing.T) {
if runtime.GOOS == "windows" && fs.HasSufficientPrivilegesForVSS() == nil {
testBackup(t, true)
}
}
func testBackup(t *testing.T, useFsSnapshot bool) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
opts := BackupOptions{UseFsSnapshot: useFsSnapshot}
// first backup
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
testListSnapshots(t, env.gopts, 1)
testRunCheck(t, env.gopts)
stat1 := dirStats(env.repo)
// second backup, implicit incremental
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
snapshotIDs := testListSnapshots(t, env.gopts, 2)
stat2 := dirStats(env.repo)
if stat2.size > stat1.size+stat1.size/10 {
t.Error("repository size has grown by more than 10 percent")
}
t.Logf("repository grown by %d bytes", stat2.size-stat1.size)
testRunCheck(t, env.gopts)
// third backup, explicit incremental
opts.Parent = snapshotIDs[0].String()
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
snapshotIDs = testListSnapshots(t, env.gopts, 3)
stat3 := dirStats(env.repo)
if stat3.size > stat1.size+stat1.size/10 {
t.Error("repository size has grown by more than 10 percent")
}
t.Logf("repository grown by %d bytes", stat3.size-stat2.size)
// restore all backups and compare
for i, snapshotID := range snapshotIDs {
restoredir := filepath.Join(env.base, fmt.Sprintf("restore%d", i))
t.Logf("restoring snapshot %v to %v", snapshotID.Str(), restoredir)
testRunRestore(t, env.gopts, restoredir, snapshotID)
diff := directoriesContentsDiff(env.testdata, filepath.Join(restoredir, "testdata"))
rtest.Assert(t, diff == "", "directories are not equal: %v", diff)
}
testRunCheck(t, env.gopts)
}
func TestBackupWithRelativePath(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
opts := BackupOptions{}
// first backup
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
firstSnapshotID := testListSnapshots(t, env.gopts, 1)[0]
// second backup, implicit incremental
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
// that the correct parent snapshot was used
latestSn, _ := testRunSnapshots(t, env.gopts)
rtest.Assert(t, latestSn != nil, "missing latest snapshot")
rtest.Assert(t, latestSn.Parent != nil && latestSn.Parent.Equal(firstSnapshotID), "second snapshot selected unexpected parent %v instead of %v", latestSn.Parent, firstSnapshotID)
}
func TestBackupParentSelection(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
opts := BackupOptions{}
// first backup
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata/0/0"}, opts, env.gopts)
firstSnapshotID := testListSnapshots(t, env.gopts, 1)[0]
// second backup, sibling path
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata/0/tests"}, opts, env.gopts)
testListSnapshots(t, env.gopts, 2)
// third backup, incremental for the first backup
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata/0/0"}, opts, env.gopts)
// test that the correct parent snapshot was used
latestSn, _ := testRunSnapshots(t, env.gopts)
rtest.Assert(t, latestSn != nil, "missing latest snapshot")
rtest.Assert(t, latestSn.Parent != nil && latestSn.Parent.Equal(firstSnapshotID), "third snapshot selected unexpected parent %v instead of %v", latestSn.Parent, firstSnapshotID)
}
func TestDryRunBackup(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
opts := BackupOptions{}
dryOpts := BackupOptions{DryRun: true}
// dry run before first backup
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, dryOpts, env.gopts)
snapshotIDs := testListSnapshots(t, env.gopts, 0)
packIDs := testRunList(t, "packs", env.gopts)
rtest.Assert(t, len(packIDs) == 0,
"expected no data, got %v", snapshotIDs)
indexIDs := testRunList(t, "index", env.gopts)
rtest.Assert(t, len(indexIDs) == 0,
"expected no index, got %v", snapshotIDs)
// first backup
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
snapshotIDs = testListSnapshots(t, env.gopts, 1)
packIDs = testRunList(t, "packs", env.gopts)
indexIDs = testRunList(t, "index", env.gopts)
// dry run between backups
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, dryOpts, env.gopts)
snapshotIDsAfter := testListSnapshots(t, env.gopts, 1)
rtest.Equals(t, snapshotIDs, snapshotIDsAfter)
dataIDsAfter := testRunList(t, "packs", env.gopts)
rtest.Equals(t, packIDs, dataIDsAfter)
indexIDsAfter := testRunList(t, "index", env.gopts)
rtest.Equals(t, indexIDs, indexIDsAfter)
// second backup, implicit incremental
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
snapshotIDs = testListSnapshots(t, env.gopts, 2)
packIDs = testRunList(t, "packs", env.gopts)
indexIDs = testRunList(t, "index", env.gopts)
// another dry run
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, dryOpts, env.gopts)
snapshotIDsAfter = testListSnapshots(t, env.gopts, 2)
rtest.Equals(t, snapshotIDs, snapshotIDsAfter)
dataIDsAfter = testRunList(t, "packs", env.gopts)
rtest.Equals(t, packIDs, dataIDsAfter)
indexIDsAfter = testRunList(t, "index", env.gopts)
rtest.Equals(t, indexIDs, indexIDsAfter)
}
func TestBackupNonExistingFile(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
_ = withRestoreGlobalOptions(func() error {
globalOptions.stderr = io.Discard
p := filepath.Join(env.testdata, "0", "0", "9")
dirs := []string{
filepath.Join(p, "0"),
filepath.Join(p, "1"),
filepath.Join(p, "nonexisting"),
filepath.Join(p, "5"),
}
opts := BackupOptions{}
testRunBackup(t, "", dirs, opts, env.gopts)
return nil
})
}
func TestBackupSelfHealing(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testRunInit(t, env.gopts)
p := filepath.Join(env.testdata, "test/test")
rtest.OK(t, os.MkdirAll(filepath.Dir(p), 0755))
rtest.OK(t, appendRandomData(p, 5))
opts := BackupOptions{}
testRunBackup(t, filepath.Dir(env.testdata), []string{filepath.Base(env.testdata)}, opts, env.gopts)
testRunCheck(t, env.gopts)
// remove all data packs
removePacksExcept(env.gopts, t, restic.NewIDSet(), false)
testRunRebuildIndex(t, env.gopts)
// now the repo is also missing the data blob in the index; check should report this
testRunCheckMustFail(t, env.gopts)
// second backup should report an error but "heal" this situation
err := testRunBackupAssumeFailure(t, filepath.Dir(env.testdata), []string{filepath.Base(env.testdata)}, opts, env.gopts)
rtest.Assert(t, err != nil,
"backup should have reported an error")
testRunCheck(t, env.gopts)
}
func TestBackupTreeLoadError(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testRunInit(t, env.gopts)
p := filepath.Join(env.testdata, "test/test")
rtest.OK(t, os.MkdirAll(filepath.Dir(p), 0755))
rtest.OK(t, appendRandomData(p, 5))
opts := BackupOptions{}
// Backup a subdirectory first, such that we can remove the tree pack for the subdirectory
testRunBackup(t, env.testdata, []string{"test"}, opts, env.gopts)
r, err := OpenRepository(context.TODO(), env.gopts)
rtest.OK(t, err)
rtest.OK(t, r.LoadIndex(context.TODO(), nil))
treePacks := restic.NewIDSet()
r.Index().Each(context.TODO(), func(pb restic.PackedBlob) {
if pb.Type == restic.TreeBlob {
treePacks.Insert(pb.PackID)
}
})
testRunBackup(t, filepath.Dir(env.testdata), []string{filepath.Base(env.testdata)}, opts, env.gopts)
testRunCheck(t, env.gopts)
// delete the subdirectory pack first
for id := range treePacks {
rtest.OK(t, r.Backend().Remove(context.TODO(), restic.Handle{Type: restic.PackFile, Name: id.String()}))
}
testRunRebuildIndex(t, env.gopts)
// now the repo is missing the tree blob in the index; check should report this
testRunCheckMustFail(t, env.gopts)
// second backup should report an error but "heal" this situation
err = testRunBackupAssumeFailure(t, filepath.Dir(env.testdata), []string{filepath.Base(env.testdata)}, opts, env.gopts)
rtest.Assert(t, err != nil, "backup should have reported an error for the subdirectory")
testRunCheck(t, env.gopts)
// remove all tree packs
removePacksExcept(env.gopts, t, restic.NewIDSet(), true)
testRunRebuildIndex(t, env.gopts)
// now the repo is also missing the data blob in the index; check should report this
testRunCheckMustFail(t, env.gopts)
// second backup should report an error but "heal" this situation
err = testRunBackupAssumeFailure(t, filepath.Dir(env.testdata), []string{filepath.Base(env.testdata)}, opts, env.gopts)
rtest.Assert(t, err != nil, "backup should have reported an error")
testRunCheck(t, env.gopts)
}
var backupExcludeFilenames = []string{
"testfile1",
"foo.tar.gz",
"private/secret/passwords.txt",
"work/source/test.c",
}
func TestBackupExclude(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testRunInit(t, env.gopts)
datadir := filepath.Join(env.base, "testdata")
for _, filename := range backupExcludeFilenames {
fp := filepath.Join(datadir, filename)
rtest.OK(t, os.MkdirAll(filepath.Dir(fp), 0755))
f, err := os.Create(fp)
rtest.OK(t, err)
fmt.Fprint(f, filename)
rtest.OK(t, f.Close())
}
snapshots := make(map[string]struct{})
opts := BackupOptions{}
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
snapshots, snapshotID := lastSnapshot(snapshots, loadSnapshotMap(t, env.gopts))
files := testRunLs(t, env.gopts, snapshotID)
rtest.Assert(t, includes(files, "/testdata/foo.tar.gz"),
"expected file %q in first snapshot, but it's not included", "foo.tar.gz")
opts.Excludes = []string{"*.tar.gz"}
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
snapshots, snapshotID = lastSnapshot(snapshots, loadSnapshotMap(t, env.gopts))
files = testRunLs(t, env.gopts, snapshotID)
rtest.Assert(t, !includes(files, "/testdata/foo.tar.gz"),
"expected file %q not in first snapshot, but it's included", "foo.tar.gz")
opts.Excludes = []string{"*.tar.gz", "private/secret"}
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
_, snapshotID = lastSnapshot(snapshots, loadSnapshotMap(t, env.gopts))
files = testRunLs(t, env.gopts, snapshotID)
rtest.Assert(t, !includes(files, "/testdata/foo.tar.gz"),
"expected file %q not in first snapshot, but it's included", "foo.tar.gz")
rtest.Assert(t, !includes(files, "/testdata/private/secret/passwords.txt"),
"expected file %q not in first snapshot, but it's included", "passwords.txt")
}
func TestBackupErrors(t *testing.T) {
if runtime.GOOS == "windows" {
return
}
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
// Assume failure
inaccessibleFile := filepath.Join(env.testdata, "0", "0", "9", "0")
rtest.OK(t, os.Chmod(inaccessibleFile, 0000))
defer func() {
rtest.OK(t, os.Chmod(inaccessibleFile, 0644))
}()
opts := BackupOptions{}
err := testRunBackupAssumeFailure(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts)
rtest.Assert(t, err != nil, "Assumed failure, but no error occurred.")
rtest.Assert(t, err == ErrInvalidSourceData, "Wrong error returned")
testListSnapshots(t, env.gopts, 1)
}
const (
incrementalFirstWrite = 10 * 1042 * 1024
incrementalSecondWrite = 1 * 1042 * 1024
incrementalThirdWrite = 1 * 1042 * 1024
)
func TestIncrementalBackup(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testRunInit(t, env.gopts)
datadir := filepath.Join(env.base, "testdata")
testfile := filepath.Join(datadir, "testfile")
rtest.OK(t, appendRandomData(testfile, incrementalFirstWrite))
opts := BackupOptions{}
testRunBackup(t, "", []string{datadir}, opts, env.gopts)
testRunCheck(t, env.gopts)
stat1 := dirStats(env.repo)
rtest.OK(t, appendRandomData(testfile, incrementalSecondWrite))
testRunBackup(t, "", []string{datadir}, opts, env.gopts)
testRunCheck(t, env.gopts)
stat2 := dirStats(env.repo)
if stat2.size-stat1.size > incrementalFirstWrite {
t.Errorf("repository size has grown by more than %d bytes", incrementalFirstWrite)
}
t.Logf("repository grown by %d bytes", stat2.size-stat1.size)
rtest.OK(t, appendRandomData(testfile, incrementalThirdWrite))
testRunBackup(t, "", []string{datadir}, opts, env.gopts)
testRunCheck(t, env.gopts)
stat3 := dirStats(env.repo)
if stat3.size-stat2.size > incrementalFirstWrite {
t.Errorf("repository size has grown by more than %d bytes", incrementalFirstWrite)
}
t.Logf("repository grown by %d bytes", stat3.size-stat2.size)
}
func TestBackupTags(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
opts := BackupOptions{}
testRunBackup(t, "", []string{env.testdata}, opts, env.gopts)
testRunCheck(t, env.gopts)
newest, _ := testRunSnapshots(t, env.gopts)
if newest == nil {
t.Fatal("expected a backup, got nil")
}
rtest.Assert(t, len(newest.Tags) == 0,
"expected no tags, got %v", newest.Tags)
parent := newest
opts.Tags = restic.TagLists{[]string{"NL"}}
testRunBackup(t, "", []string{env.testdata}, opts, env.gopts)
testRunCheck(t, env.gopts)
newest, _ = testRunSnapshots(t, env.gopts)
if newest == nil {
t.Fatal("expected a backup, got nil")
}
rtest.Assert(t, len(newest.Tags) == 1 && newest.Tags[0] == "NL",
"expected one NL tag, got %v", newest.Tags)
// Tagged backup should have untagged backup as parent.
rtest.Assert(t, parent.ID.Equal(*newest.Parent),
"expected parent to be %v, got %v", parent.ID, newest.Parent)
}
func TestBackupProgramVersion(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
testRunBackup(t, "", []string{env.testdata}, BackupOptions{}, env.gopts)
newest, _ := testRunSnapshots(t, env.gopts)
if newest == nil {
t.Fatal("expected a backup, got nil")
}
resticVersion := "restic " + version
rtest.Assert(t, newest.ProgramVersion == resticVersion,
"expected %v, got %v", resticVersion, newest.ProgramVersion)
}
func TestQuietBackup(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
opts := BackupOptions{}
env.gopts.Quiet = false
testRunBackup(t, "", []string{env.testdata}, opts, env.gopts)
testListSnapshots(t, env.gopts, 1)
testRunCheck(t, env.gopts)
env.gopts.Quiet = true
testRunBackup(t, "", []string{env.testdata}, opts, env.gopts)
testListSnapshots(t, env.gopts, 2)
testRunCheck(t, env.gopts)
}
func TestHardLink(t *testing.T) {
// this test assumes a test set with a single directory containing hard linked files
env, cleanup := withTestEnvironment(t)
defer cleanup()
datafile := filepath.Join("testdata", "test.hl.tar.gz")
fd, err := os.Open(datafile)
if os.IsNotExist(err) {
t.Skipf("unable to find data file %q, skipping", datafile)
return
}
rtest.OK(t, err)
rtest.OK(t, fd.Close())
testRunInit(t, env.gopts)
rtest.SetupTarTestFixture(t, env.testdata, datafile)
linkTests := createFileSetPerHardlink(env.testdata)
opts := BackupOptions{}
// first backup
testRunBackup(t, filepath.Dir(env.testdata), []string{filepath.Base(env.testdata)}, opts, env.gopts)
snapshotIDs := testListSnapshots(t, env.gopts, 1)
testRunCheck(t, env.gopts)
// restore all backups and compare
for i, snapshotID := range snapshotIDs {
restoredir := filepath.Join(env.base, fmt.Sprintf("restore%d", i))
t.Logf("restoring snapshot %v to %v", snapshotID.Str(), restoredir)
testRunRestore(t, env.gopts, restoredir, snapshotID)
diff := directoriesContentsDiff(env.testdata, filepath.Join(restoredir, "testdata"))
rtest.Assert(t, diff == "", "directories are not equal %v", diff)
linkResults := createFileSetPerHardlink(filepath.Join(restoredir, "testdata"))
rtest.Assert(t, linksEqual(linkTests, linkResults),
"links are not equal")
}
testRunCheck(t, env.gopts)
}
func linksEqual(source, dest map[uint64][]string) bool {
for _, vs := range source {
found := false
for kd, vd := range dest {
if linkEqual(vs, vd) {
delete(dest, kd)
found = true
break
}
}
if !found {
return false
}
}
return len(dest) == 0
}
func linkEqual(source, dest []string) bool {
// equal if sliced are equal without considering order
if source == nil && dest == nil {
return true
}
if source == nil || dest == nil {
return false
}
if len(source) != len(dest) {
return false
}
for i := range source {
found := false
for j := range dest {
if source[i] == dest[j] {
found = true
break
}
}
if !found {
return false
}
}
return true
}

View File

@@ -155,7 +155,7 @@ func runCache(opts CacheOptions, gopts GlobalOptions, args []string) error {
})
}
_ = tab.Write(gopts.stdout)
_ = tab.Write(globalOptions.stdout)
Printf("%d cache dirs in %s\n", len(dirs), cachedir)
return nil

View File

@@ -3,6 +3,7 @@ package main
import (
"context"
"encoding/json"
"strings"
"github.com/spf13/cobra"
@@ -13,7 +14,7 @@ import (
)
var cmdCat = &cobra.Command{
Use: "cat [flags] [pack|blob|snapshot|index|key|masterkey|config|lock] ID",
Use: "cat [flags] [masterkey|config|pack ID|blob ID|snapshot ID|index ID|key ID|lock ID|tree snapshot:subfolder]",
Short: "Print internal objects to stdout",
Long: `
The "cat" command is used to print internal objects to stdout.
@@ -33,9 +34,34 @@ func init() {
cmdRoot.AddCommand(cmdCat)
}
func validateCatArgs(args []string) error {
var allowedCmds = []string{"config", "index", "snapshot", "key", "masterkey", "lock", "pack", "blob", "tree"}
if len(args) < 1 {
return errors.Fatal("type not specified")
}
validType := false
for _, v := range allowedCmds {
if v == args[0] {
validType = true
break
}
}
if !validType {
return errors.Fatalf("invalid type %q, must be one of [%s]", args[0], strings.Join(allowedCmds, "|"))
}
if args[0] != "masterkey" && args[0] != "config" && len(args) != 2 {
return errors.Fatal("ID not specified")
}
return nil
}
func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
if len(args) < 1 || (args[0] != "masterkey" && args[0] != "config" && len(args) != 2) {
return errors.Fatal("type or ID not specified")
if err := validateCatArgs(args); err != nil {
return err
}
repo, err := OpenRepository(ctx, gopts)
@@ -45,7 +71,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo)
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -55,7 +81,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
tpe := args[0]
var id restic.ID
if tpe != "masterkey" && tpe != "config" && tpe != "snapshot" {
if tpe != "masterkey" && tpe != "config" && tpe != "snapshot" && tpe != "tree" {
id, err = restic.ParseID(args[1])
if err != nil {
return errors.Fatalf("unable to parse ID: %v\n", err)
@@ -72,7 +98,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
Println(string(buf))
return nil
case "index":
buf, err := repo.LoadUnpacked(ctx, restic.IndexFile, id, nil)
buf, err := repo.LoadUnpacked(ctx, restic.IndexFile, id)
if err != nil {
return err
}
@@ -80,7 +106,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
Println(string(buf))
return nil
case "snapshot":
sn, err := restic.FindSnapshot(ctx, repo.Backend(), repo, args[1])
sn, _, err := restic.FindSnapshot(ctx, repo.Backend(), repo, args[1])
if err != nil {
return errors.Fatalf("could not find snapshot: %v\n", err)
}
@@ -143,7 +169,8 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
return err
case "blob":
err = repo.LoadIndex(ctx)
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
err = repo.LoadIndex(ctx, bar)
if err != nil {
return err
}
@@ -165,6 +192,30 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
return errors.Fatal("blob not found")
case "tree":
sn, subfolder, err := restic.FindSnapshot(ctx, repo.Backend(), repo, args[1])
if err != nil {
return errors.Fatalf("could not find snapshot: %v\n", err)
}
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
err = repo.LoadIndex(ctx, bar)
if err != nil {
return err
}
sn.Tree, err = restic.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
if err != nil {
return err
}
buf, err := repo.LoadBlob(ctx, restic.TreeBlob, *sn.Tree, nil)
if err != nil {
return err
}
_, err = globalOptions.stdout.Write(buf)
return err
default:
return errors.Fatal("invalid type")
}

View File

@@ -0,0 +1,30 @@
package main
import (
"strings"
"testing"
rtest "github.com/restic/restic/internal/test"
)
func TestCatArgsValidation(t *testing.T) {
for _, test := range []struct {
args []string
err string
}{
{[]string{}, "Fatal: type not specified"},
{[]string{"masterkey"}, ""},
{[]string{"invalid"}, `Fatal: invalid type "invalid"`},
{[]string{"snapshot"}, "Fatal: ID not specified"},
{[]string{"snapshot", "12345678"}, ""},
} {
t.Run("", func(t *testing.T) {
err := validateCatArgs(test.args)
if test.err == "" {
rtest.Assert(t, err == nil, "unexpected error %q", err)
} else {
rtest.Assert(t, strings.Contains(err.Error(), test.err), "unexpected error expected %q to contain %q", err, test.err)
}
})
}
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/fs"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/ui"
)
var cmdCheck = &cobra.Command{
@@ -65,7 +66,7 @@ func init() {
// MarkDeprecated only returns an error when the flag is not found
panic(err)
}
f.BoolVar(&checkOptions.WithCache, "with-cache", false, "use the cache")
f.BoolVar(&checkOptions.WithCache, "with-cache", false, "use existing cache, only read uncached data from repository")
}
func checkFlags(opts CheckOptions) error {
@@ -97,7 +98,7 @@ func checkFlags(opts CheckOptions) error {
}
} else {
fileSize, err := parseSizeStr(opts.ReadDataSubset)
fileSize, err := ui.ParseBytes(opts.ReadDataSubset)
if err != nil {
return argumentError
}
@@ -211,7 +212,7 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts GlobalOptions, args
if !gopts.NoLock {
Verbosef("create exclusive lock for repository\n")
var lock *restic.Lock
lock, ctx, err = lockRepoExclusive(ctx, repo)
lock, ctx, err = lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -225,7 +226,8 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts GlobalOptions, args
}
Verbosef("load indexes\n")
hints, errs := chkr.LoadIndex(ctx)
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
hints, errs := chkr.LoadIndex(ctx, bar)
errorsFound := false
suggestIndexRebuild := false
@@ -245,7 +247,7 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts GlobalOptions, args
}
if suggestIndexRebuild {
Printf("Duplicate packs/old indexes are non-critical, you can run `restic rebuild-index' to correct this.\n")
Printf("Duplicate packs/old indexes are non-critical, you can run `restic repair index' to correct this.\n")
}
if mixedFound {
Printf("Mixed packs with tree and data blobs are non-critical, you can run `restic prune` to correct this.\n")
@@ -328,11 +330,28 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts GlobalOptions, args
go chkr.ReadPacks(ctx, packs, p, errChan)
var salvagePacks restic.IDs
for err := range errChan {
errorsFound = true
Warnf("%v\n", err)
if err, ok := err.(*checker.ErrPackData); ok {
if strings.Contains(err.Error(), "wrong data returned, hash is") {
salvagePacks = append(salvagePacks, err.PackID)
}
}
}
p.Done()
if len(salvagePacks) > 0 {
Warnf("\nThe repository contains pack files with damaged blobs. These blobs must be removed to repair the repository. This can be done using the following commands:\n\n")
var strIds []string
for _, id := range salvagePacks {
strIds = append(strIds, id.String())
}
Warnf("RESTIC_FEATURES=repair-packs-v1 restic repair packs %v\nrestic repair snapshots --forget\n\n", strings.Join(strIds, " "))
Warnf("Corrupted blobs are either caused by hardware problems or bugs in restic. Please open an issue at https://github.com/restic/restic/issues/new/choose for further troubleshooting!\n")
}
}
switch {
@@ -363,7 +382,7 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts GlobalOptions, args
if repoSize == 0 {
return errors.Fatal("Cannot read from a repository having size 0")
}
subsetSize, _ := parseSizeStr(opts.ReadDataSubset)
subsetSize, _ := ui.ParseBytes(opts.ReadDataSubset)
if subsetSize > repoSize {
subsetSize = repoSize
}

View File

@@ -0,0 +1,34 @@
package main
import (
"context"
"testing"
rtest "github.com/restic/restic/internal/test"
)
func testRunCheck(t testing.TB, gopts GlobalOptions) {
t.Helper()
output, err := testRunCheckOutput(gopts, true)
if err != nil {
t.Error(output)
t.Fatalf("unexpected error: %+v", err)
}
}
func testRunCheckMustFail(t testing.TB, gopts GlobalOptions) {
t.Helper()
_, err := testRunCheckOutput(gopts, false)
rtest.Assert(t, err != nil, "expected non nil error after check of damaged repository")
}
func testRunCheckOutput(gopts GlobalOptions, checkUnused bool) (string, error) {
buf, err := withCaptureStdout(func() error {
opts := CheckOptions{
ReadData: true,
CheckUnused: checkUnused,
}
return runCheck(context.TODO(), opts, gopts, nil)
})
return buf.String(), err
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/restic/restic/internal/backend"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
"golang.org/x/sync/errgroup"
@@ -74,14 +75,14 @@ func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []
if !gopts.NoLock {
var srcLock *restic.Lock
srcLock, ctx, err = lockRepo(ctx, srcRepo)
srcLock, ctx, err = lockRepo(ctx, srcRepo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(srcLock)
if err != nil {
return err
}
}
dstLock, ctx, err := lockRepo(ctx, dstRepo)
dstLock, ctx, err := lockRepo(ctx, dstRepo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(dstLock)
if err != nil {
return err
@@ -98,12 +99,13 @@ func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []
}
debug.Log("Loading source index")
if err := srcRepo.LoadIndex(ctx); err != nil {
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
if err := srcRepo.LoadIndex(ctx, bar); err != nil {
return err
}
bar = newIndexProgress(gopts.Quiet, gopts.JSON)
debug.Log("Loading destination index")
if err := dstRepo.LoadIndex(ctx); err != nil {
if err := dstRepo.LoadIndex(ctx, bar); err != nil {
return err
}
@@ -236,5 +238,8 @@ func copyTree(ctx context.Context, srcRepo restic.Repository, dstRepo restic.Rep
bar := newProgressMax(!quiet, uint64(len(packList)), "packs copied")
_, err = repository.Repack(ctx, srcRepo, dstRepo, packList, copyBlobs, bar)
bar.Done()
return err
if err != nil {
return errors.Fatal(err.Error())
}
return nil
}

View File

@@ -0,0 +1,136 @@
package main
import (
"context"
"fmt"
"path/filepath"
"testing"
rtest "github.com/restic/restic/internal/test"
)
func testRunCopy(t testing.TB, srcGopts GlobalOptions, dstGopts GlobalOptions) {
gopts := srcGopts
gopts.Repo = dstGopts.Repo
gopts.password = dstGopts.password
copyOpts := CopyOptions{
secondaryRepoOptions: secondaryRepoOptions{
Repo: srcGopts.Repo,
password: srcGopts.password,
},
}
rtest.OK(t, runCopy(context.TODO(), copyOpts, gopts, nil))
}
func TestCopy(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
env2, cleanup2 := withTestEnvironment(t)
defer cleanup2()
testSetupBackupData(t, env)
opts := BackupOptions{}
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9")}, opts, env.gopts)
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "2")}, opts, env.gopts)
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "3")}, opts, env.gopts)
testRunCheck(t, env.gopts)
testRunInit(t, env2.gopts)
testRunCopy(t, env.gopts, env2.gopts)
snapshotIDs := testListSnapshots(t, env.gopts, 3)
copiedSnapshotIDs := testListSnapshots(t, env2.gopts, 3)
// Check that the copies size seems reasonable
stat := dirStats(env.repo)
stat2 := dirStats(env2.repo)
sizeDiff := int64(stat.size) - int64(stat2.size)
if sizeDiff < 0 {
sizeDiff = -sizeDiff
}
rtest.Assert(t, sizeDiff < int64(stat.size)/50, "expected less than 2%% size difference: %v vs. %v",
stat.size, stat2.size)
// Check integrity of the copy
testRunCheck(t, env2.gopts)
// Check that the copied snapshots have the same tree contents as the old ones (= identical tree hash)
origRestores := make(map[string]struct{})
for i, snapshotID := range snapshotIDs {
restoredir := filepath.Join(env.base, fmt.Sprintf("restore%d", i))
origRestores[restoredir] = struct{}{}
testRunRestore(t, env.gopts, restoredir, snapshotID)
}
for i, snapshotID := range copiedSnapshotIDs {
restoredir := filepath.Join(env2.base, fmt.Sprintf("restore%d", i))
testRunRestore(t, env2.gopts, restoredir, snapshotID)
foundMatch := false
for cmpdir := range origRestores {
diff := directoriesContentsDiff(restoredir, cmpdir)
if diff == "" {
delete(origRestores, cmpdir)
foundMatch = true
}
}
rtest.Assert(t, foundMatch, "found no counterpart for snapshot %v", snapshotID)
}
rtest.Assert(t, len(origRestores) == 0, "found not copied snapshots")
}
func TestCopyIncremental(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
env2, cleanup2 := withTestEnvironment(t)
defer cleanup2()
testSetupBackupData(t, env)
opts := BackupOptions{}
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9")}, opts, env.gopts)
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "2")}, opts, env.gopts)
testRunCheck(t, env.gopts)
testRunInit(t, env2.gopts)
testRunCopy(t, env.gopts, env2.gopts)
testListSnapshots(t, env.gopts, 2)
testListSnapshots(t, env2.gopts, 2)
// Check that the copies size seems reasonable
testRunCheck(t, env2.gopts)
// check that no snapshots are copied, as there are no new ones
testRunCopy(t, env.gopts, env2.gopts)
testRunCheck(t, env2.gopts)
testListSnapshots(t, env2.gopts, 2)
// check that only new snapshots are copied
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "3")}, opts, env.gopts)
testRunCopy(t, env.gopts, env2.gopts)
testRunCheck(t, env2.gopts)
testListSnapshots(t, env.gopts, 3)
testListSnapshots(t, env2.gopts, 3)
// also test the reverse direction
testRunCopy(t, env2.gopts, env.gopts)
testRunCheck(t, env.gopts)
testListSnapshots(t, env.gopts, 3)
}
func TestCopyUnstableJSON(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
env2, cleanup2 := withTestEnvironment(t)
defer cleanup2()
// contains a symlink created using `ln -s '../i/'$'\355\246\361''d/samba' broken-symlink`
datafile := filepath.Join("testdata", "copy-unstable-json.tar.gz")
rtest.SetupTarTestFixture(t, env.base, datafile)
testRunInit(t, env2.gopts)
testRunCopy(t, env.gopts, env2.gopts)
testRunCheck(t, env2.gopts)
testListSnapshots(t, env2.gopts, 1)
}

View File

@@ -134,7 +134,7 @@ func printPacks(ctx context.Context, repo *repository.Repository, wr io.Writer)
}
func dumpIndexes(ctx context.Context, repo restic.Repository, wr io.Writer) error {
return index.ForAllIndexes(ctx, repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
return index.ForAllIndexes(ctx, repo.Backend(), repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
Printf("index_id: %v\n", id)
if err != nil {
return err
@@ -156,7 +156,7 @@ func runDebugDump(ctx context.Context, gopts GlobalOptions, args []string) error
if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo)
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -167,20 +167,20 @@ func runDebugDump(ctx context.Context, gopts GlobalOptions, args []string) error
switch tpe {
case "indexes":
return dumpIndexes(ctx, repo, gopts.stdout)
return dumpIndexes(ctx, repo, globalOptions.stdout)
case "snapshots":
return debugPrintSnapshots(ctx, repo, gopts.stdout)
return debugPrintSnapshots(ctx, repo, globalOptions.stdout)
case "packs":
return printPacks(ctx, repo, gopts.stdout)
return printPacks(ctx, repo, globalOptions.stdout)
case "all":
Printf("snapshots:\n")
err := debugPrintSnapshots(ctx, repo, gopts.stdout)
err := debugPrintSnapshots(ctx, repo, globalOptions.stdout)
if err != nil {
return err
}
Printf("\nindexes:\n")
err = dumpIndexes(ctx, repo, gopts.stdout)
err = dumpIndexes(ctx, repo, globalOptions.stdout)
if err != nil {
return err
}
@@ -462,14 +462,15 @@ func runDebugExamine(ctx context.Context, gopts GlobalOptions, args []string) er
if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo)
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
err = repo.LoadIndex(ctx)
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
err = repo.LoadIndex(ctx, bar)
if err != nil {
return err
}

View File

@@ -16,7 +16,7 @@ import (
)
var cmdDiff = &cobra.Command{
Use: "diff [flags] snapshot-ID snapshot-ID",
Use: "diff [flags] snapshotID snapshotID",
Short: "Show differences between two snapshots",
Long: `
The "diff" command shows differences from the first to the second snapshot. The
@@ -29,6 +29,10 @@ directory:
* M The file's content was modified
* T The type was changed, e.g. a file was made a symlink
To only compare files in specific subfolders, you can use the
"<snapshotID>:<subfolder>" syntax, where "subfolder" is a path within the
snapshot.
EXIT STATUS
===========
@@ -54,12 +58,12 @@ func init() {
f.BoolVar(&diffOptions.ShowMetadata, "metadata", false, "print changes in metadata")
}
func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.Repository, desc string) (*restic.Snapshot, error) {
sn, err := restic.FindSnapshot(ctx, be, repo, desc)
func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.Repository, desc string) (*restic.Snapshot, string, error) {
sn, subfolder, err := restic.FindSnapshot(ctx, be, repo, desc)
if err != nil {
return nil, errors.Fatal(err.Error())
return nil, "", errors.Fatal(err.Error())
}
return sn, err
return sn, subfolder, err
}
// Comparer collects all things needed to compare two snapshots.
@@ -334,7 +338,7 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo)
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -346,12 +350,12 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
if err != nil {
return err
}
sn1, err := loadSnapshot(ctx, be, repo, args[0])
sn1, subfolder1, err := loadSnapshot(ctx, be, repo, args[0])
if err != nil {
return err
}
sn2, err := loadSnapshot(ctx, be, repo, args[1])
sn2, subfolder2, err := loadSnapshot(ctx, be, repo, args[1])
if err != nil {
return err
}
@@ -359,8 +363,8 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
if !gopts.JSON {
Verbosef("comparing snapshot %v to %v:\n\n", sn1.ID().Str(), sn2.ID().Str())
}
if err = repo.LoadIndex(ctx); err != nil {
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
if err = repo.LoadIndex(ctx, bar); err != nil {
return err
}
@@ -372,6 +376,16 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
return errors.Errorf("snapshot %v has nil tree", sn2.ID().Str())
}
sn1.Tree, err = restic.FindTreeDirectory(ctx, repo, sn1.Tree, subfolder1)
if err != nil {
return err
}
sn2.Tree, err = restic.FindTreeDirectory(ctx, repo, sn2.Tree, subfolder2)
if err != nil {
return err
}
c := &Comparer{
repo: repo,
opts: diffOptions,
@@ -381,7 +395,7 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
}
if gopts.JSON {
enc := json.NewEncoder(gopts.stdout)
enc := json.NewEncoder(globalOptions.stdout)
c.printChange = func(change *Change) {
err := enc.Encode(change)
if err != nil {
@@ -415,7 +429,7 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
updateBlobs(repo, stats.BlobsAfter.Sub(both).Sub(stats.BlobsCommon), &stats.Added)
if gopts.JSON {
err := json.NewEncoder(gopts.stdout).Encode(stats)
err := json.NewEncoder(globalOptions.stdout).Encode(stats)
if err != nil {
Warnf("JSON encode failed: %v\n", err)
}

View File

@@ -0,0 +1,193 @@
package main
import (
"bufio"
"context"
"encoding/json"
"io"
"os"
"path/filepath"
"regexp"
"strings"
"testing"
rtest "github.com/restic/restic/internal/test"
)
func testRunDiffOutput(gopts GlobalOptions, firstSnapshotID string, secondSnapshotID string) (string, error) {
buf, err := withCaptureStdout(func() error {
opts := DiffOptions{
ShowMetadata: false,
}
return runDiff(context.TODO(), opts, gopts, []string{firstSnapshotID, secondSnapshotID})
})
return buf.String(), err
}
func copyFile(dst string, src string) error {
srcFile, err := os.Open(src)
if err != nil {
return err
}
dstFile, err := os.Create(dst)
if err != nil {
// ignore subsequent errors
_ = srcFile.Close()
return err
}
_, err = io.Copy(dstFile, srcFile)
if err != nil {
// ignore subsequent errors
_ = srcFile.Close()
_ = dstFile.Close()
return err
}
err = srcFile.Close()
if err != nil {
// ignore subsequent errors
_ = dstFile.Close()
return err
}
err = dstFile.Close()
if err != nil {
return err
}
return nil
}
var diffOutputRegexPatterns = []string{
"-.+modfile",
"M.+modfile1",
"\\+.+modfile2",
"\\+.+modfile3",
"\\+.+modfile4",
"-.+submoddir",
"-.+submoddir.subsubmoddir",
"\\+.+submoddir2",
"\\+.+submoddir2.subsubmoddir",
"Files: +2 new, +1 removed, +1 changed",
"Dirs: +3 new, +2 removed",
"Data Blobs: +2 new, +1 removed",
"Added: +7[0-9]{2}\\.[0-9]{3} KiB",
"Removed: +2[0-9]{2}\\.[0-9]{3} KiB",
}
func setupDiffRepo(t *testing.T) (*testEnvironment, func(), string, string) {
env, cleanup := withTestEnvironment(t)
testRunInit(t, env.gopts)
datadir := filepath.Join(env.base, "testdata")
testdir := filepath.Join(datadir, "testdir")
subtestdir := filepath.Join(testdir, "subtestdir")
testfile := filepath.Join(testdir, "testfile")
rtest.OK(t, os.Mkdir(testdir, 0755))
rtest.OK(t, os.Mkdir(subtestdir, 0755))
rtest.OK(t, appendRandomData(testfile, 256*1024))
moddir := filepath.Join(datadir, "moddir")
submoddir := filepath.Join(moddir, "submoddir")
subsubmoddir := filepath.Join(submoddir, "subsubmoddir")
modfile := filepath.Join(moddir, "modfile")
rtest.OK(t, os.Mkdir(moddir, 0755))
rtest.OK(t, os.Mkdir(submoddir, 0755))
rtest.OK(t, os.Mkdir(subsubmoddir, 0755))
rtest.OK(t, copyFile(modfile, testfile))
rtest.OK(t, appendRandomData(modfile+"1", 256*1024))
snapshots := make(map[string]struct{})
opts := BackupOptions{}
testRunBackup(t, "", []string{datadir}, opts, env.gopts)
snapshots, firstSnapshotID := lastSnapshot(snapshots, loadSnapshotMap(t, env.gopts))
rtest.OK(t, os.Rename(modfile, modfile+"3"))
rtest.OK(t, os.Rename(submoddir, submoddir+"2"))
rtest.OK(t, appendRandomData(modfile+"1", 256*1024))
rtest.OK(t, appendRandomData(modfile+"2", 256*1024))
rtest.OK(t, os.Mkdir(modfile+"4", 0755))
testRunBackup(t, "", []string{datadir}, opts, env.gopts)
_, secondSnapshotID := lastSnapshot(snapshots, loadSnapshotMap(t, env.gopts))
return env, cleanup, firstSnapshotID, secondSnapshotID
}
func TestDiff(t *testing.T) {
env, cleanup, firstSnapshotID, secondSnapshotID := setupDiffRepo(t)
defer cleanup()
// quiet suppresses the diff output except for the summary
env.gopts.Quiet = false
_, err := testRunDiffOutput(env.gopts, "", secondSnapshotID)
rtest.Assert(t, err != nil, "expected error on invalid snapshot id")
out, err := testRunDiffOutput(env.gopts, firstSnapshotID, secondSnapshotID)
rtest.OK(t, err)
for _, pattern := range diffOutputRegexPatterns {
r, err := regexp.Compile(pattern)
rtest.Assert(t, err == nil, "failed to compile regexp %v", pattern)
rtest.Assert(t, r.MatchString(out), "expected pattern %v in output, got\n%v", pattern, out)
}
// check quiet output
env.gopts.Quiet = true
outQuiet, err := testRunDiffOutput(env.gopts, firstSnapshotID, secondSnapshotID)
rtest.OK(t, err)
rtest.Assert(t, len(outQuiet) < len(out), "expected shorter output on quiet mode %v vs. %v", len(outQuiet), len(out))
}
type typeSniffer struct {
MessageType string `json:"message_type"`
}
func TestDiffJSON(t *testing.T) {
env, cleanup, firstSnapshotID, secondSnapshotID := setupDiffRepo(t)
defer cleanup()
// quiet suppresses the diff output except for the summary
env.gopts.Quiet = false
env.gopts.JSON = true
out, err := testRunDiffOutput(env.gopts, firstSnapshotID, secondSnapshotID)
rtest.OK(t, err)
var stat DiffStatsContainer
var changes int
scanner := bufio.NewScanner(strings.NewReader(out))
for scanner.Scan() {
line := scanner.Text()
var sniffer typeSniffer
rtest.OK(t, json.Unmarshal([]byte(line), &sniffer))
switch sniffer.MessageType {
case "change":
changes++
case "statistics":
rtest.OK(t, json.Unmarshal([]byte(line), &stat))
default:
t.Fatalf("unexpected message type %v", sniffer.MessageType)
}
}
rtest.Equals(t, 9, changes)
rtest.Assert(t, stat.Added.Files == 2 && stat.Added.Dirs == 3 && stat.Added.DataBlobs == 2 &&
stat.Removed.Files == 1 && stat.Removed.Dirs == 2 && stat.Removed.DataBlobs == 1 &&
stat.ChangedFiles == 1, "unexpected statistics")
// check quiet output
env.gopts.Quiet = true
outQuiet, err := testRunDiffOutput(env.gopts, firstSnapshotID, secondSnapshotID)
rtest.OK(t, err)
stat = DiffStatsContainer{}
rtest.OK(t, json.Unmarshal([]byte(outQuiet), &stat))
rtest.Assert(t, stat.Added.Files == 2 && stat.Added.Dirs == 3 && stat.Added.DataBlobs == 2 &&
stat.Removed.Files == 1 && stat.Removed.Dirs == 2 && stat.Removed.DataBlobs == 1 &&
stat.ChangedFiles == 1, "unexpected statistics")
rtest.Assert(t, stat.SourceSnapshot == firstSnapshotID && stat.TargetSnapshot == secondSnapshotID, "unexpected snapshot ids")
}

View File

@@ -24,9 +24,13 @@ single file is selected, it prints its contents to stdout. Folders are output
as a tar (default) or zip file containing the contents of the specified folder.
Pass "/" as file name to dump the whole snapshot as an archive file.
The special snapshot "latest" can be used to use the latest snapshot in the
The special snapshotID "latest" can be used to use the latest snapshot in the
repository.
To include the folder content at the root of the archive, you can use the
"<snapshotID>:<subfolder>" syntax, where "subfolder" is a path within the
snapshot.
EXIT STATUS
===========
@@ -132,14 +136,14 @@ func runDump(ctx context.Context, opts DumpOptions, gopts GlobalOptions, args []
if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo)
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
sn, err := (&restic.SnapshotFilter{
sn, subfolder, err := (&restic.SnapshotFilter{
Hosts: opts.Hosts,
Paths: opts.Paths,
Tags: opts.Tags,
@@ -148,7 +152,13 @@ func runDump(ctx context.Context, opts DumpOptions, gopts GlobalOptions, args []
return errors.Fatalf("failed to find snapshot: %v", err)
}
err = repo.LoadIndex(ctx)
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
err = repo.LoadIndex(ctx, bar)
if err != nil {
return err
}
sn.Tree, err = restic.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
if err != nil {
return err
}

View File

@@ -51,6 +51,7 @@ type FindOptions struct {
PackID, ShowPackID bool
CaseInsensitive bool
ListLong bool
HumanReadable bool
restic.SnapshotFilter
}
@@ -69,6 +70,7 @@ func init() {
f.BoolVar(&findOptions.ShowPackID, "show-pack-id", false, "display the pack-ID the blobs belong to (with --blob or --tree)")
f.BoolVarP(&findOptions.CaseInsensitive, "ignore-case", "i", false, "ignore case for pattern")
f.BoolVarP(&findOptions.ListLong, "long", "l", false, "use a long listing format showing size and mode")
f.BoolVar(&findOptions.HumanReadable, "human-readable", false, "print sizes in human readable format")
initMultiSnapshotFilter(f, &findOptions.SnapshotFilter, true)
}
@@ -104,12 +106,13 @@ func parseTime(str string) (time.Time, error) {
}
type statefulOutput struct {
ListLong bool
JSON bool
inuse bool
newsn *restic.Snapshot
oldsn *restic.Snapshot
hits int
ListLong bool
HumanReadable bool
JSON bool
inuse bool
newsn *restic.Snapshot
oldsn *restic.Snapshot
hits int
}
func (s *statefulOutput) PrintPatternJSON(path string, node *restic.Node) {
@@ -123,7 +126,6 @@ func (s *statefulOutput) PrintPatternJSON(path string, node *restic.Node) {
// Make the following attributes disappear
Name byte `json:"name,omitempty"`
Inode byte `json:"inode,omitempty"`
ExtendedAttributes byte `json:"extended_attributes,omitempty"`
Device byte `json:"device,omitempty"`
Content byte `json:"content,omitempty"`
@@ -164,7 +166,7 @@ func (s *statefulOutput) PrintPatternNormal(path string, node *restic.Node) {
s.oldsn = s.newsn
Verbosef("Found matching entries in snapshot %s from %s\n", s.oldsn.ID().Str(), s.oldsn.Time.Local().Format(TimeFormat))
}
Println(formatNode(path, node, s.ListLong))
Println(formatNode(path, node, s.ListLong, s.HumanReadable))
}
func (s *statefulOutput) PrintPattern(path string, node *restic.Node) {
@@ -501,7 +503,7 @@ func (f *Finder) indexPacksToBlobs(ctx context.Context, packIDs map[string]struc
return packIDs
}
func (f *Finder) findObjectPack(ctx context.Context, id string, t restic.BlobType) {
func (f *Finder) findObjectPack(id string, t restic.BlobType) {
idx := f.repo.Index()
rid, err := restic.ParseID(id)
@@ -524,13 +526,13 @@ func (f *Finder) findObjectPack(ctx context.Context, id string, t restic.BlobTyp
}
}
func (f *Finder) findObjectsPacks(ctx context.Context) {
func (f *Finder) findObjectsPacks() {
for i := range f.blobIDs {
f.findObjectPack(ctx, i, restic.DataBlob)
f.findObjectPack(i, restic.DataBlob)
}
for i := range f.treeIDs {
f.findObjectPack(ctx, i, restic.TreeBlob)
f.findObjectPack(i, restic.TreeBlob)
}
}
@@ -575,7 +577,7 @@ func runFind(ctx context.Context, opts FindOptions, gopts GlobalOptions, args []
if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo)
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -586,15 +588,15 @@ func runFind(ctx context.Context, opts FindOptions, gopts GlobalOptions, args []
if err != nil {
return err
}
if err = repo.LoadIndex(ctx); err != nil {
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
if err = repo.LoadIndex(ctx, bar); err != nil {
return err
}
f := &Finder{
repo: repo,
pat: pat,
out: statefulOutput{ListLong: opts.ListLong, JSON: globalOptions.JSON},
out: statefulOutput{ListLong: opts.ListLong, HumanReadable: opts.HumanReadable, JSON: gopts.JSON},
ignoreTrees: restic.NewIDSet(),
}
@@ -618,7 +620,16 @@ func runFind(ctx context.Context, opts FindOptions, gopts GlobalOptions, args []
}
}
var filteredSnapshots []*restic.Snapshot
for sn := range FindFilteredSnapshots(ctx, snapshotLister, repo, &opts.SnapshotFilter, opts.Snapshots) {
filteredSnapshots = append(filteredSnapshots, sn)
}
sort.Slice(filteredSnapshots, func(i, j int) bool {
return filteredSnapshots[i].Time.Before(filteredSnapshots[j].Time)
})
for _, sn := range filteredSnapshots {
if f.blobIDs != nil || f.treeIDs != nil {
if err = f.findIDs(ctx, sn); err != nil && err.Error() != "OK" {
return err
@@ -632,7 +643,7 @@ func runFind(ctx context.Context, opts FindOptions, gopts GlobalOptions, args []
f.out.Finish()
if opts.ShowPackID && (f.blobIDs != nil || f.treeIDs != nil) {
f.findObjectsPacks(ctx)
f.findObjectsPacks()
}
return nil

View File

@@ -0,0 +1,87 @@
package main
import (
"context"
"encoding/json"
"strings"
"testing"
"time"
rtest "github.com/restic/restic/internal/test"
)
func testRunFind(t testing.TB, wantJSON bool, gopts GlobalOptions, pattern string) []byte {
buf, err := withCaptureStdout(func() error {
gopts.JSON = wantJSON
opts := FindOptions{}
return runFind(context.TODO(), opts, gopts, []string{pattern})
})
rtest.OK(t, err)
return buf.Bytes()
}
func TestFind(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
datafile := testSetupBackupData(t, env)
opts := BackupOptions{}
testRunBackup(t, "", []string{env.testdata}, opts, env.gopts)
testRunCheck(t, env.gopts)
results := testRunFind(t, false, env.gopts, "unexistingfile")
rtest.Assert(t, len(results) == 0, "unexisting file found in repo (%v)", datafile)
results = testRunFind(t, false, env.gopts, "testfile")
lines := strings.Split(string(results), "\n")
rtest.Assert(t, len(lines) == 2, "expected one file found in repo (%v)", datafile)
results = testRunFind(t, false, env.gopts, "testfile*")
lines = strings.Split(string(results), "\n")
rtest.Assert(t, len(lines) == 4, "expected three files found in repo (%v)", datafile)
}
type testMatch struct {
Path string `json:"path,omitempty"`
Permissions string `json:"permissions,omitempty"`
Size uint64 `json:"size,omitempty"`
Date time.Time `json:"date,omitempty"`
UID uint32 `json:"uid,omitempty"`
GID uint32 `json:"gid,omitempty"`
}
type testMatches struct {
Hits int `json:"hits,omitempty"`
SnapshotID string `json:"snapshot,omitempty"`
Matches []testMatch `json:"matches,omitempty"`
}
func TestFindJSON(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
datafile := testSetupBackupData(t, env)
opts := BackupOptions{}
testRunBackup(t, "", []string{env.testdata}, opts, env.gopts)
testRunCheck(t, env.gopts)
results := testRunFind(t, true, env.gopts, "unexistingfile")
matches := []testMatches{}
rtest.OK(t, json.Unmarshal(results, &matches))
rtest.Assert(t, len(matches) == 0, "expected no match in repo (%v)", datafile)
results = testRunFind(t, true, env.gopts, "testfile")
rtest.OK(t, json.Unmarshal(results, &matches))
rtest.Assert(t, len(matches) == 1, "expected a single snapshot in repo (%v)", datafile)
rtest.Assert(t, len(matches[0].Matches) == 1, "expected a single file to match (%v)", datafile)
rtest.Assert(t, matches[0].Hits == 1, "expected hits to show 1 match (%v)", datafile)
results = testRunFind(t, true, env.gopts, "testfile*")
rtest.OK(t, json.Unmarshal(results, &matches))
rtest.Assert(t, len(matches) == 1, "expected a single snapshot in repo (%v)", datafile)
rtest.Assert(t, len(matches[0].Matches) == 3, "expected 3 files to match (%v)", datafile)
rtest.Assert(t, matches[0].Hits == 3, "expected hits to show 3 matches (%v)", datafile)
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"io"
"strconv"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
@@ -36,14 +37,49 @@ Exit status is 0 if the command was successful, and non-zero if there was any er
},
}
type ForgetPolicyCount int
var ErrNegativePolicyCount = errors.New("negative values not allowed, use 'unlimited' instead")
func (c *ForgetPolicyCount) Set(s string) error {
switch s {
case "unlimited":
*c = -1
default:
val, err := strconv.ParseInt(s, 10, 0)
if err != nil {
return err
}
if val < 0 {
return ErrNegativePolicyCount
}
*c = ForgetPolicyCount(val)
}
return nil
}
func (c *ForgetPolicyCount) String() string {
switch *c {
case -1:
return "unlimited"
default:
return strconv.FormatInt(int64(*c), 10)
}
}
func (c *ForgetPolicyCount) Type() string {
return "n"
}
// ForgetOptions collects all options for the forget command.
type ForgetOptions struct {
Last int
Hourly int
Daily int
Weekly int
Monthly int
Yearly int
Last ForgetPolicyCount
Hourly ForgetPolicyCount
Daily ForgetPolicyCount
Weekly ForgetPolicyCount
Monthly ForgetPolicyCount
Yearly ForgetPolicyCount
Within restic.Duration
WithinHourly restic.Duration
WithinDaily restic.Duration
@@ -56,7 +92,7 @@ type ForgetOptions struct {
Compact bool
// Grouping
GroupBy string
GroupBy restic.SnapshotGroupByOptions
DryRun bool
Prune bool
}
@@ -67,12 +103,12 @@ func init() {
cmdRoot.AddCommand(cmdForget)
f := cmdForget.Flags()
f.IntVarP(&forgetOptions.Last, "keep-last", "l", 0, "keep the last `n` snapshots")
f.IntVarP(&forgetOptions.Hourly, "keep-hourly", "H", 0, "keep the last `n` hourly snapshots")
f.IntVarP(&forgetOptions.Daily, "keep-daily", "d", 0, "keep the last `n` daily snapshots")
f.IntVarP(&forgetOptions.Weekly, "keep-weekly", "w", 0, "keep the last `n` weekly snapshots")
f.IntVarP(&forgetOptions.Monthly, "keep-monthly", "m", 0, "keep the last `n` monthly snapshots")
f.IntVarP(&forgetOptions.Yearly, "keep-yearly", "y", 0, "keep the last `n` yearly snapshots")
f.VarP(&forgetOptions.Last, "keep-last", "l", "keep the last `n` snapshots (use 'unlimited' to keep all snapshots)")
f.VarP(&forgetOptions.Hourly, "keep-hourly", "H", "keep the last `n` hourly snapshots (use 'unlimited' to keep all hourly snapshots)")
f.VarP(&forgetOptions.Daily, "keep-daily", "d", "keep the last `n` daily snapshots (use 'unlimited' to keep all daily snapshots)")
f.VarP(&forgetOptions.Weekly, "keep-weekly", "w", "keep the last `n` weekly snapshots (use 'unlimited' to keep all weekly snapshots)")
f.VarP(&forgetOptions.Monthly, "keep-monthly", "m", "keep the last `n` monthly snapshots (use 'unlimited' to keep all monthly snapshots)")
f.VarP(&forgetOptions.Yearly, "keep-yearly", "y", "keep the last `n` yearly snapshots (use 'unlimited' to keep all yearly snapshots)")
f.VarP(&forgetOptions.Within, "keep-within", "", "keep snapshots that are newer than `duration` (eg. 1y5m7d2h) relative to the latest snapshot")
f.VarP(&forgetOptions.WithinHourly, "keep-within-hourly", "", "keep hourly snapshots that are newer than `duration` (eg. 1y5m7d2h) relative to the latest snapshot")
f.VarP(&forgetOptions.WithinDaily, "keep-within-daily", "", "keep daily snapshots that are newer than `duration` (eg. 1y5m7d2h) relative to the latest snapshot")
@@ -90,8 +126,8 @@ func init() {
}
f.BoolVarP(&forgetOptions.Compact, "compact", "c", false, "use compact output format")
f.StringVarP(&forgetOptions.GroupBy, "group-by", "g", "host,paths", "`group` snapshots by host, paths and/or tags, separated by comma (disable grouping with '')")
forgetOptions.GroupBy = restic.SnapshotGroupByOptions{Host: true, Path: true}
f.VarP(&forgetOptions.GroupBy, "group-by", "g", "`group` snapshots by host, paths and/or tags, separated by comma (disable grouping with '')")
f.BoolVarP(&forgetOptions.DryRun, "dry-run", "n", false, "do not delete anything, just print what would be done")
f.BoolVar(&forgetOptions.Prune, "prune", false, "automatically run the 'prune' command if snapshots have been removed")
@@ -99,8 +135,29 @@ func init() {
addPruneOptions(cmdForget)
}
func verifyForgetOptions(opts *ForgetOptions) error {
if opts.Last < -1 || opts.Hourly < -1 || opts.Daily < -1 || opts.Weekly < -1 ||
opts.Monthly < -1 || opts.Yearly < -1 {
return errors.Fatal("negative values other than -1 are not allowed for --keep-*")
}
for _, d := range []restic.Duration{opts.Within, opts.WithinHourly, opts.WithinDaily,
opts.WithinMonthly, opts.WithinWeekly, opts.WithinYearly} {
if d.Hours < 0 || d.Days < 0 || d.Months < 0 || d.Years < 0 {
return errors.Fatal("durations containing negative values are not allowed for --keep-within*")
}
}
return nil
}
func runForget(ctx context.Context, opts ForgetOptions, gopts GlobalOptions, args []string) error {
err := verifyPruneOptions(&pruneOptions)
err := verifyForgetOptions(&opts)
if err != nil {
return err
}
err = verifyPruneOptions(&pruneOptions)
if err != nil {
return err
}
@@ -116,7 +173,7 @@ func runForget(ctx context.Context, opts ForgetOptions, gopts GlobalOptions, arg
if !opts.DryRun || !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepoExclusive(ctx, repo)
lock, ctx, err = lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -144,12 +201,12 @@ func runForget(ctx context.Context, opts ForgetOptions, gopts GlobalOptions, arg
}
policy := restic.ExpirePolicy{
Last: opts.Last,
Hourly: opts.Hourly,
Daily: opts.Daily,
Weekly: opts.Weekly,
Monthly: opts.Monthly,
Yearly: opts.Yearly,
Last: int(opts.Last),
Hourly: int(opts.Hourly),
Daily: int(opts.Daily),
Weekly: int(opts.Weekly),
Monthly: int(opts.Monthly),
Yearly: int(opts.Yearly),
Within: opts.Within,
WithinHourly: opts.WithinHourly,
WithinDaily: opts.WithinDaily,
@@ -172,7 +229,7 @@ func runForget(ctx context.Context, opts ForgetOptions, gopts GlobalOptions, arg
for k, snapshotGroup := range snapshotGroups {
if gopts.Verbose >= 1 && !gopts.JSON {
err = PrintSnapshotGroupHeader(gopts.stdout, k)
err = PrintSnapshotGroupHeader(globalOptions.stdout, k)
if err != nil {
return err
}
@@ -229,7 +286,7 @@ func runForget(ctx context.Context, opts ForgetOptions, gopts GlobalOptions, arg
}
if gopts.JSON && len(jsonGroups) > 0 {
err = printJSONForget(gopts.stdout, jsonGroups)
err = printJSONForget(globalOptions.stdout, jsonGroups)
if err != nil {
return err
}

View File

@@ -0,0 +1,13 @@
package main
import (
"context"
"testing"
rtest "github.com/restic/restic/internal/test"
)
func testRunForget(t testing.TB, gopts GlobalOptions, args ...string) {
opts := ForgetOptions{}
rtest.OK(t, runForget(context.TODO(), opts, gopts, args))
}

View File

@@ -0,0 +1,94 @@
package main
import (
"testing"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func TestForgetPolicyValues(t *testing.T) {
testCases := []struct {
input string
value ForgetPolicyCount
err string
}{
{"0", ForgetPolicyCount(0), ""},
{"1", ForgetPolicyCount(1), ""},
{"unlimited", ForgetPolicyCount(-1), ""},
{"", ForgetPolicyCount(0), "strconv.ParseInt: parsing \"\": invalid syntax"},
{"-1", ForgetPolicyCount(0), ErrNegativePolicyCount.Error()},
{"abc", ForgetPolicyCount(0), "strconv.ParseInt: parsing \"abc\": invalid syntax"},
}
for _, testCase := range testCases {
t.Run("", func(t *testing.T) {
var count ForgetPolicyCount
err := count.Set(testCase.input)
if testCase.err != "" {
rtest.Assert(t, err != nil, "should have returned error for input %+v", testCase.input)
rtest.Equals(t, testCase.err, err.Error())
} else {
rtest.Assert(t, err == nil, "expected no error for input %+v, got %v", testCase.input, err)
rtest.Equals(t, testCase.value, count)
rtest.Equals(t, testCase.input, count.String())
}
})
}
}
func TestForgetOptionValues(t *testing.T) {
const negValErrorMsg = "Fatal: negative values other than -1 are not allowed for --keep-*"
const negDurationValErrorMsg = "Fatal: durations containing negative values are not allowed for --keep-within*"
testCases := []struct {
input ForgetOptions
errorMsg string
}{
{ForgetOptions{Last: 1}, ""},
{ForgetOptions{Hourly: 1}, ""},
{ForgetOptions{Daily: 1}, ""},
{ForgetOptions{Weekly: 1}, ""},
{ForgetOptions{Monthly: 1}, ""},
{ForgetOptions{Yearly: 1}, ""},
{ForgetOptions{Last: 0}, ""},
{ForgetOptions{Hourly: 0}, ""},
{ForgetOptions{Daily: 0}, ""},
{ForgetOptions{Weekly: 0}, ""},
{ForgetOptions{Monthly: 0}, ""},
{ForgetOptions{Yearly: 0}, ""},
{ForgetOptions{Last: -1}, ""},
{ForgetOptions{Hourly: -1}, ""},
{ForgetOptions{Daily: -1}, ""},
{ForgetOptions{Weekly: -1}, ""},
{ForgetOptions{Monthly: -1}, ""},
{ForgetOptions{Yearly: -1}, ""},
{ForgetOptions{Last: -2}, negValErrorMsg},
{ForgetOptions{Hourly: -2}, negValErrorMsg},
{ForgetOptions{Daily: -2}, negValErrorMsg},
{ForgetOptions{Weekly: -2}, negValErrorMsg},
{ForgetOptions{Monthly: -2}, negValErrorMsg},
{ForgetOptions{Yearly: -2}, negValErrorMsg},
{ForgetOptions{Within: restic.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinHourly: restic.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinDaily: restic.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinWeekly: restic.ParseDurationOrPanic("1y2m3d3h")}, ""},
{ForgetOptions{WithinMonthly: restic.ParseDurationOrPanic("2y4m6d8h")}, ""},
{ForgetOptions{WithinYearly: restic.ParseDurationOrPanic("2y4m6d8h")}, ""},
{ForgetOptions{Within: restic.ParseDurationOrPanic("-1y2m3d3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinHourly: restic.ParseDurationOrPanic("1y-2m3d3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinDaily: restic.ParseDurationOrPanic("1y2m-3d3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinWeekly: restic.ParseDurationOrPanic("1y2m3d-3h")}, negDurationValErrorMsg},
{ForgetOptions{WithinMonthly: restic.ParseDurationOrPanic("-2y4m6d8h")}, negDurationValErrorMsg},
{ForgetOptions{WithinYearly: restic.ParseDurationOrPanic("2y-4m6d8h")}, negDurationValErrorMsg},
}
for _, testCase := range testCases {
err := verifyForgetOptions(&testCase.input)
if testCase.errorMsg != "" {
rtest.Assert(t, err != nil, "should have returned error for input %+v", testCase.input)
rtest.Equals(t, testCase.errorMsg, err.Error())
} else {
rtest.Assert(t, err == nil, "expected no error for input %+v", testCase.input)
}
}
}

View File

@@ -63,26 +63,38 @@ func writeManpages(dir string) error {
}
func writeBashCompletion(file string) error {
Verbosef("writing bash completion file to %v\n", file)
if stdoutIsTerminal() {
Verbosef("writing bash completion file to %v\n", file)
}
return cmdRoot.GenBashCompletionFile(file)
}
func writeFishCompletion(file string) error {
Verbosef("writing fish completion file to %v\n", file)
if stdoutIsTerminal() {
Verbosef("writing fish completion file to %v\n", file)
}
return cmdRoot.GenFishCompletionFile(file, true)
}
func writeZSHCompletion(file string) error {
Verbosef("writing zsh completion file to %v\n", file)
if stdoutIsTerminal() {
Verbosef("writing zsh completion file to %v\n", file)
}
return cmdRoot.GenZshCompletionFile(file)
}
func writePowerShellCompletion(file string) error {
Verbosef("writing powershell completion file to %v\n", file)
if stdoutIsTerminal() {
Verbosef("writing powershell completion file to %v\n", file)
}
return cmdRoot.GenPowerShellCompletionFile(file)
}
func runGenerate(cmd *cobra.Command, args []string) error {
func runGenerate(_ *cobra.Command, args []string) error {
if len(args) > 0 {
return errors.Fatal("the generate command expects no arguments, only options - please see `restic help generate` for usage and flags")
}
if genOpts.ManDir != "" {
err := writeManpages(genOpts.ManDir)
if err != nil {

View File

@@ -50,6 +50,10 @@ func init() {
}
func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []string) error {
if len(args) > 0 {
return errors.Fatal("the init command expects no arguments, only options - please see `restic help init` for usage and flags")
}
var version uint
if opts.RepositoryVersion == "latest" || opts.RepositoryVersion == "" {
version = restic.MaxRepoVersion
@@ -71,7 +75,7 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
return err
}
repo, err := ReadRepo(gopts)
gopts.Repo, err = ReadRepo(gopts)
if err != nil {
return err
}
@@ -83,9 +87,9 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
return err
}
be, err := create(ctx, repo, gopts.extended)
be, err := create(ctx, gopts.Repo, gopts, gopts.extended)
if err != nil {
return errors.Fatalf("create repository at %s failed: %v\n", location.StripPassword(gopts.Repo), err)
return errors.Fatalf("create repository at %s failed: %v\n", location.StripPassword(gopts.backends, gopts.Repo), err)
}
s, err := repository.New(be, repository.Options{
@@ -93,16 +97,21 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
PackSize: gopts.PackSize * 1024 * 1024,
})
if err != nil {
return err
return errors.Fatal(err.Error())
}
err = s.Init(ctx, version, gopts.password, chunkerPolynomial)
if err != nil {
return errors.Fatalf("create key in repository at %s failed: %v\n", location.StripPassword(gopts.Repo), err)
return errors.Fatalf("create key in repository at %s failed: %v\n", location.StripPassword(gopts.backends, gopts.Repo), err)
}
if !gopts.JSON {
Verbosef("created restic repository %v at %s\n", s.Config().ID[:10], location.StripPassword(gopts.Repo))
Verbosef("created restic repository %v at %s", s.Config().ID[:10], location.StripPassword(gopts.backends, gopts.Repo))
if opts.CopyChunkerParameters && chunkerPolynomial != nil {
Verbosef(" with chunker parameters copied from secondary repository\n")
} else {
Verbosef("\n")
}
Verbosef("\n")
Verbosef("Please note that knowledge of your password is required to access\n")
Verbosef("the repository. Losing your password means that your data is\n")
@@ -112,9 +121,9 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
status := initSuccess{
MessageType: "initialized",
ID: s.Config().ID,
Repository: location.StripPassword(gopts.Repo),
Repository: location.StripPassword(gopts.backends, gopts.Repo),
}
return json.NewEncoder(gopts.stdout).Encode(status)
return json.NewEncoder(globalOptions.stdout).Encode(status)
}
return nil

View File

@@ -0,0 +1,49 @@
package main
import (
"context"
"testing"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func testRunInit(t testing.TB, opts GlobalOptions) {
repository.TestUseLowSecurityKDFParameters(t)
restic.TestDisableCheckPolynomial(t)
restic.TestSetLockTimeout(t, 0)
rtest.OK(t, runInit(context.TODO(), InitOptions{}, opts, nil))
t.Logf("repository initialized at %v", opts.Repo)
}
func TestInitCopyChunkerParams(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
env2, cleanup2 := withTestEnvironment(t)
defer cleanup2()
testRunInit(t, env2.gopts)
initOpts := InitOptions{
secondaryRepoOptions: secondaryRepoOptions{
Repo: env2.gopts.Repo,
password: env2.gopts.password,
},
}
rtest.Assert(t, runInit(context.TODO(), initOpts, env.gopts, nil) != nil, "expected invalid init options to fail")
initOpts.CopyChunkerParameters = true
rtest.OK(t, runInit(context.TODO(), initOpts, env.gopts, nil))
repo, err := OpenRepository(context.TODO(), env.gopts)
rtest.OK(t, err)
otherRepo, err := OpenRepository(context.TODO(), env2.gopts)
rtest.OK(t, err)
rtest.Assert(t, repo.Config().ChunkerPolynomial == otherRepo.Config().ChunkerPolynomial,
"expected equal chunker polynomials, got %v expected %v", repo.Config().ChunkerPolynomial,
otherRepo.Config().ChunkerPolynomial)
}

View File

@@ -212,15 +212,18 @@ func runKey(ctx context.Context, gopts GlobalOptions, args []string) error {
switch args[0] {
case "list":
lock, ctx, err := lockRepo(ctx, repo)
defer unlockRepo(lock)
if err != nil {
return err
if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
return listKeys(ctx, repo, gopts)
case "add":
lock, ctx, err := lockRepo(ctx, repo)
lock, ctx, err := lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -228,7 +231,7 @@ func runKey(ctx context.Context, gopts GlobalOptions, args []string) error {
return addKey(ctx, repo, gopts)
case "remove":
lock, ctx, err := lockRepoExclusive(ctx, repo)
lock, ctx, err := lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -241,7 +244,7 @@ func runKey(ctx context.Context, gopts GlobalOptions, args []string) error {
return deleteKey(ctx, repo, id)
case "passwd":
lock, ctx, err := lockRepoExclusive(ctx, repo)
lock, ctx, err := lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err

View File

@@ -0,0 +1,145 @@
package main
import (
"bufio"
"context"
"regexp"
"testing"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func testRunKeyListOtherIDs(t testing.TB, gopts GlobalOptions) []string {
buf, err := withCaptureStdout(func() error {
return runKey(context.TODO(), gopts, []string{"list"})
})
rtest.OK(t, err)
scanner := bufio.NewScanner(buf)
exp := regexp.MustCompile(`^ ([a-f0-9]+) `)
IDs := []string{}
for scanner.Scan() {
if id := exp.FindStringSubmatch(scanner.Text()); id != nil {
IDs = append(IDs, id[1])
}
}
return IDs
}
func testRunKeyAddNewKey(t testing.TB, newPassword string, gopts GlobalOptions) {
testKeyNewPassword = newPassword
defer func() {
testKeyNewPassword = ""
}()
rtest.OK(t, runKey(context.TODO(), gopts, []string{"add"}))
}
func testRunKeyAddNewKeyUserHost(t testing.TB, gopts GlobalOptions) {
testKeyNewPassword = "john's geheimnis"
defer func() {
testKeyNewPassword = ""
keyUsername = ""
keyHostname = ""
}()
rtest.OK(t, cmdKey.Flags().Parse([]string{"--user=john", "--host=example.com"}))
t.Log("adding key for john@example.com")
rtest.OK(t, runKey(context.TODO(), gopts, []string{"add"}))
repo, err := OpenRepository(context.TODO(), gopts)
rtest.OK(t, err)
key, err := repository.SearchKey(context.TODO(), repo, testKeyNewPassword, 2, "")
rtest.OK(t, err)
rtest.Equals(t, "john", key.Username)
rtest.Equals(t, "example.com", key.Hostname)
}
func testRunKeyPasswd(t testing.TB, newPassword string, gopts GlobalOptions) {
testKeyNewPassword = newPassword
defer func() {
testKeyNewPassword = ""
}()
rtest.OK(t, runKey(context.TODO(), gopts, []string{"passwd"}))
}
func testRunKeyRemove(t testing.TB, gopts GlobalOptions, IDs []string) {
t.Logf("remove %d keys: %q\n", len(IDs), IDs)
for _, id := range IDs {
rtest.OK(t, runKey(context.TODO(), gopts, []string{"remove", id}))
}
}
func TestKeyAddRemove(t *testing.T) {
passwordList := []string{
"OnnyiasyatvodsEvVodyawit",
"raicneirvOjEfEigonOmLasOd",
}
env, cleanup := withTestEnvironment(t)
// must list keys more than once
env.gopts.backendTestHook = nil
defer cleanup()
testRunInit(t, env.gopts)
testRunKeyPasswd(t, "geheim2", env.gopts)
env.gopts.password = "geheim2"
t.Logf("changed password to %q", env.gopts.password)
for _, newPassword := range passwordList {
testRunKeyAddNewKey(t, newPassword, env.gopts)
t.Logf("added new password %q", newPassword)
env.gopts.password = newPassword
testRunKeyRemove(t, env.gopts, testRunKeyListOtherIDs(t, env.gopts))
}
env.gopts.password = passwordList[len(passwordList)-1]
t.Logf("testing access with last password %q\n", env.gopts.password)
rtest.OK(t, runKey(context.TODO(), env.gopts, []string{"list"}))
testRunCheck(t, env.gopts)
testRunKeyAddNewKeyUserHost(t, env.gopts)
}
type emptySaveBackend struct {
restic.Backend
}
func (b *emptySaveBackend) Save(ctx context.Context, h restic.Handle, _ restic.RewindReader) error {
return b.Backend.Save(ctx, h, restic.NewByteReader([]byte{}, nil))
}
func TestKeyProblems(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testRunInit(t, env.gopts)
env.gopts.backendTestHook = func(r restic.Backend) (restic.Backend, error) {
return &emptySaveBackend{r}, nil
}
testKeyNewPassword = "geheim2"
defer func() {
testKeyNewPassword = ""
}()
err := runKey(context.TODO(), env.gopts, []string{"passwd"})
t.Log(err)
rtest.Assert(t, err != nil, "expected passwd change to fail")
err = runKey(context.TODO(), env.gopts, []string{"add"})
t.Log(err)
rtest.Assert(t, err != nil, "expected key adding to fail")
t.Logf("testing access with initial password %q\n", env.gopts.password)
rtest.OK(t, runKey(context.TODO(), env.gopts, []string{"list"}))
testRunCheck(t, env.gopts)
}

View File

@@ -31,19 +31,19 @@ func init() {
cmdRoot.AddCommand(cmdList)
}
func runList(ctx context.Context, cmd *cobra.Command, opts GlobalOptions, args []string) error {
func runList(ctx context.Context, cmd *cobra.Command, gopts GlobalOptions, args []string) error {
if len(args) != 1 {
return errors.Fatal("type not specified, usage: " + cmd.Use)
}
repo, err := OpenRepository(ctx, opts)
repo, err := OpenRepository(ctx, gopts)
if err != nil {
return err
}
if !opts.NoLock && args[0] != "locks" {
if !gopts.NoLock && args[0] != "locks" {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo)
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -63,7 +63,7 @@ func runList(ctx context.Context, cmd *cobra.Command, opts GlobalOptions, args [
case "locks":
t = restic.LockFile
case "blobs":
return index.ForAllIndexes(ctx, repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
return index.ForAllIndexes(ctx, repo.Backend(), repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
if err != nil {
return err
}

View File

@@ -0,0 +1,44 @@
package main
import (
"bufio"
"context"
"io"
"testing"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func testRunList(t testing.TB, tpe string, opts GlobalOptions) restic.IDs {
buf, err := withCaptureStdout(func() error {
return runList(context.TODO(), cmdList, opts, []string{tpe})
})
rtest.OK(t, err)
return parseIDsFromReader(t, buf)
}
func parseIDsFromReader(t testing.TB, rd io.Reader) restic.IDs {
t.Helper()
IDs := restic.IDs{}
sc := bufio.NewScanner(rd)
for sc.Scan() {
id, err := restic.ParseID(sc.Text())
if err != nil {
t.Logf("parse id %v: %v", sc.Text(), err)
continue
}
IDs = append(IDs, id)
}
return IDs
}
func testListSnapshots(t testing.TB, opts GlobalOptions, expected int) restic.IDs {
t.Helper()
snapshotIDs := testRunList(t, "snapshots", opts)
rtest.Assert(t, len(snapshotIDs) == expected, "expected %v snapshot, got %v", expected, snapshotIDs)
return snapshotIDs
}

View File

@@ -50,7 +50,8 @@ Exit status is 0 if the command was successful, and non-zero if there was any er
type LsOptions struct {
ListLong bool
restic.SnapshotFilter
Recursive bool
Recursive bool
HumanReadable bool
}
var lsOptions LsOptions
@@ -62,6 +63,7 @@ func init() {
initSingleSnapshotFilter(flags, &lsOptions.SnapshotFilter)
flags.BoolVarP(&lsOptions.ListLong, "long", "l", false, "use a long listing format showing size and mode")
flags.BoolVar(&lsOptions.Recursive, "recursive", false, "include files in subfolders of the listed directories")
flags.BoolVar(&lsOptions.HumanReadable, "human-readable", false, "print sizes in human readable format")
}
type lsSnapshot struct {
@@ -85,6 +87,7 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
ModTime time.Time `json:"mtime,omitempty"`
AccessTime time.Time `json:"atime,omitempty"`
ChangeTime time.Time `json:"ctime,omitempty"`
Inode uint64 `json:"inode,omitempty"`
StructType string `json:"struct_type"` // "node"
size uint64 // Target for Size pointer.
@@ -100,6 +103,7 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
ModTime: node.ModTime,
AccessTime: node.AccessTime,
ChangeTime: node.ChangeTime,
Inode: node.Inode,
StructType: "node",
}
// Always print size for regular files, even when empty,
@@ -171,7 +175,8 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
return err
}
if err = repo.LoadIndex(ctx); err != nil {
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
if err = repo.LoadIndex(ctx, bar); err != nil {
return err
}
@@ -181,7 +186,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
)
if gopts.JSON {
enc := json.NewEncoder(gopts.stdout)
enc := json.NewEncoder(globalOptions.stdout)
printSnapshot = func(sn *restic.Snapshot) {
err := enc.Encode(lsSnapshot{
@@ -206,11 +211,11 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
Verbosef("snapshot %s of %v filtered by %v at %s):\n", sn.ID().Str(), sn.Paths, dirs, sn.Time)
}
printNode = func(path string, node *restic.Node) {
Printf("%s\n", formatNode(path, node, lsOptions.ListLong))
Printf("%s\n", formatNode(path, node, lsOptions.ListLong, lsOptions.HumanReadable))
}
}
sn, err := (&restic.SnapshotFilter{
sn, subfolder, err := (&restic.SnapshotFilter{
Hosts: opts.Hosts,
Paths: opts.Paths,
Tags: opts.Tags,
@@ -219,6 +224,11 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
return err
}
sn.Tree, err = restic.FindTreeDirectory(ctx, repo, sn.Tree, subfolder)
if err != nil {
return err
}
printSnapshot(sn)
err = walker.Walk(ctx, repo, *sn.Tree, nil, func(_ restic.ID, nodepath string, node *restic.Node, err error) (bool, error) {

View File

@@ -0,0 +1,19 @@
package main
import (
"context"
"strings"
"testing"
rtest "github.com/restic/restic/internal/test"
)
func testRunLs(t testing.TB, gopts GlobalOptions, snapshotID string) []string {
buf, err := withCaptureStdout(func() error {
gopts.Quiet = true
opts := LsOptions{}
return runLs(context.TODO(), opts, gopts, []string{snapshotID})
})
rtest.OK(t, err)
return strings.Split(buf.String(), "\n")
}

View File

@@ -122,7 +122,7 @@ func runMigrate(ctx context.Context, opts MigrateOptions, gopts GlobalOptions, a
return err
}
lock, ctx, err := lockRepoExclusive(ctx, repo)
lock, ctx, err := lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err

View File

@@ -123,14 +123,15 @@ func runMount(ctx context.Context, opts MountOptions, gopts GlobalOptions, args
if !gopts.NoLock {
var lock *restic.Lock
lock, ctx, err = lockRepo(ctx, repo)
lock, ctx, err = lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
}
}
err = repo.LoadIndex(ctx)
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
err = repo.LoadIndex(ctx, bar)
if err != nil {
return err
}

View File

@@ -12,6 +12,7 @@ import (
"testing"
"time"
"github.com/restic/restic/internal/debug"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
@@ -63,7 +64,7 @@ func testRunMount(t testing.TB, gopts GlobalOptions, dir string, wg *sync.WaitGr
rtest.OK(t, runMount(context.TODO(), opts, gopts, []string{dir}))
}
func testRunUmount(t testing.TB, gopts GlobalOptions, dir string) {
func testRunUmount(t testing.TB, dir string) {
var err error
for i := 0; i < mountWait; i++ {
if err = umount(dir); err == nil {
@@ -94,7 +95,7 @@ func checkSnapshots(t testing.TB, global GlobalOptions, repo *repository.Reposit
go testRunMount(t, global, mountpoint, &wg)
waitForMount(t, mountpoint)
defer wg.Wait()
defer testRunUmount(t, global, mountpoint)
defer testRunUmount(t, mountpoint)
if !snapshotsDirExists(t, mountpoint) {
t.Fatal(`virtual directory "snapshots" doesn't exist`)
@@ -159,6 +160,11 @@ func TestMount(t *testing.T) {
t.Skip("Skipping fuse tests")
}
debugEnabled := debug.TestLogToStderr(t)
if debugEnabled {
defer debug.TestDisableLog(t)
}
env, cleanup := withTestEnvironment(t)
// must list snapshots more than once
env.gopts.backendTestHook = nil

View File

@@ -3,6 +3,7 @@ package main
import (
"context"
"math"
"runtime"
"sort"
"strconv"
"strings"
@@ -80,7 +81,7 @@ func addPruneOptions(c *cobra.Command) {
func verifyPruneOptions(opts *PruneOptions) error {
opts.MaxRepackBytes = math.MaxUint64
if len(opts.MaxRepackSize) > 0 {
size, err := parseSizeStr(opts.MaxRepackSize)
size, err := ui.ParseBytes(opts.MaxRepackSize)
if err != nil {
return err
}
@@ -123,7 +124,7 @@ func verifyPruneOptions(opts *PruneOptions) error {
}
default:
size, err := parseSizeStr(maxUnused)
size, err := ui.ParseBytes(maxUnused)
if err != nil {
return errors.Fatalf("invalid number of bytes %q for --max-unused: %v", opts.MaxUnused, err)
}
@@ -167,7 +168,7 @@ func runPrune(ctx context.Context, opts PruneOptions, gopts GlobalOptions) error
opts.unsafeRecovery = true
}
lock, ctx, err := lockRepoExclusive(ctx, repo)
lock, ctx, err := lockRepoExclusive(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -186,7 +187,8 @@ func runPruneWithRepo(ctx context.Context, opts PruneOptions, gopts GlobalOption
Verbosef("loading indexes...\n")
// loading the index before the snapshots is ok, as we use an exclusive lock here
err := repo.LoadIndex(ctx)
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
err := repo.LoadIndex(ctx, bar)
if err != nil {
return err
}
@@ -205,6 +207,9 @@ func runPruneWithRepo(ctx context.Context, opts PruneOptions, gopts GlobalOption
return err
}
// Trigger GC to reset garbage collection threshold
runtime.GC()
return doPrune(ctx, opts, gopts, repo, plan)
}
@@ -488,7 +493,7 @@ func decidePackAction(ctx context.Context, opts PruneOptions, repo restic.Reposi
// Pack size does not fit and pack is needed => error
// If the pack is not needed, this is no error, the pack can
// and will be simply removed, see below.
Warnf("pack %s: calculated size %d does not match real size %d\nRun 'restic rebuild-index'.\n",
Warnf("pack %s: calculated size %d does not match real size %d\nRun 'restic repair index'.\n",
id.Str(), p.unusedSize+p.usedSize, packSize)
return errorSizeNotMatching
}
@@ -729,7 +734,7 @@ func doPrune(ctx context.Context, opts PruneOptions, gopts GlobalOptions, repo r
_, err := repository.Repack(ctx, repo, repo, plan.repackPacks, plan.keepBlobs, bar)
bar.Done()
if err != nil {
return errors.Fatalf("%s", err)
return errors.Fatal(err.Error())
}
// Also remove repacked packs

View File

@@ -0,0 +1,221 @@
package main
import (
"context"
"encoding/json"
"path/filepath"
"testing"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func testRunPrune(t testing.TB, gopts GlobalOptions, opts PruneOptions) {
oldHook := gopts.backendTestHook
gopts.backendTestHook = func(r restic.Backend) (restic.Backend, error) { return newListOnceBackend(r), nil }
defer func() {
gopts.backendTestHook = oldHook
}()
rtest.OK(t, runPrune(context.TODO(), opts, gopts))
}
func TestPrune(t *testing.T) {
testPruneVariants(t, false)
testPruneVariants(t, true)
}
func testPruneVariants(t *testing.T, unsafeNoSpaceRecovery bool) {
suffix := ""
if unsafeNoSpaceRecovery {
suffix = "-recovery"
}
t.Run("0"+suffix, func(t *testing.T) {
opts := PruneOptions{MaxUnused: "0%", unsafeRecovery: unsafeNoSpaceRecovery}
checkOpts := CheckOptions{ReadData: true, CheckUnused: true}
testPrune(t, opts, checkOpts)
})
t.Run("50"+suffix, func(t *testing.T) {
opts := PruneOptions{MaxUnused: "50%", unsafeRecovery: unsafeNoSpaceRecovery}
checkOpts := CheckOptions{ReadData: true}
testPrune(t, opts, checkOpts)
})
t.Run("unlimited"+suffix, func(t *testing.T) {
opts := PruneOptions{MaxUnused: "unlimited", unsafeRecovery: unsafeNoSpaceRecovery}
checkOpts := CheckOptions{ReadData: true}
testPrune(t, opts, checkOpts)
})
t.Run("CachableOnly"+suffix, func(t *testing.T) {
opts := PruneOptions{MaxUnused: "5%", RepackCachableOnly: true, unsafeRecovery: unsafeNoSpaceRecovery}
checkOpts := CheckOptions{ReadData: true}
testPrune(t, opts, checkOpts)
})
t.Run("Small", func(t *testing.T) {
opts := PruneOptions{MaxUnused: "unlimited", RepackSmall: true}
checkOpts := CheckOptions{ReadData: true, CheckUnused: true}
testPrune(t, opts, checkOpts)
})
}
func createPrunableRepo(t *testing.T, env *testEnvironment) {
testSetupBackupData(t, env)
opts := BackupOptions{}
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9")}, opts, env.gopts)
firstSnapshot := testListSnapshots(t, env.gopts, 1)[0]
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "2")}, opts, env.gopts)
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "3")}, opts, env.gopts)
testListSnapshots(t, env.gopts, 3)
testRunForgetJSON(t, env.gopts)
testRunForget(t, env.gopts, firstSnapshot.String())
}
func testRunForgetJSON(t testing.TB, gopts GlobalOptions, args ...string) {
buf, err := withCaptureStdout(func() error {
gopts.JSON = true
opts := ForgetOptions{
DryRun: true,
Last: 1,
}
return runForget(context.TODO(), opts, gopts, args)
})
rtest.OK(t, err)
var forgets []*ForgetGroup
rtest.OK(t, json.Unmarshal(buf.Bytes(), &forgets))
rtest.Assert(t, len(forgets) == 1,
"Expected 1 snapshot group, got %v", len(forgets))
rtest.Assert(t, len(forgets[0].Keep) == 1,
"Expected 1 snapshot to be kept, got %v", len(forgets[0].Keep))
rtest.Assert(t, len(forgets[0].Remove) == 2,
"Expected 2 snapshots to be removed, got %v", len(forgets[0].Remove))
}
func testPrune(t *testing.T, pruneOpts PruneOptions, checkOpts CheckOptions) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
createPrunableRepo(t, env)
testRunPrune(t, env.gopts, pruneOpts)
rtest.OK(t, runCheck(context.TODO(), checkOpts, env.gopts, nil))
}
var pruneDefaultOptions = PruneOptions{MaxUnused: "5%"}
func TestPruneWithDamagedRepository(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
datafile := filepath.Join("testdata", "backup-data.tar.gz")
testRunInit(t, env.gopts)
rtest.SetupTarTestFixture(t, env.testdata, datafile)
opts := BackupOptions{}
// create and delete snapshot to create unused blobs
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "2")}, opts, env.gopts)
firstSnapshot := testListSnapshots(t, env.gopts, 1)[0]
testRunForget(t, env.gopts, firstSnapshot.String())
oldPacks := listPacks(env.gopts, t)
// create new snapshot, but lose all data
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "3")}, opts, env.gopts)
testListSnapshots(t, env.gopts, 1)
removePacksExcept(env.gopts, t, oldPacks, false)
oldHook := env.gopts.backendTestHook
env.gopts.backendTestHook = func(r restic.Backend) (restic.Backend, error) { return newListOnceBackend(r), nil }
defer func() {
env.gopts.backendTestHook = oldHook
}()
// prune should fail
rtest.Assert(t, runPrune(context.TODO(), pruneDefaultOptions, env.gopts) == errorPacksMissing,
"prune should have reported index not complete error")
}
// Test repos for edge cases
func TestEdgeCaseRepos(t *testing.T) {
opts := CheckOptions{}
// repo where index is completely missing
// => check and prune should fail
t.Run("no-index", func(t *testing.T) {
testEdgeCaseRepo(t, "repo-index-missing.tar.gz", opts, pruneDefaultOptions, false, false)
})
// repo where an existing and used blob is missing from the index
// => check and prune should fail
t.Run("index-missing-blob", func(t *testing.T) {
testEdgeCaseRepo(t, "repo-index-missing-blob.tar.gz", opts, pruneDefaultOptions, false, false)
})
// repo where a blob is missing
// => check and prune should fail
t.Run("missing-data", func(t *testing.T) {
testEdgeCaseRepo(t, "repo-data-missing.tar.gz", opts, pruneDefaultOptions, false, false)
})
// repo where blobs which are not needed are missing or in invalid pack files
// => check should fail and prune should repair this
t.Run("missing-unused-data", func(t *testing.T) {
testEdgeCaseRepo(t, "repo-unused-data-missing.tar.gz", opts, pruneDefaultOptions, false, true)
})
// repo where data exists that is not referenced
// => check and prune should fully work
t.Run("unreferenced-data", func(t *testing.T) {
testEdgeCaseRepo(t, "repo-unreferenced-data.tar.gz", opts, pruneDefaultOptions, true, true)
})
// repo where an obsolete index still exists
// => check and prune should fully work
t.Run("obsolete-index", func(t *testing.T) {
testEdgeCaseRepo(t, "repo-obsolete-index.tar.gz", opts, pruneDefaultOptions, true, true)
})
// repo which contains mixed (data/tree) packs
// => check and prune should fully work
t.Run("mixed-packs", func(t *testing.T) {
testEdgeCaseRepo(t, "repo-mixed.tar.gz", opts, pruneDefaultOptions, true, true)
})
// repo which contains duplicate blobs
// => checking for unused data should report an error and prune resolves the
// situation
opts = CheckOptions{
ReadData: true,
CheckUnused: true,
}
t.Run("duplicates", func(t *testing.T) {
testEdgeCaseRepo(t, "repo-duplicates.tar.gz", opts, pruneDefaultOptions, false, true)
})
}
func testEdgeCaseRepo(t *testing.T, tarfile string, optionsCheck CheckOptions, optionsPrune PruneOptions, checkOK, pruneOK bool) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
datafile := filepath.Join("testdata", tarfile)
rtest.SetupTarTestFixture(t, env.base, datafile)
if checkOK {
testRunCheck(t, env.gopts)
} else {
rtest.Assert(t, runCheck(context.TODO(), optionsCheck, env.gopts, nil) != nil,
"check should have reported an error")
}
if pruneOK {
testRunPrune(t, env.gopts, optionsPrune)
testRunCheck(t, env.gopts)
} else {
rtest.Assert(t, runPrune(context.TODO(), optionsPrune, env.gopts) != nil,
"prune should have reported an error")
}
}

View File

@@ -46,7 +46,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions) error {
return err
}
lock, ctx, err := lockRepo(ctx, repo)
lock, ctx, err := lockRepo(ctx, repo, gopts.RetryLock, gopts.JSON)
defer unlockRepo(lock)
if err != nil {
return err
@@ -58,7 +58,8 @@ func runRecover(ctx context.Context, gopts GlobalOptions) error {
}
Verbosef("load index files\n")
if err = repo.LoadIndex(ctx); err != nil {
bar := newIndexProgress(gopts.Quiet, gopts.JSON)
if err = repo.LoadIndex(ctx, bar); err != nil {
return err
}
@@ -73,7 +74,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions) error {
})
Verbosef("load %d trees\n", len(trees))
bar := newProgressMax(!gopts.Quiet, uint64(len(trees)), "trees loaded")
bar = newProgressMax(!gopts.Quiet, uint64(len(trees)), "trees loaded")
for id := range trees {
tree, err := restic.LoadTree(ctx, repo, id)
if err != nil {

14
cmd/restic/cmd_repair.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import (
"github.com/spf13/cobra"
)
var cmdRepair = &cobra.Command{
Use: "repair",
Short: "Repair the repository",
}
func init() {
cmdRoot.AddCommand(cmdRepair)
}

Some files were not shown because too many files have changed in this diff Show More