Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: provide CLI app in a standalone package
Browse files Browse the repository at this point in the history
Users can start the tool from their own entrypoints by using buncli.New/Run etc.
They are also responsible for configuring the DB connection and AutoMigrator.

bundb/bunctl will eventually use FromPlugin() to read config from a pre-built plugin.
bevzzz committed Nov 26, 2024
1 parent 83bea5a commit 4967e7c
Showing 7 changed files with 181 additions and 354 deletions.
357 changes: 3 additions & 354 deletions cmd/bundb/main.go
Original file line number Diff line number Diff line change
@@ -25,366 +25,15 @@ Although... this way we are moving towards a .bundb.config or something.
package main

import (
"bytes"
"database/sql"
"fmt"
"log"
"os"
"os/exec"
"path"
"plugin"
"strings"

"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/mssqldialect"
"github.com/uptrace/bun/dialect/mysqldialect"
"github.com/uptrace/bun/dialect/oracledialect"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/dialect/sqlitedialect"
"github.com/uptrace/bun/driver/pgdriver"
"github.com/uptrace/bun/driver/sqliteshim"
"github.com/uptrace/bun/migrate"
"github.com/uptrace/bun/schema"
"github.com/urfave/cli/v2"
"github.com/uptrace/bun/extra/buncli"
)

const (
defaultMigrationsDirectory = "./migrations"
pluginName = "plugin.so"
)

var (
supportedDrivers = []string{"postgres", "sqlserver", "mysql", "oci8", "file"}
autoMigratorOptions []migrate.AutoMigratorOption
migrationsDirectory string
)

var (
cleanup = &cli.BoolFlag{
Name: "cleanup",
}
)

var app = &cli.App{
Name: "bundb",
Usage: "Database migration tool for uptrace/bun",
Commands: cli.Commands{
// bundb init --create-directory
// bundb create --sql --go --tx [-d | --dir]
// bundb migrate
// bundb auto create --tx
// bundb auto migrate
&cli.Command{
Name: "auto",
Usage: "manage database schema with AutoMigrator",
Subcommands: cli.Commands{
&cli.Command{
Name: "create",
Usage: "Generate SQL migration files",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "uri",
Aliases: []string{"database-uri", "dsn"},
Required: true,
EnvVars: []string{"BUNDB_URI"},
},
&cli.StringFlag{
Name: "driver",
},
&cli.StringFlag{
Name: "d",
Aliases: []string{"migrations-directory"},
Destination: &migrationsDirectory,
Value: defaultMigrationsDirectory,
Action: func(ctx *cli.Context, dir string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithMigrationsDirectoryAuto(dir))
return nil
},
},
&cli.StringFlag{
Name: "t",
Aliases: []string{"migrations-table"},
Action: func(ctx *cli.Context, migrationsTable string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithTableNameAuto(migrationsTable))
return nil
},
},
&cli.StringFlag{
Name: "l",
Aliases: []string{"locks", "migration-locks-table"},
Action: func(ctx *cli.Context, locksTable string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithLocksTableNameAuto(locksTable))
return nil
},
},
&cli.StringFlag{
Name: "s",
Aliases: []string{"schema"},
Action: func(ctx *cli.Context, schemaName string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithSchemaName(schemaName))
return nil
},
},
&cli.StringSliceFlag{
Name: "exclude",
Action: func(ctx *cli.Context, tables []string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithExcludeTable(tables...))
return nil
},
},
&cli.BoolFlag{
Name: "rebuild",
},
cleanup,
&cli.BoolFlag{
Name: "tx",
Aliases: []string{"transactional"},
},
},
Action: func(ctx *cli.Context) error {
if err := buildPlugin(ctx.Bool("rebuild")); err != nil {
return err
}

if cleanup.Get(ctx) {
defer deletePlugin()
}

db, err := connect(ctx.String("uri"), ctx.String("driver"), !ctx.IsSet("driver"))
if err != nil {
return err

}

if !ctx.IsSet("migrations-directory") {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithMigrationsDirectoryAuto(defaultMigrationsDirectory))

}
m, err := automigrator(db)
if err != nil {
return err
}

if ctx.Bool("tx") {
_, err = m.CreateTxSQLMigrations(ctx.Context)
} else {
_, err = m.CreateSQLMigrations(ctx.Context)
}
if err != nil {
return err
}
return nil
},
},
&cli.Command{
Name: "migrate",
Usage: "Generate SQL migrations and apply them right away",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "uri",
Aliases: []string{"database-uri", "dsn"},
Required: true,
EnvVars: []string{"BUNDB_URI"},
},
&cli.StringFlag{
Name: "driver",
},
&cli.StringFlag{
Name: "d",
Aliases: []string{"migrations-directory"},
Destination: &migrationsDirectory,
Value: defaultMigrationsDirectory,
Action: func(ctx *cli.Context, dir string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithMigrationsDirectoryAuto(dir))
return nil
},
},
&cli.StringFlag{
Name: "t",
Aliases: []string{"migrations-table"},
Action: func(ctx *cli.Context, migrationsTable string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithTableNameAuto(migrationsTable))
return nil
},
},
&cli.StringFlag{
Name: "l",
Aliases: []string{"locks", "migration-locks-table"},
Action: func(ctx *cli.Context, locksTable string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithLocksTableNameAuto(locksTable))
return nil
},
},
&cli.StringFlag{
Name: "s",
Aliases: []string{"schema"},
Action: func(ctx *cli.Context, schemaName string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithSchemaName(schemaName))
return nil
},
},
&cli.StringSliceFlag{
Name: "exclude",
Action: func(ctx *cli.Context, tables []string) error {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithExcludeTable(tables...))
return nil
},
},
&cli.BoolFlag{
Name: "rebuild",
},
cleanup,
},
Action: func(ctx *cli.Context) error {
if err := buildPlugin(ctx.Bool("rebuild")); err != nil {
return err
}

if cleanup.Get(ctx) {
defer deletePlugin()
}

db, err := connect(ctx.String("uri"), ctx.String("driver"), !ctx.IsSet("driver"))
if err != nil {
return err

}

if !ctx.IsSet("migrations-directory") {
autoMigratorOptions = append(autoMigratorOptions, migrate.WithMigrationsDirectoryAuto(defaultMigrationsDirectory))

}
m, err := automigrator(db)
if err != nil {
return err
}

group, err := m.Migrate(ctx.Context)
if err != nil {
return err
}
if group.IsZero() {
log.Print("ok, nothing to migrate")
}
return nil
},
},
},
},
},
}

func pluginPath() string {
return path.Join(migrationsDirectory, pluginName)
}

// TODO: wrap Build and Open steps into a sync.OnceFunc, so that we could use the Plugin object in multiple places
// without having to worry if it has been compiled or not.
func buildPlugin(force bool) error {
if force {
if err := deletePlugin(); err != nil {
return err
}
}

// Cmd.Run returns *exec.ExitError which will only contain the exit code message in case of an error.
// Rather than logging "exit code 1" we want to output a more informative error, so we redirect the Stderr.
var errBuf bytes.Buffer

cmd := exec.Command("go", "build", "-C", migrationsDirectory, "-buildmode", "plugin", "-o", pluginName)
cmd.Stderr = &errBuf

err := cmd.Run()
if err != nil {
// TODO: if errBuf contains "no such file or directory" add the following to the error message:
// "Create 'migrations/' directory by running: bundb init --create-directory migrations/"
return fmt.Errorf("build %s: %s", pluginPath(), &errBuf)
}
return nil
}

func deletePlugin() error {
return os.RemoveAll(pluginPath())
}

// connect to the database under the URI. A driver must be one of the supported drivers.
// If not set explicitly, the name of the driver is guessed from the URI.
//
// Example:
//
// "postgres://root:@localhost:5432/test" -> "postgres"
func connect(uri, driverName string, guessDriver bool) (*bun.DB, error) {
var sqldb *sql.DB
var dialect schema.Dialect
var err error

if guessDriver {
driver, _, found := strings.Cut(uri, ":")
if !found {
return nil, fmt.Errorf("driver cannot be guessed from connection string; pass -driver option explicitly")
}
driverName = driver
}

switch driverName {
case "postgres":
sqldb = sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(uri)))
dialect = pgdialect.New()
case "sqlserver":
sqldb, err = sql.Open(driverName, uri)
dialect = mssqldialect.New()
case "file":
sqldb, err = sql.Open(sqliteshim.ShimName, uri)
dialect = sqlitedialect.New()
case "mysql":
sqldb, err = sql.Open(driverName, uri)
dialect = mysqldialect.New()
case "oci8":
sqldb, err = sql.Open(driverName, uri)
dialect = oracledialect.New()
default:
err = fmt.Errorf("driver %q not recognized, supported drivers are %+v", driverName, supportedDrivers)
}

if err != nil {
return nil, err
}

return bun.NewDB(sqldb, dialect), nil
}

// automigrator creates AutoMigrator for models from user's 'migrations' package.
func automigrator(db *bun.DB) (*migrate.AutoMigrator, error) {
sym, err := lookup("Models")
if err != nil {
return nil, err
}

models, ok := sym.(*[]interface{})
if !ok {
return nil, fmt.Errorf("migrations plugin must export Models as []interface{}, got %T", models)
}
autoMigratorOptions = append(autoMigratorOptions, migrate.WithModel(*models...))

auto, err := migrate.NewAutoMigrator(db, autoMigratorOptions...)
if err != nil {
return nil, err
}
return auto, nil
}

// lookup a symbol from user's migrations plugin.
func lookup(symbol string) (plugin.Symbol, error) {
p, err := plugin.Open(pluginPath())
if err != nil {
return nil, err
}
return p.Lookup(symbol)
}

func main() {
log.SetPrefix("bundb: ")
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
// TODO: use buncli.New(buncli.FromPlugin()) to read config from plugin
if err := buncli.Run(os.Args, nil); err != nil {

Check failure on line 37 in cmd/bundb/main.go

GitHub Actions / lint

SA9003: empty branch (staticcheck)
}
}
56 changes: 56 additions & 0 deletions extra/buncli/auto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package buncli

import (
"github.com/urfave/cli/v2"
)

func CmdAuto(c *Config) *cli.Command {
return &cli.Command{
Name: "auto",
Usage: "Manage database schema with AutoMigrator",
Subcommands: cli.Commands{
&cli.Command{
Name: "create",
Usage: "Generate SQL migration files",
Flags: []cli.Flag{
flagTx,
},
Action: func(ctx *cli.Context) error {
return autoCreate(ctx, c)
},
},
&cli.Command{
Name: "migrate",
Usage: "Generate SQL migrations and apply them right away",
Action: func(ctx *cli.Context) error {
return autoMigrate(ctx, c)
},
},
},
}
}

var (
// flagTx adds --transactional flag.
flagTx = &cli.BoolFlag{
Name: "tx",
Aliases: []string{"transactional"},
Usage: "write migrations to .tx.(up|down).sql file, they will be marked as transactional",
Value: false,
}
)

func autoMigrate(ctx *cli.Context, c *Config) error {
_, err := c.AutoMigrator.Migrate(ctx.Context)
return err
}

func autoCreate(ctx *cli.Context, c *Config) error {
var err error
if flagTx.Get(ctx) {
_, err = c.AutoMigrator.CreateTxSQLMigrations(ctx.Context)
} else {
_, err = c.AutoMigrator.CreateSQLMigrations(ctx.Context)
}
return err
}
57 changes: 57 additions & 0 deletions extra/buncli/buncli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
TODO:
- Commands:
- init - Create migration+locks tables [--cmd to add cmd/ folder structure]
- migrate - Apply database migrations
- rollback - Rollback the last migration group
- create - Create template SQL migration filex [--go | --sql | --transactional]
- unlock - Unlock locks table
- provide NewCommand() *cli.Command intead of the cli.App, so that buncli could be embeded in the existing CLIs
- configure logging and verbosity
- (experimental, low prio) add FromPlugin() to read config from plugin and use from cmd/bundb.
*/
package buncli

import (
"context"

"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
"github.com/urfave/cli/v2"
)

// bunApp is the root-level bundb app that all other commands attach to.
var bunApp = &cli.App{
Name: "bundb",
Usage: "Database migration tool for uptrace/bun",
}

// New creates a new CLI application for managing bun migrations.
func New(c *Config) *App {
bunApp.Commands = cli.Commands{
CmdAuto(c),
}
return &App{
App: bunApp,
}
}

type Config struct {
DB *bun.DB
AutoMigrator *migrate.AutoMigrator
}

// Run calls cli.App.Run and returns its error.
func Run(args []string, c *Config) error {
return New(c).Run(args)
}

// RunCtx calls cli.App.RunContexta and returns its error.
func RunContext(ctx context.Context, args []string, c *Config) error {
return New(c).RunContext(ctx, args)
}

// App is a wrapper around cli.App that extends it with bun-specific features.
type App struct {
*cli.App
}
22 changes: 22 additions & 0 deletions extra/buncli/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module github.com/uptrace/bun/extra/buncli

go 1.22.0

require (
github.com/uptrace/bun v1.2.7-0.20241125022320-89e9d5169f8a
github.com/urfave/cli/v2 v2.27.5
)

require (
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
golang.org/x/sys v0.27.0 // indirect
)

replace github.com/uptrace/bun => ../..
28 changes: 28 additions & 0 deletions extra/buncli/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
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/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
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/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -8,17 +8,24 @@ require (
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.8.1
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc
github.com/uptrace/bun/extra/buncli v0.0.0-00010101000000-000000000000
github.com/vmihailenco/msgpack/v5 v5.4.1
)

require (
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/urfave/cli/v2 v2.27.5 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
golang.org/x/sys v0.27.0 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace github.com/uptrace/bun/extra/buncli => ./extra/buncli
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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=
@@ -24,6 +26,8 @@ github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPK
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
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/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=
@@ -33,10 +37,14 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/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=

0 comments on commit 4967e7c

Please sign in to comment.