Packages: add ‘provides’ listing support
Support a list of provided files on a package, to make it easier to identify which package to install based on a required file path.
This commit is contained in:
parent
4810eaab92
commit
4c89e8a9d5
@ -298,6 +298,9 @@ bool Catalog::removeDirectory()
|
||||
PackageList
|
||||
Catalog::packages(Type ty) const
|
||||
{
|
||||
if (ty == AnyPackageType)
|
||||
return m_packages;
|
||||
|
||||
PackageList r;
|
||||
std::copy_if(m_packages.begin(), m_packages.end(),
|
||||
std::back_inserter(r),
|
||||
@ -338,7 +341,9 @@ Catalog::installedPackages(Type ty) const
|
||||
std::copy_if(m_packages.begin(), m_packages.end(),
|
||||
std::back_inserter(r),
|
||||
[ty](const PackageRef& p) {
|
||||
return p->isInstalled() && p->type() == ty;
|
||||
if (ty != AnyPackageType && (p->type() != ty))
|
||||
return false;
|
||||
return p->isInstalled();
|
||||
});
|
||||
return r;
|
||||
}
|
||||
@ -726,6 +731,32 @@ int Catalog::markPackagesForInstallation(const string_list &packageIds) {
|
||||
|
||||
CatalogRef Catalog::migratedFrom() const { return m_migratedFrom; }
|
||||
|
||||
PackageList Catalog::packagesProviding(const Type inferredType, const std::string& directory, const std::string& subpath) const
|
||||
{
|
||||
PackageList p;
|
||||
copy_if(m_packages.begin(), m_packages.end(), std::back_inserter(p),
|
||||
[inferredType, &directory, &subpath](const PackageRef& pkg) {
|
||||
// if we detected a package type, it needs to match, so the resulting
|
||||
// path matches as well
|
||||
if (inferredType != AnyPackageType) {
|
||||
if (inferredType != pkg->type()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (directory != pkg->dirName())
|
||||
return false;
|
||||
|
||||
if (subpath.empty()) {
|
||||
return true; // we're done, success
|
||||
}
|
||||
|
||||
return pkg->doesProvidePath(subpath);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
} // of namespace simgear
|
||||
|
@ -194,7 +194,9 @@ public:
|
||||
void changeStatus(Delegate::StatusCode newStatus);
|
||||
|
||||
void processAlternate(SGPropertyNode_ptr alt);
|
||||
|
||||
|
||||
PackageList packagesProviding(const Type inferredType, const std::string& path, const std::string& subpath) const;
|
||||
|
||||
Root* m_root;
|
||||
SGPropertyNode_ptr m_props;
|
||||
SGPath m_installRoot;
|
||||
|
@ -177,7 +177,9 @@ int parseTest()
|
||||
SG_CHECK_EQUAL(cat->description(), "First test catalog");
|
||||
|
||||
// check the packages too
|
||||
SG_CHECK_EQUAL(cat->packages().size(), 6);
|
||||
SG_CHECK_EQUAL(cat->packages().size(), 4);
|
||||
SG_CHECK_EQUAL(cat->packages(simgear::pkg::LibraryPackage).size(), 2);
|
||||
SG_CHECK_EQUAL(cat->packages(simgear::pkg::AIModelPackage).size(), 1);
|
||||
|
||||
pkg::PackageRef p1 = cat->packages().front();
|
||||
SG_CHECK_EQUAL(p1->catalog(), cat.ptr());
|
||||
@ -187,6 +189,7 @@ int parseTest()
|
||||
SG_CHECK_EQUAL(p1->name(), "Alpha package");
|
||||
SG_CHECK_EQUAL(p1->revision(), 8);
|
||||
SG_CHECK_EQUAL(p1->fileSizeBytes(), 593);
|
||||
SG_CHECK_EQUAL(p1->type(), simgear::pkg::AircraftPackage);
|
||||
|
||||
|
||||
pkg::PackageRef p2 = cat->getPackageById("c172p");
|
||||
@ -370,7 +373,7 @@ void testAddCatalog(HTTP::Client* cl)
|
||||
p.append("org.flightgear.test.catalog1");
|
||||
p.append("catalog.xml");
|
||||
SG_VERIFY(p.exists());
|
||||
SG_CHECK_EQUAL(root->allPackages().size(), 6);
|
||||
SG_CHECK_EQUAL(root->allPackages().size(), 4);
|
||||
SG_CHECK_EQUAL(root->catalogs().size(), 1);
|
||||
|
||||
pkg::PackageRef p1 = root->getPackageById("alpha");
|
||||
@ -1219,8 +1222,8 @@ void testMigrateInstalled(HTTP::Client *cl) {
|
||||
waitForUpdateComplete(cl, root);
|
||||
|
||||
string_list existing;
|
||||
for (const auto &pack : oldCatalog->installedPackages()) {
|
||||
existing.push_back(pack->id());
|
||||
for (const auto& pack : oldCatalog->installedPackages(simgear::pkg::AnyPackageType)) {
|
||||
existing.push_back(pack->id());
|
||||
}
|
||||
|
||||
SG_CHECK_EQUAL(4, existing.size());
|
||||
@ -1309,6 +1312,31 @@ void testDontMigrateRemoved(HTTP::Client *cl) {
|
||||
}
|
||||
}
|
||||
|
||||
void testProvides(HTTP::Client* cl)
|
||||
{
|
||||
SGPath rootPath(simgear::Dir::current().path());
|
||||
rootPath.append("pkg_check_provides");
|
||||
simgear::Dir pd(rootPath);
|
||||
pd.removeChildren();
|
||||
global_catalogVersion = 0;
|
||||
|
||||
pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
|
||||
// specify a test dir
|
||||
root->setHTTPClient(cl);
|
||||
|
||||
pkg::CatalogRef c = pkg::Catalog::createFromUrl(root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
|
||||
waitForUpdateComplete(cl, root);
|
||||
|
||||
// query
|
||||
auto packages = root->packagesProviding("Aircraft/b744", false);
|
||||
SG_CHECK_EQUAL(packages.size(), 1);
|
||||
SG_CHECK_EQUAL(packages.front()->qualifiedId(), "org.flightgear.test.catalog1.b747-400");
|
||||
|
||||
packages = root->packagesProviding("movies/Foo/intro.mov", false);
|
||||
SG_CHECK_EQUAL(packages.size(), 1);
|
||||
SG_CHECK_EQUAL(packages.front()->qualifiedId(), "org.flightgear.test.catalog1.movies");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
sglog().setLogLevels( SG_ALL, SG_WARN );
|
||||
@ -1358,6 +1386,8 @@ int main(int argc, char* argv[])
|
||||
|
||||
testDontMigrateRemoved(&cl);
|
||||
|
||||
testProvides(&cl);
|
||||
|
||||
cerr << "Successfully passed all tests!" << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -34,9 +34,10 @@ namespace {
|
||||
const string_list static_typeNames = {
|
||||
"aircraft",
|
||||
"ai-model",
|
||||
"add-on"};
|
||||
"add-on",
|
||||
"library"};
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace simgear {
|
||||
|
||||
@ -79,6 +80,10 @@ void Package::initWithProps(const SGPropertyNode* aProps)
|
||||
} else {
|
||||
m_type = AircraftPackage;
|
||||
}
|
||||
|
||||
for (auto p : m_props->getChildren("provides")) {
|
||||
m_provides.push_back(p->getStringValue());
|
||||
}
|
||||
}
|
||||
|
||||
void Package::updateFromProps(const SGPropertyNode* aProps)
|
||||
@ -221,7 +226,10 @@ bool Package::isInstalled() const
|
||||
std::string Package::directoryForType(Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case AnyPackageType:
|
||||
throw sg_range_exception("Package::directoryForType: passed 'AnyPackage'");
|
||||
case AircraftPackage:
|
||||
case LibraryPackage:
|
||||
default:
|
||||
return "Aircraft";
|
||||
case AIModelPackage:
|
||||
@ -353,7 +361,7 @@ unsigned int Package::revision() const
|
||||
|
||||
std::string Package::name() const
|
||||
{
|
||||
return m_props->getStringValue("name");
|
||||
return getLocalisedProp("name", 0);
|
||||
}
|
||||
|
||||
size_t Package::fileSizeBytes() const
|
||||
@ -482,14 +490,8 @@ std::string Package::nameForVariant(const std::string& vid) const
|
||||
return name();
|
||||
}
|
||||
|
||||
for (auto var : m_props->getChildren("variant")) {
|
||||
if (vid == var->getStringValue("id")) {
|
||||
return var->getStringValue("name");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throw sg_exception("Unknow variant +" + vid + " in package " + id());
|
||||
const int index = indexOfVariant(vid);
|
||||
return nameForVariant(index);
|
||||
}
|
||||
|
||||
unsigned int Package::indexOfVariant(const std::string& vid) const
|
||||
@ -515,7 +517,7 @@ unsigned int Package::indexOfVariant(const std::string& vid) const
|
||||
|
||||
std::string Package::nameForVariant(const unsigned int vIndex) const
|
||||
{
|
||||
return propsForVariant(vIndex, "name")->getStringValue("name");
|
||||
return getLocalisedProp("name", vIndex);
|
||||
}
|
||||
|
||||
SGPropertyNode_ptr Package::propsForVariant(const unsigned int vIndex, const char* propName) const
|
||||
@ -635,6 +637,17 @@ Type Package::type() const
|
||||
return m_type;
|
||||
}
|
||||
|
||||
string_list Package::providesPaths() const
|
||||
{
|
||||
return m_provides;
|
||||
}
|
||||
|
||||
bool Package::doesProvidePath(const std::string& p) const
|
||||
{
|
||||
auto it = std::find(m_provides.begin(), m_provides.end(), p);
|
||||
return it != m_provides.end();
|
||||
}
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
} // of namespace simgear
|
||||
|
@ -209,6 +209,14 @@ public:
|
||||
|
||||
static std::string directoryForType(Type type);
|
||||
|
||||
/**
|
||||
@brief key files provided by this package. Optional list of externally interesting files
|
||||
within this package, relative to the package root.
|
||||
*/
|
||||
string_list providesPaths() const;
|
||||
|
||||
bool doesProvidePath(const std::string& p) const;
|
||||
|
||||
private:
|
||||
SGPath pathOnDisk() const;
|
||||
|
||||
@ -240,6 +248,7 @@ private:
|
||||
string_set m_tags;
|
||||
Catalog* m_catalog = nullptr; // non-owning ref, explicitly
|
||||
string_list m_variants;
|
||||
string_list m_provides;
|
||||
|
||||
mutable function_list<InstallCallback> _install_cb;
|
||||
};
|
||||
|
@ -28,10 +28,13 @@ namespace pkg {
|
||||
enum Type {
|
||||
AircraftPackage = 0,
|
||||
AIModelPackage,
|
||||
AddOnPackage
|
||||
AddOnPackage,
|
||||
LibraryPackage, ///< common files for use by other package(s) (eg, the DavePack)
|
||||
|
||||
// if you extend this enum, extend the static_typeNames string array
|
||||
// in Package.cxx file as well.
|
||||
|
||||
AnyPackageType = 9999
|
||||
};
|
||||
|
||||
// forward decls
|
||||
|
@ -906,6 +906,42 @@ string_list Root::explicitlyRemovedCatalogs() const {
|
||||
return d->manuallyRemovedCatalogs;
|
||||
}
|
||||
|
||||
|
||||
PackageList Root::packagesProviding(const std::string& path, bool onlyInstalled) const
|
||||
{
|
||||
string modPath = path;
|
||||
auto inferredType = AnyPackageType;
|
||||
if (strutils::starts_with(path, "Aircraft/")) {
|
||||
inferredType = AircraftPackage;
|
||||
modPath = path.substr(9);
|
||||
} else if (strutils::starts_with(path, "AI/Aircraft/")) {
|
||||
inferredType = AIModelPackage;
|
||||
modPath = path.substr(12);
|
||||
}
|
||||
|
||||
string subPath;
|
||||
const auto firstSeperatorPos = modPath.find('/');
|
||||
if (firstSeperatorPos != std::string::npos) {
|
||||
subPath = modPath.substr(firstSeperatorPos + 1);
|
||||
modPath.resize(firstSeperatorPos);
|
||||
}
|
||||
|
||||
PackageList r;
|
||||
for (auto cat : d->catalogs) {
|
||||
const auto p = cat.second->packagesProviding(inferredType, modPath, subPath);
|
||||
r.insert(r.end(), p.begin(), p.end());
|
||||
} // catalog iteratrion
|
||||
|
||||
if (onlyInstalled) {
|
||||
auto it = std::remove_if(r.begin(), r.end(), [](const PackageRef& p) {
|
||||
return p->isInstalled();
|
||||
});
|
||||
r.erase(it, r.end());
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
} // of namespace simgear
|
||||
|
@ -159,7 +159,22 @@ public:
|
||||
*/
|
||||
string_list explicitlyRemovedCatalogs() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Given a relative path to a file, return the packages which provide it.
|
||||
* If the path starts with a type-based prefix (eg 'Aircraft' or 'AI/Aircraft'), the
|
||||
* corresponding package type will be considered. The next item must correspond to
|
||||
* the package directory name.
|
||||
*
|
||||
* If the path contains components more specific than this, they will be checked
|
||||
* against matching packkages 'provides' list. If the path does not contain such
|
||||
* components, a match of the type+directory name will be considered sufficient.
|
||||
*
|
||||
* @param path
|
||||
* @return PackageList
|
||||
*/
|
||||
PackageList packagesProviding(const std::string& path, bool onlyInstalled) const;
|
||||
|
||||
private:
|
||||
friend class Install;
|
||||
friend class Catalog;
|
||||
friend class Package;
|
||||
|
@ -230,6 +230,9 @@
|
||||
<url>http://localhost:2000/catalogTest1/common-sounds.zip</url>
|
||||
<file-size-bytes>360</file-size-bytes>
|
||||
<md5>acf9eb89cf396eb42f8823d9cdf17584</md5>
|
||||
<type>library</type>
|
||||
<provides>engine1.wav</provides>
|
||||
<provides>engine3.wav</provides>
|
||||
</package>
|
||||
|
||||
|
||||
@ -244,5 +247,22 @@
|
||||
<archive-path>movies_6789</archive-path>
|
||||
<file-size-bytes>232</file-size-bytes>
|
||||
<md5>e5f89c3f1ed1bdda16174c868f3c7b30</md5>
|
||||
<type>library</type>
|
||||
<provides>Foo/intro.mov</provides>
|
||||
</package>
|
||||
|
||||
<package>
|
||||
<id>b737-ng-ai</id>
|
||||
<name>Boeing 737 NG AI Model</name>
|
||||
<dir>b737NG</dir>
|
||||
<description>AI Model for the 737-NG</description>
|
||||
<revision type="int">111</revision>
|
||||
<file-size-bytes type="int">860</file-size-bytes>
|
||||
<type>ai-model</type>
|
||||
<provides>737NG/Models/BritishAirways-738.xml</provides>
|
||||
<md5>a94ca5704f305b90767f40617d194ed6</md5>
|
||||
<url>http://localhost:2000/mirrorA/b737.tar.gz</url>
|
||||
<url>http://localhost:2000/mirrorB/b737.tar.gz</url>
|
||||
<url>http://localhost:2000/mirrorC/b737.tar.gz</url>
|
||||
</package>
|
||||
</PropertyList>
|
||||
|
Loading…
Reference in New Issue
Block a user