2023-05-19 17:24:18 +03:00
|
|
|
// Package run holds the run.Run construct, which encapsulates CLI state
|
|
|
|
// for a command execution.
|
|
|
|
package run
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
|
2023-11-20 04:06:36 +03:00
|
|
|
"github.com/spf13/cobra"
|
2023-05-19 17:24:18 +03:00
|
|
|
|
|
|
|
"github.com/neilotoole/sq/cli/config"
|
2023-11-20 04:06:36 +03:00
|
|
|
"github.com/neilotoole/sq/cli/output"
|
|
|
|
"github.com/neilotoole/sq/libsq"
|
2023-05-19 17:24:18 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/core/cleanup"
|
|
|
|
"github.com/neilotoole/sq/libsq/core/errz"
|
2024-01-15 04:45:34 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/core/lg"
|
2023-11-20 04:06:36 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/core/options"
|
2024-02-09 19:08:39 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/core/sqlz"
|
2023-05-19 17:24:18 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/driver"
|
2024-01-25 09:29:55 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/files"
|
2024-02-09 19:08:39 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/source"
|
2023-05-19 17:24:18 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type runKey struct{}
|
|
|
|
|
|
|
|
// NewContext returns ctx with ru added as a value.
|
|
|
|
func NewContext(ctx context.Context, ru *Run) context.Context {
|
|
|
|
if ctx == nil {
|
|
|
|
ctx = context.Background()
|
|
|
|
}
|
|
|
|
|
|
|
|
return context.WithValue(ctx, runKey{}, ru)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FromContext extracts the Run added to ctx via NewContext.
|
|
|
|
func FromContext(ctx context.Context) *Run {
|
|
|
|
return ctx.Value(runKey{}).(*Run)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run is a container for injectable resources passed
|
|
|
|
// to all cobra exec funcs. The Close method should be invoked when
|
|
|
|
// the Run is no longer needed.
|
|
|
|
type Run struct {
|
2024-02-09 19:08:39 +03:00
|
|
|
// Out is the output destination, typically a decorated writer over
|
|
|
|
// [Run.Stdout]. This writer should generally be used for program output,
|
|
|
|
// not [Run.Stdout].
|
2023-05-19 17:24:18 +03:00
|
|
|
Out io.Writer
|
|
|
|
|
2024-02-09 19:08:39 +03:00
|
|
|
// Stdout is the original stdout file descriptor, which is typically
|
|
|
|
// the actual os.Stdout. Output should generally be written to [Run.Out]
|
|
|
|
// except for a few rare circumstances, such as executing an external
|
|
|
|
// program.
|
|
|
|
Stdout io.Writer
|
|
|
|
|
|
|
|
// ErrOut is the error output destination, typically a decorated writer
|
|
|
|
// over [Run.Stderr]. This writer should generally be used for error output,
|
|
|
|
// not [Run.Stderr].
|
2023-05-19 17:24:18 +03:00
|
|
|
ErrOut io.Writer
|
|
|
|
|
2024-02-09 19:08:39 +03:00
|
|
|
// Stderr is the original stderr file descriptor, which is typically
|
|
|
|
// the actual os.Stderr. Error output should generally be written to
|
|
|
|
// [Run.ErrOut] except for a few rare circumstances, such as executing an
|
|
|
|
// external program.
|
|
|
|
Stderr io.Writer
|
|
|
|
|
2024-01-27 10:11:24 +03:00
|
|
|
// ConfigStore manages config persistence.
|
|
|
|
ConfigStore config.Store
|
|
|
|
|
|
|
|
// Stdin typically is os.Stdin, but can be changed for testing.
|
|
|
|
Stdin *os.File
|
|
|
|
|
2023-05-19 17:24:18 +03:00
|
|
|
// Cmd is the command instance provided by cobra for
|
|
|
|
// the currently executing command. This field will
|
|
|
|
// be set before the command's runFunc is invoked.
|
|
|
|
Cmd *cobra.Command
|
|
|
|
|
|
|
|
// Config is the run's config.
|
|
|
|
Config *config.Config
|
|
|
|
|
|
|
|
// OptionsRegistry is a registry of CLI options.Opt instances.
|
|
|
|
OptionsRegistry *options.Registry
|
|
|
|
|
|
|
|
// DriverRegistry is a registry of driver implementations.
|
|
|
|
DriverRegistry *driver.Registry
|
|
|
|
|
|
|
|
// Files manages file access.
|
2024-01-25 09:29:55 +03:00
|
|
|
Files *files.Files
|
2023-05-19 17:24:18 +03:00
|
|
|
|
2024-01-15 04:45:34 +03:00
|
|
|
// Grips mediates access to driver.Grip instances.
|
|
|
|
Grips *driver.Grips
|
2023-05-19 17:24:18 +03:00
|
|
|
|
|
|
|
// Writers holds the various writer types that
|
|
|
|
// the CLI uses to print output.
|
|
|
|
Writers *output.Writers
|
|
|
|
|
2024-01-15 04:45:34 +03:00
|
|
|
// Cleanup holds cleanup functions, except log closing, which
|
|
|
|
// is held by LogCloser.
|
2023-05-19 17:24:18 +03:00
|
|
|
Cleanup *cleanup.Cleanup
|
2024-01-15 04:45:34 +03:00
|
|
|
|
|
|
|
// LogCloser contains any log-closing action (such as closing
|
|
|
|
// a log file). It may be nil. Execution of this function
|
|
|
|
// should be more-or-less the final cleanup action performed by the CLI,
|
|
|
|
// and absolutely must happen after all other cleanup actions.
|
|
|
|
LogCloser func() error
|
2024-01-27 10:11:24 +03:00
|
|
|
|
|
|
|
// Args is the arg slice supplied by cobra for
|
|
|
|
// the currently executing command. This field will
|
|
|
|
// be set before the command's runFunc is invoked.
|
|
|
|
Args []string
|
2023-05-19 17:24:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Close should be invoked to dispose of any open resources
|
|
|
|
// held by ru. If an error occurs during Close and ru.Log
|
|
|
|
// is not nil, that error is logged at WARN level before
|
2024-01-15 04:45:34 +03:00
|
|
|
// being returned. Note that Run.LogCloser must be invoked separately.
|
2023-05-19 17:24:18 +03:00
|
|
|
func (ru *Run) Close() error {
|
|
|
|
if ru == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-01-15 04:45:34 +03:00
|
|
|
if ru.Cmd != nil {
|
|
|
|
lg.FromContext(ru.Cmd.Context()).Debug("Closing run")
|
|
|
|
}
|
|
|
|
|
|
|
|
return errz.Wrap(ru.Cleanup.Run(), "close run")
|
2023-05-19 17:24:18 +03:00
|
|
|
}
|
2023-05-22 18:08:14 +03:00
|
|
|
|
2024-02-09 19:08:39 +03:00
|
|
|
// DB is a convenience method that gets the sqlz.DB and driver.SQLDriver\
|
|
|
|
// for src.
|
|
|
|
func (ru *Run) DB(ctx context.Context, src *source.Source) (sqlz.DB, driver.SQLDriver, error) {
|
|
|
|
grip, err := ru.Grips.Open(ctx, src)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
db, err := grip.DB(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return db, grip.SQLDriver(), nil
|
|
|
|
}
|
|
|
|
|
2023-06-18 04:28:11 +03:00
|
|
|
// NewQueryContext returns a *libsq.QueryContext constructed from ru.
|
|
|
|
func NewQueryContext(ru *Run, args map[string]string) *libsq.QueryContext {
|
2023-05-22 18:08:14 +03:00
|
|
|
return &libsq.QueryContext{
|
2024-01-15 04:45:34 +03:00
|
|
|
Collection: ru.Config.Collection,
|
|
|
|
Grips: ru.Grips,
|
|
|
|
Args: args,
|
2023-05-22 18:08:14 +03:00
|
|
|
}
|
|
|
|
}
|