diff --git a/src/Application.cc b/src/Application.cc index 95d1e2a55..38facd1c4 100644 --- a/src/Application.cc +++ b/src/Application.cc @@ -19,7 +19,9 @@ #include #include +#include #include +#include #include #include @@ -222,24 +224,50 @@ bool Application::LoadConfig(const std::string &_config) return false; } + std::string configFull = _config; + + // Check if the passed in config file exists. + // (If the default config path doesn't exist yet, it's expected behavior. + // It will be created the first time the user presses "Save configuration".) + if (!common::exists(configFull) && (configFull != this->DefaultConfigPath())) + { + // If not, then check environment variable + std::string configPathEnv; + common::env("GZ_GUI_RESOURCE_PATH", configPathEnv); + + if (!configPathEnv.empty()) + { + std::vector parentPaths = common::Split(configPathEnv, ':'); + for (auto parentPath : parentPaths) + { + std::string tempPath = common::joinPaths(parentPath, configFull); + if (common::exists(tempPath)) + { + configFull = tempPath; + break; + } + } + } + } + // Use tinyxml to read config tinyxml2::XMLDocument doc; - auto success = !doc.LoadFile(_config.c_str()); + auto success = !doc.LoadFile(configFull.c_str()); if (!success) { // We do not show an error message if the default config path doesn't exist // yet. It's expected behavior, it will be created the first time the user // presses "Save configuration". - if (_config != this->DefaultConfigPath()) + if (configFull != this->DefaultConfigPath()) { - ignerr << "Failed to load file [" << _config << "]: XMLError" + ignerr << "Failed to load file [" << configFull << "]: XMLError" << std::endl; } return false; } - ignmsg << "Loading config [" << _config << "]" << std::endl; + ignmsg << "Loading config [" << configFull << "]" << std::endl; // Clear all previous plugins auto plugins = this->dataPtr->mainWin->findChildren(); diff --git a/src/Application_TEST.cc b/src/Application_TEST.cc index 5d575a3c9..9ca02cc90 100644 --- a/src/Application_TEST.cc +++ b/src/Application_TEST.cc @@ -172,6 +172,28 @@ TEST(ApplicationTest, IGN_UTILS_TEST_DISABLED_ON_WIN32(LoadConfig)) auto testSourcePath = std::string(PROJECT_SOURCE_PATH) + "/test/"; EXPECT_TRUE(app.LoadConfig(testSourcePath + "config/test.config")); } + + // Test environment variable and relative path + { + // Environment variable not set + Application app(g_argc, g_argv); + EXPECT_FALSE(app.LoadConfig("ignore.config")); + + // Invalid path + setenv("GZ_GUI_RESOURCE_PATH", "invalidPath", 1); + EXPECT_FALSE(app.LoadConfig("ignore.config")); + + // Valid path + setenv("GZ_GUI_RESOURCE_PATH", + (std::string(PROJECT_SOURCE_PATH) + "/test/config").c_str(), 1); + EXPECT_TRUE(app.LoadConfig("ignore.config")); + + // Multiple paths, one valid + setenv("GZ_GUI_RESOURCE_PATH", + ("banana:" + std::string(PROJECT_SOURCE_PATH) + "/test/config" + + ":orange").c_str(), 1); + EXPECT_TRUE(app.LoadConfig("ignore.config")); + } } ////////////////////////////////////////////////// diff --git a/src/cmd/cmdgui.rb.in b/src/cmd/cmdgui.rb.in index 2b766662f..5ecdd4260 100644 --- a/src/cmd/cmdgui.rb.in +++ b/src/cmd/cmdgui.rb.in @@ -52,7 +52,10 @@ COMMANDS = { 'gui' => " The default verbosity is 1, use -v without\n"\ " arguments for level 3.\n"\ "\n" + - COMMON_OPTIONS, + COMMON_OPTIONS + "\n\n" + + "Environment variables: \n"\ + " GZ_GUI_RESOURCE_PATH Colon separated paths used to locate GUI \n"\ + " resources such as configuration files. \n"\ } # diff --git a/tutorials/07_config.md b/tutorials/07_config.md index 240ac6786..8178cbda6 100644 --- a/tutorials/07_config.md +++ b/tutorials/07_config.md @@ -15,9 +15,19 @@ By default, Ignition GUI will load the config file at Configuration files can also be loaded from the command line or through the C++ API. -From the command line, use the `--config` / `-c` option, for example: +From the command line, use the `--config` / `-c` option. +For example, you can specify an absolute path: -`ign gui -c path/to/example.config` +`ign gui -c /absolute/path/to/example.config` + +Or a path relative to the current working directory: + +`ign gui -c relative/path/to/example.config` + +Or a path relative to a custom directory, which you can specify by setting the +environment variable `GZ_GUI_RESOURCE_PATH`, like so: + +`GZ_GUI_RESOURCE_PATH=/absolute/path/to/ ign gui --config example.config` From the C++ API, pass the file path to [Application::LoadConfig](https://ignitionrobotics.org/api/gui/3.0/classignition_1_1gui_1_1Application.html#a03c4c3a1b1e58cc4bff05658f21fff17).