feat(symlinks&hardlinks): linkup copy dialog
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
parent
8ba51c7900
commit
5978882378
@ -420,7 +420,7 @@ void create_link::runPrivlaged(const QString& offset)
|
||||
qint64 byteswritten = clientConnection->write(block);
|
||||
bool bytesflushed = clientConnection->flush();
|
||||
qDebug() << "block flushed" << byteswritten << bytesflushed;
|
||||
//clientConnection->disconnectFromServer();
|
||||
|
||||
});
|
||||
|
||||
qDebug() << "Listening on pipe" << serverName;
|
||||
@ -437,7 +437,6 @@ void create_link::runPrivlaged(const QString& offset)
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ExternalLinkFileProcess::runLinkFile() {
|
||||
QString fileLinkExe = PathCombine(QCoreApplication::instance()->applicationDirPath(), BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink");
|
||||
QString params = "-s " + m_server;
|
||||
@ -463,7 +462,7 @@ void ExternalLinkFileProcess::runLinkFile() {
|
||||
ShExecInfo.lpFile = programNameWin;
|
||||
ShExecInfo.lpParameters = paramsWin;
|
||||
ShExecInfo.lpDirectory = NULL;
|
||||
ShExecInfo.nShow = SW_NORMAL;
|
||||
ShExecInfo.nShow = SW_HIDE;
|
||||
ShExecInfo.hInstApp = NULL;
|
||||
|
||||
ShellExecuteEx(&ShExecInfo);
|
||||
|
@ -211,16 +211,21 @@ class create_link : public QObject {
|
||||
|
||||
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
||||
|
||||
int totalLinked() { return m_linked; }
|
||||
|
||||
|
||||
void runPrivlaged() { runPrivlaged(QString()); }
|
||||
void runPrivlaged(const QString& offset);
|
||||
|
||||
int totalLinked() { return m_linked; }
|
||||
QList<LinkResult> getResults() { return m_path_results; }
|
||||
|
||||
|
||||
signals:
|
||||
void fileLinked(const QString& srcName, const QString& dstName);
|
||||
void linkFailed(const QString& srcName, const QString& dstName, const QString& err_msg, int err_value);
|
||||
void finishedPrivlaged(bool gotResults);
|
||||
void finished();
|
||||
void finishedPrivlaged(bool gotResults);
|
||||
|
||||
|
||||
private:
|
||||
bool operator()(const QString& offset, bool dryRun = false);
|
||||
|
@ -103,9 +103,9 @@ bool InstanceCopyPrefs::isUseHardLinksEnabled() const
|
||||
return useHardLinks;
|
||||
}
|
||||
|
||||
bool InstanceCopyPrefs::isLinkWorldsEnabled() const
|
||||
bool InstanceCopyPrefs::isDontLinkSavesEnabled() const
|
||||
{
|
||||
return linkWorlds;
|
||||
return dontLinkSaves;
|
||||
}
|
||||
|
||||
// ======= Setters =======
|
||||
@ -159,7 +159,7 @@ void InstanceCopyPrefs::enableUseHardLinks(bool b)
|
||||
useHardLinks = b;
|
||||
}
|
||||
|
||||
void InstanceCopyPrefs::enableLinkWorlds(bool b)
|
||||
void InstanceCopyPrefs::enableDontLinkSaves(bool b)
|
||||
{
|
||||
linkWorlds = b;
|
||||
dontLinkSaves = b;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ struct InstanceCopyPrefs {
|
||||
[[nodiscard]] bool isCopyScreenshotsEnabled() const;
|
||||
[[nodiscard]] bool isLinkFilesEnabled() const;
|
||||
[[nodiscard]] bool isUseHardLinksEnabled() const;
|
||||
[[nodiscard]] bool isLinkWorldsEnabled() const;
|
||||
[[nodiscard]] bool isDontLinkSavesEnabled() const;
|
||||
// Setters
|
||||
void enableCopySaves(bool b);
|
||||
void enableKeepPlaytime(bool b);
|
||||
@ -33,7 +33,7 @@ struct InstanceCopyPrefs {
|
||||
void enableCopyScreenshots(bool b);
|
||||
void enableLinkFiles(bool b);
|
||||
void enableUseHardLinks(bool b);
|
||||
void enableLinkWorlds(bool b);
|
||||
void enableDontLinkSaves(bool b);
|
||||
|
||||
protected: // data
|
||||
bool copySaves = true;
|
||||
@ -46,5 +46,5 @@ struct InstanceCopyPrefs {
|
||||
bool copyScreenshots = true;
|
||||
bool linkFiles = false;
|
||||
bool useHardLinks = false;
|
||||
bool linkWorlds = true;
|
||||
bool dontLinkSaves = false;
|
||||
};
|
||||
|
@ -11,6 +11,11 @@ InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyP
|
||||
m_keepPlaytime = prefs.isKeepPlaytimeEnabled();
|
||||
|
||||
QString filters = prefs.getSelectedFiltersAsRegex();
|
||||
|
||||
m_useLinks = prefs.isLinkFilesEnabled();
|
||||
m_useHardLinks = prefs.isUseHardLinksEnabled();
|
||||
m_copySaves = prefs.isDontLinkSavesEnabled() && prefs.isCopySavesEnabled();
|
||||
|
||||
if (!filters.isEmpty())
|
||||
{
|
||||
// Set regex filter:
|
||||
@ -25,11 +30,71 @@ void InstanceCopyTask::executeTask()
|
||||
{
|
||||
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
|
||||
|
||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this]{
|
||||
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
||||
folderCopy.followSymlinks(false).matcher(m_matcher.get());
|
||||
auto copySaves = [&](){
|
||||
FS::copy savesCopy(FS::PathCombine(m_origInstance->instanceRoot(), "saves") , FS::PathCombine(m_stagingPath, "saves"));
|
||||
savesCopy.followSymlinks(false);
|
||||
|
||||
return folderCopy();
|
||||
return savesCopy();
|
||||
};
|
||||
|
||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this, copySaves]{
|
||||
if (m_useLinks) {
|
||||
FS::create_link folderLink(m_origInstance->instanceRoot(), m_stagingPath);
|
||||
folderLink.linkRecursively(true).useHardLinks(m_useHardLinks).matcher(m_matcher.get());
|
||||
|
||||
bool there_were_errors = false;
|
||||
|
||||
if(!folderLink()){
|
||||
#if defined Q_OS_WIN32
|
||||
if (!m_useHardLinks) {
|
||||
qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";
|
||||
|
||||
qDebug() << "atempting to run with privelage";
|
||||
|
||||
QEventLoop loop;
|
||||
bool got_priv_results = false;
|
||||
|
||||
connect(&folderLink, &FS::create_link::finishedPrivlaged, this, [&](bool gotResults){
|
||||
if (!gotResults) {
|
||||
qDebug() << "Privlaged run exited without results!";
|
||||
}
|
||||
got_priv_results = gotResults;
|
||||
loop.quit();
|
||||
});
|
||||
folderLink.runPrivlaged();
|
||||
|
||||
loop.exec(); // wait for the finished signal
|
||||
|
||||
for (auto result : folderLink.getResults()) {
|
||||
if (result.err_value != 0) {
|
||||
there_were_errors = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_copySaves) {
|
||||
there_were_errors |= !copySaves();
|
||||
}
|
||||
|
||||
return got_priv_results && !there_were_errors;
|
||||
} else {
|
||||
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
|
||||
}
|
||||
#else
|
||||
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
|
||||
#endif return false;
|
||||
}
|
||||
|
||||
if (m_copySaves) {
|
||||
there_were_errors |= !copySaves();
|
||||
}
|
||||
|
||||
return !there_were_errors;
|
||||
} else {
|
||||
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
||||
folderCopy.followSymlinks(false).matcher(m_matcher.get());
|
||||
|
||||
return folderCopy();
|
||||
}
|
||||
});
|
||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted);
|
||||
|
@ -30,4 +30,7 @@ private:
|
||||
QFutureWatcher<bool> m_copyFutureWatcher;
|
||||
std::unique_ptr<IPathMatcher> m_matcher;
|
||||
bool m_keepPlaytime;
|
||||
bool m_useLinks = false;
|
||||
bool m_useHardLinks = false;
|
||||
bool m_copySaves = true;
|
||||
};
|
||||
|
@ -88,7 +88,7 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
|
||||
|
||||
ui->linkFilesGroup->setChecked(m_selectedOptions.isLinkFilesEnabled());
|
||||
ui->hardLinksCheckbox->setChecked(m_selectedOptions.isUseHardLinksEnabled());
|
||||
ui->linkWorldsCheckbox->setChecked(m_selectedOptions.isLinkWorldsEnabled());
|
||||
ui->dontLinkSavesCheckbox->setChecked(m_selectedOptions.isDontLinkSavesEnabled());
|
||||
}
|
||||
|
||||
CopyInstanceDialog::~CopyInstanceDialog()
|
||||
@ -179,6 +179,7 @@ void CopyInstanceDialog::on_selectAllCheckbox_stateChanged(int state)
|
||||
void CopyInstanceDialog::on_copySavesCheckbox_stateChanged(int state)
|
||||
{
|
||||
m_selectedOptions.enableCopySaves(state == Qt::Checked);
|
||||
ui->dontLinkSavesCheckbox->setChecked((state == Qt::Checked) && ui->dontLinkSavesCheckbox->isChecked());
|
||||
updateSelectAllCheckbox();
|
||||
}
|
||||
|
||||
@ -235,7 +236,7 @@ void CopyInstanceDialog::on_hardLinksCheckbox_stateChanged(int state)
|
||||
m_selectedOptions.enableUseHardLinks(state == Qt::Checked);
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_linkWorldsCheckbox_stateChanged(int state)
|
||||
void CopyInstanceDialog::on_dontLinkSavesCheckbox_stateChanged(int state)
|
||||
{
|
||||
m_selectedOptions.enableLinkWorlds(state == Qt::Checked);
|
||||
m_selectedOptions.enableDontLinkSaves(state == Qt::Checked);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ slots:
|
||||
void on_copyScreenshotsCheckbox_stateChanged(int state);
|
||||
void on_linkFilesGroup_toggled(bool checked);
|
||||
void on_hardLinksCheckbox_stateChanged(int state);
|
||||
void on_linkWorldsCheckbox_stateChanged(int state);
|
||||
void on_dontLinkSavesCheckbox_stateChanged(int state);
|
||||
|
||||
private:
|
||||
void checkAllCheckboxes(const bool& b);
|
||||
|
@ -240,17 +240,14 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="linkWorldsCheckbox">
|
||||
<widget class="QCheckBox" name="dontLinkSavesCheckbox">
|
||||
<property name="toolTip">
|
||||
<string>World save data will be linked and thus shared between instances.</string>
|
||||
<string>If "copy saves" is selected world save data will be copied instead of linked and thus not shared between instances.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Link worlds</string>
|
||||
<string>Don't link saves</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
|
Loading…
Reference in New Issue
Block a user