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.
This commit is contained in:
James Turner 2014-06-15 19:55:50 +02:00
parent 5024b62c0a
commit bb5e07d958
4 changed files with 97 additions and 16 deletions

View File

@ -245,18 +245,46 @@ void Catalog::parseProps(const SGPropertyNode* aProps)
// copy everything except package children? // copy everything except package children?
m_props = new SGPropertyNode; m_props = new SGPropertyNode;
m_variantDict.clear(); // will rebuild during parse
std::set<PackageRef> orphans;
orphans.insert(m_packages.begin(), m_packages.end());
int nChildren = aProps->nChildren(); int nChildren = aProps->nChildren();
for (int i = 0; i < nChildren; i++) { for (int i = 0; i < nChildren; i++) {
const SGPropertyNode* pkgProps = aProps->getChild(i); const SGPropertyNode* pkgProps = aProps->getChild(i);
if (strcmp(pkgProps->getName(), "package") == 0) { if (strcmp(pkgProps->getName(), "package") == 0) {
PackageRef p = new Package(pkgProps, this); 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); 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 { } else {
SGPropertyNode* c = m_props->getChild(pkgProps->getName(), pkgProps->getIndex(), true); SGPropertyNode* c = m_props->getChild(pkgProps->getName(), pkgProps->getIndex(), true);
copyProperties(pkgProps, c); copyProperties(pkgProps, c);
} }
} // of children iteration } // of children iteration
if (!orphans.empty()) {
SG_LOG(SG_GENERAL, SG_WARN, "have orphan packages: will become inaccesible");
std::set<PackageRef>::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.empty()) {
if (m_url != m_props->getStringValue("url")) { if (m_url != m_props->getStringValue("url")) {
// this effectively allows packages to migrate to new locations, // 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 PackageRef Catalog::getPackageById(const std::string& aId) const
{ {
BOOST_FOREACH(PackageRef p, m_packages) { // search the variant dict here, so looking up aircraft variants
if (p->id() == aId) { // works as expected.
return p; PackageWeakMap::const_iterator it = m_variantDict.find(aId);
} if (it == m_variantDict.end())
} return NULL;
return NULL; // not found return it->second;
} }
std::string Catalog::id() const std::string Catalog::id() const

View File

@ -144,6 +144,9 @@ private:
PackageList m_packages; PackageList m_packages;
time_t m_retrievedTime; time_t m_retrievedTime;
typedef std::map<std::string, Package*> PackageWeakMap;
PackageWeakMap m_variantDict;
// important that this is a weak-ref to Installs, // important that this is a weak-ref to Installs,
// since it is only cleaned up in the Install destructor // since it is only cleaned up in the Install destructor
typedef std::map<PackageRef, Install*> PackageInstallDict; typedef std::map<PackageRef, Install*> PackageInstallDict;

View File

@ -46,6 +46,14 @@ void Package::initWithProps(const SGPropertyNode* aProps)
std::string t(c->getStringValue()); std::string t(c->getStringValue());
m_tags.insert(boost::to_lower_copy(t)); 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 bool Package::matches(const SGPropertyNode* aFilter) const
@ -133,7 +141,7 @@ InstallRef Package::existingInstall() const
std::string Package::id() const std::string Package::id() const
{ {
return m_props->getStringValue("id"); return m_id;
} }
std::string Package::qualifiedId() const std::string Package::qualifiedId() const
@ -241,6 +249,34 @@ PackageList Package::dependencies() const
return result; 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 pkg
} // of namespace simgear } // of namespace simgear

View File

@ -60,6 +60,12 @@ public:
std::string id() const; 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 * Fully-qualified ID, including our catalog'd ID
*/ */
@ -71,6 +77,11 @@ public:
*/ */
std::string name() const; 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 * syntactic sugar to get the localised description
*/ */
@ -119,9 +130,12 @@ private:
void initWithProps(const SGPropertyNode* aProps); void initWithProps(const SGPropertyNode* aProps);
void updateFromProps(const SGPropertyNode* aProps);
std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const; std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const;
SGPropertyNode_ptr m_props; SGPropertyNode_ptr m_props;
std::string m_id;
string_set m_tags; string_set m_tags;
CatalogRef m_catalog; CatalogRef m_catalog;
}; };