GH-93 add an option to not copy saves on instance copy

This commit is contained in:
Petr Mrázek 2015-10-10 05:55:55 +02:00
parent 4fbcb3efb9
commit 44db72ead5
10 changed files with 138 additions and 60 deletions

View File

@ -1090,7 +1090,7 @@ InstancePtr MainWindow::instanceFromZipPack(QString instName, QString instGroup,
CustomMessageBox::selectable(this, tr("Error"), tr("Archive does not contain instance.cfg"))->show(); CustomMessageBox::selectable(this, tr("Error"), tr("Archive does not contain instance.cfg"))->show();
return nullptr; return nullptr;
} }
if (!FS::copyPath(instanceCfgFile.absoluteDir().absolutePath(), instDir)) if (!FS::copy(instanceCfgFile.absoluteDir().absolutePath(), instDir)())
{ {
CustomMessageBox::selectable(this, tr("Error"), tr("Unable to copy instance"))->show(); CustomMessageBox::selectable(this, tr("Error"), tr("Unable to copy instance"))->show();
return nullptr; return nullptr;

View File

@ -9,16 +9,18 @@
#include <QDesktopServices> #include <QDesktopServices>
#include <QUrl> #include <QUrl>
namespace FS {
void ensureExists(const QDir &dir) void ensureExists(const QDir &dir)
{ {
if (!QDir().mkpath(dir.absolutePath())) if (!QDir().mkpath(dir.absolutePath()))
{ {
throw FS::FileSystemException("Unable to create directory " + dir.dirName() + " (" + throw FileSystemException("Unable to create directory " + dir.dirName() + " (" +
dir.absolutePath() + ")"); dir.absolutePath() + ")");
} }
} }
void FS::write(const QString &filename, const QByteArray &data) void write(const QString &filename, const QByteArray &data)
{ {
ensureExists(QFileInfo(filename).dir()); ensureExists(QFileInfo(filename).dir());
QSaveFile file(filename); QSaveFile file(filename);
@ -39,7 +41,7 @@ void FS::write(const QString &filename, const QByteArray &data)
} }
} }
QByteArray FS::read(const QString &filename) QByteArray read(const QString &filename)
{ {
QFile file(filename); QFile file(filename);
if (!file.open(QFile::ReadOnly)) if (!file.open(QFile::ReadOnly))
@ -58,7 +60,7 @@ QByteArray FS::read(const QString &filename)
return data; return data;
} }
bool FS::ensureFilePathExists(QString filenamepath) bool ensureFilePathExists(QString filenamepath)
{ {
QFileInfo a(filenamepath); QFileInfo a(filenamepath);
QDir dir; QDir dir;
@ -67,7 +69,7 @@ bool FS::ensureFilePathExists(QString filenamepath)
return success; return success;
} }
bool FS::ensureFolderPathExists(QString foldernamepath) bool ensureFolderPathExists(QString foldernamepath)
{ {
QFileInfo a(foldernamepath); QFileInfo a(foldernamepath);
QDir dir; QDir dir;
@ -76,56 +78,77 @@ bool FS::ensureFolderPathExists(QString foldernamepath)
return success; return success;
} }
bool FS::copyPath(const QString &src, const QString &dst, bool follow_symlinks) bool copy::operator()(const QString &offset)
{ {
//NOTE always deep copy on windows. the alternatives are too messy. //NOTE always deep copy on windows. the alternatives are too messy.
#if defined Q_OS_WIN32 #if defined Q_OS_WIN32
follow_symlinks = true; m_followSymlinks = true;
#endif #endif
QDir dir(src); auto src = PathCombine(m_src.absolutePath(), offset);
if (!dir.exists()) auto dst = PathCombine(m_dst.absolutePath(), offset);
QFileInfo currentSrc(src);
if (!currentSrc.exists())
return false; return false;
if(!m_followSymlinks && currentSrc.isSymLink())
{
qDebug() << "creating symlink" << src << " - " << dst;
if (!ensureFilePathExists(dst))
{
qWarning() << "Cannot create path!";
return false;
}
return QFile::link(currentSrc.symLinkTarget(), dst);
}
else if(currentSrc.isFile())
{
qDebug() << "copying file" << src << " - " << dst;
if (!ensureFilePathExists(dst))
{
qWarning() << "Cannot create path!";
return false;
}
return QFile::copy(src, dst);
}
else if(currentSrc.isDir())
{
qDebug() << "recursing" << offset;
if (!ensureFolderPathExists(dst)) if (!ensureFolderPathExists(dst))
{
qWarning() << "Cannot create path!";
return false; return false;
bool OK = true;
qDebug() << "Looking at " << dir.absolutePath();
foreach(QString f, dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System))
{
QString inner_src = src + QDir::separator() + f;
QString inner_dst = dst + QDir::separator() + f;
qDebug() << f << "translates to"<< inner_src << "to" << inner_dst;
QFileInfo fileInfo(inner_src);
if(!follow_symlinks && fileInfo.isSymLink())
{
qDebug() << "creating symlink" << inner_src << " - " << inner_dst;
OK &= QFile::link(fileInfo.symLinkTarget(),inner_dst);
} }
else if (fileInfo.isDir()) QDir currentDir(src);
for(auto & f : currentDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System))
{ {
qDebug() << "recursing" << inner_src << " - " << inner_dst; auto inner_offset = PathCombine(offset, f);
OK &= copyPath(inner_src, inner_dst, follow_symlinks); // ignore and skip stuff that matches the blacklist.
if(m_blacklist && m_blacklist->matches(inner_offset))
{
continue;
} }
else if (fileInfo.isFile()) if(!operator()(inner_offset))
{ {
qDebug() << "copying file" << inner_src << " - " << inner_dst; return false;
OK &= QFile::copy(inner_src, inner_dst); }
}
} }
else else
{ {
OK = false; qCritical() << "Copy ERROR: Unknown filesystem object:" << src;
qCritical() << "Copy ERROR: Unknown filesystem object:" << inner_src; return false;
} }
} return true;
return OK;
} }
#if defined Q_OS_WIN32 #if defined Q_OS_WIN32
#include <windows.h> #include <windows.h>
#include <string> #include <string>
#endif #endif
bool FS::deletePath(QString path) bool deletePath(QString path)
{ {
bool OK = true; bool OK = true;
QDir dir(path); QDir dir(path);
@ -138,7 +161,7 @@ bool FS::deletePath(QString path)
QDir::AllDirs | QDir::Files, QDir::AllDirs | QDir::Files,
QDir::DirsFirst); QDir::DirsFirst);
for(QFileInfo info: allEntries) for(auto & info: allEntries)
{ {
#if defined Q_OS_WIN32 #if defined Q_OS_WIN32
QString nativePath = QDir::toNativeSeparators(info.absoluteFilePath()); QString nativePath = QDir::toNativeSeparators(info.absoluteFilePath());
@ -182,7 +205,7 @@ bool FS::deletePath(QString path)
} }
QString FS::PathCombine(QString path1, QString path2) QString PathCombine(QString path1, QString path2)
{ {
if(!path1.size()) if(!path1.size())
return path2; return path2;
@ -191,17 +214,17 @@ QString FS::PathCombine(QString path1, QString path2)
return QDir::cleanPath(path1 + QDir::separator() + path2); return QDir::cleanPath(path1 + QDir::separator() + path2);
} }
QString FS::PathCombine(QString path1, QString path2, QString path3) QString PathCombine(QString path1, QString path2, QString path3)
{ {
return PathCombine(PathCombine(path1, path2), path3); return PathCombine(PathCombine(path1, path2), path3);
} }
QString FS::AbsolutePath(QString path) QString AbsolutePath(QString path)
{ {
return QFileInfo(path).absolutePath(); return QFileInfo(path).absolutePath();
} }
QString FS::ResolveExecutable(QString path) QString ResolveExecutable(QString path)
{ {
if (path.isEmpty()) if (path.isEmpty())
{ {
@ -225,7 +248,7 @@ QString FS::ResolveExecutable(QString path)
* Any paths inside the current directory will be normalized to relative paths (to current) * Any paths inside the current directory will be normalized to relative paths (to current)
* Other paths will be made absolute * Other paths will be made absolute
*/ */
QString FS::NormalizePath(QString path) QString NormalizePath(QString path)
{ {
QDir a = QDir::currentPath(); QDir a = QDir::currentPath();
QString currentAbsolute = a.absolutePath(); QString currentAbsolute = a.absolutePath();
@ -245,7 +268,7 @@ QString FS::NormalizePath(QString path)
QString badFilenameChars = "\"\\/?<>:*|!"; QString badFilenameChars = "\"\\/?<>:*|!";
QString FS::RemoveInvalidFilenameChars(QString string, QChar replaceWith) QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
{ {
for (int i = 0; i < string.length(); i++) for (int i = 0; i < string.length(); i++)
{ {
@ -257,7 +280,7 @@ QString FS::RemoveInvalidFilenameChars(QString string, QChar replaceWith)
return string; return string;
} }
QString FS::DirNameFromString(QString string, QString inDir) QString DirNameFromString(QString string, QString inDir)
{ {
int num = 0; int num = 0;
QString baseName = RemoveInvalidFilenameChars(string, '-'); QString baseName = RemoveInvalidFilenameChars(string, '-');
@ -281,7 +304,7 @@ QString FS::DirNameFromString(QString string, QString inDir)
return dirName; return dirName;
} }
void FS::openDirInDefaultProgram(QString path, bool ensureExists) void openDirInDefaultProgram(QString path, bool ensureExists)
{ {
QDir parentPath; QDir parentPath;
QDir dir(path); QDir dir(path);
@ -292,14 +315,14 @@ void FS::openDirInDefaultProgram(QString path, bool ensureExists)
QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
} }
void FS::openFileInDefaultProgram(QString filename) void openFileInDefaultProgram(QString filename)
{ {
QDesktopServices::openUrl(QUrl::fromLocalFile(filename)); QDesktopServices::openUrl(QUrl::fromLocalFile(filename));
} }
// Does the directory path contain any '!'? If yes, return true, otherwise false. // Does the directory path contain any '!'? If yes, return true, otherwise false.
// (This is a problem for Java) // (This is a problem for Java)
bool FS::checkProblemticPathJava(QDir folder) bool checkProblemticPathJava(QDir folder)
{ {
QString pathfoldername = folder.absolutePath(); QString pathfoldername = folder.absolutePath();
return pathfoldername.contains("!", Qt::CaseInsensitive); return pathfoldername.contains("!", Qt::CaseInsensitive);
@ -366,13 +389,13 @@ HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args)
#endif #endif
QString FS::getDesktopDir() QString getDesktopDir()
{ {
return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
} }
// Cross-platform Shortcut creation // Cross-platform Shortcut creation
bool FS::createShortCut(QString location, QString dest, QStringList args, QString name, bool createShortCut(QString location, QString dest, QStringList args, QString name,
QString icon) QString icon)
{ {
#if defined Q_OS_LINUX #if defined Q_OS_LINUX
@ -426,3 +449,4 @@ bool FS::createShortCut(QString location, QString dest, QStringList args, QStrin
return false; return false;
#endif #endif
} }
}

View File

@ -3,9 +3,11 @@
#pragma once #pragma once
#include "Exception.h" #include "Exception.h"
#include "pathmatcher/IPathMatcher.h"
#include "multimc_logic_export.h" #include "multimc_logic_export.h"
#include <QDir> #include <QDir>
#include <QFlags>
namespace FS namespace FS
{ {
@ -38,10 +40,39 @@ MULTIMC_LOGIC_EXPORT bool ensureFilePathExists(QString filenamepath);
*/ */
MULTIMC_LOGIC_EXPORT bool ensureFolderPathExists(QString filenamepath); MULTIMC_LOGIC_EXPORT bool ensureFolderPathExists(QString filenamepath);
/** class MULTIMC_LOGIC_EXPORT copy
* Copy a folder recursively {
*/ public:
MULTIMC_LOGIC_EXPORT bool copyPath(const QString &src, const QString &dst, bool follow_symlinks = true); copy(const copy&) = delete;
copy(const QString & src, const QString & dst)
{
m_src = src;
m_dst = dst;
}
copy & followSymlinks(const bool follow)
{
m_followSymlinks = follow;
return *this;
}
copy & blacklist(const IPathMatcher * filter)
{
m_blacklist = filter;
return *this;
}
bool operator()()
{
return operator()(QString());
}
private:
bool operator()(const QString &offset);
private:
bool m_followSymlinks = true;
const IPathMatcher * m_blacklist = nullptr;
QDir m_src;
QDir m_dst;
};
/** /**
* Delete a folder recursively * Delete a folder recursively

View File

@ -38,6 +38,7 @@
#include "ftb/FTBPlugin.h" #include "ftb/FTBPlugin.h"
#include "NullInstance.h" #include "NullInstance.h"
#include "FileSystem.h" #include "FileSystem.h"
#include "pathmatcher/RegexpMatcher.h"
const static int GROUP_FILE_FORMAT_VERSION = 1; const static int GROUP_FILE_FORMAT_VERSION = 1;
@ -486,9 +487,18 @@ InstanceList::InstCreateError
InstanceList::copyInstance(InstancePtr &newInstance, InstancePtr &oldInstance, const QString &instDir, bool copySaves) InstanceList::copyInstance(InstancePtr &newInstance, InstancePtr &oldInstance, const QString &instDir, bool copySaves)
{ {
QDir rootDir(instDir); QDir rootDir(instDir);
std::unique_ptr<IPathMatcher> matcher;
if(!copySaves)
{
auto matcherReal = new RegexpMatcher("[.]?minecraft/saves");
matcherReal->caseSensitive(false);
matcher.reset(matcherReal);
}
qDebug() << instDir.toUtf8(); qDebug() << instDir.toUtf8();
if (!FS::copyPath(oldInstance->instanceRoot(), instDir, false)) FS::copy folderCopy(oldInstance->instanceRoot(), instDir);
folderCopy.followSymlinks(false).blacklist(matcher.get());
if (!folderCopy())
{ {
FS::deletePath(instDir); FS::deletePath(instDir);
return InstanceList::CantCreateDir; return InstanceList::CantCreateDir;

View File

@ -278,7 +278,7 @@ bool Mod::replace(Mod &with)
} }
if (t == MOD_FOLDER) if (t == MOD_FOLDER)
{ {
success = FS::copyPath(with.m_file.filePath(), m_file.path()); success = FS::copy(with.m_file.filePath(), m_file.path())();
} }
if (success) if (success)
{ {

View File

@ -286,7 +286,7 @@ bool ModList::installMod(const QFileInfo &filename, int index)
QString from = filename.filePath(); QString from = filename.filePath();
QString to = FS::PathCombine(m_dir.path(), filename.fileName()); QString to = FS::PathCombine(m_dir.path(), filename.fileName());
if (!FS::copyPath(from, to)) if (!FS::copy(from, to)())
return false; return false;
m.repath(to); m.repath(to);
beginInsertRows(QModelIndex(), index, index); beginInsertRows(QModelIndex(), index, index);

View File

@ -197,7 +197,7 @@ bool World::install(const QString &to, const QString &name)
else if(m_containerFile.isDir()) else if(m_containerFile.isDir())
{ {
QString from = m_containerFile.filePath(); QString from = m_containerFile.filePath();
ok = FS::copyPath(from, finalPath); ok = FS::copy(from, finalPath)();
} }
if(ok && !name.isEmpty() && m_actualName != name) if(ok && !name.isEmpty() && m_actualName != name)
@ -350,7 +350,7 @@ bool World::replace(World &with)
{ {
if (!destroy()) if (!destroy())
return false; return false;
bool success = FS::copyPath(with.m_containerFile.filePath(), m_containerFile.path()); bool success = FS::copy(with.m_containerFile.filePath(), m_containerFile.path())();
if (success) if (success)
{ {
m_folderName = with.m_folderName; m_folderName = with.m_folderName;

View File

@ -8,5 +8,5 @@ public:
public: public:
virtual ~IPathMatcher(){}; virtual ~IPathMatcher(){};
virtual bool matches(const QString &string) = 0; virtual bool matches(const QString &string) const = 0;
}; };

View File

@ -15,7 +15,7 @@ public:
return *this; return *this;
} }
virtual bool matches(const QString &string) override virtual bool matches(const QString &string) const override
{ {
for(auto iter: m_matchers) for(auto iter: m_matchers)
{ {

View File

@ -5,13 +5,26 @@ class RegexpMatcher : public IPathMatcher
{ {
public: public:
virtual ~RegexpMatcher() {}; virtual ~RegexpMatcher() {};
RegexpMatcher(QString regexp) RegexpMatcher(const QString &regexp)
{ {
m_regexp.setPattern(regexp); m_regexp.setPattern(regexp);
m_onlyFilenamePart = !regexp.contains('/'); m_onlyFilenamePart = !regexp.contains('/');
} }
virtual bool matches(const QString &string) override RegexpMatcher &caseSensitive(bool cs = true)
{
if(cs)
{
m_regexp.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
}
else
{
m_regexp.setPatternOptions(QRegularExpression::NoPatternOption);
}
return *this;
}
virtual bool matches(const QString &string) const override
{ {
if(m_onlyFilenamePart) if(m_onlyFilenamePart)
{ {