GH-1060 update tweaks
* download to multimc folder hierarchy * use rename, not copy * keep backup after update * clean previous backup before update * it's not 'copy', it's 'replace'
This commit is contained in:
parent
22c5ced5dc
commit
15b7c3039a
@ -988,7 +988,8 @@ void MainWindow::downloadUpdates(GoUpdate::Status status)
|
|||||||
ProgressDialog updateDlg(this);
|
ProgressDialog updateDlg(this);
|
||||||
status.rootPath = MMC->rootPath;
|
status.rootPath = MMC->rootPath;
|
||||||
|
|
||||||
GoUpdate::DownloadTask updateTask(status, &updateDlg);
|
auto dlPath = PathCombine(MMC->root(), "update", "XXXXXX");
|
||||||
|
GoUpdate::DownloadTask updateTask(status, dlPath, &updateDlg);
|
||||||
// If the task succeeds, install the updates.
|
// If the task succeeds, install the updates.
|
||||||
if (updateDlg.exec(&updateTask))
|
if (updateDlg.exec(&updateTask))
|
||||||
{
|
{
|
||||||
|
@ -662,18 +662,20 @@ void MultiMC::installUpdates(const QString updateFilesDir, GoUpdate::OperationLi
|
|||||||
#error Unsupported operating system.
|
#error Unsupported operating system.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString backupPath = PathCombine(root(), "update-backup");
|
QString backupPath = PathCombine(root(), "update", "backup");
|
||||||
QString trashPath = PathCombine(root(), "update-trash");
|
|
||||||
|
// clean up the backup folder. it should be empty before we start
|
||||||
|
if(!deletePath(backupPath))
|
||||||
|
{
|
||||||
|
qWarning() << "couldn't remove previous backup folder" << backupPath;
|
||||||
|
}
|
||||||
|
// and it should exist.
|
||||||
if(!ensureFolderPathExists(backupPath))
|
if(!ensureFolderPathExists(backupPath))
|
||||||
{
|
{
|
||||||
qWarning() << "couldn't create folder" << backupPath;
|
qWarning() << "couldn't create folder" << backupPath;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!ensureFolderPathExists(trashPath))
|
|
||||||
{
|
|
||||||
qWarning() << "couldn't create folder" << trashPath;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
struct BackupEntry
|
struct BackupEntry
|
||||||
{
|
{
|
||||||
QString orig;
|
QString orig;
|
||||||
@ -681,30 +683,34 @@ void MultiMC::installUpdates(const QString updateFilesDir, GoUpdate::OperationLi
|
|||||||
};
|
};
|
||||||
enum Failure
|
enum Failure
|
||||||
{
|
{
|
||||||
Copy,
|
Replace,
|
||||||
Delete,
|
Delete,
|
||||||
Start,
|
Start,
|
||||||
Nothing
|
Nothing
|
||||||
} failedOperationType = Nothing;
|
} failedOperationType = Nothing;
|
||||||
|
|
||||||
QString failedFile;
|
QString failedFile;
|
||||||
|
|
||||||
QList <BackupEntry> backups;
|
QList <BackupEntry> backups;
|
||||||
QList <BackupEntry> trashcan;
|
QList <BackupEntry> trashcan;
|
||||||
|
|
||||||
|
// perform the update operations
|
||||||
for(auto op: operations)
|
for(auto op: operations)
|
||||||
{
|
{
|
||||||
switch(op.type)
|
switch(op.type)
|
||||||
{
|
{
|
||||||
case GoUpdate::Operation::OP_COPY:
|
// replace = move original out to backup, if it exists, move the new file in its place
|
||||||
|
case GoUpdate::Operation::OP_REPLACE:
|
||||||
{
|
{
|
||||||
QFileInfo replaced (PathCombine(root(), op.dest));
|
QFileInfo replaced (PathCombine(root(), op.dest));
|
||||||
if(replaced.exists())
|
if(replaced.exists())
|
||||||
{
|
{
|
||||||
QString backupFilePath = PathCombine(backupPath, replaced.fileName());
|
QString backupName = op.dest;
|
||||||
|
backupName.replace('/', '_');
|
||||||
|
QString backupFilePath = PathCombine(backupPath, backupName);
|
||||||
if(!QFile::rename(replaced.absoluteFilePath(), backupFilePath))
|
if(!QFile::rename(replaced.absoluteFilePath(), backupFilePath))
|
||||||
{
|
{
|
||||||
qWarning() << "Couldn't rename:" << replaced.absoluteFilePath() << "to" << backupFilePath;
|
qWarning() << "Couldn't move:" << replaced.absoluteFilePath() << "to" << backupFilePath;
|
||||||
failedOperationType = Copy;
|
failedOperationType = Replace;
|
||||||
failedFile = op.dest;
|
failedFile = op.dest;
|
||||||
goto FAILED;
|
goto FAILED;
|
||||||
}
|
}
|
||||||
@ -713,17 +719,26 @@ void MultiMC::installUpdates(const QString updateFilesDir, GoUpdate::OperationLi
|
|||||||
be.backup = backupFilePath;
|
be.backup = backupFilePath;
|
||||||
backups.append(be);
|
backups.append(be);
|
||||||
}
|
}
|
||||||
// FIXME: use rename instead.
|
// make sure the folder we are putting this into exists
|
||||||
if(!QFile::copy(op.file, replaced.absoluteFilePath()))
|
if(!ensureFilePathExists(replaced.absoluteFilePath()))
|
||||||
{
|
{
|
||||||
qWarning() << "CPY: Couldn't copy:" << op.file << "to" << replaced.absoluteFilePath();
|
qWarning() << "REPLACE: Couldn't create folder:" << replaced.absoluteFilePath();
|
||||||
failedOperationType = Copy;
|
failedOperationType = Replace;
|
||||||
|
failedFile = op.dest;
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
// now move the new file in
|
||||||
|
if(!QFile::rename(op.file, replaced.absoluteFilePath()))
|
||||||
|
{
|
||||||
|
qWarning() << "REPLACE: Couldn't move:" << op.file << "to" << replaced.absoluteFilePath();
|
||||||
|
failedOperationType = Replace;
|
||||||
failedFile = op.dest;
|
failedFile = op.dest;
|
||||||
goto FAILED;
|
goto FAILED;
|
||||||
}
|
}
|
||||||
QFile::setPermissions(replaced.absoluteFilePath(), unixModeToPermissions(op.mode));
|
QFile::setPermissions(replaced.absoluteFilePath(), unixModeToPermissions(op.mode));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
// delete = move original to backup
|
||||||
case GoUpdate::Operation::OP_DELETE:
|
case GoUpdate::Operation::OP_DELETE:
|
||||||
{
|
{
|
||||||
QString trashFilePath = PathCombine(backupPath, op.file);
|
QString trashFilePath = PathCombine(backupPath, op.file);
|
||||||
@ -732,7 +747,7 @@ void MultiMC::installUpdates(const QString updateFilesDir, GoUpdate::OperationLi
|
|||||||
{
|
{
|
||||||
if(!QFile::rename(origFilePath, trashFilePath))
|
if(!QFile::rename(origFilePath, trashFilePath))
|
||||||
{
|
{
|
||||||
qWarning() << "DEL: Couldn't move:" << op.file << "to" << trashFilePath;
|
qWarning() << "DELETE: Couldn't move:" << op.file << "to" << trashFilePath;
|
||||||
failedFile = op.file;
|
failedFile = op.file;
|
||||||
failedOperationType = Delete;
|
failedOperationType = Delete;
|
||||||
goto FAILED;
|
goto FAILED;
|
||||||
@ -758,15 +773,6 @@ void MultiMC::installUpdates(const QString updateFilesDir, GoUpdate::OperationLi
|
|||||||
failedOperationType = Start;
|
failedOperationType = Start;
|
||||||
goto FAILED;
|
goto FAILED;
|
||||||
}
|
}
|
||||||
// now clean up the backed up stuff.
|
|
||||||
for(auto backup:backups)
|
|
||||||
{
|
|
||||||
QFile::remove(backup.backup);
|
|
||||||
}
|
|
||||||
for(auto backup:trashcan)
|
|
||||||
{
|
|
||||||
QFile::remove(backup.backup);
|
|
||||||
}
|
|
||||||
qApp->quit();
|
qApp->quit();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -787,13 +793,17 @@ FAILED:
|
|||||||
if(!QFile::rename(backup.backup, backup.orig))
|
if(!QFile::rename(backup.backup, backup.orig))
|
||||||
{
|
{
|
||||||
revertOK = false;
|
revertOK = false;
|
||||||
qWarning() << "removing new" << backup.orig << "failed!";
|
qWarning() << "restoring" << backup.orig << "failed!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(auto backup:trashcan)
|
for(auto backup:trashcan)
|
||||||
{
|
{
|
||||||
qWarning() << "restoring" << backup.orig << "from" << backup.backup;
|
qWarning() << "restoring" << backup.orig << "from" << backup.backup;
|
||||||
revertOK &= QFile::rename(backup.backup, backup.orig);
|
if(!QFile::rename(backup.backup, backup.orig))
|
||||||
|
{
|
||||||
|
revertOK = false;
|
||||||
|
qWarning() << "restoring" << backup.orig << "failed!";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
QString msg;
|
QString msg;
|
||||||
if(!revertOK)
|
if(!revertOK)
|
||||||
@ -804,11 +814,13 @@ FAILED:
|
|||||||
}
|
}
|
||||||
else switch (failedOperationType)
|
else switch (failedOperationType)
|
||||||
{
|
{
|
||||||
case Copy:
|
case Replace:
|
||||||
msg = tr("Couldn't replace file %1. Changes were reverted.\nSee the MultiMC log file for details.").arg(failedFile);
|
msg = tr("Couldn't replace file %1. Changes were reverted.\n"
|
||||||
|
"See the MultiMC log file for details.").arg(failedFile);
|
||||||
break;
|
break;
|
||||||
case Delete:
|
case Delete:
|
||||||
msg = tr("Couldn't remove file %1. Changes were reverted.\nSee the MultiMC log file for details.").arg(failedFile);
|
msg = tr("Couldn't remove file %1. Changes were reverted.\n"
|
||||||
|
"See the MultiMC log file for details.").arg(failedFile);
|
||||||
break;
|
break;
|
||||||
case Start:
|
case Start:
|
||||||
msg = tr("The new version didn't start and the update was rolled back.");
|
msg = tr("The new version didn't start and the update was rolled back.");
|
||||||
@ -817,7 +829,7 @@ FAILED:
|
|||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QMessageBox::critical(nullptr, tr("Update failed"), msg);
|
QMessageBox::critical(nullptr, tr("Update failed!"), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MultiMC::setIconTheme(const QString& name)
|
void MultiMC::setIconTheme(const QString& name)
|
||||||
|
@ -27,8 +27,8 @@
|
|||||||
namespace GoUpdate
|
namespace GoUpdate
|
||||||
{
|
{
|
||||||
|
|
||||||
DownloadTask::DownloadTask(Status status, QObject *parent)
|
DownloadTask::DownloadTask(Status status, QString target, QObject *parent)
|
||||||
: Task(parent)
|
: Task(parent), m_updateFilesDir(target)
|
||||||
{
|
{
|
||||||
m_status = status;
|
m_status = status;
|
||||||
|
|
||||||
|
@ -30,7 +30,12 @@ class DownloadTask : public Task
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DownloadTask(Status status, QObject* parent = 0);
|
/**
|
||||||
|
* Create a download task
|
||||||
|
*
|
||||||
|
* target is a template - XXXXXX at the end will be replaced with a random generated string, ensuring uniqueness
|
||||||
|
*/
|
||||||
|
explicit DownloadTask(Status status, QString target, QObject* parent = 0);
|
||||||
|
|
||||||
/// Get the directory that will contain the update files.
|
/// Get the directory that will contain the update files.
|
||||||
QString updateFilesDir();
|
QString updateFilesDir();
|
||||||
|
@ -68,7 +68,7 @@ struct Operation
|
|||||||
{
|
{
|
||||||
static Operation CopyOp(QString fsource, QString fdest, int fmode=0644)
|
static Operation CopyOp(QString fsource, QString fdest, int fmode=0644)
|
||||||
{
|
{
|
||||||
return Operation{OP_COPY, fsource, fdest, fmode};
|
return Operation{OP_REPLACE, fsource, fdest, fmode};
|
||||||
}
|
}
|
||||||
static Operation DeleteOp(QString file)
|
static Operation DeleteOp(QString file)
|
||||||
{
|
{
|
||||||
@ -84,7 +84,7 @@ struct Operation
|
|||||||
//! Specifies the type of operation that this is.
|
//! Specifies the type of operation that this is.
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
OP_COPY,
|
OP_REPLACE,
|
||||||
OP_DELETE,
|
OP_DELETE,
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ QDebug operator<<(QDebug dbg, const Operation::Type &t)
|
|||||||
{
|
{
|
||||||
switch (t)
|
switch (t)
|
||||||
{
|
{
|
||||||
case Operation::OP_COPY:
|
case Operation::OP_REPLACE:
|
||||||
dbg << "OP_COPY";
|
dbg << "OP_COPY";
|
||||||
break;
|
break;
|
||||||
case Operation::OP_DELETE:
|
case Operation::OP_DELETE:
|
||||||
|
Loading…
Reference in New Issue
Block a user