Merge pull request #221 from tuna/go-1.25

Bump toolchain, CI and dependencies
This commit is contained in:
Shengqi Chen
2026-04-13 21:53:49 +08:00
committed by GitHub
28 changed files with 1005 additions and 449 deletions

View File

@@ -14,11 +14,11 @@ jobs:
contents: write
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '^1.23'
go-version-file: go.mod
id: go
- name: Build
run: |
@@ -28,7 +28,7 @@ jobs:
tar -cz --numeric-owner --owner root --group root -f tunasync-${TAG}-$i-bin.tar.gz -C build-$i tunasync tunasynctl
done
- name: Create Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ github.ref_name }}

View File

@@ -15,12 +15,12 @@ jobs:
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '^1.23'
go-version-file: go.mod
id: go
- name: Get dependencies
@@ -34,7 +34,7 @@ jobs:
make tunasynctl
- name: Keep artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: tunasync-bin
path: build-linux-amd64/
@@ -53,15 +53,15 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y cgroup-tools
docker pull alpine:3.8
docker pull alpine:3.23
- name: Check out code into the Go module directory
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '^1.22'
go-version-file: go.mod
id: go
- name: Run Unit tests.
@@ -88,17 +88,17 @@ jobs:
(TESTREEXEC="$case" TERM=xterm-256color exec -a "$argv0" ./worker.test -test.v=true -test.coverprofile "profile5_$case.gcov" -test.run TestReexec -- "$@")
}
run_test_reexec 1 tunasync-exec __dummy__
run_test_reexec 2 tunasync-exec /tmp/dummy_exec
run_test_reexec 2 tunasync-exec /tmp/dummy_exec 3< /dev/null
run_test_reexec 3 tunasync-exec /tmp/dummy_exec 3< <(echo -n "abrt")
run_test_reexec 4 tunasync-exec /tmp/dummy_exec 3< <(echo -n "cont")
run_test_reexec 5 tunasync-exec2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
with:
driver-opts: network=host
- name: Cache Docker layers
uses: actions/cache@v4
uses: actions/cache@v5
if: github.event_name == 'push'
with:
path: /tmp/.buildx-cache
@@ -106,7 +106,7 @@ jobs:
restore-keys: |
${{ runner.os }}-buildx-
- name: Cache Docker layers
uses: actions/cache@v4
uses: actions/cache@v5
if: github.event_name == 'pull_request'
with:
path: /tmp/.buildx-cache
@@ -125,7 +125,7 @@ jobs:
mkdir -p /tmp/.buildx-cache
- name: Build Docker image for uml rootfs
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .umlrootfs
file: .umlrootfs/Dockerfile

View File

@@ -17,7 +17,8 @@ $(BUILDBIN:%=build-$(ARCH)/%) : build-$(ARCH)/% : cmd/%
GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=0 go build -o $@ -ldflags ${LDFLAGS} github.com/tuna/tunasync/$<
test:
go test -v -covermode=count -coverprofile=profile.gcov ./...
# see: https://stackoverflow.com/questions/79780882/go-no-such-tool-covdata-in-go-1-25
GOTOOLCHAIN=go1.26.2+auto go test -v -covermode=count -coverprofile=profile.gcov ./...
build-test-worker:
CGO_ENABLED=0 go test -c -covermode=count github.com/tuna/tunasync/worker

View File

