1
0
Fork 0

Migrate old autosave XML files. (Disabled for now)

Code and tests to demonstrate migrating of older auto-save files, with
blacklisting support to exclude properties. Disabled pending agreement
on the required blacklisting values.
This commit is contained in:
James Turner 2017-04-10 14:38:35 +01:00
parent a9a85a618e
commit 3e1a701712
4 changed files with 287 additions and 1 deletions

View file

@ -187,4 +187,5 @@ endif()
if (COMMAND flightgear_test)
flightgear_test(posinit test_posinit.cxx)
flightgear_test(autosaveMigration test_autosaveMigration.cxx)
endif()

View file

@ -675,6 +675,103 @@ SGPath FGGlobals::autosaveFilePath(SGPath userDataPath) const
return simgear::Dir(userDataPath).file(autosaveName());
}
static void deleteProperties(SGPropertyNode* props, const string_list& blacklist)
{
const std::string path(props->getPath());
auto it = std::find_if(blacklist.begin(), blacklist.end(), [path](const std::string& black)
{ return simgear::strutils::matchPropPathToTemplate(path, black); });
if (it != blacklist.end()) {
SGPropertyNode* pr = props->getParent();
pr->removeChild(props);
return;
}
// recurse
for (int c=0; c < props->nChildren(); ++c) {
deleteProperties(props->getChild(c), blacklist);
}
}
using VersionPair = std::pair<int, int>;
static bool operator<(const VersionPair& a, const VersionPair& b)
{
if (a.first == b.first) {
return a.second < b.second;
}
return a.first < b.first;
}
static void tryAutosaveMigration(const SGPath& userDataPath, SGPropertyNode* props)
{
const string_list versionParts = simgear::strutils::split(VERSION, ".");
if (versionParts.size() < 2) {
return;
}
simgear::Dir userDataDir(userDataPath);
SGPath migratePath;
VersionPair foundVersion(0, 0);
const VersionPair currentVersion(simgear::strutils::to_int(versionParts[0]),
simgear::strutils::to_int(versionParts[1]));
for (auto previousSave : userDataDir.children(simgear::Dir::TYPE_FILE, ".xml")) {
const std::string base = previousSave.file_base();
VersionPair v;
// extract version from name
const int matches = ::sscanf(base.c_str(), "autosave_%d_%d", &v.first, &v.second);
if (matches != 2) {
continue;
}
if (currentVersion < v) {
// ignore autosaves from more recent versions; this happens when
// running unsable and stable at the same time
continue;
}
if (v.first < 2000) {
// ignore autosaves from older versions, too much change to deal
// with.
continue;
}
if (foundVersion < v) {
foundVersion = v;
migratePath = previousSave;
}
}
if (!migratePath.exists()) {
return;
}
SG_LOG(SG_GENERAL, SG_INFO, "Migrating old autosave:" << migratePath);
SGPropertyNode oldProps;
try {
readProperties(migratePath, &oldProps, SGPropertyNode::USERARCHIVE);
} catch (sg_exception& e) {
SG_LOG(SG_GENERAL, SG_WARN, "failed to read previous user settings:" << e.getMessage()
<< "(from " << e.getOrigin() << ")");
return;
}
// read migration blacklist
string_list blacklist;
for (auto node : fgGetNode("/sim/autosave-migration/blacklist")->getChildren("path")) {
blacklist.push_back(node->getStringValue());
}
// apply migration filters for each property in turn
deleteProperties(&oldProps, blacklist);
// copy remaining props out
copyProperties(&oldProps, props);
}
// Load user settings from the autosave file (normally in $FG_HOME)
void
FGGlobals::loadUserSettings(SGPath userDataPath)
@ -697,6 +794,10 @@ FGGlobals::loadUserSettings(SGPath userDataPath)
SG_LOG(SG_INPUT, SG_WARN, "failed to read user settings:" << e.getMessage()
<< "(from " << e.getOrigin() << ")");
}
} else {
#if 0
tryAutosaveMigration(userDataPath, &autosave);
#endif
}
copyProperties(&autosave, globals->get_props());
}

View file

