23
#include "PreCompiled.h"
26
# include <boost/core/ignore_unused.hpp>
31
#include <xercesc/framework/LocalFileFormatTarget.hpp>
32
#include <xercesc/framework/LocalFileInputSource.hpp>
33
#include <xercesc/framework/MemBufInputSource.hpp>
34
#include <xercesc/sax/HandlerBase.hpp>
36
#include "App/Application.h"
37
#include "App/Expression.h"
38
#include "Base/XMLTools.h"
60
namespace fs = boost::filesystem;
61
XERCES_CPP_NAMESPACE_USE
63
namespace MetadataInternal
65
class XMLErrorHandler: public HandlerBase
67
void warning(const SAXParseException& toCatch) override
70
boost::ignore_unused(toCatch);
73
void error(const SAXParseException& toCatch) override
75
std::stringstream message;
76
message << "Error at file \"" << StrX(toCatch.getSystemId()) << "\", line "
77
<< toCatch.getLineNumber() << ", column " << toCatch.getColumnNumber()
78
<< "\n Message: " << StrX(toCatch.getMessage()) << std::endl;
79
throw Base::XMLBaseException(message.str());
82
void fatalError(const SAXParseException& toCatch) override
84
std::stringstream message;
85
message << "Fatal error at file \"" << StrX(toCatch.getSystemId()) << "\", line "
86
<< toCatch.getLineNumber() << ", column " << toCatch.getColumnNumber()
87
<< "\n Message: " << StrX(toCatch.getMessage()) << std::endl;
88
throw Base::XMLBaseException(message.str());
93
Metadata::Metadata(const fs::path& metadataFile)
96
#if defined(FC_OS_WIN32)
98
LocalFileInputSource(reinterpret_cast<const XMLCh*>(metadataFile.wstring().c_str()));
100
auto source = LocalFileInputSource(XUTF8Str(metadataFile.string().c_str()).unicodeForm());
102
loadFromInputSource(source);
109
Metadata::Metadata(const DOMNode* domNode, int format)
112
auto element = dynamic_cast<const DOMElement*>(domNode);
116
parseVersion1(element);
119
throw Base::XMLBaseException(
120
"package.xml format version is not supported by this version of FreeCAD");
125
App::Metadata::Metadata(const std::string& rawData)
128
MemBufInputSource buffer(
129
reinterpret_cast<const XMLByte*>(rawData.c_str()),
131
"raw data (in memory)");
132
loadFromInputSource(buffer);
135
void Metadata::loadFromInputSource(const InputSource& source)
138
XMLPlatformUtils::Initialize();
140
_parser = std::make_shared<XercesDOMParser>();
141
_parser->setValidationScheme(XercesDOMParser::Val_Never);
142
_parser->setDoNamespaces(true);
144
auto errHandler = std::make_unique<MetadataInternal::XMLErrorHandler>();
145
_parser->setErrorHandler(errHandler.get());
147
_parser->parse(source);
149
auto doc = _parser->getDocument();
150
_dom = doc->getDocumentElement();
152
auto rootTagName = StrXUTF8(_dom->getTagName()).str;
153
if (rootTagName != "package") {
154
throw Base::XMLBaseException(
155
"Malformed package.xml document: Root <package> group not found");
157
auto formatVersion = XMLString::parseInt(_dom->getAttribute(XUTF8Str("format").unicodeForm()));
158
switch (formatVersion) {
163
throw Base::XMLBaseException(
164
"package.xml format version is not supported by this version of FreeCAD");
168
Metadata::~Metadata() = default;
170
std::string Metadata::name() const
175
std::string Metadata::type() const
180
Meta::Version Metadata::version() const
185
std::string App::Metadata::date() const
190
std::string Metadata::description() const
195
std::vector<Meta::Contact> Metadata::maintainer() const
200
std::vector<Meta::License> Metadata::license() const
205
std::vector<Meta::Url> Metadata::url() const
210
std::vector<Meta::Contact> Metadata::author() const
215
std::vector<Meta::Dependency> Metadata::depend() const
220
std::vector<Meta::Dependency> Metadata::conflict() const
225
std::vector<Meta::Dependency> Metadata::replace() const
230
std::vector<std::string> Metadata::tag() const
235
fs::path Metadata::icon() const
240
std::string Metadata::classname() const
245
boost::filesystem::path Metadata::subdirectory() const
247
return _subdirectory;
250
std::vector<fs::path> Metadata::file() const
255
Meta::Version Metadata::freecadmin() const
260
Meta::Version Metadata::freecadmax() const
265
Meta::Version Metadata::pythonmin() const
270
std::multimap<std::string, Metadata> Metadata::content() const
275
std::vector<Meta::GenericMetadata> Metadata::operator[](const std::string& tag) const
277
std::vector<Meta::GenericMetadata> returnValue;
278
auto range = _genericMetadata.equal_range(tag);
279
for (auto item = range.first; item != range.second; ++item) {
280
returnValue.push_back(item->second);
285
XERCES_CPP_NAMESPACE::DOMElement* Metadata::dom() const
290
void Metadata::setName(const std::string& name)
292
std::string invalidCharacters = "/\\?%*:|\"<>";
293
if (_name.find_first_of(invalidCharacters) != std::string::npos) {
294
throw Base::RuntimeError("Name cannot contain any of: " + invalidCharacters);
299
void Metadata::setType(const std::string& type)
304
void Metadata::setVersion(const Meta::Version& version)
309
void App::Metadata::setDate(const std::string& date)
314
void Metadata::setDescription(const std::string& description)
316
_description = description;
319
void Metadata::addMaintainer(const Meta::Contact& maintainer)
321
_maintainer.push_back(maintainer);
324
void Metadata::addLicense(const Meta::License& license)
326
_license.push_back(license);
329
void Metadata::addUrl(const Meta::Url& url)
334
void Metadata::addAuthor(const Meta::Contact& author)
336
_author.push_back(author);
339
void Metadata::addDepend(const Meta::Dependency& dep)
341
_depend.push_back(dep);
344
void Metadata::addConflict(const Meta::Dependency& dep)
346
_conflict.push_back(dep);
349
void Metadata::addReplace(const Meta::Dependency& dep)
351
_replace.push_back(dep);
354
void Metadata::addTag(const std::string& tag)
359
void Metadata::setIcon(const fs::path& path)
364
void Metadata::setClassname(const std::string& name)
369
void Metadata::setSubdirectory(const boost::filesystem::path& path)
371
_subdirectory = path;
374
void Metadata::addFile(const fs::path& path)
376
_file.push_back(path);
379
void Metadata::addContentItem(const std::string& tag, const Metadata& item)
381
_content.insert(std::make_pair(tag, item));
384
void Metadata::setFreeCADMin(const Meta::Version& version)
386
_freecadmin = version;
389
void Metadata::setPythonMin(const Meta::Version& version)
391
_pythonmin = version;
394
void Metadata::setFreeCADMax(const Meta::Version& version)
396
_freecadmax = version;
399
void Metadata::addGenericMetadata(const std::string& tag,
400
const Meta::GenericMetadata& genericMetadata)
402
_genericMetadata.insert(std::make_pair(tag, genericMetadata));
405
void Metadata::removeContentItem(const std::string& tag, const std::string& itemName)
407
auto tagRange = _content.equal_range(tag);
409
std::find_if(tagRange.first, tagRange.second, [&itemName](const auto& check) -> bool {
410
return itemName == check.second.name();
412
if (foundItem != tagRange.second) {
413
_content.erase(foundItem);
417
void Metadata::removeMaintainer(const Meta::Contact& maintainer)
419
auto new_end = std::remove(_maintainer.begin(), _maintainer.end(), maintainer);
420
_maintainer.erase(new_end, _maintainer.end());
423
void Metadata::removeLicense(const Meta::License& license)
425
auto new_end = std::remove(_license.begin(), _license.end(), license);
426
_license.erase(new_end, _license.end());
429
void Metadata::removeUrl(const Meta::Url& url)
431
auto new_end = std::remove(_url.begin(), _url.end(), url);
432
_url.erase(new_end, _url.end());
435
void Metadata::removeAuthor(const Meta::Contact& author)
437
auto new_end = std::remove(_author.begin(), _author.end(), author);
438
_author.erase(new_end, _author.end());
441
void Metadata::removeDepend(const Meta::Dependency& dep)
444
for (const auto& check : _depend) {
450
throw Base::RuntimeError("No match found for dependency to remove");
452
auto new_end = std::remove(_depend.begin(), _depend.end(), dep);
453
_depend.erase(new_end, _depend.end());
456
void Metadata::removeConflict(const Meta::Dependency& dep)
458
auto new_end = std::remove(_conflict.begin(), _conflict.end(), dep);
459
_conflict.erase(new_end, _conflict.end());
462
void Metadata::removeReplace(const Meta::Dependency& dep)
464
auto new_end = std::remove(_replace.begin(), _replace.end(), dep);
465
_replace.erase(new_end, _replace.end());
468
void Metadata::removeTag(const std::string& tag)
470
auto new_end = std::remove(_tag.begin(), _tag.end(), tag);
471
_tag.erase(new_end, _tag.end());
474
void Metadata::removeFile(const boost::filesystem::path& path)
476
auto new_end = std::remove(_file.begin(), _file.end(), path);
477
_file.erase(new_end, _file.end());
481
void Metadata::clearContent()
486
void Metadata::clearMaintainer()
491
void Metadata::clearLicense()
496
void Metadata::clearUrl()
501
void Metadata::clearAuthor()
506
void Metadata::clearDepend()
511
void Metadata::clearConflict()
516
void Metadata::clearReplace()
521
void Metadata::clearTag()
526
void Metadata::clearFile()
532
DOMElement* appendSimpleXMLNode(DOMElement* baseNode, const std::string& nodeName,
533
const std::string& nodeContents)
536
if (nodeContents.empty()) {
539
auto doc = baseNode->getOwnerDocument();
540
DOMElement* namedElement = doc->createElement(XUTF8Str(nodeName.c_str()).unicodeForm());
541
baseNode->appendChild(namedElement);
542
DOMText* namedNode = doc->createTextNode(XUTF8Str(nodeContents.c_str()).unicodeForm());
543
namedElement->appendChild(namedNode);
547
void addAttribute(DOMElement* node, const std::string& key, const std::string& value)
552
node->setAttribute(XUTF8Str(key.c_str()).unicodeForm(), XUTF8Str(value.c_str()).unicodeForm());
555
void addAttribute(DOMElement* node, const std::string& key, bool value)
558
node->setAttribute(XUTF8Str(key.c_str()).unicodeForm(), XUTF8Str("True").unicodeForm());
561
node->setAttribute(XUTF8Str(key.c_str()).unicodeForm(), XUTF8Str("False").unicodeForm());
565
void addAttribute(DOMElement* node, const std::string& key, Meta::DependencyType value)
569
std::string stringified("automatic");
571
case Meta::DependencyType::automatic:
572
stringified = "automatic";
574
case Meta::DependencyType::internal:
575
stringified = "internal";
577
case Meta::DependencyType::addon:
578
stringified = "addon";
580
case Meta::DependencyType::python:
581
stringified = "python";
584
node->setAttribute(XUTF8Str(key.c_str()).unicodeForm(),
585
XUTF8Str(stringified.c_str()).unicodeForm());
588
void addDependencyNode(DOMElement* root, const std::string& name, const Meta::Dependency& depend)
590
auto element = appendSimpleXMLNode(root, name, depend.package);
592
addAttribute(element, "version_lt", depend.version_lt);
593
addAttribute(element, "version_lte", depend.version_lte);
594
addAttribute(element, "version_eq", depend.version_eq);
595
addAttribute(element, "version_gte", depend.version_gte);
596
addAttribute(element, "version_gt", depend.version_gt);
597
addAttribute(element, "condition", depend.condition);
598
addAttribute(element, "optional", depend.optional);
599
addAttribute(element, "type", depend.dependencyType);
603
void Metadata::write(const fs::path& file) const
605
DOMImplementation* impl =
606
DOMImplementationRegistry::getDOMImplementation(XUTF8Str("Core LS").unicodeForm());
608
DOMDocument* doc = impl->createDocument(nullptr, XUTF8Str("package").unicodeForm(), nullptr);
609
DOMElement* root = doc->getDocumentElement();
610
root->setAttribute(XUTF8Str("format").unicodeForm(), XUTF8Str("1").unicodeForm());
611
root->setAttribute(XUTF8Str("xmlns").unicodeForm(),
612
XUTF8Str("https://wiki.freecad.org/Package_Metadata").unicodeForm());
614
appendToElement(root);
616
DOMLSSerializer* theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer();
617
DOMConfiguration* config = theSerializer->getDomConfig();
618
if (config->canSetParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true)) {
619
config->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
623
if (config->canSetParameter(XMLUni::fgDOMWRTSplitCdataSections, true)) {
624
config->setParameter(XMLUni::fgDOMWRTSplitCdataSections, true);
627
if (config->canSetParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true)) {
628
config->setParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true);
632
XMLFormatTarget* myFormTarget = new LocalFileFormatTarget(file.string().c_str());
633
DOMLSOutput* theOutput = ((DOMImplementationLS*)impl)->createLSOutput();
635
theOutput->setByteStream(myFormTarget);
636
theSerializer->write(doc, theOutput);
638
theOutput->release();
639
theSerializer->release();
642
catch (const XMLException& toCatch) {
643
char* message = XMLString::transcode(toCatch.getMessage());
644
std::string what = message;
645
XMLString::release(&message);
646
throw Base::XMLBaseException(what);
648
catch (const DOMException& toCatch) {
649
char* message = XMLString::transcode(toCatch.getMessage());
650
std::string what = message;
651
XMLString::release(&message);
652
throw Base::XMLBaseException(what);
658
bool Metadata::satisfies(const Meta::Dependency& dep)
660
if (dep.package != _name) {
665
if (!dep.condition.empty()) {
666
auto injectedString = dep.condition;
667
std::map<std::string, std::string> replacements;
668
std::map<std::string, std::string>& config = App::Application::Config();
669
replacements.insert(std::make_pair("$BuildVersionMajor", config["BuildVersionMajor"]));
670
replacements.insert(std::make_pair("$BuildVersionMinor", config["BuildVersionMinor"]));
671
replacements.insert(std::make_pair("$BuildVersionMinor", config["BuildVersionPoint"]));
672
replacements.insert(std::make_pair("$BuildRevision", config["BuildRevision"]));
673
for (const auto& replacement : replacements) {
674
auto pos = injectedString.find(replacement.first);
675
while (pos != std::string::npos) {
676
injectedString.replace(pos, replacement.first.length(), replacement.second);
677
pos = injectedString.find(replacement.first);
680
auto parsedExpression = App::Expression::parse(nullptr, dep.condition);
681
auto result = parsedExpression->eval();
682
if (!boost::any_cast<bool>(result->getValueAsAny())) {
687
if (!dep.version_eq.empty()) {
688
return _version == Meta::Version(dep.version_eq);
692
if (!dep.version_lt.empty()) {
693
if (!(_version < Meta::Version(dep.version_lt))) {
697
if (!dep.version_lte.empty()) {
698
if (!(_version <= Meta::Version(dep.version_lt))) {
702
if (!dep.version_gt.empty()) {
703
if (!(_version > Meta::Version(dep.version_lt))) {
707
if (!dep.version_gte.empty()) {
708
if (!(_version >= Meta::Version(dep.version_lt))) {
715
bool Metadata::supportsCurrentFreeCAD() const
717
static auto fcVersion = Meta::Version();
718
if (fcVersion == Meta::Version()) {
719
std::map<std::string, std::string>& config = App::Application::Config();
720
std::stringstream ss;
721
ss << config["BuildVersionMajor"] << "." << config["BuildVersionMinor"] << "."
722
<< config["BuildVersionPoint"] << "."
723
<< (config["BuildRevision"].empty() ? "0" : config["BuildRevision"]);
724
fcVersion = Meta::Version(ss.str());
727
if (_freecadmin != Meta::Version() && _freecadmin > fcVersion) {
730
if (_freecadmax != Meta::Version() && _freecadmax < fcVersion) {
736
void Metadata::appendToElement(DOMElement* root) const
738
appendSimpleXMLNode(root, "name", _name);
739
appendSimpleXMLNode(root, "type", _type);
740
appendSimpleXMLNode(root, "description", _description);
741
if (_version != Meta::Version()) {
743
appendSimpleXMLNode(root, "version", _version.str());
746
if (!_date.empty()) {
747
appendSimpleXMLNode(root, "date", _date);
750
for (const auto& maintainer : _maintainer) {
751
auto element = appendSimpleXMLNode(root, "maintainer", maintainer.name);
753
addAttribute(element, "email", maintainer.email);
757
for (const auto& license : _license) {
758
auto element = appendSimpleXMLNode(root, "license", license.name);
760
addAttribute(element, "file", license.file.string());
764
if (_freecadmin != Meta::Version()) {
765
appendSimpleXMLNode(root, "freecadmin", _freecadmin.str());
768
if (_freecadmax != Meta::Version()) {
769
appendSimpleXMLNode(root, "freecadmax", _freecadmax.str());
772
if (_pythonmin != Meta::Version()) {
773
appendSimpleXMLNode(root, "pythonmin", _pythonmin.str());
776
for (const auto& url : _url) {
777
auto element = appendSimpleXMLNode(root, "url", url.location);
779
std::string typeAsString("website");
781
case Meta::UrlType::website:
782
typeAsString = "website";
784
case Meta::UrlType::repository:
785
typeAsString = "repository";
787
case Meta::UrlType::bugtracker:
788
typeAsString = "bugtracker";
790
case Meta::UrlType::readme:
791
typeAsString = "readme";
793
case Meta::UrlType::documentation:
794
typeAsString = "documentation";
796
case Meta::UrlType::discussion:
797
typeAsString = "discussion";
800
addAttribute(element, "type", typeAsString);
801
if (url.type == Meta::UrlType::repository) {
802
addAttribute(element, "branch", url.branch);
807
for (const auto& author : _author) {
808
auto element = appendSimpleXMLNode(root, "author", author.name);
810
addAttribute(element, "email", author.email);
814
for (const auto& depend : _depend) {
815
addDependencyNode(root, "depend", depend);
818
for (const auto& conflict : _conflict) {
819
addDependencyNode(root, "conflict", conflict);
822
for (const auto& replace : _replace) {
823
addDependencyNode(root, "replace", replace);
826
for (const auto& tag : _tag) {
827
appendSimpleXMLNode(root, "tag", tag);
830
appendSimpleXMLNode(root, "icon", _icon.string());
832
appendSimpleXMLNode(root, "classname", _classname);
834
appendSimpleXMLNode(root, "subdirectory", _subdirectory.string());
836
for (const auto& file : _file) {
837
appendSimpleXMLNode(root, "file", file.string());
840
for (const auto& md : _genericMetadata) {
841
auto element = appendSimpleXMLNode(root, md.first, md.second.contents);
842
for (const auto& attr : md.second.attributes) {
843
addAttribute(element, attr.first, attr.second);
847
if (!_content.empty()) {
848
auto doc = root->getOwnerDocument();
849
DOMElement* contentRootElement = doc->createElement(XUTF8Str("content").unicodeForm());
850
root->appendChild(contentRootElement);
851
for (const auto& content : _content) {
852
DOMElement* contentElement =
853
doc->createElement(XUTF8Str(content.first.c_str()).unicodeForm());
854
contentRootElement->appendChild(contentElement);
855
content.second.appendToElement(contentElement);
861
void Metadata::parseVersion1(const DOMNode* startNode)
863
auto children = startNode->getChildNodes();
865
for (XMLSize_t i = 0; i < children->getLength(); ++i) {
866
auto child = children->item(i);
867
auto element = dynamic_cast<const DOMElement*>(child);
872
auto tag = element->getNodeName();
873
auto tagString = StrXUTF8(tag).str;
875
if (tagString == "name") {
876
_name = StrXUTF8(element->getTextContent()).str;
878
else if (tagString == "type") {
879
_type = StrXUTF8(element->getTextContent()).str;
881
else if (tagString == "version") {
882
_version = Meta::Version(StrXUTF8(element->getTextContent()).str);
884
else if (tagString == "date") {
885
_date = StrXUTF8(element->getTextContent()).str;
887
else if (tagString == "description") {
888
_description = StrXUTF8(element->getTextContent()).str;
890
else if (tagString == "maintainer") {
891
_maintainer.emplace_back(element);
893
else if (tagString == "license") {
894
_license.emplace_back(element);
896
else if (tagString == "freecadmin") {
897
_freecadmin = Meta::Version(StrXUTF8(element->getTextContent()).str);
899
else if (tagString == "freecadmax") {
900
_freecadmax = Meta::Version(StrXUTF8(element->getTextContent()).str);
902
else if (tagString == "pythonmin") {
903
_pythonmin = Meta::Version(StrXUTF8(element->getTextContent()).str);
905
else if (tagString == "url") {
906
_url.emplace_back(element);
908
else if (tagString == "author") {
909
_author.emplace_back(element);
911
else if (tagString == "depend") {
912
_depend.emplace_back(element);
914
else if (tagString == "conflict") {
915
_conflict.emplace_back(element);
917
else if (tagString == "replace") {
918
_replace.emplace_back(element);
920
else if (tagString == "tag") {
921
_tag.emplace_back(StrXUTF8(element->getTextContent()).str);
923
else if (tagString == "file") {
924
_file.emplace_back(StrXUTF8(element->getTextContent()).str);
926
else if (tagString == "classname") {
927
_classname = StrXUTF8(element->getTextContent()).str;
929
else if (tagString == "subdirectory") {
930
_subdirectory = StrXUTF8(element->getTextContent()).str;
932
else if (tagString == "icon") {
933
_icon = fs::path(StrXUTF8(element->getTextContent()).str);
935
else if (tagString == "content") {
936
parseContentNodeVersion1(element);
941
auto nodeChildren = element->getChildNodes();
942
bool hasGrandchildren = false;
943
for (XMLSize_t j = 0; j < nodeChildren->getLength() && !hasGrandchildren; ++j) {
944
if (nodeChildren->item(j)->getChildNodes()->getLength() > 0) {
945
hasGrandchildren = true;
948
if (!hasGrandchildren) {
949
_genericMetadata.insert(std::make_pair(tagString, Meta::GenericMetadata(element)));
955
void Metadata::parseContentNodeVersion1(const DOMElement* contentNode)
957
auto children = contentNode->getChildNodes();
958
for (XMLSize_t i = 0; i < children->getLength(); ++i) {
959
auto child = dynamic_cast<const DOMElement*>(children->item(i));
961
auto tag = StrXUTF8(child->getTagName()).str;
962
_content.insert(std::make_pair(tag, Metadata(child, 1)));
967
Meta::Contact::Contact(std::string name, std::string email)
968
: name(std::move(name)),
969
email(std::move(email))
974
Meta::Contact::Contact(const XERCES_CPP_NAMESPACE::DOMElement* elem)
979
auto emailAttribute = elem->getAttribute(XUTF8Str("email").unicodeForm());
980
name = StrXUTF8(elem->getTextContent()).str;
981
email = StrXUTF8(emailAttribute).str;
984
bool App::Meta::Contact::operator==(const Contact& rhs) const
986
return name == rhs.name && email == rhs.email;
989
Meta::License::License(std::string name, fs::path file)
990
: name(std::move(name)),
991
file(std::move(file))
996
Meta::License::License(const XERCES_CPP_NAMESPACE::DOMElement* elem)
1001
auto fileAttribute = elem->getAttribute(XUTF8Str("file").unicodeForm());
1002
if (XMLString::stringLen(fileAttribute) > 0) {
1003
file = fs::path(StrXUTF8(fileAttribute).str);
1005
name = StrXUTF8(elem->getTextContent()).str;
1008
bool App::Meta::License::operator==(const License& rhs) const
1010
return name == rhs.name && file == rhs.file;
1013
App::Meta::Url::Url()
1015
type(App::Meta::UrlType::website)
1018
Meta::Url::Url(std::string location, UrlType type)
1019
: location(std::move(location)),
1025
Meta::Url::Url(const XERCES_CPP_NAMESPACE::DOMElement* elem)
1030
auto typeAttribute = StrXUTF8(elem->getAttribute(XUTF8Str("type").unicodeForm())).str;
1031
if (typeAttribute.empty() || typeAttribute == "website") {
1032
type = UrlType::website;
1034
else if (typeAttribute == "bugtracker") {
1035
type = UrlType::bugtracker;
1037
else if (typeAttribute == "repository") {
1038
type = UrlType::repository;
1040
else if (typeAttribute == "readme") {
1041
type = UrlType::readme;
1043
else if (typeAttribute == "documentation") {
1044
type = UrlType::documentation;
1046
else if (typeAttribute == "discussion") {
1047
type = UrlType::discussion;
1050
type = UrlType::website;
1053
if (type == UrlType::repository) {
1054
branch = StrXUTF8(elem->getAttribute(XUTF8Str("branch").unicodeForm())).str;
1056
location = StrXUTF8(elem->getTextContent()).str;
1059
bool App::Meta::Url::operator==(const Url& rhs) const
1061
if (type == UrlType::repository && branch != rhs.branch) {
1064
return type == rhs.type && location == rhs.location;
1067
App::Meta::Dependency::Dependency()
1069
dependencyType(App::Meta::DependencyType::automatic)
1072
App::Meta::Dependency::Dependency(std::string pkg)
1073
: package(std::move(pkg)),
1075
dependencyType(App::Meta::DependencyType::automatic)
1078
Meta::Dependency::Dependency(const XERCES_CPP_NAMESPACE::DOMElement* elem)
1080
version_lt = StrXUTF8(elem->getAttribute(XUTF8Str("version_lt").unicodeForm())).str;
1081
version_lte = StrXUTF8(elem->getAttribute(XUTF8Str("version_lte").unicodeForm())).str;
1082
version_eq = StrXUTF8(elem->getAttribute(XUTF8Str("version_eq").unicodeForm())).str;
1083
version_gte = StrXUTF8(elem->getAttribute(XUTF8Str("version_gte").unicodeForm())).str;
1084
version_gt = StrXUTF8(elem->getAttribute(XUTF8Str("version_gt").unicodeForm())).str;
1085
condition = StrXUTF8(elem->getAttribute(XUTF8Str("condition").unicodeForm())).str;
1086
std::string opt_string = StrXUTF8(elem->getAttribute(XUTF8Str("optional").unicodeForm())).str;
1087
if (opt_string == "true"
1088
|| opt_string == "True") {
1094
std::string type_string = StrXUTF8(elem->getAttribute(XUTF8Str("type").unicodeForm())).str;
1095
if (type_string == "automatic" || type_string.empty()) {
1096
dependencyType = Meta::DependencyType::automatic;
1098
else if (type_string == "addon") {
1099
dependencyType = Meta::DependencyType::addon;
1101
else if (type_string == "internal") {
1102
dependencyType = Meta::DependencyType::internal;
1104
else if (type_string == "python") {
1105
dependencyType = Meta::DependencyType::python;
1108
auto message = std::string("Invalid dependency type \"") + type_string + "\"";
1109
throw Base::XMLBaseException(message);
1112
package = StrXUTF8(elem->getTextContent()).str;
1115
bool App::Meta::Dependency::operator==(const Dependency& rhs) const
1117
return package == rhs.package && version_lt == rhs.version_lt && version_lte == rhs.version_lte
1118
&& version_eq == rhs.version_eq && version_gte == rhs.version_gte
1119
&& version_gt == rhs.version_gt && condition == rhs.condition && optional == rhs.optional
1120
&& dependencyType == rhs.dependencyType;
1123
Meta::Version::Version() = default;
1125
Meta::Version::Version(int major, int minor, int patch, std::string suffix)
1129
suffix(std::move(suffix))
1132
Meta::Version::Version(const std::string& versionString)
1134
std::istringstream stream(versionString);
1135
char separator {'.'};
1138
stream >> separator;
1144
stream >> separator;
1154
std::string Meta::Version::str() const
1156
if (*this == Meta::Version()) {
1159
std::ostringstream stream;
1160
stream << major << "." << minor << "." << patch << suffix;
1161
return stream.str();
1164
bool Meta::Version::operator<(const Version& rhs) const
1166
return std::tie(major, minor, patch, suffix)
1167
< std::tie(rhs.major, rhs.minor, rhs.patch, rhs.suffix);
1170
bool Meta::Version::operator>(const Version& rhs) const
1172
return std::tie(major, minor, patch, suffix)
1173
> std::tie(rhs.major, rhs.minor, rhs.patch, rhs.suffix);
1176
bool Meta::Version::operator<=(const Version& rhs) const
1178
return std::tie(major, minor, patch, suffix)
1179
<= std::tie(rhs.major, rhs.minor, rhs.patch, rhs.suffix);
1182
bool Meta::Version::operator>=(const Version& rhs) const
1184
return std::tie(major, minor, patch, suffix)
1185
>= std::tie(rhs.major, rhs.minor, rhs.patch, rhs.suffix);
1188
bool Meta::Version::operator==(const Version& rhs) const
1190
return std::tie(major, minor, patch, suffix)
1191
== std::tie(rhs.major, rhs.minor, rhs.patch, rhs.suffix);
1194
bool Meta::Version::operator!=(const Version& rhs) const
1196
return std::tie(major, minor, patch, suffix)
1197
!= std::tie(rhs.major, rhs.minor, rhs.patch, rhs.suffix);
1200
Meta::GenericMetadata::GenericMetadata(const XERCES_CPP_NAMESPACE::DOMElement* elem)
1202
contents = StrXUTF8(elem->getTextContent()).str;
1203
for (XMLSize_t i = 0; i < elem->getAttributes()->getLength(); ++i) {
1204
auto attr = elem->getAttributes()->item(i);
1206
std::make_pair(StrXUTF8(attr->getNodeName()).str, StrXUTF8(attr->getTextContent()).str));
1210
App::Meta::GenericMetadata::GenericMetadata(std::string contents)
1211
: contents(std::move(contents))