netgen/libsrc/core/version.hpp
Monty Montgomery e9eae568ff Don't fail silently in VersionInfo(), print useful message
Having version.hpp throw an exception when built against a malformed
version number (due to, eg, not having the git tag available in an
automated package build from source bundle) results in _init_ failing
during an otherwise apparently successful dlopen(), as well as the
netgen-mesher executable crashing before hitting main().

This patch both forces an abort and prints a helpful message alerting
the builder/user that something went wrong instead of handing over
either a coredump or a weirdly malfunctioning library with no apparent
cause.  Hopefully this will avoid a repeat of automated Fedora builds
shipping nonfunctional Netgen RPMs for several years!
2022-05-14 23:37:22 -04:00

111 lines
3.7 KiB
C++

#ifndef NETGEN_CORE_VERSION_HPP
#define NETGEN_CORE_VERSION_HPP
#include <iostream>
#include <string>
#include <tuple>
#include "exception.hpp"
#include "ngcore_api.hpp"
namespace ngcore
{
class VersionInfo
{
private:
size_t mayor_{}, minor_{}, release{}, patch{};
std::string git_hash{};
public:
VersionInfo() = default;
VersionInfo(std::string vstring)
{
std::string save = vstring;
try {
minor_ = release = patch = 0;
git_hash = "";
if(vstring.substr(0,1) == "v")
vstring = vstring.substr(1,vstring.size()-1);
auto dot = vstring.find('.');
mayor_ = std::stoi(vstring.substr(0,dot));
if(dot == size_t(-1)) vstring = "";
else vstring = vstring.substr(dot+1, vstring.size()-dot-1);
if(!vstring.empty())
{
dot = vstring.find('.');
minor_ = std::stoi(vstring.substr(0,dot));
if (dot == size_t(-1)) vstring = "";
else vstring = vstring.substr(dot+1, vstring.size()-dot-1);
if(!vstring.empty())
{
dot = vstring.find('-');
release = std::stoi(vstring.substr(0,dot));
if(dot == size_t(-1)) vstring = "";
else vstring = vstring.substr(dot+1,vstring.size()-dot-1);
if(!vstring.empty())
{
dot = vstring.find('-');
patch = std::stoi(vstring.substr(0,dot));
if(dot == size_t(-1)) vstring = "";
else vstring = vstring.substr(dot+1, vstring.size()-dot-1);
if(!vstring.empty())
git_hash = vstring;
}
}
}
} catch(...) {
std::cerr << "Malformed NETGEN_VERSION (" << save <<"\n";
std::cerr << "Micompiled/mispackaged Netgen library\n";
abort();
}
}
VersionInfo(const char* cstr) : VersionInfo(std::string(cstr)) { }
std::string to_string() const
{ std::string vstring = "v" + std::to_string(mayor_);
if(minor_ || release || patch || !git_hash.empty())
{
vstring += "." + std::to_string(minor_);
if(release || patch || !git_hash.empty())
{
vstring += "." + std::to_string(release);
if(patch || !git_hash.empty())
{
vstring += "-" + std::to_string(patch);
if(!git_hash.empty())
vstring += "-" + git_hash;
}
}
}
return vstring;
}
bool operator <(const VersionInfo& other) const
{
return std::tie(mayor_, minor_, release, patch) <
std::tie(other.mayor_, other.minor_, other.release, other.patch);
}
bool operator ==(const VersionInfo& other) const
{
return mayor_ == other.mayor_ && minor_ == other.minor_ && release == other.release
&& patch == other.patch;
}
bool operator !=(const VersionInfo& other) const
{
return !(*this==other);
}
bool operator >(const VersionInfo& other) const { return other < (*this); }
bool operator <=(const VersionInfo& other) const { return !((*this) > other); }
bool operator >=(const VersionInfo& other) const { return !((*this) < other); }
};
inline std::ostream& operator << (std::ostream& ost, const VersionInfo& version)
{
return ost << version.to_string();
}
NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library);
NGCORE_API const std::map<std::string, VersionInfo>& GetLibraryVersions();
NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version);
} // namespace ngcore
#endif // NETGEN_CORE_VERSION_HPP