Add button in options menu to migrate to shared data directory a18855301306
Summary of migrated files will be shown to user in a popup, and a log file with every moved file will be left in the original directory stamps, saves, scripts, screenshots, and powder.pref will be migrated. Recordings are not.
This commit is contained in:
parent
0292344328
commit
b3aa6252ce
@ -738,32 +738,34 @@ int main(int argc, char * argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
Platform::originalCwd = Platform::GetCwd();
|
||||
|
||||
std::map<ByteString, ByteString> arguments = readArguments(argc, argv);
|
||||
|
||||
if(arguments["ddir"].length())
|
||||
if (arguments["ddir"].length())
|
||||
{
|
||||
#ifdef WIN
|
||||
int failure = _chdir(arguments["ddir"].c_str());
|
||||
#else
|
||||
int failure = chdir(arguments["ddir"].c_str());
|
||||
#endif
|
||||
if (failure)
|
||||
{
|
||||
if (!failure)
|
||||
Platform::sharedCwd = Platform::GetCwd();
|
||||
else
|
||||
perror("failed to chdir to requested ddir");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *ddir = SDL_GetPrefPath(NULL, "The Powder Toy");
|
||||
#ifdef WIN
|
||||
struct _stat s;
|
||||
if(_stat("powder.pref", &s) != 0)
|
||||
if (_stat("powder.pref", &s) != 0)
|
||||
#else
|
||||
struct stat s;
|
||||
if(stat("powder.pref", &s) != 0)
|
||||
if (stat("powder.pref", &s) != 0)
|
||||
#endif
|
||||
{
|
||||
char *ddir = SDL_GetPrefPath(NULL, "The Powder Toy");
|
||||
if(ddir)
|
||||
if (ddir)
|
||||
{
|
||||
#ifdef WIN
|
||||
int failure = _chdir(ddir);
|
||||
@ -773,10 +775,17 @@ int main(int argc, char * argv[])
|
||||
if (failure)
|
||||
{
|
||||
perror("failed to chdir to default ddir");
|
||||
SDL_free(ddir);
|
||||
ddir = nullptr;
|
||||
}
|
||||
SDL_free(ddir);
|
||||
}
|
||||
}
|
||||
|
||||
if (ddir)
|
||||
{
|
||||
Platform::sharedCwd = ddir;
|
||||
SDL_free(ddir);
|
||||
}
|
||||
}
|
||||
|
||||
scale = Client::Ref().GetPrefInteger("Scale", 1);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <dirent.h>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef WIN
|
||||
@ -29,11 +30,13 @@
|
||||
namespace Platform
|
||||
{
|
||||
|
||||
std::string originalCwd;
|
||||
std::string sharedCwd;
|
||||
|
||||
ByteString GetCwd()
|
||||
{
|
||||
char cwdTemp[PATH_MAX];
|
||||
getcwd(cwdTemp, PATH_MAX);
|
||||
return cwdTemp;
|
||||
char *cwd = getcwd(NULL, 0);
|
||||
return cwd == nullptr ? "" : cwd;
|
||||
}
|
||||
|
||||
ByteString ExecutableName()
|
||||
@ -324,11 +327,13 @@ std::vector<ByteString> DirectorySearch(ByteString directory, ByteString search,
|
||||
{
|
||||
ByteString currentFileName = ByteString(directoryEntry->d_name);
|
||||
if (currentFileName.length()>4)
|
||||
directoryList.push_back(directory+currentFileName);
|
||||
directoryList.push_back(currentFileName);
|
||||
}
|
||||
closedir(directoryHandle);
|
||||
#endif
|
||||
|
||||
search = search.ToLower();
|
||||
|
||||
std::vector<ByteString> searchResults;
|
||||
for (std::vector<ByteString>::iterator iter = directoryList.begin(), end = directoryList.end(); iter != end; ++iter)
|
||||
{
|
||||
@ -339,7 +344,7 @@ std::vector<ByteString> DirectorySearch(ByteString directory, ByteString search,
|
||||
if (filename.EndsWith(*extIter))
|
||||
{
|
||||
extensionMatch = true;
|
||||
tempfilename = filename.SubstrFromEnd(0, (*extIter).size()).ToUpper();
|
||||
tempfilename = filename.SubstrFromEnd(0, (*extIter).size()).ToLower();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -355,6 +360,138 @@ std::vector<ByteString> DirectorySearch(ByteString directory, ByteString search,
|
||||
return searchResults;
|
||||
}
|
||||
|
||||
String DoMigration(ByteString fromDir, ByteString toDir)
|
||||
{
|
||||
if (fromDir.at(fromDir.length() - 1) != '/')
|
||||
fromDir = fromDir + '/';
|
||||
if (toDir.at(toDir.length() - 1) != '/')
|
||||
toDir = toDir + '/';
|
||||
|
||||
std::ofstream logFile(fromDir + "/migrationlog.txt", std::ios::out);
|
||||
logFile << "Running migration of data from " << fromDir + " to " << toDir << std::endl;
|
||||
|
||||
// Get lists of files to migrate
|
||||
auto stamps = DirectorySearch(fromDir + "stamps", "", { ".stm" });
|
||||
auto saves = DirectorySearch(fromDir + "Saves", "", { ".cps", ".stm" });
|
||||
auto scripts = DirectorySearch(fromDir + "scripts", "", { ".lua", ".txt" });
|
||||
auto downloadedScripts = DirectorySearch(fromDir + "scripts/downloaded", "", { ".lua" });
|
||||
bool hasScriptinfo = FileExists(toDir + "scripts/downloaded/scriptinfo");
|
||||
auto screenshots = DirectorySearch(fromDir, "powdertoy-", { ".png" });
|
||||
bool hasAutorun = FileExists(fromDir + "autorun.lua");
|
||||
bool hasPref = FileExists(fromDir + "powder.pref");
|
||||
|
||||
if (stamps.empty() && saves.empty() && scripts.empty() && downloadedScripts.empty() && screenshots.empty() && !hasAutorun && !hasPref)
|
||||
{
|
||||
logFile << "Nothing to migrate.";
|
||||
return "Nothing to migrate. This button is used to migrate data from pre-96.0 TPT installations to the shared directory";
|
||||
}
|
||||
|
||||
StringBuilder result;
|
||||
std::stack<ByteString> dirsToDelete;
|
||||
|
||||
// Migrate a list of files
|
||||
auto migrateList = [&](std::vector<ByteString> list, ByteString directory, String niceName) {
|
||||
result << '\n' << niceName << ": ";
|
||||
if (!list.empty() && !directory.empty())
|
||||
MakeDirectory(toDir + directory);
|
||||
int migratedCount = 0, failedCount = 0;
|
||||
for (auto &item : list)
|
||||
{
|
||||
std::string from = fromDir + directory + "/" + item;
|
||||
std::string to = toDir + directory + "/" + item;
|
||||
if (!FileExists(to))
|
||||
{
|
||||
if (rename(from.c_str(), to.c_str()))
|
||||
{
|
||||
failedCount++;
|
||||
logFile << "failed to move " << from << " to " << to << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
migratedCount++;
|
||||
logFile << "moved " << from << " to " << to << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logFile << "skipping " << from << "(already exists)" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
dirsToDelete.push(directory);
|
||||
result << "\bt" << migratedCount << " migratated\x0E, \br" << failedCount << " failed\x0E";
|
||||
int duplicates = list.size() - migratedCount - failedCount;
|
||||
if (duplicates)
|
||||
result << ", " << list.size() - migratedCount - failedCount << " skipped (duplicate)";
|
||||
};
|
||||
|
||||
// Migrate a single file
|
||||
auto migrateFile = [&fromDir, &toDir, &result, &logFile](ByteString filename) {
|
||||
ByteString from = fromDir + filename;
|
||||
ByteString to = toDir + filename;
|
||||
if (!FileExists(to))
|
||||
{
|
||||
if (rename(from.c_str(), to.c_str()))
|
||||
{
|
||||
logFile << "failed to move " << from << " to " << to << std::endl;
|
||||
result << "\n\br" << filename.FromUtf8() << " migration failed\x0E";
|
||||
}
|
||||
else
|
||||
{
|
||||
logFile << "moved " << from << " to " << to << std::endl;
|
||||
result << '\n' << filename.FromUtf8() << " migrated";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logFile << "skipping " << from << "(already exists)" << std::endl;
|
||||
result << '\n' << filename.FromUtf8() << " skipped (already exists)";
|
||||
}
|
||||
|
||||
if (!DeleteFile(fromDir + filename)) {
|
||||
logFile << "failed to delete " << filename << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
// Do actual migration
|
||||
DeleteFile(fromDir + "stamps/stamps.def");
|
||||
migrateList(stamps, "stamps", "Stamps");
|
||||
migrateList(saves, "Saves", "Saves");
|
||||
if (!scripts.empty())
|
||||
migrateList(scripts, "scripts", "Scripts");
|
||||
if (!hasScriptinfo && !downloadedScripts.empty())
|
||||
{
|
||||
migrateList(downloadedScripts, "scripts/downloaded", "Downloaded scripts");
|
||||
migrateFile("scripts/downloaded/scriptinfo");
|
||||
}
|
||||
if (!screenshots.empty())
|
||||
migrateList(screenshots, "", "Screenshots");
|
||||
if (hasAutorun)
|
||||
migrateFile("autorun.lua");
|
||||
if (hasPref)
|
||||
migrateFile("powder.pref");
|
||||
|
||||
// Delete leftover directories
|
||||
while (!dirsToDelete.empty())
|
||||
{
|
||||
ByteString toDelete = dirsToDelete.top();
|
||||
if (!DeleteDirectory(fromDir + toDelete)) {
|
||||
logFile << "failed to delete " << toDelete << std::endl;
|
||||
}
|
||||
dirsToDelete.pop();
|
||||
}
|
||||
|
||||
// chdir into the new directory
|
||||
chdir(toDir.c_str());
|
||||
|
||||
if (scripts.size())
|
||||
Client::Ref().RescanStamps();
|
||||
|
||||
logFile << std::endl << std::endl << "Migration complete. Results: " << result.Build().ToUtf8();
|
||||
logFile.close();
|
||||
|
||||
return result.Build();
|
||||
}
|
||||
|
||||
#ifdef WIN
|
||||
ByteString WinNarrow(const std::wstring &source)
|
||||
|
@ -39,11 +39,15 @@ namespace Platform
|
||||
*/
|
||||
bool MakeDirectory(ByteString dir);
|
||||
std::vector<ByteString> DirectorySearch(ByteString directory, ByteString search, std::vector<ByteString> extensions);
|
||||
String DoMigration(ByteString fromDir, ByteString toDir);
|
||||
|
||||
#ifdef WIN
|
||||
ByteString WinNarrow(const std::wstring &source);
|
||||
std::wstring WinWiden(const ByteString &source);
|
||||
#endif
|
||||
|
||||
extern std::string originalCwd;
|
||||
extern std::string sharedCwd;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -44,10 +44,10 @@ class LoadFilesTask: public Task
|
||||
notifyProgress(-1);
|
||||
for(std::vector<ByteString>::iterator iter = files.begin(), end = files.end(); iter != end; ++iter)
|
||||
{
|
||||
SaveFile * saveFile = new SaveFile(*iter);
|
||||
SaveFile * saveFile = new SaveFile(directory + *iter);
|
||||
try
|
||||
{
|
||||
std::vector<unsigned char> data = Client::Ref().ReadFile(*iter);
|
||||
std::vector<unsigned char> data = Client::Ref().ReadFile(directory + *iter);
|
||||
GameSave * tempSave = new GameSave(data);
|
||||
saveFile->SetGameSave(tempSave);
|
||||
saveFiles.push_back(saveFile);
|
||||
|
@ -2,22 +2,19 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#ifdef WIN
|
||||
#include <direct.h>
|
||||
#define getcwd _getcwd
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "SDLCompat.h"
|
||||
|
||||
#include "OptionsController.h"
|
||||
#include "OptionsModel.h"
|
||||
|
||||
#include "client/Client.h"
|
||||
#include "common/Platform.h"
|
||||
#include "graphics/Graphics.h"
|
||||
#include "gui/Style.h"
|
||||
#include "simulation/ElementDefs.h"
|
||||
|
||||
#include "gui/dialogues/ConfirmPrompt.h"
|
||||
#include "gui/dialogues/InformationMessage.h"
|
||||
#include "gui/interface/Button.h"
|
||||
#include "gui/interface/Checkbox.h"
|
||||
#include "gui/interface/DropDown.h"
|
||||
@ -305,8 +302,6 @@ OptionsView::OptionsView():
|
||||
scrollPanel->AddChild(tempLabel);
|
||||
scrollPanel->AddChild(perfectCirclePressure);
|
||||
|
||||
//perfectCirclePressure
|
||||
|
||||
currentY+=20;
|
||||
decoSpace = new ui::DropDown(ui::Point(8, currentY), ui::Point(60, 16));
|
||||
decoSpace->SetActionCallback({ [this] { c->SetDecoSpace(decoSpace->GetOption().second); } });
|
||||
@ -324,23 +319,25 @@ OptionsView::OptionsView():
|
||||
currentY+=20;
|
||||
ui::Button * dataFolderButton = new ui::Button(ui::Point(8, currentY), ui::Point(90, 16), "Open Data Folder");
|
||||
dataFolderButton->SetActionCallback({ [] {
|
||||
auto *cwd = getcwd(NULL, 0);
|
||||
if (cwd)
|
||||
{
|
||||
ByteString cwd = Platform::GetCwd();
|
||||
if (!cwd.empty())
|
||||
Platform::OpenURI(cwd);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "cannot open data folder: getcwd(...) failed\n");
|
||||
}
|
||||
} });
|
||||
scrollPanel->AddChild(dataFolderButton);
|
||||
|
||||
tempLabel = new ui::Label(ui::Point(dataFolderButton->Position.X+dataFolderButton->Size.X+3, currentY), ui::Point(1, 16), "\bg- Open the data and preferences folder");
|
||||
autowidth(tempLabel);
|
||||
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
scrollPanel->AddChild(tempLabel);
|
||||
ui::Button * migrationButton = new ui::Button(ui::Point(Size.X - 178, currentY), ui::Point(163, 16), "Migrate to shared data directory");
|
||||
migrationButton->SetActionCallback({ [] {
|
||||
ByteString from = Platform::originalCwd;
|
||||
ByteString to = Platform::sharedCwd;
|
||||
new ConfirmPrompt("Do Migration?", "This will migrate all stamps, saves, and scripts from\n\bt" + from.FromUtf8() + "\bw\nto the shared data directory at\n\bt" + to.FromUtf8() + "\bw\n\n" +
|
||||
"Files that already exist will not be overwritten.", { [=] () {
|
||||
String ret = Platform::DoMigration(from, to);
|
||||
new InformationMessage("Migration Complete", ret, false);
|
||||
} });
|
||||
} });
|
||||
scrollPanel->AddChild(migrationButton);
|
||||
|
||||
ui::Button * tempButton = new ui::Button(ui::Point(0, Size.Y-16), ui::Point(Size.X, 16), "OK");
|
||||
tempButton->SetActionCallback({ [this] { c->Exit(); } });
|
||||
|
Loading…
Reference in New Issue
Block a user