configuration: support multiple configuration files

This commit is contained in:
Andrzej Rybczak
2014-11-15 15:07:49 +01:00
parent 8745523170
commit 38d9f811de
8 changed files with 61 additions and 18 deletions

View File

@@ -18,6 +18,7 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <algorithm>
#include <boost/filesystem/operations.hpp>
#include <boost/program_options.hpp>
#include <iostream>
@@ -27,6 +28,7 @@
#include "config.h"
#include "mpdpp.h"
#include "settings.h"
#include "utility/string.h"
namespace po = boost::program_options;
@@ -37,23 +39,45 @@ namespace {
const char *env_home;
std::string xdg_config_home()
{
std::string result;
const char *env_xdg_config_home = getenv("XDG_CONFIG_HOME");
if (env_xdg_config_home == nullptr)
result = "~/.config/ncmpcpp/";
else
{
result = env_xdg_config_home;
if (!result.empty() && result.back() != '/')
result += "/";
}
return result;
}
}
void expand_home(std::string &path)
{
assert(env_home != nullptr);
if (!path.empty() && path[0] == '~')
path.replace(0, 1, env_home);
}
bool configure(int argc, char **argv)
{
std::string bindings_path, config_path;
const std::vector<std::string> default_config_paths = {
"~/.ncmpcpp/config",
xdg_config_home() + "config"
};
std::string bindings_path;
std::vector<std::string> config_paths;
po::options_description options("Options");
options.add_options()
("host,h", po::value<std::string>()->default_value("localhost"), "connect to server at host")
("port,p", po::value<int>()->default_value(6600), "connect to server at port")
("config,c", po::value<std::string>(&config_path)->default_value("~/.ncmpcpp/config"), "specify configuration file")
("config,c", po::value<std::vector<std::string>>(&config_paths)->default_value(default_config_paths, join<std::string>(default_config_paths, " AND ")), "specify configuration file(s)")
("bindings,b", po::value<std::string>(&bindings_path)->default_value("~/.ncmpcpp/bindings"), "specify bindings file")
("screen,s", po::value<std::string>(), "specify initial screen")
("slave-screen,S", po::value<std::string>(), "specify initial slave screen")
@@ -120,7 +144,6 @@ bool configure(int argc, char **argv)
}
po::notify(vm);
// get home directory
env_home = getenv("HOME");
if (env_home == nullptr)
@@ -130,8 +153,8 @@ bool configure(int argc, char **argv)
}
// read configuration
expand_home(config_path);
if (Config.read(config_path) == false)
std::for_each(config_paths.begin(), config_paths.end(), expand_home);
if (Config.read(config_paths) == false)
exit(1);
// if bindings file was not specified, use the one from main directory.

View File

@@ -173,7 +173,7 @@ option_parser::worker buffer(NC::Buffer &arg, ValueT &&value, TransformT &&map)
}
bool Configuration::read(const std::string &config_path)
bool Configuration::read(const std::vector<std::string> &config_paths)
{
std::string mpd_host;
unsigned mpd_port;
@@ -653,8 +653,16 @@ bool Configuration::read(const std::string &config_path)
active_window_border, NC::Border::Red
));
std::ifstream f(config_path);
return p.run(f);
return std::all_of(
config_paths.begin(),
config_paths.end(),
[&p](const std::string &config_path) {
std::ifstream f(config_path);
if (f.is_open())
std::clog << "Reading configuration from " << config_path << "...\n";
return p.run(f);
}
);
}
/* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab : */

View File

@@ -53,7 +53,7 @@ struct Configuration
: playlist_disable_highlight_delay(0), visualizer_sync_interval(0)
{ }
bool read(const std::string &config_path);
bool read(const std::vector<std::string> &config_paths);
std::string ncmpcpp_directory;
std::string lyrics_directory;

View File

@@ -106,8 +106,18 @@ struct option_parser
m_defined = true;
}
bool defined() const { return m_defined; }
void run_default() const { m_default(); }
bool defined() const
{
return m_defined;
}
void run_default()
{
if (m_defined)
throw std::runtime_error("option already defined");
m_default();
m_defined = true;
}
private:
bool m_defined;

View File

@@ -32,8 +32,8 @@ template <size_t N> size_t const_strlen(const char (&)[N]) {
}
// it's present in boost for std::string, but we want more general version.
template <typename CollectionT, typename StringT>
StringT join(CollectionT &&collection, StringT &&separator)
template <typename StringT, typename CollectionT>
StringT join(const CollectionT &collection, const StringT &separator)
{
StringT result;
auto first = std::begin(collection), last = std::end(collection);