HTTP::Request(aUrl),
m_owner(aOwner)
{
+ // refreshing
+ m_owner->changeStatus(Delegate::FAIL_IN_PROGRESS);
}
protected:
time(&m_owner->m_retrievedTime);
m_owner->writeTimestamp();
- m_owner->refreshComplete(Delegate::FAIL_SUCCESS);
+ m_owner->refreshComplete(Delegate::CATALOG_REFRESHED);
}
private:
Catalog::Catalog(Root *aRoot) :
m_root(aRoot),
+ m_status(Delegate::FAIL_UNKNOWN),
m_retrievedTime(0)
{
}
CatalogRef c = new Catalog(aRoot);
c->m_installRoot = aPath;
- c->parseProps(props);
+ c->parseProps(props); // will set status
c->parseTimestamp();
return c;
}
+bool Catalog::uninstall()
+{
+ bool ok;
+ bool atLeastOneFailure = false;
+
+ BOOST_FOREACH(PackageRef p, installedPackages()) {
+ ok = p->existingInstall()->uninstall();
+ if (!ok) {
+ SG_LOG(SG_GENERAL, SG_WARN, "uninstall of package " <<
+ p->id() << " failed");
+ // continue trying other packages, bailing out here
+ // gains us nothing
+ atLeastOneFailure = true;
+ }
+ }
+
+ Dir d(m_installRoot);
+ ok = d.remove(true /* recursive */);
+ if (!ok) {
+ atLeastOneFailure = true;
+ }
+
+ changeStatus(atLeastOneFailure ? Delegate::FAIL_FILESYSTEM
+ : Delegate::FAIL_SUCCESS);
+ return ok;
+}
+
PackageList const&
Catalog::packages() const
{
void Catalog::refresh()
{
Downloader* dl = new Downloader(this, url());
+ // will iupdate status to IN_PROGRESS
m_root->makeHTTPRequest(dl);
m_root->catalogRefreshBegin(this);
}
Dir d(m_installRoot);
d.create(0755);
}
+
+ // parsed XML ok, mark status as valid
+ changeStatus(Delegate::FAIL_SUCCESS);
}
PackageRef Catalog::getPackageById(const std::string& aId) const
void Catalog::refreshComplete(Delegate::FailureCode aReason)
{
m_root->catalogRefreshComplete(this, aReason);
+ changeStatus(aReason);
}
void Catalog::registerInstall(Install* ins)
m_installed.erase(ins->package());
}
+void Catalog::changeStatus(Delegate::FailureCode newStatus)
+{
+ if (m_status == newStatus) {
+ return;
+ }
+
+ m_status = newStatus;
+ m_statusCallbacks(this);
+}
+
+void Catalog::addStatusCallback(const Callback& cb)
+{
+ m_statusCallbacks.push_back(cb);
+}
+
+Delegate::FailureCode Catalog::status() const
+{
+ return m_status;
+}
+
} // of namespace pkg
} // of namespace simgear
#include <ctime>
#include <map>
+#include <boost/bind.hpp>
+
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
+#include <simgear/structure/function_list.hxx>
#include <simgear/package/Delegate.hxx>
Root* root() const
{ return m_root;};
+ /**
+ * uninstall this catalog entirely, including all installed packages
+ */
+ bool uninstall();
+
/**
* perform a refresh of the catalog contents
*/
* access the raw property data in the catalog
*/
SGPropertyNode* properties() const;
+
+ Delegate::FailureCode status() const;
+
+ typedef boost::function<void(Catalog*)> Callback;
+
+ void addStatusCallback(const Callback& cb);
+
+ template<class C>
+ void addStatusCallback(C* instance, void (C::*mem_func)(Catalog*))
+ {
+ return addStatusCallback(boost::bind(mem_func, instance, _1));
+ }
private:
Catalog(Root* aRoot);
std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const;
+ void changeStatus(Delegate::FailureCode newStatus);
+
Root* m_root;
SGPropertyNode_ptr m_props;
SGPath m_installRoot;
std::string m_url;
-
+ Delegate::FailureCode m_status;
+
PackageList m_packages;
time_t m_retrievedTime;
// since it is only cleaned up in the Install destructor
typedef std::map<PackageRef, Install*> PackageInstallDict;
PackageInstallDict m_installed;
+
+ function_list<Callback> m_statusCallbacks;
};
} // of namespace pkg
FAIL_DOWNLOAD, ///< network issue
FAIL_EXTRACT, ///< package archive failed to extract cleanly
FAIL_FILESYSTEM, ///< unknown filesystem error occurred
- FAIL_VERSION ///< version check mismatch
+ FAIL_VERSION, ///< version check mismatch
+ CATALOG_REFRESHED
} FailureCode;
m_package->catalog()->root()->startInstall(this);
}
-void Install::uninstall()
+bool Install::uninstall()
{
Dir d(m_path);
- d.remove(true);
+ if (!d.remove(true)) {
+ SG_LOG(SG_GENERAL, SG_ALERT, "package uninstall failed: couldn't remove path " << m_path);
+ return false;
+ }
+
m_package->catalog()->unregisterInstall(this);
+ return true;
+}
+
+bool Install::isDownloading() const
+{
+ return (m_download != NULL);
}
//------------------------------------------------------------------------------
bool hasUpdate() const;
void startUpdate();
-
- void uninstall();
+ bool uninstall();
+
+ bool isDownloading() const;
+
/**
* Set the handler to be called when the installation successfully
* completes.
}
}
+bool Root::removeCatalogById(const std::string& aId)
+{
+ CatalogDict::iterator catIt = d->catalogs.find(aId);
+ if (catIt == d->catalogs.end()) {
+ SG_LOG(SG_GENERAL, SG_WARN, "removeCatalogById: unknown ID:" << aId);
+ return false;
+ }
+
+ CatalogRef cat = catIt->second;
+
+ // drop the reference
+ d->catalogs.erase(catIt);
+
+ bool ok = cat->uninstall();
+ if (!ok) {
+ SG_LOG(SG_GENERAL, SG_WARN, "removeCatalogById: catalog :" << aId
+ << "failed to uninstall");
+ }
+
+ return ok;
+}
+
} // of namespace pkg
} // of namespace simgear
CatalogRef getCatalogById(const std::string& aId) const;
void scheduleToUpdate(InstallRef aInstall);
+
+ /**
+ * remove a catalog. Will uninstall all packages originating
+ * from the catalog too.
+ */
+ bool removeCatalogById(const std::string& aId);
private:
friend class Install;
friend class Catalog;