mirror of
https://github.com/restic/restic.git
synced 2025-12-11 18:21:54 +00:00
Merge pull request #5491 from MichaelEischer/patch-release-cherrypicks
Patch release cherrypicks
This commit is contained in:
4
.github/workflows/docker.yml
vendored
4
.github/workflows/docker.yml
vendored
@@ -26,10 +26,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
|
||||
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
|
||||
8
.github/workflows/tests.yml
vendored
8
.github/workflows/tests.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Go ${{ matrix.go }}
|
||||
uses: actions/setup-go@v5
|
||||
@@ -220,7 +220,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Go ${{ env.latest_go }}
|
||||
uses: actions/setup-go@v5
|
||||
@@ -242,7 +242,7 @@ jobs:
|
||||
checks: write
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Go ${{ env.latest_go }}
|
||||
uses: actions/setup-go@v5
|
||||
@@ -287,7 +287,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
|
||||
10
CHANGELOG.md
10
CHANGELOG.md
@@ -54,7 +54,7 @@ restic users. The changes are ordered by importance.
|
||||
* Fix #5249: Fix creation of oversized index by `repair index --read-all-packs`
|
||||
* Fix #5259: Fix rare crash in command output
|
||||
* Chg #4938: Update dependencies and require Go 1.23 or newer
|
||||
* Chg #5162: Promote feature flags
|
||||
* Chg #5162: Graduate feature flags
|
||||
* Enh #1378: Add JSON support to `check` command
|
||||
* Enh #2511: Support generating shell completions to stdout
|
||||
* Enh #3697: Allow excluding online-only cloud files (e.g. OneDrive)
|
||||
@@ -76,7 +76,7 @@ restic users. The changes are ordered by importance.
|
||||
* Enh #5173: Add experimental S3 cold storage support
|
||||
* Enh #5174: Add xattr support for NetBSD 10+
|
||||
* Enh #5251: Improve retry handling for flaky `rclone` backends
|
||||
* Enh #52897: Make `recover` automatically rebuild index when needed
|
||||
* Enh #5287: Make `recover` automatically rebuild index when needed
|
||||
|
||||
## Details
|
||||
|
||||
@@ -208,7 +208,7 @@ restic users. The changes are ordered by importance.
|
||||
|
||||
https://github.com/restic/restic/pull/4938
|
||||
|
||||
* Change #5162: Promote feature flags
|
||||
* Change #5162: Graduate feature flags
|
||||
|
||||
The `deprecate-legacy-index`, `deprecate-s3-legacy-layout`,
|
||||
`explicit-s3-anonymous-auth` and `safe-forget-keep-tags` features are now stable
|
||||
@@ -408,13 +408,13 @@ restic users. The changes are ordered by importance.
|
||||
|
||||
https://github.com/restic/restic/pull/5251
|
||||
|
||||
* Enhancement #52897: Make `recover` automatically rebuild index when needed
|
||||
* Enhancement #5287: Make `recover` automatically rebuild index when needed
|
||||
|
||||
When trying to recover data from an interrupted snapshot, it was previously
|
||||
necessary to manually run `repair index` before runnning `recover`. This now
|
||||
happens automatically so that only `recover` is necessary.
|
||||
|
||||
https://github.com/restic/restic/issues/52897
|
||||
https://github.com/restic/restic/issues/5287
|
||||
https://github.com/restic/restic/pull/5296
|
||||
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@ When trying to recover data from an interrupted snapshot, it was previously
|
||||
necessary to manually run `repair index` before runnning `recover`. This now
|
||||
happens automatically so that only `recover` is necessary.
|
||||
|
||||
https://github.com/restic/restic/issues/52897
|
||||
https://github.com/restic/restic/issues/5287
|
||||
https://github.com/restic/restic/pull/5296
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Change: Promote feature flags
|
||||
Change: Graduate feature flags
|
||||
|
||||
The `deprecate-legacy-index`, `deprecate-s3-legacy-layout`,
|
||||
`explicit-s3-anonymous-auth` and `safe-forget-keep-tags` features are
|
||||
|
||||
14
changelog/unreleased/issue-5324
Normal file
14
changelog/unreleased/issue-5324
Normal file
@@ -0,0 +1,14 @@
|
||||
Bugfix: Correctly handle `backup --stdin-filename` with directories
|
||||
|
||||
In restic 0.18.0, the `backup` command failed if a filename that includes
|
||||
a least a directory was passed to `--stdin-filename`. For example,
|
||||
`--stdin-filename /foo/bar` resulted in the following error:
|
||||
|
||||
```
|
||||
Fatal: unable to save snapshot: open /foo: no such file or directory
|
||||
```
|
||||
|
||||
This has been fixed now.
|
||||
|
||||
https://github.com/restic/restic/issues/5324
|
||||
https://github.com/restic/restic/pull/5356
|
||||
7
changelog/unreleased/issue-5325
Normal file
7
changelog/unreleased/issue-5325
Normal file
@@ -0,0 +1,7 @@
|
||||
Bugfix: Correctly handle `RESTIC_HOST` in `forget` command
|
||||
|
||||
The `forget` command did not use the host name from the `RESTIC_HOST`
|
||||
environment variable. This has been fixed.
|
||||
|
||||
https://github.com/restic/restic/issues/5325
|
||||
https://github.com/restic/restic/pull/5327
|
||||
7
changelog/unreleased/issue-5342
Normal file
7
changelog/unreleased/issue-5342
Normal file
@@ -0,0 +1,7 @@
|
||||
Bugfix: Ignore "chmod not supported" errors when writing files
|
||||
|
||||
Restic 0.18.0 introduced a bug that caused "chmod xxx: operation not supported"
|
||||
errors to appear when writing to a local file repository that did not support
|
||||
chmod (like CIFS or WebDAV mounted via FUSE). Restic now ignores those errors.
|
||||
|
||||
https://github.com/restic/restic/issues/5342
|
||||
7
changelog/unreleased/issue-5344
Normal file
7
changelog/unreleased/issue-5344
Normal file
@@ -0,0 +1,7 @@
|
||||
Bugfix: Ignore EOPNOTSUPP as an error for xattr
|
||||
|
||||
Restic 0.18.0 added xattr support for NetBSD 10+, but not all NetBSD
|
||||
filesystems support xattrs. Other BSD systems can likewise return
|
||||
EOPNOTSUPP, so restic now simply ignores EOPNOTSUPP errors for xattrs.
|
||||
|
||||
https://github.com/restic/restic/issues/5344
|
||||
8
changelog/unreleased/issue-5429
Normal file
8
changelog/unreleased/issue-5429
Normal file
@@ -0,0 +1,8 @@
|
||||
Bugfix: do not retry if rest-server runs out of space
|
||||
|
||||
Rest-server return error `507 Insufficient Storage` if no more storage
|
||||
capacity is available at the server. Restic now no longer retries uploads
|
||||
in this case.
|
||||
|
||||
https://github.com/restic/restic/issues/5429
|
||||
https://github.com/restic/restic/pull/5452
|
||||
8
changelog/unreleased/pull-5421
Normal file
8
changelog/unreleased/pull-5421
Normal file
@@ -0,0 +1,8 @@
|
||||
Bugfix: Fix rare crash if directory is removed during backup
|
||||
|
||||
In restic 0.18.0, the `backup` command could crash if a directory is removed
|
||||
inbetween reading its metadata and listing its directory content.
|
||||
|
||||
This has been fixed.
|
||||
|
||||
https://github.com/restic/restic/pull/5421
|
||||
@@ -591,11 +591,12 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
|
||||
return err
|
||||
}
|
||||
}
|
||||
targetFS = &fs.Reader{
|
||||
ModTime: timeStamp,
|
||||
Name: filename,
|
||||
Mode: 0644,
|
||||
ReadCloser: source,
|
||||
targetFS, err = fs.NewReader(filename, source, fs.ReaderOptions{
|
||||
ModTime: timeStamp,
|
||||
Mode: 0644,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to backup from stdin: %w", err)
|
||||
}
|
||||
targets = []string{filename}
|
||||
}
|
||||
|
||||
@@ -632,12 +632,15 @@ func TestStdinFromCommand(t *testing.T) {
|
||||
|
||||
testSetupBackupData(t, env)
|
||||
opts := BackupOptions{
|
||||
StdinCommand: true,
|
||||
StdinFilename: "stdin",
|
||||
StdinCommand: true,
|
||||
// test that subdirectories are handled correctly
|
||||
StdinFilename: "stdin/subdir/file",
|
||||
}
|
||||
|
||||
testRunBackup(t, filepath.Dir(env.testdata), []string{"python", "-c", "import sys; print('something'); sys.exit(0)"}, opts, env.gopts)
|
||||
testListSnapshots(t, env.gopts, 1)
|
||||
snapshots := testListSnapshots(t, env.gopts, 1)
|
||||
files := testRunLs(t, env.gopts, snapshots[0].String())
|
||||
rtest.Assert(t, includes(files, "/stdin/subdir/file"), "file %q missing from snapshot, got %v", "stdin/subdir/file", files)
|
||||
|
||||
testRunCheck(t, env.gopts)
|
||||
}
|
||||
|
||||
@@ -137,13 +137,14 @@ func (opts *ForgetOptions) AddFlags(f *pflag.FlagSet) {
|
||||
f.Var(&opts.KeepTags, "keep-tag", "keep snapshots with this `taglist` (can be specified multiple times)")
|
||||
f.BoolVar(&opts.UnsafeAllowRemoveAll, "unsafe-allow-remove-all", false, "allow deleting all snapshots of a snapshot group")
|
||||
|
||||
initMultiSnapshotFilter(f, &opts.SnapshotFilter, false)
|
||||
f.StringArrayVar(&opts.Hosts, "hostname", nil, "only consider snapshots with the given `hostname` (can be specified multiple times)")
|
||||
err := f.MarkDeprecated("hostname", "use --host")
|
||||
if err != nil {
|
||||
// MarkDeprecated only returns an error when the flag is not found
|
||||
panic(err)
|
||||
}
|
||||
// must be defined after `--hostname` to not override the default value from the environment
|
||||
initMultiSnapshotFilter(f, &opts.SnapshotFilter, false)
|
||||
|
||||
f.BoolVarP(&opts.Compact, "compact", "c", false, "use compact output format")
|
||||
opts.GroupBy = restic.SnapshotGroupByOptions{Host: true, Path: true}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/restic/restic/internal/restic"
|
||||
rtest "github.com/restic/restic/internal/test"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func TestForgetPolicyValues(t *testing.T) {
|
||||
@@ -92,3 +93,10 @@ func TestForgetOptionValues(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestForgetHostnameDefaulting(t *testing.T) {
|
||||
t.Setenv("RESTIC_HOST", "testhost")
|
||||
opts := ForgetOptions{}
|
||||
opts.AddFlags(pflag.NewFlagSet("test", pflag.ContinueOnError))
|
||||
rtest.Equals(t, []string{"testhost"}, opts.Hosts)
|
||||
}
|
||||
|
||||
@@ -30,14 +30,12 @@ func registerProfiling(cmd *cobra.Command) {
|
||||
return profiler.Start(profiler.opts)
|
||||
}
|
||||
|
||||
origPostRun := cmd.PersistentPostRunE
|
||||
cmd.PersistentPostRunE = func(cmd *cobra.Command, args []string) error {
|
||||
// Once https://github.com/spf13/cobra/issues/1893 is fixed,
|
||||
// this could use PersistentPostRunE instead of OnFinalize,
|
||||
// reverting https://github.com/restic/restic/pull/5373.
|
||||
cobra.OnFinalize(func() {
|
||||
profiler.Stop()
|
||||
if origPostRun != nil {
|
||||
return origPostRun(cmd, args)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
})
|
||||
|
||||
profiler.opts.AddFlags(cmd.PersistentFlags())
|
||||
}
|
||||
|
||||
@@ -74,6 +74,16 @@ avoid any conflicts:
|
||||
|
||||
$ dnf copr remove copart/restic
|
||||
|
||||
Gentoo Linux
|
||||
============
|
||||
|
||||
On `Gentoo Linux <https://www.gentoo.org/>`__, you can install the ``restic``
|
||||
package from the official repos using ``emerge``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
# emerge restic
|
||||
|
||||
macOS
|
||||
=====
|
||||
|
||||
@@ -175,15 +185,19 @@ restic can be installed from the official repo of Solus via the ``eopkg`` packag
|
||||
Windows
|
||||
=======
|
||||
|
||||
restic can be installed using `Scoop <https://scoop.sh/>`__:
|
||||
restic can be installed using either `Scoop <https://scoop.sh/>`__ or `WinGet <https://learn.microsoft.com/en-us/windows/package-manager/>`__.
|
||||
|
||||
Regardless of the method, the ``restic.exe`` binary will be added to your ``PATH`` automatically, making the ``restic`` command accessible in Powershell or CMD.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
scoop install restic
|
||||
|
||||
Using this installation method, ``restic.exe`` will automatically be available
|
||||
in the ``PATH``. It can be called from cmd.exe or PowerShell by typing ``restic``.
|
||||
.. code-block:: console
|
||||
|
||||
winget install --exact --id restic.restic --scope Machine
|
||||
|
||||
By default, WinGet will install restic into the ``User`` scope, which is typically in your user's ``%LOCALAPPDATA%`` directory. This behavior may be undesirable for system-wide backups, so specifying ``--scope Machine`` is recommended so that restic is installed into ``%ProgramFiles%``. This requires elevation.
|
||||
|
||||
.. _official_binaries:
|
||||
|
||||
@@ -253,13 +267,6 @@ the `restic beta download site
|
||||
and ready to run, and a new version is built every time a push is made to the
|
||||
master branch.
|
||||
|
||||
Windows
|
||||
=======
|
||||
|
||||
On Windows, put the `restic.exe` binary into `%SystemRoot%\\System32` to use restic
|
||||
in scripts without the need for absolute paths to the binary. This requires
|
||||
administrator rights.
|
||||
|
||||
Docker Container
|
||||
****************
|
||||
|
||||
|
||||
@@ -349,7 +349,7 @@ Wasabi
|
||||
|
||||
S3 storage from `Wasabi <https://wasabi.com>`__ can be used as follows.
|
||||
|
||||
- Determine the correct Wasabi service URL for your bucket `here <https://wasabi-support.zendesk.com/hc/en-us/articles/360015106031-What-are-the-service-URLs-for-Wasabi-s-different-regions->`__.
|
||||
- Determine the correct Wasabi service URL for your bucket `here <https://docs.wasabi.com/v1/docs/what-are-the-service-urls-for-wasabi-s-different-storage-regions>`__.
|
||||
- Set environment variables with the necessary account credentials
|
||||
|
||||
.. code-block:: console
|
||||
@@ -854,6 +854,6 @@ with an empty password, use the following command.
|
||||
restic init --insecure-no-password
|
||||
|
||||
|
||||
The ``init`` and ``copy`` command also support the option ``--from-insecure-no-password``
|
||||
The ``init`` and ``copy`` commands also support the option ``--from-insecure-no-password``
|
||||
which applies to the source repository. The ``key add`` and ``key passwd`` commands
|
||||
include the ``--new-insecure-no-password`` option to add or set and empty password.
|
||||
include the ``--new-insecure-no-password`` option to add or set an empty password.
|
||||
|
||||
@@ -346,9 +346,10 @@ A trailing ``/`` is ignored, a leading ``/`` anchors the pattern at the root dir
|
||||
This means, ``/bin`` matches ``/bin/bash`` but does not match ``/usr/bin/restic``.
|
||||
|
||||
Regular wildcards cannot be used to match over the directory separator ``/``,
|
||||
e.g. ``b*ash`` matches ``/bin/bash`` but does not match ``/bin/ash``. For this,
|
||||
the special wildcard ``**`` can be used to match arbitrary sub-directories: The
|
||||
pattern ``foo/**/bar`` matches:
|
||||
e.g. ``b*ash`` matches ``/bin/bash`` but does not match ``/bin/ash``. To match
|
||||
across an arbitrary number of subdirectories, use the special ``**`` wildcard.
|
||||
The ``**`` must be positioned between path separators. The pattern
|
||||
``foo/**/bar`` matches:
|
||||
|
||||
* ``/dir1/foo/dir2/bar/file``
|
||||
* ``/foo/bar/file``
|
||||
|
||||
@@ -297,7 +297,7 @@ Note that it is not possible to change the chunker parameters of an existing rep
|
||||
Removing files from snapshots
|
||||
=============================
|
||||
|
||||
Snapshots sometimes turn out to include more files that intended. Instead of
|
||||
Snapshots sometimes turn out to include more files than intended. Instead of
|
||||
removing the snapshots entirely and running the corresponding backup commands
|
||||
again (which is not always practical after the fact) it is possible to remove
|
||||
the unwanted files from affected snapshots by rewriting them using the
|
||||
@@ -338,8 +338,8 @@ the only fields added are ``TotalFilesProcessed`` and ``TotalBytesProcessed``.
|
||||
|
||||
By default, the ``rewrite`` command will keep the original snapshots and create
|
||||
new ones for every snapshot which was modified during rewriting. The new
|
||||
snapshots are marked with the tag ``rewrite`` to differentiate them from the
|
||||
original, rewritten snapshots.
|
||||
snapshots are marked with the tag ``rewrite`` to distinguish them from the
|
||||
original, untouched snapshots.
|
||||
|
||||
Alternatively, you can use the ``--forget`` option to immediately remove the
|
||||
original snapshots. In this case, no tag is added to the new snapshots. Please
|
||||
|
||||
@@ -34,11 +34,12 @@ Backend Connections
|
||||
|
||||
Restic uses a global limit for the number of concurrent connections to a backend.
|
||||
This limit can be configured using ``-o <backend-name>.connections=5``, for example for
|
||||
the REST backend the parameter would be ``-o rest.connections=5``. By default restic uses
|
||||
``5`` connections for each backend, except for the local backend which uses a limit of ``2``.
|
||||
The defaults should work well in most cases. For high-latency backends it can be beneficial
|
||||
to increase the number of connections. Please be aware that this increases the resource
|
||||
consumption of restic and that a too high connection count *will degrade performance*.
|
||||
the REST backend the parameter would be ``-o rest.connections=5`` or for the local backend
|
||||
``-o local.connections=2``. By default restic uses ``5`` connections for each backend,
|
||||
except for the local backend which uses a limit of ``2``. The defaults should work well in
|
||||
most cases. For high-latency backends it can be beneficial to increase the number of
|
||||
connections. Please be aware that this increases the resource consumption of restic and
|
||||
that a too high connection count *will degrade performance*.
|
||||
|
||||
|
||||
CPU Usage
|
||||
|
||||
@@ -71,8 +71,17 @@ The program can be built with debug support like this:
|
||||
$ go run build.go -tags debug
|
||||
|
||||
This will make the ``restic debug <subcommand>`` available which can be used to
|
||||
inspect internal data structures. In addition, this enables profiling support
|
||||
which can help with investigation performance and memory usage issues.
|
||||
inspect internal data structures.
|
||||
|
||||
In addition, this enables profiling flags such as ``--cpu-profile`` and
|
||||
``--mem-profile`` which can help with investigation performance and memory usage
|
||||
issues. See ``restic help`` for more details and a few additional
|
||||
``--...-profile`` flags.
|
||||
|
||||
Running Restic with profiling enabled generates a ``.pprof`` file such as
|
||||
``cpu.pprof``. To view a profile in a web browser, first make sure that the
|
||||
``dot`` command from `Graphviz <https://graphviz.org/>`__ is in the PATH. Then,
|
||||
run ``go tool pprof -http : cpu.pprof``.
|
||||
|
||||
|
||||
************
|
||||
|
||||
@@ -18,7 +18,7 @@ depends on the following things:
|
||||
* The path to the Go workspace (``GOPATH=/home/build/go``)
|
||||
* Other environment variables (mostly ``$GOOS``, ``$GOARCH``, ``$CGO_ENABLED``)
|
||||
|
||||
In addition, The compressed ZIP files for Windows depends on the modification
|
||||
In addition, the compressed ZIP files for Windows depends on the modification
|
||||
timestamp and filename of the binary contained in it. In order to reproduce the
|
||||
exact same ZIP file every time, we update the timestamp of the file ``VERSION``
|
||||
in the source code archive and set the timezone to Europe/Berlin.
|
||||
@@ -52,10 +52,10 @@ In the following example, we'll use the file ``restic-0.14.0.tar.gz`` and Go
|
||||
$ go version
|
||||
go version go1.19 linux/amd64
|
||||
|
||||
$ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -tags selfupdate -o restic_linux_amd64 ./cmd/restic
|
||||
$ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -tags selfupdate,disable_grpc_modules -o restic_linux_amd64 ./cmd/restic
|
||||
$ bzip2 restic_linux_amd64
|
||||
|
||||
$ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -tags selfupdate -o restic_0.14.0_windows_amd64.exe ./cmd/restic
|
||||
$ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -tags selfupdate,disable_grpc_modules -o restic_0.14.0_windows_amd64.exe ./cmd/restic
|
||||
$ touch --reference VERSION restic_0.14.0_windows_amd64.exe
|
||||
$ TZ=Europe/Berlin zip -q -X restic_0.14.0_windows_amd64.zip restic_0.14.0_windows_amd64.exe
|
||||
|
||||
@@ -66,7 +66,7 @@ The released binaries for restic are built using a Docker container. You can
|
||||
find it on `Docker Hub <https://hub.docker.com/r/restic/builder>`__ as
|
||||
``restic/builder``, the ``Dockerfile`` and instructions on how to build the
|
||||
container can be found in the `GitHub repository
|
||||
<https://github.com/restic/builder>`__
|
||||
<https://github.com/restic/builder>`__.
|
||||
|
||||
The container serves the following goals:
|
||||
* Have a very controlled environment which is independent from the local system
|
||||
@@ -93,7 +93,7 @@ The following steps are necessary to build the binaries:
|
||||
|
||||
mkdir output
|
||||
|
||||
3. Mount the source code and the output directory in the container and run the default command, which starts ``helpers/build-release-binaries/main.go``:
|
||||
4. Mount the source code and the output directory in the container and run the default command, which starts ``helpers/build-release-binaries/main.go``:
|
||||
|
||||
.. code::
|
||||
|
||||
@@ -103,7 +103,7 @@ The following steps are necessary to build the binaries:
|
||||
restic/builder \
|
||||
go run helpers/build-release-binaries/main.go --version 0.14.0
|
||||
|
||||
4. If anything goes wrong, you can enable debug output like this:
|
||||
5. If anything goes wrong, you can enable debug output like this:
|
||||
|
||||
.. code::
|
||||
|
||||
@@ -114,7 +114,7 @@ The following steps are necessary to build the binaries:
|
||||
go run helpers/build-release-binaries/main.go --version 0.14.0 --verbose
|
||||
|
||||
Verifying SLSA Provenance for GHCR Docker Images
|
||||
*******************************************
|
||||
************************************************
|
||||
|
||||
Our Docker images in the GitHub Container Registry (GHCR) are built with SLSA
|
||||
(Supply-chain Levels for Software Artifacts) provenance.
|
||||
@@ -131,9 +131,8 @@ To verify this provenance:
|
||||
--source-uri github.com/restic/restic \
|
||||
<image-name>@<digest>
|
||||
|
||||
Replace `<tag>` with the Git tag of the release you're verifying, `<image-name>`
|
||||
with the full name of the Docker image (including the registry), and `<digest>`
|
||||
with the SHA256 digest of the image.
|
||||
Replace `<image-name>` with the full name of the Docker image (including the registry),
|
||||
and `<digest>` with the SHA256 digest of the image.
|
||||
|
||||
3. If the verification is successful, you'll see output indicating that the provenance
|
||||
is valid.
|
||||
@@ -146,7 +145,7 @@ Verifying the Official Binaries
|
||||
|
||||
To verify the official binaries, you can either build them yourself using the above
|
||||
instructions or use the ``helpers/verify-release-binaries.sh`` script from the restic
|
||||
repository. Run it as ``helpers/verify-release-binaries.sh restic_version go_version``.
|
||||
repository. Run it as ``helpers/verify-release-binaries.sh $restic_version $go_version``.
|
||||
The specified go compiler version must match the one used to build the official
|
||||
binaries. For example, for restic 0.16.2 the command would be
|
||||
``helpers/verify-release-binaries.sh 0.16.2 1.21.3``.
|
||||
|
||||
32
doc/faq.rst
32
doc/faq.rst
@@ -110,9 +110,8 @@ How can I specify encryption passwords automatically?
|
||||
When you run ``restic backup``, you need to enter the passphrase on
|
||||
the console. This is not very convenient for automated backups, so you
|
||||
can also provide the password through the ``--password-file`` option, or one of
|
||||
the environment variables ``RESTIC_PASSWORD`` or ``RESTIC_PASSWORD_FILE``.
|
||||
A discussion is in progress over implementing unattended backups happens in
|
||||
:issue:`533`.
|
||||
the environment variables: ``RESTIC_PASSWORD``, ``RESTIC_PASSWORD_FILE``,
|
||||
or ``RESTIC_PASSWORD_COMMAND``.
|
||||
|
||||
.. important:: Be careful how you set the environment; using the env
|
||||
command, a `system()` call or using inline shell
|
||||
@@ -124,10 +123,33 @@ A discussion is in progress over implementing unattended backups happens in
|
||||
`accessible only to that user`_. Please make sure that
|
||||
the permissions on the files where the password is
|
||||
eventually stored are safe (e.g. `0600` and owned by
|
||||
root).
|
||||
root). Note also that ``RESTIC_PASSWORD_COMMAND`` is
|
||||
safe because it does not export the password itself to
|
||||
the environment.
|
||||
|
||||
.. _accessible only to that user: https://security.stackexchange.com/questions/14000/environment-variable-accessibility-in-linux/14009#14009
|
||||
|
||||
On platforms with an available keychain, keyring or similar secret store, a
|
||||
user can add and then dynamically retrieve passwords, cloud credentials,
|
||||
repository paths, or any other data deemed sensitive. Here's an example of
|
||||
part of a shell script using the `built-in`_ ``security`` command on macOS
|
||||
to retrieve credentials from the system's Keychain before running various
|
||||
``restic`` commands:
|
||||
|
||||
.. _built-in: https://ss64.com/mac/security.html
|
||||
|
||||
::
|
||||
|
||||
export GOOGLE_PROJECT_ID=$(security find-generic-password -a resticGCS -s restic_project_ID -w)
|
||||
|
||||
export GOOGLE_APPLICATION_CREDENTIALS=$(security find-generic-password -a resticGCS -s restic_key -w)
|
||||
|
||||
export RESTIC_REPOSITORY=$(security find-generic-password -a resticGCS -s restic_repo_path -w)
|
||||
|
||||
export RESTIC_PASSWORD_COMMAND='security find-generic-password -a resticGCS -s restic_pwd -w'
|
||||
|
||||
|
||||
|
||||
How to prioritize restic's IO and CPU time
|
||||
------------------------------------------
|
||||
|
||||
@@ -253,7 +275,7 @@ Archive** storage classes is available:
|
||||
.. code-block:: console
|
||||
|
||||
$ restic backup -o s3.storage-class=GLACIER somedir/
|
||||
$ RESTIC_FEATURES=s3-restore restic restore -o s3.enable-restore=1 -o s3.restore-days=7 -o s3.restore-timeout=1d latest
|
||||
$ RESTIC_FEATURES=s3-restore restic restore -o s3.enable-restore=1 -o s3.restore-days=7 -o s3.restore-timeout=24h latest
|
||||
|
||||
**Notes:**
|
||||
|
||||
|
||||
89
go.mod
89
go.mod
@@ -8,9 +8,9 @@ godebug winsymlink=0
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.51.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2
|
||||
github.com/Backblaze/blazer v0.7.2
|
||||
github.com/Microsoft/go-winio v0.6.2
|
||||
github.com/anacrolix/fuse v0.3.1
|
||||
@@ -21,42 +21,42 @@ require (
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||
github.com/klauspost/compress v1.18.0
|
||||
github.com/minio/minio-go/v7 v7.0.88
|
||||
github.com/minio/minio-go/v7 v7.0.89
|
||||
github.com/ncw/swift/v2 v2.0.3
|
||||
github.com/peterbourgon/unixtransport v0.0.4
|
||||
github.com/peterbourgon/unixtransport v0.0.6
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/profile v1.7.0
|
||||
github.com/pkg/sftp v1.13.8
|
||||
github.com/pkg/sftp v1.13.9
|
||||
github.com/pkg/xattr v0.4.10
|
||||
github.com/restic/chunker v0.4.0
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/pflag v1.0.6
|
||||
go.uber.org/automaxprocs v1.6.0
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/net v0.37.0
|
||||
golang.org/x/oauth2 v0.28.0
|
||||
golang.org/x/sync v0.12.0
|
||||
golang.org/x/sys v0.31.0
|
||||
golang.org/x/term v0.30.0
|
||||
golang.org/x/text v0.23.0
|
||||
golang.org/x/time v0.11.0
|
||||
google.golang.org/api v0.227.0
|
||||
golang.org/x/crypto v0.41.0
|
||||
golang.org/x/net v0.43.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.16.0
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.org/x/term v0.34.0
|
||||
golang.org/x/text v0.28.0
|
||||
golang.org/x/time v0.12.0
|
||||
google.golang.org/api v0.248.0
|
||||
)
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.19.2 // indirect
|
||||
cloud.google.com/go v0.118.3 // indirect
|
||||
cloud.google.com/go/auth v0.15.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
cloud.google.com/go/iam v1.4.1 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
|
||||
cel.dev/expr v0.24.0 // indirect
|
||||
cloud.google.com/go v0.120.0 // indirect
|
||||
cloud.google.com/go/auth v0.16.5 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.8.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
@@ -64,17 +64,18 @@ require (
|
||||
github.com/felixge/fgprof v0.9.3 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 // indirect
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/minio/crc64nvme v1.0.1 // indirect
|
||||
@@ -83,19 +84,21 @@ require (
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
|
||||
github.com/zeebo/errs v1.4.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
|
||||
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
|
||||
google.golang.org/grpc v1.71.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.7 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
198
go.sum
198
go.sum
@@ -1,45 +1,45 @@
|
||||
cel.dev/expr v0.19.2 h1:V354PbqIXr9IQdwy4SYA4xa0HXaWq1BUPAGzugBY5V4=
|
||||
cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||
cloud.google.com/go v0.118.3 h1:jsypSnrE/w4mJysioGdMBg4MiW/hHx/sArFpaBWHdME=
|
||||
cloud.google.com/go v0.118.3/go.mod h1:Lhs3YLnBlwJ4KA6nuObNMZ/fCbOQBPuWKPoE0Wa/9Vc=
|
||||
cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps=
|
||||
cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
|
||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
cloud.google.com/go/iam v1.4.1 h1:cFC25Nv+u5BkTR/BT1tXdoF2daiVbZ1RLx2eqfQ9RMM=
|
||||
cloud.google.com/go/iam v1.4.1/go.mod h1:2vUEJpUG3Q9p2UdsyksaKpDzlwOrnMzS30isdReIcLM=
|
||||
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA=
|
||||
cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q=
|
||||
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
|
||||
cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
|
||||
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
|
||||
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
|
||||
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
|
||||
cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc=
|
||||
cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA=
|
||||
cloud.google.com/go/longrunning v0.6.5 h1:sD+t8DO8j4HKW4QfouCklg7ZC1qC4uzVZt8iz3uTW+Q=
|
||||
cloud.google.com/go/longrunning v0.6.5/go.mod h1:Et04XK+0TTLKa5IPYryKf5DkpwImy6TluQ1QTLwlKmY=
|
||||
cloud.google.com/go/monitoring v1.24.0 h1:csSKiCJ+WVRgNkRzzz3BPoGjFhjPY23ZTcaenToJxMM=
|
||||
cloud.google.com/go/monitoring v1.24.0/go.mod h1:Bd1PRK5bmQBQNnuGwHBfUamAV1ys9049oEPHnn4pcsc=
|
||||
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
||||
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
|
||||
cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM=
|
||||
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
|
||||
cloud.google.com/go/storage v1.51.0 h1:ZVZ11zCiD7b3k+cH5lQs/qcNaoSz3U9I0jgwVzqDlCw=
|
||||
cloud.google.com/go/storage v1.51.0/go.mod h1:YEJfu/Ki3i5oHC/7jyTgsGZwdQ8P9hqMqvpi5kRKGgc=
|
||||
cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE=
|
||||
cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 h1:DSDNVxqkoXJiko6x8a90zidoYqnYYa6c1MTzDKzKkTo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
|
||||
cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4=
|
||||
cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 h1:UXT0o77lXQrikd1kgwIPQOUect7EoR/+sbP4wQKdzxM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0/go.mod h1:cTvi54pg19DoT07ekoeMgE/taAwNtCShVeZqA+Iv2xI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1/go.mod h1:Ng3urmn6dYe8gnbCMoHHVl5APYz2txho3koEkV2o2HA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2 h1:FwladfywkNirM+FZYLBR2kBz5C8Tg0fw5w5Y7meRXWI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2/go.mod h1:vv5Ad0RrIoT1lJFdWBZwt4mB1+j+V8DUroixmKDTCdk=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
|
||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/Backblaze/blazer v0.7.2 h1:UWNHMLB+Nf+UmbO2qkVvgriODLEMz4kIyr2Hm+DVXQM=
|
||||
github.com/Backblaze/blazer v0.7.2/go.mod h1:T4y3EYa9IQ5J0PKc/C/J8/CEnSd3qa/lgNw938wZg10=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0 h1:OqVGm6Ei3x5+yZmSJG1Mh2NwHvpVmZ08CB5qJhT9Nuk=
|
||||
@@ -65,8 +65,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk=
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -96,17 +96,19 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw
|
||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
@@ -124,20 +126,20 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
|
||||
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
|
||||
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
|
||||
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@@ -155,15 +157,15 @@ github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY
|
||||
github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.88 h1:v8MoIJjwYxOkehp+eiLIuvXk87P2raUtoU5klrAAshs=
|
||||
github.com/minio/minio-go/v7 v7.0.88/go.mod h1:33+O8h0tO7pCeCWwBVa07RhVVfB/3vS4kEX7rwYKmIg=
|
||||
github.com/minio/minio-go/v7 v7.0.89 h1:hx4xV5wwTUfyv8LarhJAwNecnXpoTsj9v3f3q/ZkiJU=
|
||||
github.com/minio/minio-go/v7 v7.0.89/go.mod h1:2rFnGAp02p7Dddo1Fq4S2wYOfpF0MUTSeLTRC90I204=
|
||||
github.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=
|
||||
github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
|
||||
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/peterbourgon/ff/v3 v3.3.1/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
|
||||
github.com/peterbourgon/unixtransport v0.0.4 h1:UTF0FxXCAglvoZz9jaGPYjEg52DjBLDYGMJvJni6Tfw=
|
||||
github.com/peterbourgon/unixtransport v0.0.4/go.mod h1:o8aUkOCa8W/BIXpi15uKvbSabjtBh0JhSOJGSfoOhAU=
|
||||
github.com/peterbourgon/unixtransport v0.0.6 h1:sWIViDoRIg2MeyRbWTUDdvvY5XbKaaSr9ionmzNGXWY=
|
||||
github.com/peterbourgon/unixtransport v0.0.6/go.mod h1:o8aUkOCa8W/BIXpi15uKvbSabjtBh0JhSOJGSfoOhAU=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
@@ -171,8 +173,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||
github.com/pkg/sftp v1.13.8 h1:Xt7eJ/xqXv7s0VuzFw7JXhZj6Oc1zI6l4GK8KP9sFB0=
|
||||
github.com/pkg/sftp v1.13.8/go.mod h1:DmvEkvKE2lshEeuo2JMp06yqcx9HVnR7e3zqQl42F3U=
|
||||
github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
|
||||
github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
|
||||
github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
|
||||
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
@@ -181,8 +183,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
||||
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
|
||||
github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
github.com/restic/chunker v0.4.0 h1:YUPYCUn70MYP7VO4yllypp2SjmsRhRJaad3xKu1QFRw=
|
||||
github.com/restic/chunker v0.4.0/go.mod h1:z0cH2BejpW636LXw0R/BGyv+Ey8+m9QGiOanDHItzyw=
|
||||
github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s=
|
||||
@@ -199,6 +201,8 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
|
||||
github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@@ -214,26 +218,28 @@ github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDH
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 h1:JRxssobiPg23otYU5SbWtQC//snGVIM3Tx6QRzlQBao=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
@@ -243,8 +249,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4=
|
||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
@@ -266,10 +272,10 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
|
||||
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -278,8 +284,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -299,8 +305,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -311,8 +317,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -324,10 +330,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
@@ -339,18 +345,18 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.227.0 h1:QvIHF9IuyG6d6ReE+BNd11kIB8hZvjN8Z5xY5t21zYc=
|
||||
google.golang.org/api v0.227.0/go.mod h1:EIpaG6MbTgQarWF5xJvX0eOJPK9n/5D4Bynb9j2HXvQ=
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/api v0.248.0 h1:hUotakSkcwGdYUqzCRc5yGYsg4wXxpkKlW5ryVqvC1Y=
|
||||
google.golang.org/api v0.248.0/go.mod h1:yAFUAF56Li7IuIQbTFoLwXTCI6XCFKueOlS7S9e4F9k=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -264,6 +264,11 @@ func (arch *Archiver) trackItem(item string, previous, current *restic.Node, s I
|
||||
// nodeFromFileInfo returns the restic node from an os.FileInfo.
|
||||
func (arch *Archiver) nodeFromFileInfo(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*restic.Node, error) {
|
||||
node, err := meta.ToNode(ignoreXattrListError)
|
||||
// node does not exist. This prevents all further processing for this file.
|
||||
// If an error and a node are returned, then preserve as much data as possible (see below).
|
||||
if err != nil && node == nil {
|
||||
return nil, err
|
||||
}
|
||||
if !arch.WithAtime {
|
||||
node.AccessTime = node.ModTime
|
||||
}
|
||||
@@ -718,8 +723,14 @@ func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree,
|
||||
arch.trackItem(snItem, oldNode, n, is, time.Since(start))
|
||||
})
|
||||
if err != nil {
|
||||
err = arch.error(join(snPath, name), err)
|
||||
if err == nil {
|
||||
// ignore error
|
||||
continue
|
||||
}
|
||||
return futureNode{}, 0, err
|
||||
}
|
||||
|
||||
nodes = append(nodes, fn)
|
||||
}
|
||||
|
||||
|
||||
@@ -174,12 +174,11 @@ func TestArchiverSaveFileReaderFS(t *testing.T) {
|
||||
|
||||
ts := time.Now()
|
||||
filename := "xx"
|
||||
readerFs := &fs.Reader{
|
||||
ModTime: ts,
|
||||
Mode: 0123,
|
||||
Name: filename,
|
||||
ReadCloser: io.NopCloser(strings.NewReader(test.Data)),
|
||||
}
|
||||
readerFs, err := fs.NewReader(filename, io.NopCloser(strings.NewReader(test.Data)), fs.ReaderOptions{
|
||||
ModTime: ts,
|
||||
Mode: 0123,
|
||||
})
|
||||
rtest.OK(t, err)
|
||||
|
||||
node, stats := saveFile(t, repo, filename, readerFs)
|
||||
|
||||
@@ -288,13 +287,11 @@ func TestArchiverSaveReaderFS(t *testing.T) {
|
||||
|
||||
ts := time.Now()
|
||||
filename := "xx"
|
||||
readerFs := &fs.Reader{
|
||||
ModTime: ts,
|
||||
Mode: 0123,
|
||||
Name: filename,
|
||||
ReadCloser: io.NopCloser(strings.NewReader(test.Data)),
|
||||
}
|
||||
|
||||
readerFs, err := fs.NewReader(filename, io.NopCloser(strings.NewReader(test.Data)), fs.ReaderOptions{
|
||||
ModTime: ts,
|
||||
Mode: 0123,
|
||||
})
|
||||
rtest.OK(t, err)
|
||||
arch := New(repo, readerFs, Options{})
|
||||
arch.Error = func(item string, err error) error {
|
||||
t.Errorf("archiver error for %v: %v", item, err)
|
||||
@@ -1849,8 +1846,8 @@ func TestArchiverParent(t *testing.T) {
|
||||
func TestArchiverErrorReporting(t *testing.T) {
|
||||
ignoreErrorForBasename := func(basename string) ErrorFunc {
|
||||
return func(item string, err error) error {
|
||||
if filepath.Base(item) == "targetfile" {
|
||||
t.Logf("ignoring error for targetfile: %v", err)
|
||||
if filepath.Base(item) == basename {
|
||||
t.Logf("ignoring error for %v: %v", basename, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1873,12 +1870,13 @@ func TestArchiverErrorReporting(t *testing.T) {
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
src TestDir
|
||||
want TestDir
|
||||
prepare func(t testing.TB)
|
||||
errFn ErrorFunc
|
||||
mustError bool
|
||||
name string
|
||||
targets []string
|
||||
src TestDir
|
||||
want TestDir
|
||||
prepare func(t testing.TB)
|
||||
errFn ErrorFunc
|
||||
errStr []string
|
||||
}{
|
||||
{
|
||||
name: "no-error",
|
||||
@@ -1891,8 +1889,8 @@ func TestArchiverErrorReporting(t *testing.T) {
|
||||
src: TestDir{
|
||||
"targetfile": TestFile{Content: "foobar"},
|
||||
},
|
||||
prepare: chmodUnreadable("targetfile"),
|
||||
mustError: true,
|
||||
prepare: chmodUnreadable("targetfile"),
|
||||
errStr: []string{"open targetfile: permission denied"},
|
||||
},
|
||||
{
|
||||
name: "file-unreadable-ignore-error",
|
||||
@@ -1913,8 +1911,8 @@ func TestArchiverErrorReporting(t *testing.T) {
|
||||
"targetfile": TestFile{Content: "foobar"},
|
||||
},
|
||||
},
|
||||
prepare: chmodUnreadable("subdir/targetfile"),
|
||||
mustError: true,
|
||||
prepare: chmodUnreadable("subdir/targetfile"),
|
||||
errStr: []string{"open subdir/targetfile: permission denied"},
|
||||
},
|
||||
{
|
||||
name: "file-subdir-unreadable-ignore-error",
|
||||
@@ -1932,6 +1930,20 @@ func TestArchiverErrorReporting(t *testing.T) {
|
||||
prepare: chmodUnreadable("subdir/targetfile"),
|
||||
errFn: ignoreErrorForBasename("targetfile"),
|
||||
},
|
||||
{
|
||||
name: "parent-dir-missing",
|
||||
targets: []string{"subdir/missing"},
|
||||
src: TestDir{},
|
||||
errStr: []string{"stat subdir: no such file or directory", "CreateFile subdir: The system cannot find the file specified"},
|
||||
},
|
||||
{
|
||||
name: "parent-dir-missing-filtered",
|
||||
targets: []string{"targetfile", "subdir/missing"},
|
||||
src: TestDir{
|
||||
"targetfile": TestFile{Content: "foobar"},
|
||||
},
|
||||
errFn: ignoreErrorForBasename("subdir"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -1951,14 +1963,21 @@ func TestArchiverErrorReporting(t *testing.T) {
|
||||
arch := New(repo, fs.Track{FS: fs.Local{}}, Options{})
|
||||
arch.Error = test.errFn
|
||||
|
||||
_, snapshotID, _, err := arch.Snapshot(ctx, []string{"."}, SnapshotOptions{Time: time.Now()})
|
||||
if test.mustError {
|
||||
if err != nil {
|
||||
t.Logf("found expected error (%v), skipping further checks", err)
|
||||
return
|
||||
target := test.targets
|
||||
if len(target) == 0 {
|
||||
target = []string{"."}
|
||||
}
|
||||
_, snapshotID, _, err := arch.Snapshot(ctx, target, SnapshotOptions{Time: time.Now()})
|
||||
if test.errStr != nil {
|
||||
// check if any of the expected errors are contained in the error message
|
||||
for _, errStr := range test.errStr {
|
||||
if strings.Contains(err.Error(), errStr) {
|
||||
t.Logf("found expected error (%v)", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatalf("expected error not returned by archiver")
|
||||
t.Fatalf("expected error (%v) not returned by archiver, got (%v)", test.errStr, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -43,5 +43,12 @@ func isMacENOTTY(err error) bool {
|
||||
|
||||
// set file to readonly
|
||||
func setFileReadonly(f string, mode os.FileMode) error {
|
||||
return os.Chmod(f, mode&^0222)
|
||||
err := os.Chmod(f, mode&^0222)
|
||||
|
||||
// ignore the error if the FS does not support setting this mode (e.g. CIFS with gvfs on Linux)
|
||||
if err != nil && errors.Is(err, errors.ErrUnsupported) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ func (b *Backend) IsPermanentError(err error) bool {
|
||||
|
||||
var rerr *restError
|
||||
if errors.As(err, &rerr) {
|
||||
if rerr.StatusCode == http.StatusRequestedRangeNotSatisfiable || rerr.StatusCode == http.StatusUnauthorized || rerr.StatusCode == http.StatusForbidden {
|
||||
if rerr.StatusCode == http.StatusRequestedRangeNotSatisfiable || rerr.StatusCode == http.StatusUnauthorized || rerr.StatusCode == http.StatusForbidden || rerr.StatusCode == http.StatusInsufficientStorage {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ type Config struct {
|
||||
|
||||
EnableRestore bool `option:"enable-restore" help:"restore objects from GLACIER or DEEP_ARCHIVE storage classes (default: false, requires \"s3-restore\" feature flag)"`
|
||||
RestoreDays int `option:"restore-days" help:"lifetime in days of restored object (default: 7)"`
|
||||
RestoreTimeout time.Duration `option:"restore-timeout" help:"maximum time to wait for objects transition (default: 1d)"`
|
||||
RestoreTimeout time.Duration `option:"restore-timeout" help:"maximum time to wait for objects transition (default: 24h)"`
|
||||
RestoreTier string `option:"restore-tier" help:"Retrieval tier at which the restore will be processed. (Standard, Bulk or Expedited) (default: Standard)"`
|
||||
|
||||
Connections uint `option:"connections" help:"set a limit for the number of concurrent connections (default: 5)"`
|
||||
|
||||
@@ -19,97 +19,135 @@ import (
|
||||
// be opened once, all subsequent open calls return syscall.EIO. For Lstat(),
|
||||
// the provided FileInfo is returned.
|
||||
type Reader struct {
|
||||
Name string
|
||||
io.ReadCloser
|
||||
items map[string]readerItem
|
||||
}
|
||||
|
||||
// for FileInfo
|
||||
type ReaderOptions struct {
|
||||
Mode os.FileMode
|
||||
ModTime time.Time
|
||||
Size int64
|
||||
|
||||
AllowEmptyFile bool
|
||||
}
|
||||
|
||||
open sync.Once
|
||||
type readerItem struct {
|
||||
open *sync.Once
|
||||
fi *ExtendedFileInfo
|
||||
rc io.ReadCloser
|
||||
allowEmptyFile bool
|
||||
|
||||
children []string
|
||||
}
|
||||
|
||||
// statically ensure that Local implements FS.
|
||||
var _ FS = &Reader{}
|
||||
|
||||
func NewReader(name string, r io.ReadCloser, opts ReaderOptions) (*Reader, error) {
|
||||
items := make(map[string]readerItem)
|
||||
name = readerCleanPath(name)
|
||||
if name == "/" {
|
||||
return nil, fmt.Errorf("invalid filename specified")
|
||||
}
|
||||
|
||||
isFile := true
|
||||
for {
|
||||
if isFile {
|
||||
fi := &ExtendedFileInfo{
|
||||
Name: path.Base(name),
|
||||
Mode: opts.Mode,
|
||||
ModTime: opts.ModTime,
|
||||
Size: opts.Size,
|
||||
}
|
||||
items[name] = readerItem{
|
||||
open: &sync.Once{},
|
||||
fi: fi,
|
||||
rc: r,
|
||||
allowEmptyFile: opts.AllowEmptyFile,
|
||||
}
|
||||
isFile = false
|
||||
} else {
|
||||
fi := &ExtendedFileInfo{
|
||||
Name: path.Base(name),
|
||||
Mode: os.ModeDir | 0755,
|
||||
ModTime: opts.ModTime,
|
||||
Size: 0,
|
||||
}
|
||||
items[name] = readerItem{
|
||||
fi: fi,
|
||||
// keep the children set during the previous iteration
|
||||
children: items[name].children,
|
||||
}
|
||||
}
|
||||
|
||||
parent := path.Dir(name)
|
||||
if parent == name {
|
||||
break
|
||||
}
|
||||
// add the current file to the children of the parent directory
|
||||
item := items[parent]
|
||||
item.children = append(item.children, path.Base(name))
|
||||
items[parent] = item
|
||||
|
||||
name = parent
|
||||
}
|
||||
return &Reader{
|
||||
items: items,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func readerCleanPath(name string) string {
|
||||
return path.Clean("/" + name)
|
||||
}
|
||||
|
||||
// VolumeName returns leading volume name, for the Reader file system it's
|
||||
// always the empty string.
|
||||
func (fs *Reader) VolumeName(_ string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (fs *Reader) fi() *ExtendedFileInfo {
|
||||
return &ExtendedFileInfo{
|
||||
Name: fs.Name,
|
||||
Mode: fs.Mode,
|
||||
ModTime: fs.ModTime,
|
||||
Size: fs.Size,
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *Reader) OpenFile(name string, flag int, _ bool) (f File, err error) {
|
||||
if flag & ^(O_RDONLY|O_NOFOLLOW) != 0 {
|
||||
return nil, pathError("open", name,
|
||||
fmt.Errorf("invalid combination of flags 0x%x", flag))
|
||||
}
|
||||
|
||||
switch name {
|
||||
case fs.Name:
|
||||
fs.open.Do(func() {
|
||||
f = newReaderFile(fs.ReadCloser, fs.fi(), fs.AllowEmptyFile)
|
||||
name = readerCleanPath(name)
|
||||
item, ok := fs.items[name]
|
||||
if !ok {
|
||||
return nil, pathError("open", name, syscall.ENOENT)
|
||||
}
|
||||
|
||||
// Check if the path matches our target file
|
||||
if item.rc != nil {
|
||||
item.open.Do(func() {
|
||||
f = newReaderFile(item.rc, item.fi, item.allowEmptyFile)
|
||||
})
|
||||
|
||||
if f == nil {
|
||||
return nil, pathError("open", name, syscall.EIO)
|
||||
}
|
||||
|
||||
return f, nil
|
||||
case "/", ".":
|
||||
f = fakeDir{
|
||||
entries: []string{fs.fi().Name},
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
return nil, pathError("open", name, syscall.ENOENT)
|
||||
f = fakeDir{
|
||||
fakeFile: fakeFile{
|
||||
fi: item.fi,
|
||||
},
|
||||
entries: slices.Clone(item.children),
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Lstat returns the FileInfo structure describing the named file.
|
||||
// If the file is a symbolic link, the returned FileInfo
|
||||
// describes the symbolic link. Lstat makes no attempt to follow the link.
|
||||
// If there is an error, it will be of type *os.PathError.
|
||||
func (fs *Reader) Lstat(name string) (*ExtendedFileInfo, error) {
|
||||
getDirInfo := func(name string) *ExtendedFileInfo {
|
||||
return &ExtendedFileInfo{
|
||||
Name: fs.Base(name),
|
||||
Size: 0,
|
||||
Mode: os.ModeDir | 0755,
|
||||
ModTime: time.Now(),
|
||||
}
|
||||
name = readerCleanPath(name)
|
||||
item, ok := fs.items[name]
|
||||
if !ok {
|
||||
return nil, pathError("lstat", name, os.ErrNotExist)
|
||||
}
|
||||
|
||||
switch name {
|
||||
case fs.Name:
|
||||
return fs.fi(), nil
|
||||
case "/", ".":
|
||||
return getDirInfo(name), nil
|
||||
}
|
||||
|
||||
dir := fs.Dir(fs.Name)
|
||||
for {
|
||||
if dir == "/" || dir == "." {
|
||||
break
|
||||
}
|
||||
if name == dir {
|
||||
return getDirInfo(name), nil
|
||||
}
|
||||
dir = fs.Dir(dir)
|
||||
}
|
||||
|
||||
return nil, pathError("lstat", name, os.ErrNotExist)
|
||||
return item.fi, nil
|
||||
}
|
||||
|
||||
// Join joins any number of path elements into a single path, adding a
|
||||
@@ -137,7 +175,7 @@ func (fs *Reader) IsAbs(_ string) bool {
|
||||
//
|
||||
// For the Reader, all paths are absolute.
|
||||
func (fs *Reader) Abs(p string) (string, error) {
|
||||
return path.Clean(p), nil
|
||||
return readerCleanPath(p), nil
|
||||
}
|
||||
|
||||
// Clean returns the cleaned path. For details, see filepath.Clean.
|
||||
|
||||
@@ -17,19 +17,11 @@ import (
|
||||
|
||||
func verifyFileContentOpenFile(t testing.TB, fs FS, filename string, want []byte) {
|
||||
f, err := fs.OpenFile(filename, O_RDONLY, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test.OK(t, err)
|
||||
|
||||
buf, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test.OK(t, err)
|
||||
test.OK(t, f.Close())
|
||||
|
||||
if !cmp.Equal(want, buf) {
|
||||
t.Error(cmp.Diff(want, buf))
|
||||
@@ -38,19 +30,11 @@ func verifyFileContentOpenFile(t testing.TB, fs FS, filename string, want []byte
|
||||
|
||||
func verifyDirectoryContents(t testing.TB, fs FS, dir string, want []string) {
|
||||
f, err := fs.OpenFile(dir, O_RDONLY, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test.OK(t, err)
|
||||
|
||||
entries, err := f.Readdirnames(-1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test.OK(t, err)
|
||||
test.OK(t, f.Close())
|
||||
|
||||
sort.Strings(want)
|
||||
sort.Strings(entries)
|
||||
@@ -69,7 +53,7 @@ func checkFileInfo(t testing.TB, fi *ExtendedFileInfo, filename string, modtime
|
||||
t.Errorf("Mode has wrong value, want 0%o, got 0%o", mode, fi.Mode)
|
||||
}
|
||||
|
||||
if !modtime.Equal(time.Time{}) && !fi.ModTime.Equal(modtime) {
|
||||
if !fi.ModTime.Equal(modtime) {
|
||||
t.Errorf("ModTime has wrong value, want %v, got %v", modtime, fi.ModTime)
|
||||
}
|
||||
|
||||
@@ -82,40 +66,48 @@ func checkFileInfo(t testing.TB, fi *ExtendedFileInfo, filename string, modtime
|
||||
}
|
||||
}
|
||||
|
||||
func TestFSReader(t *testing.T) {
|
||||
data := test.Random(55, 1<<18+588)
|
||||
now := time.Now()
|
||||
filename := "foobar"
|
||||
type fsTest []struct {
|
||||
name string
|
||||
f func(t *testing.T, fs FS)
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
f func(t *testing.T, fs FS)
|
||||
}{
|
||||
func createReadDirTest(fpath, filename string) fsTest {
|
||||
return fsTest{
|
||||
{
|
||||
name: "Readdirnames-slash",
|
||||
name: "Readdirnames-slash-" + fpath,
|
||||
f: func(t *testing.T, fs FS) {
|
||||
verifyDirectoryContents(t, fs, "/", []string{filename})
|
||||
verifyDirectoryContents(t, fs, "/"+fpath, []string{filename})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Readdirnames-current",
|
||||
name: "Readdirnames-current-" + fpath,
|
||||
f: func(t *testing.T, fs FS) {
|
||||
verifyDirectoryContents(t, fs, ".", []string{filename})
|
||||
verifyDirectoryContents(t, fs, path.Clean(fpath), []string{filename})
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createFileTest(filename string, now time.Time, data []byte) fsTest {
|
||||
return fsTest{
|
||||
{
|
||||
name: "file/OpenFile",
|
||||
f: func(t *testing.T, fs FS) {
|
||||
verifyFileContentOpenFile(t, fs, filename, data)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "file/Open-error-not-exist",
|
||||
f: func(t *testing.T, fs FS) {
|
||||
_, err := fs.OpenFile(filename+"/other", O_RDONLY, false)
|
||||
test.Assert(t, errors.Is(err, os.ErrNotExist), "unexpected error, got %v, expected %v", err, os.ErrNotExist)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "file/Lstat",
|
||||
f: func(t *testing.T, fs FS) {
|
||||
fi, err := fs.Lstat(filename)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test.OK(t, err)
|
||||
|
||||
checkFileInfo(t, fi, filename, now, 0644, false)
|
||||
},
|
||||
@@ -123,91 +115,113 @@ func TestFSReader(t *testing.T) {
|
||||
{
|
||||
name: "file/Stat",
|
||||
f: func(t *testing.T, fs FS) {
|
||||
f, err := fs.OpenFile(filename, O_RDONLY, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fi := fsOpenAndStat(t, fs, filename, true)
|
||||
checkFileInfo(t, fi, filename, now, 0644, false)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dir/Lstat-slash",
|
||||
f: func(t *testing.T, fs FS) {
|
||||
fi, err := fs.Lstat("/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkFileInfo(t, fi, "/", time.Time{}, os.ModeDir|0755, true)
|
||||
func createDirTest(fpath string, now time.Time) fsTest {
|
||||
return fsTest{
|
||||
{
|
||||
name: "dir/Lstat-slash-" + fpath,
|
||||
f: func(t *testing.T, fs FS) {
|
||||
fi, err := fs.Lstat("/" + fpath)
|
||||
test.OK(t, err)
|
||||
|
||||
checkFileInfo(t, fi, "/"+fpath, now, os.ModeDir|0755, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dir/Lstat-current",
|
||||
name: "dir/Lstat-current-" + fpath,
|
||||
f: func(t *testing.T, fs FS) {
|
||||
fi, err := fs.Lstat(".")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fi, err := fs.Lstat("./" + fpath)
|
||||
test.OK(t, err)
|
||||
|
||||
checkFileInfo(t, fi, ".", time.Time{}, os.ModeDir|0755, true)
|
||||
checkFileInfo(t, fi, "/"+fpath, now, os.ModeDir|0755, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dir/Lstat-error-not-exist",
|
||||
name: "dir/Lstat-error-not-exist-" + fpath,
|
||||
f: func(t *testing.T, fs FS) {
|
||||
_, err := fs.Lstat("other")
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err := fs.Lstat(fpath + "/other")
|
||||
test.Assert(t, errors.Is(err, os.ErrNotExist), "unexpected error, got %v, expected %v", err, os.ErrNotExist)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dir/Open-slash",
|
||||
name: "dir/Open-slash-" + fpath,
|
||||
f: func(t *testing.T, fs FS) {
|
||||
fi, err := fs.Lstat("/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
checkFileInfo(t, fi, "/", time.Time{}, os.ModeDir|0755, true)
|
||||
fi := fsOpenAndStat(t, fs, "/"+fpath, false)
|
||||
checkFileInfo(t, fi, "/"+fpath, now, os.ModeDir|0755, true)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dir/Open-current",
|
||||
name: "dir/Open-current-" + fpath,
|
||||
f: func(t *testing.T, fs FS) {
|
||||
fi, err := fs.Lstat(".")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
checkFileInfo(t, fi, ".", time.Time{}, os.ModeDir|0755, true)
|
||||
fi := fsOpenAndStat(t, fs, "./"+fpath, false)
|
||||
checkFileInfo(t, fi, "/"+fpath, now, os.ModeDir|0755, true)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
fs := &Reader{
|
||||
Name: filename,
|
||||
ReadCloser: io.NopCloser(bytes.NewReader(data)),
|
||||
func fsOpenAndStat(t *testing.T, fs FS, fpath string, metadataOnly bool) *ExtendedFileInfo {
|
||||
f, err := fs.OpenFile(fpath, O_RDONLY, metadataOnly)
|
||||
test.OK(t, err)
|
||||
|
||||
fi, err := f.Stat()
|
||||
test.OK(t, err)
|
||||
test.OK(t, f.Close())
|
||||
return fi
|
||||
}
|
||||
|
||||
func TestFSReader(t *testing.T) {
|
||||
data := test.Random(55, 1<<18+588)
|
||||
now := time.Now()
|
||||
filename := "foobar"
|
||||
|
||||
tests := createReadDirTest("", filename)
|
||||
tests = append(tests, createFileTest(filename, now, data)...)
|
||||
tests = append(tests, createDirTest("", now)...)
|
||||
|
||||
for _, tst := range tests {
|
||||
fs, err := NewReader(filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{
|
||||
Mode: 0644,
|
||||
Size: int64(len(data)),
|
||||
ModTime: now,
|
||||
}
|
||||
})
|
||||
test.OK(t, err)
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
test.f(t, fs)
|
||||
t.Run(tst.name, func(t *testing.T) {
|
||||
tst.f(t, fs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFSReaderNested(t *testing.T) {
|
||||
data := test.Random(55, 1<<18+588)
|
||||
now := time.Now()
|
||||
filename := "foo/sub/bar"
|
||||
|
||||
tests := createReadDirTest("", "foo")
|
||||
tests = append(tests, createReadDirTest("foo", "sub")...)
|
||||
tests = append(tests, createReadDirTest("foo/sub", "bar")...)
|
||||
tests = append(tests, createFileTest(filename, now, data)...)
|
||||
tests = append(tests, createDirTest("", now)...)
|
||||
tests = append(tests, createDirTest("foo", now)...)
|
||||
tests = append(tests, createDirTest("foo/sub", now)...)
|
||||
|
||||
for _, tst := range tests {
|
||||
fs, err := NewReader(filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{
|
||||
Mode: 0644,
|
||||
Size: int64(len(data)),
|
||||
ModTime: now,
|
||||
})
|
||||
test.OK(t, err)
|
||||
|
||||
t.Run(tst.name, func(t *testing.T) {
|
||||
tst.f(t, fs)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -230,29 +244,24 @@ func TestFSReaderDir(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fs := &Reader{
|
||||
Name: test.filename,
|
||||
ReadCloser: io.NopCloser(bytes.NewReader(data)),
|
||||
|
||||
for _, tst := range tests {
|
||||
t.Run(tst.name, func(t *testing.T) {
|
||||
fs, err := NewReader(tst.filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{
|
||||
Mode: 0644,
|
||||
Size: int64(len(data)),
|
||||
ModTime: now,
|
||||
}
|
||||
|
||||
dir := path.Dir(fs.Name)
|
||||
})
|
||||
test.OK(t, err)
|
||||
dir := path.Dir(tst.filename)
|
||||
for {
|
||||
if dir == "/" || dir == "." {
|
||||
break
|
||||
}
|
||||
|
||||
fi, err := fs.Lstat(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test.OK(t, err)
|
||||
|
||||
checkFileInfo(t, fi, dir, time.Time{}, os.ModeDir|0755, true)
|
||||
checkFileInfo(t, fi, dir, now, os.ModeDir|0755, true)
|
||||
|
||||
dir = path.Dir(dir)
|
||||
}
|
||||
@@ -285,40 +294,30 @@ func TestFSReaderMinFileSize(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fs := &Reader{
|
||||
Name: "testfile",
|
||||
ReadCloser: io.NopCloser(strings.NewReader(test.data)),
|
||||
for _, tst := range tests {
|
||||
t.Run(tst.name, func(t *testing.T) {
|
||||
fs, err := NewReader("testfile", io.NopCloser(strings.NewReader(tst.data)), ReaderOptions{
|
||||
Mode: 0644,
|
||||
ModTime: time.Now(),
|
||||
AllowEmptyFile: test.allowEmpty,
|
||||
}
|
||||
|
||||
AllowEmptyFile: tst.allowEmpty,
|
||||
})
|
||||
test.OK(t, err)
|
||||
f, err := fs.OpenFile("testfile", O_RDONLY, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test.OK(t, err)
|
||||
|
||||
buf, err := io.ReadAll(f)
|
||||
if test.readMustErr {
|
||||
if tst.readMustErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected error not found, got nil")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test.OK(t, err)
|
||||
}
|
||||
|
||||
if string(buf) != test.data {
|
||||
t.Fatalf("wrong data returned, want %q, got %q", test.data, string(buf))
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
if string(buf) != tst.data {
|
||||
t.Fatalf("wrong data returned, want %q, got %q", tst.data, string(buf))
|
||||
}
|
||||
test.OK(t, f.Close())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +53,8 @@ func handleXattrErr(err error) error {
|
||||
|
||||
case *xattr.Error:
|
||||
// On Linux, xattr calls on files in an SMB/CIFS mount can return
|
||||
// ENOATTR instead of ENOTSUP.
|
||||
switch e.Err {
|
||||
case syscall.ENOTSUP, xattr.ENOATTR:
|
||||
// ENOATTR instead of ENOTSUP. BSD can return EOPNOTSUPP.
|
||||
if e.Err == syscall.ENOTSUP || e.Err == syscall.EOPNOTSUPP || e.Err == xattr.ENOATTR {
|
||||
return nil
|
||||
}
|
||||
return errors.WithStack(e)
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/restic/restic/internal/errors"
|
||||
)
|
||||
@@ -52,7 +51,7 @@ func nextNumber(input string) (num int, rest string, err error) {
|
||||
}
|
||||
|
||||
for i, s := range input {
|
||||
if !unicode.IsNumber(s) {
|
||||
if s < '0' || s > '9' {
|
||||
rest = input[i:]
|
||||
break
|
||||
}
|
||||
|
||||
@@ -37,6 +37,9 @@ func TestNextNumber(t *testing.T) {
|
||||
{
|
||||
input: "5d ", num: 5, rest: "d ",
|
||||
},
|
||||
{
|
||||
input: "5", num: 5, rest: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -78,6 +81,7 @@ func TestParseDuration(t *testing.T) {
|
||||
{input: "2w", err: true},
|
||||
{input: "1y4m3w1d", err: true},
|
||||
{input: "s", err: true},
|
||||
{input: "\xdf\x80", err: true}, // NKO DIGIT ZERO; we want ASCII digits
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -908,13 +908,12 @@ func TestRestorerSparseFiles(t *testing.T) {
|
||||
|
||||
var zeros [1<<20 + 13]byte
|
||||
|
||||
target := &fs.Reader{
|
||||
Mode: 0600,
|
||||
Name: "/zeros",
|
||||
ReadCloser: io.NopCloser(bytes.NewReader(zeros[:])),
|
||||
}
|
||||
target, err := fs.NewReader("/zeros", io.NopCloser(bytes.NewReader(zeros[:])), fs.ReaderOptions{
|
||||
Mode: 0600,
|
||||
})
|
||||
rtest.OK(t, err)
|
||||
sc := archiver.NewScanner(target)
|
||||
err := sc.Scan(context.TODO(), []string{"/zeros"})
|
||||
err = sc.Scan(context.TODO(), []string{"/zeros"})
|
||||
rtest.OK(t, err)
|
||||
|
||||
arch := archiver.New(repo, target, archiver.Options{})
|
||||
|
||||
@@ -91,6 +91,8 @@ func walk(ctx context.Context, repo restic.BlobLoader, prefix string, parentTree
|
||||
if err == ErrSkipNode {
|
||||
continue
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
err = walk(ctx, repo, p, *node.Subtree, subtree, visitor)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/restic/restic/internal/restic"
|
||||
rtest "github.com/restic/restic/internal/test"
|
||||
)
|
||||
|
||||
// TestTree is used to construct a list of trees for testing the walker.
|
||||
@@ -93,12 +94,12 @@ func (t TreeMap) Connections() uint {
|
||||
|
||||
// checkFunc returns a function suitable for walking the tree to check
|
||||
// something, and a function which will check the final result.
|
||||
type checkFunc func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB))
|
||||
type checkFunc func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error))
|
||||
|
||||
// checkItemOrder ensures that the order of the 'path' arguments is the one passed in as 'want'.
|
||||
func checkItemOrder(want []string) checkFunc {
|
||||
pos := 0
|
||||
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB)) {
|
||||
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error)) {
|
||||
walker = func(treeID restic.ID, path string, node *restic.Node, err error) error {
|
||||
if err != nil {
|
||||
t.Errorf("error walking %v: %v", path, err)
|
||||
@@ -121,7 +122,8 @@ func checkItemOrder(want []string) checkFunc {
|
||||
return walker(restic.ID{}, "leave: "+path, nil, nil)
|
||||
}
|
||||
|
||||
final = func(t testing.TB) {
|
||||
final = func(t testing.TB, err error) {
|
||||
rtest.OK(t, err)
|
||||
if pos != len(want) {
|
||||
t.Errorf("not enough items returned, want %d, got %d", len(want), pos)
|
||||
}
|
||||
@@ -134,7 +136,7 @@ func checkItemOrder(want []string) checkFunc {
|
||||
// checkParentTreeOrder ensures that the order of the 'parentID' arguments is the one passed in as 'want'.
|
||||
func checkParentTreeOrder(want []string) checkFunc {
|
||||
pos := 0
|
||||
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB)) {
|
||||
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error)) {
|
||||
walker = func(treeID restic.ID, path string, node *restic.Node, err error) error {
|
||||
if err != nil {
|
||||
t.Errorf("error walking %v: %v", path, err)
|
||||
@@ -153,7 +155,8 @@ func checkParentTreeOrder(want []string) checkFunc {
|
||||
return nil
|
||||
}
|
||||
|
||||
final = func(t testing.TB) {
|
||||
final = func(t testing.TB, err error) {
|
||||
rtest.OK(t, err)
|
||||
if pos != len(want) {
|
||||
t.Errorf("not enough items returned, want %d, got %d", len(want), pos)
|
||||
}
|
||||
@@ -168,7 +171,7 @@ func checkParentTreeOrder(want []string) checkFunc {
|
||||
func checkSkipFor(skipFor map[string]struct{}, wantPaths []string) checkFunc {
|
||||
var pos int
|
||||
|
||||
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB)) {
|
||||
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error)) {
|
||||
walker = func(treeID restic.ID, path string, node *restic.Node, err error) error {
|
||||
if err != nil {
|
||||
t.Errorf("error walking %v: %v", path, err)
|
||||
@@ -196,7 +199,8 @@ func checkSkipFor(skipFor map[string]struct{}, wantPaths []string) checkFunc {
|
||||
return walker(restic.ID{}, "leave: "+path, nil, nil)
|
||||
}
|
||||
|
||||
final = func(t testing.TB) {
|
||||
final = func(t testing.TB, err error) {
|
||||
rtest.OK(t, err)
|
||||
if pos != len(wantPaths) {
|
||||
t.Errorf("wrong number of paths returned, want %d, got %d", len(wantPaths), pos)
|
||||
}
|
||||
@@ -206,6 +210,32 @@ func checkSkipFor(skipFor map[string]struct{}, wantPaths []string) checkFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func checkErrorReturned(errForPath string) checkFunc {
|
||||
expectedErr := fmt.Errorf("error for %v", errForPath)
|
||||
|
||||
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error)) {
|
||||
walker = func(treeID restic.ID, path string, node *restic.Node, err error) error {
|
||||
if path == errForPath {
|
||||
return expectedErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
leaveDir = func(path string) error {
|
||||
return walker(restic.ID{}, "leave: "+path, nil, nil)
|
||||
}
|
||||
|
||||
final = func(t testing.TB, err error) {
|
||||
if err == nil {
|
||||
t.Errorf("expected error for %v, got nil", errForPath)
|
||||
}
|
||||
rtest.Assert(t, err == expectedErr, "expected error for %v, got %v", errForPath, err)
|
||||
}
|
||||
|
||||
return walker, leaveDir, final
|
||||
}
|
||||
}
|
||||
|
||||
func TestWalker(t *testing.T) {
|
||||
var tests = []struct {
|
||||
tree TestTree
|
||||
@@ -427,6 +457,21 @@ func TestWalker(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
tree: TestTree{
|
||||
"subdir1": TestTree{
|
||||
"file": TestFile{},
|
||||
},
|
||||
"subdir2": TestTree{},
|
||||
},
|
||||
checks: []checkFunc{
|
||||
checkErrorReturned("/subdir1"),
|
||||
checkErrorReturned("/subdir2"),
|
||||
checkErrorReturned("/subdir1/file"),
|
||||
checkErrorReturned("leave: /subdir1"),
|
||||
checkErrorReturned("leave: /subdir2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -442,10 +487,7 @@ func TestWalker(t *testing.T) {
|
||||
ProcessNode: fn,
|
||||
LeaveDir: leaveDir,
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
last(t)
|
||||
last(t, err)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user