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

1
NEWS
View File

@@ -9,6 +9,7 @@ ncmpcpp-0.7 (????-??-??)
* List filtering has been removed due to the major part of its functionality overlapping with find forward/backward. * List filtering has been removed due to the major part of its functionality overlapping with find forward/backward.
* Find backward/forward function is now incremental. * Find backward/forward function is now incremental.
* Support for 256 colors and customization of background colors has been added. * Support for 256 colors and customization of background colors has been added.
* Multiple configuration files via command line arguments are now accepted. In addition, by default ncmpcpp attempts to read both $HOME/.ncmpcpp/config and $XDG_CONFIG_HOME/ncmpcpp/config (in this order).
ncmpcpp-0.6.2 (????-??-??) ncmpcpp-0.6.2 (????-??-??)

View File

@@ -1,7 +1,8 @@
#################################################### ##############################################################
## this is example configuration file, copy it to ## ## This is the example configuration file. Copy it to ##
## ~/.ncmpcpp/config and set up your preferences ## ## $HOME/.ncmpcpp/config or $XDG_CONFIG_HOME/ncmpcpp/config ##
#################################################### ## and set up your preferences. ##
##############################################################
# #
##### directories ###### ##### directories ######
## ##

View File

@@ -31,7 +31,7 @@ Display help.
Display version information. Display version information.
.TP .TP
.SH "CONFIGURATION" .SH "CONFIGURATION"
When ncmpcpp starts, it tries to read user's settings from the ~/.ncmpcpp/config file. If no user's configuration is found, ncmpcpp uses its default configuration. An example configuration file containing all default values is provided with ncmpcpp and can be usually found in /usr/share/doc/ncmpcpp (exact location may depend on used distribution or configure prefix). When ncmpcpp starts, it tries to read user's settings from $HOME/.ncmpcpp/config and $XDG_CONFIG_HOME/ncmpcpp/config files. If no configuration is found, ncmpcpp uses its default configuration. An example configuration file containing all default values is provided with ncmpcpp and can be usually found in /usr/share/doc/ncmpcpp (exact location may depend on used distribution or configure prefix).
Note: Configuration option values can either be enclosed in quotation marks or not. Note: Configuration option values can either be enclosed in quotation marks or not.
- If they are enclosed, the leftmost and the rightmost quotation marks are treated as delimiters, therefore it is not necessary to escape quotation marks you use within the value itself. - If they are enclosed, the leftmost and the rightmost quotation marks are treated as delimiters, therefore it is not necessary to escape quotation marks you use within the value itself.

View File

@@ -18,6 +18,7 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/ ***************************************************************************/
#include <algorithm>
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <iostream> #include <iostream>
@@ -27,6 +28,7 @@
#include "config.h" #include "config.h"
#include "mpdpp.h" #include "mpdpp.h"
#include "settings.h" #include "settings.h"
#include "utility/string.h"
namespace po = boost::program_options; namespace po = boost::program_options;
@@ -37,23 +39,45 @@ namespace {
const char *env_home; 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) void expand_home(std::string &path)
{ {
assert(env_home != nullptr);
if (!path.empty() && path[0] == '~') if (!path.empty() && path[0] == '~')
path.replace(0, 1, env_home); path.replace(0, 1, env_home);
} }
bool configure(int argc, char **argv) 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"); po::options_description options("Options");
options.add_options() options.add_options()
("host,h", po::value<std::string>()->default_value("localhost"), "connect to server at host") ("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") ("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") ("bindings,b", po::value<std::string>(&bindings_path)->default_value("~/.ncmpcpp/bindings"), "specify bindings file")
("screen,s", po::value<std::string>(), "specify initial screen") ("screen,s", po::value<std::string>(), "specify initial screen")
("slave-screen,S", po::value<std::string>(), "specify initial slave 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); po::notify(vm);
// get home directory // get home directory
env_home = getenv("HOME"); env_home = getenv("HOME");
if (env_home == nullptr) if (env_home == nullptr)
@@ -130,8 +153,8 @@ bool configure(int argc, char **argv)
} }
// read configuration // read configuration
expand_home(config_path); std::for_each(config_paths.begin(), config_paths.end(), expand_home);
if (Config.read(config_path) == false) if (Config.read(config_paths) == false)
exit(1); exit(1);
// if bindings file was not specified, use the one from main directory. // 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; std::string mpd_host;
unsigned mpd_port; unsigned mpd_port;
@@ -653,8 +653,16 @@ bool Configuration::read(const std::string &config_path)
active_window_border, NC::Border::Red active_window_border, NC::Border::Red
)); ));
std::ifstream f(config_path); return std::all_of(
return p.run(f); 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 : */ /* 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) : 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 ncmpcpp_directory;
std::string lyrics_directory; std::string lyrics_directory;

View File

@@ -106,8 +106,18 @@ struct option_parser
m_defined = true; m_defined = true;
} }
bool defined() const { return m_defined; } bool defined() const
void run_default() const { m_default(); } {
return m_defined;
}
void run_default()
{
if (m_defined)
throw std::runtime_error("option already defined");
m_default();
m_defined = true;
}
private: private:
bool m_defined; 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. // it's present in boost for std::string, but we want more general version.
template <typename CollectionT, typename StringT> template <typename StringT, typename CollectionT>
StringT join(CollectionT &&collection, StringT &&separator) StringT join(const CollectionT &collection, const StringT &separator)
{ {
StringT result; StringT result;
auto first = std::begin(collection), last = std::end(collection); auto first = std::begin(collection), last = std::end(collection);