mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-14 18:18:55 -06:00
Merge pull request #6390 from dolthub/steph/dolt-profile
Adds new `--profile` global arg
This commit is contained in:
@@ -310,6 +310,24 @@ func CreateCountCommitsArgParser() *argparser.ArgParser {
|
||||
return ap
|
||||
}
|
||||
|
||||
func CreateGlobalArgParser(name string) *argparser.ArgParser {
|
||||
ap := argparser.NewArgParserWithVariableArgs(name)
|
||||
if name == "dolt" {
|
||||
ap.SupportsString("profile", "", "profile", "The name of the profile to use when executing SQL queries. Run `dolt profile --help` for more information.")
|
||||
}
|
||||
ap.SupportsString("user", "u", "user", "Defines the local superuser.")
|
||||
ap.SupportsString("password", "p", "password", "Defines the password for the user.")
|
||||
ap.SupportsString("host", "", "host", "Defines the host to connect to.")
|
||||
ap.SupportsString("port", "", "port", "Defines the port to connect to.")
|
||||
ap.SupportsFlag("no-tls", "", "Disables TLS for the connection to remote databases.")
|
||||
ap.SupportsString("data-dir", "", "data-dir", "Defines a data directory whose subdirectories should all be dolt data repositories accessible as independent databases.")
|
||||
ap.SupportsString("doltcfg-dir", "", "doltcfg-dir", "Defines a directory that contains configuration files for dolt.")
|
||||
ap.SupportsString("privilege-file", "", "privilege-file", "DePath to a file to load and store users and grants.")
|
||||
ap.SupportsString("branch-control-file", "", "branch-control-file", "Path to a file to load and store branch control permissions.")
|
||||
ap.SupportsString("use-db", "", "use-db", "The name of the database to use when executing SQL queries.")
|
||||
return ap
|
||||
}
|
||||
|
||||
var awsParams = []string{dbfactory.AWSRegionParam, dbfactory.AWSCredsTypeParam, dbfactory.AWSCredsFileParam, dbfactory.AWSCredsProfile}
|
||||
var ossParams = []string{dbfactory.OSSCredsFileParam, dbfactory.OSSCredsProfile}
|
||||
|
||||
|
||||
363
go/cmd/dolt/commands/profile.go
Normal file
363
go/cmd/dolt/commands/profile.go
Normal file
@@ -0,0 +1,363 @@
|
||||
// Copyright 2023 Dolthub, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
|
||||
"github.com/dolthub/dolt/go/cmd/dolt/cli"
|
||||
"github.com/dolthub/dolt/go/cmd/dolt/errhand"
|
||||
eventsapi "github.com/dolthub/dolt/go/gen/proto/dolt/services/eventsapi/v1alpha1"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/dbfactory"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/env"
|
||||
"github.com/dolthub/dolt/go/libraries/utils/argparser"
|
||||
"github.com/dolthub/dolt/go/libraries/utils/config"
|
||||
)
|
||||
|
||||
var profileDocs = cli.CommandDocumentationContent{
|
||||
ShortDesc: "Manage dolt profiles for CLI global options.",
|
||||
LongDesc: `With no arguments, shows a list of existing profiles. Two subcommands are available to perform operations on the profiles.
|
||||
{{.EmphasisLeft}}add{{.EmphasisRight}}
|
||||
Adds a profile named {{.LessThan}}name{{.GreaterThan}}. If the profile already exists, it will be overwritten.
|
||||
|
||||
{{.EmphasisLeft}}remove{{.EmphasisRight}}, {{.EmphasisLeft}}rm{{.EmphasisRight}}
|
||||
Remove the profile named {{.LessThan}}name{{.GreaterThan}}.`,
|
||||
Synopsis: []string{
|
||||
"[-v | --verbose]",
|
||||
"add [-u {{.LessThan}}user{{.GreaterThan}}] [-p {{.LessThan}}password{{.GreaterThan}}] [--host {{.LessThan}}host{{.GreaterThan}}] [--port {{.LessThan}}port{{.GreaterThan}}] [--no-tls] [--data-dir {{.LessThan}}directory{{.GreaterThan}}] [--doltcfg-dir {{.LessThan}}directory{{.GreaterThan}}] [--privilege-file {{.LessThan}}privilege file{{.GreaterThan}}] [--branch-control-file {{.LessThan}}branch control file{{.GreaterThan}}] [--use-db {{.LessThan}}database{{.GreaterThan}}] {{.LessThan}}name{{.GreaterThan}}",
|
||||
"remove {{.LessThan}}name{{.GreaterThan}}",
|
||||
},
|
||||
}
|
||||
|
||||
const (
|
||||
addProfileId = "add"
|
||||
removeProfileId = "remove"
|
||||
GlobalCfgProfileKey = "profile"
|
||||
DefaultProfileName = "default"
|
||||
defaultProfileWarning = "Default profile has been added. All dolt commands taking global arguments will use this default profile until it is removed.\nWARNING: This will alter the behavior of commands which specify no `--profile`.\nIf you are using dolt in contexts where you expect a `.dolt` directory to be accessed, the default profile will be used instead."
|
||||
)
|
||||
|
||||
type ProfileCmd struct{}
|
||||
|
||||
// Name returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
|
||||
func (cmd ProfileCmd) Name() string {
|
||||
return "profile"
|
||||
}
|
||||
|
||||
// Description returns a description of the command
|
||||
func (cmd ProfileCmd) Description() string {
|
||||
return "Manage dolt profiles for CLI global options."
|
||||
}
|
||||
|
||||
func (cmd ProfileCmd) Docs() *cli.CommandDocumentation {
|
||||
ap := cmd.ArgParser()
|
||||
return cli.NewCommandDocumentation(profileDocs, ap)
|
||||
}
|
||||
|
||||
func (cmd ProfileCmd) ArgParser() *argparser.ArgParser {
|
||||
ap := cli.CreateGlobalArgParser("profile")
|
||||
ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"name", "Defines the name of the profile to add or remove."})
|
||||
ap.SupportsFlag(cli.VerboseFlag, "v", "Includes full details when printing list of profiles.")
|
||||
return ap
|
||||
}
|
||||
|
||||
// EventType returns the type of the event to log
|
||||
func (cmd ProfileCmd) EventType() eventsapi.ClientEventType {
|
||||
return eventsapi.ClientEventType_PROFILE
|
||||
}
|
||||
|
||||
func (cmd ProfileCmd) RequiresRepo() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Exec executes the command
|
||||
func (cmd ProfileCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv, cliCtx cli.CliContext) int {
|
||||
ap := cmd.ArgParser()
|
||||
help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, profileDocs, ap))
|
||||
apr := cli.ParseArgsOrDie(ap, args, help)
|
||||
|
||||
var verr errhand.VerboseError
|
||||
|
||||
switch {
|
||||
case apr.NArg() == 0:
|
||||
verr = printProfiles(dEnv, apr)
|
||||
case apr.Arg(0) == addProfileId:
|
||||
verr = addProfile(dEnv, apr)
|
||||
case apr.Arg(0) == removeProfileId:
|
||||
verr = removeProfile(dEnv, apr)
|
||||
default:
|
||||
verr = errhand.BuildDError("").SetPrintUsage().Build()
|
||||
}
|
||||
|
||||
return HandleVErrAndExitCode(verr, usage)
|
||||
}
|
||||
|
||||
func addProfile(dEnv *env.DoltEnv, apr *argparser.ArgParseResults) errhand.VerboseError {
|
||||
if apr.NArg() != 2 {
|
||||
return errhand.BuildDError("Only one profile name can be specified").SetPrintUsage().Build()
|
||||
}
|
||||
|
||||
profileName := strings.TrimSpace(apr.Arg(1))
|
||||
|
||||
p := newProfile(apr)
|
||||
profStr := p.String()
|
||||
|
||||
cfg, ok := dEnv.Config.GetConfig(env.GlobalConfig)
|
||||
if !ok {
|
||||
return errhand.BuildDError("error: failed to get global config").Build()
|
||||
}
|
||||
//TODO: enable config to retrieve json objects instead of just strings
|
||||
encodedProfiles, err := cfg.GetString(GlobalCfgProfileKey)
|
||||
if err != nil {
|
||||
if err != config.ErrConfigParamNotFound {
|
||||
return errhand.BuildDError("error: failed to get profiles, %s", err).Build()
|
||||
} else {
|
||||
profilesJSON := "{\"" + profileName + "\"" + ": " + profStr + "}"
|
||||
err = writeProfileToGlobalConfig(profilesJSON, cfg)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to write profile to config, %s", err).Build()
|
||||
}
|
||||
if profileName == DefaultProfileName {
|
||||
cli.Println(color.YellowString(defaultProfileWarning))
|
||||
}
|
||||
|
||||
err = setGlobalConfigPermissions(dEnv)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to set permissions, %s", err).Build()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
profilesJSON, profileExists, err := decodeProfileAndCheckExists(profileName, encodedProfiles)
|
||||
if profileExists {
|
||||
return errhand.BuildDError("error: profile %s already exists, please delete this profile and re-add it if you want to edit any values.", profileName).Build()
|
||||
}
|
||||
|
||||
profilesJSON, err = sjson.Set(profilesJSON, profileName, profStr)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to add profile, %s", err).Build()
|
||||
}
|
||||
err = writeProfileToGlobalConfig(profilesJSON, cfg)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to write profile to config, %s", err).Build()
|
||||
}
|
||||
|
||||
if profileName == DefaultProfileName {
|
||||
cli.Println(color.YellowString(defaultProfileWarning))
|
||||
}
|
||||
|
||||
err = setGlobalConfigPermissions(dEnv)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to set permissions, %s", err).Build()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeProfile(dEnv *env.DoltEnv, apr *argparser.ArgParseResults) errhand.VerboseError {
|
||||
if apr.NArg() != 2 {
|
||||
return errhand.BuildDError("Only one profile name can be specified").SetPrintUsage().Build()
|
||||
}
|
||||
|
||||
profileName := strings.TrimSpace(apr.Arg(1))
|
||||
|
||||
cfg, ok := dEnv.Config.GetConfig(env.GlobalConfig)
|
||||
if !ok {
|
||||
return errhand.BuildDError("error: failed to get global config").Build()
|
||||
}
|
||||
encodedProfiles, err := cfg.GetString(GlobalCfgProfileKey)
|
||||
if err != nil {
|
||||
if err == config.ErrConfigParamNotFound {
|
||||
return errhand.BuildDError("error: no existing profiles").Build()
|
||||
}
|
||||
return errhand.BuildDError("error: failed to get profiles, %s", err).Build()
|
||||
}
|
||||
profilesJSON, profileExists, err := decodeProfileAndCheckExists(profileName, encodedProfiles)
|
||||
if !profileExists {
|
||||
return errhand.BuildDError("error: profile %s does not exist", profileName).Build()
|
||||
}
|
||||
|
||||
profilesJSON, err = sjson.Delete(profilesJSON, profileName)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to remove profile, %s", err).Build()
|
||||
}
|
||||
if profilesJSON == "{}" {
|
||||
err = cfg.Unset([]string{GlobalCfgProfileKey})
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to remove profile, %s", err).Build()
|
||||
}
|
||||
} else {
|
||||
err = writeProfileToGlobalConfig(profilesJSON, cfg)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to write profile to config, %s", err).Build()
|
||||
}
|
||||
}
|
||||
|
||||
err = setGlobalConfigPermissions(dEnv)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to set permissions, %s", err).Build()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printProfiles(dEnv *env.DoltEnv, apr *argparser.ArgParseResults) errhand.VerboseError {
|
||||
cfg, ok := dEnv.Config.GetConfig(env.GlobalConfig)
|
||||
if !ok {
|
||||
return errhand.BuildDError("error: failed to get global config").Build()
|
||||
}
|
||||
encodedProfiles, err := cfg.GetString(GlobalCfgProfileKey)
|
||||
if err != nil {
|
||||
if err == config.ErrConfigParamNotFound {
|
||||
return nil
|
||||
}
|
||||
return errhand.BuildDError("error: failed to get profiles, %s", err).Build()
|
||||
}
|
||||
profilesJSON, err := DecodeProfile(encodedProfiles)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to decode profiles, %s", err).Build()
|
||||
}
|
||||
|
||||
profileMap := gjson.Parse(profilesJSON)
|
||||
if !profileMap.Exists() {
|
||||
return nil
|
||||
}
|
||||
|
||||
for profileName, profile := range profileMap.Map() {
|
||||
var p Profile
|
||||
var val []byte = []byte(profile.String())
|
||||
err := json.Unmarshal([]byte(val), &p)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to unmarshal profile, %s", err).Build()
|
||||
}
|
||||
prettyPrintProfile(profileName, p, apr.Contains(cli.VerboseFlag))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func prettyPrintProfile(profileName string, profile Profile, verbose bool) {
|
||||
cli.Println(profileName)
|
||||
if verbose {
|
||||
if profile.HasPassword {
|
||||
cli.Println(fmt.Sprintf("\tuser: %s\n\tpassword: %s\n\thost: %s\n\tport: %s\n\tno-tls: %t\n\tdata-dir: %s\n\tdoltcfg-dir: %s\n\tprivilege-file: %s\n\tbranch-control-file: %s\n\tuse-db: %s\n",
|
||||
profile.User, profile.Password, profile.Host, profile.Port, profile.NoTLS, profile.DataDir, profile.DoltCfgDir, profile.PrivilegeFile, profile.BranchControl, profile.UseDB))
|
||||
} else {
|
||||
cli.Println(fmt.Sprintf("\tuser: %s\n\thost: %s\n\tport: %s\n\tno-tls: %t\n\tdata-dir: %s\n\tdoltcfg-dir: %s\n\tprivilege-file: %s\n\tbranch-control-file: %s\n\tuse-db: %s\n",
|
||||
profile.User, profile.Host, profile.Port, profile.NoTLS, profile.DataDir, profile.DoltCfgDir, profile.PrivilegeFile, profile.BranchControl, profile.UseDB))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setGlobalConfigPermissions sets permissions on global config file to 0600 to protect potentially sensitive information (credentials)
|
||||
func setGlobalConfigPermissions(dEnv *env.DoltEnv) error {
|
||||
homeDir, err := env.GetCurrentUserHomeDir()
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to get home directory: %s", err).Build()
|
||||
}
|
||||
path, err := dEnv.FS.Abs(filepath.Join(homeDir, dbfactory.DoltDir, env.GlobalConfigFile))
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to get global config path: %s", err).Build()
|
||||
}
|
||||
err = os.Chmod(path, 0600)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("error: failed to set permissions on global config: %s", err).Build()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeProfileToGlobalConfig encodes a given profile JSON (represented by a string) to base64 and writes that encoded profile to the global config
|
||||
func writeProfileToGlobalConfig(profile string, config config.ReadWriteConfig) error {
|
||||
profilesData := []byte(profile)
|
||||
encodedProfiles := make([]byte, base64.StdEncoding.EncodedLen(len(profilesData)))
|
||||
base64.StdEncoding.Encode(encodedProfiles, profilesData)
|
||||
|
||||
err := config.SetStrings(map[string]string{GlobalCfgProfileKey: string(encodedProfiles)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeProfile decodes a given base64 encoded profile string to a string representing a JSON
|
||||
func DecodeProfile(encodedProfile string) (string, error) {
|
||||
decodedProfile := make([]byte, base64.StdEncoding.DecodedLen(len(encodedProfile)))
|
||||
n, err := base64.StdEncoding.Decode(decodedProfile, []byte(encodedProfile))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
decodedProfile = decodedProfile[:n]
|
||||
return string(decodedProfile), nil
|
||||
}
|
||||
|
||||
// decodeProfileAndCheckExists decodes the given profiles and retrieves the profile named profileName. Returns a
|
||||
// string representing the profile JSON and a bool indicating whether the profile exists
|
||||
func decodeProfileAndCheckExists(profileName, encodedProfiles string) (string, bool, error) {
|
||||
profilesJSON, err := DecodeProfile(encodedProfiles)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
profileCheck := gjson.Get(profilesJSON, profileName)
|
||||
return profilesJSON, profileCheck.Exists(), nil
|
||||
}
|
||||
|
||||
type Profile struct {
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
HasPassword bool `json:"has-password"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
NoTLS bool `json:"no-tls"`
|
||||
DataDir string `json:"data-dir"`
|
||||
DoltCfgDir string `json:"doltcfg-dir"`
|
||||
PrivilegeFile string `json:"privilege-file"`
|
||||
BranchControl string `json:"branch-control-file"`
|
||||
UseDB string `json:"use-db"`
|
||||
}
|
||||
|
||||
func (p Profile) String() string {
|
||||
b, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func newProfile(apr *argparser.ArgParseResults) Profile {
|
||||
return Profile{
|
||||
User: apr.GetValueOrDefault(cli.UserFlag, ""),
|
||||
Password: apr.GetValueOrDefault(cli.PasswordFlag, ""),
|
||||
HasPassword: apr.Contains(cli.PasswordFlag),
|
||||
Host: apr.GetValueOrDefault(cli.HostFlag, ""),
|
||||
Port: apr.GetValueOrDefault(cli.PortFlag, ""),
|
||||
NoTLS: apr.Contains(cli.NoTLSFlag),
|
||||
DataDir: apr.GetValueOrDefault(DataDirFlag, ""),
|
||||
DoltCfgDir: apr.GetValueOrDefault(CfgDirFlag, ""),
|
||||
PrivilegeFile: apr.GetValueOrDefault(PrivsFilePathFlag, ""),
|
||||
BranchControl: apr.GetValueOrDefault(BranchCtrlPathFlag, ""),
|
||||
UseDB: apr.GetValueOrDefault(UseDbFlag, ""),
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ const (
|
||||
|
||||
type RemoteCmd struct{}
|
||||
|
||||
// Name is returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
|
||||
// Name returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
|
||||
func (cmd RemoteCmd) Name() string {
|
||||
return "remote"
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ const (
|
||||
DefaultUser = "root"
|
||||
DefaultHost = "localhost"
|
||||
UseDbFlag = "use-db"
|
||||
ProfileFlag = "profile"
|
||||
|
||||
welcomeMsg = `# Welcome to the DoltSQL shell.
|
||||
# Statements must be terminated with ';'.
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"github.com/dolthub/go-mysql-server/sql"
|
||||
"github.com/fatih/color"
|
||||
"github.com/pkg/profile"
|
||||
"github.com/tidwall/gjson"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/exporters/jaeger"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
@@ -55,6 +56,7 @@ import (
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dsess"
|
||||
"github.com/dolthub/dolt/go/libraries/events"
|
||||
"github.com/dolthub/dolt/go/libraries/utils/argparser"
|
||||
"github.com/dolthub/dolt/go/libraries/utils/config"
|
||||
"github.com/dolthub/dolt/go/libraries/utils/filesys"
|
||||
"github.com/dolthub/dolt/go/store/nbs"
|
||||
"github.com/dolthub/dolt/go/store/util/tempfiles"
|
||||
@@ -118,6 +120,7 @@ var doltSubCommands = []cli.Command{
|
||||
docscmds.Commands,
|
||||
stashcmds.StashCommands,
|
||||
&commands.Assist{},
|
||||
commands.ProfileCmd{},
|
||||
}
|
||||
|
||||
var commandsWithoutCliCtx = []cli.Command{
|
||||
@@ -150,6 +153,7 @@ var commandsWithoutCliCtx = []cli.Command{
|
||||
dumpZshCommand,
|
||||
docscmds.Commands,
|
||||
&commands.Assist{},
|
||||
commands.ProfileCmd{},
|
||||
}
|
||||
|
||||
var commandsWithoutGlobalArgSupport = []cli.Command{
|
||||
@@ -185,7 +189,7 @@ func supportsGlobalArgs(commandName string) bool {
|
||||
}
|
||||
|
||||
var doltCommand = cli.NewSubCommandHandler("dolt", "it's git for data", doltSubCommands)
|
||||
var globalArgParser = buildGlobalArgs()
|
||||
var globalArgParser = cli.CreateGlobalArgParser("dolt")
|
||||
var globalDocs = cli.CommandDocsForCommandString("dolt", doc, globalArgParser)
|
||||
|
||||
var globalSpecialMsg = `
|
||||
@@ -420,8 +424,24 @@ func runMain() int {
|
||||
|
||||
_, usage := cli.HelpAndUsagePrinters(globalDocs)
|
||||
|
||||
apr, remainingArgs, err := globalArgParser.ParseGlobalArgs(args)
|
||||
var fs filesys.Filesys
|
||||
fs = filesys.LocalFS
|
||||
dEnv := env.Load(ctx, env.GetCurrentUserHomeDir, fs, doltdb.LocalDirDoltDB, Version)
|
||||
dEnv.IgnoreLockFile = ignoreLockFile
|
||||
|
||||
root, err := env.GetCurrentUserHomeDir()
|
||||
if err != nil {
|
||||
cli.PrintErrln(color.RedString("Failed to load the HOME directory: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
globalConfig, ok := dEnv.Config.GetConfig(env.GlobalConfig)
|
||||
if !ok {
|
||||
cli.PrintErrln(color.RedString("Failed to get global config"))
|
||||
return 1
|
||||
}
|
||||
|
||||
apr, remainingArgs, subcommandName, err := parseGlobalArgsAndSubCommandName(globalConfig, args)
|
||||
if err == argparser.ErrHelp {
|
||||
doltCommand.PrintUsage("dolt")
|
||||
cli.Println(globalSpecialMsg)
|
||||
@@ -433,10 +453,6 @@ func runMain() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
subcommandName := remainingArgs[0]
|
||||
|
||||
var fs filesys.Filesys
|
||||
fs = filesys.LocalFS
|
||||
dataDir, hasDataDir := apr.GetValue(commands.DataDirFlag)
|
||||
if hasDataDir {
|
||||
// If a relative path was provided, this ensures we have an absolute path everywhere.
|
||||
@@ -450,14 +466,6 @@ func runMain() int {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
dEnv := env.Load(ctx, env.GetCurrentUserHomeDir, fs, doltdb.LocalDirDoltDB, Version)
|
||||
dEnv.IgnoreLockFile = ignoreLockFile
|
||||
|
||||
root, err := env.GetCurrentUserHomeDir()
|
||||
if err != nil {
|
||||
cli.PrintErrln(color.RedString("Failed to load the HOME directory: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if dEnv.CfgLoadErr != nil {
|
||||
cli.PrintErrln(color.RedString("Failed to load the global config. %v", dEnv.CfgLoadErr))
|
||||
@@ -729,19 +737,92 @@ func interceptSendMetrics(ctx context.Context, args []string) (bool, int) {
|
||||
return true, doltCommand.Exec(ctx, "dolt", args, dEnv, nil)
|
||||
}
|
||||
|
||||
func buildGlobalArgs() *argparser.ArgParser {
|
||||
ap := argparser.NewArgParserWithVariableArgs("dolt")
|
||||
// parseGlobalArgsAndSubCommandName parses the global arguments, including a profile if given or a default profile if exists. Also returns the subcommand name.
|
||||
func parseGlobalArgsAndSubCommandName(globalConfig config.ReadWriteConfig, args []string) (apr *argparser.ArgParseResults, remaining []string, subcommandName string, err error) {
|
||||
apr, remaining, err = globalArgParser.ParseGlobalArgs(args)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
|
||||
ap.SupportsString(cli.UserFlag, "u", "user", fmt.Sprintf("Defines the local superuser (defaults to `%v`). If the specified user exists, will take on permissions of that user.", commands.DefaultUser))
|
||||
ap.SupportsString(cli.PasswordFlag, "p", "password", "Defines the password for the user. Defaults to empty string.")
|
||||
ap.SupportsString(cli.HostFlag, "", "host", "Defines the host to connect to.")
|
||||
ap.SupportsInt(cli.PortFlag, "", "port", "Defines the port to connect to. Only used when the --host flag is also provided. Defaults to `3306`.")
|
||||
ap.SupportsFlag(cli.NoTLSFlag, "", "Disables TLS for the connection to remote databases.")
|
||||
ap.SupportsString(commands.DataDirFlag, "", "directory", "Defines a directory whose subdirectories should all be dolt data repositories accessible as independent databases within. Defaults to the current directory.")
|
||||
ap.SupportsString(commands.CfgDirFlag, "", "directory", "Defines a directory that contains configuration files for dolt. Defaults to `$data-dir/.doltcfg`. Will only be created if there is a change to configuration settings.")
|
||||
ap.SupportsString(commands.PrivsFilePathFlag, "", "privilege file", "Path to a file to load and store users and grants. Defaults to `$doltcfg-dir/privileges.db`. Will only be created if there is a change to privileges.")
|
||||
ap.SupportsString(commands.BranchCtrlPathFlag, "", "branch control file", "Path to a file to load and store branch control permissions. Defaults to `$doltcfg-dir/branch_control.db`. Will only be created if there is a change to branch control permissions.")
|
||||
ap.SupportsString(commands.UseDbFlag, "", "database", "The name of the database to use when executing SQL queries. Defaults the database of the root directory, if it exists, and the first alphabetically if not.")
|
||||
subcommandName = remaining[0]
|
||||
|
||||
return ap
|
||||
useDefaultProfile := false
|
||||
profileName, hasProfile := apr.GetValue(commands.ProfileFlag)
|
||||
encodedProfiles, err := globalConfig.GetString(commands.GlobalCfgProfileKey)
|
||||
if err != nil {
|
||||
if err == config.ErrConfigParamNotFound {
|
||||
if hasProfile {
|
||||
return nil, nil, "", fmt.Errorf("no profiles found")
|
||||
} else {
|
||||
return apr, remaining, subcommandName, nil
|
||||
}
|
||||
} else {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
}
|
||||
profiles, err := commands.DecodeProfile(encodedProfiles)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
|
||||
if !hasProfile && supportsGlobalArgs(subcommandName) {
|
||||
defaultProfile := gjson.Get(profiles, commands.DefaultProfileName)
|
||||
if defaultProfile.Exists() {
|
||||
args = append([]string{"--profile", commands.DefaultProfileName}, args...)
|
||||
apr, remaining, err = globalArgParser.ParseGlobalArgs(args)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
profileName, _ = apr.GetValue(commands.ProfileFlag)
|
||||
useDefaultProfile = true
|
||||
}
|
||||
}
|
||||
|
||||
if hasProfile || useDefaultProfile {
|
||||
profileArgs, err := getProfile(apr, profileName, profiles)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
args = append(profileArgs, args...)
|
||||
apr, remaining, err = globalArgParser.ParseGlobalArgs(args)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// getProfile retrieves the given profile from the provided list of profiles and returns the args (as flags) and values
|
||||
// for that profile in a []string. If the profile is not found, an error is returned.
|
||||
func getProfile(apr *argparser.ArgParseResults, profileName, profiles string) (result []string, err error) {
|
||||
prof := gjson.Get(profiles, profileName)
|
||||
if prof.Exists() {
|
||||
hasPassword := false
|
||||
password := ""
|
||||
for flag, value := range prof.Map() {
|
||||
if !apr.Contains(flag) {
|
||||
if flag == cli.PasswordFlag {
|
||||
password = value.Str
|
||||
} else if flag == "has-password" {
|
||||
hasPassword = value.Bool()
|
||||
} else if flag == cli.NoTLSFlag {
|
||||
if value.Bool() {
|
||||
result = append(result, "--"+flag)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if value.Str != "" {
|
||||
result = append(result, "--"+flag, value.Str)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !apr.Contains(cli.PasswordFlag) && hasPassword {
|
||||
result = append(result, "--"+cli.PasswordFlag, password)
|
||||
}
|
||||
return result, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("profile %s not found", profileName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ const (
|
||||
ClientEventType_STASH_LIST ClientEventType = 59
|
||||
ClientEventType_STASH_POP ClientEventType = 60
|
||||
ClientEventType_SHOW ClientEventType = 61
|
||||
ClientEventType_PROFILE ClientEventType = 62
|
||||
)
|
||||
|
||||
// Enum value maps for ClientEventType.
|
||||
|
||||
@@ -71,6 +71,8 @@ require (
|
||||
github.com/prometheus/client_golang v1.13.0
|
||||
github.com/rs/zerolog v1.28.0
|
||||
github.com/shirou/gopsutil/v3 v3.22.1
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/tidwall/sjson v1.2.5
|
||||
github.com/vbauerster/mpb v3.4.0+incompatible
|
||||
github.com/vbauerster/mpb/v8 v8.0.2
|
||||
github.com/xitongsys/parquet-go v1.6.1
|
||||
@@ -134,10 +136,8 @@ require (
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/rs/xid v1.4.0 // indirect
|
||||
github.com/tetratelabs/wazero v1.1.0 // indirect
|
||||
github.com/tidwall/gjson v1.14.4 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/tklauser/numcpus v0.3.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
|
||||
6
go/libraries/doltcore/env/paths.go
vendored
6
go/libraries/doltcore/env/paths.go
vendored
@@ -28,8 +28,8 @@ const (
|
||||
doltRootPathEnvVar = "DOLT_ROOT_PATH"
|
||||
credsDir = "creds"
|
||||
|
||||
configFile = "config.json"
|
||||
globalConfig = "config_global.json"
|
||||
configFile = "config.json"
|
||||
GlobalConfigFile = "config_global.json"
|
||||
|
||||
repoStateFile = "repo_state.json"
|
||||
)
|
||||
@@ -77,7 +77,7 @@ func getGlobalCfgPath(hdp HomeDirProvider) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return filepath.Join(homeDir, dbfactory.DoltDir, globalConfig), nil
|
||||
return filepath.Join(homeDir, dbfactory.DoltDir, GlobalConfigFile), nil
|
||||
}
|
||||
|
||||
func getLocalConfigPath() string {
|
||||
|
||||
2
go/libraries/doltcore/env/paths_test.go
vendored
2
go/libraries/doltcore/env/paths_test.go
vendored
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
func TestGetGlobalCfgPath(t *testing.T) {
|
||||
homeDir := "/user/bheni"
|
||||
expected := filepath.Join(homeDir, dbfactory.DoltDir, globalConfig)
|
||||
expected := filepath.Join(homeDir, dbfactory.DoltDir, GlobalConfigFile)
|
||||
actual, _ := getGlobalCfgPath(func() (string, error) {
|
||||
return homeDir, nil
|
||||
})
|
||||
|
||||
@@ -135,6 +135,7 @@ SKIP_SERVER_TESTS=$(cat <<-EOM
|
||||
~sql-reset.bats~
|
||||
~sql-checkout.bats~
|
||||
~cli-hosted.bats~
|
||||
~profile.bats~
|
||||
EOM
|
||||
)
|
||||
|
||||
|
||||
368
integration-tests/bats/profile.bats
Executable file
368
integration-tests/bats/profile.bats
Executable file
@@ -0,0 +1,368 @@
|
||||
#!/usr/bin/env bats
|
||||
load $BATS_TEST_DIRNAME/helper/common.bash
|
||||
load $BATS_TEST_DIRNAME/helper/query-server-common.bash
|
||||
|
||||
make_repo() {
|
||||
mkdir "$1"
|
||||
cd "$1"
|
||||
dolt init
|
||||
dolt sql -q "create table $1_tbl (id int)"
|
||||
dolt sql <<SQL
|
||||
CREATE TABLE table1 (pk int PRIMARY KEY);
|
||||
CREATE TABLE table2 (pk int PRIMARY KEY);
|
||||
SQL
|
||||
dolt add -A && dolt commit -m "tables table1, table2"
|
||||
cd -
|
||||
}
|
||||
|
||||
setup() {
|
||||
setup_no_dolt_init
|
||||
make_repo defaultDB
|
||||
make_repo altDB
|
||||
|
||||
unset DOLT_CLI_PASSWORD
|
||||
unset DOLT_SILENCE_USER_REQ_FOR_TESTING
|
||||
}
|
||||
|
||||
teardown() {
|
||||
stop_sql_server 1
|
||||
teardown_common
|
||||
}
|
||||
|
||||
@test "profile: --profile exists and isn't empty" {
|
||||
cd defaultDB
|
||||
dolt sql -q "create table test (pk int primary key)"
|
||||
dolt sql -q "insert into test values (999)"
|
||||
dolt add test
|
||||
dolt commit -m "insert initial value into test"
|
||||
cd -
|
||||
|
||||
dolt profile add --use-db defaultDB defaultTest
|
||||
run dolt --profile defaultTest sql -q "select * from test"
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "999" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: --profile doesn't exist" {
|
||||
dolt profile add --use-db defaultDB defaultTest
|
||||
|
||||
run dolt --profile nonExistentProfile sql -q "select * from altDB_tbl"
|
||||
[ "$status" -eq 1 ] || false
|
||||
[[ "$output" =~ "Failure to parse arguments: profile nonExistentProfile not found" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: additional flag gets used" {
|
||||
cd altDB
|
||||
dolt sql -q "create table test (pk int primary key)"
|
||||
dolt sql -q "insert into test values (999)"
|
||||
dolt add test
|
||||
dolt commit -m "insert initial value into test"
|
||||
cd -
|
||||
|
||||
dolt profile add --user dolt --password "" userProfile
|
||||
run dolt --profile userProfile --use-db altDB sql -q "select * from test"
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "999" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: duplicate flag overrides correctly" {
|
||||
cd altDB
|
||||
dolt sql -q "create table test (pk int primary key)"
|
||||
dolt sql -q "insert into test values (999)"
|
||||
dolt add test
|
||||
dolt commit -m "insert initial value into test"
|
||||
cd -
|
||||
|
||||
dolt profile add --use-db defaultDB defaultTest
|
||||
run dolt --profile defaultTest --use-db altDB sql -q "select * from test"
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "999" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: duplicate flag with non-duplicate flags in profile overrides correctly" {
|
||||
cd altDB
|
||||
dolt sql -q "create table test (pk int primary key)"
|
||||
dolt sql -q "insert into test values (999)"
|
||||
dolt add test
|
||||
dolt commit -m "insert initial value into test"
|
||||
cd -
|
||||
|
||||
start_sql_server altDb
|
||||
dolt --user dolt --password "" sql -q "CREATE USER 'steph' IDENTIFIED BY 'pass'; GRANT ALL PRIVILEGES ON altDB.* TO 'steph' WITH GRANT OPTION;";
|
||||
dolt profile add --user "not-steph" --password "pass" --use-db altDB userWithDBProfile
|
||||
|
||||
run dolt --profile userWithDBProfile --user steph sql -q "select * from test"
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "999" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: duplicate flag with non-duplicate flags overrides correctly" {
|
||||
cd altDB
|
||||
dolt sql -q "create table test (pk int primary key)"
|
||||
dolt sql -q "insert into test values (999)"
|
||||
dolt add test
|
||||
dolt commit -m "insert initial value into test"
|
||||
cd -
|
||||
|
||||
start_sql_server altDb
|
||||
dolt --user dolt --password "" sql -q "CREATE USER 'steph' IDENTIFIED BY 'pass'; GRANT ALL PRIVILEGES ON altDB.* TO 'steph' WITH GRANT OPTION;";
|
||||
dolt profile add --user "not-steph" --password "pass" userProfile
|
||||
|
||||
run dolt --profile userProfile --user steph --use-db altDB sql -q "select * from test"
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "999" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile add adds a profile" {
|
||||
run dolt profile add --use-db altDB altTest
|
||||
[ "$status" -eq 0 ] || false
|
||||
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "altTest" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile add does not overwrite an existing profile" {
|
||||
run dolt profile add --user "steph" --password "password123" userProfile
|
||||
[ "$status" -eq 0 ] || false
|
||||
|
||||
run dolt profile -v
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "userProfile" ]] || false
|
||||
[[ "$output" =~ "steph" ]] || false
|
||||
[[ "$output" =~ "password123" ]] || false
|
||||
|
||||
run dolt profile add --user "joe" --password "password123" userProfile
|
||||
[ "$status" -eq 1 ] || false
|
||||
[[ "$output" =~ "profile userProfile already exists, please delete this profile and re-add it if you want to edit any values" ]] || false
|
||||
|
||||
run dolt profile -v
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "userProfile" ]] || false
|
||||
[[ "$output" =~ "steph" ]] || false
|
||||
[[ ! "$output" =~ "joe" ]] || false
|
||||
[[ "$output" =~ "password123" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile add adds a profile with existing profiles" {
|
||||
dolt profile add --use-db altDB altTest
|
||||
dolt profile add --use-db defaultDB defaultTest
|
||||
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "altTest" ]] || false
|
||||
[[ "$output" =~ "defaultTest" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile add with multiple names errors" {
|
||||
run dolt profile add --use-db altDB altTest altTest2
|
||||
[ "$status" -eq 1 ] || false
|
||||
[[ "$output" =~ "Only one profile name can be specified" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: adding default profile prints warning message" {
|
||||
run dolt profile add --use-db defaultDB default
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "Default profile has been added. All dolt commands taking global arguments will use this default profile until it is removed." ]] || false
|
||||
[[ "$output" =~ "WARNING: This will alter the behavior of commands which specify no \`--profile\`." ]] || false
|
||||
[[ "$output" =~ "If you are using dolt in contexts where you expect a \`.dolt\` directory to be accessed, the default profile will be used instead." ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile add encodes profiles in config" {
|
||||
run dolt profile add --use-db altDB altTest
|
||||
[ "$status" -eq 0 ] || false
|
||||
|
||||
run cat "$BATS_TMPDIR/config-$$/.dolt/config_global.json"
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ ! "$output" =~ "altTest" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile add locks global config with 0600" {
|
||||
run dolt profile add --use-db altDB altTest
|
||||
[ "$status" -eq 0 ] || false
|
||||
|
||||
run stat "$BATS_TMPDIR/config-$$/.dolt/config_global.json"
|
||||
[[ "$output" =~ "-rw-------" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile remove removes a profile" {
|
||||
dolt profile add --use-db altDB altTest
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "altTest" ]] || false
|
||||
|
||||
run dolt profile remove altTest
|
||||
[ "$status" -eq 0 ] || false
|
||||
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ ! "$output" =~ "altTest:" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile remove leaves existing profiles" {
|
||||
dolt profile add --use-db altDB altTest
|
||||
dolt profile add --use-db defaultDB defaultTest
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "altTest" ]] || false
|
||||
[[ "$output" =~ "defaultTest" ]] || false
|
||||
|
||||
run dolt profile remove altTest
|
||||
[ "$status" -eq 0 ] || false
|
||||
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ ! "$output" =~ "altTest:" ]] || false
|
||||
[[ "$output" =~ "defaultTest" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile remove last profile also removes profile param from global config" {
|
||||
dolt profile add --use-db altDB altTest
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "altTest" ]] || false
|
||||
|
||||
run dolt profile remove altTest
|
||||
[ "$status" -eq 0 ] || false
|
||||
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ ! "$output" =~ "altTest" ]] || false
|
||||
|
||||
run dolt config --list --global
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ ! "$output" =~ "profile" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile remove with no existing profiles errors" {
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" = "" ]] || false
|
||||
|
||||
run dolt profile remove altTest
|
||||
[ "$status" -eq 1 ] || false
|
||||
[[ "$output" =~ "no existing profiles" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile remove with non-existent profile errors" {
|
||||
dolt profile add --use-db altDB altTest
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "altTest" ]] || false
|
||||
|
||||
run dolt profile remove defaultTest
|
||||
[ "$status" -eq 1 ] || false
|
||||
[[ "$output" =~ "profile defaultTest does not exist" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile remove with multiple names errors" {
|
||||
dolt profile add --use-db altDB altTest
|
||||
run dolt profile remove altTest altTest2
|
||||
[ "$status" -eq 1 ] || false
|
||||
[[ "$output" =~ "Only one profile name can be specified" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile remove locks global config with 0600" {
|
||||
dolt profile add --use-db altDB altTest
|
||||
run dolt profile remove altTest
|
||||
[ "$status" -eq 0 ] || false
|
||||
|
||||
run stat "$BATS_TMPDIR/config-$$/.dolt/config_global.json"
|
||||
[[ "$output" =~ "-rw-------" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile lists all profiles" {
|
||||
dolt profile add --use-db altDB altTest
|
||||
dolt profile add --use-db defaultDB -u "steph" --password "pass" defaultTest
|
||||
|
||||
run dolt profile
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "altTest" ]] || false
|
||||
[[ ! "$output" =~ "use-db: altDB" ]] || false
|
||||
[[ "$output" =~ "defaultTest" ]] || false
|
||||
[[ ! "$output" =~ "user: steph" ]] || false
|
||||
[[ ! "$output" =~ "password: pass" ]] || false
|
||||
[[ ! "$output" =~ "use-db: defaultDB" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: dolt profile --verbose lists all profiles and all details" {
|
||||
dolt profile add --use-db altDB altTest
|
||||
dolt profile add --use-db defaultDB -u "steph" --password "pass" defaultTest
|
||||
|
||||
run dolt profile -v
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "altTest" ]] || false
|
||||
[[ "$output" =~ "use-db: altDB" ]] || false
|
||||
[[ "$output" =~ "defaultTest" ]] || false
|
||||
[[ "$output" =~ "user: steph" ]] || false
|
||||
[[ "$output" =~ "password: pass" ]] || false
|
||||
[[ "$output" =~ "use-db: defaultDB" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: default profile used when none specified" {
|
||||
cd defaultDB
|
||||
dolt sql -q "create table test (pk int primary key)"
|
||||
dolt sql -q "insert into test values (999)"
|
||||
dolt add test
|
||||
dolt commit -m "insert initial value into test"
|
||||
cd -
|
||||
|
||||
dolt profile add --use-db defaultDB default
|
||||
run dolt sql -q "select * from test"
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "999" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: no profile used when none specified and no default set" {
|
||||
cd defaultDB
|
||||
dolt sql -q "insert into table1 values (999)"
|
||||
dolt add table1
|
||||
dolt commit -m "insert initial value into table1"
|
||||
cd -
|
||||
|
||||
dolt profile add --use-db defaultDB defaultTest
|
||||
run dolt sql -q "select * from table1"
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ ! "$output" =~ "999" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: correct default profile used when none specified" {
|
||||
cd defaultDB
|
||||
dolt sql -q "create table test (pk int primary key)"
|
||||
dolt sql -q "insert into test values (999)"
|
||||
dolt add test
|
||||
dolt commit -m "insert initial value into test"
|
||||
cd -
|
||||
|
||||
dolt profile add --use-db defaultDB default
|
||||
dolt profile add --use-db altDB altTest
|
||||
run dolt sql -q "select * from test"
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "999" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: commands that don't support global args work with a default profile set" {
|
||||
cd altDB
|
||||
dolt sql -q "create table test (pk int primary key)"
|
||||
dolt sql -q "insert into test values (999)"
|
||||
dolt add test
|
||||
dolt commit -m "insert initial value into test"
|
||||
dolt profile add --use-db defaultDB default
|
||||
|
||||
run dolt log
|
||||
[ "$status" -eq 0 ] || false
|
||||
[[ "$output" =~ "insert initial value into test" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: profile with user but not password waits for password prompt" {
|
||||
dolt profile add --use-db defaultDB -u "steph" defaultTest
|
||||
run dolt --profile defaultTest sql -q "select * from table1" <<< ""
|
||||
[ "$status" -eq 1 ] || false
|
||||
[[ "$output" =~ "Enter password:" ]] || false
|
||||
}
|
||||
|
||||
@test "profile: profile with user and empty password doesn't wait for password prompt" {
|
||||
dolt profile add --use-db defaultDB -u "steph" -p "" defaultTest
|
||||
run dolt --profile defaultTest sql -q "show tables"
|
||||
[ "$status" -eq 0 ] || false
|
||||
}
|
||||
Reference in New Issue
Block a user