Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reworked config #350

Merged
merged 15 commits into from
Jun 6, 2024
150 changes: 100 additions & 50 deletions cmd/doltgres/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,16 @@ const (
stdErrParam = "stderr"
stdOutAndErrParam = "out-and-err"
configParam = "config"
dataDirParam = "data-dir"
dataDirParam = "data-dir"
defaultCfgFile = "config.yaml"

versionFlag = "version"
configHelpFlag = "config-help"

dataDirHelpText = "Path to the directory where doltgres databases are stored. If not provided, the value in " +
"config.yaml will be used. If that's not provided either, the value of the DOLTGRES_DATA_DIR environment variable " +
"will be used if set, otherwise $HOME/doltgres/databases will be used. The directory will be created if it doesn't " +
"exist."
)

func parseArgs() (flags map[string]*bool, params map[string]*string) {
Expand All @@ -69,13 +75,13 @@ func parseArgs() (flags map[string]*bool, params map[string]*string) {
flags = make(map[string]*bool)
params = make(map[string]*string)

params[configParam] = flag.String(configParam, "", "Path to the config file. If not provided, ./config.yaml will be used if it exists.")
params[dataDirParam] = flag.String(dataDirParam, "", dataDirHelpText)
params[chdirParam] = flag.String(chdirParam, "", "set the working directory for doltgres")
params[stdInParam] = flag.String(stdInParam, "", "file to use as stdin")
params[stdOutParam] = flag.String(stdOutParam, "", "file to use as stdout")
params[stdErrParam] = flag.String(stdErrParam, "", "file to use as stderr")
params[stdOutAndErrParam] = flag.String(stdOutAndErrParam, "", "file to use as stdout and stderr")
params[configParam] = flag.String(configParam, "config.yaml", "path to the config file")
params[dataDirParam] = flag.String(dataDirParam, "", "path to the directory where doltgres databases are stored")

flags[versionFlag] = flag.Bool(versionFlag, false, "print the version")
flags[configHelpFlag] = flag.Bool(configHelpFlag, false, "print the config file help")
Expand All @@ -99,8 +105,7 @@ func main() {

err := redirectStdio(params)
if err != nil {
cli.PrintErrln(err.Error())
os.Exit(1)
handleErrAndExitCode(err)
}

restoreIO := cli.InitIO()
Expand All @@ -109,73 +114,118 @@ func main() {
warnIfMaxFilesTooLow()

fs := filesys.LocalFS
// dEnv will be reloaded at server start to point to the data dir on the server config
dEnv := env.Load(ctx, env.GetCurrentUserHomeDir, fs, doltdb.LocalDirDoltDB, server.Version)

err = configureDataDir(fs, params)
cfg, loadedFromDisk, err := loadServerConfig(params, fs)
if err != nil {
cli.PrintErrln(err.Error())
os.Exit(1)
}

overrides := map[string]string{
servercfg.OverrideDataDirKey: *params[dataDirParam],
handleErrAndExitCode(err)
}

cfg, err := servercfg.ReadConfigFromYamlFile(fs, *params[configParam], overrides)
err = setupDataDir(params, cfg, loadedFromDisk, fs)
if err != nil {
cli.PrintErrln(err.Error())
os.Exit(1)
handleErrAndExitCode(err)
}


// TODO: override other aspects of cfg with command line params

err = runServer(ctx, dEnv, cfg)
handleErrAndExitCode(err)
}

func handleErrAndExitCode(err error) {
if err != nil {
cli.PrintErrln(err.Error())
os.Exit(1)
}

os.Exit(0)
}

// configureDataDir sets the --data-dir argument as appropriate if it isn't specified
func configureDataDir(fs filesys.Filesys, params map[string]*string) error {
_, ok := paramVal(params, dataDirParam)
if ok {
return nil
// setupDataDir sets the appropriate data dir for the config given based on parameters and env, and creates the data
// dir as necessary.
func setupDataDir(params map[string]*string, cfg *servercfg.DoltgresConfig, cfgLoadedFromDisk bool, fs filesys.Filesys) error {
dataDir, dataDirType, err := getDataDirFromParams(params)
if err != nil {
return err
}

// This logic chooses a data dir in the following order of preference:
// 1) explicit flag
// 2) env var if no config file, or if the config file doesn't have a data dir
// 3) default value if no config file, or if the config file doesn't have a data dir
// 4) the value in the config file
if dataDirType == dataDirExplicitParam || !cfgLoadedFromDisk || cfg.DataDirStr == nil {
cfg.DataDirStr = &dataDir
}

// We should use the directory as pointed to by "DOLTGRES_DATA_DIR", if has been set, otherwise we'll use the default
var dbDir string
if envDir := os.Getenv(server.DOLTGRES_DATA_DIR); len(envDir) > 0 {
dbDir = envDir
exists, isDir := fs.Exists(dbDir)
if !exists {
if err := fs.MkDirs(dbDir); err != nil {
return fmt.Errorf("failed to make dir '%s': %w", dbDir, err)
}
} else if !isDir {
return fmt.Errorf("Attempted to use the directory `%s` as the DoltgreSQL database directory, "+
"however the preceding is a file and not a directory. Please change the environment variable `%s` so "+
"that it points to a directory.", dbDir, server.DOLTGRES_DATA_DIR)
dataDirPath := cfg.DataDir()
dataDirExists, isDir := fs.Exists(dataDirPath)
if !dataDirExists {
if err := fs.MkDirs(dataDirPath); err != nil {
return fmt.Errorf("failed to make dir '%s': %w", dataDirPath, err)
}
} else {
homeDir, err := env.GetCurrentUserHomeDir()
if err != nil {
return fmt.Errorf("failed to get current user's home directory: %w", err)
} else if !isDir {
return fmt.Errorf("cannot use file %s as doltgres data directory", dataDirPath)
}

return nil
}

// loadServerConfig loads server configuration in the following order:
// 1. If the --config flag is provided, loads the config from the file at the path provided, or returns an errors if it cannot.
// 2. If the default config file config.yaml exists, attempts to load it, but doesn't return an error if it doesn't exist.
// 3. If neither of the above are successful, returns the default config server config.
// The second result param is a boolean indicating whether a file was loaded, since we vary later initialization
// behavior depending on whether we loaded a config file from disk.
func loadServerConfig(params map[string]*string, fs filesys.Filesys) (*servercfg.DoltgresConfig, bool, error) {
configFilePath, configFilePathSpecified := paramVal(params, configParam)

if configFilePathSpecified {
cfgPathExists, isDir := fs.Exists(configFilePath)
if !cfgPathExists {
return nil, false, fmt.Errorf("config file not found at %s", configFilePath)
} else if isDir {
return nil, false, fmt.Errorf("cannot use directory %s for config file", configFilePath)
}

dbDir = filepath.Join(homeDir, server.DOLTGRES_DATA_DIR_DEFAULT)
if exists, isDir := fs.Exists(dbDir); !exists {
if err = fs.MkDirs(dbDir); err != nil {
return fmt.Errorf("failed to make dir '%s': %w", dbDir, err)
}
} else if !isDir {
return fmt.Errorf("Attempted to use the directory `%s` as the DoltgreSQL database directory, "+
"however the preceding is a file and not a directory. Please change the environment variable `%s` so "+
"that it points to a directory.", dbDir, server.DOLTGRES_DATA_DIR)
cfg, err := servercfg.ReadConfigFromYamlFile(fs, configFilePath)
return cfg, true, err
} else {
cfgPathExists, isDir := fs.Exists(defaultCfgFile)
if cfgPathExists && !isDir {
cfg, err := servercfg.ReadConfigFromYamlFile(fs, defaultCfgFile)
return cfg, true, err
}
}

params[dataDirParam] = &dbDir
return nil
return servercfg.DefaultServerConfig(), false, nil
}

type dataDirType byte
const (
dataDirExplicitParam dataDirType = iota
dataDirEnv
dataDirDefault
)

// getDataDirFromParams returns the dataDir to be used by the server, along with whether it was explicitly set.
func getDataDirFromParams(params map[string]*string) (string, dataDirType, error) {
if dataDir, ok := paramVal(params, dataDirParam); ok {
return dataDir, dataDirExplicitParam, nil
}

if envDir := os.Getenv(servercfg.DOLTGRES_DATA_DIR); len(envDir) > 0 {
return envDir, dataDirEnv, nil
} else {
homeDir, err := env.GetCurrentUserHomeDir()
if err != nil {
return "", dataDirDefault, fmt.Errorf("failed to get current user's home directory: %w", err)
}

dbDir := filepath.Join(homeDir, servercfg.DOLTGRES_DATA_DIR_DEFAULT)
return dbDir, dataDirDefault, nil
}
}

// runServer launches a server on the env given and waits for it to finish
Expand Down
8 changes: 1 addition & 7 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,6 @@ import (

const (
Version = "0.8.0"

// DOLTGRES_DATA_DIR is an environment variable that defines the location of DoltgreSQL databases
DOLTGRES_DATA_DIR = "DOLTGRES_DATA_DIR"
// DOLTGRES_DATA_DIR_DEFAULT is the portion to append to the user's home directory if DOLTGRES_DATA_DIR has not been specified
DOLTGRES_DATA_DIR_DEFAULT = "doltgres/databases"

DefUserName = "postres"
DefUserEmail = "postgres@somewhere.com"
DoltgresDir = "doltgres"
Expand Down Expand Up @@ -140,7 +134,7 @@ func runServer(ctx context.Context, cfg *servercfg.DoltgresConfig, dEnv *env.Dol
// enforce the creation of a Doltgres database/directory, which would create a name conflict with the file
return nil, fmt.Errorf("Attempted to create the default `doltgres` database at `%s`, but a file with "+
"the same name was found. Either remove the file, change the directory using the `--data-dir` argument, "+
"or change the environment variable `%s` so that it points to a different directory.", workingDir, DOLTGRES_DATA_DIR)
"or change the environment variable `%s` so that it points to a different directory.", workingDir, servercfg.DOLTGRES_DATA_DIR)
}

controller := svcs.NewController()
Expand Down
Loading
Loading