From 0d5c4e8e7fdd2bd592a4075418c9ef317bdba4ad Mon Sep 17 00:00:00 2001 From: Matteo Pietro Dazzi Date: Mon, 29 Dec 2025 10:27:49 +0100 Subject: [PATCH] feat: auto extract archives (#1212) --- .github/workflows/test.yml | 1 + Dockerfile | 2 +- go.mod | 37 ++- go.sum | 214 ++++++++++++++++-- pkg/base/model.go | 23 +- pkg/base/model_test.go | 76 +++++++ pkg/download/downloader.go | 23 ++ pkg/download/extract.go | 183 +++++++++++++++ pkg/download/extract_test.go | 154 +++++++++++++ pkg/protocol/http/model.go | 6 + .../lib/api/model/downloader_config.dart | 17 ++ .../lib/api/model/downloader_config.g.dart | 17 +- ui/flutter/lib/api/model/options.dart | 6 + ui/flutter/lib/api/model/options.g.dart | 6 + .../create/controllers/create_controller.dart | 2 +- .../app/modules/create/views/create_view.dart | 85 ++++++- .../modules/setting/views/setting_view.dart | 48 ++++ ui/flutter/lib/i18n/langs/de_de.dart | 5 + ui/flutter/lib/i18n/langs/en_us.dart | 5 + ui/flutter/lib/i18n/langs/es_es.dart | 5 + ui/flutter/lib/i18n/langs/fa_ir.dart | 5 + ui/flutter/lib/i18n/langs/fr_fr.dart | 5 + ui/flutter/lib/i18n/langs/hu_hu.dart | 5 + ui/flutter/lib/i18n/langs/id_id.dart | 5 + ui/flutter/lib/i18n/langs/it_it.dart | 5 + ui/flutter/lib/i18n/langs/ja_jp.dart | 5 + ui/flutter/lib/i18n/langs/pl_pl.dart | 5 + ui/flutter/lib/i18n/langs/pt_br.dart | 5 + ui/flutter/lib/i18n/langs/ru_ru.dart | 5 + ui/flutter/lib/i18n/langs/ta_ta.dart | 5 + ui/flutter/lib/i18n/langs/tr_tr.dart | 5 + ui/flutter/lib/i18n/langs/uk_ua.dart | 5 + ui/flutter/lib/i18n/langs/vi_vn.dart | 5 + ui/flutter/lib/i18n/langs/zh_cn.dart | 5 + ui/flutter/lib/i18n/langs/zh_tw.dart | 5 + 35 files changed, 950 insertions(+), 40 deletions(-) create mode 100644 pkg/download/extract.go create mode 100644 pkg/download/extract_test.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 335b701e..2d784ba1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,6 +25,7 @@ on: - ".github/workflows/test.yml" - "go.mod" - "go.sum" + workflow_dispatch: env: GO_VERSION: "1.24" diff --git a/Dockerfile b/Dockerfile index 2f699210..3d83cdee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23.3 AS go +FROM golang:1.24.0 AS go WORKDIR /app COPY ./go.mod ./go.sum ./ RUN go mod download diff --git a/go.mod b/go.mod index 62dbc0be..6a96ee09 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/GopeedLab/gopeed -go 1.23.0 +go 1.24.0 -toolchain go1.23.1 +toolchain go1.24.11 require ( github.com/anacrolix/missinggo/v2 v2.8.0 @@ -16,29 +16,44 @@ require ( github.com/imroc/req/v3 v3.52.2 github.com/matoous/go-nanoid/v2 v2.0.0 github.com/mattn/go-ieproxy v0.0.12 + github.com/mholt/archives v0.1.5 github.com/pkg/errors v0.9.1 github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 github.com/rs/zerolog v1.31.0 github.com/xiaoqidun/setft v0.0.0-20220310121541-be86327699ad go.etcd.io/bbolt v1.3.11 golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f - golang.org/x/sync v0.13.0 + golang.org/x/sync v0.17.0 ) require ( - github.com/andybalholm/brotli v1.1.1 // indirect + github.com/STARRY-S/zip v0.2.3 // indirect + github.com/andybalholm/brotli v1.2.0 // indirect + github.com/bodgit/plumbing v1.3.0 // indirect + github.com/bodgit/sevenzip v1.6.1 // indirect + github.com/bodgit/windows v1.0.1 // indirect + github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/icholy/digest v1.1.0 // indirect github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect + github.com/mikelolasagasti/xz v1.0.1 // indirect + github.com/minio/minlz v1.0.1 // indirect + github.com/nwaples/rardecode/v2 v2.2.0 // indirect github.com/onsi/ginkgo/v2 v2.23.4 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/quic-go v0.51.0 // indirect github.com/refraction-networking/utls v1.6.7 // indirect - github.com/stretchr/testify v1.10.0 // indirect + github.com/sorairolake/lzip-go v0.3.8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/ulikunitz/xz v0.5.15 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/mock v0.5.1 // indirect + go4.org v0.0.0-20230225012048-214862532bf5 // indirect ) require ( @@ -128,13 +143,13 @@ require ( go.opentelemetry.io/otel v1.32.0 // indirect go.opentelemetry.io/otel/metric v1.32.0 // indirect go.opentelemetry.io/otel/trace v1.32.0 // indirect - golang.org/x/crypto v0.37.0 // indirect - golang.org/x/mod v0.24.0 // indirect - golang.org/x/net v0.39.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/text v0.24.0 + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/mod v0.27.0 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.29.0 golang.org/x/time v0.8.0 // indirect - golang.org/x/tools v0.32.0 // indirect + golang.org/x/tools v0.36.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect lukechampine.com/blake3 v1.3.0 // indirect modernc.org/libc v1.61.0 // indirect diff --git a/go.sum b/go.sum index 87392db3..a249befd 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,28 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk= crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= @@ -21,6 +37,8 @@ github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrX github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= github.com/RoaringBitmap/roaring v1.9.4 h1:yhEIoH4YezLYT04s1nHehNO64EKFTop/wBhxv2QzDdQ= github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90= +github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4= +github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= @@ -94,8 +112,8 @@ github.com/anacrolix/upnp v0.1.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U= github.com/anacrolix/upnp v0.1.4/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic= github.com/anacrolix/utp v0.2.0 h1:65Cdmr6q9WSw2KsM+rtJFu7rqDzLl2bdysf4KlNPcFI= github.com/anacrolix/utp v0.2.0/go.mod h1:HGk4GYQw1O/3T1+yhqT/F6EcBd+AAwlo9dYErNy7mj8= -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -112,16 +130,26 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bits-and-blooms/bitset v1.15.0 h1:DiCRMscZsGyYePE9AR3sVhKqUXCt5IZvkX5AfAc5xLQ= github.com/bits-and-blooms/bitset v1.15.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= +github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= +github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4= +github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8= +github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= +github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8= github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= @@ -139,6 +167,9 @@ github.com/dop251/goja v0.0.0-20240919115326-6c7d1df7ff05 h1:oK4+QcKsczZjHYTHD0J github.com/dop251/goja v0.0.0-20240919115326-6c7d1df7ff05/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4= github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc h1:MKYt39yZJi0Z9xEeRmDX2L4ocE0ETKcHKw6MVL3R+co= github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc/go.mod h1:VULptt4Q/fNzQUJlqY/GP3qHyU7ZH46mFkBZe0ZTokU= +github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= +github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -152,6 +183,8 @@ github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3O github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= @@ -175,6 +208,8 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A= github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -202,13 +237,18 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -219,6 +259,7 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= @@ -233,12 +274,19 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 h1:gD0vax+4I+mAj+jEChEf25Ia07Jq7kYOFO5PPhAxFl4= github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -257,6 +305,9 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +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/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -267,6 +318,7 @@ github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4= github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y= @@ -279,6 +331,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -287,10 +341,14 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 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 v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 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/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -319,6 +377,12 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ= +github.com/mholt/archives v0.1.5/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4= +github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0= +github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc= +github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A= +github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -339,6 +403,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A= +github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= @@ -349,6 +415,8 @@ github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= @@ -403,6 +471,7 @@ github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -428,6 +497,7 @@ github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5D github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -438,6 +508,7 @@ github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1 github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= @@ -452,13 +523,18 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= +github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik= +github.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -478,6 +554,9 @@ github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EU github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= +github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= @@ -495,6 +574,9 @@ go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= @@ -508,31 +590,55 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs= go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= +go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= +golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -542,8 +648,14 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -554,10 +666,13 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +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.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -569,20 +684,28 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ 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= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -605,16 +728,18 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.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/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= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +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.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -622,8 +747,10 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -631,27 +758,71 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= 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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -686,6 +857,10 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= @@ -738,6 +913,9 @@ modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= zombiezen.com/go/sqlite v0.12.0/go.mod h1:RKdRR9xoQDSnB47yy7G4PtrjGZJtupb/SyEbJZLaRes= zombiezen.com/go/sqlite v1.4.0 h1:N1s3RIljwtp4541Y8rM880qgGIgq3fTD2yks1xftnKU= zombiezen.com/go/sqlite v1.4.0/go.mod h1:0w9F1DN9IZj9AcLS9YDKMboubCACkwYCGkzoy3eG5ik= diff --git a/pkg/base/model.go b/pkg/base/model.go index 8c18dc83..a58ca28c 100644 --- a/pkg/base/model.go +++ b/pkg/base/model.go @@ -2,13 +2,14 @@ package base import ( "fmt" - "github.com/GopeedLab/gopeed/pkg/util" - "github.com/mattn/go-ieproxy" - "golang.org/x/exp/slices" "net/http" "net/url" "sync" "time" + + "github.com/GopeedLab/gopeed/pkg/util" + "github.com/mattn/go-ieproxy" + "golang.org/x/exp/slices" ) // Request download request @@ -183,6 +184,7 @@ type DownloaderStoreConfig struct { Extra map[string]any `json:"extra"` Proxy *DownloaderProxyConfig `json:"proxy"` Webhook *WebhookConfig `json:"webhook"` // Webhook is the webhook configuration + Archive *ArchiveConfig `json:"archive"` // Archive is the archive extraction configuration } func (cfg *DownloaderStoreConfig) Init() *DownloaderStoreConfig { @@ -198,6 +200,12 @@ func (cfg *DownloaderStoreConfig) Init() *DownloaderStoreConfig { if cfg.Webhook == nil { cfg.Webhook = &WebhookConfig{} } + if cfg.Archive == nil { + cfg.Archive = &ArchiveConfig{ + AutoExtract: false, + DeleteAfterExtract: false, + } + } return cfg } @@ -223,6 +231,9 @@ func (cfg *DownloaderStoreConfig) Merge(beforeCfg *DownloaderStoreConfig) *Downl if cfg.Webhook == nil { cfg.Webhook = beforeCfg.Webhook } + if cfg.Archive == nil { + cfg.Archive = beforeCfg.Archive + } return cfg } @@ -232,6 +243,12 @@ type WebhookConfig struct { URLs []string `json:"urls"` // URLs is the list of webhook URLs } +// ArchiveConfig is the archive extraction configuration +type ArchiveConfig struct { + AutoExtract bool `json:"autoExtract"` // AutoExtract enables automatic extraction of archives after download + DeleteAfterExtract bool `json:"deleteAfterExtract"` // DeleteAfterExtract deletes the archive after successful extraction +} + type DownloaderProxyConfig struct { Enable bool `json:"enable"` // System is the flag that use system proxy diff --git a/pkg/base/model_test.go b/pkg/base/model_test.go index c1ba6919..5fff4dbf 100644 --- a/pkg/base/model_test.go +++ b/pkg/base/model_test.go @@ -19,6 +19,10 @@ func TestDownloaderStoreConfig_Init(t *testing.T) { ProtocolConfig: map[string]any{}, Proxy: &DownloaderProxyConfig{}, Webhook: &WebhookConfig{}, + Archive: &ArchiveConfig{ + AutoExtract: false, + DeleteAfterExtract: false, + }, }, }, { @@ -31,6 +35,10 @@ func TestDownloaderStoreConfig_Init(t *testing.T) { ProtocolConfig: map[string]any{}, Proxy: &DownloaderProxyConfig{}, Webhook: &WebhookConfig{}, + Archive: &ArchiveConfig{ + AutoExtract: false, + DeleteAfterExtract: false, + }, }, }, { @@ -47,6 +55,10 @@ func TestDownloaderStoreConfig_Init(t *testing.T) { }, Proxy: &DownloaderProxyConfig{}, Webhook: &WebhookConfig{}, + Archive: &ArchiveConfig{ + AutoExtract: false, + DeleteAfterExtract: false, + }, }, }, { @@ -63,6 +75,29 @@ func TestDownloaderStoreConfig_Init(t *testing.T) { Enable: true, }, Webhook: &WebhookConfig{}, + Archive: &ArchiveConfig{ + AutoExtract: false, + DeleteAfterExtract: false, + }, + }, + }, + { + "Init Archive", + &DownloaderStoreConfig{ + Archive: &ArchiveConfig{ + AutoExtract: true, + DeleteAfterExtract: false, + }, + }, + &DownloaderStoreConfig{ + MaxRunning: 5, + ProtocolConfig: map[string]any{}, + Proxy: &DownloaderProxyConfig{}, + Webhook: &WebhookConfig{}, + Archive: &ArchiveConfig{ + AutoExtract: true, + DeleteAfterExtract: false, + }, }, }, } @@ -76,6 +111,7 @@ func TestDownloaderStoreConfig_Init(t *testing.T) { Extra: tt.fields.Extra, Proxy: tt.fields.Proxy, Webhook: tt.fields.Webhook, + Archive: tt.fields.Archive, } if got := cfg.Init(); !reflect.DeepEqual(got, tt.want) { t.Errorf("Init() = %v, want %v", got, tt.want) @@ -250,6 +286,45 @@ func TestDownloaderStoreConfig_Merge(t *testing.T) { }, }, }, + { + "Merge Archive No Override", + &DownloaderStoreConfig{ + Archive: &ArchiveConfig{ + AutoExtract: true, + }, + }, + args{ + beforeCfg: &DownloaderStoreConfig{ + Archive: &ArchiveConfig{ + AutoExtract: false, + DeleteAfterExtract: false, + }, + }, + }, + &DownloaderStoreConfig{ + Archive: &ArchiveConfig{ + AutoExtract: true, + }, + }, + }, + { + "Merge Archive Override", + &DownloaderStoreConfig{}, + args{ + beforeCfg: &DownloaderStoreConfig{ + Archive: &ArchiveConfig{ + AutoExtract: false, + DeleteAfterExtract: false, + }, + }, + }, + &DownloaderStoreConfig{ + Archive: &ArchiveConfig{ + AutoExtract: false, + DeleteAfterExtract: false, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -261,6 +336,7 @@ func TestDownloaderStoreConfig_Merge(t *testing.T) { Extra: tt.fields.Extra, Proxy: tt.fields.Proxy, Webhook: tt.fields.Webhook, + Archive: tt.fields.Archive, } if got := cfg.Merge(tt.args.beforeCfg); !reflect.DeepEqual(got, tt.want) { t.Errorf("Merge() = %v, want %v", got, tt.want) diff --git a/pkg/download/downloader.go b/pkg/download/downloader.go index 4c5c897e..cba7ee1b 100644 --- a/pkg/download/downloader.go +++ b/pkg/download/downloader.go @@ -877,6 +877,29 @@ func (d *Downloader) watch(task *Task) { }() } + + // Auto-extract archive files + if e.AutoExtract && isArchiveFile(downloadFilePath) { + go func() { + // Extract to the same directory as the downloaded file + destDir := task.Meta.Opts.Path + extractErr := extractArchive(downloadFilePath, destDir, e.ArchivePassword) + if extractErr != nil { + d.Logger.Error().Err(extractErr).Msgf("auto extract archive failed, task id: %s", task.ID) + } else { + d.Logger.Info().Msgf("auto extract archive completed, task id: %s", task.ID) + // Delete archive after successful extraction if enabled + if e.DeleteAfterExtract { + deleteErr := os.Remove(downloadFilePath) + if deleteErr != nil { + d.Logger.Error().Err(deleteErr).Msgf("delete archive after extraction failed, task id: %s", task.ID) + } else { + d.Logger.Info().Msgf("archive deleted after extraction, task id: %s", task.ID) + } + } + } + }() + } } } diff --git a/pkg/download/extract.go b/pkg/download/extract.go new file mode 100644 index 00000000..63e0746d --- /dev/null +++ b/pkg/download/extract.go @@ -0,0 +1,183 @@ +package download + +import ( + "context" + "io" + "os" + "path/filepath" + "slices" + "strings" + + "github.com/mholt/archives" +) + +// supportedArchiveExtensions contains file extensions supported by mholt/archives library +var supportedArchiveExtensions = []string{ + // Archive formats + ".zip", + ".tar", + ".tar.gz", ".tgz", + ".tar.bz2", ".tbz2", + ".tar.xz", ".txz", + ".tar.lz4", ".tlz4", + ".tar.sz", ".tsz", + ".tar.zst", ".tzst", + ".rar", + ".7z", + // Compression formats + ".gz", + ".bz2", + ".xz", + ".lz4", + ".sz", + ".zst", + ".br", + ".lz", +} + +// isArchiveFile checks if a file is a supported archive format +func isArchiveFile(filename string) bool { + lowerName := strings.ToLower(filename) + return slices.ContainsFunc(supportedArchiveExtensions, func(ext string) bool { + return strings.HasSuffix(lowerName, ext) + }) +} + +// extractArchive extracts an archive file to a destination directory +func extractArchive(archivePath string, destDir string, password string) error { + // Open the archive file + file, err := os.Open(archivePath) + if err != nil { + return err + } + defer file.Close() + + // Get file info for format identification + stat, err := file.Stat() + if err != nil { + return err + } + + // Identify the archive format + format, input, err := archives.Identify(context.Background(), archivePath, file) + if err != nil { + return err + } + + // Create destination directory if it doesn't exist + if err := os.MkdirAll(destDir, 0755); err != nil { + return err + } + + // Handle password-protected archives + if password != "" { + // Try to set password for formats that support it + if rar, ok := format.(archives.Rar); ok { + rar.Password = password + format = rar + } + if sz, ok := format.(archives.SevenZip); ok { + sz.Password = password + format = sz + } + // Note: Zip format in archives doesn't have a Password field + // Password-protected zips are not fully supported + } + + // Handle extraction based on format type + switch f := format.(type) { + case archives.Extractor: + // For archive formats (zip, rar, 7z, tar, etc.) + return f.Extract(context.Background(), input, func(ctx context.Context, fileInfo archives.FileInfo) error { + return extractFile(ctx, fileInfo, destDir) + }) + case archives.Decompressor: + // For single-file compression formats (gz, bz2, xz, etc.) + // Decompress to a file without the compression extension + baseName := filepath.Base(archivePath) + lowerBaseName := strings.ToLower(baseName) + for _, ext := range supportedArchiveExtensions { + if strings.HasSuffix(lowerBaseName, ext) { + // Get the actual suffix from the original filename (preserving case) + actualSuffix := baseName[len(baseName)-len(ext):] + baseName = strings.TrimSuffix(baseName, actualSuffix) + break + } + } + destPath := filepath.Join(destDir, baseName) + + reader, err := f.OpenReader(input) + if err != nil { + return err + } + defer reader.Close() + + destFile, err := os.Create(destPath) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, reader) + return err + case archives.Archiver: + // This format is an archiver, try to extract using the extractor interface + if ext, ok := format.(archives.Extractor); ok { + // Reset file position + if seeker, ok := input.(io.Seeker); ok { + seeker.Seek(0, io.SeekStart) + } + return ext.Extract(context.Background(), io.NewSectionReader(file, 0, stat.Size()), func(ctx context.Context, fileInfo archives.FileInfo) error { + return extractFile(ctx, fileInfo, destDir) + }) + } + } + + return nil +} + +// extractFile handles extracting a single file from an archive +func extractFile(ctx context.Context, fileInfo archives.FileInfo, destDir string) error { + // Skip directories, they will be created when extracting files + if fileInfo.IsDir() { + destPath := filepath.Join(destDir, fileInfo.NameInArchive) + return os.MkdirAll(destPath, fileInfo.Mode()) + } + + // Sanitize the path to prevent path traversal attacks + cleanPath := filepath.Clean(fileInfo.NameInArchive) + if strings.HasPrefix(cleanPath, "..") || filepath.IsAbs(cleanPath) { + // Skip files with suspicious paths + return nil + } + + destPath := filepath.Join(destDir, cleanPath) + + // Create parent directories + if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil { + return err + } + + // Open the file from the archive + reader, err := fileInfo.Open() + if err != nil { + return err + } + defer reader.Close() + + // Create the destination file + destFile, err := os.Create(destPath) + if err != nil { + return err + } + defer destFile.Close() + + // Copy the contents + _, err = io.Copy(destFile, reader) + if err != nil { + return err + } + + // Set file permissions + return os.Chmod(destPath, fileInfo.Mode()) +} diff --git a/pkg/download/extract_test.go b/pkg/download/extract_test.go new file mode 100644 index 00000000..febbd50a --- /dev/null +++ b/pkg/download/extract_test.go @@ -0,0 +1,154 @@ +package download + +import ( + "archive/zip" + "os" + "path/filepath" + "testing" +) + +func TestIsArchiveFile(t *testing.T) { + tests := []struct { + filename string + expected bool + }{ + // Archive formats + {"file.zip", true}, + {"file.ZIP", true}, + {"file.tar", true}, + {"file.tar.gz", true}, + {"file.tgz", true}, + {"file.tar.bz2", true}, + {"file.tbz2", true}, + {"file.tar.xz", true}, + {"file.txz", true}, + {"file.tar.zst", true}, + {"file.tzst", true}, + {"file.rar", true}, + {"file.RAR", true}, + {"file.7z", true}, + // Compression formats + {"file.gz", true}, + {"file.bz2", true}, + {"file.xz", true}, + {"file.lz4", true}, + {"file.sz", true}, + {"file.zst", true}, + {"file.br", true}, + {"file.lz", true}, + // Non-archive files + {"file.txt", false}, + {"file.pdf", false}, + {"file.exe", false}, + {"archive", false}, + } + + for _, tt := range tests { + t.Run(tt.filename, func(t *testing.T) { + result := isArchiveFile(tt.filename) + if result != tt.expected { + t.Errorf("isArchiveFile(%q) = %v, expected %v", tt.filename, result, tt.expected) + } + }) + } +} + +func TestExtractArchive_Zip(t *testing.T) { + // Create a temporary directory + tempDir, err := os.MkdirTemp("", "extract_test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tempDir) + + // Create a test zip file + zipPath := filepath.Join(tempDir, "test.zip") + destDir := filepath.Join(tempDir, "extracted") + + if err := createTestZip(zipPath); err != nil { + t.Fatal(err) + } + + // Extract the archive + err = extractArchive(zipPath, destDir, "") + if err != nil { + t.Fatalf("extractArchive failed: %v", err) + } + + // Verify the extracted files + expectedFiles := []string{ + filepath.Join(destDir, "test.txt"), + filepath.Join(destDir, "subdir", "nested.txt"), + } + + for _, path := range expectedFiles { + if _, err := os.Stat(path); os.IsNotExist(err) { + t.Errorf("expected file %q not found after extraction", path) + } + } + + // Verify content + content, err := os.ReadFile(filepath.Join(destDir, "test.txt")) + if err != nil { + t.Fatal(err) + } + if string(content) != "Hello, World!" { + t.Errorf("unexpected content: %q", string(content)) + } +} + +func TestExtractArchive_NonArchive(t *testing.T) { + // Create a temporary directory + tempDir, err := os.MkdirTemp("", "extract_test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tempDir) + + // Create a non-archive file + txtPath := filepath.Join(tempDir, "test.txt") + if err := os.WriteFile(txtPath, []byte("not an archive"), 0644); err != nil { + t.Fatal(err) + } + + destDir := filepath.Join(tempDir, "extracted") + + // Trying to extract a non-archive should return an error + err = extractArchive(txtPath, destDir, "") + if err == nil { + t.Error("expected error when extracting non-archive file") + } +} + +// createTestZip creates a test zip file with sample content +func createTestZip(path string) error { + zipFile, err := os.Create(path) + if err != nil { + return err + } + defer zipFile.Close() + + w := zip.NewWriter(zipFile) + + // Add a file to the root + f, err := w.Create("test.txt") + if err != nil { + return err + } + _, err = f.Write([]byte("Hello, World!")) + if err != nil { + return err + } + + // Add a file in a subdirectory + f, err = w.Create("subdir/nested.txt") + if err != nil { + return err + } + _, err = f.Write([]byte("Nested content")) + if err != nil { + return err + } + + return w.Close() +} diff --git a/pkg/protocol/http/model.go b/pkg/protocol/http/model.go index d642d20a..7b18e4c1 100644 --- a/pkg/protocol/http/model.go +++ b/pkg/protocol/http/model.go @@ -10,6 +10,12 @@ type OptsExtra struct { Connections int `json:"connections"` // AutoTorrent when task download complete, and it is a .torrent file, it will be auto create a new task for the torrent file AutoTorrent bool `json:"autoTorrent"` + // AutoExtract when task download complete, and it is an archive file, it will be auto extracted + AutoExtract bool `json:"autoExtract"` + // ArchivePassword is the password for extracting password-protected archives + ArchivePassword string `json:"archivePassword"` + // DeleteAfterExtract when true, deletes the archive file after successful extraction + DeleteAfterExtract bool `json:"deleteAfterExtract"` } // Stats for download diff --git a/ui/flutter/lib/api/model/downloader_config.dart b/ui/flutter/lib/api/model/downloader_config.dart index 83c416de..3b736a4b 100644 --- a/ui/flutter/lib/api/model/downloader_config.dart +++ b/ui/flutter/lib/api/model/downloader_config.dart @@ -10,6 +10,7 @@ class DownloaderConfig { ExtraConfig extra = ExtraConfig(); ProxyConfig proxy = ProxyConfig(); WebhookConfig webhook = WebhookConfig(); + ArchiveConfig archive = ArchiveConfig(); DownloaderConfig({ this.downloadDir = '', @@ -226,3 +227,19 @@ class ExtraConfigGithubMirror { Map toJson() => _$ExtraConfigGithubMirrorToJson(this); } + +@JsonSerializable() +class ArchiveConfig { + bool autoExtract; + bool deleteAfterExtract; + + ArchiveConfig({ + this.autoExtract = true, + this.deleteAfterExtract = true, + }); + + factory ArchiveConfig.fromJson(Map? json) => + json == null ? ArchiveConfig() : _$ArchiveConfigFromJson(json); + + Map toJson() => _$ArchiveConfigToJson(this); +} diff --git a/ui/flutter/lib/api/model/downloader_config.g.dart b/ui/flutter/lib/api/model/downloader_config.g.dart index 6eeabca8..739b2474 100644 --- a/ui/flutter/lib/api/model/downloader_config.g.dart +++ b/ui/flutter/lib/api/model/downloader_config.g.dart @@ -16,7 +16,9 @@ DownloaderConfig _$DownloaderConfigFromJson(Map json) => ..extra = ExtraConfig.fromJson(json['extra'] as Map?) ..proxy = ProxyConfig.fromJson(json['proxy'] as Map) ..webhook = - WebhookConfig.fromJson(json['webhook'] as Map?); + WebhookConfig.fromJson(json['webhook'] as Map?) + ..archive = + ArchiveConfig.fromJson(json['archive'] as Map?); Map _$DownloaderConfigToJson(DownloaderConfig instance) => { @@ -26,6 +28,7 @@ Map _$DownloaderConfigToJson(DownloaderConfig instance) => 'extra': instance.extra.toJson(), 'proxy': instance.proxy.toJson(), 'webhook': instance.webhook.toJson(), + 'archive': instance.archive.toJson(), }; ProtocolConfig _$ProtocolConfigFromJson(Map json) => @@ -232,3 +235,15 @@ Map _$ExtraConfigGithubMirrorToJson( 'enabled': instance.enabled, 'mirrors': instance.mirrors.map((e) => e.toJson()).toList(), }; + +ArchiveConfig _$ArchiveConfigFromJson(Map json) => + ArchiveConfig( + autoExtract: json['autoExtract'] as bool? ?? true, + deleteAfterExtract: json['deleteAfterExtract'] as bool? ?? true, + ); + +Map _$ArchiveConfigToJson(ArchiveConfig instance) => + { + 'autoExtract': instance.autoExtract, + 'deleteAfterExtract': instance.deleteAfterExtract, + }; diff --git a/ui/flutter/lib/api/model/options.dart b/ui/flutter/lib/api/model/options.dart index 2c5fac45..a1e6e3a7 100644 --- a/ui/flutter/lib/api/model/options.dart +++ b/ui/flutter/lib/api/model/options.dart @@ -26,10 +26,16 @@ class Options { class OptsExtraHttp { int connections; bool autoTorrent; + bool autoExtract; + String archivePassword; + bool deleteAfterExtract; OptsExtraHttp({ this.connections = 0, this.autoTorrent = false, + this.autoExtract = false, + this.archivePassword = '', + this.deleteAfterExtract = false, }); factory OptsExtraHttp.fromJson(Map json) => diff --git a/ui/flutter/lib/api/model/options.g.dart b/ui/flutter/lib/api/model/options.g.dart index 8cbad447..296a5046 100644 --- a/ui/flutter/lib/api/model/options.g.dart +++ b/ui/flutter/lib/api/model/options.g.dart @@ -37,10 +37,16 @@ OptsExtraHttp _$OptsExtraHttpFromJson(Map json) => OptsExtraHttp( connections: (json['connections'] as num?)?.toInt() ?? 0, autoTorrent: json['autoTorrent'] as bool? ?? false, + autoExtract: json['autoExtract'] as bool? ?? false, + archivePassword: json['archivePassword'] as String? ?? '', + deleteAfterExtract: json['deleteAfterExtract'] as bool? ?? false, ); Map _$OptsExtraHttpToJson(OptsExtraHttp instance) => { 'connections': instance.connections, 'autoTorrent': instance.autoTorrent, + 'autoExtract': instance.autoExtract, + 'archivePassword': instance.archivePassword, + 'deleteAfterExtract': instance.deleteAfterExtract, }; diff --git a/ui/flutter/lib/app/modules/create/controllers/create_controller.dart b/ui/flutter/lib/app/modules/create/controllers/create_controller.dart index 7b5550bd..6d522002 100644 --- a/ui/flutter/lib/app/modules/create/controllers/create_controller.dart +++ b/ui/flutter/lib/app/modules/create/controllers/create_controller.dart @@ -23,7 +23,7 @@ class CreateController extends GetxController @override void onInit() { super.onInit(); - advancedTabController = TabController(length: 2, vsync: this); + advancedTabController = TabController(length: 3, vsync: this); directDownload.value = Get.find() .downloaderConfig .value diff --git a/ui/flutter/lib/app/modules/create/views/create_view.dart b/ui/flutter/lib/app/modules/create/views/create_view.dart index 67cdca8f..9a4fe0b8 100644 --- a/ui/flutter/lib/app/modules/create/views/create_view.dart +++ b/ui/flutter/lib/app/modules/create/views/create_view.dart @@ -56,10 +56,13 @@ class CreateView extends GetView { ), ]; final _btTrackerController = TextEditingController(); + final _archivePasswordController = TextEditingController(); final _availableSchemes = ["http:", "https:", "magnet:"]; final _skipVerifyCertController = false.obs; + final _autoExtractController = Rxn(); + final _deleteAfterExtractController = Rxn(); CreateView({Key? key}) : super(key: key); @@ -77,6 +80,15 @@ class CreateView extends GetView { final downloadDir = appController.downloaderConfig.value.downloadDir; _pathController.text = renderPathPlaceholders(downloadDir); } + // Initialize archive settings from global config if not already set + if (_autoExtractController.value == null) { + _autoExtractController.value = + appController.downloaderConfig.value.archive.autoExtract; + } + if (_deleteAfterExtractController.value == null) { + _deleteAfterExtractController.value = + appController.downloaderConfig.value.archive.deleteAfterExtract; + } final CreateTask? routerParams = Get.rootDelegate.arguments(); if (routerParams?.req?.url.isNotEmpty ?? false) { @@ -497,17 +509,20 @@ class CreateView extends GetView { const Divider(), TabBar( controller: controller.advancedTabController, - tabs: const [ - Tab( + tabs: [ + const Tab( text: 'HTTP', ), - Tab( + const Tab( text: 'BitTorrent', + ), + Tab( + text: 'archives'.tr, ) ], ), DefaultTabController( - length: 2, + length: 3, child: ContentSizeTabBarView( controller: controller.advancedTabController, @@ -602,6 +617,63 @@ class CreateView extends GetView { hintText: 'addTrackerHit'.tr, )), ], + ), + Column( + children: [ + Padding( + padding: + const EdgeInsets.only(top: 10), + child: CompactCheckbox( + label: 'autoExtract'.tr, + value: _autoExtractController + .value ?? false, + onChanged: (bool? value) { + _autoExtractController + .value = value ?? false; + }, + textStyle: const TextStyle( + color: Colors.grey, + ), + ), + ), + Obx( + () => Visibility( + visible: _autoExtractController.value ?? false, + child: Column( + children: [ + Padding( + padding: + const EdgeInsets.only(top: 10), + child: TextFormField( + controller: _archivePasswordController, + obscureText: true, + decoration: InputDecoration( + labelText: 'archivePassword'.tr, + hintText: 'archivePasswordHint'.tr, + ), + ), + ), + Padding( + padding: + const EdgeInsets.only(top: 10), + child: CompactCheckbox( + label: 'deleteAfterExtract'.tr, + value: _deleteAfterExtractController + .value ?? false, + onChanged: (bool? value) { + _deleteAfterExtractController + .value = value ?? false; + }, + textStyle: const TextStyle( + color: Colors.grey, + ), + ), + ), + ], + ), + ), + ), + ], ) ], ), @@ -798,7 +870,10 @@ class CreateView extends GetView { Object? parseReqOptsExtra() { return OptsExtraHttp() ..connections = int.tryParse(_connectionsController.text) ?? 0 - ..autoTorrent = true; + ..autoTorrent = true + ..autoExtract = _autoExtractController.value ?? false + ..archivePassword = _archivePasswordController.text + ..deleteAfterExtract = _deleteAfterExtractController.value ?? false; } String _hitText() { diff --git a/ui/flutter/lib/app/modules/setting/views/setting_view.dart b/ui/flutter/lib/app/modules/setting/views/setting_view.dart index ecef615e..a388ee10 100644 --- a/ui/flutter/lib/app/modules/setting/views/setting_view.dart +++ b/ui/flutter/lib/app/modules/setting/views/setting_view.dart @@ -148,6 +148,46 @@ class SettingView extends GetView { ); }); + // Archive auto extract configuration + final buildAutoExtract = _buildConfigItem('autoExtract', () { + return appController.downloaderConfig.value.archive.autoExtract + ? 'on'.tr + : 'off'.tr; + }, (Key key) { + return Container( + alignment: Alignment.centerLeft, + child: Switch( + value: appController.downloaderConfig.value.archive.autoExtract, + onChanged: (bool value) async { + appController.downloaderConfig.update((val) { + val!.archive.autoExtract = value; + }); + await debounceSave(); + }, + ), + ); + }); + + // Archive delete after extract configuration + final buildDeleteAfterExtract = _buildConfigItem('deleteAfterExtract', () { + return appController.downloaderConfig.value.archive.deleteAfterExtract + ? 'on'.tr + : 'off'.tr; + }, (Key key) { + return Container( + alignment: Alignment.centerLeft, + child: Switch( + value: appController.downloaderConfig.value.archive.deleteAfterExtract, + onChanged: (bool value) async { + appController.downloaderConfig.update((val) { + val!.archive.deleteAfterExtract = value; + }); + await debounceSave(); + }, + ), + ); + }); + // Download categories configuration buildDownloadCategories() { final categories = downloaderCfg.value.extra.downloadCategories @@ -1315,6 +1355,14 @@ class SettingView extends GetView { buildAutoStartup(), ]), )), + Text('archives'.tr), + Card( + child: Column( + children: _addDivider([ + buildAutoExtract(), + buildDeleteAfterExtract(), + ]), + )), const Text('HTTP'), Card( child: Column( diff --git a/ui/flutter/lib/i18n/langs/de_de.dart b/ui/flutter/lib/i18n/langs/de_de.dart index ae977e84..faefae50 100644 --- a/ui/flutter/lib/i18n/langs/de_de.dart +++ b/ui/flutter/lib/i18n/langs/de_de.dart @@ -116,6 +116,11 @@ const deDE = { 'taskUrl': 'Aufgaben-URL', 'downloadPath': 'Download-Pfad', 'skipVerifyCert': 'Zertifikatsüberprüfung überspringen', + 'archives': 'Archive', + 'autoExtract': 'Archive automatisch entpacken', + 'archivePassword': 'Archiv-Passwort', + 'archivePasswordHint': 'Leer lassen, wenn nicht passwortgeschützt', + 'deleteAfterExtract': 'Archiv nach Entpacken löschen', 'name': 'Name', 'size': 'Größe', 'unknown': 'Unbekannt', diff --git a/ui/flutter/lib/i18n/langs/en_us.dart b/ui/flutter/lib/i18n/langs/en_us.dart index b2079de1..b179ec88 100644 --- a/ui/flutter/lib/i18n/langs/en_us.dart +++ b/ui/flutter/lib/i18n/langs/en_us.dart @@ -124,6 +124,11 @@ const enUS = { 'taskUrl': 'Task URL', 'downloadPath': 'Download Path', 'skipVerifyCert': 'Skip Certificate Verification', + 'archives': 'Archives', + 'autoExtract': 'Auto Extract Archives', + 'archivePassword': 'Archive Password', + 'archivePasswordHint': 'Leave empty if not password protected', + 'deleteAfterExtract': 'Delete Archive After Extraction', 'name': 'Name', 'size': 'Size', 'unknown': 'Unknown', diff --git a/ui/flutter/lib/i18n/langs/es_es.dart b/ui/flutter/lib/i18n/langs/es_es.dart index 2de5c012..83179a3c 100644 --- a/ui/flutter/lib/i18n/langs/es_es.dart +++ b/ui/flutter/lib/i18n/langs/es_es.dart @@ -108,6 +108,11 @@ const esES = { 'taskUrl': 'URL de la Tarea', 'downloadPath': 'Ruta de Descarga', 'skipVerifyCert': 'Omitir Verificación de Certificado', + 'archives': 'Archivos', + 'autoExtract': 'Extraer archivos automáticamente', + 'archivePassword': 'Contraseña del archivo', + 'archivePasswordHint': 'Dejar vacío si no tiene contraseña', + 'deleteAfterExtract': 'Eliminar archivo después de extraer', 'insertPlaceholder': 'Insertar marcador de posición', 'placeholderYear': 'Año actual', 'placeholderMonth': 'Mes actual (01-12)', diff --git a/ui/flutter/lib/i18n/langs/fa_ir.dart b/ui/flutter/lib/i18n/langs/fa_ir.dart index 06898eab..58192aac 100644 --- a/ui/flutter/lib/i18n/langs/fa_ir.dart +++ b/ui/flutter/lib/i18n/langs/fa_ir.dart @@ -63,6 +63,11 @@ const faIR = { 'از تمامی افرادی که در ساخت و توسعه‌ی جامعه‌ی Gopeed مشارکت کرده‌اند، سپاسگزاری می‌کنیم!', 'browserExtension': 'افزونه مرورگر', 'skipVerifyCert': 'رد کردن تأیید گواهینامه', + 'archives': 'آرشیوها', + 'autoExtract': 'استخراج خودکار بایگانی‌ها', + 'archivePassword': 'رمز عبور بایگانی', + 'archivePasswordHint': 'اگر رمز ندارد خالی بگذارید', + 'deleteAfterExtract': 'حذف آرشیو پس از استخراج', 'insertPlaceholder': 'درج نگهدارنده', 'placeholderYear': 'سال جاری', 'placeholderMonth': 'ماه جاری (01-12)', diff --git a/ui/flutter/lib/i18n/langs/fr_fr.dart b/ui/flutter/lib/i18n/langs/fr_fr.dart index d20cde67..68a3400f 100644 --- a/ui/flutter/lib/i18n/langs/fr_fr.dart +++ b/ui/flutter/lib/i18n/langs/fr_fr.dart @@ -100,6 +100,11 @@ const frFR = { 'browserExtension': 'Extension du navigateur', 'launchAtStartup': 'Lancer au démarrage', 'skipVerifyCert': 'Ignorer la vérification du certificat', + 'archives': 'Archives', + 'autoExtract': 'Extraire automatiquement les archives', + 'archivePassword': 'Mot de passe de l\'archive', + 'archivePasswordHint': 'Laisser vide si non protégé par mot de passe', + 'deleteAfterExtract': "Supprimer l'archive après extraction", 'insertPlaceholder': 'Insérer un espace réservé', 'placeholderYear': 'Année en cours', 'placeholderMonth': 'Mois en cours (01-12)', diff --git a/ui/flutter/lib/i18n/langs/hu_hu.dart b/ui/flutter/lib/i18n/langs/hu_hu.dart index 84c95f61..04310a26 100644 --- a/ui/flutter/lib/i18n/langs/hu_hu.dart +++ b/ui/flutter/lib/i18n/langs/hu_hu.dart @@ -116,6 +116,11 @@ const huHU = { 'taskUrl': 'Feladat URL', 'downloadPath': 'Letöltési útvonal', 'skipVerifyCert': 'Tanúsítvány ellenőrzés átugrása', + 'archives': 'Archívumok', + 'autoExtract': 'Archívumok automatikus kicsomagolása', + 'archivePassword': 'Archívum jelszó', + 'archivePasswordHint': 'Hagyja üresen, ha nincs jelszóval védve', + 'deleteAfterExtract': 'Archívum törlése kicsomagolás után', 'name': 'Név', 'size': 'Méret', 'unknown': 'Ismeretlen', diff --git a/ui/flutter/lib/i18n/langs/id_id.dart b/ui/flutter/lib/i18n/langs/id_id.dart index 4af06c61..25c0e6ac 100644 --- a/ui/flutter/lib/i18n/langs/id_id.dart +++ b/ui/flutter/lib/i18n/langs/id_id.dart @@ -110,6 +110,11 @@ const idID = { 'taskUrl': 'URL Tugas', 'downloadPath': 'Direktori Unduhan', 'skipVerifyCert': 'Lupakan verifikasi sertifikat', + 'archives': 'Arsip', + 'autoExtract': 'Ekstrak Arsip Otomatis', + 'archivePassword': 'Kata Sandi Arsip', + 'archivePasswordHint': 'Kosongkan jika tidak dilindungi kata sandi', + 'deleteAfterExtract': 'Hapus arsip setelah ekstraksi', 'insertPlaceholder': 'Sisipkan placeholder', 'placeholderYear': 'Tahun saat ini', 'placeholderMonth': 'Bulan saat ini (01-12)', diff --git a/ui/flutter/lib/i18n/langs/it_it.dart b/ui/flutter/lib/i18n/langs/it_it.dart index 7905c812..b960b3b5 100644 --- a/ui/flutter/lib/i18n/langs/it_it.dart +++ b/ui/flutter/lib/i18n/langs/it_it.dart @@ -98,6 +98,11 @@ const itIT = { 'browserExtension': 'Estensione del browser', 'launchAtStartup': "Lancia all'avvio", 'skipVerifyCert': 'Salta la verifica del certificato', + 'archives': 'Archivi', + 'autoExtract': 'Estrai automaticamente gli archivi', + 'archivePassword': 'Password archivio', + 'archivePasswordHint': 'Lasciare vuoto se non protetto da password', + 'deleteAfterExtract': "Elimina l'archivio dopo l'estrazione", 'insertPlaceholder': 'Inserisci segnaposto', 'placeholderYear': 'Anno corrente', 'placeholderMonth': 'Mese corrente (01-12)', diff --git a/ui/flutter/lib/i18n/langs/ja_jp.dart b/ui/flutter/lib/i18n/langs/ja_jp.dart index 008902c3..0b3f7d23 100644 --- a/ui/flutter/lib/i18n/langs/ja_jp.dart +++ b/ui/flutter/lib/i18n/langs/ja_jp.dart @@ -64,6 +64,11 @@ const jaJP = { 'thanksDesc': 'Gopeedコミュニティの建設に協力してくださったすべての貢献者の方々に感謝します!', 'browserExtension': 'ブラウザ拡張機能', 'skipVerifyCert': '証明書の検証をスキップ', + 'archives': 'アーカイブ', + 'autoExtract': 'アーカイブを自動展開', + 'archivePassword': 'アーカイブパスワード', + 'archivePasswordHint': 'パスワードなしの場合は空のままにしてください', + 'deleteAfterExtract': '展開後にアーカイブを削除', 'insertPlaceholder': 'プレースホルダーを挿入', 'placeholderYear': '現在の年', 'placeholderMonth': '現在の月 (01-12)', diff --git a/ui/flutter/lib/i18n/langs/pl_pl.dart b/ui/flutter/lib/i18n/langs/pl_pl.dart index bfb5d20c..9ae4dcef 100644 --- a/ui/flutter/lib/i18n/langs/pl_pl.dart +++ b/ui/flutter/lib/i18n/langs/pl_pl.dart @@ -96,6 +96,11 @@ const plPL = { 'browserExtension': 'Wtyczka dla przeglądarki', 'launchAtStartup': 'Uruchom na starcie', 'skipVerifyCert': 'Pomiń weryfikację certyfikatu', + 'archives': 'Archiwa', + 'autoExtract': 'Automatycznie wyodrębnij archiwa', + 'archivePassword': 'Hasło archiwum', + 'archivePasswordHint': 'Pozostaw puste, jeśli nie ma hasła', + 'deleteAfterExtract': 'Usuń archiwum po rozpakowaniu', 'insertPlaceholder': 'Wstaw placeholder', 'placeholderYear': 'Bieżący rok', 'placeholderMonth': 'Bieżący miesiąc (01-12)', diff --git a/ui/flutter/lib/i18n/langs/pt_br.dart b/ui/flutter/lib/i18n/langs/pt_br.dart index 765126b3..11c3d1cf 100644 --- a/ui/flutter/lib/i18n/langs/pt_br.dart +++ b/ui/flutter/lib/i18n/langs/pt_br.dart @@ -113,6 +113,11 @@ const ptBR = { 'taskUrl': 'Tarefa URL', 'downloadPath': 'Download Path', 'skipVerifyCert': 'Pular Verificação de Certificado', + 'archives': 'Arquivos', + 'autoExtract': 'Extrair arquivos automaticamente', + 'archivePassword': 'Senha do arquivo', + 'archivePasswordHint': 'Deixar vazio se não estiver protegido por senha', + 'deleteAfterExtract': 'Excluir arquivo após extração', 'name': 'Nome', 'size': 'Tamanho', 'unknown': 'Desconhecido', diff --git a/ui/flutter/lib/i18n/langs/ru_ru.dart b/ui/flutter/lib/i18n/langs/ru_ru.dart index a80d2945..f37bdaab 100644 --- a/ui/flutter/lib/i18n/langs/ru_ru.dart +++ b/ui/flutter/lib/i18n/langs/ru_ru.dart @@ -113,6 +113,11 @@ const ruRU = { 'taskUrl': 'URL задачи', 'downloadPath': 'Путь загрузки', 'skipVerifyCert': 'Пропустить проверку сертификата', + 'archives': 'Архивы', + 'autoExtract': 'Автоматически распаковать архивы', + 'archivePassword': 'Пароль архива', + 'archivePasswordHint': 'Оставить пустым, если архив не защищён паролем', + 'deleteAfterExtract': 'Удалить архив после распаковки', 'name': 'Название', 'size': 'Размер', 'unknown': 'Неизвестно', diff --git a/ui/flutter/lib/i18n/langs/ta_ta.dart b/ui/flutter/lib/i18n/langs/ta_ta.dart index 7ea6bc49..bb9c6cb6 100644 --- a/ui/flutter/lib/i18n/langs/ta_ta.dart +++ b/ui/flutter/lib/i18n/langs/ta_ta.dart @@ -98,6 +98,11 @@ const taTA = { 'browserExtension': 'உலாவி நீட்டிப்பு', 'launchAtStartup': 'தொடக்கத்தின் போது இயங்கு', 'skipVerifyCert': 'திருத்தி சான்று சரிபார்க்கவும்', + 'archives': 'காப்பகங்கள்', + 'autoExtract': 'காப்பகங்களை தானாக பிரித்தெடு', + 'archivePassword': 'காப்பக கடவுச்சொல்', + 'archivePasswordHint': 'கடவுச்சொல் இல்லையென்றால் காலியாக விடவும்', + 'deleteAfterExtract': 'பிரித்தெடுத்த பிறகு காப்பகத்தை நீக்கு', 'insertPlaceholder': 'இடங்காட்டி செருக', 'placeholderYear': 'தற்போதைய ஆண்டு', 'placeholderMonth': 'தற்போதைய மாதம் (01-12)', diff --git a/ui/flutter/lib/i18n/langs/tr_tr.dart b/ui/flutter/lib/i18n/langs/tr_tr.dart index a5b0bc42..c11f60dc 100644 --- a/ui/flutter/lib/i18n/langs/tr_tr.dart +++ b/ui/flutter/lib/i18n/langs/tr_tr.dart @@ -114,6 +114,11 @@ const trTR = { 'taskUrl': 'Görev URL’si', 'downloadPath': 'İndirme Yolu', 'skipVerifyCert': 'Sertifika Doğrulamayı Atla', + 'archives': 'Arşivler', + 'autoExtract': 'Arşivleri otomatik çıkart', + 'archivePassword': 'Arşiv şifresi', + 'archivePasswordHint': 'Şifre yoksa boş bırakın', + 'deleteAfterExtract': 'Çıkarmadan sonra arşivi sil', 'name': 'Ad', 'size': 'Boyut', 'unknown': 'Bilinmeyen', diff --git a/ui/flutter/lib/i18n/langs/uk_ua.dart b/ui/flutter/lib/i18n/langs/uk_ua.dart index 09bd3875..3024847b 100644 --- a/ui/flutter/lib/i18n/langs/uk_ua.dart +++ b/ui/flutter/lib/i18n/langs/uk_ua.dart @@ -113,6 +113,11 @@ const ukUA = { 'taskUrl': 'URL завдання', 'downloadPath': 'Шлях завантаження', 'skipVerifyCert': 'Пропустити перевірку сертифіката', + 'archives': 'Архіви', + 'autoExtract': 'Автоматично розпаковувати архіви', + 'archivePassword': 'Пароль архіву', + 'archivePasswordHint': 'Залишити порожнім, якщо архів не захищений паролем', + 'deleteAfterExtract': 'Видалити архів після розпакування', 'name': 'Назва', 'size': 'Розмір', 'unknown': 'Невідомо', diff --git a/ui/flutter/lib/i18n/langs/vi_vn.dart b/ui/flutter/lib/i18n/langs/vi_vn.dart index 4eae4e0e..5bfc2277 100644 --- a/ui/flutter/lib/i18n/langs/vi_vn.dart +++ b/ui/flutter/lib/i18n/langs/vi_vn.dart @@ -91,6 +91,11 @@ const viVN = { 'Cảm ơn tất cả những người đóng góp đã giúp xây dựng và phát triển cộng đồng Gopeed!', 'browserExtension': 'Tiện ích mở rộng trình duyệt', 'skipVerifyCert': 'Bỏ qua xác thực chứng chỉ', + 'archives': 'Tập tin nén', + 'autoExtract': 'Tự động giải nén tập tin nén', + 'archivePassword': 'Mật khẩu tập tin nén', + 'archivePasswordHint': 'Để trống nếu không có mật khẩu', + 'deleteAfterExtract': 'Xóa tập tin nén sau khi giải nén', 'insertPlaceholder': 'Chèn placeholder', 'placeholderYear': 'Năm hiện tại', 'placeholderMonth': 'Tháng hiện tại (01-12)', diff --git a/ui/flutter/lib/i18n/langs/zh_cn.dart b/ui/flutter/lib/i18n/langs/zh_cn.dart index cd508425..eec6c812 100644 --- a/ui/flutter/lib/i18n/langs/zh_cn.dart +++ b/ui/flutter/lib/i18n/langs/zh_cn.dart @@ -122,6 +122,11 @@ const zhCN = { 'taskUrl': '任务链接', 'downloadPath': '下载路径', 'skipVerifyCert': '跳过证书验证', + 'archives': '压缩包', + 'autoExtract': '自动解压压缩包', + 'archivePassword': '压缩包密码', + 'archivePasswordHint': '如无密码请留空', + 'deleteAfterExtract': '解压后删除压缩包', 'name': '名称', 'size': '大小', 'unknown': '未知', diff --git a/ui/flutter/lib/i18n/langs/zh_tw.dart b/ui/flutter/lib/i18n/langs/zh_tw.dart index 51d18a17..77a40230 100644 --- a/ui/flutter/lib/i18n/langs/zh_tw.dart +++ b/ui/flutter/lib/i18n/langs/zh_tw.dart @@ -110,6 +110,11 @@ const zhTW = { 'taskUrl': '任務連結', 'downloadPath': '下載路徑', 'skipVerifyCert': '跳過憑證驗證', + 'archives': '壓縮檔', + 'autoExtract': '自動解壓縮壓縮包', + 'archivePassword': '壓縮包密碼', + 'archivePasswordHint': '如無密碼請留空', + 'deleteAfterExtract': '解壓後刪除壓縮檔', 'name': '名稱', 'size': '大小', 'unknown': '未知',