diff --git a/esp/platform/application_config.cpp b/esp/platform/application_config.cpp index fa4228651a8..54dd828631a 100644 --- a/esp/platform/application_config.cpp +++ b/esp/platform/application_config.cpp @@ -64,7 +64,7 @@ IPropertyTree *loadApplicationConfig(const char *application, const char* argv[] appendPTreeFromYamlFile(defaultConfig, application_dir->query().queryFilename(), true); //apply provided config to the application - Owned config = loadConfiguration(defaultConfig, argv, "esp", "ESP", nullptr, nullptr); + Owned config = loadConfiguration(defaultConfig, nullptr, argv, "esp", "ESP", nullptr, nullptr); return config.getClear(); } diff --git a/system/jlib/jptree.cpp b/system/jlib/jptree.cpp index 70d483495ad..00f166a8f0b 100644 --- a/system/jlib/jptree.cpp +++ b/system/jlib/jptree.cpp @@ -8696,13 +8696,13 @@ static void holdLoop() } #endif -static std::tuple doLoadConfiguration(IPropertyTree *componentDefault, const char * * argv, const char * componentTag, const char * envPrefix, const char * legacyFilename, IPropertyTree * (mapper)(IPropertyTree *), const char *altNameAttribute); +static std::tuple doLoadConfiguration(IPropertyTree *componentDefault, IPropertyTree *globalDefault, const char * * argv, const char * componentTag, const char * envPrefix, const char * legacyFilename, IPropertyTree * (mapper)(IPropertyTree *), const char *altNameAttribute); class CConfigUpdater : public CInterface { StringAttr absoluteConfigFilename; StringAttr configFilename; - Linked componentDefault; + Linked componentDefault, globalDefault; StringArray args; StringAttr componentTag, envPrefix, legacyFilename; IPropertyTree * (*mapper)(IPropertyTree *); @@ -8721,11 +8721,12 @@ class CConfigUpdater : public CInterface { return args.ordinality(); // NB: null terminated, so always >=1 if initialized } - void init(const char *_absoluteConfigFilename, IPropertyTree *_componentDefault, const char * * argv, const char * _componentTag, const char * _envPrefix, const char *_legacyFilename, IPropertyTree * (_mapper)(IPropertyTree *), const char *_altNameAttribute) + void init(const char *_absoluteConfigFilename, IPropertyTree *_componentDefault, IPropertyTree *_globalDefault, const char * * argv, const char * _componentTag, const char * _envPrefix, const char *_legacyFilename, IPropertyTree * (_mapper)(IPropertyTree *), const char *_altNameAttribute) { dbgassertex(!isInitialized()); absoluteConfigFilename.set(_absoluteConfigFilename); componentDefault.set(_componentDefault); + globalDefault.set(_globalDefault); componentTag.set(_componentTag); envPrefix.set(_envPrefix); legacyFilename.set(_legacyFilename); @@ -8761,7 +8762,7 @@ class CConfigUpdater : public CInterface #endif if (changed) { - auto result = doLoadConfiguration(componentDefault, args.getArray(), componentTag, envPrefix, legacyFilename, mapper, altNameAttribute); + auto result = doLoadConfiguration(componentDefault, globalDefault, args.getArray(), componentTag, envPrefix, legacyFilename, mapper, altNameAttribute); // NB: block calls to get*Config*() until callbacks notified and new swapped in CriticalBlock b(configCS); @@ -8913,10 +8914,10 @@ void CConfigUpdateHook::installOnce(ConfigUpdateFunc callbackFunc, bool callWhen } -static std::tuple doLoadConfiguration(IPropertyTree *componentDefault, const char * * argv, const char * componentTag, const char * envPrefix, const char * legacyFilename, IPropertyTree * (mapper)(IPropertyTree *), const char *altNameAttribute) +static std::tuple doLoadConfiguration(IPropertyTree *componentDefault, IPropertyTree *globalDefault, const char * * argv, const char * componentTag, const char * envPrefix, const char * legacyFilename, IPropertyTree * (mapper)(IPropertyTree *), const char *altNameAttribute) { Owned newComponentConfig = createPTreeFromIPT(componentDefault); - Owned newGlobalConfig; + Linked newGlobalConfig = globalDefault ? createPTreeFromIPT(globalDefault) : nullptr; StringBuffer absConfigFilename; const char * optConfig = nullptr; bool outputConfig = false; @@ -8979,6 +8980,7 @@ static std::tuple doLoadConfigura } absConfigFilename.append(config); + Owned configGlobal; Owned delta; if (optConfig) { @@ -8989,7 +8991,7 @@ static std::tuple doLoadConfigura if (!isEmptyString(optConfig)) { delta.setown(loadConfiguration(absConfigFilename, componentTag, true, altNameAttribute)); - newGlobalConfig.setown(loadConfiguration(absConfigFilename, "global", false, altNameAttribute)); + configGlobal.setown(loadConfiguration(absConfigFilename, "global", false, altNameAttribute)); } } else @@ -8997,13 +8999,21 @@ static std::tuple doLoadConfigura if (legacyFilename && checkFileExists(legacyFilename)) { delta.setown(createPTreeFromXMLFile(legacyFilename, ipt_caseInsensitive)); - newGlobalConfig.set(delta->queryPropTree("global")); + configGlobal.set(delta->queryPropTree("global")); } if (delta && mapper) delta.setown(mapper(delta)); } + if (configGlobal) + { + if (newGlobalConfig) + mergeConfiguration(*newGlobalConfig, *configGlobal); + else + newGlobalConfig.setown(configGlobal.getClear()); + } + if (delta) mergeConfiguration(*newComponentConfig, *delta, altNameAttribute); @@ -9046,13 +9056,13 @@ static std::tuple doLoadConfigura return std::make_tuple(std::string(absConfigFilename.str()), newComponentConfig.getClear(), newGlobalConfig.getClear()); } -jlib_decl IPropertyTree * loadConfiguration(IPropertyTree *componentDefault, const char * * argv, const char * componentTag, const char * envPrefix, const char * legacyFilename, IPropertyTree * (mapper)(IPropertyTree *), const char *altNameAttribute, bool monitor) +jlib_decl IPropertyTree * loadConfiguration(IPropertyTree *componentDefault, IPropertyTree *globalDefault, const char * * argv, const char * componentTag, const char * envPrefix, const char * legacyFilename, IPropertyTree * (mapper)(IPropertyTree *), const char *altNameAttribute, bool monitor) { assertex(configFileUpdater); // NB: loadConfiguration should always be called after configFileUpdater is initialized if (configFileUpdater->isInitialized()) throw makeStringExceptionV(99, "Configuration for component %s has already been initialised", componentTag); - auto result = doLoadConfiguration(componentDefault, argv, componentTag, envPrefix, legacyFilename, mapper, altNameAttribute); + auto result = doLoadConfiguration(componentDefault, globalDefault, argv, componentTag, envPrefix, legacyFilename, mapper, altNameAttribute); componentConfiguration.setown(std::get<1>(result)); globalConfiguration.setown(std::get<2>(result)); @@ -9072,7 +9082,7 @@ jlib_decl IPropertyTree * loadConfiguration(IPropertyTree *componentDefault, con * installed config hooks to be called when an environment change is detected e.g when pushed to Dali) */ - configFileUpdater->init(std::get<0>(result).c_str(), componentDefault, argv, componentTag, envPrefix, legacyFilename, mapper, altNameAttribute); + configFileUpdater->init(std::get<0>(result).c_str(), componentDefault, globalDefault, argv, componentTag, envPrefix, legacyFilename, mapper, altNameAttribute); if (monitor) configFileUpdater->startMonitoring(); @@ -9086,17 +9096,19 @@ jlib_decl IPropertyTree * loadConfiguration(const char * defaultYaml, const char throw makeStringExceptionV(99, "Configuration for component %s has already been initialised", componentTag); Owned componentDefault; + Owned defaultGlobalConfig; if (defaultYaml) { Owned defaultConfig = createPTreeFromYAML(defaultYaml); componentDefault.set(defaultConfig->queryPropTree(componentTag)); if (!componentDefault) throw makeStringExceptionV(99, "Default configuration does not contain the tag %s", componentTag); + defaultGlobalConfig.set(defaultConfig->queryPropTree("global")); } else componentDefault.setown(createPTree(componentTag)); - return loadConfiguration(componentDefault, argv, componentTag, envPrefix, legacyFilename, mapper, altNameAttribute, monitor); + return loadConfiguration(componentDefault, defaultGlobalConfig, argv, componentTag, envPrefix, legacyFilename, mapper, altNameAttribute, monitor); } void replaceComponentConfig(IPropertyTree *newComponentConfig, IPropertyTree *newGlobalConfig) diff --git a/system/jlib/jptree.hpp b/system/jlib/jptree.hpp index e52db5eec1a..40366556d9f 100644 --- a/system/jlib/jptree.hpp +++ b/system/jlib/jptree.hpp @@ -317,7 +317,7 @@ inline static bool isValidXPathChr(char c) jlib_decl void mergeConfiguration(IPropertyTree & target, const IPropertyTree & source, const char *altNameAttribute=nullptr, bool overwriteAttr=true); jlib_decl IPropertyTree * loadArgsIntoConfiguration(IPropertyTree *config, const char * * argv, std::initializer_list ignoreOptions = {}); -jlib_decl IPropertyTree * loadConfiguration(IPropertyTree * defaultConfig, const char * * argv, const char * componentTag, const char * envPrefix, const char * legacyFilename, IPropertyTree * (mapper)(IPropertyTree *), const char *altNameAttribute=nullptr, bool monitor=true); +jlib_decl IPropertyTree * loadConfiguration(IPropertyTree * defaultConfig, IPropertyTree * globalConfig, const char * * argv, const char * componentTag, const char * envPrefix, const char * legacyFilename, IPropertyTree * (mapper)(IPropertyTree *), const char *altNameAttribute=nullptr, bool monitor=true); jlib_decl IPropertyTree * loadConfiguration(const char * defaultYaml, const char * * argv, const char * componentTag, const char * envPrefix, const char * legacyFilename, IPropertyTree * (mapper)(IPropertyTree *), const char *altNameAttribute=nullptr, bool monitor=true); jlib_decl void replaceComponentConfig(IPropertyTree *newComponentConfig, IPropertyTree *newGlobalConfig); jlib_decl void initNullConfiguration(); diff --git a/thorlcr/slave/thslavemain.cpp b/thorlcr/slave/thslavemain.cpp index 910c83311b3..09945d05616 100644 --- a/thorlcr/slave/thslavemain.cpp +++ b/thorlcr/slave/thslavemain.cpp @@ -407,7 +407,7 @@ int main( int argc, const char *argv[] ) #ifdef _CONTAINERIZED globals.setown(loadConfiguration(thorDefaultConfigYaml, argv, "thor", "THOR", nullptr, nullptr, nullptr, false)); #else - globals.setown(loadConfiguration(globals, argv, "thor", "THOR", nullptr, nullptr, nullptr, false)); + globals.setown(loadConfiguration(globals, nullptr, argv, "thor", "THOR", nullptr, nullptr, nullptr, false)); #endif // NB: the thor configuration is serialized from the manager and only available after RegisterSelf