#include <boost/foreach.hpp>
#include <cstring>
+#include <map>
+#include <deque>
+#include <set>
#include <simgear/debug/logstream.hxx>
#include <simgear/props/props_io.hxx>
namespace pkg {
-void Root::setMaxAgeSeconds(int seconds)
+typedef std::map<std::string, Catalog*> CatalogDict;
+
+class Root::RootPrivate
{
- m_maxAgeSeconds = seconds;
+public:
+ RootPrivate() :
+ http(NULL),
+ maxAgeSeconds(60 * 60 * 24),
+ delegate(NULL)
+ {
+
+ }
+
+ SGPath path;
+ std::string locale;
+ HTTP::Client* http;
+ CatalogDict catalogs;
+ unsigned int maxAgeSeconds;
+ Delegate* delegate;
+ std::string version;
+
+ std::set<Catalog*> refreshing;
+ std::deque<Install*> updateDeque;
+ std::deque<HTTP::Request_ptr> httpPendingRequests;
+};
+
+SGPath Root::path() const
+{
+ return d->path;
+}
+
+void Root::setMaxAgeSeconds(unsigned int seconds)
+{
+ d->maxAgeSeconds = seconds;
+}
+
+unsigned int Root::maxAgeSeconds() const
+{
+ return d->maxAgeSeconds;
}
void Root::setHTTPClient(HTTP::Client* aHTTP)
{
- m_http = aHTTP;
+ d->http = aHTTP;
+ BOOST_FOREACH(HTTP::Request_ptr req, d->httpPendingRequests) {
+ d->http->makeRequest(req);
+ }
+
+ d->httpPendingRequests.clear();
}
-HTTP::Client* Root::getHTTPClient() const
+void Root::makeHTTPRequest(HTTP::Request *req)
{
- return m_http;
+ if (d->http) {
+ d->http->makeRequest(req);
+ return;
+ }
+
+ d->httpPendingRequests.push_back(req);
}
-
-Root::Root(const SGPath& aPath) :
- m_path(aPath),
- m_http(NULL),
- m_maxAgeSeconds(60 * 60 * 24),
- m_delegate(NULL)
+
+Root::Root(const SGPath& aPath, const std::string& aVersion) :
+ d(new RootPrivate)
{
+ d->path = aPath;
+ d->version = aVersion;
if (getenv("LOCALE")) {
- m_locale = getenv("LOCALE");
+ d->locale = getenv("LOCALE");
}
- Dir d(aPath);
- if (!d.exists()) {
- d.create(0755);
+ Dir dir(aPath);
+ if (!dir.exists()) {
+ dir.create(0755);
return;
}
- BOOST_FOREACH(SGPath c, d.children(Dir::TYPE_DIR)) {
+ BOOST_FOREACH(SGPath c, dir.children(Dir::TYPE_DIR)) {
Catalog* cat = Catalog::createFromPath(this, c);
if (cat) {
- m_catalogs[cat->id()] = cat;
+ d->catalogs[cat->id()] = cat;
}
} // of child directories iteration
}
{
}
-
+
+std::string Root::catalogVersion() const
+{
+ return d->version;
+}
+
Catalog* Root::getCatalogById(const std::string& aId) const
{
- CatalogDict::const_iterator it = m_catalogs.find(aId);
- if (it == m_catalogs.end()) {
+ CatalogDict::const_iterator it = d->catalogs.find(aId);
+ if (it == d->catalogs.end()) {
return NULL;
}
Package* pkg = NULL;
if (lastDot == std::string::npos) {
// naked package ID
- CatalogDict::const_iterator it = m_catalogs.begin();
- for (; it != m_catalogs.end(); ++it) {
+ CatalogDict::const_iterator it = d->catalogs.begin();
+ for (; it != d->catalogs.end(); ++it) {
pkg = it->second->getPackageById(aName);
if (pkg) {
return pkg;
CatalogList Root::catalogs() const
{
CatalogList r;
- CatalogDict::const_iterator it = m_catalogs.begin();
- for (; it != m_catalogs.end(); ++it) {
+ CatalogDict::const_iterator it = d->catalogs.begin();
+ for (; it != d->catalogs.end(); ++it) {
r.push_back(it->second);
}
{
PackageList r;
- CatalogDict::const_iterator it = m_catalogs.begin();
- for (; it != m_catalogs.end(); ++it) {
+ CatalogDict::const_iterator it = d->catalogs.begin();
+ for (; it != d->catalogs.end(); ++it) {
PackageList r2(it->second->packagesMatching(aFilter));
r.insert(r.end(), r2.begin(), r2.end());
}
{
PackageList r;
- CatalogDict::const_iterator it = m_catalogs.begin();
- for (; it != m_catalogs.end(); ++it) {
+ CatalogDict::const_iterator it = d->catalogs.begin();
+ for (; it != d->catalogs.end(); ++it) {
PackageList r2(it->second->packagesNeedingUpdate());
r.insert(r.end(), r2.begin(), r2.end());
}
void Root::refresh(bool aForce)
{
- CatalogDict::iterator it = m_catalogs.begin();
- for (; it != m_catalogs.end(); ++it) {
- if (aForce || (it->second->ageInSeconds() > m_maxAgeSeconds)) {
+ CatalogDict::iterator it = d->catalogs.begin();
+ for (; it != d->catalogs.end(); ++it) {
+ if (aForce || it->second->needsRefresh()) {
it->second->refresh();
}
}
}
+void Root::setDelegate(simgear::pkg::Delegate *aDelegate)
+{
+ d->delegate = aDelegate;
+}
+
void Root::setLocale(const std::string& aLocale)
{
- m_locale = aLocale;
+ d->locale = aLocale;
}
std::string Root::getLocale() const
{
- return m_locale;
+ return d->locale;
}
void Root::scheduleToUpdate(Install* aInstall)
dep->install();
}
- bool wasEmpty = m_updateDeque.empty();
- m_updateDeque.push_back(aInstall);
+ bool wasEmpty = d->updateDeque.empty();
+ d->updateDeque.push_back(aInstall);
+
if (wasEmpty) {
aInstall->startUpdate();
}
void Root::startInstall(Install* aInstall)
{
- if (m_delegate) {
- m_delegate->startInstall(aInstall);
+ if (d->delegate) {
+ d->delegate->startInstall(aInstall);
}
}
void Root::installProgress(Install* aInstall, unsigned int aBytes, unsigned int aTotal)
{
- if (m_delegate) {
- m_delegate->installProgress(aInstall, aBytes, aTotal);
+ if (d->delegate) {
+ d->delegate->installProgress(aInstall, aBytes, aTotal);
}
}
void Root::startNext(Install* aCurrent)
{
- if (m_updateDeque.front() != aCurrent) {
+ if (d->updateDeque.front() != aCurrent) {
SG_LOG(SG_GENERAL, SG_ALERT, "current install of package not head of the deque");
} else {
- m_updateDeque.pop_front();
+ d->updateDeque.pop_front();
}
- if (!m_updateDeque.empty()) {
- m_updateDeque.front()->startUpdate();
+ if (!d->updateDeque.empty()) {
+ d->updateDeque.front()->startUpdate();
}
}
void Root::finishInstall(Install* aInstall)
{
- if (m_delegate) {
- m_delegate->finishInstall(aInstall);
+ if (d->delegate) {
+ d->delegate->finishInstall(aInstall);
}
startNext(aInstall);
{
SG_LOG(SG_GENERAL, SG_ALERT, "failed to install package:"
<< aInstall->package()->id() << ":" << aReason);
- if (m_delegate) {
- m_delegate->failedInstall(aInstall, aReason);
+ if (d->delegate) {
+ d->delegate->failedInstall(aInstall, aReason);
}
startNext(aInstall);
void Root::catalogRefreshBegin(Catalog* aCat)
{
- m_refreshing.insert(aCat);
+ d->refreshing.insert(aCat);
}
-void Root::catalogRefreshComplete(Catalog* aCat, bool aSuccess)
+void Root::catalogRefreshComplete(Catalog* aCat, Delegate::FailureCode aReason)
{
- m_refreshing.erase(aCat);
- if (m_refreshing.empty()) {
- if (m_delegate) {
- m_delegate->refreshComplete();
+ CatalogDict::iterator catIt = d->catalogs.find(aCat->id());
+ if (aReason != Delegate::FAIL_SUCCESS) {
+ if (d->delegate) {
+ d->delegate->failedRefresh(aCat, aReason);
+ }
+
+ // if the failure is permanent, delete the catalog from our
+ // list (don't touch it on disk)
+ bool isPermanentFailure = (aReason == Delegate::FAIL_VERSION);
+ if (isPermanentFailure) {
+ SG_LOG(SG_GENERAL, SG_WARN, "permanent failure for catalog:" << aCat->id());
+ d->catalogs.erase(catIt);
+ }
+ } else if (catIt == d->catalogs.end()) {
+ // first fresh, add to our storage now
+ d->catalogs.insert(catIt, CatalogDict::value_type(aCat->id(), aCat));
+ }
+
+ d->refreshing.erase(aCat);
+ if (d->refreshing.empty()) {
+ if (d->delegate) {
+ d->delegate->refreshComplete();
}
}
}