The Gaudi Framework  master (01b473db)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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"
20 #include <Gaudi/Parsers/Factory.h>
21 #include <Gaudi/Property.h>
22 #include <GaudiKernel/IProperty.h>
23 #include <GaudiKernel/MsgStream.h>
26 #include <GaudiKernel/Service.h>
27 #include <GaudiKernel/StatusCode.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 
39 namespace Gaudi {
40  namespace Parsers {
41  class Catalog;
42  }
43 } // namespace Gaudi
44 
45 class JobOptionsSvc : public extends<Service, Gaudi::Interfaces::IOptionsSvc> {
46 public:
47  typedef std::vector<const Gaudi::Details::PropertyBase*> PropertiesT;
48 
49 private:
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 
58 protected:
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 
93 public:
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 
109 private:
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 
116 private:
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 
137 namespace gp = Gaudi::Parsers;
138 
139 JobOptionsSvc::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 
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 
192 void 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 
203 void 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 
225 StatusCode 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" ) {
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 
261 void 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 
278 void 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 }
JobOptionsSvc::get
std::string get(const std::string &key, const std::string &default_={}) const override
Definition: JobOptionsSvc.cpp:61
MSG::DEBUG
@ DEBUG
Definition: IMessageSvc.h:22
Gaudi::Details::PropertyBase
PropertyBase base class allowing PropertyBase* collections to be "homogeneous".
Definition: PropertyBase.h:34
Service::initialize
StatusCode initialize() override
Definition: Service.cpp:118
Gaudi.Configuration.log
log
Definition: Configuration.py:28
JobOptionsSvc::m_reportUnused
Gaudi::Property< bool > m_reportUnused
Definition: JobOptionsSvc.cpp:130
AtlasMCRecoFullPrecedenceDump.path
path
Definition: AtlasMCRecoFullPrecedenceDump.py:49
StatusCode::isSuccess
bool isSuccess() const
Definition: StatusCode.h:314
Gaudi::Parsers::Units
Definition: Units.h:19
System.h
gaudirun.s
string s
Definition: gaudirun.py:346
JobOptionsSvc::m_old_iface_compat_2
std::map< std::string, PropertiesT > m_old_iface_compat_2
Definition: JobOptionsSvc.cpp:56
System::getEnv
GAUDI_API std::string getEnv(const char *var)
get a particular environment variable (returning "UNKNOWN" if not set)
Definition: System.cpp:329
ISvcLocator
Definition: ISvcLocator.h:42
jsonFromLHCbLog.json
json
Definition: jsonFromLHCbLog.py:86
JobOptionsSvc::m_pythonAction
Gaudi::Property< std::string > m_pythonAction
Definition: JobOptionsSvc.cpp:121
JobOptionsSvc::m_source_path
Gaudi::Property< std::string > m_source_path
Definition: JobOptionsSvc.cpp:118
JobOptionsSvc::set
void set(const std::string &key, const std::string &value) override
Definition: JobOptionsSvc.cpp:60
JobOptionsSvc::bind
void bind(const std::string &prefix, Gaudi::Details::PropertyBase *property) override
Definition: JobOptionsSvc.cpp:261
gaudirun.prefix
string prefix
Definition: gaudirun.py:361
Gaudi::Parsers::Node
Definition: Node.h:23
JobOptionsSvc::m_options
StorageType m_options
Definition: JobOptionsSvc.cpp:53
JobOptionsSvc::m_pythonParams
Gaudi::Property< std::string > m_pythonParams
Definition: JobOptionsSvc.cpp:122
StatusCode.h
CommonMessaging< implements< IService, IProperty, IStateful > >::msgLevel
MSG::Level msgLevel() const
get the cached level (originally extracted from the embedded MsgStream)
Definition: CommonMessaging.h:147
PropertyHolder< CommonMessaging< implements< IService, IProperty, IStateful > > >::property
Gaudi::Details::PropertyBase * property(std::string_view name) const
\fixme property and bindPropertiesTo should be protected
Definition: PropertyHolder.h:224
JobOptionsSvc::broadcast
void broadcast(const std::regex &filter, const std::string &value, OnlyDefaults defaults_only) override
Definition: JobOptionsSvc.cpp:278
PropertyId.h
JobOptionsSvc::start
StatusCode start() override
Definition: JobOptionsSvc.cpp:187
Gaudi::Parsers::PragmaOptions
Definition: PragmaOptions.h:17
JobOptionsSvc::m_old_iface_compat
std::map< std::string, std::unique_ptr< Gaudi::Details::PropertyBase > > m_old_iface_compat
Definition: JobOptionsSvc.cpp:55
Gaudi::Utils::begin
AttribStringParser::Iterator begin(const AttribStringParser &parser)
Definition: AttribStringParser.h:135
Service::name
const std::string & name() const override
Retrieve name of the service
Definition: Service.cpp:333
StatusCode
Definition: StatusCode.h:64
Gaudi::Parsers::Node::ToString
std::string ToString(int indent=0) const
Definition: Node.cpp:56
gaudirun.opts
opts
Definition: gaudirun.py:336
JobOptionsSvc::m_dump
Gaudi::Property< std::string > m_dump
Definition: JobOptionsSvc.cpp:120
Gaudi::cxx::for_each
void for_each(ContainerOfSynced &c, Fun &&f)
Definition: SynchronizedValue.h:98
JobOptionsSvc::stop
StatusCode stop() override
Definition: JobOptionsSvc.cpp:167
JobOptionsSvc::m_globalDefaultsProp
Gaudi::Property< std::vector< std::pair< std::string, std::string > > > m_globalDefaultsProp
Definition: JobOptionsSvc.cpp:124
CommonMessaging
Definition: CommonMessaging.h:65
Gaudi::Parsers::Messages
Definition: Messages.h:20
Gaudi::Property::declareUpdateHandler
Details::PropertyBase & declareUpdateHandler(std::function< void(Details::PropertyBase &)> fun) override
set new callback for update
Definition: Property.h:135
JobOptionsSvc::StorageType
std::unordered_map< PropertyId, Gaudi::Details::WeakPropertyRef > StorageType
Definition: JobOptionsSvc.cpp:51
JobOptionsSvc::readOptions
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
Definition: JobOptionsSvc.cpp:225
endmsg
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:198
System::isEnvSet
GAUDI_API bool isEnvSet(const char *var)
Check if an environment variable is set or not.
Definition: System.cpp:349
extends
Base class used to extend a class implementing other interfaces.
Definition: extends.h:19
Units.h
Gaudi
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition: __init__.py:1
Gaudi::Parsers::ReadOptions
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
JobOptionsSvc::dump
void dump(const std::string &file, const Gaudi::Parsers::Catalog &catalog) const
dump properties catalog to file
Definition: JobOptionsSvc.cpp:192
Messages.h
JobOptionsSvc::m_dir_search_path
Gaudi::Property< std::string > m_dir_search_path
Definition: JobOptionsSvc.cpp:119
PythonConfig.h
Service.h
Factory.h
JobOptionsSvc::PropertiesT
std::vector< const Gaudi::Details::PropertyBase * > PropertiesT
Definition: JobOptionsSvc.cpp:47
Node.h
Gaudi::Details::PropertyId
Helper to record a property identifier as a sequence of SharedString instances.
Definition: PropertyId.h:65
StatusCode::SUCCESS
constexpr static const auto SUCCESS
Definition: StatusCode.h:99
ConditionsStallTest.name
name
Definition: ConditionsStallTest.py:77
Service::stop
StatusCode stop() override
Definition: Service.cpp:181
JobOptionsSvc::initialize
StatusCode initialize() override
Definition: JobOptionsSvc.cpp:150
JobOptionsSvc::m_source_type
Gaudi::Property< std::string > m_source_type
Definition: JobOptionsSvc.cpp:117
Gaudi::Parsers::PragmaOptions::IsPrintOptions
bool IsPrintOptions()
Definition: PragmaOptions.h:33
System::PathResolver::find_file
static std::string find_file(const std::string &logical_file_name, const std::string &search_path, SearchType search_type=LocalSearch)
Definition: PathResolver.cpp:96
JobOptionsSvc
Definition: JobOptionsSvc.cpp:45
DECLARE_COMPONENT
#define DECLARE_COMPONENT(type)
Definition: PluginServiceV1.h:45
JobOptionsSvc::isSet
bool isSet(const std::string &key) const override
Definition: JobOptionsSvc.cpp:83
Properties.v
v
Definition: Properties.py:122
Gaudi::Parsers::PragmaOptions::HasDumpFile
bool HasDumpFile()
Definition: PragmaOptions.h:35
Gaudi::Parsers
Definition: DODBasicMapper.cpp:17
IProperty.h
IOTest.end
end
Definition: IOTest.py:125
StatusCode::FAILURE
constexpr static const auto FAILURE
Definition: StatusCode.h:100
JobOptionsSvc::pop
std::string pop(const std::string &key, const std::string &default_={}) override
Definition: JobOptionsSvc.cpp:65
PathResolver.h
Catalog.h
JobOptionsSvc::fillServiceCatalog
void fillServiceCatalog(const Gaudi::Parsers::Catalog &catalog)
Definition: JobOptionsSvc.cpp:217
PropertyHolder.h
ProduceConsume.key
key
Definition: ProduceConsume.py:84
JobOptionsSvc::items
std::vector< std::tuple< std::string, std::string > > items() const override
Definition: JobOptionsSvc.cpp:76
Gaudi::Parsers::PragmaOptions::IsPrintTree
bool IsPrintTree()
Definition: PragmaOptions.h:34
IOptionsSvc.h
Gaudi::Parsers::PragmaOptions::dumpFile
const std::string & dumpFile() const
Definition: PragmaOptions.h:30
JobOptionsSvc::has
bool has(const std::string &key) const override
Definition: JobOptionsSvc.cpp:75
conf
Definition: conf.py:1
JobOptionsSvc::m_globalDefaults
std::vector< std::pair< std::regex, std::string > > m_globalDefaults
Definition: JobOptionsSvc.cpp:132
Gaudi::Property< std::string >
JobOptionsSvc::JobOptionsSvc
JobOptionsSvc(const std::string &name, ISvcLocator *svc)
Definition: JobOptionsSvc.cpp:139
Gaudi::Parsers::Catalog
Definition: Catalog.h:22
Property.h
MsgStream.h
PythonConfig
Definition: PythonConfig.h:30
Gaudi::Functional::details::out
OptOut && out
Definition: details.h:179
Analyzer.h
PragmaOptions.h