@ -0,0 +1,166 @@
// Written by James Turner, started 2017.
//
// Copyright (C) 2017 James Turner
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program 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
// 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 "config.h"
#include "unitTestHelpers.hxx"
#include <simgear/misc/test_macros.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/misc/sg_dir.hxx>
#include "Main/globals.hxx"
#include "Main/options.hxx"
#include "Main/fg_props.hxx"
using namespace flightgear;
void writeLegacyAutosave(SGPath userData, int majorVersion, int minorVersion)
{
std::ostringstream os;
os << "autosave_" << majorVersion << "_" << minorVersion << ".xml";
sg_ofstream of(userData / os.str());
{
of << "<?xml version=\"1.0\"?>" \
"<PropertyList>" \
"<sim>" \
"<window-height>42</window-height>" \
"<presets>" \
"<foo>12</foo>" \
"<child><bar>12</bar></child>" \
"</presets>" \
"<presets n=\"1\">" \
"<foo>13</foo>" \
"</presets>" \
"<rendering>" \
"<msaa>10</msaa>" \
"<texture-size>512</texture-size>" \
"<texture-pack>" \
"<foo>abc</foo>" \
"<wibble>abc</wibble>" \
"</texture-pack>" \
"</rendering>" \
"<gui>" \
"<dialog n=\"1\">" \
"<widget>button</widget>" \
"</dialog>" \
"<dialog n=\"2\">" \
"<widget>slider</widget>" \
"</dialog>"\
"</gui>" \
"</sim>" \
"<some-setting>888</some-setting>" \
"<views>" \
"<view>" \
"<new-prop>somevalue</new-prop>" \
"<old-prop>somevalue</old-prop>" \
"</view>" \
"</views>" \
"</PropertyList>";
}
of.close();
}
void writeLegacyAutosave2(SGPath userData, int majorVersion, int minorVersion)
{
std::ostringstream os;
os << "autosave_" << majorVersion << "_" << minorVersion << ".xml";
sg_ofstream of(userData / os.str());
{
of << "<?xml version=\"1.0\"?>" \
"<PropertyList>" \
"<sim>" \
"<bad>1</bad>" \
"</sim>" \
"</views>" \
"</PropertyList>";
}
of.close();
}
void testMigration()
{
fgtest::initTestGlobals("autosaveMigration");
Options::reset();
SGPath testUserDataPath = globals->get_fg_home() / "test_autosave_migrate";
if (!testUserDataPath.exists()) {
SGPath p = testUserDataPath / "foo";
p.create_dir(0755);
}
simgear::Dir homeDir(testUserDataPath);
for (auto path : homeDir.children(simgear::Dir::TYPE_FILE, ".xml")) {
path.remove();
}
writeLegacyAutosave(testUserDataPath, 2016, 1);
const string_list versionParts = simgear::strutils::split(VERSION, ".");
SG_VERIFY(versionParts.size() == 3);
const int currentMajor = simgear::strutils::to_int(versionParts[0]);
const int currentMinor = simgear::strutils::to_int(versionParts[1]);
// none of these should not be read
writeLegacyAutosave2(testUserDataPath, 2016, 0);
writeLegacyAutosave2(testUserDataPath, currentMajor, currentMinor + 1);
writeLegacyAutosave2(testUserDataPath, currentMajor+1, currentMinor + 1);
SGPath p = globals->autosaveFilePath(testUserDataPath);
if (p.exists()) {
SG_VERIFY(p.remove());
}
// write some blck-list rules to property tree
SGPropertyNode_ptr blacklist = fgGetNode("/sim/autosave-migration/blacklist", true);
blacklist->addChild("path")->setStringValue("/sim[0]/presets[0]/*");
blacklist->addChild("path")->setStringValue("/sim[0]/rendering[0]/texture-");
blacklist->addChild("path")->setStringValue("/views[0]/view[*]/old-prop");
blacklist->addChild("path")->setStringValue("/sim[0]/gui");
// execute method under test
globals->loadUserSettings(testUserDataPath);
SG_CHECK_EQUAL(globals->get_props()->getNode("sim")->getChildren("presets").size(), 2);
SG_CHECK_EQUAL(globals->get_props()->getNode("sim")->getChildren("gui").size(), 0);
SG_CHECK_EQUAL(globals->get_props()->getIntValue("sim/window-height"), 42);
SG_CHECK_EQUAL(globals->get_props()->getIntValue("sim/presets/foo"), 0);
SG_CHECK_EQUAL(globals->get_props()->getIntValue("sim/presets[1]/foo"), 13);
SG_CHECK_EQUAL(globals->get_props()->getIntValue("some-setting"), 888);
// if this is not zero, one of the bad autosaves was read
SG_CHECK_EQUAL(globals->get_props()->getIntValue("sim/bad"), 0);
fgtest::shutdownTestGlobals();
}
int main(int argc, char* argv[])
{
testMigration();
return EXIT_SUCCESS;
}

View file

@ -1,3 +1,21 @@
// Written by James Turner, started 2017.
//
// Copyright (C) 2017 James Turner
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program 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
// 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 "config.h"
#include "unitTestHelpers.hxx"
@ -114,6 +132,6 @@ int main(int argc, char* argv[])
testDefaultStartup();
testAirportOnlyStartup();
testAirportAndMetarStartup();
return EXIT_SUCCESS;
}