The Gaudi Framework  master (e68eea06)
Loading...
Searching...
No Matches
JobOptionsSvc.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#include "Analyzer.h"
12#include "Catalog.h"
13#include "Messages.h"
14#include "Node.h"
15#include "PragmaOptions.h"
16#include "PropertyId.h"
17#include "PythonConfig.h"
18#include "Units.h"
21#include <Gaudi/Property.h>
26#include <GaudiKernel/Service.h>
28#include <GaudiKernel/System.h>
29#include <algorithm>
30#include <fstream>
31#include <functional>
32#include <memory>
33#include <nlohmann/json.hpp>
34#include <string>
35#include <string_view>
36#include <unordered_map>
37#include <vector>
38
39namespace Gaudi {
40 namespace Parsers {
41 class Catalog;
42 }
43} // namespace Gaudi
44
45class JobOptionsSvc : public extends<Service, Gaudi::Interfaces::IOptionsSvc> {
46public:
47 typedef std::vector<const Gaudi::Details::PropertyBase*> PropertiesT;
48
49private:
51 using StorageType = std::unordered_map<PropertyId, Gaudi::Details::WeakPropertyRef>;
52
54
55 mutable std::map<std::string, std::unique_ptr<Gaudi::Details::PropertyBase>> m_old_iface_compat;
56 mutable std::map<std::string, PropertiesT> m_old_iface_compat_2;
57
58protected:
60 void set( const std::string& key, const std::string& value ) override { m_options[key] = value; }
61 std::string get( const std::string& key, const std::string& default_ = {} ) const override {
62 auto item = m_options.find( key );
63 return item != m_options.end() ? std::string{ item->second } : default_;
64 }
65 std::string pop( const std::string& key, const std::string& default_ = {} ) override {
66 std::string result = default_;
67
68 auto item = m_options.find( key );
69 if ( item != m_options.end() ) {
70 result = std::move( item->second );
71 m_options.erase( item );
72 }
73 return result;
74 }
75 bool has( const std::string& key ) const override { return m_options.find( key ) != m_options.end(); }
76 std::vector<std::tuple<std::string, std::string>> items() const override {
77 std::vector<std::tuple<std::string, std::string>> v;
78 v.reserve( m_options.size() );
79 std::for_each( begin( m_options ), end( m_options ), [&v]( const auto& item ) { v.emplace_back( item ); } );
80 std::sort( begin( v ), end( v ) );
81 return v;
82 }
83 bool isSet( const std::string& key ) const override {
84 auto item = m_options.find( key );
85 return item != m_options.end() && item->second.isSet();
86 }
87
88 void bind( const std::string& prefix, Gaudi::Details::PropertyBase* property ) override;
89
90 void broadcast( const std::regex& filter, const std::string& value, OnlyDefaults defaults_only ) override;
92
93public:
94 // Constructor
95 JobOptionsSvc( const std::string& name, ISvcLocator* svc );
96
97 StatusCode initialize() override;
98 StatusCode start() override;
99 StatusCode stop() override;
100
107 StatusCode readOptions( std::string_view file, std::string_view path = "" ) override;
108
109private:
110 void fillServiceCatalog( const Gaudi::Parsers::Catalog& catalog );
111
113 void dump( const std::string& file, const Gaudi::Parsers::Catalog& catalog ) const;
114 void dump( const std::string& file ) const;
115
116private:
123
125 this,
126 "GlobalDefaults",
127 {},
128 "Allow definition of global defaults for properties as list of pairs (regex, value)" };
129
130 Gaudi::Property<bool> m_reportUnused{ this, "ReportUnused", false, "Print report of properties set, but not used" };
131
132 std::vector<std::pair<std::regex, std::string>> m_globalDefaults;
133};
134
136
137namespace gp = Gaudi::Parsers;
138
139JobOptionsSvc::JobOptionsSvc( const std::string& name, ISvcLocator* svc ) : base_class( name, svc ) {
140 if ( System::isEnvSet( "JOBOPTSEARCHPATH" ) ) m_dir_search_path = System::getEnv( "JOBOPTSEARCHPATH" );
141 if ( System::isEnvSet( "JOBOPTSDUMPFILE" ) ) m_dump = System::getEnv( "JOBOPTSDUMPFILE" );
142
143 m_globalDefaultsProp.declareUpdateHandler( [this]( Gaudi::Details::PropertyBase& ) {
144 m_globalDefaults.clear();
145 m_globalDefaults.reserve( m_globalDefaultsProp.size() );
146 for ( const auto& p : m_globalDefaultsProp ) { m_globalDefaults.emplace_back( p.first, p.second ); }
147 } );
148}
149
151 // Call base class initializer
153 // Read the job options if needed
154 if ( sc ) {
155 if ( m_source_type == "NONE" ) {
156 return sc;
157 } else if ( m_source_type == "PYTHON" ) {
158 PythonConfig conf( this );
159 return conf.evaluateConfig( m_source_path, m_pythonParams, m_pythonAction );
160 } else {
162 }
163 }
164 return sc;
165}
166
168 if ( m_reportUnused ) {
169 std::vector<std::string> unused;
170 unused.reserve( m_options.size() );
171
172 for ( const auto& p : m_options ) {
173 if ( !p.second.isBound() ) unused.emplace_back( p.first );
174 }
175
176 if ( !unused.empty() ) {
177 std::sort( unused.begin(), unused.end() );
178 auto& log = warning();
179 log << unused.size() << " unused properties:";
180 for ( const auto& k : unused ) log << "\n - " << k;
181 log << endmsg;
182 }
183 }
184 return Service::stop();
185}
186
188 if ( !m_dump.empty() ) { dump( m_dump ); }
189 return StatusCode::SUCCESS;
190}
191
192void JobOptionsSvc::dump( const std::string& file, const gp::Catalog& catalog ) const {
193 std::ofstream out( file, std::ios_base::out | std::ios_base::trunc );
194 if ( !out ) {
195 error() << "Unable to open dump-file \"" + file + "\"" << endmsg;
196 return;
197 }
198 info() << "Properties are dumped into \"" + file + "\"" << endmsg;
199 // perform the actual dump:
200 out << catalog;
201}
202
203void JobOptionsSvc::dump( const std::string& file ) const {
204 std::ofstream out( file, std::ios_base::out | std::ios_base::trunc );
205 if ( !out ) {
206 error() << "Unable to open dump-file \"" + file + "\"" << endmsg;
207 } else {
208 info() << "Properties are dumped into \"" + file + "\"" << endmsg;
209 for ( const auto& [key, value] : items() ) {
210 out << key << " = " << value << ';';
211 if ( !m_options.find( key )->second.isBound() ) out << " // unused";
212 out << '\n';
213 }
214 }
215}
216
218 for ( const auto& client : catalog ) {
219 for ( const auto& current : client.second ) {
220 set( client.first + '.' + current.NameInClient(), current.ValueAsString() );
221 }
222 }
223}
224
225StatusCode JobOptionsSvc::readOptions( std::string_view file, std::string_view path ) {
226 std::string search_path = std::string{ path };
227 if ( search_path.empty() && !m_dir_search_path.empty() ) { search_path = m_dir_search_path; }
228
229 if ( msgLevel( MSG::DEBUG ) )
230 debug() << "Reading options from the file "
231 << "'" << file << "'" << endmsg;
232
233 if ( file.size() >= 5 && file.substr( file.size() - 5 ) == ".json" ) {
234 nlohmann::json opts;
235 std::ifstream input( System::PathResolver::find_file( std::string( file ), std::string( path ) ) );
236 input >> opts;
237 for ( auto item = opts.begin(); item != opts.end(); ++item ) { set( item.key(), item.value().get<std::string>() ); }
238 return StatusCode::SUCCESS;
239 }
240
241 gp::Messages messages( msgStream() );
242 gp::Catalog catalog;
243 gp::Units units;
244 gp::PragmaOptions pragma;
245 gp::Node ast;
246 StatusCode sc = gp::ReadOptions( file, path, &messages, &catalog, &units, &pragma, &ast ) ? StatusCode::SUCCESS
248
249 if ( sc.isSuccess() ) {
250 if ( pragma.IsPrintOptions() ) { info() << "Print options" << std::endl << catalog << endmsg; }
251 if ( pragma.IsPrintTree() ) { info() << "Print tree:" << std::endl << ast.ToString() << endmsg; }
252 if ( pragma.HasDumpFile() ) dump( pragma.dumpFile(), catalog );
253 info() << "Job options successfully read in from " << file << endmsg;
254 fillServiceCatalog( catalog );
255 } else {
256 fatal() << "Job options errors." << endmsg;
257 }
258 return sc;
259}
260
261void JobOptionsSvc::bind( const std::string& prefix, Gaudi::Details::PropertyBase* property ) {
262 const std::string key = prefix + '.' + property->name();
263
264 std::tuple<bool, std::string_view> defaultValue{ false, "" };
265 if ( !has( key ) && !m_globalDefaults.empty() ) { // look for a global default only if it was not set
266 std::smatch match;
267 for ( const auto& p : m_globalDefaults ) {
268 if ( regex_match( key, match, p.first ) ) { defaultValue = { true, p.second }; }
269 }
270 }
271
272 m_options[key] = *property;
273
274 // at this point the property is bound, so we can set the default if needed
275 if ( std::get<0>( defaultValue ) ) set( key, std::string{ std::get<1>( defaultValue ) } );
276}
277
278void JobOptionsSvc::broadcast( const std::regex& filter, const std::string& value, OnlyDefaults defaults_only ) {
279 std::smatch match;
280 for ( auto& p : m_options ) {
281 if ( !defaults_only || !p.second.isSet() ) {
282 const auto s = p.first.str();
283 if ( regex_match( s, match, filter ) ) { p.second = value; }
284 }
285 }
286}
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define DECLARE_COMPONENT(type)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & warning() const
shortcut for the method msgStream(MSG::WARNING)
MsgStream & fatal() const
shortcut for the method msgStream(MSG::FATAL)
MsgStream & msgStream() const
Return an uninitialized MsgStream.
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
PropertyBase base class allowing PropertyBase* collections to be "homogeneous".
Helper to record a property identifier as a sequence of SharedString instances.
Definition PropertyId.h:65
const std::string & dumpFile() const
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition ISvcLocator.h:42
Gaudi::Property< std::string > m_pythonAction
std::vector< std::pair< std::regex, std::string > > m_globalDefaults
std::map< std::string, std::unique_ptr< Gaudi::Details::PropertyBase > > m_old_iface_compat
std::string get(const std::string &key, const std::string &default_={}) const override
std::map< std::string, PropertiesT > m_old_iface_compat_2
void dump(const std::string &file, const Gaudi::Parsers::Catalog &catalog) const
dump properties catalog to file
std::string pop(const std::string &key, const std::string &default_={}) override
void bind(const std::string &prefix, Gaudi::Details::PropertyBase *property) override
std::vector< const Gaudi::Details::PropertyBase * > PropertiesT
Gaudi::Property< bool > m_reportUnused
std::unordered_map< PropertyId, Gaudi::Details::WeakPropertyRef > StorageType
void fillServiceCatalog(const Gaudi::Parsers::Catalog &catalog)
std::vector< std::tuple< std::string, std::string > > items() const override
JobOptionsSvc(const std::string &name, ISvcLocator *svc)
Gaudi::Property< std::string > m_source_type
StatusCode stop() override
void set(const std::string &key, const std::string &value) override
Gaudi::Property< std::string > m_pythonParams
Gaudi::Property< std::string > m_source_path
StatusCode start() override
Gaudi::Property< std::string > m_dump
void broadcast(const std::regex &filter, const std::string &value, OnlyDefaults defaults_only) override
Gaudi::Details::PropertyId PropertyId
StatusCode readOptions(std::string_view file, std::string_view path="") override
look for file 'file' into search path 'path' and read it to update existing JobOptionsCatalogue
bool has(const std::string &key) const override
StatusCode initialize() override
StorageType m_options
bool isSet(const std::string &key) const override
Gaudi::Property< std::string > m_dir_search_path
Gaudi::Property< std::vector< std::pair< std::string, std::string > > > m_globalDefaultsProp
Gaudi::Details::PropertyBase * property(std::string_view name) const
const std::string & name() const override
Retrieve name of the service.
Definition Service.cpp:333
StatusCode stop() override
Definition Service.cpp:181
StatusCode initialize() override
Definition Service.cpp:118
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isSuccess() const
Definition StatusCode.h:314
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
static std::string find_file(const std::string &logical_file_name, const std::string &search_path, SearchType search_type=LocalSearch)
Base class used to extend a class implementing other interfaces.
Definition extends.h:19
bool ReadOptions(std::string_view filename, std::string_view search_path, Messages *messages, Catalog *catalog, Units *units, PragmaOptions *pragma, Node *root)
Parse and analyze filename, save all messages and properties.
Definition Analyzer.cpp:365
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1
@ DEBUG
Definition IMessageSvc.h:22
GAUDI_API bool isEnvSet(const char *var)
Check if an environment variable is set or not.
Definition System.cpp:349
GAUDI_API std::string getEnv(const char *var)
get a particular environment variable (returning "UNKNOWN" if not set)
Definition System.cpp:329
Definition conf.py:1
std::string ToString(int indent=0) const
Definition Node.cpp:56