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:
parent
a9a85a618e
commit
3e1a701712
4 changed files with 287 additions and 1 deletions
|
@ -187,4 +187,5 @@ endif()
|
|||
|
||||
if (COMMAND flightgear_test)
|
||||
flightgear_test(posinit test_posinit.cxx)
|
||||
flightgear_test(autosaveMigration test_autosaveMigration.cxx)
|
||||
endif()
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
166
src/Main/test_autosaveMigration.cxx
Normal file
166
src/Main/test_autosaveMigration.cxx
Normal 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;
|
||||
}
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue