From 4967e7cf2502b83cbbaac0f1b82164f7832a77e5 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 26 Nov 2024 14:47:23 +0100 Subject: [PATCH] refactor: provide CLI app in a standalone package 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. --- cmd/bundb/main.go | 357 +---------------------------------------- extra/buncli/auto.go | 56 +++++++ extra/buncli/buncli.go | 57 +++++++ extra/buncli/go.mod | 22 +++ extra/buncli/go.sum | 28 ++++ go.mod | 7 + go.sum | 8 + 7 files changed, 181 insertions(+), 354 deletions(-) create mode 100644 extra/buncli/auto.go create mode 100644 extra/buncli/buncli.go create mode 100644 extra/buncli/go.mod create mode 100644 extra/buncli/go.sum diff --git a/cmd/bundb/main.go b/cmd/bundb/main.go index f5cfa1573..1e5365b04 100644 --- a/cmd/bundb/main.go +++ b/cmd/bundb/main.go @@ -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 { } } diff --git a/extra/buncli/auto.go b/extra/buncli/auto.go new file mode 100644 index 000000000..0d9849072 --- /dev/null +++ b/extra/buncli/auto.go @@ -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 +} diff --git a/extra/buncli/buncli.go b/extra/buncli/buncli.go new file mode 100644 index 000000000..58983666e --- /dev/null +++ b/extra/buncli/buncli.go @@ -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 +} diff --git a/extra/buncli/go.mod b/extra/buncli/go.mod new file mode 100644 index 000000000..16a966cd2 --- /dev/null +++ b/extra/buncli/go.mod @@ -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 => ../.. diff --git a/extra/buncli/go.sum b/extra/buncli/go.sum new file mode 100644 index 000000000..63ffdb699 --- /dev/null +++ b/extra/buncli/go.sum @@ -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= diff --git a/go.mod b/go.mod index 48b197ab8..dba5573ed 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 0e97efd20..a7f2f5675 100644 --- a/go.sum +++ b/go.sum @@ -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=