@@ -11,8 +11,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/moby/sys/reexec"
"github.com/pkg/profile"
"github.com/urfave/cli"
"gopkg.in/op/go-logging.v1"
"github.com/urfave/cli/v2"
tunasync "github.com/tuna/tunasync/internal"
"github.com/tuna/tunasync/manager"
@@ -24,7 +23,7 @@ var (
githash = "No githash provided"
)
var logger = logging.MustGetLogger("tunasync")
var logger = tunasync.MustGetLogger("tunasync")
func startManager(c *cli.Context) error {
tunasync.InitLogger(c.Bool("verbose"), c.Bool("debug"), c.Bool("with-systemd"))
@@ -140,54 +139,56 @@ func main() {
app.Usage = "tunasync mirror job management tool"
app.EnableBashCompletion = true
app.Version = tunasync.Version
app.Commands = []cli.Command{
app.Commands = []*cli.Command{
{
Name: "manager",
Aliases: []string{"m"},
Usage: "start the tunasync manager",
Action: startManager,
Flags: []cli.Flag{
cli.StringFlag{
Name: "config, c",
Usage: "Load manager configurations from `FILE`",
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "Load manager configurations from `FILE`",
},
cli.StringFlag{
&cli.StringFlag{
Name: "addr",
Usage: "The manager will listen on `ADDR`",
},
cli.StringFlag{
&cli.IntFlag{
Name: "port",
Usage: "The manager will bind to `PORT`",
},
cli.StringFlag{
&cli.StringFlag{
Name: "cert",
Usage: "Use SSL certificate from `FILE`",
},
cli.StringFlag{
&cli.StringFlag{
Name: "key",
Usage: "Use SSL key from `FILE`",
},
cli.StringFlag{
&cli.StringFlag{
Name: "db-file",
Usage: "Use `FILE` as the database file",
},
cli.StringFlag{
&cli.StringFlag{
Name: "db-type",
Usage: "Use database type `TYPE`",
},
cli.BoolFlag{
Name: "verbose, v",
Usage: "Enable verbose logging",
&cli.BoolFlag{
Name: "verbose",
Aliases: []string{"v"},
Usage: "Enable verbose logging",
},
cli.BoolFlag{
&cli.BoolFlag{
Name: "debug",
Usage: "Run manager in debug mode",
},
cli.BoolFlag{
&cli.BoolFlag{
Name: "with-systemd",
Usage: "Enable systemd-compatible logging",
},
cli.StringFlag{
&cli.StringFlag{
Name: "pidfile",
Value: "/run/tunasync/tunasync.manager.pid",
Usage: "The pid file of the manager process",
@@ -200,28 +201,30 @@ func main() {
Usage: "start the tunasync worker",
Action: startWorker,
Flags: []cli.Flag{
cli.StringFlag{
Name: "config, c",
Usage: "Load worker configurations from `FILE`",
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "Load worker configurations from `FILE`",
},
cli.BoolFlag{
Name: "verbose, v",
Usage: "Enable verbose logging",
&cli.BoolFlag{
Name: "verbose",
Aliases: []string{"v"},
Usage: "Enable verbose logging",
},
cli.BoolFlag{
&cli.BoolFlag{
Name: "debug",
Usage: "Run worker in debug mode",
},
cli.BoolFlag{
&cli.BoolFlag{
Name: "with-systemd",
Usage: "Enable systemd-compatible logging",
},
cli.StringFlag{
&cli.StringFlag{
Name: "pidfile",
Value: "/run/tunasync/tunasync.worker.pid",
Usage: "The pid file of the worker process",
},
cli.StringFlag{
&cli.StringFlag{
Name: "prof-path",
Value: "",
Usage: "Go profiling file path",

View File

@@ -12,8 +12,7 @@ import (
"time"
"github.com/BurntSushi/toml"
"github.com/urfave/cli"
"gopkg.in/op/go-logging.v1"
"github.com/urfave/cli/v2"
tunasync "github.com/tuna/tunasync/internal"
)
@@ -33,7 +32,7 @@ const (
userCfgFile = "$HOME/.config/tunasync/ctl.conf" // user-specific conf
)
var logger = logging.MustGetLogger("tunasynctl")
var logger = tunasync.MustGetLogger("tunasynctl")
var baseURL string
var client *http.Client
@@ -42,7 +41,7 @@ func initializeWrapper(handler cli.ActionFunc) cli.ActionFunc {
return func(c *cli.Context) error {
err := initialize(c)
if err != nil {
return cli.NewExitError(err.Error(), 1)
return cli.Exit(err.Error(), 1)
}
return handler(c)
}
@@ -83,7 +82,7 @@ func initialize(c *cli.Context) error {
return err
}
}
logger.Debug("user config file: %s", os.ExpandEnv(userCfgFile))
logger.Debugf("user config file: %s", os.ExpandEnv(userCfgFile))
if _, err := os.Stat(os.ExpandEnv(userCfgFile)); err == nil {
err = loadConfig(os.ExpandEnv(userCfgFile), cfg)
if err != nil {
@@ -134,14 +133,14 @@ func listWorkers(c *cli.Context) error {
var workers []tunasync.WorkerStatus
_, err := tunasync.GetJSON(baseURL+listWorkersPath, &workers, client)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Filed to correctly get informations from"+
"manager server: %s", err.Error()), 1)
}
b, err := json.MarshalIndent(workers, "", " ")
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Error printing out informations: %s",
err.Error()),
1)
@@ -156,7 +155,7 @@ func listJobs(c *cli.Context) error {
var jobs []tunasync.WebMirrorStatus
_, err := tunasync.GetJSON(baseURL+listJobsPath, &jobs, client)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to correctly get information "+
"of all jobs from manager server: %s", err.Error()),
1)
@@ -168,7 +167,7 @@ func listJobs(c *cli.Context) error {
var status tunasync.SyncStatus
err = status.UnmarshalJSON([]byte("\"" + strings.TrimSpace(s) + "\""))
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Error parsing status: %s", err.Error()),
1)
}
@@ -188,9 +187,9 @@ func listJobs(c *cli.Context) error {
}
} else {
var jobs []tunasync.MirrorStatus
args := c.Args()
args := c.Args().Slice()
if len(args) == 0 {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Usage Error: jobs command need at"+
" least one arguments or \"--all\" flag."), 1)
}
@@ -210,7 +209,7 @@ func listJobs(c *cli.Context) error {
for range args {
job := <-ans
if job == nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to correctly get information "+
"of jobs from at least one manager"),
1)
@@ -224,7 +223,7 @@ func listJobs(c *cli.Context) error {
tpl := template.New("")
_, err := tpl.Parse(format)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Error parsing format template: %s", err.Error()),
1)
}
@@ -233,7 +232,7 @@ func listJobs(c *cli.Context) error {
for _, job := range jobs {
err = tpl.Execute(os.Stdout, job)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Error printing out information: %s", err.Error()),
1)
}
@@ -243,7 +242,7 @@ func listJobs(c *cli.Context) error {
for _, job := range jobs {
err = tpl.Execute(os.Stdout, job)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Error printing out information: %s", err.Error()),
1)
}
@@ -253,7 +252,7 @@ func listJobs(c *cli.Context) error {
} else {
b, err := json.MarshalIndent(genericJobs, "", " ")
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Error printing out information: %s", err.Error()),
1)
}
@@ -264,13 +263,13 @@ func listJobs(c *cli.Context) error {
}
func updateMirrorSize(c *cli.Context) error {
args := c.Args()
args := c.Args().Slice()
if len(args) != 2 {
return cli.NewExitError("Usage: tunasynctl set-size -w <worker-id> <mirror> <size>", 1)
return cli.Exit("Usage: tunasynctl set-size -w <worker-id> <mirror> <size>", 1)
}
workerID := c.String("worker")
mirrorID := args.Get(0)
mirrorSize := args.Get(1)
mirrorID := args[0]
mirrorSize := args[1]
msg := struct {
Name string `json:"name"`
@@ -286,7 +285,7 @@ func updateMirrorSize(c *cli.Context) error {
resp, err := tunasync.PostJSON(url, msg, client)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to send request to manager: %s",
err.Error()),
1)
@@ -294,7 +293,7 @@ func updateMirrorSize(c *cli.Context) error {
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Manager failed to update mirror size: %s", body), 1,
)
}
@@ -302,7 +301,7 @@ func updateMirrorSize(c *cli.Context) error {
var status tunasync.MirrorStatus
json.Unmarshal(body, &status)
if status.Size != mirrorSize {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf(
"Mirror size error, expecting %s, manager returned %s",
mirrorSize, status.Size,
@@ -315,13 +314,13 @@ func updateMirrorSize(c *cli.Context) error {
}
func removeWorker(c *cli.Context) error {
args := c.Args()
args := c.Args().Slice()
if len(args) != 0 {
return cli.NewExitError("Usage: tunasynctl -w <worker-id>", 1)
return cli.Exit("Usage: tunasynctl -w <worker-id>", 1)
}
workerID := c.String("worker")
if len(workerID) == 0 {
return cli.NewExitError("Please specify the <worker-id>", 1)
return cli.Exit("Please specify the <worker-id>", 1)
}
url := fmt.Sprintf("%s/workers/%s", baseURL, workerID)
@@ -332,7 +331,7 @@ func removeWorker(c *cli.Context) error {
resp, err := client.Do(req)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to send request to manager: %s", err.Error()), 1)
}
defer resp.Body.Close()
@@ -340,12 +339,12 @@ func removeWorker(c *cli.Context) error {
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to parse response: %s", err.Error()),
1)
}
return cli.NewExitError(fmt.Sprintf("Failed to correctly send"+
return cli.Exit(fmt.Sprintf("Failed to correctly send"+
" command: HTTP status code is not 200: %s", body),
1)
}
@@ -355,7 +354,7 @@ func removeWorker(c *cli.Context) error {
if res["message"] == "deleted" {
fmt.Println("Successfully removed the worker")
} else {
return cli.NewExitError("Failed to remove the worker", 1)
return cli.Exit("Failed to remove the worker", 1)
}
return nil
}
@@ -368,7 +367,7 @@ func flushDisabledJobs(c *cli.Context) error {
resp, err := client.Do(req)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to send request to manager: %s",
err.Error()),
1)
@@ -378,12 +377,12 @@ func flushDisabledJobs(c *cli.Context) error {
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to parse response: %s", err.Error()),
1)
}
return cli.NewExitError(fmt.Sprintf("Failed to correctly send"+
return cli.Exit(fmt.Sprintf("Failed to correctly send"+
" command: HTTP status code is not 200: %s", body),
1)
}
@@ -396,15 +395,16 @@ func cmdJob(cmd tunasync.CmdVerb) cli.ActionFunc {
return func(c *cli.Context) error {
var mirrorID string
var argsList []string
if len(c.Args()) == 1 {
mirrorID = c.Args()[0]
} else if len(c.Args()) == 2 {
mirrorID = c.Args()[0]
for _, arg := range strings.Split(c.Args()[1], ",") {
args := c.Args().Slice()
if len(args) == 1 {
mirrorID = args[0]
} else if len(args) == 2 {
mirrorID = args[0]
for _, arg := range strings.Split(args[1], ",") {
argsList = append(argsList, strings.TrimSpace(arg))
}
} else {
return cli.NewExitError("Usage Error: cmd command receive just "+
return cli.Exit("Usage Error: cmd command receive just "+
"1 required positional argument MIRROR and 1 optional "+
"argument WORKER", 1)
}
@@ -422,7 +422,7 @@ func cmdJob(cmd tunasync.CmdVerb) cli.ActionFunc {
}
resp, err := tunasync.PostJSON(baseURL+cmdPath, cmd, client)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to correctly send command: %s",
err.Error()),
1)
@@ -432,12 +432,12 @@ func cmdJob(cmd tunasync.CmdVerb) cli.ActionFunc {
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to parse response: %s", err.Error()),
1)
}
return cli.NewExitError(fmt.Sprintf("Failed to correctly send"+
return cli.Exit(fmt.Sprintf("Failed to correctly send"+
" command: HTTP status code is not 200: %s", body),
1)
}
@@ -451,7 +451,7 @@ func cmdWorker(cmd tunasync.CmdVerb) cli.ActionFunc {
return func(c *cli.Context) error {
if c.String("worker") == "" {
return cli.NewExitError("Please specify the worker with -w <worker-id>", 1)
return cli.Exit("Please specify the worker with -w <worker-id>", 1)
}
cmd := tunasync.ClientCmd{
@@ -460,7 +460,7 @@ func cmdWorker(cmd tunasync.CmdVerb) cli.ActionFunc {
}
resp, err := tunasync.PostJSON(baseURL+cmdPath, cmd, client)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to correctly send command: %s",
err.Error()),
1)
@@ -470,12 +470,12 @@ func cmdWorker(cmd tunasync.CmdVerb) cli.ActionFunc {
if resp.StatusCode != http.StatusOK {
body, err := io.ReadAll(resp.Body)
if err != nil {
return cli.NewExitError(
return cli.Exit(
fmt.Sprintf("Failed to parse response: %s", err.Error()),
1)
}
return cli.NewExitError(fmt.Sprintf("Failed to correctly send"+
return cli.Exit(fmt.Sprintf("Failed to correctly send"+
" command: HTTP status code is not 200: %s", body),
1)
}
@@ -514,62 +514,71 @@ func main() {
app.Usage = "control client for tunasync manager"
commonFlags := []cli.Flag{
cli.StringFlag{
Name: "config, c",
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "Read configuration from `FILE` rather than" +
" ~/.config/tunasync/ctl.conf and /etc/tunasync/ctl.conf",
},
cli.StringFlag{
Name: "manager, m",
Usage: "The manager server address",
&cli.StringFlag{
Name: "manager",
Aliases: []string{"m"},
Usage: "The manager server address",
},
cli.StringFlag{
Name: "port, p",
Usage: "The manager server port",
&cli.IntFlag{
Name: "port",
Aliases: []string{"p"},
Usage: "The manager server port",
},
cli.StringFlag{
&cli.StringFlag{
Name: "ca-cert",
Usage: "Trust root CA cert file `CERT`",
},
cli.BoolFlag{
Name: "verbose, v",
Usage: "Enable verbosely logging",
&cli.BoolFlag{
Name: "verbose",
Aliases: []string{"v"},
Usage: "Enable verbosely logging",
},
cli.BoolFlag{
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debugging logging",
},
}
cmdFlags := []cli.Flag{
cli.StringFlag{
Name: "worker, w",
Usage: "Send the command to `WORKER`",
&cli.StringFlag{
Name: "worker",
Aliases: []string{"w"},
Usage: "Send the command to `WORKER`",
},
}
forceStartFlag := cli.BoolFlag{
Name: "force, f",
Usage: "Override the concurrent limit",
forceStartFlag := &cli.BoolFlag{
Name: "force",
Aliases: []string{"f"},
Usage: "Override the concurrent limit",
}
app.Commands = []cli.Command{
app.Commands = []*cli.Command{
{
Name: "list",
Usage: "List jobs of workers",
Flags: append(commonFlags,
[]cli.Flag{
cli.BoolFlag{
Name: "all, a",
Usage: "List all jobs of all workers",
&cli.BoolFlag{
Name: "all",
Aliases: []string{"a"},
Usage: "List all jobs of all workers",
},
cli.StringFlag{
Name: "status, s",
Usage: "Filter output based on status provided",
&cli.StringFlag{
Name: "status",
Aliases: []string{"s"},
Usage: "Filter output based on status provided",
},
cli.StringFlag{
Name: "format, f",
Usage: "Pretty-print containers using a Go template",
&cli.StringFlag{
Name: "format",
Aliases: []string{"f"},
Usage: "Pretty-print containers using a Go template",
},
}...),
Action: initializeWrapper(listJobs),
@@ -591,9 +600,10 @@ func main() {
Usage: "Remove a worker",
Flags: append(
commonFlags,
cli.StringFlag{
Name: "worker, w",
Usage: "worker-id of the worker to be removed",
&cli.StringFlag{
Name: "worker",
Aliases: []string{"w"},
Usage: "worker-id of the worker to be removed",
},
),
Action: initializeWrapper(removeWorker),
@@ -603,9 +613,10 @@ func main() {
Usage: "Set mirror size",
Flags: append(
commonFlags,
cli.StringFlag{
Name: "worker, w",
Usage: "specify worker-id of the mirror job",
&cli.StringFlag{
Name: "worker",
Aliases: []string{"w"},
Usage: "specify worker-id of the mirror job",
},
),
Action: initializeWrapper(updateMirrorSize),

116
go.mod
View File

@@ -1,89 +1,89 @@
module github.com/tuna/tunasync
go 1.23.0
toolchain go1.23.5
go 1.26.2
require (
github.com/BurntSushi/toml v1.4.0
github.com/alicebob/miniredis v2.5.0+incompatible
dario.cat/mergo v1.0.2
github.com/BurntSushi/toml v1.6.0
github.com/alicebob/miniredis/v2 v2.37.0
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
github.com/boltdb/bolt v1.3.1
github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe
github.com/containerd/cgroups/v3 v3.0.5
github.com/dennwc/btrfs v0.0.0-20241002142654-12ae127e0bf6
github.com/dgraph-io/badger/v2 v2.2007.4
github.com/codeskyblue/go-sh v0.0.0-20250509230738-c29da582b0f5
github.com/containerd/cgroups/v3 v3.1.3
github.com/dennwc/btrfs v0.0.0-20260222081608-edfb8b9e4f55
github.com/dgraph-io/badger/v4 v4.9.1
github.com/docker/go-units v0.5.0
github.com/gin-gonic/gin v1.10.0
github.com/go-redis/redis/v8 v8.11.5
github.com/imdario/mergo v0.3.16
github.com/gin-gonic/gin v1.12.0
github.com/moby/sys/reexec v0.1.0
github.com/opencontainers/runtime-spec v1.2.1
github.com/opencontainers/runtime-spec v1.3.0
github.com/pkg/errors v0.9.1
github.com/pkg/profile v1.7.0
github.com/redis/go-redis/v9 v9.18.0
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46
github.com/smartystreets/goconvey v1.6.4
github.com/smartystreets/goconvey v1.8.1
github.com/syndtr/goleveldb v1.0.0
github.com/urfave/cli v1.22.16
golang.org/x/sys v0.31.0
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
github.com/urfave/cli/v2 v2.27.7
go.etcd.io/bbolt v1.4.3
golang.org/x/sys v0.43.0
)
replace github.com/boltdb/bolt v1.3.1 => go.etcd.io/bbolt v1.3.11
require (
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/bytedance/sonic v1.12.9 // indirect
github.com/bytedance/sonic/loader v0.2.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/bytedance/gopkg v0.1.4 // indirect
github.com/bytedance/sonic v1.15.0 // indirect
github.com/bytedance/sonic/loader v0.5.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cilium/ebpf v0.17.3 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/cilium/ebpf v0.21.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/dennwc/ioctl v1.0.0 // indirect
github.com/dgraph-io/ristretto v0.2.0 // indirect
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect
github.com/coreos/go-systemd/v22 v22.7.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/dennwc/ioctl v1.0.1 // indirect
github.com/dgraph-io/ristretto/v2 v2.4.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/fgprof v0.9.5 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v1.0.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/gin-contrib/sse v1.1.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.25.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomodule/redigo v1.8.2 // indirect
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
github.com/go-playground/validator/v10 v10.30.2 // indirect
github.com/goccy/go-json v0.10.6 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/godbus/dbus/v5 v5.2.2 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/google/flatbuffers v25.12.19+incompatible // indirect
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect
github.com/gopherjs/gopherjs v1.20.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/klauspost/compress v1.18.5 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-isatty v0.0.21 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/pelletier/go-toml/v2 v2.3.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/smartystreets/assertions v1.2.0 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/smarty/assertions v1.16.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect
go.etcd.io/bbolt v1.4.0 // indirect
golang.org/x/arch v0.14.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/text v0.23.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
github.com/yuin/gopher-lua v1.1.2 // indirect
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel v1.43.0 // indirect
go.opentelemetry.io/otel/metric v1.43.0 // indirect
go.opentelemetry.io/otel/trace v1.43.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/arch v0.26.0 // indirect
golang.org/x/crypto v0.50.0 // indirect
golang.org/x/net v0.53.0 // indirect
golang.org/x/text v0.36.0 // indirect
google.golang.org/protobuf v1.36.11 // indirect
)

331
go.sum
View File

@@ -1,22 +1,21 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/alicebob/miniredis/v2 v2.37.0 h1:RheObYW32G1aiJIj81XVt78ZHJpHonHLHW7OLIshq68=
github.com/alicebob/miniredis/v2 v2.37.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
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/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/bytedance/sonic v1.12.9 h1:Od1BvK55NnewtGaJsTDeAOSnLVO2BTSLOe0+ooKokmQ=
github.com/bytedance/sonic v1.12.9/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0=
github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM=
github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4=
github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE=
github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI=
github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
@@ -28,108 +27,96 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/cilium/ebpf v0.17.3 h1:FnP4r16PWYSE4ux6zN+//jMcW4nMVRvuTLVTvCjyyjg=
github.com/cilium/ebpf v0.17.3/go.mod h1:G5EDHij8yiLzaqn0WjyfJHvRa+3aDlReIaLVRMvOyJk=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cilium/ebpf v0.21.0 h1:4dpx1J/B/1apeTmWBH5BkVLayHTkFrMovVPnHEk+l3k=
github.com/cilium/ebpf v0.21.0/go.mod h1:1kHKv6Kvh5a6TePP5vvvoMa1bclRyzUXELSs272fmIQ=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe h1:69JI97HlzP+PH5Mi1thcGlDoBr6PS2Oe+l3mNmAkbs4=
github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE=
github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
github.com/codeskyblue/go-sh v0.0.0-20250509230738-c29da582b0f5 h1:2Q4bAJrPn4r2w2vw5jNg3RyaNkI+r35TDS8l21WlyUI=
github.com/codeskyblue/go-sh v0.0.0-20250509230738-c29da582b0f5/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE=
github.com/containerd/cgroups/v3 v3.1.3 h1:eUNflyMddm18+yrDmZPn3jI7C5hJ9ahABE5q6dyLYXQ=
github.com/containerd/cgroups/v3 v3.1.3/go.mod h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA=
github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dennwc/btrfs v0.0.0-20241002142654-12ae127e0bf6 h1:fV+JlCY0cCJh3l0jfE7iB3ZmrdfJSgfcjdrCQhPokGg=
github.com/dennwc/btrfs v0.0.0-20241002142654-12ae127e0bf6/go.mod h1:MYsOV9Dgsec3FFSOjywi0QK5r6TeBbdWxdrMGtiYXHA=
github.com/dennwc/ioctl v1.0.0 h1:DsWAAjIxRqNcLn9x6mwfuf2pet3iB7aK90K4tF16rLg=
github.com/dennwc/ioctl v1.0.0/go.mod h1:ellh2YB5ldny99SBU/VX7Nq0xiZbHphf1DrtHxxjMk0=
github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=
github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dennwc/btrfs v0.0.0-20260222081608-edfb8b9e4f55 h1:VAnGuI8RNnP8vHqCn8X1O63TexAv+QjMqffBdkLbYKU=
github.com/dennwc/btrfs v0.0.0-20260222081608-edfb8b9e4f55/go.mod h1:Kn6RQo4OP1ZEoLB3uldDJabFcf72VgDRInxEqLEo8OE=
github.com/dennwc/ioctl v1.0.1-0.20181021180353-017804252068/go.mod h1:ellh2YB5ldny99SBU/VX7Nq0xiZbHphf1DrtHxxjMk0=
github.com/dennwc/ioctl v1.0.1 h1:9iI6o0gbknFAz3GvR/NY1qy0glki6EtU6W3ZtJlpbMc=
github.com/dennwc/ioctl v1.0.1/go.mod h1:ellh2YB5ldny99SBU/VX7Nq0xiZbHphf1DrtHxxjMk0=
github.com/dgraph-io/badger/v4 v4.9.1 h1:DocZXZkg5JJHJPtUErA0ibyHxOVUDVoXLSCV6t8NC8w=
github.com/dgraph-io/badger/v4 v4.9.1/go.mod h1:5/MEx97uzdPUHR4KtkNt8asfI2T4JiEiQlV7kWUo8c0=
github.com/dgraph-io/ristretto/v2 v2.4.0 h1:I/w09yLjhdcVD2QV192UJcq8dPBaAJb9pOuMyNy0XlU=
github.com/dgraph-io/ristretto/v2 v2.4.0/go.mod h1:0KsrXtXvnv0EqnzyowllbVJB8yBonswa2lTCK2gGo9E=
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38=
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gin-contrib/sse v1.1.1 h1:uGYpNwTacv5R68bSGMapo62iLTRa9l5zxGCps4hK6ko=
github.com/gin-contrib/sse v1.1.1/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s=
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ=
github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc=
github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6 h1:teYtXy9B7y5lHTp8V9KPxpYRAVA7dozigQcMiBust1s=
github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
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.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs=
github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
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/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg=
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
github.com/gopherjs/gopherjs v1.20.1 h1:22uLWFvVcxhJ+j3dJ99NNfwGyHynxCmjhYsrcwqbY60=
github.com/gopherjs/gopherjs v1.20.1/go.mod h1:h+FTmmLgbXMmmtuZFp9bUqXciN429Wx0sJEJuMnpyfM=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
@@ -139,34 +126,24 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=
github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
github.com/moby/sys/reexec v0.1.0 h1:RrBi8e0EBTLEgfruBOFcxtElzRGTEUkeIFaVXgU7wok=
github.com/moby/sys/reexec v0.1.0/go.mod h1:EqjBg8F3X7iZe5pU6nRZnYCMUTXoxsjiIfHup5wYIN8=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
@@ -176,130 +153,112 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg=
github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pelletier/go-toml/v2 v2.3.0 h1:k59bC/lIZREW0/iVaQR8nDHxVq8OVlIzYCOJf421CaM=
github.com/pelletier/go-toml/v2 v2.3.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs=
github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
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.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/smarty/assertions v1.16.0 h1:EvHNkdRA4QHMrn75NZSoUQ/mAUXAYWfatfB01yTCzfY=
github.com/smarty/assertions v1.16.0/go.mod h1:duaaFdCS0K9dnoM50iyek/eYINOZ64gbh1Xlf6LG7AI=
github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY=
github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg=
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/yuin/gopher-lua v1.1.2 h1:yF/FjE3hD65tBbt0VXLE13HWS9h34fdzJmrWRXwobGA=
github.com/yuin/gopher-lua v1.1.2/go.mod h1:7aRmXIWl37SqRf0koeyylBEzJ+aPt8A+mmkQ4f1ntR8=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4=
golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/arch v0.26.0 h1:jZ6dpec5haP/fUv1kLCbuJy6dnRrfX6iVK08lZBFpk4=
golang.org/x/arch v0.26.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/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-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE=
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

View File

@@ -1,35 +1,281 @@
package internal
import (
"context"
"fmt"
"io"
"log/slog"
"os"
"gopkg.in/op/go-logging.v1"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
)
// InitLogger initilizes logging format and level
func InitLogger(verbose, debug, withSystemd bool) {
var fmtString string
if withSystemd {
fmtString = "[%{level:.6s}] %{message}"
} else {
if debug {
fmtString = "%{color}[%{time:06-01-02 15:04:05}][%{level:.6s}][%{shortfile}]%{color:reset} %{message}"
} else {
fmtString = "%{color}[%{time:06-01-02 15:04:05}][%{level:.6s}]%{color:reset} %{message}"
}
}
format := logging.MustStringFormatter(fmtString)
logging.SetFormatter(format)
logging.SetBackend(logging.NewLogBackend(os.Stdout, "", 0))
const LevelNotice = slog.Level(2)
type Logger struct {
name string
}
type lineHandler struct {
w io.Writer
level slog.Leveler
addSource bool
withSystemd bool
attrs []slog.Attr
groups []string
mu *sync.Mutex
}
var defaultHandler atomic.Value
func init() {
InitLogger(false, false, false)
}
func MustGetLogger(name string) *Logger {
return &Logger{name: name}
}
// InitLogger initializes logging format and level.
func InitLogger(verbose, debug, withSystemd bool) {
level := LevelNotice
if debug {
logging.SetLevel(logging.DEBUG, "tunasync")
logging.SetLevel(logging.DEBUG, "tunasynctl")
level = slog.LevelDebug
} else if verbose {
logging.SetLevel(logging.INFO, "tunasync")
logging.SetLevel(logging.INFO, "tunasynctl")
} else {
logging.SetLevel(logging.NOTICE, "tunasync")
logging.SetLevel(logging.NOTICE, "tunasynctl")
level = slog.LevelInfo
}
defaultHandler.Store(slog.Handler(newLineHandler(os.Stdout, level, debug, withSystemd)))
}
func (l *Logger) Debug(args ...any) {
l.log(slog.LevelDebug, normalizeArgs(args...))
}
func (l *Logger) Debugf(format string, args ...any) {
l.log(slog.LevelDebug, formatMessage(format, args...))
}
func (l *Logger) Info(args ...any) {
l.log(slog.LevelInfo, normalizeArgs(args...))
}
func (l *Logger) Infof(format string, args ...any) {
l.log(slog.LevelInfo, formatMessage(format, args...))
}
func (l *Logger) Notice(args ...any) {
l.log(LevelNotice, normalizeArgs(args...))
}
func (l *Logger) Noticef(format string, args ...any) {
l.log(LevelNotice, formatMessage(format, args...))
}
func (l *Logger) Warning(args ...any) {
l.log(slog.LevelWarn, normalizeArgs(args...))
}
func (l *Logger) Warningf(format string, args ...any) {
l.log(slog.LevelWarn, formatMessage(format, args...))
}
func (l *Logger) Error(args ...any) {
l.log(slog.LevelError, normalizeArgs(args...))
}
func (l *Logger) Errorf(format string, args ...any) {
l.log(slog.LevelError, formatMessage(format, args...))
}
func (l *Logger) Panic(args ...any) {
msg := normalizeArgs(args...)
l.log(slog.LevelError, msg)
panic(msg)
}
func (l *Logger) Panicf(format string, args ...any) {
msg := formatMessage(format, args...)
l.log(slog.LevelError, msg)
panic(msg)
}
func (l *Logger) log(level slog.Level, msg string) {
handler := currentHandler()
ctx := context.Background()
if !handler.Enabled(ctx, level) {
return
}
var pcs [1]uintptr
runtime.Callers(3, pcs[:])
record := slog.NewRecord(time.Now(), level, msg, pcs[0])
_ = handler.Handle(ctx, record)
}
func currentHandler() slog.Handler {
if h, ok := defaultHandler.Load().(slog.Handler); ok {
return h
}
return newLineHandler(os.Stdout, LevelNotice, false, false)
}
func newLineHandler(w io.Writer, level slog.Leveler, addSource, withSystemd bool) *lineHandler {
return &lineHandler{
w: w,
level: level,
addSource: addSource,
withSystemd: withSystemd,
mu: &sync.Mutex{},
}
}
func (h *lineHandler) Enabled(_ context.Context, level slog.Level) bool {
return level >= h.level.Level()
}
func (h *lineHandler) Handle(_ context.Context, record slog.Record) error {
var b strings.Builder
if h.withSystemd {
b.WriteString("[")
b.WriteString(levelLabel(record.Level))
b.WriteString("] ")
} else {
b.WriteString("[")
b.WriteString(record.Time.Format("06-01-02 15:04:05"))
b.WriteString("][")
b.WriteString(levelLabel(record.Level))
b.WriteString("]")
if h.addSource {
if src := shortSource(record.PC); src != "" {
b.WriteString("[")
b.WriteString(src)
b.WriteString("]")
}
}
b.WriteString(" ")
}
b.WriteString(record.Message)
attrs := append([]slog.Attr{}, h.attrs...)
record.Attrs(func(attr slog.Attr) bool {
attrs = append(attrs, attr)
return true
})
appendAttrs(&b, h.groups, attrs)
b.WriteByte('\n')
h.mu.Lock()
defer h.mu.Unlock()
_, err := io.WriteString(h.w, b.String())
return err
}
func (h *lineHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
cloned := *h
cloned.attrs = append(append([]slog.Attr{}, h.attrs...), attrs...)
return &cloned
}
func (h *lineHandler) WithGroup(name string) slog.Handler {
cloned := *h
cloned.groups = append(append([]string{}, h.groups...), name)
return &cloned
}
func appendAttrs(b *strings.Builder, groups []string, attrs []slog.Attr) {
for _, attr := range attrs {
attr.Value = attr.Value.Resolve()
if attr.Equal(slog.Attr{}) {
continue
}
key := attr.Key
if len(groups) > 0 {
key = strings.Join(append(append([]string{}, groups...), key), ".")
}
b.WriteByte(' ')
b.WriteString(key)
b.WriteByte('=')
b.WriteString(attrValue(attr.Value))
}
}
func attrValue(v slog.Value) string {
switch v.Kind() {
case slog.KindString:
return strconv.Quote(v.String())
case slog.KindBool:
return strconv.FormatBool(v.Bool())
case slog.KindInt64:
return strconv.FormatInt(v.Int64(), 10)
case slog.KindUint64:
return strconv.FormatUint(v.Uint64(), 10)
case slog.KindFloat64:
return strconv.FormatFloat(v.Float64(), 'f', -1, 64)
case slog.KindDuration:
return v.Duration().String()
case slog.KindTime:
return v.Time().Format(time.RFC3339Nano)
case slog.KindAny:
return fmt.Sprintf("%v", v.Any())
default:
return v.String()
}
}
func levelLabel(level slog.Level) string {
switch {
case level <= slog.LevelDebug:
return "DEBUG"
case level < LevelNotice:
return "INFO"
case level < slog.LevelWarn:
return "NOTICE"
case level < slog.LevelError:
return "WARN"
default:
return "ERROR"
}
}
func shortSource(pc uintptr) string {
if pc == 0 {
return ""
}
frame, _ := runtime.CallersFrames([]uintptr{pc}).Next()
if frame.File == "" {
return ""
}
return fmt.Sprintf("%s:%d", filepath.Base(frame.File), frame.Line)
}
func normalizeArgs(args ...any) string {
if len(args) == 0 {
return ""
}
if format, ok := args[0].(string); ok && len(args) > 1 && strings.Contains(format, "%") {
return fmt.Sprintf(format, args[1:]...)
}
return fmt.Sprint(args...)
}
func formatMessage(format string, args ...any) string {
if len(args) == 0 {
return format
}
if strings.Contains(format, "%") {
return fmt.Sprintf(format, args...)
}
items := make([]any, 0, len(args)+1)
items = append(items, format)
items = append(items, args...)
return fmt.Sprint(items...)
}

325
internal/logger_test.go Normal file
View File

@@ -0,0 +1,325 @@
package internal
import (
"bytes"
"context"
"log/slog"
"runtime"
"strings"
"testing"
"time"
)
type lazyString string
func (l lazyString) LogValue() slog.Value {
return slog.StringValue(string(l))
}
func withDefaultHandler(t *testing.T, handler slog.Handler) {
t.Helper()
prev := currentHandler()
defaultHandler.Store(handler)
t.Cleanup(func() {
defaultHandler.Store(prev)
})
}
func TestInitLoggerConfiguresHandler(t *testing.T) {
prev := currentHandler()
t.Cleanup(func() {
defaultHandler.Store(prev)
})
InitLogger(false, false, true)
h, ok := currentHandler().(*lineHandler)
if !ok {
t.Fatalf("expected *lineHandler, got %T", currentHandler())
}
if got := h.level.Level(); got != LevelNotice {
t.Fatalf("notice level = %v, want %v", got, LevelNotice)
}
if !h.withSystemd {
t.Fatalf("withSystemd = false, want true")
}
if h.addSource {
t.Fatalf("addSource = true, want false")
}
InitLogger(true, false, false)
h = currentHandler().(*lineHandler)
if got := h.level.Level(); got != slog.LevelInfo {
t.Fatalf("info level = %v, want %v", got, slog.LevelInfo)
}
if h.withSystemd {
t.Fatalf("withSystemd = true, want false")
}
if h.addSource {
t.Fatalf("addSource = true, want false")
}
InitLogger(false, true, false)
h = currentHandler().(*lineHandler)
if got := h.level.Level(); got != slog.LevelDebug {
t.Fatalf("debug level = %v, want %v", got, slog.LevelDebug)
}
if !h.addSource {
t.Fatalf("addSource = false, want true")
}
}
func TestLoggerMethodsWriteExpectedLevels(t *testing.T) {
var buf bytes.Buffer
withDefaultHandler(t, newLineHandler(&buf, slog.LevelDebug, false, false))
logger := MustGetLogger("unit")
if logger.name != "unit" {
t.Fatalf("logger name = %q, want %q", logger.name, "unit")
}
debugFormat := "debug %s"
logger.Debug(debugFormat, "one")
logger.Debugf("debugf %d", 2)
logger.Info("info")
logger.Infof("infof %d", 3)
logger.Notice("notice")
logger.Noticef("noticef %d", 4)
logger.Warning("warning")
logger.Warningf("warningf %d", 5)
logger.Error("error")
logger.Errorf("errorf %d", 6)
lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
if len(lines) != 10 {
t.Fatalf("line count = %d, want 10\n%s", len(lines), buf.String())
}
wants := []string{
"[DEBUG] debug one",
"[DEBUG] debugf 2",
"[INFO] info",
"[INFO] infof 3",
"[NOTICE] notice",
"[NOTICE] noticef 4",
"[WARN] warning",
"[WARN] warningf 5",
"[ERROR] error",
"[ERROR] errorf 6",
}
for i, want := range wants {
if !strings.Contains(lines[i], want) {
t.Fatalf("line %d = %q, want substring %q", i, lines[i], want)
}
}
}
func TestLoggerRespectsLevelFiltering(t *testing.T) {
var buf bytes.Buffer
withDefaultHandler(t, newLineHandler(&buf, slog.LevelInfo, false, false))
logger := MustGetLogger("unit")
logger.Debug("hidden")
logger.Info("visible")
out := buf.String()
if strings.Contains(out, "hidden") {
t.Fatalf("unexpected debug output: %q", out)
}
if !strings.Contains(out, "[INFO] visible") {
t.Fatalf("missing info output: %q", out)
}
}
func TestLoggerPanicMethods(t *testing.T) {
var buf bytes.Buffer
withDefaultHandler(t, newLineHandler(&buf, slog.LevelDebug, false, false))
logger := MustGetLogger("panic")
assertPanic := func(name, want string, fn func()) {
t.Helper()
defer func() {
got := recover()
if got != want {
t.Fatalf("%s panic = %v, want %q", name, got, want)
}
}()
fn()
}
assertPanic("Panic", "boom", func() {
logger.Panic("boom")
})
if !strings.Contains(buf.String(), "[ERROR] boom") {
t.Fatalf("panic output missing: %q", buf.String())
}
buf.Reset()
assertPanic("Panicf", "boom 2", func() {
logger.Panicf("boom %d", 2)
})
if !strings.Contains(buf.String(), "[ERROR] boom 2") {
t.Fatalf("panicf output missing: %q", buf.String())
}
}
func TestLineHandlerFormatsAttrsAndSource(t *testing.T) {
var buf bytes.Buffer
handler := newLineHandler(&buf, slog.LevelDebug, true, false).
WithGroup("grp").
WithAttrs([]slog.Attr{
slog.String("prefix", "yes"),
{},
})
pc, _, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("runtime.Caller failed")
}
record := slog.NewRecord(
time.Date(2024, time.January, 2, 3, 4, 5, 0, time.UTC),
LevelNotice,
"hello",
pc,
)
record.AddAttrs(
slog.String("name", "value"),
slog.Bool("ok", true),
slog.Int64("n", -3),
slog.Uint64("u", 4),
slog.Float64("f", 1.5),
slog.Duration("d", 2*time.Second),
slog.Time("when", time.Date(2024, time.January, 2, 3, 4, 5, 0, time.UTC)),
slog.Any("obj", struct{ X int }{X: 7}),
slog.Any("lazy", lazyString("resolved")),
)
if !handler.Enabled(context.Background(), LevelNotice) {
t.Fatal("handler should be enabled for notice")
}
if err := handler.Handle(context.Background(), record); err != nil {
t.Fatalf("Handle returned error: %v", err)
}
out := buf.String()
for _, want := range []string{
"[24-01-02 03:04:05][NOTICE][logger_test.go:",
" hello",
"grp.prefix=\"yes\"",
"grp.name=\"value\"",
"grp.ok=true",
"grp.n=-3",
"grp.u=4",
"grp.f=1.5",
"grp.d=2s",
"grp.when=2024-01-02T03:04:05Z",
"grp.obj={7}",
"grp.lazy=\"resolved\"",
} {
if !strings.Contains(out, want) {
t.Fatalf("output = %q, want substring %q", out, want)
}
}
}
func TestLineHandlerSystemdFormat(t *testing.T) {
var buf bytes.Buffer
handler := newLineHandler(&buf, slog.LevelDebug, false, true)
record := slog.NewRecord(
time.Date(2024, time.January, 2, 3, 4, 5, 0, time.UTC),
slog.LevelWarn,
"systemd",
0,
)
if err := handler.Handle(context.Background(), record); err != nil {
t.Fatalf("Handle returned error: %v", err)
}
out := buf.String()
if got, want := out, "[WARN] systemd\n"; got != want {
t.Fatalf("systemd output = %q, want %q", got, want)
}
}
func TestLoggerHelpers(t *testing.T) {
if got := normalizeArgs(); got != "" {
t.Fatalf("normalizeArgs() = %q, want empty", got)
}
format := "value=%d"
if got := normalizeArgs(format, 4); got != "value=4" {
t.Fatalf("normalizeArgs(format) = %q, want %q", got, "value=4")
}
if got := normalizeArgs("value", 4); got != "value4" {
t.Fatalf("normalizeArgs(sprint) = %q, want %q", got, "value4")
}
if got := formatMessage("plain"); got != "plain" {
t.Fatalf("formatMessage(no args) = %q, want %q", got, "plain")
}
if got := formatMessage(format, 4); got != "value=4" {
t.Fatalf("formatMessage(format) = %q, want %q", got, "value=4")
}
plain := "plain"
if got := formatMessage(plain, 4); got != "plain4" {
t.Fatalf("formatMessage(sprint) = %q, want %q", got, "plain4")
}
if got := levelLabel(slog.LevelDebug); got != "DEBUG" {
t.Fatalf("levelLabel(debug) = %q, want DEBUG", got)
}
if got := levelLabel(slog.LevelInfo); got != "INFO" {
t.Fatalf("levelLabel(info) = %q, want INFO", got)
}
if got := levelLabel(LevelNotice); got != "NOTICE" {
t.Fatalf("levelLabel(notice) = %q, want NOTICE", got)
}
if got := levelLabel(slog.LevelWarn); got != "WARN" {
t.Fatalf("levelLabel(warn) = %q, want WARN", got)
}
if got := levelLabel(slog.LevelError); got != "ERROR" {
t.Fatalf("levelLabel(error) = %q, want ERROR", got)
}
if got := shortSource(0); got != "" {
t.Fatalf("shortSource(0) = %q, want empty", got)
}
pc, _, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("runtime.Caller failed")
}
if got := shortSource(pc); !strings.Contains(got, "logger_test.go:") {
t.Fatalf("shortSource(pc) = %q, want logger_test.go:*", got)
}
if got := attrValue(slog.StringValue("value")); got != "\"value\"" {
t.Fatalf("attrValue(string) = %q, want %q", got, "\"value\"")
}
if got := attrValue(slog.BoolValue(true)); got != "true" {
t.Fatalf("attrValue(bool) = %q, want true", got)
}
if got := attrValue(slog.Int64Value(-3)); got != "-3" {
t.Fatalf("attrValue(int64) = %q, want -3", got)
}
if got := attrValue(slog.Uint64Value(4)); got != "4" {
t.Fatalf("attrValue(uint64) = %q, want 4", got)
}
if got := attrValue(slog.Float64Value(1.5)); got != "1.5" {
t.Fatalf("attrValue(float64) = %q, want 1.5", got)
}
if got := attrValue(slog.DurationValue(2 * time.Second)); got != "2s" {
t.Fatalf("attrValue(duration) = %q, want 2s", got)
}
if got := attrValue(slog.TimeValue(time.Date(2024, time.January, 2, 3, 4, 5, 0, time.UTC))); got != "2024-01-02T03:04:05Z" {
t.Fatalf("attrValue(time) = %q, want RFC3339", got)
}
if got := attrValue(slog.AnyValue(struct{ X int }{X: 7})); got != "{7}" {
t.Fatalf("attrValue(any) = %q, want %q", got, "{7}")
}
if got := attrValue(slog.GroupValue(slog.Int("x", 1))); !strings.Contains(got, "x=1") {
t.Fatalf("attrValue(group) = %q, want substring %q", got, "x=1")
}
}

View File

@@ -1,7 +1,7 @@
package manager
import (
"gopkg.in/op/go-logging.v1"
tunasync "github.com/tuna/tunasync/internal"
)
var logger = logging.MustGetLogger("tunasync")
var logger = tunasync.MustGetLogger("tunasync")

View File

@@ -2,7 +2,7 @@ package manager
import (
"github.com/BurntSushi/toml"
"github.com/urfave/cli"
"github.com/urfave/cli/v2"
)
// A Config is the top-level toml-serializaible config struct
@@ -42,7 +42,7 @@ func LoadConfig(cfgFile string, c *cli.Context) (*Config, error) {
if cfgFile != "" {
if _, err := toml.DecodeFile(cfgFile, cfg); err != nil {
logger.Errorf(err.Error())
logger.Error(err.Error())
return nil, err
}
}
@@ -68,7 +68,7 @@ func LoadConfig(cfgFile string, c *cli.Context) (*Config, error) {
cfg.Files.DBFile = c.String("db-file")
}
if c.String("db-type") != "" {
cfg.Files.DBFile = c.String("db-type")
cfg.Files.DBType = c.String("db-type")
}
return cfg, nil

View File

@@ -8,7 +8,7 @@ import (
"github.com/BurntSushi/toml"
. "github.com/smartystreets/goconvey/convey"
"github.com/urfave/cli"
"github.com/urfave/cli/v2"
)
func TestConfig(t *testing.T) {
@@ -46,40 +46,43 @@ func TestConfig(t *testing.T) {
app := cli.NewApp()
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "config, c",
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
},
cli.StringFlag{
&cli.StringFlag{
Name: "addr",
},
cli.IntFlag{
&cli.IntFlag{
Name: "port",
},
cli.StringFlag{
&cli.StringFlag{
Name: "cert",
},
cli.StringFlag{
&cli.StringFlag{
Name: "key",
},
cli.StringFlag{
&cli.StringFlag{
Name: "status-file",
},
cli.StringFlag{
&cli.StringFlag{
Name: "db-file",
},
}
Convey("when giving no config options", func() {
app.Action = func(c *cli.Context) {
app.Action = func(c *cli.Context) error {
cfgFile := c.String("config")
cfg, err := LoadConfig(cfgFile, c)
So(err, ShouldEqual, nil)
So(cfg.Server.Addr, ShouldEqual, "127.0.0.1")
return nil
}
args := strings.Split("cmd", " ")
app.Run(args)
err = app.Run(args)
So(err, ShouldEqual, nil)
})
Convey("when giving config options", func() {
app.Action = func(c *cli.Context) {
app.Action = func(c *cli.Context) error {
cfgFile := c.String("config")
So(cfgFile, ShouldEqual, tmpfile.Name())
conf, err := LoadConfig(cfgFile, c)
@@ -88,14 +91,15 @@ func TestConfig(t *testing.T) {
So(conf.Server.Port, ShouldEqual, 5000)
So(conf.Files.StatusFile, ShouldEqual, "/tmp/tunasync.json")
So(conf.Files.DBFile, ShouldEqual, "/var/lib/tunasync/tunasync.db")
return nil
}
cmd := fmt.Sprintf("cmd -c %s", tmpfile.Name())
args := strings.Split(cmd, " ")
app.Run(args)
err = app.Run(args)
So(err, ShouldEqual, nil)
})
Convey("when giving cli options", func() {
app.Action = func(c *cli.Context) {
app.Action = func(c *cli.Context) error {
cfgFile := c.String("config")
So(cfgFile, ShouldEqual, "")
conf, err := LoadConfig(cfgFile, c)
@@ -106,16 +110,17 @@ func TestConfig(t *testing.T) {
So(conf.Server.SSLKey, ShouldEqual, "/ssl.key")
So(conf.Files.StatusFile, ShouldEqual, "/tunasync.json")
So(conf.Files.DBFile, ShouldEqual, "/tunasync.db")
return nil
}
args := strings.Split(
"cmd --addr=0.0.0.0 --port=5001 --cert=/ssl.cert --key /ssl.key --status-file=/tunasync.json --db-file=/tunasync.db",
" ",
)
app.Run(args)
err = app.Run(args)
So(err, ShouldEqual, nil)
})
Convey("when giving both config and cli options", func() {
app.Action = func(c *cli.Context) {
app.Action = func(c *cli.Context) error {
cfgFile := c.String("config")
So(cfgFile, ShouldEqual, tmpfile.Name())
conf, err := LoadConfig(cfgFile, c)
@@ -126,14 +131,15 @@ func TestConfig(t *testing.T) {
So(conf.Server.SSLKey, ShouldEqual, "/ssl.key")
So(conf.Files.StatusFile, ShouldEqual, "/tunasync.json")
So(conf.Files.DBFile, ShouldEqual, "/tunasync.db")
return nil
}
cmd := fmt.Sprintf(
"cmd -c %s --cert=/ssl.cert --key /ssl.key --status-file=/tunasync.json --db-file=/tunasync.db",
tmpfile.Name(),
)
args := strings.Split(cmd, " ")
app.Run(args)
err = app.Run(args)
So(err, ShouldEqual, nil)
})
})
})

View File

@@ -6,11 +6,11 @@ import (
"strings"
"time"
bolt "github.com/boltdb/bolt"
"github.com/dgraph-io/badger/v2"
"github.com/go-redis/redis/v8"
"github.com/dgraph-io/badger/v4"
"github.com/pkg/errors"
"github.com/redis/go-redis/v9"
"github.com/syndtr/goleveldb/leveldb"
bolt "go.etcd.io/bbolt"
. "github.com/tuna/tunasync/internal"
)

View File

@@ -1,7 +1,7 @@
package manager
import (
"github.com/dgraph-io/badger/v2"
"github.com/dgraph-io/badger/v4"
)
// implement kv interface backed by badger

View File

@@ -3,7 +3,7 @@ package manager
import (
"fmt"
bolt "github.com/boltdb/bolt"
bolt "go.etcd.io/bbolt"
)
// implement kv interface backed by boltdb

View File

@@ -3,7 +3,7 @@ package manager
import (
"context"
"github.com/go-redis/redis/v8"
"github.com/redis/go-redis/v9"
)
// implement kv interface backed by redis

View File

@@ -9,7 +9,7 @@ import (
"testing"
"time"
"github.com/alicebob/miniredis"
"github.com/alicebob/miniredis/v2"
. "github.com/smartystreets/goconvey/convey"
. "github.com/tuna/tunasync/internal"
)

View File

@@ -121,7 +121,7 @@ func initCgroup(cfg *cgroupConfig) error {
for _, p := range procs {
if err := wkrMgr.AddProc(p); err != nil {
if errors.Is(err, syscall.ESRCH) {
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring")
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring", p)
} else {
return err
}
@@ -206,7 +206,7 @@ func initCgroup(cfg *cgroupConfig) error {
for _, proc := range procs {
if err := wkrMgr.Add(proc); err != nil {
if errors.Is(err, syscall.ESRCH) {
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring")
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring", proc.Pid)
} else {
return err
}

View File

@@ -53,8 +53,13 @@ func TestReexec(t *testing.T) {
return errors.New("pipe is nil")
} else {
_, err := pipe.Stat()
return err
if err != nil {
return err
}
}
pipe.Close()
_, err := pipe.Stat()
return err
})(), ShouldNotBeNil)
So(func() {
reexec.Init()
@@ -172,7 +177,7 @@ sleep 30
daemonPidBytes, err := os.ReadFile(bgPidfile)
So(err, ShouldBeNil)
daemonPid := strings.Trim(string(daemonPidBytes), " \n")
logger.Debug("daemon pid: %s", daemonPid)
logger.Debugf("daemon pid: %s", daemonPid)
procDir := filepath.Join("/proc", daemonPid)
_, err = os.Stat(procDir)
So(err, ShouldBeNil)
@@ -266,7 +271,7 @@ sleep 30
for _, p := range procs {
if err := origMgr.AddProc(p); err != nil {
if errors.Is(err, syscall.ESRCH) {
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring")
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring", p)
} else {
So(err, ShouldBeNil)
}
@@ -306,7 +311,7 @@ sleep 30
for _, proc := range procs {
if err := origMgr.Add(proc); err != nil {
if errors.Is(err, syscall.ESRCH) {
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring")
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring", proc.Pid)
} else {
So(err, ShouldBeNil)
}

View File

@@ -105,7 +105,7 @@ func (p *cmdProvider) Run(started chan empty) error {
return err
}
if len(matches) != 0 {
logger.Debug("Fail-on-match: %r", matches)
logger.Debugf("Fail-on-match: %v", matches)
return fmt.Errorf("Fail-on-match regexp found %d matches", len(matches))
}
}

View File

@@ -3,11 +3,11 @@ package worker
// put global variables and types here
import (
"gopkg.in/op/go-logging.v1"
tunasync "github.com/tuna/tunasync/internal"
)
type empty struct{}
const defaultMaxRetry = 2
var logger = logging.MustGetLogger("tunasync")
var logger = tunasync.MustGetLogger("tunasync")

View File

@@ -5,11 +5,11 @@ import (
"os"
"path/filepath"
"dario.cat/mergo"
"github.com/BurntSushi/toml"
cgv1 "github.com/containerd/cgroups/v3/cgroup1"
cgv2 "github.com/containerd/cgroups/v3/cgroup2"
units "github.com/docker/go-units"
"github.com/imdario/mergo"
)
type providerEnum uint8
@@ -213,20 +213,20 @@ func LoadConfig(cfgFile string) (*Config, error) {
cfg := new(Config)
if _, err := toml.DecodeFile(cfgFile, cfg); err != nil {
logger.Errorf(err.Error())
logger.Error(err.Error())
return nil, err
}
if cfg.Include.IncludeMirrors != "" {
includedFiles, err := filepath.Glob(cfg.Include.IncludeMirrors)
if err != nil {
logger.Errorf(err.Error())
logger.Error(err.Error())
return nil, err
}
for _, f := range includedFiles {
var incMirCfg includedMirrorConfig
if _, err := toml.DecodeFile(f, &incMirCfg); err != nil {
logger.Errorf(err.Error())
logger.Error(err.Error())
return nil, err
}
cfg.MirrorsConf = append(cfg.MirrorsConf, incMirCfg.Mirrors...)

View File

@@ -22,7 +22,7 @@ func cmdRun(p string, args []string) {
logger.Debugf("cmdRun failed %s", err)
return
}
logger.Debugf("cmdRun: ", string(out))
logger.Debugf("cmdRun: %s", string(out))
}
func getDockerByName(name string) (string, error) {
@@ -74,7 +74,7 @@ sleep 20
emptyHook: emptyHook{
provider: provider,
},
image: "alpine:3.8",
image: "alpine:3.23",
volumes: []string{
fmt.Sprintf("%s:%s", cmdScript, "/bin/cmd.sh"),
},

View File

@@ -297,7 +297,7 @@ func TestRsyncProviderWithDocker(t *testing.T) {
Upstream: "rsync://rsync.tuna.moe/tuna/",
Command: "/bin/myrsync",
ExcludeFile: excludeFile,
DockerImage: "alpine:3.8",
DockerImage: "alpine:3.23",
LogDir: tmpDir,
MirrorDir: tmpDir,
UseIPv6: true,

View File

@@ -139,7 +139,7 @@ func (p *rsyncProvider) Run(started chan empty) error {
if err := p.Wait(); err != nil {
code, msg := internal.TranslateRsyncErrorCode(err)
if code != 0 {
logger.Debug("Rsync exitcode %d (%s)", code, msg)
logger.Debugf("Rsync exitcode %d (%s)", code, msg)
if p.logFileFd != nil {
p.logFileFd.WriteString(msg + "\n")
}

View File

@@ -142,7 +142,7 @@ func (c *cmdJob) Start() error {
if cg.cgCfg.isUnified {
if err := cg.cgMgrV2.AddProc(uint64(pid)); err != nil {
if errors.Is(err, syscall.ESRCH) {
logger.Infof("Write pid %d to cgroup failed: process vanished, ignoring")
logger.Infof("Write pid %d to cgroup failed: process vanished, ignoring", pid)
} else {
return err
}
@@ -150,7 +150,7 @@ func (c *cmdJob) Start() error {
} else {
if err := cg.cgMgrV1.Add(cgv1.Process{Pid: pid}); err != nil {
if errors.Is(err, syscall.ESRCH) {
logger.Infof("Write pid %d to cgroup failed: process vanished, ignoring")
logger.Infof("Write pid %d to cgroup failed: process vanished, ignoring", pid)
} else {
return err
}

View File

@@ -75,7 +75,7 @@ func (q *scheduleQueue) Pop() *mirrorJob {
job := first.Value().(*mirrorJob)
q.list.Delete(first.Key())
delete(q.jobs, job.Name())
logger.Debug("Popped out job %s @%v", job.Name(), t)
logger.Debugf("Popped out job %s @%v", job.Name(), t)
return job
}
return nil

View File

@@ -197,7 +197,7 @@ func (p *twoStageRsyncProvider) Run(started chan empty) error {
if err != nil {
code, msg := internal.TranslateRsyncErrorCode(err)
if code != 0 {
logger.Debug("Rsync exitcode %d (%s)", code, msg)
logger.Debugf("Rsync exitcode %d (%s)", code, msg)
if p.logFileFd != nil {
p.logFileFd.WriteString(msg + "\n")
}