• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.16
/libs/core/runtime_configuration/src/init_ini_data.cpp
1
//  Copyright (c) 2005-2025 Hartmut Kaiser
2
//  Copyright (c)      2011 Bryce Lelbach
3
//
4
//  SPDX-License-Identifier: BSL-1.0
5
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7

8
#include <hpx/config.hpp>
9
#include <hpx/assert.hpp>
10
#include <hpx/modules/errors.hpp>
11
#include <hpx/modules/filesystem.hpp>
12
#include <hpx/modules/ini.hpp>
13
#include <hpx/modules/logging.hpp>
14
#include <hpx/modules/plugin.hpp>
15
#include <hpx/modules/prefix.hpp>
16
#include <hpx/modules/string_util.hpp>
17
#include <hpx/runtime_configuration/component_registry_base.hpp>
18
#include <hpx/runtime_configuration/init_ini_data.hpp>
19
#include <hpx/runtime_configuration/plugin_registry_base.hpp>
20
#include <hpx/version.hpp>
21

22
#include <algorithm>
23
#include <iostream>
24
#include <map>
25
#include <memory>
26
#include <random>
27
#include <string>
28
#include <system_error>
29
#include <utility>
30
#include <vector>
31

32
///////////////////////////////////////////////////////////////////////////////
33
namespace hpx::util {
34

35
    ///////////////////////////////////////////////////////////////////////////
1,920✔
36
    bool handle_ini_file(section& ini, std::string const& loc)
37
    {
38
        try
39
        {
40
            namespace fs = filesystem;
41
            std::error_code ec;
3,840✔
42
            if (!fs::exists(loc, ec) || ec)
1,920✔
43
                return false;    // avoid exception on missing file
×
44
            ini.read(loc);
45
        }
×
46
        catch (hpx::exception const& /*e*/)
47
        {
48
            return false;
×
49
        }
×
50
        return true;
51
    }
52

53
    ///////////////////////////////////////////////////////////////////////////
960✔
54
    bool handle_ini_file_env(
55
        section& ini, char const* env_var, char const* file_suffix)
56
    {
960✔
57
        if (char const* env = getenv(env_var); nullptr != env)
960✔
58
        {
59
            namespace fs = filesystem;
60

61
            fs::path inipath(env);
640✔
62
            if (nullptr != file_suffix)
640✔
63
                inipath /= fs::path(file_suffix);
640✔
64

65
            if (handle_ini_file(ini, inipath.string()))
1,280✔
66
            {
67
                LBT_(info).format("loaded configuration (${{{}}}): {}", env_var,
×
68
                    inipath.string());
×
69
                return true;
70
            }
71
        }
640✔
72
        return false;
73
    }
74

75
    ///////////////////////////////////////////////////////////////////////////
76
    // read system and user specified ini files
77
    //
78
    // returns true if at least one alternative location has been read
79
    // successfully
80
    bool init_ini_data_base(section& ini, std::string& hpx_ini_file)
320✔
81
    {
82
        namespace fs = filesystem;
83

84
        // fall back: use compile time prefix
85
        std::string ini_paths(ini.get_entry("hpx.master_ini_path"));
320✔
86
        std::string ini_paths_suffixes(
87
            ini.get_entry("hpx.master_ini_path_suffixes"));
320✔
88

89
        // split off the separate paths from the given path list
90
        hpx::string_util::char_separator sep(HPX_INI_PATH_DELIMITER);
320✔
91
        hpx::string_util::tokenizer tok_paths(ini_paths, sep);
92
        auto end_paths = tok_paths.end();
93
        hpx::string_util::tokenizer tok_suffixes(ini_paths_suffixes, sep);
94
        auto end_suffixes = tok_suffixes.end();
95

96
        bool result = false;
97
        for (auto it = tok_paths.begin(); it != end_paths; ++it)
640✔
98
        {
99
            for (auto jt = tok_suffixes.begin(); jt != end_suffixes; ++jt)
960✔
100
            {
101
                std::string path = *it;
102
                path += *jt;
103
                bool result2 = handle_ini_file(ini, path + "/hpx.ini");
640✔
104
                if (result2)
640✔
105
                {
106
                    LBT_(info).format("loaded configuration: {}/hpx.ini", path);
×
107
                }
108
                result = result2 || result;
640✔
109
            }
320✔
110
        }
320✔
111

112
        // look in the current directory first
113
        {
114
            std::string cwd = fs::current_path().string() + "/.hpx.ini";
640✔
115
            bool result2 = handle_ini_file(ini, cwd);
320✔
116
            if (result2)
320✔
117
            {
118
                LBT_(info).format("loaded configuration: {}", cwd);
×
119
            }
120
            result = result2 || result;
320✔
121
        }
122

123
        // look for master ini in the HPX_INI environment
124
        result = handle_ini_file_env(ini, "HPX_INI") || result;
320✔
125

126
        // afterward in the standard locations
127
#if !defined(HPX_WINDOWS)    // /etc/hpx.ini doesn't make sense for Windows
128
        {
129
            bool result2 = handle_ini_file(ini, "/etc/hpx.ini");
320✔
130
            if (result2)
320✔
131
            {
132
                LBT_(info).format("loaded configuration: /etc/hpx.ini");
×
133
            }
134
            result = result2 || result;
320✔
135
        }
136
#endif
137

138
        result = handle_ini_file_env(ini, "HOME", ".hpx.ini") || result;
320✔
139
        result = handle_ini_file_env(ini, "PWD", ".hpx.ini") || result;
320✔
140

141
        if (!hpx_ini_file.empty())
320✔
142
        {
143
            if (std::error_code ec; !fs::exists(hpx_ini_file, ec) || ec)
×
144
            {
145
                std::cerr
146
                    << "hpx::init: command line warning: file specified using "
147
                       "--hpx:config does not exist ("
148
                    << hpx_ini_file << ").\n";
149
                hpx_ini_file.clear();
150
                result = false;
151
            }
152
            else
153
            {
154
                bool result2 = handle_ini_file(ini, hpx_ini_file);
×
155
                if (result2)
×
156
                {
157
                    LBT_(info).format("loaded configuration: {}", hpx_ini_file);
×
158
                }
159
                return result || result2;
×
160
            }
161
        }
162
        return result;
163
    }
640✔
164

165
    ///////////////////////////////////////////////////////////////////////////
166
    // global function to read component ini information
167
    void merge_component_inis(section& ini)
64✔
168
    {
169
        namespace fs = filesystem;
170

171
        // now merge all information into one global structure
172
        std::string ini_path(
173
            ini.get_entry("hpx.ini_path", HPX_DEFAULT_INI_PATH));
192✔
174
        std::vector<std::string> ini_paths;
64✔
175

176
        // split off the separate paths from the given path list
177
        hpx::string_util::char_separator sep(HPX_INI_PATH_DELIMITER);
64✔
178
        hpx::string_util::tokenizer tok(ini_path, sep);
179
        auto end = tok.end();
180
        for (auto it = tok.begin(); it != end; ++it)
64✔
181
            ini_paths.push_back(*it);
64✔
182

183
        // have all path elements, now find ini files in there...
184
        auto ini_end = ini_paths.end();
185
        for (auto it = ini_paths.begin(); it != ini_end; ++it)
64✔
186
        {
187
            try
188
            {
189
                fs::directory_iterator nodir;
190
                fs::path this_path(*it);
×
191

192
                std::error_code ec;
193
                if (!fs::exists(this_path, ec) || ec)
×
194
                    continue;
195

196
                for (fs::directory_iterator dir(this_path); dir != nodir; ++dir)
×
197
                {
198
                    auto& p = dir->path();
199
                    if (p.extension() != ".ini")
×
200
                        continue;
×
201

202
                    // read and merge the ini file into the main ini hierarchy
203
                    try
204
                    {
205
                        ini.merge(p.string());
×
206
                        LBT_(info).format(
×
207
                            "loaded configuration: {}", p.string());
×
208
                    }
209
                    // NOLINTNEXTLINE(bugprone-empty-catch)
×
210
                    catch (hpx::exception const& /*e*/)
211
                    {
×
212
                    }
213
                }
×
214
            }
×
215
            // NOLINTNEXTLINE(bugprone-empty-catch)
216
            catch (fs::filesystem_error const& /*e*/)
×
217
            {
218
            }
192✔
219
        }
220
    }
221

222
    ///////////////////////////////////////////////////////////////////////////
223
    // iterate over all shared libraries in the given directory and construct
224
    // default ini settings assuming all of those are components
48✔
225
    std::vector<std::shared_ptr<components::component_registry_base>>
226
    load_component_factory_static(util::section& ini, std::string name,
227
        hpx::util::plugin::get_plugins_list_type const get_factory,
228
        error_code& ec)
229
    {
230
        hpx::util::plugin::static_plugin_factory<
231
            components::component_registry_base> const pf(get_factory);
48✔
232
        std::vector<std::shared_ptr<components::component_registry_base>>
233
            registries;
234

48✔
235
        // retrieve the names of all known registries
236
        std::vector<std::string> names;
48✔
237
        pf.get_names(names, ec);
238
        if (ec)
239
            return registries;
48✔
240

48✔
241
        std::vector<std::string> ini_data;
242
        if (names.empty())
243
        {
244
            // This HPX module does not export any factories, but
245
            // might export startup/shutdown functions. Create some
246
            // default configuration data.
247
#if defined(HPX_DEBUG)
248
            // demangle the name in debug mode
249
            if (name[name.size() - 1] == 'd')
250
                name.resize(name.size() - 1);
×
251
#endif
×
252
            ini_data.emplace_back("[hpx.components." + name + "]");
×
253
            ini_data.emplace_back("name = " + name);
×
254
            ini_data.emplace_back("no_factory = 1");
×
255
            ini_data.emplace_back("enabled = 1");
256
            ini_data.emplace_back("static = 1");
257
        }
258
        else
48✔
259
        {
260
            registries.reserve(names.size());
908✔
261
            // ask all registries
262
            for (std::string const& s : names)
263
            {
264
                // create the component registry object
860✔
265
                std::shared_ptr<components::component_registry_base> registry(
860✔
266
                    pf.create(s, ec));
267
                if (ec)
268
                    continue;
1,720✔
269

270
                registry->get_component_info(ini_data, "", true);
271
                registries.push_back(HPX_MOVE(registry));
272
            }
273
        }
274

275
        // incorporate all information from this module's
48✔
276
        // registry into our internal ini object
277
        ini.parse("<component registry>", ini_data, false, false);
48✔
278
        return registries;
279
    }
128✔
280

281
    static void load_component_factory(hpx::util::plugin::dll& d,
282
        util::section& ini, std::string const& curr,
283
        std::vector<std::shared_ptr<components::component_registry_base>>&
284
            component_registries,
285
        std::string name, error_code& ec)
286
    {
128✔
287
        hpx::util::plugin::plugin_factory<
288
            components::component_registry_base> const pf(d, "registry");
289

128✔
290
        // retrieve the names of all known registries
291
        std::vector<std::string> names;
128✔
292
        pf.get_names(names, ec);
293
        if (ec)
294
            return;
96✔
295

96✔
296
        std::vector<std::string> ini_data;
297
        if (names.empty())
298
        {
299
            // This HPX module does not export any factories, but
300
            // might export startup/shutdown functions. Create some
301
            // default configuration data.
302
#if defined(HPX_DEBUG)
303
            // demangle the name in debug mode
304
            if (name[name.size() - 1] == 'd')
305
                name.resize(name.size() - 1);
128✔
306
#endif
64✔
307
            ini_data.emplace_back("[hpx.components." + name + "]");
64✔
308
            ini_data.emplace_back("name = " + name);
64✔
309
            ini_data.emplace_back("path = " + curr);
64✔
310
            ini_data.emplace_back("no_factory = 1");
311
            ini_data.emplace_back("enabled = 1");
312
        }
313
        else
314
        {
64✔
315
            // ask all registries
316
            for (std::string const& s : names)
317
            {
318
                // create the component registry object
32✔
319
                std::shared_ptr<components::component_registry_base> registry(
32✔
320
                    pf.create(s, ec));
321
                if (ec)
322
                    return;
32✔
323

324
                registry->get_component_info(ini_data, curr);
325
                component_registries.push_back(HPX_MOVE(registry));
326
            }
327
        }
328

329
        // incorporate all information from this module's
96✔
330
        // registry into our internal ini object
128✔
331
        ini.parse("<component registry>", ini_data, false, false);
332
    }
333

334
    ///////////////////////////////////////////////////////////////////////////
128✔
335
    static std::vector<std::shared_ptr<plugins::plugin_registry_base>>
336
    load_plugin_factory(hpx::util::plugin::dll& d, util::section& ini,
337
        std::string const& /* curr */, std::string const& /* name */,
338
        error_code& ec)
339
    {
340
        using plugin_list_type =
341
            std::vector<std::shared_ptr<plugins::plugin_registry_base>>;
128✔
342

343
        plugin_list_type plugin_registries;
128✔
344
        hpx::util::plugin::plugin_factory<plugins::plugin_registry_base> const
345
            pf(d, "plugin");
346

128✔
347
        // retrieve the names of all known registries
348
        std::vector<std::string> names;
128✔
349
        pf.get_names(names, ec);    // throws on error
350
        if (ec)
351
            return plugin_registries;
32✔
352

32✔
353
        std::vector<std::string> ini_data;
354
        if (!names.empty())
355
        {
64✔
356
            // ask all registries
357
            for (std::string const& s : names)
358
            {
359
                // create the plugin registry object
32✔
360
                std::shared_ptr<plugins::plugin_registry_base> registry(
32✔
361
                    pf.create(s, ec));
362
                if (ec)
363
                    continue;
32✔
364

365
                registry->get_plugin_info(ini_data);
366
                plugin_registries.push_back(HPX_MOVE(registry));
367
            }
368
        }
369

370
        // incorporate all information from this module's
32✔
371
        // registry into our internal ini object
372
        ini.parse("<plugin registry>", ini_data, false, false);
128✔
373
        return plugin_registries;
374
    }
375

376
    ///////////////////////////////////////////////////////////////////////////
377
    std::vector<std::shared_ptr<plugins::plugin_registry_base>>
378
    init_ini_data_default(std::string const& libs, util::section& ini,
379
        std::map<std::string, filesystem::path>& basenames,
380
        std::map<std::string, hpx::util::plugin::dll>& modules,
381
        std::vector<std::shared_ptr<components::component_registry_base>>&
382
            component_registries)
383
    {
384
        namespace fs = filesystem;
385

386
        using plugin_list_type =
387
            std::vector<std::shared_ptr<plugins::plugin_registry_base>>;
388

389
        plugin_list_type plugin_registries;
390

391
        // list of modules to load
392
        std::vector<std::pair<fs::path, std::string>> libdata;
32✔
393
        try
394
        {
395
            fs::directory_iterator nodir;
396
            fs::path libs_path(libs);
397

398
            std::error_code ec;
399
            if (!fs::exists(libs_path, ec) || ec)
400
                return plugin_registries;    // given directory doesn't exist
401

402
            // retrieve/create section [hpx.components]
403
            if (!ini.has_section("hpx.components"))
32✔
404
            {
405
                util::section* hpx_sec = ini.get_section("hpx");
406
                HPX_ASSERT(nullptr != hpx_sec);
32✔
407

408
                util::section comp_sec;
409
                hpx_sec->add_section("components", comp_sec);
410
            }
32✔
411

412
            // generate component sections for all found shared libraries
413
            // this will create too many sections, but the non-components will
32✔
414
            // be filtered out during loading
415
            for (fs::directory_iterator dir(libs_path); dir != nodir; ++dir)
416
            {
417
                fs::path curr(*dir);
64✔
418
                if (curr.extension() != HPX_SHARED_LIB_EXTENSION)
419
                    continue;
×
420

421
                // instance name and module name are the same
422
                std::string name(fs::basename(curr));    //-V821
×
423

×
424
#if !defined(HPX_WINDOWS)
×
425
                if (0 == name.find("lib"))
426
                    name = name.substr(3);
427
#endif
428
#if defined(__APPLE__)    // shared library version is added before extension
429
                std::string const version = hpx::full_version_as_string();
384✔
430
                std::string::size_type i = name.find(version);
431
                if (i != std::string::npos)
384✔
432
                    name.erase(
768✔
433
                        i - 1, version.length() + 1);    // - 1 for one more dot
434
#endif
435
                // ensure base directory, remove symlinks, etc.
436
                std::error_code fsec;
128✔
437
                fs::path canonical_curr =
438
                    fs::canonical(curr, fs::initial_path(), fsec);
439
                if (fsec)
128✔
440
                    canonical_curr = curr;
256✔
441

442
                // make sure every module name is loaded exactly once, the
443
                // first occurrence of a module name is used
444
                std::string basename = canonical_curr.filename().string();
445
                std::pair<std::map<std::string, fs::path>::iterator, bool> p =
446
                    basenames.emplace(basename, canonical_curr);
447

448
                if (p.second)
449
                {
450
                    libdata.emplace_back(canonical_curr, name);
451
                }
452
                else
128✔
453
                {
128✔
454
                    LRT_(warning).format(
×
455
                        "skipping module {} ({}): ignored because of: {}",
456
                        basename, canonical_curr.string(),
457
                        p.first->second.string());
458
                }
256✔
459
            }
460
        }
128✔
461
        catch (fs::filesystem_error const& e)
462
        {
128✔
463
            LRT_(info).format("caught filesystem error: {}", e.what());
464
        }
128✔
465

466
        // return if no new modules have been found
467
        if (libdata.empty())
468
            return plugin_registries;
×
469

470
        // make sure each node loads libraries in a different order
×
471
        std::random_device random_device;
×
472
        std::mt19937 generator(random_device());
473
        std::shuffle(libdata.begin(), libdata.end(), HPX_MOVE(generator));
512✔
474

32✔
475
        for (auto const& p : libdata)
×
476
        {
477
            LRT_(info).format("attempting to load: {}", p.first.string());
×
478

×
479
            // get the handle of the library
480
            error_code ec(throwmode::lightweight);
481
            hpx::util::plugin::dll d(p.first.string(), p.second);
32✔
482
            d.load_library(ec);
483
            if (ec)
484
            {
485
                LRT_(info).format("skipping (load_library failed): {}: {}",
32✔
486
                    p.first.string(), get_error_what(ec));
32✔
487
                continue;
32✔
488
            }
489

160✔
490
            bool must_keep_loaded = false;
491

128✔
492
            // get the component factory
493
            std::string curr_fullname(p.first.parent_path().string());
494
            load_component_factory(
495
                d, ini, curr_fullname, component_registries, p.second, ec);
256✔
496
            if (ec)
497
            {
128✔
498
                LRT_(info).format(
499
                    "skipping (load_component_factory failed): {}: {}",
×
500
                    p.first.string(), get_error_what(ec));
×
501
                ec = error_code(throwmode::lightweight);    // reinit ec
502
            }
503
            else
504
            {
505
                LRT_(debug).format(
506
                    "load_component_factory succeeded: {}", p.first.string());
507
                must_keep_loaded = true;
256✔
508
            }
256✔
509

510
            // get the plugin factory
128✔
511
            plugin_list_type tmp_regs =
512
                load_plugin_factory(d, ini, curr_fullname, p.second, ec);
32✔
513

514
            if (ec)
×
515
            {
64✔
516
                LRT_(info).format(
517
                    "skipping (load_plugin_factory failed): {}: {}",
518
                    p.first.string(), get_error_what(ec));
519
            }
96✔
520
            else
×
521
            {
522
                LRT_(debug).format(
523
                    "load_plugin_factory succeeded: {}", p.first.string());
524

525
                std::copy(tmp_regs.begin(), tmp_regs.end(),
526
                    std::back_inserter(plugin_registries));
128✔
527
                must_keep_loaded = true;
528
            }
128✔
529

530
            // store loaded library for future use
96✔
531
            if (must_keep_loaded)
532
            {
×
533
                modules.emplace(p.second, HPX_MOVE(d));
534
            }
535
        }
536
        return plugin_registries;
32✔
537
    }
×
538
}    // namespace hpx::util
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc