Compare commits

...

1 Commits

Author SHA1 Message Date
Bart
f95f7889f9 refactor: Search config directories over a candidate list
Config::setup searched the working directory, the XDG config directory
and the system config directory with a do/while(false) block and breaks,
trying both file names in each.

Replace it with a list of `Candidate` values, each naming a config
directory and its data directory, and a loop that takes the first
holding a config file. Add a docstring for the search order.

The directories chosen and the file reported are unchanged. The last
candidate is now also checked under the legacy name, which the old code
assigned without checking, so one more filesystem check runs when
nothing is found.
2026-10-02 21:19:48 +00:00
2 changed files with 67 additions and 46 deletions

View File

@@ -330,8 +330,21 @@ public:
public:
Config();
/* Be very careful to make sure these bool params
are in the right order. */
/**
* Set up the configuration and determine the config and data directories.
*
* When no config file is named, searches the working directory, then the XDG
* config directory when HOME is set, then the system config directory, and
* takes the first holding a config file under either name. The system config
* directory is the default when none does.
*
* Be very careful to make sure these bool params are in the right order.
*
* @param strConf Path of the config file, or empty to search for it.
* @param bQuiet Whether to minimize logging verbosity.
* @param bSilent Whether to write no console output after startup.
* @param bStandalone Whether to operate in stand-alone mode.
*/
void
setup(std::string const& strConf, bool bQuiet, bool bSilent, bool bStandalone);

View File

@@ -43,6 +43,7 @@
#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <thread>
#include <type_traits>
@@ -319,59 +320,66 @@ Config::setup(std::string const& strConf, bool bQuiet, bool bSilent, bool bStand
}
else
{
do
// A config directory, paired with its data directory.
struct Candidate
{
// Check if either of the config files exist in the current working
// directory, in which case the databases will be stored in a
// subdirectory.
configDir = std::filesystem::current_path();
dataDir = configDir / kDatabaseDirName;
configFile_ = configDir / kConfigFileName;
if (std::filesystem::exists(configFile_))
break;
configFile_ = configDir / kConfigLegacyName;
if (std::filesystem::exists(configFile_))
break;
std::filesystem::path configDir;
std::filesystem::path dataDir;
};
// Check if the home directory is set, and optionally the XDG config
// and/or data directories, as the config may be there. See
// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html.
auto const strHome = getEnvVar("HOME");
if (!strHome.empty())
// The candidates to search, in order.
std::vector<Candidate> candidates;
candidates.reserve(3);
// The current working directory, with the databases in a subdirectory.
auto const cwd = std::filesystem::current_path();
candidates.emplace_back(cwd, cwd / kDatabaseDirName);
// The XDG config and data directories, which only apply when the home
// directory is set. See
// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html.
if (auto const strHome = getEnvVar("HOME"); !strHome.empty())
{
auto strXdgConfigHome = getEnvVar("XDG_CONFIG_HOME");
if (strXdgConfigHome.empty())
{
auto strXdgConfigHome = getEnvVar("XDG_CONFIG_HOME");
auto strXdgDataHome = getEnvVar("XDG_DATA_HOME");
if (strXdgConfigHome.empty())
{
// $XDG_CONFIG_HOME was not set, use default based on $HOME.
strXdgConfigHome = strHome + "/.config";
}
if (strXdgDataHome.empty())
{
// $XDG_DATA_HOME was not set, use default based on $HOME.
strXdgDataHome = strHome + "/.local/share";
}
// $XDG_CONFIG_HOME was not set, use default based on $HOME.
strXdgConfigHome = strHome + "/.config";
}
auto strXdgDataHome = getEnvVar("XDG_DATA_HOME");
if (strXdgDataHome.empty())
{
// $XDG_DATA_HOME was not set, use default based on $HOME.
strXdgDataHome = strHome + "/.local/share";
}
candidates.emplace_back(
strXdgConfigHome + "/" + systemName(), strXdgDataHome + "/" + systemName());
}
// Check if either of the config files exist in the XDG config
// dir.
dataDir = strXdgDataHome + "/" + systemName();
configDir = strXdgConfigHome + "/" + systemName();
configFile_ = configDir / kConfigFileName;
if (std::filesystem::exists(configFile_))
break;
configFile_ = configDir / kConfigLegacyName;
// The system config directory, as a last resort.
candidates.emplace_back("/etc/" + systemName(), "/var/lib/" + systemName());
// Take the first candidate holding a config file under either name.
// When none does, the last candidate's values stand.
for (auto const& candidate : candidates)
{
configDir = candidate.configDir;
dataDir = candidate.dataDir;
bool found = false;
for (std::string_view const fileName : {kConfigFileName, kConfigLegacyName})
{
configFile_ = configDir / fileName;
if (std::filesystem::exists(configFile_))
{
found = true;
break;
}
}
// As a last resort, check the system config directory.
dataDir = "/var/lib/" + systemName();
configDir = "/etc/" + systemName();
configFile_ = configDir / kConfigFileName;
if (std::filesystem::exists(configFile_))
if (found)
break;
configFile_ = configDir / kConfigLegacyName;
} while (false);
}
}
// Update default values