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

User directory config files #534

Merged
merged 10 commits into from
May 1, 2017
Merged

User directory config files #534

merged 10 commits into from
May 1, 2017

Conversation

JeroMiya
Copy link
Contributor

@JeroMiya JeroMiya commented Apr 6, 2017

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.

std::string configSubpath = "config";

#if defined(OSVR_LINUX)
// There's currently no great location for storing log files in the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can delete the first paragraph of the comment and update the second para to reflect XDG_CONFIG_HOME.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

// 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");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_DIRS defines the preference-ordered set of base directories to search for configuration files in addition to the $XDG_CONFIG_HOME base directory. The directories in $XDG_CONFIG_DIRS should be separated with a colon :.

If $XDG_CONFIG_DIRS is either not set or empty, a value equal to /etc/xdg should 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_HOME is considered more important than any of the base directories defined by $XDG_CONFIG_DIRS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget #include <string>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

namespace osvr {
namespace server {

ServerPtr configureServerFromString(std::string const &json) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use the more succinct C++11 loop: for (const auto& configName : configName) { log->error() << configName; }.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code was removed - the config file attempts are logged elsewhere so this was redundant.

@@ -38,130 +38,30 @@
#include <exception>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/cache/config/g throughout, I think.


names.push_back(userConfig.string());
names.push_back(configFileName);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/xdg if $XDG_CONFIG_DIRS is not set or empty.
  • /etc/osvr_server_config.json for old-school paths
  • /usr/local/etc/osvr_server_config.json for 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.json for old-school paths
  • /usr/local/etc/osvr_server_config.json for old-school paths

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to new issue: #537

@@ -47,23 +47,6 @@

namespace osvr {
namespace server {
namespace detail {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, wow! This is ancient. I thought we killed it ages ago.


for (const auto name : configNames) {
std::ifstream config(name);
if (config.good()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log which file you're running with so it's easier to troubleshoot later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's logged in configureServerFromFile, but I adjusted the log there to be more consistent with the others in wording.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we even need to check the member good() or can we just use the explicit bool conversion operator?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

operator bool would return true at EOF while good() would return false. So calling good() avoids reading an empty file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alrighty then, things I didn't know about iostreams.

Copy link
Contributor

@godbyk godbyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple minor quibbles, but otherwise I think it looks good!

@@ -92,7 +83,7 @@ int main(int argc, char *argv[]) {
}

if (values.count("help")) {
std::cout << optionsVisible << std::endl;
log->info() << optionsVisible << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -0,0 +1,73 @@
// Internal Includes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add standard copyright header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

date and indentation don't match but...

@@ -0,0 +1,45 @@
/** @file
@brief Auto-generated configuration header - do not edit!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This header file isn't auto-generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the comment

Copy link
Contributor

@godbyk godbyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Looks good to me!

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 "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the word "files" here a typo?

Copy link
Member

@rpavlik rpavlik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor itty bitty nitpicks.

<< "' not found. Using empty configuration.";
configPath = boost::none;
server = osvr::server::configureServerFromFirstFileInList(configPaths);
if (!server) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this 2015 code?

@@ -0,0 +1,73 @@
// Internal Includes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

date and indentation don't match but...

return nullptr;
}

std::stringstream sstr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming this is how you load a whole file in a single gulp?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we even need to check the member good() or can we just use the explicit bool conversion operator?

@rpavlik
Copy link
Member

rpavlik commented May 1, 2017

👍

@JeroMiya JeroMiya merged commit ef4b572 into master May 1, 2017
@JeroMiya JeroMiya deleted the user-config branch May 1, 2017 20:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants