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

polserver / polserver / 21100551564

17 Jan 2026 08:40PM UTC coverage: 60.504% (+0.01%) from 60.492%
21100551564

Pull #857

github

turleypol
fixed scope
Pull Request #857: ClangTidy readability-else-after-return

837 of 1874 new or added lines in 151 files covered. (44.66%)

48 existing lines in 26 files now uncovered.

44445 of 73458 relevant lines covered (60.5%)

515341.61 hits per line

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

74.73
/pol-core/plib/pkg.cpp
1
/** @file
2
 *
3
 * @par History
4
 */
5

6

7
#include "pkg.h"
8

9
#include "pol_global_config.h"
10
#include <algorithm>
11
#include <filesystem>
12
#include <stdlib.h>
13
#include <system_error>
14

15
#include "../clib/cfgelem.h"
16
#include "../clib/cfgfile.h"
17
#include "../clib/clib.h"
18
#include "../clib/fileutil.h"
19
#include "../clib/logfacility.h"
20
#include "../clib/passert.h"
21
#include "../clib/stlutil.h"
22
#include "../clib/strutil.h"
23
#include "systemstate.h"
24

25
namespace fs = std::filesystem;
26

27
namespace Pol::Plib
28
{
29
bool Package::provides_system_home_page() const
38✔
30
{
31
  return provides_system_home_page_;
38✔
32
}
33

34

35
Package* find_package( const std::string& pkgname )
8,920✔
36
{
37
  auto itr = systemstate.packages_byname.find( pkgname );
8,920✔
38
  if ( itr != systemstate.packages_byname.end() )
8,920✔
39
  {
40
    return ( *itr ).second;
301✔
41
  }
42

43
  return nullptr;
8,619✔
44
}
45

46
void remove_package( Package* pkg )
×
47
{
48
  auto last = std::remove( systemstate.packages.begin(), systemstate.packages.end(), pkg );
×
49
  systemstate.packages.erase( last, systemstate.packages.end() );
×
50

51
  auto itr = systemstate.packages_byname.begin();
×
52
  while ( itr != systemstate.packages_byname.end() )
×
53
  {
54
    if ( itr->second == pkg )
×
55
    {
56
      systemstate.packages_byname.erase( itr );
×
57
      break;
×
58
    }
59
    ++itr;
×
60
  }
61
}
×
62

63
void compare_versions( const std::string& verleft, const std::string& verright, bool& isgreater,
23,870✔
64
                       bool& isequal )
65
{
66
  isgreater = isequal = false;
23,870✔
67

68
  const char* vneed = verright.c_str();
23,870✔
69
  const char* vhave = verleft.c_str();
23,870✔
70

71
  while ( ( vneed != nullptr && vneed[0] != '\0' ) || ( vhave != nullptr && vhave[0] != '\0' ) )
49,724✔
72
  {
73
    char* new_vneed = nullptr;
43,760✔
74
    char* new_vhave = nullptr;
43,760✔
75
    unsigned int vneedpart, vhavepart;
76
    vneedpart = ( vneed != nullptr ) ? strtoul( vneed, &new_vneed, 0 ) : 0;
43,760✔
77
    vhavepart = ( vhave != nullptr ) ? strtoul( vhave, &new_vhave, 0 ) : 0;
43,760✔
78

79
    if ( vhavepart > vneedpart )
43,760✔
80
    {
81
      isgreater = true;
9,954✔
82
      return;
17,906✔
83
    }
84
    if ( vhavepart < vneedpart )
33,806✔
85
    {
86
      return;
7,952✔
87
    }
88
    // same, so check the next one
89
    vneed = new_vneed;
25,854✔
90
    if ( vneed && *vneed )
25,854✔
91
      ++vneed;
11,928✔
92
    vhave = new_vhave;
25,854✔
93
    if ( vhave && *vhave )
25,854✔
94
      ++vhave;
15,914✔
95
  }
96
  isequal = true;
5,964✔
97
}
98

99
bool version_greater_or_equal( const std::string& version_have, const std::string& version_need )
19,892✔
100
{
101
  bool isgreater;
102
  bool isequal;
103
  compare_versions( version_have, version_need, isgreater, isequal );
19,892✔
104
  return ( isequal || isgreater );
19,892✔
105
}
106

107
bool version_equal( const std::string& version_have, const std::string& version_need )
3,978✔
108
{
109
  bool isgreater;
110
  bool isequal;
111
  compare_versions( version_have, version_need, isgreater, isequal );
3,978✔
112
  return isequal;
3,978✔
113
}
114

115
void test_check_version()
1,988✔
116
{  // have // need
117
  passert( version_greater_or_equal( "0", "0" ) == true );
1,988✔
118
  passert( version_greater_or_equal( "1", "0" ) == true );
1,988✔
119
  passert( version_greater_or_equal( "0", "1" ) == false );
1,988✔
120
  passert( version_greater_or_equal( "0.5", "1" ) == false );
1,988✔
121
  passert( version_greater_or_equal( "0.5", "0" ) == true );
1,988✔
122
  passert( version_greater_or_equal( "1.2", "1.12" ) == false );
1,988✔
123
  passert( version_greater_or_equal( "1.12", "1.2" ) == true );
1,988✔
124
  passert( version_greater_or_equal( "1.2.3", "1" ) == true );
1,988✔
125
  passert( version_greater_or_equal( "1.1", "1.2.3" ) == false );
1,988✔
126
  passert( version_greater_or_equal( "1.3", "1.2.3" ) == true );
1,988✔
127

128
  passert( version_equal( "93", "93.0.0" ) == true );
1,988✔
129
  passert( version_equal( "93.0.0", "93" ) == true );
1,988✔
130
}
1,988✔
131

132
PackageList::PackageList( Clib::ConfigElem& elem, const char* tag )
25,857✔
133
{
134
  std::string tmp;
25,857✔
135
  while ( elem.remove_prop( tag, &tmp ) )
25,857✔
136
  {
137
    Clib::mklowerASCII( tmp );
×
138
    ISTRINGSTREAM is( tmp );
×
139
    Elem _elem;
×
140
    if ( is >> _elem.pkgname )
×
141
    {
142
      if ( !( is >> _elem.version ) )
×
143
        _elem.version = "0";
×
144

145
      elems.push_back( _elem );
×
146
    }
147
  }
×
148
}
25,857✔
149
size_t PackageList::sizeEstimate() const
57✔
150
{
151
  size_t size = sizeof( PackageList );
57✔
152
  for ( const auto& elem : elems )
57✔
153
    size += elem.pkgname.capacity() + elem.version.capacity();
×
154
  return size;
57✔
155
}
156

157
Package::Package( const std::string& pkg_dir, Clib::ConfigElem& elem )
8,619✔
158
    : dir_( Clib::normalized_dir_form( pkg_dir ) ),
8,619✔
159
      name_( elem.remove_string( "Name" ) ),
8,619✔
160
      version_( elem.remove_string( "Version", "0" ) ),
8,619✔
161
      core_required_( "" ),
8,619✔
162
      requires_( elem, "Requires" ),
8,619✔
163
      conflicts_( elem, "Conflicts" ),
8,619✔
164
      replaces_( elem, "Replaces" ),
8,619✔
165
      provides_system_home_page_( elem.remove_bool( "ProvidesSystemHomePage", false ) )
8,619✔
166
{
167
  Clib::mklowerASCII( name_ );
8,619✔
168
  std::string tmp = elem.read_string( "CoreRequired", "0" );
8,619✔
169
  if ( isdigit( tmp[0] ) )
8,619✔
170
  {
171
    core_required_ = elem.remove_string( "CoreRequired", "" );
8,619✔
172
  }
173
  else
174
  {
175
    // Forms like CoreRequired POL095-2003-01-28 are no longer allowed.
176
    ERROR_PRINTLN(
×
177
        "Error in package {}({}):\n"
178
        "  Core version must be a semantic version (n.n.n), but got "
179
        "\"{}\".",
180
        name_, dir_, core_required_ );
×
181
    throw std::runtime_error( "Malformed CoreRequired package field" );
×
182
  }
183
}
8,619✔
184

185
std::string Package::desc() const
34✔
186
{
187
  return name() + " (" + dir() + ")";
68✔
188
}
189

190
bool Package::check_replacements() const
8,619✔
191
{
192
  bool any = false;
8,619✔
193
  for ( const auto& elem : replaces_.elems )
8,619✔
194
  {
195
    Package* found = find_package( elem.pkgname );
×
196
    if ( found != nullptr )
×
197
    {
198
      any = true;
×
199
      INFO_PRINTLN( "Package {} replaces package {}", desc(), found->desc() );
×
200
      remove_package( found );
×
201
      delete found;
×
202
      found = nullptr;
×
203
    }
204
  }
205
  return any;
8,619✔
206
}
207

208
void Package::check_dependencies() const
8,619✔
209
{
210
  if ( !core_required_.empty() )
8,619✔
211
  {
212
    if ( !( version_greater_or_equal( POL_VERSION_STR, core_required_ ) ) )
10✔
213
    {
214
      ERROR_PRINTLN(
×
215
          "Error in package {}:\n"
216
          "  Core version {} is required, but version {} is running.",
217
          desc(), core_required_, POL_VERSION_STR );
×
218
      throw std::runtime_error( "Package requires a newer core version" );
×
219
    }
220
  }
221
  for ( const auto& elem : requires_.elems )
8,619✔
222
  {
223
    Package* found = find_package( elem.pkgname );
×
224
    if ( found == nullptr )
×
225
    {
226
      ERROR_PRINTLN(
×
227
          "Error in package '{}' ({}):\n"
228
          "  Package '{}' is required, but is not installed.",
229
          name_, dir_, elem.pkgname );
×
230
      throw std::runtime_error( "Package dependency error" );
×
231
    }
232

NEW
233
    if ( !version_greater_or_equal( found->version_, elem.version ) )
×
234
    {
NEW
235
      ERROR_PRINTLN(
×
236
          "Error in package '{}' ({}):\n"
237
          "  Package '{}' version {} is required, but version {} "
238
          "was found",
NEW
239
          name_, dir_, elem.pkgname, elem.version, found->version_ );
×
NEW
240
      throw std::runtime_error( "Package dependency error" );
×
241
    }
242
  }
243
}
8,619✔
244

245
void Package::check_conflicts() const
8,619✔
246
{
247
  for ( const auto& elem : conflicts_.elems )
8,619✔
248
  {
249
    Package* found = find_package( elem.pkgname );
×
250
    if ( found != nullptr )
×
251
    {
252
      ERROR_PRINTLN(
×
253
          "Error in package {}:\n"
254
          "  Package conflicts with package {}",
255
          desc(), found->desc() );
×
256
      throw std::runtime_error( "Package dependency error" );
×
257
    }
258
  }
259
}
8,619✔
260

261
size_t Package::estimateSize() const
19✔
262
{
263
  size_t size = dir_.capacity() + name_.capacity() + version_.capacity() +
19✔
264
                +core_required_.capacity() + requires_.sizeEstimate() + conflicts_.sizeEstimate() +
19✔
265
                replaces_.sizeEstimate() + sizeof( bool ) /*provides_system_home_page_*/
19✔
266
      ;
267
  return size;
19✔
268
}
269

270
void load_package( const std::string& pkg_dir, Clib::ConfigElem& elem, bool quiet )
8,619✔
271
{
272
  std::unique_ptr<Package> pkg( new Package( pkg_dir, elem ) );
8,619✔
273
  Package* existing_pkg = find_package( pkg->name() );
8,619✔
274

275
  if ( existing_pkg != nullptr )
8,619✔
276
  {
277
    bool isgreater, isequal;
278
    compare_versions( pkg->version(), existing_pkg->version(), isgreater, isequal );
×
279
    if ( isgreater )
×
280
    {
281
      // replace existing package with newer version
282
      if ( !quiet )
×
283
        INFO_PRINTLN( "Replacing package {} version {} with version {} found in {}",
×
284
                      existing_pkg->desc(), existing_pkg->version(), pkg->version(), pkg->dir() );
×
285
      remove_package( existing_pkg );
×
286
      delete existing_pkg;
×
287
      existing_pkg = nullptr;
×
288
    }
289
    else if ( isequal )
×
290
    {
291
      ERROR_PRINTLN(
×
292
          "Error in package {}:\n"
293
          "  Package by same name already found in {}",
294
          pkg->desc(), existing_pkg->desc() );
×
295
      throw std::runtime_error( "Duplicate package found" );
×
296
    }
297
    else
298
    {
299
      // skip this package, its version is older
300
      if ( !quiet )
×
301
        INFO_PRINTLN( "Skipping package {} version {} because version {} was already found in ",
×
302
                      pkg->desc(), pkg->version(), existing_pkg->version(), existing_pkg->dir() );
×
303
      return;
×
304
    }
305
  }
306

307
  systemstate.packages.push_back( pkg.get() );
8,619✔
308
  Package* ppkg = pkg.release();
8,619✔
309
  systemstate.packages_byname.insert( PackagesByName::value_type( ppkg->name(), ppkg ) );
8,619✔
310
}
8,619✔
311

312

313
void load_packages( const std::string& basedir, bool quiet )
6,272✔
314
{
315
  std::error_code ec;
6,272✔
316
  for ( auto dir_itr = fs::recursive_directory_iterator( basedir, ec );
6,272✔
317
        dir_itr != fs::recursive_directory_iterator(); ++dir_itr )
15,618,602✔
318
  {
319
    if ( !dir_itr->is_directory() )
7,806,165✔
320
      continue;
7,797,546✔
321
    if ( auto fn = dir_itr->path().filename().string();
278,234✔
322
         !fn.empty() && ( *fn.begin() == '.' || fn == "template" ) )
278,234✔
323
    {
324
      dir_itr.disable_recursion_pending();
3✔
325
      continue;
3✔
326
    }
278,234✔
327
    const auto pkg_dir = dir_itr->path();
278,231✔
328
    const auto pkg_cfg = pkg_dir / "pkg.cfg";
278,231✔
329
    if ( !fs::exists( pkg_cfg ) )
278,231✔
330
      continue;
269,612✔
331
    Clib::ConfigFile cf( pkg_cfg.string().c_str() );
8,619✔
332
    Clib::ConfigElem elem;
8,619✔
333

334
    cf.readraw( elem );
8,619✔
335

336
    if ( ( elem.remove_bool( "Enabled" ) == true || fs::exists( pkg_dir / "enabled.pkg" ) ) &&
25,857✔
337
         !fs::exists( pkg_dir / "disabled.pkg" ) )
17,238✔
338
    {
339
      if ( !quiet )
8,619✔
340
        INFO_PRINTLN( "Loading package in {}", pkg_dir.string() );
57✔
341
      load_package( pkg_dir.string() + "/", elem, quiet );
8,619✔
342
    }
343
  }
554,115✔
344
}
6,272✔
345

346
void check_deps_for_package( const Package* pkg )
8,619✔
347
{
348
  pkg->check_dependencies();
8,619✔
349
  pkg->check_conflicts();
8,619✔
350
}
8,619✔
351

352
void replace_packages()
4,284✔
353
{
354
  bool done;
355
  do
356
  {
357
    done = true;
4,284✔
358

359
    for ( const auto& pkg : systemstate.packages )
12,903✔
360
    {
361
      bool change = pkg->check_replacements();
8,619✔
362
      if ( change )
8,619✔
363
      {
364
        done = false;
×
365
        break;
×
366
      }
367
    }
368

369
  } while ( !done );
4,284✔
370
}
4,284✔
371

372
void check_package_deps()
4,284✔
373
{
374
  for ( const auto& pkg : systemstate.packages )
12,903✔
375
    check_deps_for_package( pkg );
8,619✔
376
}
4,284✔
377

378
void load_packages( bool quiet )
1,988✔
379
{
380
  test_check_version();
1,988✔
381

382
  load_packages( "pkg/", quiet );
1,988✔
383

384
  if ( Clib::FileExists( "config/pkgroots.cfg" ) )
1,988✔
385
  {
386
    Clib::ConfigFile cf( "config/pkgroots.cfg", "PackageRoot" );
1,988✔
387
    Clib::ConfigElem elem;
1,988✔
388
    while ( cf.read( elem ) )
3,976✔
389
    {
390
      std::string dir;
1,988✔
391
      while ( elem.remove_prop( "dir", &dir ) )
3,976✔
392
      {
393
        dir = Clib::normalized_dir_form( dir );
1,988✔
394
        if ( !quiet )
1,988✔
395
          INFO_PRINTLN( "Searching for packages under {}", dir );
3✔
396
        load_packages( dir.c_str(), quiet );
1,988✔
397
      }
398
    }
1,988✔
399
  }
1,988✔
400

401
  replace_packages();
1,988✔
402

403
  check_package_deps();
1,988✔
404
  // sort pkg vector by name, so e.g. startup order is in a defined and maybe also expected order.
405
  std::sort( systemstate.packages.begin(), systemstate.packages.end(),
1,988✔
406
             []( const Package* pkg1, const Package* pkg2 )
2,267✔
407
             { return pkg1->name() < pkg2->name(); } );
2,267✔
408
}
1,988✔
409

410
bool pkgdef_split( const std::string& spec, const Package* inpkg, const Package** outpkg,
1,748✔
411
                   std::string* path )
412
{
413
  if ( spec[0] == ':' )
1,748✔
414
  {
415
    if ( spec[1] == ':' )  // '::corefile'  -- a core file
287✔
416
    {
417
      *outpkg = nullptr;
52✔
418
      *path = spec.substr( 2, std::string::npos );
52✔
419
    }
420
    else  // ':pkgname:pkgfile'  -- a packaged file
421
    {
422
      std::string::size_type second_colon = spec.find( ':', 2 );
235✔
423
      if ( second_colon != std::string::npos )
235✔
424
      {
425
        std::string pkgname = spec.substr( 1, second_colon - 1 );
235✔
426
        std::string pkgfile = spec.substr( second_colon + 1, std::string::npos );
235✔
427
        Package* dstpkg = find_package( pkgname );
235✔
428
        if ( dstpkg != nullptr )
235✔
429
        {
430
          *outpkg = dstpkg;
235✔
431
          *path = pkgfile;
235✔
432
        }
433
        else
434
        {
435
          ERROR_PRINTLN( "Unable to find package '{}'", pkgname );
×
436
          return false;
×
437
        }
438
      }
235✔
439
      else
440
      {
441
        ERROR_PRINTLN( "Poorly formed packagefile descriptor: '{}'", spec );
×
442
        return false;
×
443
      }
444
    }
445
  }
446
  else
447
  {
448
    *outpkg = inpkg;
1,461✔
449
    *path = spec;
1,461✔
450
  }
451
  return true;
1,748✔
452
}
453

454
void load_packaged_cfgs( const char* cfgname, const char* taglist,
27✔
455
                         void ( *loadentry )( const Package*, Clib::ConfigElem& ) )
456
{
457
  for ( const auto& pkg : systemstate.packages )
540✔
458
  {
459
    std::string filename = GetPackageCfgPath( pkg, cfgname );
513✔
460
    if ( Clib::FileExists( filename.c_str() ) )
513✔
461
    {
462
      Clib::ConfigFile cf( filename.c_str(), taglist );
18✔
463
      Clib::ConfigElem elem;
18✔
464

465
      while ( cf.read( elem ) )
330✔
466
      {
467
        loadentry( pkg, elem );
312✔
468
      }
469
    }
18✔
470
  }
513✔
471
}
27✔
472

473
void load_all_cfgs( const char* cfgname, const char* taglist,
6✔
474
                    void ( *loadentry )( const Package*, Clib::ConfigElem& ) )
475
{
476
  std::string filename = std::string( "config/" ) + cfgname;
6✔
477
  if ( Clib::FileExists( filename ) )
6✔
478
  {
479
    Clib::ConfigFile cf( filename.c_str(), taglist );
6✔
480
    Clib::ConfigElem elem;
6✔
481

482
    while ( cf.read( elem ) )
357✔
483
    {
484
      loadentry( nullptr, elem );
351✔
485
    }
486
  }
6✔
487
  load_packaged_cfgs( cfgname, taglist, loadentry );
6✔
488
}
6✔
489

490

491
std::string GetPackageCfgPath( const Package* pkg, const std::string& filename )
2,457✔
492
{
493
  std::string filepath;
2,457✔
494
  if ( pkg == nullptr )
2,457✔
495
  {  // If no package is sent, assume pol/config/file.xxx
496
    filepath = "config/" + filename;
37✔
497
  }
498
  else
499
  {  // ** Going to save this feature for 097 **
500
    // With packages, first try for /pkg/config/file.xxx
501
    filepath = pkg->dir() + "config/" + filename;
2,420✔
502
    if ( !Clib::FileExists( filepath ) )
2,420✔
503
    {
504
      // Lastly, assume /pkg/file.xxx
505
      filepath = pkg->dir() + filename;
2,408✔
506
    }
507
  }
508

509
  return filepath;
2,457✔
510
}
×
511
}  // namespace Pol::Plib
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

© 2026 Coveralls, Inc