Repository navigation
User directory config files - #534
Conversation
| std::string configSubpath = "config"; | ||
|
|
||
| #if defined(OSVR_LINUX) | ||
| // There's currently no great location for storing log files in the |
There was a problem hiding this comment.
We can delete the first paragraph of the comment and update the second para to reflect XDG_CONFIG_HOME.
| // specific non-essential data files should be stored. If | ||
| // $XDG_CACHE_HOME is either not set or empty, a default equal to | ||
| // $HOME/.cache should be used. | ||
| auto xdg_cache_dir = getEnvironmentVariable("XDG_CONFIG_HOME"); |
There was a problem hiding this comment.
On Linux, if you're searching for an existing configuration file (as opposed to determining where to write a new one), then you will want to check the XDG_CONFIG_DIRS paths as well. From the XDG Base Directory Specification:
$XDG_CONFIG_DIRSdefines the preference-ordered set of base directories to search for configuration files in addition to the$XDG_CONFIG_HOMEbase directory. The directories in$XDG_CONFIG_DIRSshould be separated with a colon:.If
$XDG_CONFIG_DIRSis either not set or empty, a value equal to/etc/xdgshould be used.The order of base directories denotes their importance; the first directory listed is the most important. When the same information is defined in multiple places the information defined relative to the more important base directory takes precedent. [...] The base directory defined by
$XDG_CONFIG_HOMEis considered more important than any of the base directories defined by$XDG_CONFIG_DIRS.
There was a problem hiding this comment.
I'm going to put this as a TODO for now. The function this is in currently only returns one directory, and this change would require it to return multiple directories.
| log->error() << "'" << configName << "' is special file."; | ||
| return -1; | ||
| } | ||
| log->error() << "Could not find specified config file."; |
There was a problem hiding this comment.
The error message could be more specific (or removed if configureServerFromFirstFileInList() prints a better one). Possible failure cases: file not found, file couldn't be opened, file couldn't be prased, etc.
|
|
||
| // Standard includes | ||
| #include <vector> | ||
|
|
There was a problem hiding this comment.
Don't forget #include <string>.
| namespace osvr { | ||
| namespace server { | ||
|
|
||
| ServerPtr configureServerFromString(std::string const &json) { |
There was a problem hiding this comment.
Thanks for moving this to the .cpp file. I meant to do that when I was originally refactoring and it slipped my mind later.
| } | ||
| log->error() << "Could not open config file!"; | ||
| log->error() << "Attempted the following files:"; | ||
| for (auto i = configNames.begin(); i != configNames.end(); i++) { |
There was a problem hiding this comment.
You could use the more succinct C++11 loop: for (const auto& configName : configName) { log->error() << configName; }.
There was a problem hiding this comment.
This code was removed - the config file attempts are logged elsewhere so this was redundant.
| #include <iostream> | ||
| #include <sstream> | ||
| #include <vector> | ||
|
|
There was a problem hiding this comment.
Need #include <string>. And it looks like you can ditch iostream and fstream and exception (move 'em to the .cpp file). Same with the Log headers above.
| #if defined(OSVR_LINUX) | ||
| // $XDG_CONFIG_HOME defines the base directory relative to which user | ||
| // specific non-essential data files should be stored. If | ||
| // $XDG_CACHE_HOME is either not set or empty, a default equal to |
There was a problem hiding this comment.
s/XDG_CACHE_HOME/XDG_CONFIG_HOME/
| // $XDG_CONFIG_HOME defines the base directory relative to which user | ||
| // specific non-essential data files should be stored. If | ||
| // $XDG_CACHE_HOME is either not set or empty, a default equal to | ||
| // $HOME/.cache should be used. |
There was a problem hiding this comment.
s/cache/config/g throughout, I think.
|
|
||
| names.push_back(userConfig.string()); | ||
| names.push_back(configFileName); | ||
|
|
There was a problem hiding this comment.
There are more places worth checking, too.
On Linux:
$XDG_CONFIG_HOME/osvr/osvr_server_config.json- For each colon-separated dir in
$XDG_CONFIG_DIRS:$prefix/osvr/osvr_server_config.json /etc/xdgif$XDG_CONFIG_DIRSis not set or empty./etc/osvr_server_config.jsonfor old-school paths/usr/local/etc/osvr_server_config.jsonfor old-school paths
On macOS:
$HOME/Library/Application Support/OSVR/config/osvr_server_config.json/Library/Application Support/OSVR/config/osvr_server_config.json- wherever brew installs it by default (I think
/usr/local/Cellar/osvr-core/bin/osvr_server_config.json, maybe) /etc/osvr_server_config.jsonfor old-school paths/usr/local/etc/osvr_server_config.jsonfor old-school paths
|
|
||
| namespace osvr { | ||
| namespace server { | ||
| namespace detail { |
There was a problem hiding this comment.
Oh, wow! This is ancient. I thought we killed it ages ago.
|
|
||
| for (const auto name : configNames) { | ||
| std::ifstream config(name); | ||
| if (config.good()) { |
There was a problem hiding this comment.
Log which file you're running with so it's easier to troubleshoot later.
There was a problem hiding this comment.
It's logged in configureServerFromFile, but I adjusted the log there to be more consistent with the others in wording.
There was a problem hiding this comment.
do we even need to check the member good() or can we just use the explicit bool conversion operator?
There was a problem hiding this comment.
operator bool would return true at EOF while good() would return false. So calling good() avoids reading an empty file.
There was a problem hiding this comment.
alrighty then, things I didn't know about iostreams.
godbyk
left a comment
There was a problem hiding this comment.
Just a couple minor quibbles, but otherwise I think it looks good!
|
|
||
| if (values.count("help")) { | ||
| std::cout << optionsVisible << std::endl; | ||
| log->info() << optionsVisible << std::endl; |
There was a problem hiding this comment.
In this particular case, we should use std::cout instead of a logger because we don't want the output lines prefixed with timestamps, etc.
| @@ -0,0 +1,73 @@ | |||
| // Internal Includes | |||
There was a problem hiding this comment.
Add standard copyright header.
There was a problem hiding this comment.
date and indentation don't match but...
| @@ -0,0 +1,45 @@ | |||
| /** @file | |||
| @brief Auto-generated configuration header - do not edit! | |||
There was a problem hiding this comment.
This header file isn't auto-generated.
There was a problem hiding this comment.
updated the comment
| log->info() << "Using config file " << configFileArgument << " from command line argument."; | ||
| configPaths = { configFileArgument }; | ||
| } else { | ||
| log->info() << "Using default config files - pass a filename on the command " |
There was a problem hiding this comment.
is the word "files" here a typo?
| << "' not found. Using empty configuration."; | ||
| configPath = boost::none; | ||
| server = osvr::server::configureServerFromFirstFileInList(configPaths); | ||
| if (!server) { |
There was a problem hiding this comment.
you've got trailing spaces - did you clang format your changes?
| if (!server) { | ||
| // only attempt to load the empty config if no arguments are passed. | ||
| if (!values.count("config")) { | ||
| log->info() << "Could not find a valid config file. Using default config object."; |
There was a problem hiding this comment.
Is this maybe better phrased "could not find config file with default name" or something like that? The user seeing this message wouldn't have passed a config file, so they might be confused as to why they're seeing this.
| <http://sensics.com/osvr> | ||
| */ | ||
|
|
||
| // Copyright 2015 Sensics, Inc. |
| @@ -0,0 +1,73 @@ | |||
| // Internal Includes | |||
There was a problem hiding this comment.
date and indentation don't match but...
| return nullptr; | ||
| } | ||
|
|
||
| std::stringstream sstr; |
There was a problem hiding this comment.
I'm assuming this is how you load a whole file in a single gulp?
There was a problem hiding this comment.
@rpavlik Yeah, this just loads the whole file into a string. It's the best way I could find to do it.
|
|
||
| for (const auto name : configNames) { | ||
| std::ifstream config(name); | ||
| if (config.good()) { |
There was a problem hiding this comment.
do we even need to check the member good() or can we just use the explicit bool conversion operator?
|
👍 |
Do not merge yet. Please merge this PR first:
#529
Then I'll rebase this on those changes.
This pull request includes and supersedes this one:
#265
This adds search-paths behavior for the osvr config file, including prioritizing a user-specific configuration if present, before falling back to the current CWD behavior.