Merge pull request #2364 from dolthub/zachmu/sql-create-polish

Better support for sql outside a database directory
This commit is contained in:
Zach Musgrave
2021-11-09 16:50:38 -08:00
committed by GitHub
26 changed files with 385 additions and 132 deletions
+35
View File
@@ -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")
+4 -1
View File
@@ -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)
}
+22 -19
View File
@@ -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 {
+1
View File
@@ -137,6 +137,7 @@ func TestConfigGet(t *testing.T) {
CfgSet: multiCfg,
ConfigElem: env.LocalConfig,
Key: "title",
Code: 1,
},
{
Name: "missing param",
+8
View File
@@ -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 == "" {
+18 -16
View File
@@ -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")
}
}
})
}
}
+5
View File
@@ -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)
+5
View File
@@ -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
+3 -5
View File
@@ -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
+5 -16
View File
@@ -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.
+1 -1
View File
@@ -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)
}()
+4 -1
View File
@@ -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)
+51 -21
View File
@@ -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
View File
@@ -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
View File
@@ -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))
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+1
View File
@@ -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!";
+74 -7
View File
@@ -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" {
+5 -1
View File
@@ -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() {
+2 -3
View File
@@ -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" {
+28 -4
View File
@@ -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" {