mirror of
https://github.com/dolthub/dolt.git
synced 2026-04-22 11:29:06 -05:00
Merge pull request #2364 from dolthub/zachmu/sql-create-polish
Better support for sql outside a database directory
This commit is contained in:
@@ -244,6 +244,41 @@ func CheckEnvIsValid(dEnv *env.DoltEnv) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
const (
|
||||
userNameRequiredError = `Author identity unknown
|
||||
|
||||
*** Please tell me who you are.
|
||||
|
||||
Run
|
||||
|
||||
dolt config --global user.email "you@example.com"
|
||||
dolt config --global user.name "Your Name"
|
||||
|
||||
to set your account's default identity.
|
||||
Omit --global to set the identity only in this repository.
|
||||
|
||||
fatal: empty ident name not allowed
|
||||
`
|
||||
)
|
||||
|
||||
// CheckUserNameAndEmail returns true if the user name and email are set for this environment, or prints an error and
|
||||
// returns false if not.
|
||||
func CheckUserNameAndEmail(dEnv *env.DoltEnv) bool {
|
||||
_, err := dEnv.Config.GetString(env.UserEmailKey)
|
||||
if err != nil {
|
||||
PrintErr(userNameRequiredError)
|
||||
return false
|
||||
}
|
||||
|
||||
_, err = dEnv.Config.GetString(env.UserNameKey)
|
||||
if err != nil {
|
||||
PrintErr(userNameRequiredError)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (hc SubCommandHandler) printUsage(commandStr string) {
|
||||
Println("Valid commands for", commandStr, "are")
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ func (cmd CommitCmd) Exec(ctx context.Context, commandStr string, args []string,
|
||||
help, usage := cli.HelpAndUsagePrinters(cli.GetCommandDocumentation(commandStr, commitDocs, ap))
|
||||
apr := cli.ParseArgsOrDie(ap, args, help)
|
||||
|
||||
// Check if the -all param is provided. Stage all tables if so.
|
||||
allFlag := apr.Contains(cli.AllFlag)
|
||||
|
||||
roots, err := dEnv.Roots(ctx)
|
||||
@@ -96,6 +95,10 @@ func (cmd CommitCmd) Exec(ctx context.Context, commandStr string, args []string,
|
||||
if authorStr, ok := apr.GetValue(cli.AuthorParam); ok {
|
||||
name, email, err = cli.ParseAuthor(authorStr)
|
||||
} else {
|
||||
// This command creates a commit, so we need user identity
|
||||
if !cli.CheckUserNameAndEmail(dEnv) {
|
||||
return 1
|
||||
}
|
||||
name, email, err = env.GetNameAndEmail(dEnv.Config)
|
||||
}
|
||||
|
||||
|
||||
@@ -142,32 +142,35 @@ func getOperation(dEnv *env.DoltEnv, setCfgTypes *set.StrSet, args []string, pri
|
||||
return 1
|
||||
}
|
||||
|
||||
cfgTypesSl := setCfgTypes.AsSlice()
|
||||
for _, cfgType := range cfgTypesSl {
|
||||
if _, ok := dEnv.Config.GetConfig(newCfgElement(cfgType)); !ok {
|
||||
cli.PrintErrln(color.RedString("Unable to read config."))
|
||||
var cfg config.ReadableConfig
|
||||
switch setCfgTypes.Size() {
|
||||
case 0:
|
||||
cfg = dEnv.Config
|
||||
case 1:
|
||||
configElement := newCfgElement(setCfgTypes.AsSlice()[0])
|
||||
var ok bool
|
||||
cfg, ok = dEnv.Config.GetConfig(configElement)
|
||||
if !ok {
|
||||
cli.Println(color.RedString("No config found for %s", configElement.String()))
|
||||
return 1
|
||||
}
|
||||
default:
|
||||
// should be impossible due to earlier checks
|
||||
cli.Println(color.RedString("Cannot get more than one config scope at once"))
|
||||
return 1
|
||||
}
|
||||
|
||||
if setCfgTypes.Size() == 0 {
|
||||
cfgTypesSl = []string{localParamName, globalParamName}
|
||||
}
|
||||
|
||||
for _, cfgType := range cfgTypesSl {
|
||||
cfg, ok := dEnv.Config.GetConfig(newCfgElement(cfgType))
|
||||
if ok {
|
||||
if val, err := cfg.GetString(args[0]); err == nil {
|
||||
printFn(args[0], &val)
|
||||
return 0
|
||||
} else if err != config.ErrConfigParamNotFound {
|
||||
cli.PrintErrln(color.RedString("Unexpected error: %s", err.Error()))
|
||||
return 1
|
||||
}
|
||||
val, err := cfg.GetString(args[0])
|
||||
if err != nil {
|
||||
if err != config.ErrConfigParamNotFound {
|
||||
cli.PrintErrln(color.RedString("Unexpected error: %s", err.Error()))
|
||||
}
|
||||
// Not found prints no error but returns status 1
|
||||
return 1
|
||||
}
|
||||
|
||||
return 1
|
||||
printFn(args[0], &val)
|
||||
return 0
|
||||
}
|
||||
|
||||
func addOperation(dEnv *env.DoltEnv, setCfgTypes *set.StrSet, args []string, usage cli.UsagePrinter) int {
|
||||
|
||||
@@ -137,6 +137,7 @@ func TestConfigGet(t *testing.T) {
|
||||
CfgSet: multiCfg,
|
||||
ConfigElem: env.LocalConfig,
|
||||
Key: "title",
|
||||
Code: 1,
|
||||
},
|
||||
{
|
||||
Name: "missing param",
|
||||
|
||||
@@ -94,6 +94,14 @@ func (cmd InitCmd) Exec(ctx context.Context, commandStr string, args []string, d
|
||||
name, _ := apr.GetValue(usernameParamName)
|
||||
email, _ := apr.GetValue(emailParamName)
|
||||
initBranch, _ := apr.GetValue(initBranchParamName)
|
||||
|
||||
if len(name) == 0 || len(email) == 0 {
|
||||
// This command creates a commit, so we need user identity
|
||||
if !cli.CheckUserNameAndEmail(dEnv) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
name = dEnv.Config.IfEmptyUseConfig(name, env.UserNameKey)
|
||||
email = dEnv.Config.IfEmptyUseConfig(email, env.UserEmailKey)
|
||||
if initBranch == "" {
|
||||
|
||||
@@ -58,25 +58,27 @@ func TestInit(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
dEnv := createUninitializedEnv()
|
||||
gCfg, _ := dEnv.Config.GetConfig(env.GlobalConfig)
|
||||
gCfg.SetStrings(test.GlobalConfig)
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
dEnv := createUninitializedEnv()
|
||||
gCfg, _ := dEnv.Config.GetConfig(env.GlobalConfig)
|
||||
gCfg.SetStrings(test.GlobalConfig)
|
||||
|
||||
result := InitCmd{}.Exec(context.Background(), "dolt init", test.Args, dEnv)
|
||||
result := InitCmd{}.Exec(context.Background(), "dolt init", test.Args, dEnv)
|
||||
|
||||
if (result == 0) != test.ExpectSuccess {
|
||||
t.Error(test.Name, "- Expected success:", test.ExpectSuccess, "result:", result == 0)
|
||||
} else if test.ExpectSuccess {
|
||||
// succceeded as expected
|
||||
if !dEnv.HasDoltDir() {
|
||||
t.Error(test.Name, "- .dolt dir should exist after initialization")
|
||||
if (result == 0) != test.ExpectSuccess {
|
||||
t.Error(test.Name, "- Expected success:", test.ExpectSuccess, "result:", result == 0)
|
||||
} else if test.ExpectSuccess {
|
||||
// succceeded as expected
|
||||
if !dEnv.HasDoltDir() {
|
||||
t.Error(test.Name, "- .dolt dir should exist after initialization")
|
||||
}
|
||||
} else {
|
||||
// failed as expected
|
||||
if dEnv.HasDoltDir() {
|
||||
t.Error(test.Name, "- dolt directory shouldn't exist after failure to initialize")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// failed as expected
|
||||
if dEnv.HasDoltDir() {
|
||||
t.Error(test.Name, "- dolt directory shouldn't exist after failure to initialize")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,11 @@ func (cmd MergeCmd) Exec(ctx context.Context, commandStr string, args []string,
|
||||
return 1
|
||||
}
|
||||
|
||||
// This command may create a commit, so we need user identity
|
||||
if !cli.CheckUserNameAndEmail(dEnv) {
|
||||
return 1
|
||||
}
|
||||
|
||||
var verr errhand.VerboseError
|
||||
if apr.Contains(cli.AbortParam) {
|
||||
mergeActive, err := dEnv.IsMergeActive(ctx)
|
||||
|
||||
@@ -67,6 +67,11 @@ func (cmd RevertCmd) Exec(ctx context.Context, commandStr string, args []string,
|
||||
help, usage := cli.HelpAndUsagePrinters(cli.GetCommandDocumentation(commandStr, commitDocs, ap))
|
||||
apr := cli.ParseArgsOrDie(ap, args, help)
|
||||
|
||||
// This command creates a commit, so we need user identity
|
||||
if !cli.CheckUserNameAndEmail(dEnv) {
|
||||
return 1
|
||||
}
|
||||
|
||||
if apr.NArg() < 1 {
|
||||
usage()
|
||||
return 1
|
||||
|
||||
@@ -179,6 +179,9 @@ func (cmd SqlCmd) Exec(ctx context.Context, commandStr string, args []string, dE
|
||||
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
|
||||
}
|
||||
|
||||
// We need a username and password for many SQL commands, so set defaults if they don't exist
|
||||
dEnv.Config.SetFailsafes(env.DefaultFailsafeConfig)
|
||||
|
||||
mrEnv, verr := getMultiRepoEnv(ctx, apr, dEnv, cmd)
|
||||
if verr != nil {
|
||||
return HandleVErrAndExitCode(verr, usage)
|
||||
@@ -352,10 +355,6 @@ func getMultiRepoEnv(ctx context.Context, apr *argparser.ArgParseResults, dEnv *
|
||||
return nil, errhand.VerboseErrorFromError(err)
|
||||
}
|
||||
} else {
|
||||
if !cli.CheckEnvIsValid(dEnv) {
|
||||
return nil, errhand.BuildDError("Invalid working directory").Build()
|
||||
}
|
||||
|
||||
mrEnv, err = env.DoltEnvAsMultiEnv(ctx, dEnv)
|
||||
if err != nil {
|
||||
return nil, errhand.VerboseErrorFromError(err)
|
||||
@@ -1540,7 +1539,6 @@ func newSqlEngine(
|
||||
dbStates = append(dbStates, dbState)
|
||||
}
|
||||
|
||||
// TODO: not having user and email for this command should probably be an error or warning, it disables certain functionality
|
||||
sess, err := dsess.NewDoltSession(sql.NewEmptyContext(), sql.NewBaseSession(), pro, config, dbStates...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -49,7 +49,7 @@ func Serve(ctx context.Context, version string, serverConfig ServerConfig, serve
|
||||
|
||||
// Code is easier to work through if we assume that serverController is never nil
|
||||
if serverController == nil {
|
||||
serverController = CreateServerController()
|
||||
serverController = NewServerController()
|
||||
}
|
||||
|
||||
var mySQLServer *server.Server
|
||||
@@ -99,21 +99,10 @@ func Serve(ctx context.Context, version string, serverConfig ServerConfig, serve
|
||||
dbNamesAndPaths := serverConfig.DatabaseNamesAndPaths()
|
||||
|
||||
if len(dbNamesAndPaths) == 0 {
|
||||
if dEnv.Valid() {
|
||||
// Running in a dolt dir
|
||||
var err error
|
||||
mrEnv, err = env.DoltEnvAsMultiEnv(ctx, dEnv)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
} else {
|
||||
// Running outside a dolt dir
|
||||
var err error
|
||||
cfg, _ := dEnv.Config.GetConfig(env.GlobalConfig)
|
||||
mrEnv, err = env.MultiEnvForDirectory(ctx, cfg, dEnv.FS, version)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
var err error
|
||||
mrEnv, err = env.DoltEnvAsMultiEnv(ctx, dEnv)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
|
||||
@@ -53,7 +53,7 @@ var (
|
||||
)
|
||||
|
||||
func TestServerArgs(t *testing.T) {
|
||||
serverController := CreateServerController()
|
||||
serverController := NewServerController()
|
||||
go func() {
|
||||
startServer(context.Background(), "test", "dolt sql-server", []string{
|
||||
"-H", "localhost",
|
||||
@@ -93,7 +93,7 @@ listener:
|
||||
read_timeout_millis: 5000
|
||||
write_timeout_millis: 5000
|
||||
`
|
||||
serverController := CreateServerController()
|
||||
serverController := NewServerController()
|
||||
go func() {
|
||||
dEnv := dtestutils.CreateEnvWithSeedData(t)
|
||||
dEnv.FS.WriteFile("config.yaml", []byte(yamlConfig))
|
||||
@@ -126,7 +126,7 @@ func TestServerBadArgs(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(strings.Join(test, " "), func(t *testing.T) {
|
||||
serverController := CreateServerController()
|
||||
serverController := NewServerController()
|
||||
go func(serverController *ServerController) {
|
||||
startServer(context.Background(), "test", "dolt sql-server", test, env, serverController)
|
||||
}(serverController)
|
||||
@@ -161,7 +161,7 @@ func TestServerGoodParams(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(ConfigInfo(test), func(t *testing.T) {
|
||||
sc := CreateServerController()
|
||||
sc := NewServerController()
|
||||
go func(config ServerConfig, sc *ServerController) {
|
||||
_, _ = Serve(context.Background(), "", config, sc, env)
|
||||
}(test, sc)
|
||||
@@ -182,7 +182,7 @@ func TestServerSelect(t *testing.T) {
|
||||
env := dtestutils.CreateEnvWithSeedData(t)
|
||||
serverConfig := DefaultServerConfig().withLogLevel(LogLevel_Fatal).withPort(15300)
|
||||
|
||||
sc := CreateServerController()
|
||||
sc := NewServerController()
|
||||
defer sc.StopServer()
|
||||
go func() {
|
||||
_, _ = Serve(context.Background(), "", serverConfig, sc, env)
|
||||
@@ -231,7 +231,7 @@ func TestServerSelect(t *testing.T) {
|
||||
|
||||
// If a port is already in use, throw error "Port XXXX already in use."
|
||||
func TestServerFailsIfPortInUse(t *testing.T) {
|
||||
serverController := CreateServerController()
|
||||
serverController := NewServerController()
|
||||
server := &http.Server{
|
||||
Addr: ":15200",
|
||||
Handler: http.DefaultServeMux,
|
||||
@@ -257,7 +257,7 @@ func TestServerSetDefaultBranch(t *testing.T) {
|
||||
dEnv := dtestutils.CreateEnvWithSeedData(t)
|
||||
serverConfig := DefaultServerConfig().withLogLevel(LogLevel_Fatal).withPort(15302)
|
||||
|
||||
sc := CreateServerController()
|
||||
sc := NewServerController()
|
||||
defer sc.StopServer()
|
||||
go func() {
|
||||
_, _ = Serve(context.Background(), "", serverConfig, sc, dEnv)
|
||||
@@ -404,7 +404,7 @@ func TestReadReplica(t *testing.T) {
|
||||
dsess.InitPersistedSystemVars(multiSetup.MrEnv.GetEnv(readReplicaDbName))
|
||||
|
||||
// start server as read replica
|
||||
sc := CreateServerController()
|
||||
sc := NewServerController()
|
||||
serverConfig := DefaultServerConfig().withLogLevel(LogLevel_Fatal).withPort(15303)
|
||||
|
||||
func() {
|
||||
|
||||
@@ -19,8 +19,6 @@ import (
|
||||
)
|
||||
|
||||
type ServerController struct {
|
||||
//serverClosed *sync.WaitGroup
|
||||
//serverStarted *sync.WaitGroup
|
||||
startCh chan struct{}
|
||||
closeCh chan struct{}
|
||||
closeCalled *sync.Once
|
||||
@@ -31,16 +29,15 @@ type ServerController struct {
|
||||
closeError error
|
||||
}
|
||||
|
||||
// CreateServerController creates a `ServerController` for use with synchronizing on `Serve`.
|
||||
func CreateServerController() *ServerController {
|
||||
sc := &ServerController{
|
||||
// NewServerController creates a `ServerController` for use with synchronizing on `Serve`.
|
||||
func NewServerController() *ServerController {
|
||||
return &ServerController{
|
||||
startCh: make(chan struct{}),
|
||||
closeCh: make(chan struct{}),
|
||||
closeCalled: &sync.Once{},
|
||||
closeRegistered: &sync.Once{},
|
||||
stopRegistered: &sync.Once{},
|
||||
}
|
||||
return sc
|
||||
}
|
||||
|
||||
// registerCloseFunction is called within `Serve` to associate the close function with a future `StopServer` call.
|
||||
|
||||
@@ -113,7 +113,7 @@ func (cmd SqlClientCmd) Exec(ctx context.Context, commandStr string, args []stri
|
||||
}
|
||||
cli.PrintErrf("Starting server with Config %v\n", ConfigInfo(serverConfig))
|
||||
|
||||
serverController = CreateServerController()
|
||||
serverController = NewServerController()
|
||||
go func() {
|
||||
_, _ = Serve(ctx, SqlServerCmd{}.VersionStr, serverConfig, serverController, dEnv)
|
||||
}()
|
||||
|
||||
@@ -162,7 +162,7 @@ func (cmd SqlServerCmd) RequiresRepo() bool {
|
||||
|
||||
// Exec executes the command
|
||||
func (cmd SqlServerCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv) int {
|
||||
controller := CreateServerController()
|
||||
controller := NewServerController()
|
||||
newCtx, cancelF := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
@@ -176,6 +176,9 @@ func startServer(ctx context.Context, versionStr, commandStr string, args []stri
|
||||
ap := SqlServerCmd{}.CreateArgParser()
|
||||
help, _ := cli.HelpAndUsagePrinters(cli.GetCommandDocumentation(commandStr, sqlServerDocs, ap))
|
||||
|
||||
// We need a username and password for many SQL commands, so set defaults if they don't exist
|
||||
dEnv.Config.SetFailsafes(env.DefaultFailsafeConfig)
|
||||
|
||||
apr := cli.ParseArgsOrDie(ap, args, help)
|
||||
serverConfig, err := GetServerConfig(dEnv, apr)
|
||||
|
||||
|
||||
Vendored
+51
-21
@@ -96,20 +96,7 @@ var _ config.ReadableConfig = &DoltCliConfig{}
|
||||
func LoadDoltCliConfig(hdp HomeDirProvider, fs filesys.ReadWriteFS) (*DoltCliConfig, error) {
|
||||
ch := config.NewConfigHierarchy()
|
||||
|
||||
gPath, err := getGlobalCfgPath(hdp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lPath := getLocalConfigPath()
|
||||
|
||||
gCfg, err := ensureGlobalConfig(gPath, fs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ch.AddConfig(globalConfigName, gCfg)
|
||||
|
||||
if exists, _ := fs.Exists(lPath); exists {
|
||||
lCfg, err := config.FromFile(lPath, fs)
|
||||
|
||||
@@ -118,6 +105,18 @@ func LoadDoltCliConfig(hdp HomeDirProvider, fs filesys.ReadWriteFS) (*DoltCliCon
|
||||
}
|
||||
}
|
||||
|
||||
gPath, err := getGlobalCfgPath(hdp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gCfg, err := ensureGlobalConfig(gPath, fs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ch.AddConfig(globalConfigName, gCfg)
|
||||
|
||||
return &DoltCliConfig{ch, ch, fs}, nil
|
||||
}
|
||||
|
||||
@@ -230,25 +229,56 @@ type writeableLocalDoltCliConfig struct {
|
||||
}
|
||||
|
||||
// WriteableConfig returns a ReadWriteConfig reading from this config hierarchy. The config will read from the hierarchy
|
||||
// and write to the local config.
|
||||
// and write to the local config if it's available, or the global config otherwise.
|
||||
func (dcc *DoltCliConfig) WriteableConfig() config.ReadWriteConfig {
|
||||
return writeableLocalDoltCliConfig{dcc}
|
||||
}
|
||||
|
||||
func (w writeableLocalDoltCliConfig) SetStrings(updates map[string]string) error {
|
||||
localCfg, ok := w.GetConfig(LocalConfig)
|
||||
// SetFailsafes sets the config values given as failsafes, i.e. values that will be returned as a last resort if they
|
||||
// are not found elsewhere in the config hierarchy. The "failsafe" config can be written to in order to conform to the
|
||||
// interface of ConfigHierarchy, but values will not persist beyond this session.
|
||||
// Calling SetFailsafes more than once will overwrite any previous values.
|
||||
// Should only be called after primary configuration of the config hierarchy has been completed.
|
||||
func (dcc DoltCliConfig) SetFailsafes(cfg map[string]string) {
|
||||
existing, ok := dcc.ch.GetConfig("failsafe")
|
||||
if !ok {
|
||||
return errors.New("no local config found")
|
||||
existing = config.NewEmptyMapConfig()
|
||||
dcc.ch.AddConfig("failsafe", existing)
|
||||
}
|
||||
|
||||
return localCfg.SetStrings(updates)
|
||||
_ = existing.SetStrings(cfg)
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultEmail = "doltuser@dolthub.com"
|
||||
DefaultName = "Dolt System Account"
|
||||
)
|
||||
|
||||
var DefaultFailsafeConfig = map[string]string{
|
||||
UserEmailKey: DefaultEmail,
|
||||
UserNameKey: DefaultName,
|
||||
}
|
||||
|
||||
func (w writeableLocalDoltCliConfig) SetStrings(updates map[string]string) error {
|
||||
cfg, ok := w.GetConfig(LocalConfig)
|
||||
if !ok {
|
||||
cfg, ok = w.GetConfig(GlobalConfig)
|
||||
if !ok {
|
||||
return errors.New("no local or global config found")
|
||||
}
|
||||
}
|
||||
|
||||
return cfg.SetStrings(updates)
|
||||
}
|
||||
|
||||
func (w writeableLocalDoltCliConfig) Unset(params []string) error {
|
||||
localCfg, ok := w.GetConfig(LocalConfig)
|
||||
cfg, ok := w.GetConfig(LocalConfig)
|
||||
if !ok {
|
||||
return errors.New("no local config found")
|
||||
cfg, ok = w.GetConfig(GlobalConfig)
|
||||
if !ok {
|
||||
return errors.New("no local or global config found")
|
||||
}
|
||||
}
|
||||
|
||||
return localCfg.Unset(params)
|
||||
return cfg.Unset(params)
|
||||
}
|
||||
|
||||
+90
-18
@@ -14,7 +14,14 @@
|
||||
|
||||
package env
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/dolthub/dolt/go/libraries/utils/config"
|
||||
)
|
||||
|
||||
const (
|
||||
email = "bigbillieb@fake.horse"
|
||||
@@ -27,26 +34,91 @@ func TestConfig(t *testing.T) {
|
||||
lCfg, _ := dEnv.Config.GetConfig(LocalConfig)
|
||||
gCfg, _ := dEnv.Config.GetConfig(GlobalConfig)
|
||||
|
||||
lCfg.SetStrings(map[string]string{UserEmailKey: email})
|
||||
lCfg.SetStrings(map[string]string{UserEmailKey: email, UserNameKey: "local_override"})
|
||||
gCfg.SetStrings(map[string]string{UserNameKey: name})
|
||||
|
||||
if dEnv.Config.GetStringOrDefault(UserEmailKey, "no") != email {
|
||||
t.Error("Should return", email)
|
||||
}
|
||||
assert.Equal(t, email, dEnv.Config.GetStringOrDefault(UserEmailKey, "no"))
|
||||
assert.Equal(t, "local_override", dEnv.Config.GetStringOrDefault(UserNameKey, "no"))
|
||||
assert.Equal(t, "yes", dEnv.Config.GetStringOrDefault("bad_key", "yes"))
|
||||
|
||||
if dEnv.Config.GetStringOrDefault("bad_key", "yes") != "yes" {
|
||||
t.Error("Should return default value of yes")
|
||||
}
|
||||
assert.Equal(t, email, dEnv.Config.IfEmptyUseConfig("", UserEmailKey))
|
||||
assert.Equal(t, "not empty", dEnv.Config.IfEmptyUseConfig("not empty", UserEmailKey))
|
||||
|
||||
if dEnv.Config.IfEmptyUseConfig("", UserEmailKey) != email {
|
||||
t.Error("Should return", email)
|
||||
}
|
||||
assert.Equal(t, "", dEnv.Config.IfEmptyUseConfig("", "missing"))
|
||||
|
||||
if dEnv.Config.IfEmptyUseConfig("not empty", UserEmailKey) != "not empty" {
|
||||
t.Error("Should return default value")
|
||||
}
|
||||
|
||||
if dEnv.Config.IfEmptyUseConfig("", "missing") != "" {
|
||||
t.Error("Should return empty string")
|
||||
}
|
||||
_, err := dEnv.Config.GetString("missing")
|
||||
assert.Equal(t, config.ErrConfigParamNotFound, err)
|
||||
}
|
||||
|
||||
func TestFailsafes(t *testing.T) {
|
||||
dEnv, _ := createTestEnv(true, true)
|
||||
|
||||
lCfg, _ := dEnv.Config.GetConfig(LocalConfig)
|
||||
require.NoError(t, lCfg.Unset([]string{UserNameKey}))
|
||||
|
||||
dEnv.Config.SetFailsafes(DefaultFailsafeConfig)
|
||||
|
||||
assert.Equal(t, DefaultEmail, dEnv.Config.GetStringOrDefault(UserEmailKey, "none"))
|
||||
assert.Equal(t, DefaultName, dEnv.Config.GetStringOrDefault(UserNameKey, "none"))
|
||||
|
||||
dEnv.Config.SetFailsafes(map[string]string{UserEmailKey: "new", "abc": "def"})
|
||||
|
||||
assert.Equal(t, "new", dEnv.Config.GetStringOrDefault(UserEmailKey, "none"))
|
||||
assert.Equal(t, DefaultName, dEnv.Config.GetStringOrDefault(UserNameKey, "none"))
|
||||
assert.Equal(t, "def", dEnv.Config.GetStringOrDefault("abc", "none"))
|
||||
}
|
||||
|
||||
func TestWritableDoltConfig(t *testing.T) {
|
||||
dEnv, _ := createTestEnv(true, true)
|
||||
|
||||
localName := "Willy"
|
||||
|
||||
gCfg, _ := dEnv.Config.GetConfig(GlobalConfig)
|
||||
lCfg, _ := dEnv.Config.GetConfig(LocalConfig)
|
||||
require.NoError(t, gCfg.SetStrings(map[string]string{UserNameKey: name}))
|
||||
require.NoError(t, lCfg.SetStrings(map[string]string{UserNameKey: localName}))
|
||||
|
||||
cfg := dEnv.Config.WriteableConfig()
|
||||
|
||||
assert.Equal(t, localName, cfg.GetStringOrDefault(UserNameKey, "none"))
|
||||
|
||||
require.NoError(t, cfg.SetStrings(map[string]string{"test": "abc"}))
|
||||
require.NoError(t, cfg.Unset([]string{UserNameKey}))
|
||||
|
||||
assert.Equal(t, name, cfg.GetStringOrDefault(UserNameKey, "none"))
|
||||
assert.Equal(t, "abc", cfg.GetStringOrDefault("test", "none"))
|
||||
|
||||
_, err := lCfg.GetString(UserNameKey)
|
||||
assert.Equal(t, config.ErrConfigParamNotFound, err)
|
||||
|
||||
assert.Equal(t, name, gCfg.GetStringOrDefault(UserNameKey, "none"))
|
||||
_, err = gCfg.GetString("test")
|
||||
assert.Equal(t, config.ErrConfigParamNotFound, err)
|
||||
}
|
||||
|
||||
func TestWritableDoltConfigNoLocal(t *testing.T) {
|
||||
dEnv, _ := createTestEnv(true, false)
|
||||
|
||||
newName := "Willy"
|
||||
|
||||
gCfg, _ := dEnv.Config.GetConfig(GlobalConfig)
|
||||
require.NoError(t, gCfg.SetStrings(map[string]string{UserNameKey: name, "test": "abc"}))
|
||||
|
||||
cfg := dEnv.Config.WriteableConfig()
|
||||
|
||||
assert.Equal(t, name, cfg.GetStringOrDefault(UserNameKey, "none"))
|
||||
assert.Equal(t, "abc", cfg.GetStringOrDefault("test", "none"))
|
||||
|
||||
require.NoError(t, cfg.SetStrings(map[string]string{UserNameKey: newName}))
|
||||
require.NoError(t, cfg.Unset([]string{"test"}))
|
||||
|
||||
assert.Equal(t, newName, cfg.GetStringOrDefault(UserNameKey, "none"))
|
||||
|
||||
_, err := cfg.GetString("test")
|
||||
assert.Equal(t, config.ErrConfigParamNotFound, err)
|
||||
|
||||
assert.Equal(t, newName, gCfg.GetStringOrDefault(UserNameKey, "none"))
|
||||
|
||||
_, err = gCfg.GetString("test")
|
||||
assert.Equal(t, config.ErrConfigParamNotFound, err)
|
||||
}
|
||||
|
||||
+8
-1
@@ -156,8 +156,15 @@ func getRepoRootDir(path, pathSeparator string) string {
|
||||
return name
|
||||
}
|
||||
|
||||
// DoltEnvAsMultiEnv returns a MultiRepoEnv which wraps the DoltEnv and names it based on the directory DoltEnv refers to
|
||||
// DoltEnvAsMultiEnv returns a MultiRepoEnv which wraps the DoltEnv and names it based on the directory DoltEnv refers
|
||||
// to. If the env given doesn't contain a valid dolt database, creates a MultiEnvRepo from any databases found in the
|
||||
// directory at the root of the filesystem and returns that.
|
||||
func DoltEnvAsMultiEnv(ctx context.Context, dEnv *DoltEnv) (*MultiRepoEnv, error) {
|
||||
if !dEnv.Valid() {
|
||||
cfg := dEnv.Config.WriteableConfig()
|
||||
return MultiEnvForDirectory(ctx, cfg, dEnv.FS, dEnv.Version)
|
||||
}
|
||||
|
||||
dbName := "dolt"
|
||||
|
||||
if dEnv.RSLoadErr != nil {
|
||||
|
||||
@@ -44,7 +44,7 @@ func NewConfigHierarchy() *ConfigHierarchy {
|
||||
|
||||
// AddConfig adds a ReadWriteConfig to the hierarchy. Newly added configs are at a lower priority than the configs that
|
||||
// were added previously. Though the ConfigHierarchy does not support modification of stored values in the configs
|
||||
// directly, the configs it manages must implement the WriteConfig interface.
|
||||
// directly, the configs it manages must implement the WritableConfig interface.
|
||||
func (ch *ConfigHierarchy) AddConfig(name string, cs ReadWriteConfig) {
|
||||
name = strings.TrimSpace(strings.ToLower(name))
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ func (mc *MapConfig) GetStringOrDefault(key, defStr string) string {
|
||||
return defStr
|
||||
}
|
||||
|
||||
// SetString sets the values for a map of updates.
|
||||
// SetStrings sets the values for a map of updates.
|
||||
func (mc *MapConfig) SetStrings(updates map[string]string) error {
|
||||
for k, v := range updates {
|
||||
mc.properties[k] = v
|
||||
|
||||
@@ -163,7 +163,7 @@ func getProfFile(b *testing.B) *os.File {
|
||||
}
|
||||
|
||||
func executeServerQueries(ctx context.Context, b *testing.B, dEnv *env.DoltEnv, cfg srv.ServerConfig, queries []query) {
|
||||
serverController := srv.CreateServerController()
|
||||
serverController := srv.NewServerController()
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ func getProfFile(b *testing.B) *os.File {
|
||||
}
|
||||
|
||||
func executeServerQueries(ctx context.Context, b *testing.B, dEnv *env.DoltEnv, cfg srv.ServerConfig, queries []query) {
|
||||
serverController := srv.CreateServerController()
|
||||
serverController := srv.NewServerController()
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
select " _..-'( )`-.._\n ./'. '||\\\\. (\\_/) .//||` .`\\.\n ./'.|'.'||||\\\\|.. )O O( ..|//||||`.`|.`\\.\n ./'..|'.|| |||||\\`````` '`\"'` ''''''/||||| ||.`|..`\\.\n ./'.||'.|||| ||||||||||||. .|||||||||||| |||||.`||.`\\.\n /'|||'.|||||| ||||||||||||{ }|||||||||||| ||||||.`|||`\\\n '.|||'.||||||| ||||||||||||{ }|||||||||||| |||||||.`|||.`\n '.||| ||||||||| |/' ``\\||`` ''||/'' `\\| ||||||||| |||.`\n |/' \\./' `\\./ \\!|\\ /|!/ \\./' `\\./ `\\|\n V V V }' `\\ /' `{ V V V\n ` ` ` V ' ' '\n" as "BATS!";
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env bats
|
||||
load $BATS_TEST_DIRNAME/helper/common.bash
|
||||
load $BATS_TEST_DIRNAME/helper/query-server-common.bash
|
||||
|
||||
setup() {
|
||||
setup_no_dolt_init
|
||||
@@ -11,6 +12,7 @@ setup() {
|
||||
teardown() {
|
||||
teardown_common
|
||||
rm -rf "$BATS_TMPDIR/config-test$$"
|
||||
stop_sql_server
|
||||
}
|
||||
|
||||
@test "config: make sure no dolt configuration for simulated fresh user" {
|
||||
@@ -22,7 +24,7 @@ teardown() {
|
||||
@test "config: try to initialize a repository with no configuration" {
|
||||
run dolt init
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ "Could not determine user.name" ]] || false
|
||||
[[ "$output" =~ "Please tell me who you are" ]] || false
|
||||
}
|
||||
|
||||
@test "config: set a global config variable" {
|
||||
@@ -77,7 +79,7 @@ teardown() {
|
||||
dolt config --global --add user.name "bats tester"
|
||||
run dolt init
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ "Could not determine user.email" ]] || false
|
||||
[[ "$output" =~ "Please tell me who you are" ]] || false
|
||||
dolt config --global --add user.email "bats-tester@liquidata.co"
|
||||
run dolt init
|
||||
[ "$status" -eq 0 ]
|
||||
@@ -165,7 +167,39 @@ teardown() {
|
||||
[[ "$output" =~ "$regex" ]] || false
|
||||
}
|
||||
|
||||
@test "config: COMMIT correctly errors when user.name or user.email is unset." {
|
||||
@test "config: SQL can create databases with no user and email set" {
|
||||
dolt sql -b -q "
|
||||
CREATE DATABASE testdb;
|
||||
use testdb;
|
||||
CREATE TABLE test (pk int primary key, c1 varchar(1));"
|
||||
|
||||
[ -d "testdb" ]
|
||||
cd testdb
|
||||
run dolt log
|
||||
[ "$status" -eq 0 ]
|
||||
regex='Dolt System Account <doltuser@dolthub.com>'
|
||||
[[ "$output" =~ "$regex" ]] || false
|
||||
}
|
||||
|
||||
@test "config: sql server can create databases with no user and email set" {
|
||||
skiponwindows "This test has dependencies missing on windows installations"
|
||||
|
||||
start_sql_server
|
||||
|
||||
server_query "" 1 "create database testdb"
|
||||
server_query "" 1 "show databases" "Database\ninformation_schema\ntestdb"
|
||||
server_query "testdb" 1 "create table a(x int)"
|
||||
server_query "testdb" 1 "insert into a values (1), (2)"
|
||||
|
||||
[ -d "testdb" ]
|
||||
cd testdb
|
||||
run dolt log
|
||||
[ "$status" -eq 0 ]
|
||||
regex='Dolt System Account <doltuser@dolthub.com>'
|
||||
[[ "$output" =~ "$regex" ]] || false
|
||||
}
|
||||
|
||||
@test "config: SQL COMMIT uses default values when user.name or user.email is unset." {
|
||||
dolt config --global --add user.name "bats tester"
|
||||
dolt config --global --add user.email "joshn@doe.com"
|
||||
|
||||
@@ -179,13 +213,46 @@ teardown() {
|
||||
dolt config --global --unset user.email
|
||||
|
||||
run dolt sql -q "SET @@dolt_repo_$$_head = COMMIT('-a', '-m', 'updated stuff')"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ "Aborting commit due to empty committer name. Is your config set" ]] || false
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
dolt config --global --add user.name "bats tester"
|
||||
run dolt sql -q "SET @@dolt_repo_$$_head = COMMIT('-a', '-m', 'updated stuff')"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ "Aborting commit due to empty committer email. Is your config set" ]] || false
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "config: DOLT_COMMIT uses default values when user.name or user.email is unset." {
|
||||
dolt config --global --add user.name "bats tester"
|
||||
dolt config --global --add user.email "joshn@doe.com"
|
||||
|
||||
dolt init
|
||||
dolt sql -q "
|
||||
CREATE TABLE test (
|
||||
pk int primary key
|
||||
)"
|
||||
|
||||
dolt config --global --unset user.name
|
||||
dolt config --global --unset user.email
|
||||
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'created table test')"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run dolt log -n 1
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "Dolt System Account" ]] || false
|
||||
[[ "$output" =~ "created table test" ]] || false
|
||||
|
||||
dolt sql -q "create table test2 (pk int primary key)"
|
||||
|
||||
dolt config --global --add user.name "bats tester"
|
||||
|
||||
run dolt sql -q "SELECT DOLT_COMMIT('-a', '-m', 'created table test2')"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run dolt log -n 1
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "bats tester" ]] || false
|
||||
[[ "$output" =~ "doltuser@dolthub.com" ]] || false
|
||||
[[ "$output" =~ "created table test2" ]] || false
|
||||
}
|
||||
|
||||
@test "config: Set default init branch" {
|
||||
|
||||
@@ -48,7 +48,11 @@ setup_no_dolt_init() {
|
||||
|
||||
assert_feature_version() {
|
||||
run dolt version --feature
|
||||
[[ "$output" =~ "feature version: 2" ]] || exit 1
|
||||
# Tests that don't end in a valid dolt dir will fail the above
|
||||
# command, don't check its output in that case
|
||||
if [ "$status" -eq 0 ]; then
|
||||
[[ "$output" =~ "feature version: 2" ]] || exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
setup_common() {
|
||||
|
||||
@@ -142,9 +142,8 @@ NOT_VALID_REPO_ERROR="The current directory is not a valid dolt repository."
|
||||
}
|
||||
|
||||
@test "no-repo: dolt sql outside of a dolt repository" {
|
||||
run dolt sql
|
||||
[ "$status" -ne 0 ]
|
||||
[ "${lines[0]}" = "$NOT_VALID_REPO_ERROR" ]
|
||||
run dolt sql -q "show databases"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "no-repo: dolt checkout outside of a dolt repository" {
|
||||
|
||||
@@ -616,12 +616,12 @@ SQL
|
||||
}
|
||||
|
||||
@test "sql: run outside a dolt directory" {
|
||||
skip "Doesn't work yet"
|
||||
|
||||
mkdir new && cd new
|
||||
dolt sql
|
||||
|
||||
dolt sql --disable-batch <<SQL
|
||||
mkdir decoy
|
||||
touch decoy/file.txt
|
||||
|
||||
dolt sql --disable-batch <<SQL
|
||||
CREATE DATABASE test1;
|
||||
USE test1;
|
||||
CREATE TABLE table_a(x int primary key);
|
||||
@@ -646,6 +646,30 @@ SQL
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "test1" ]] || false
|
||||
[[ "$output" =~ "information_schema" ]] || false
|
||||
[[ ! "$output" =~ "decoy" ]] || false
|
||||
|
||||
# There's a bug in the teardown logic that means we need to cd
|
||||
# into the repo directory before the test ends
|
||||
cd ../
|
||||
}
|
||||
|
||||
@test "sql: bad dolt db" {
|
||||
mkdir new && cd new
|
||||
|
||||
mkdir -p decoy/.dolt/noms/oldgen
|
||||
mkdir -p decoy/.dolt/noms/temptf
|
||||
echo '{}' > decoy/config.json
|
||||
|
||||
# Not doing this cd ../ results in the teardown method failing on
|
||||
# a skip, not sure why. It's not part of the actual test
|
||||
cd ../
|
||||
skip "This results in a panic right now"
|
||||
|
||||
run dolt sql -q "show databases" -r csv
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${#lines[@]}" -eq 2 ]
|
||||
[[ "$output" =~ "information_schema" ]] || false
|
||||
[[ ! "$output" =~ "decoy" ]] || false
|
||||
}
|
||||
|
||||
@test "sql: set head ref session var" {
|
||||
|
||||
Reference in New Issue
Block a user