Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78d073a0f0 | ||
|
|
d62796c19d | ||
|
|
7ea7ff43fc | ||
|
|
dafd185595 | ||
|
|
1568ed8b97 | ||
|
|
444e2ffb2d |
+1
-1
@@ -1 +1 @@
|
|||||||
2020.3.0
|
2020.3.1
|
||||||
|
|||||||
@@ -631,11 +631,15 @@ bool SGMetar::scanWind()
|
|||||||
int dir;
|
int dir;
|
||||||
if (!strncmp(m, "VRB", 3))
|
if (!strncmp(m, "VRB", 3))
|
||||||
m += 3, dir = -1;
|
m += 3, dir = -1;
|
||||||
|
else if (!strncmp(m, "///", 3)) // direction not measurable
|
||||||
|
m += 3, dir = -1;
|
||||||
else if (!scanNumber(&m, &dir, 3))
|
else if (!scanNumber(&m, &dir, 3))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
if (!scanNumber(&m, &i, 2, 3))
|
if (!strncmp(m, "//", 2)) // speed not measurable
|
||||||
|
m += 2, i = -1;
|
||||||
|
else if (!scanNumber(&m, &i, 2, 3))
|
||||||
return false;
|
return false;
|
||||||
double speed = i;
|
double speed = i;
|
||||||
|
|
||||||
@@ -655,6 +659,8 @@ bool SGMetar::scanWind()
|
|||||||
m += 3, factor = SG_KMH_TO_MPS;
|
m += 3, factor = SG_KMH_TO_MPS;
|
||||||
else if (!strncmp(m, "MPS", 3))
|
else if (!strncmp(m, "MPS", 3))
|
||||||
m += 3, factor = 1.0;
|
m += 3, factor = 1.0;
|
||||||
|
else if (!strncmp(m, " ", 1)) // default to Knots
|
||||||
|
factor = SG_KT_TO_MPS;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
if (!scanBoundary(&m))
|
if (!scanBoundary(&m))
|
||||||
|
|||||||
@@ -76,12 +76,29 @@ void test_sensor_failure_cloud()
|
|||||||
SG_CHECK_EQUAL_EP2(m1.getPressure_hPa(), 1025, TEST_EPSILON);
|
SG_CHECK_EQUAL_EP2(m1.getPressure_hPa(), 1025, TEST_EPSILON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_sensor_failure_wind()
|
||||||
|
{
|
||||||
|
SGMetar m1("2020/10/23 16:55 LIVD 231655Z /////KT 9999 OVC025 10/08 Q1020 RMK OVC VIS MIN 9999 BLU");
|
||||||
|
SG_CHECK_EQUAL(m1.getWindDir(), -1);
|
||||||
|
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), -1, TEST_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_wind_unit_not_specified()
|
||||||
|
{
|
||||||
|
SGMetar m1("2020/10/23 11:58 KLSV 231158Z 05010G14 10SM CLR 16/M04 A2992 RMK SLPNO WND DATA ESTMD ALSTG/SLP ESTMD 10320 20124 5//// $");
|
||||||
|
SG_CHECK_EQUAL(m1.getWindDir(), 50);
|
||||||
|
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), 10.0, TEST_EPSILON);
|
||||||
|
SG_CHECK_EQUAL_EP2(m1.getGustSpeed_kt(), 14.0, TEST_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
test_basic();
|
test_basic();
|
||||||
test_sensor_failure_weather();
|
test_sensor_failure_weather();
|
||||||
test_sensor_failure_cloud();
|
test_sensor_failure_cloud();
|
||||||
|
test_sensor_failure_wind();
|
||||||
|
test_wind_unit_not_specified();
|
||||||
} catch (sg_exception& e) {
|
} catch (sg_exception& e) {
|
||||||
cerr << "got exception:" << e.getMessage() << endl;
|
cerr << "got exception:" << e.getMessage() << endl;
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -156,8 +156,13 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
|
|||||||
r->ttl = result->dnstxt_ttl;
|
r->ttl = result->dnstxt_ttl;
|
||||||
for (int i = 0; i < result->dnstxt_nrr; i++) {
|
for (int i = 0; i < result->dnstxt_nrr; i++) {
|
||||||
//TODO: interprete the .len field of dnstxt_txt?
|
//TODO: interprete the .len field of dnstxt_txt?
|
||||||
string txt = string((char*)result->dnstxt_txt[i].txt);
|
auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt);
|
||||||
r->entries.push_back( txt );
|
if (!rawTxt) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string txt{rawTxt};
|
||||||
|
r->entries.push_back(txt);
|
||||||
string_list tokens = simgear::strutils::split( txt, "=", 1 );
|
string_list tokens = simgear::strutils::split( txt, "=", 1 );
|
||||||
if( tokens.size() == 2 ) {
|
if( tokens.size() == 2 ) {
|
||||||
r->attributes[tokens[0]] = tokens[1];
|
r->attributes[tokens[0]] = tokens[1];
|
||||||
|
|||||||
@@ -643,16 +643,53 @@ void Catalog::processAlternate(SGPropertyNode_ptr alt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have an alternate ID, and it's differnt from our ID, so let's
|
// we have an alternate ID, and it's different from our ID, so let's
|
||||||
// define a new catalog
|
// define a new catalog
|
||||||
if (!altId.empty()) {
|
if (!altId.empty()) {
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Adding new catalog:" << altId << " as version alternate for " << id());
|
// don't auto-re-add Catalogs the user has explicilty rmeoved, that would
|
||||||
// new catalog being added
|
// suck
|
||||||
createFromUrl(root(), altUrl);
|
const auto removedByUser = root()->explicitlyRemovedCatalogs();
|
||||||
|
auto it = std::find(removedByUser.begin(), removedByUser.end(), altId);
|
||||||
// and we can go idle now
|
if (it != removedByUser.end()) {
|
||||||
changeStatus(Delegate::FAIL_VERSION);
|
changeStatus(Delegate::FAIL_VERSION);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_WARN,
|
||||||
|
"Adding new catalog:" << altId << " as version alternate for "
|
||||||
|
<< id());
|
||||||
|
// new catalog being added
|
||||||
|
auto newCat = createFromUrl(root(), altUrl);
|
||||||
|
|
||||||
|
bool didRun = false;
|
||||||
|
newCat->m_migratedFrom = this;
|
||||||
|
|
||||||
|
auto migratePackagesCb = [didRun](Catalog *c) mutable {
|
||||||
|
// removing callbacks is awkward, so use this
|
||||||
|
// flag to only run once. (and hence, we need to be mutable)
|
||||||
|
if (didRun)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (c->status() == Delegate::STATUS_REFRESHED) {
|
||||||
|
didRun = true;
|
||||||
|
|
||||||
|
string_list existing;
|
||||||
|
for (const auto &pack : c->migratedFrom()->installedPackages()) {
|
||||||
|
existing.push_back(pack->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
const int count = c->markPackagesForInstallation(existing);
|
||||||
|
SG_LOG(
|
||||||
|
SG_GENERAL, SG_INFO,
|
||||||
|
"Marked " << count
|
||||||
|
<< " packages from previous catalog for installation");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
newCat->addStatusCallback(migratePackagesCb);
|
||||||
|
// and we can go idle now
|
||||||
|
changeStatus(Delegate::FAIL_VERSION);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, "Migrating catalog " << id() << " to new URL:" << altUrl);
|
SG_LOG(SG_GENERAL, SG_INFO, "Migrating catalog " << id() << " to new URL:" << altUrl);
|
||||||
@@ -661,6 +698,26 @@ void Catalog::processAlternate(SGPropertyNode_ptr alt)
|
|||||||
root()->makeHTTPRequest(dl);
|
root()->makeHTTPRequest(dl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Catalog::markPackagesForInstallation(const string_list &packageIds) {
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (const auto &id : packageIds) {
|
||||||
|
auto ourPkg = getPackageById(id);
|
||||||
|
if (!ourPkg)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto existing = ourPkg->existingInstall();
|
||||||
|
if (!existing) {
|
||||||
|
ourPkg->markForInstall();
|
||||||
|
++result;
|
||||||
|
}
|
||||||
|
} // of outer package ID candidates iteration
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CatalogRef Catalog::migratedFrom() const { return m_migratedFrom; }
|
||||||
|
|
||||||
} // of namespace pkg
|
} // of namespace pkg
|
||||||
|
|
||||||
} // of namespace simgear
|
} // of namespace simgear
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
#include <simgear/misc/strutils.hxx>
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
|
|
||||||
#include <simgear/structure/SGReferenced.hxx>
|
#include <simgear/structure/SGReferenced.hxx>
|
||||||
@@ -93,7 +94,7 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* retrieve all the packages in the catalog which are installed
|
* retrieve all the packages in the catalog which are installed
|
||||||
* and have a pendig update
|
* and have a pending update
|
||||||
*/
|
*/
|
||||||
PackageList packagesNeedingUpdate() const;
|
PackageList packagesNeedingUpdate() const;
|
||||||
|
|
||||||
@@ -151,7 +152,32 @@ public:
|
|||||||
|
|
||||||
bool isUserEnabled() const;
|
bool isUserEnabled() const;
|
||||||
void setUserEnabled(bool b);
|
void setUserEnabled(bool b);
|
||||||
private:
|
|
||||||
|
/**
|
||||||
|
* Given a list of package IDs, mark all which exist in this package,
|
||||||
|
* for installation. ANy packahe IDs not present in this catalog,
|
||||||
|
* will be ignored.
|
||||||
|
*
|
||||||
|
* @result The number for packages newly marked for installation.
|
||||||
|
*/
|
||||||
|
int markPackagesForInstallation(const string_list &packageIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a catalog is added due to migration, this will contain the
|
||||||
|
* Catalog which triggered the add. Usually this will be a catalog
|
||||||
|
* corresponding to an earlier version.
|
||||||
|
*
|
||||||
|
* Note it's only valid at the time, the migration actually took place;
|
||||||
|
* when the new catalog is loaded from disk, this value will return
|
||||||
|
* null.
|
||||||
|
*
|
||||||
|
* This is intended to allow Uis to show a 'catalog was migrated'
|
||||||
|
* feedback, when they see a catalog refresh, which has a non-null
|
||||||
|
* value of this method.
|
||||||
|
*/
|
||||||
|
CatalogRef migratedFrom() const;
|
||||||
|
|
||||||
|
private:
|
||||||
Catalog(Root* aRoot);
|
Catalog(Root* aRoot);
|
||||||
|
|
||||||
class Downloader;
|
class Downloader;
|
||||||
@@ -197,6 +223,8 @@ private:
|
|||||||
PackageWeakMap m_variantDict;
|
PackageWeakMap m_variantDict;
|
||||||
|
|
||||||
function_list<Callback> m_statusCallbacks;
|
function_list<Callback> m_statusCallbacks;
|
||||||
|
|
||||||
|
CatalogRef m_migratedFrom;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // of namespace pkg
|
} // of namespace pkg
|
||||||
|
|||||||
@@ -827,7 +827,10 @@ void testVersionMigrateToId(HTTP::Client* cl)
|
|||||||
|
|
||||||
it = std::find(enabledCats.begin(), enabledCats.end(), altCat);
|
it = std::find(enabledCats.begin(), enabledCats.end(), altCat);
|
||||||
SG_VERIFY(it != enabledCats.end());
|
SG_VERIFY(it != enabledCats.end());
|
||||||
|
|
||||||
|
SG_CHECK_EQUAL(altCat->packagesNeedingUpdate().size(),
|
||||||
|
1); // should be the 737
|
||||||
|
|
||||||
// install a parallel package from the new catalog
|
// install a parallel package from the new catalog
|
||||||
pkg::PackageRef p2 = root->getPackageById("org.flightgear.test.catalog-alt.b737-NG");
|
pkg::PackageRef p2 = root->getPackageById("org.flightgear.test.catalog-alt.b737-NG");
|
||||||
SG_CHECK_EQUAL(p2->id(), "b737-NG");
|
SG_CHECK_EQUAL(p2->id(), "b737-NG");
|
||||||
@@ -840,8 +843,8 @@ void testVersionMigrateToId(HTTP::Client* cl)
|
|||||||
pkg::PackageRef p3 = root->getPackageById("b737-NG");
|
pkg::PackageRef p3 = root->getPackageById("b737-NG");
|
||||||
SG_CHECK_EQUAL(p2, p3);
|
SG_CHECK_EQUAL(p2, p3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// test that re-init-ing doesn't mirgate again
|
// test that re-init-ing doesn't migrate again
|
||||||
{
|
{
|
||||||
pkg::RootRef root(new pkg::Root(rootPath, "7.5"));
|
pkg::RootRef root(new pkg::Root(rootPath, "7.5"));
|
||||||
root->setHTTPClient(cl);
|
root->setHTTPClient(cl);
|
||||||
@@ -1184,6 +1187,128 @@ void testMirrorsFailure(HTTP::Client* cl)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testMigrateInstalled(HTTP::Client *cl) {
|
||||||
|
SGPath rootPath(simgear::Dir::current().path());
|
||||||
|
rootPath.append("pkg_migrate_installed");
|
||||||
|
simgear::Dir pd(rootPath);
|
||||||
|
pd.removeChildren();
|
||||||
|
|
||||||
|
pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
|
||||||
|
root->setHTTPClient(cl);
|
||||||
|
|
||||||
|
pkg::CatalogRef oldCatalog, newCatalog;
|
||||||
|
|
||||||
|
{
|
||||||
|
oldCatalog = pkg::Catalog::createFromUrl(
|
||||||
|
root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
|
||||||
|
waitForUpdateComplete(cl, root);
|
||||||
|
|
||||||
|
pkg::PackageRef p1 =
|
||||||
|
root->getPackageById("org.flightgear.test.catalog1.b747-400");
|
||||||
|
p1->install();
|
||||||
|
auto p2 = root->getPackageById("org.flightgear.test.catalog1.c172p");
|
||||||
|
p2->install();
|
||||||
|
auto p3 = root->getPackageById("org.flightgear.test.catalog1.b737-NG");
|
||||||
|
p3->install();
|
||||||
|
waitForUpdateComplete(cl, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
newCatalog = pkg::Catalog::createFromUrl(
|
||||||
|
root.ptr(), "http://localhost:2000/catalogTest2/catalog.xml");
|
||||||
|
waitForUpdateComplete(cl, root);
|
||||||
|
|
||||||
|
string_list existing;
|
||||||
|
for (const auto &pack : oldCatalog->installedPackages()) {
|
||||||
|
existing.push_back(pack->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_CHECK_EQUAL(4, existing.size());
|
||||||
|
|
||||||
|
int result = newCatalog->markPackagesForInstallation(existing);
|
||||||
|
SG_CHECK_EQUAL(2, result);
|
||||||
|
SG_CHECK_EQUAL(2, newCatalog->packagesNeedingUpdate().size());
|
||||||
|
|
||||||
|
auto p1 = root->getPackageById("org.flightgear.test.catalog2.b737-NG");
|
||||||
|
auto ins = p1->existingInstall();
|
||||||
|
SG_CHECK_EQUAL(0, ins->revsion());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
root->scheduleAllUpdates();
|
||||||
|
waitForUpdateComplete(cl, root);
|
||||||
|
|
||||||
|
SG_CHECK_EQUAL(0, newCatalog->packagesNeedingUpdate().size());
|
||||||
|
|
||||||
|
auto p1 = root->getPackageById("org.flightgear.test.catalog2.b737-NG");
|
||||||
|
auto ins = p1->existingInstall();
|
||||||
|
SG_CHECK_EQUAL(ins->revsion(), p1->revision());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testDontMigrateRemoved(HTTP::Client *cl) {
|
||||||
|
global_catalogVersion = 2; // version which has migration info
|
||||||
|
SGPath rootPath(simgear::Dir::current().path());
|
||||||
|
rootPath.append("cat_dont_migrate_id");
|
||||||
|
simgear::Dir pd(rootPath);
|
||||||
|
pd.removeChildren();
|
||||||
|
|
||||||
|
// install and mnaully remove the alt catalog
|
||||||
|
|
||||||
|
{
|
||||||
|
pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
|
||||||
|
root->setHTTPClient(cl);
|
||||||
|
|
||||||
|
pkg::CatalogRef c = pkg::Catalog::createFromUrl(
|
||||||
|
root.ptr(), "http://localhost:2000/catalogTest1/catalog-alt.xml");
|
||||||
|
waitForUpdateComplete(cl, root);
|
||||||
|
|
||||||
|
root->removeCatalogById("org.flightgear.test.catalog-alt");
|
||||||
|
}
|
||||||
|
|
||||||
|
// install the migration catalog
|
||||||
|
{
|
||||||
|
pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
|
||||||
|
root->setHTTPClient(cl);
|
||||||
|
|
||||||
|
pkg::CatalogRef c = pkg::Catalog::createFromUrl(
|
||||||
|
root.ptr(), "http://localhost:2000/catalogTest1/catalog.xml");
|
||||||
|
waitForUpdateComplete(cl, root);
|
||||||
|
SG_VERIFY(c->isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// change version to an alternate one
|
||||||
|
{
|
||||||
|
pkg::RootRef root(new pkg::Root(rootPath, "7.5"));
|
||||||
|
|
||||||
|
auto removed = root->explicitlyRemovedCatalogs();
|
||||||
|
auto j = std::find(removed.begin(), removed.end(),
|
||||||
|
"org.flightgear.test.catalog-alt");
|
||||||
|
SG_VERIFY(j != removed.end());
|
||||||
|
|
||||||
|
root->setHTTPClient(cl);
|
||||||
|
|
||||||
|
// this would tirgger migration, but we blocked it
|
||||||
|
root->refresh(true);
|
||||||
|
waitForUpdateComplete(cl, root);
|
||||||
|
|
||||||
|
pkg::CatalogRef cat = root->getCatalogById("org.flightgear.test.catalog1");
|
||||||
|
SG_VERIFY(!cat->isEnabled());
|
||||||
|
SG_CHECK_EQUAL(cat->status(), pkg::Delegate::FAIL_VERSION);
|
||||||
|
SG_CHECK_EQUAL(cat->id(), "org.flightgear.test.catalog1");
|
||||||
|
SG_CHECK_EQUAL(cat->url(),
|
||||||
|
"http://localhost:2000/catalogTest1/catalog.xml");
|
||||||
|
|
||||||
|
auto enabledCats = root->catalogs();
|
||||||
|
auto it = std::find(enabledCats.begin(), enabledCats.end(), cat);
|
||||||
|
SG_VERIFY(it == enabledCats.end());
|
||||||
|
|
||||||
|
// check the new catalog
|
||||||
|
auto altCat = root->getCatalogById("org.flightgear.test.catalog-alt");
|
||||||
|
SG_VERIFY(altCat.get() == nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
sglog().setLogLevels( SG_ALL, SG_WARN );
|
sglog().setLogLevels( SG_ALL, SG_WARN );
|
||||||
@@ -1228,7 +1353,11 @@ int main(int argc, char* argv[])
|
|||||||
testInstallBadPackage(&cl);
|
testInstallBadPackage(&cl);
|
||||||
|
|
||||||
testMirrorsFailure(&cl);
|
testMirrorsFailure(&cl);
|
||||||
|
|
||||||
|
testMigrateInstalled(&cl);
|
||||||
|
|
||||||
|
testDontMigrateRemoved(&cl);
|
||||||
|
|
||||||
cerr << "Successfully passed all tests!" << endl;
|
cerr << "Successfully passed all tests!" << endl;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,6 +198,11 @@ InstallRef Package::install()
|
|||||||
{
|
{
|
||||||
InstallRef ins = existingInstall();
|
InstallRef ins = existingInstall();
|
||||||
if (ins) {
|
if (ins) {
|
||||||
|
// if there's updates, treat this as a 'start update' request
|
||||||
|
if (ins->hasUpdate()) {
|
||||||
|
m_catalog->root()->scheduleToUpdate(ins);
|
||||||
|
}
|
||||||
|
|
||||||
return ins;
|
return ins;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,13 +215,39 @@ InstallRef Package::install()
|
|||||||
return ins;
|
return ins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstallRef Package::markForInstall() {
|
||||||
|
InstallRef ins = existingInstall();
|
||||||
|
if (ins) {
|
||||||
|
return ins;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto pd = pathOnDisk();
|
||||||
|
|
||||||
|
Dir dir(pd);
|
||||||
|
if (!dir.create(0700)) {
|
||||||
|
SG_LOG(SG_IO, SG_ALERT,
|
||||||
|
"Package::markForInstall: couldn't create directory at:" << pd);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ins = new Install{this, pd};
|
||||||
|
_install_cb(this, ins); // not sure if we should trigger the callback for this
|
||||||
|
|
||||||
|
// repeat for dependencies to be kind
|
||||||
|
for (auto dep : dependencies()) {
|
||||||
|
dep->markForInstall();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ins;
|
||||||
|
}
|
||||||
|
|
||||||
InstallRef Package::existingInstall(const InstallCallback& cb) const
|
InstallRef Package::existingInstall(const InstallCallback& cb) const
|
||||||
{
|
{
|
||||||
InstallRef install;
|
InstallRef install;
|
||||||
try {
|
try {
|
||||||
install = m_catalog->root()->existingInstallForPackage(const_cast<Package*>(this));
|
install = m_catalog->root()->existingInstallForPackage(const_cast<Package*>(this));
|
||||||
} catch (std::exception& ) {
|
} catch (std::exception& ) {
|
||||||
return InstallRef();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if( cb )
|
if( cb )
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ public:
|
|||||||
InstallRef
|
InstallRef
|
||||||
existingInstall(const InstallCallback& cb = InstallCallback()) const;
|
existingInstall(const InstallCallback& cb = InstallCallback()) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark this package for installation, but don't actually start the
|
||||||
|
* download process. This creates the on-disk placeholder, so
|
||||||
|
* the package will appear an eededing to be updated.
|
||||||
|
*/
|
||||||
|
InstallRef markForInstall();
|
||||||
|
|
||||||
bool isInstalled() const;
|
bool isInstalled() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -283,6 +283,32 @@ public:
|
|||||||
fireDataForThumbnail(url, reinterpret_cast<const uint8_t*>(bytes.data()), bytes.size());
|
fireDataForThumbnail(url, reinterpret_cast<const uint8_t*>(bytes.data()), bytes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writeRemovedCatalogsFile() const {
|
||||||
|
SGPath p = path / "RemovedCatalogs";
|
||||||
|
sg_ofstream stream(p, std::ios::out | std::ios::trunc | std::ios::binary);
|
||||||
|
for (const auto &cid : manuallyRemovedCatalogs) {
|
||||||
|
stream << cid << "\n";
|
||||||
|
}
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadRemovedCatalogsFile() {
|
||||||
|
manuallyRemovedCatalogs.clear();
|
||||||
|
SGPath p = path / "RemovedCatalogs";
|
||||||
|
if (!p.exists())
|
||||||
|
return;
|
||||||
|
|
||||||
|
sg_ifstream stream(p, std::ios::in);
|
||||||
|
while (!stream.eof()) {
|
||||||
|
std::string line;
|
||||||
|
std::getline(stream, line);
|
||||||
|
const auto trimmed = strutils::strip(line);
|
||||||
|
if (!trimmed.empty()) {
|
||||||
|
manuallyRemovedCatalogs.push_back(trimmed);
|
||||||
|
}
|
||||||
|
} // of lines iteration
|
||||||
|
}
|
||||||
|
|
||||||
DelegateVec delegates;
|
DelegateVec delegates;
|
||||||
|
|
||||||
SGPath path;
|
SGPath path;
|
||||||
@@ -312,6 +338,9 @@ public:
|
|||||||
|
|
||||||
typedef std::map<PackageRef, InstallRef> InstallCache;
|
typedef std::map<PackageRef, InstallRef> InstallCache;
|
||||||
InstallCache m_installs;
|
InstallCache m_installs;
|
||||||
|
|
||||||
|
/// persistent list of catalogs the user has manually removed
|
||||||
|
string_list manuallyRemovedCatalogs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -400,6 +429,8 @@ Root::Root(const SGPath& aPath, const std::string& aVersion) :
|
|||||||
thumbsCacheDir.create(0755);
|
thumbsCacheDir.create(0755);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d->loadRemovedCatalogsFile();
|
||||||
|
|
||||||
for (SGPath c : dir.children(Dir::TYPE_DIR | Dir::NO_DOT_OR_DOTDOT)) {
|
for (SGPath c : dir.children(Dir::TYPE_DIR | Dir::NO_DOT_OR_DOTDOT)) {
|
||||||
// note this will set the catalog status, which will insert into
|
// note this will set the catalog status, which will insert into
|
||||||
// disabled catalogs automatically if necesary
|
// disabled catalogs automatically if necesary
|
||||||
@@ -621,6 +652,13 @@ void Root::scheduleToUpdate(InstallRef aInstall)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Root::scheduleAllUpdates() {
|
||||||
|
auto toBeUpdated = packagesNeedingUpdate(); // make a copy
|
||||||
|
for (const auto &u : toBeUpdated) {
|
||||||
|
scheduleToUpdate(u->existingInstall());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Root::isInstallQueued(InstallRef aInstall) const
|
bool Root::isInstallQueued(InstallRef aInstall) const
|
||||||
{
|
{
|
||||||
auto it = std::find(d->updateDeque.begin(), d->updateDeque.end(), aInstall);
|
auto it = std::find(d->updateDeque.begin(), d->updateDeque.end(), aInstall);
|
||||||
@@ -783,6 +821,9 @@ bool Root::removeCatalogById(const std::string& aId)
|
|||||||
<< "failed to remove directory");
|
<< "failed to remove directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d->manuallyRemovedCatalogs.push_back(aId);
|
||||||
|
d->writeRemovedCatalogsFile();
|
||||||
|
|
||||||
// notify that a catalog is being removed
|
// notify that a catalog is being removed
|
||||||
d->firePackagesChanged();
|
d->firePackagesChanged();
|
||||||
|
|
||||||
@@ -854,6 +895,10 @@ void Root::unregisterInstall(InstallRef ins)
|
|||||||
d->fireFinishUninstall(ins->package());
|
d->fireFinishUninstall(ins->package());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string_list Root::explicitlyRemovedCatalogs() const {
|
||||||
|
return d->manuallyRemovedCatalogs;
|
||||||
|
}
|
||||||
|
|
||||||
} // of namespace pkg
|
} // of namespace pkg
|
||||||
|
|
||||||
} // of namespace simgear
|
} // of namespace simgear
|
||||||
|
|||||||
@@ -155,7 +155,22 @@ public:
|
|||||||
void requestThumbnailData(const std::string& aUrl);
|
void requestThumbnailData(const std::string& aUrl);
|
||||||
|
|
||||||
bool isInstallQueued(InstallRef aInstall) const;
|
bool isInstallQueued(InstallRef aInstall) const;
|
||||||
private:
|
|
||||||
|
/**
|
||||||
|
* Mark all 'to be updated' packages for update now
|
||||||
|
*/
|
||||||
|
void scheduleAllUpdates();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief list of catalog IDs, the user has explicitly removed via
|
||||||
|
* removeCatalogById(). This is important to allow the user to opt-out
|
||||||
|
* of migrated packages.
|
||||||
|
*
|
||||||
|
* This information is stored in a helper file, in the root directory
|
||||||
|
*/
|
||||||
|
string_list explicitlyRemovedCatalogs() const;
|
||||||
|
|
||||||
|
private:
|
||||||
friend class Install;
|
friend class Install;
|
||||||
friend class Catalog;
|
friend class Catalog;
|
||||||
friend class Package;
|
friend class Package;
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<PropertyList>
|
||||||
|
<id>org.flightgear.test.catalog2</id>
|
||||||
|
<description>Second test catalog</description>
|
||||||
|
<url>http://localhost:2000/catalogTest2/catalog.xml</url>
|
||||||
|
<catalog-version>4</catalog-version>
|
||||||
|
|
||||||
|
<version>8.1.*</version>
|
||||||
|
<version>8.0.0</version>
|
||||||
|
<version>8.2.0</version>
|
||||||
|
|
||||||
|
<package>
|
||||||
|
<id>alpha</id>
|
||||||
|
<name>Alpha package</name>
|
||||||
|
<revision type="int">8</revision>
|
||||||
|
<file-size-bytes type="int">593</file-size-bytes>
|
||||||
|
|
||||||
|
<md5>a469c4b837f0521db48616cfe65ac1ea</md5>
|
||||||
|
<url>http://localhost:2000/catalogTest1/alpha.zip</url>
|
||||||
|
|
||||||
|
<dir>alpha</dir>
|
||||||
|
|
||||||
|
</package>
|
||||||
|
|
||||||
|
|
||||||
|
<package>
|
||||||
|
<id>b737-NG</id>
|
||||||
|
<name>Boeing 737 NG</name>
|
||||||
|
<dir>b737NG</dir>
|
||||||
|
<description>A popular twin-engined narrow body jet</description>
|
||||||
|
<revision type="int">111</revision>
|
||||||
|
<file-size-bytes type="int">860</file-size-bytes>
|
||||||
|
|
||||||
|
<tag>boeing</tag>
|
||||||
|
<tag>jet</tag>
|
||||||
|
<tag>ifr</tag>
|
||||||
|
|
||||||
|
<!-- not within a localized element -->
|
||||||
|
<de>
|
||||||
|
<description>German description of B737NG XYZ</description>
|
||||||
|
</de>
|
||||||
|
<fr>
|
||||||
|
<description>French description of B737NG</description>
|
||||||
|
</fr>
|
||||||
|
|
||||||
|
<rating>
|
||||||
|
<FDM type="int">5</FDM>
|
||||||
|
<systems type="int">5</systems>
|
||||||
|
<model type="int">4</model>
|
||||||
|
<cockpit type="int">4</cockpit>
|
||||||
|
</rating>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<package>
|
||||||
|
<id>b747-400</id>
|
||||||
|
<name>Boeing 747-400</name>
|
||||||
|
<dir>b744</dir>
|
||||||
|
<description>A popular four-engined wide-body jet</description>
|
||||||
|
<revision type="int">111</revision>
|
||||||
|
<file-size-bytes type="int">860</file-size-bytes>
|
||||||
|
|
||||||
|
<tag>boeing</tag>
|
||||||
|
<tag>jet</tag>
|
||||||
|
<tag>ifr</tag>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<rating>
|
||||||
|
<FDM type="int">5</FDM>
|
||||||
|
<systems type="int">5</systems>
|
||||||
|
<model type="int">4</model>
|
||||||
|
<cockpit type="int">4</cockpit>
|
||||||
|
</rating>
|
||||||
|
|
||||||
|
<md5>4d3f7417d74f811aa20ccc4f35673d20</md5>
|
||||||
|
<!-- this URL will sometimes fail, on purpose -->
|
||||||
|
<url>http://localhost:2000/catalogTest1/b747.tar.gz</url>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
</PropertyList>
|
||||||
@@ -380,7 +380,8 @@ namespace simgear
|
|||||||
ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size, ALfloat& freqf, unsigned int& block_align)
|
ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size, ALfloat& freqf, unsigned int& block_align)
|
||||||
{
|
{
|
||||||
if (!path.exists()) {
|
if (!path.exists()) {
|
||||||
throw sg_io_exception("loadWAVFromFile: file not found", path);
|
SG_LOG(SG_IO, SG_DEV_ALERT, "loadWAVFromFile: file not found:" << path);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer b;
|
Buffer b;
|
||||||
@@ -395,13 +396,15 @@ ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size,
|
|||||||
fd = gzopen(ps.c_str(), "rb");
|
fd = gzopen(ps.c_str(), "rb");
|
||||||
#endif
|
#endif
|
||||||
if (!fd) {
|
if (!fd) {
|
||||||
throw sg_io_exception("loadWAVFromFile: unable to open file", path);
|
SG_LOG(SG_IO, SG_DEV_ALERT, "loadWAVFromFile: unable to open file:" << path);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loadWavFile(fd, &b);
|
loadWavFile(fd, &b);
|
||||||
} catch (sg_exception& e) {
|
} catch (sg_exception& e) {
|
||||||
throw sg_io_exception(e.getFormattedMessage() + "\nfor: " + path.str());
|
SG_LOG(SG_IO, SG_DEV_ALERT, "loadWAVFromFile:" << e.getFormattedMessage() << "\nfor: " << path);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALvoid* data = b.data;
|
ALvoid* data = b.data;
|
||||||
|
|||||||
@@ -813,13 +813,14 @@ bool SGSoundMgr::load( const std::string &samplepath,
|
|||||||
|
|
||||||
auto data = simgear::loadWAVFromFile(samplepath, format, size, freqf, blocksz);
|
auto data = simgear::loadWAVFromFile(samplepath, format, size, freqf, blocksz);
|
||||||
freq = (ALsizei)freqf;
|
freq = (ALsizei)freqf;
|
||||||
if (data == nullptr) {
|
if (!data) {
|
||||||
throw sg_io_exception("Failed to load wav file", sg_location(samplepath));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16) {
|
if (format == AL_FORMAT_STEREO8 || format == AL_FORMAT_STEREO16) {
|
||||||
free(data);
|
free(data);
|
||||||
throw sg_io_exception("Warning: STEREO files are not supported for 3D audio effects: " + samplepath);
|
SG_LOG(SG_IO, SG_DEV_ALERT, "Warning: STEREO files are not supported for 3D audio effects: " << samplepath);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*dbuf = (void *)data;
|
*dbuf = (void *)data;
|
||||||
|
|||||||
Reference in New Issue
Block a user