Files
simgear/simgear/package/Package.cxx
T
Thomas Geymayer 9868fb03a2 pkg::Package: callback for installation start.
Allow eg. Aircraft Center to add listeners to packages to
be called if installation starts.
2014-06-30 18:36:15 +02:00

296 lines
7.7 KiB
C++

// Copyright (C) 2013 James Turner - zakalawe@mac.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include <simgear/package/Package.hxx>
#include <cassert>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/package/Catalog.hxx>
#include <simgear/package/Install.hxx>
#include <simgear/package/Root.hxx>
namespace simgear {
namespace pkg {
Package::Package(const SGPropertyNode* aProps, CatalogRef aCatalog) :
m_catalog(aCatalog)
{
initWithProps(aProps);
}
void Package::initWithProps(const SGPropertyNode* aProps)
{
m_props = const_cast<SGPropertyNode*>(aProps);
// cache tag values
BOOST_FOREACH(const SGPropertyNode* c, aProps->getChildren("tag")) {
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
{
int nChildren = aFilter->nChildren();
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode* c = aFilter->getChild(i);
const std::string& filter_name = c->getNameString();
if (strutils::starts_with(filter_name, "rating-")) {
int minRating = c->getIntValue();
std::string rname = c->getName() + 7;
int ourRating = m_props->getChild("rating")->getIntValue(rname, 0);
if (ourRating < minRating) {
return false;
}
}
else if (filter_name == "tag") {
std::string tag(c->getStringValue());
boost::to_lower(tag);
if (m_tags.find(tag) == m_tags.end()) {
return false;
}
}
// substring search of name, description
else if (filter_name == "name") {
std::string n(c->getStringValue());
boost::to_lower(n);
size_t pos = boost::to_lower_copy(name()).find(n);
if (pos == std::string::npos) {
return false;
}
}
else if (filter_name == "description") {
std::string n(c->getStringValue());
boost::to_lower(n);
size_t pos = boost::to_lower_copy(description()).find(n);
if (pos == std::string::npos) {
return false;
}
}
else if (filter_name == "installed") {
if (isInstalled() != c->getBoolValue()) {
return false;
}
}
else
SG_LOG(SG_GENERAL, SG_WARN, "unknown filter term:" << filter_name);
} // of filter props iteration
return true;
}
bool Package::isInstalled() const
{
// anything to check for? look for a valid revision file?
return pathOnDisk().exists();
}
SGPath Package::pathOnDisk() const
{
SGPath p(m_catalog->installRoot());
p.append("Aircraft");
p.append(id());
return p;
}
InstallRef Package::install()
{
InstallRef ins = existingInstall();
if (ins) {
return ins;
}
// start a new install
ins = new Install(this, pathOnDisk());
m_catalog->root()->scheduleToUpdate(ins);
_install_cb(this, ins);
return ins;
}
InstallRef Package::existingInstall(const InstallCallback& cb) const
{
InstallRef install = m_catalog->installForPackage(const_cast<Package*>(this));
if( cb )
{
_install_cb.push_back(cb);
if( install )
cb(const_cast<Package*>(this), install);
}
return install;
}
std::string Package::id() const
{
return m_id;
}
std::string Package::qualifiedId() const
{
return m_catalog->id() + "." + id();
}
std::string Package::md5() const
{
return m_props->getStringValue("md5");
}
unsigned int Package::revision() const
{
return m_props->getIntValue("revision");
}
std::string Package::name() const
{
return m_props->getStringValue("name");
}
size_t Package::fileSizeBytes() const
{
return m_props->getIntValue("file-size-bytes");
}
std::string Package::description() const
{
return getLocalisedProp("description");
}
SGPropertyNode* Package::properties() const
{
return m_props.ptr();
}
string_list Package::thumbnailUrls() const
{
string_list r;
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail")) {
r.push_back(dl->getStringValue());
}
return r;
}
string_list Package::downloadUrls() const
{
string_list r;
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("url")) {
r.push_back(dl->getStringValue());
}
return r;
}
std::string Package::getLocalisedProp(const std::string& aName) const
{
return getLocalisedString(m_props, aName.c_str());
}
std::string Package::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
{
std::string locale = m_catalog->root()->getLocale();
if (aRoot->hasChild(locale)) {
const SGPropertyNode* localeRoot = aRoot->getChild(locale.c_str());
if (localeRoot->hasChild(aName)) {
return localeRoot->getStringValue(aName);
}
}
return aRoot->getStringValue(aName);
}
PackageList Package::dependencies() const
{
PackageList result;
BOOST_FOREACH(SGPropertyNode* dep, m_props->getChildren("depends")) {
std::string depName = dep->getStringValue("package");
unsigned int rev = dep->getIntValue("revision", 0);
// prefer local hangar package if possible, in case someone does something
// silly with naming. Of course flightgear's aircraft search doesn't know
// about hanagrs, so names still need to be unique.
PackageRef depPkg = m_catalog->getPackageById(depName);
if (!depPkg) {
Root* rt = m_catalog->root();
depPkg = rt->getPackageById(depName);
if (!depPkg) {
throw sg_exception("Couldn't satisfy dependency of " + id() + " : " + depName);
}
}
if (depPkg->revision() < rev) {
throw sg_range_exception("Couldn't find suitable revision of " + depName);
}
// forbid recursive dependency graphs, we don't need that level
// of complexity for aircraft resources
assert(depPkg->dependencies() == PackageList());
result.push_back(depPkg);
}
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