From bb5e07d958e175717e9e8699b13fa53fe4312079 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 15 Jun 2014 19:55:50 +0200 Subject: [PATCH] Package: support for variants - Catalog keeps a map from variant IDs to packages - Package caches its ID - Refreshing a catalog updates existing Package instances Dropping a package from a Catalog will now warn, need to decide a real policy for this scenario. --- simgear/package/Catalog.cxx | 50 +++++++++++++++++++++++++++++-------- simgear/package/Catalog.hxx | 7 ++++-- simgear/package/Package.cxx | 38 +++++++++++++++++++++++++++- simgear/package/Package.hxx | 18 +++++++++++-- 4 files changed, 97 insertions(+), 16 deletions(-) diff --git a/simgear/package/Catalog.cxx b/simgear/package/Catalog.cxx index 9d5f4ac7..9c36d2aa 100644 --- a/simgear/package/Catalog.cxx +++ b/simgear/package/Catalog.cxx @@ -244,19 +244,47 @@ void Catalog::parseProps(const SGPropertyNode* aProps) { // copy everything except package children? m_props = new SGPropertyNode; - + + m_variantDict.clear(); // will rebuild during parse + std::set orphans; + orphans.insert(m_packages.begin(), m_packages.end()); + int nChildren = aProps->nChildren(); for (int i = 0; i < nChildren; i++) { const SGPropertyNode* pkgProps = aProps->getChild(i); if (strcmp(pkgProps->getName(), "package") == 0) { - PackageRef p = new Package(pkgProps, this); - m_packages.push_back(p); + PackageRef p = getPackageById(pkgProps->getStringValue("id")); + if (p) { + // existing package + p->updateFromProps(pkgProps); + orphans.erase(p); // not an orphan + } else { + // new package + p = new Package(pkgProps, this); + m_packages.push_back(p); + } + + string_list vars(p->variants()); + for (string_list::iterator it = vars.begin(); it != vars.end(); ++it) { + m_variantDict[*it] = p.ptr(); + } } else { SGPropertyNode* c = m_props->getChild(pkgProps->getName(), pkgProps->getIndex(), true); copyProperties(pkgProps, c); } } // of children iteration - + + if (!orphans.empty()) { + SG_LOG(SG_GENERAL, SG_WARN, "have orphan packages: will become inaccesible"); + std::set::iterator it; + for (it = orphans.begin(); it != orphans.end(); ++it) { + SG_LOG(SG_GENERAL, SG_WARN, "\torphan package:" << (*it)->qualifiedId()); + PackageList::iterator pit = std::find(m_packages.begin(), m_packages.end(), *it); + assert(pit != m_packages.end()); + m_packages.erase(pit); + } + } + if (!m_url.empty()) { if (m_url != m_props->getStringValue("url")) { // this effectively allows packages to migrate to new locations, @@ -280,13 +308,13 @@ void Catalog::parseProps(const SGPropertyNode* aProps) PackageRef Catalog::getPackageById(const std::string& aId) const { - BOOST_FOREACH(PackageRef p, m_packages) { - if (p->id() == aId) { - return p; - } - } - - return NULL; // not found + // search the variant dict here, so looking up aircraft variants + // works as expected. + PackageWeakMap::const_iterator it = m_variantDict.find(aId); + if (it == m_variantDict.end()) + return NULL; + + return it->second; } std::string Catalog::id() const diff --git a/simgear/package/Catalog.hxx b/simgear/package/Catalog.hxx index 1d06b9be..bae9c04a 100644 --- a/simgear/package/Catalog.hxx +++ b/simgear/package/Catalog.hxx @@ -51,7 +51,7 @@ typedef SGSharedPtr InstallRef; typedef std::vector PackageList; typedef std::vector CatalogList; - class Catalog : public SGReferenced +class Catalog : public SGReferenced { public: virtual ~Catalog(); @@ -140,9 +140,12 @@ private: SGPropertyNode_ptr m_props; SGPath m_installRoot; std::string m_url; - + PackageList m_packages; time_t m_retrievedTime; + + typedef std::map PackageWeakMap; + PackageWeakMap m_variantDict; // important that this is a weak-ref to Installs, // since it is only cleaned up in the Install destructor diff --git a/simgear/package/Package.cxx b/simgear/package/Package.cxx index 9c8a0b80..a5c8d341 100644 --- a/simgear/package/Package.cxx +++ b/simgear/package/Package.cxx @@ -46,6 +46,14 @@ void Package::initWithProps(const SGPropertyNode* aProps) std::string t(c->getStringValue()); m_tags.insert(boost::to_lower_copy(t)); } + + m_id = m_props->getStringValue("id"); +} + +void Package::updateFromProps(const SGPropertyNode* aProps) +{ + m_tags.clear(); + initWithProps(aProps); } bool Package::matches(const SGPropertyNode* aFilter) const @@ -133,7 +141,7 @@ InstallRef Package::existingInstall() const std::string Package::id() const { - return m_props->getStringValue("id"); + return m_id; } std::string Package::qualifiedId() const @@ -241,6 +249,34 @@ PackageList Package::dependencies() const return result; } +string_list Package::variants() const +{ + string_list result; + result.push_back(id()); + + BOOST_FOREACH(SGPropertyNode* var, m_props->getChildren("variant")) { + result.push_back(var->getStringValue("id")); + } + + return result; +} + +std::string Package::nameForVariant(const std::string& vid) const +{ + if (vid == id()) { + return name(); + } + + BOOST_FOREACH(SGPropertyNode* var, m_props->getChildren("variant")) { + if (vid == var->getStringValue("id")) { + return var->getStringValue("name"); + } + } + + + throw sg_exception("Unknow variant +" + vid + " in package " + id()); +} + } // of namespace pkg } // of namespace simgear diff --git a/simgear/package/Package.hxx b/simgear/package/Package.hxx index 56edabc4..2c2ce556 100644 --- a/simgear/package/Package.hxx +++ b/simgear/package/Package.hxx @@ -60,6 +60,12 @@ public: std::string id() const; + /** + * Variant IDs. Note the primary ID will always be included as + * variants()[0], to simplify enumerating all variants + */ + string_list variants() const; + /** * Fully-qualified ID, including our catalog'd ID */ @@ -70,7 +76,12 @@ public: * although this is not ruled out for the future. */ std::string name() const; - + + /** + * Human readable name of a variant + */ + std::string nameForVariant(const std::string& vid) const; + /** * syntactic sugar to get the localised description */ @@ -118,10 +129,13 @@ private: Package(const SGPropertyNode* aProps, CatalogRef aCatalog); void initWithProps(const SGPropertyNode* aProps); - + + void updateFromProps(const SGPropertyNode* aProps); + std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const; SGPropertyNode_ptr m_props; + std::string m_id; string_set m_tags; CatalogRef m_catalog; }; -- 2.39.5