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

v2.25.0 #280

Merged
merged 3 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,15 @@ Equipments should be prefixed as `[equipment-...]`.
Consumers should be prefixed as `[consumer-...]`.
General settings are defined in section `[readout]`.

Section names ending with `-*` can be used to define default parameters. They are applied to all section with similar names. Existing key-value pairs are not overwritten, but are defined according to defaults if they don't exist. For example, it is possible to define the TFperiod for all equipments by adding a section named `[equipment-*]` with `TFperiod=32`.

Values can be symbolic links to a value stored in another configuration file. The syntax is: @LINK,URI,entryPoint,path
For example: @LINK,file:/local/readout-test-config-link1.cfg,,bank.size
Parameters are similar to the command-line arguments of o2-readout-exe, see ```Usage``` below.
Files are cached, i.e. the corresponding configuration tree is loaded only once if several values use a link to the same URI/entryPoint.
Links substitutions are done at the end of the configuration tree aggregation (sections merging, etc).
It is done recursively (up to 5 iterations, after which it fails to avoid circular dependencies).

Comments can be added by starting a line with the # sign. Inline comments (# later in the line) are not accepted.
Documented example files are provided with the source code and distribution.

Expand Down
4 changes: 4 additions & 0 deletions doc/releaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -628,3 +628,7 @@ This file describes the main feature changes for each readout.exe released versi
## v2.24.0 - 18/06/2024
- Updated configuration parameters:
- equipment-rorc-*: added parameters firmwareVersionsDenied and firmwareVersionsAllowed, to enforce the check of firmware for specific versions. By default, v3.10.0 (e4a5a46e) is denied and all other allowed: it is the default version in CRU flash and should be updated to a more recent one at boot time.

## v2.25.0 - 25/06/2024
- Updated configuration parameters:
- Values can be a link to a value stored in another file.
2 changes: 1 addition & 1 deletion src/ReadoutVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#define READOUT_VERSION "2.24.0"
#define READOUT_VERSION "2.25.0"

92 changes: 92 additions & 0 deletions src/mainReadout.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,98 @@ int Readout::_configure(const boost::property_tree::ptree& properties)
pos = cfg.get().erase(pos);
}

// resolve "symlinks"
int cfgLinksErrors = 0;
struct ConfigCache {
std::string URI;
std::string EntryPoint;
std::unique_ptr<ConfigFile> cfg;
};
std::vector<ConfigCache> cfgCache;
int nSubstitutions = 0;
std::function<void(boost::property_tree::ptree &, const std::string &)> resolveLinks;
resolveLinks = [&resolveLinks, &cfgLinksErrors, &cfgCache, &loadConfig, &nSubstitutions](boost::property_tree::ptree &pt, const std::string &key) -> void {
if (pt.empty()) {
std::string value = pt.data();
const std::string keywordLink = "@LINK";
if (value.compare(0, keywordLink.length(), keywordLink) == 0) {
// this is a symlink
// extract reference
// syntax: @LINK,URI,EntryPoint,Path
std::vector<std::string> linkArgs;
getListFromString(value, linkArgs, ',');
if (linkArgs.size() != 4) {
theLog.log(LogErrorSupport_(3102), "Failed to parse link: %s = %s", key.c_str(), value.c_str());
cfgLinksErrors++;
return;
}
const char* cfgLinkUri = linkArgs[1].c_str();
const char* cfgLinkEntryPoint = linkArgs[2].c_str();
const char* cfgLinkPath = linkArgs[3].c_str();
// search for file in cache
unsigned int ix = 0;
for(;ix < cfgCache.size(); ix++) {
if ((cfgCache[ix].URI == cfgLinkUri) && (cfgCache[ix].EntryPoint == cfgLinkEntryPoint)) {
break;
}
}
if (ix == cfgCache.size()) {
// no match in cache, add it
try {
auto cfg = std::make_unique<ConfigFile>();
if (cfg==nullptr) {
throw __LINE__;
}
if (loadConfig(cfgLinkUri, cfgLinkEntryPoint, *cfg)) {
throw __LINE__;
}
cfgCache.push_back({cfgLinkUri, cfgLinkEntryPoint, std::move(cfg)});
}
catch(...) {
theLog.log(LogErrorSupport_(3102), "Failed to load linked configuration %s %s", cfgLinkUri, cfgLinkEntryPoint);
cfgLinksErrors++;
return;
}
theLog.log(LogInfoSupport, "Reading linked configuration from %s %s", cfgLinkUri, cfgLinkEntryPoint);
}
// at this stage we now have a valid config in cache at index ix
// get value from linked config
std::string linkValue;
if (cfgCache[ix].cfg->getOptionalValue<std::string>(cfgLinkPath, linkValue)) {
theLog.log(LogErrorSupport_(3102), "Failed to get link value: %s = %s", key.c_str(), value.c_str());
cfgLinksErrors++;
return;
}
theLog.log(LogInfoDevel_(3002), "Link substituted : %s = %s -> %s", key.c_str(), value.c_str(), linkValue.c_str());
pt.data() = linkValue;
nSubstitutions++;
}
return;
}
for (boost::property_tree::ptree::iterator pos = pt.begin(); pos != pt.end();++pos) {
//printf("%s\n", pos->first.c_str());
resolveLinks(pos->second, pos->first.c_str());
}
};
int maxLoops = 5;
for (int i = 0; i <= maxLoops; i++) {
if (i == maxLoops) {
theLog.log(LogErrorSupport_(3100), "Links not fully resolved after %d iterations, there might be some circular dependencies in the configuration", maxLoops);
cfgLinksErrors++;
break;
}
nSubstitutions = 0;
resolveLinks(cfg.get(),"");
if (nSubstitutions == 0) {
break;
}
}
if (cfgLinksErrors) {
theLog.log(LogErrorSupport_(3100), "Some links in the configuration could not be resolved");
return -1;
}


// extract optional configuration parameters
// configuration parameter: | readout | customCommands | string | | List of key=value pairs defining some custom shell commands to be executed at before/after state change commands. |
if (customCommandsShellPid) {
Expand Down