GH-93 add an option to not copy saves on instance copy
This commit is contained in:
		| @@ -1090,7 +1090,7 @@ InstancePtr MainWindow::instanceFromZipPack(QString instName, QString instGroup, | ||||
| 		CustomMessageBox::selectable(this, tr("Error"), tr("Archive does not contain instance.cfg"))->show(); | ||||
| 		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(); | ||||
| 		return nullptr; | ||||
|   | ||||
| @@ -9,16 +9,18 @@ | ||||
| #include <QDesktopServices> | ||||
| #include <QUrl> | ||||
|  | ||||
| namespace FS { | ||||
|  | ||||
| void ensureExists(const QDir &dir) | ||||
| { | ||||
| 	if (!QDir().mkpath(dir.absolutePath())) | ||||
| 	{ | ||||
| 		throw FS::FileSystemException("Unable to create directory " + dir.dirName() + " (" + | ||||
| 		throw FileSystemException("Unable to create directory " + dir.dirName() + " (" + | ||||
| 									  dir.absolutePath() + ")"); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void FS::write(const QString &filename, const QByteArray &data) | ||||
| void write(const QString &filename, const QByteArray &data) | ||||
| { | ||||
| 	ensureExists(QFileInfo(filename).dir()); | ||||
| 	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); | ||||
| 	if (!file.open(QFile::ReadOnly)) | ||||
| @@ -58,7 +60,7 @@ QByteArray FS::read(const QString &filename) | ||||
| 	return data; | ||||
| } | ||||
|  | ||||
| bool FS::ensureFilePathExists(QString filenamepath) | ||||
| bool ensureFilePathExists(QString filenamepath) | ||||
| { | ||||
| 	QFileInfo a(filenamepath); | ||||
| 	QDir dir; | ||||
| @@ -67,7 +69,7 @@ bool FS::ensureFilePathExists(QString filenamepath) | ||||
| 	return success; | ||||
| } | ||||
|  | ||||
| bool FS::ensureFolderPathExists(QString foldernamepath) | ||||
| bool ensureFolderPathExists(QString foldernamepath) | ||||
| { | ||||
| 	QFileInfo a(foldernamepath); | ||||
| 	QDir dir; | ||||
| @@ -76,56 +78,77 @@ bool FS::ensureFolderPathExists(QString foldernamepath) | ||||
| 	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. | ||||
| 	#if defined Q_OS_WIN32 | ||||
| 	follow_symlinks = true; | ||||
| 	m_followSymlinks = true; | ||||
| 	#endif | ||||
|  | ||||
| 	QDir dir(src); | ||||
| 	if (!dir.exists()) | ||||
| 		return false; | ||||
| 	if (!ensureFolderPathExists(dst)) | ||||
| 	auto src = PathCombine(m_src.absolutePath(), offset); | ||||
| 	auto dst = PathCombine(m_dst.absolutePath(), offset); | ||||
|  | ||||
| 	QFileInfo currentSrc(src); | ||||
| 	if (!currentSrc.exists()) | ||||
| 		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)) | ||||
| 	if(!m_followSymlinks && currentSrc.isSymLink()) | ||||
| 	{ | ||||
| 		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" << src << " - " << dst; | ||||
| 		if (!ensureFilePathExists(dst)) | ||||
| 		{ | ||||
| 			qDebug() << "creating symlink" << inner_src << " - " << inner_dst; | ||||
| 			OK &= QFile::link(fileInfo.symLinkTarget(),inner_dst); | ||||
| 			qWarning() << "Cannot create path!"; | ||||
| 			return false; | ||||
| 		} | ||||
| 		else if (fileInfo.isDir()) | ||||
| 		return QFile::link(currentSrc.symLinkTarget(), dst); | ||||
| 	} | ||||
| 	else if(currentSrc.isFile()) | ||||
| 	{ | ||||
| 		qDebug() << "copying file" << src << " - " << dst; | ||||
| 		if (!ensureFilePathExists(dst)) | ||||
| 		{ | ||||
| 			qDebug() << "recursing" << inner_src << " - " << inner_dst; | ||||
| 			OK &= copyPath(inner_src, inner_dst, follow_symlinks); | ||||
| 			qWarning() << "Cannot create path!"; | ||||
| 			return false; | ||||
| 		} | ||||
| 		else if (fileInfo.isFile()) | ||||
| 		return QFile::copy(src, dst); | ||||
| 	} | ||||
| 	else if(currentSrc.isDir()) | ||||
| 	{ | ||||
| 		qDebug() << "recursing" << offset; | ||||
| 		if (!ensureFolderPathExists(dst)) | ||||
| 		{ | ||||
| 			qDebug() << "copying file" << inner_src << " - " << inner_dst; | ||||
| 			OK &= QFile::copy(inner_src, inner_dst); | ||||
| 			qWarning() << "Cannot create path!"; | ||||
| 			return false; | ||||
| 		} | ||||
| 		else | ||||
| 		QDir currentDir(src); | ||||
| 		for(auto & f : currentDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System)) | ||||
| 		{ | ||||
| 			OK = false; | ||||
| 			qCritical() << "Copy ERROR: Unknown filesystem object:" << inner_src; | ||||
| 			auto inner_offset = PathCombine(offset, f); | ||||
| 			// ignore and skip stuff that matches the blacklist. | ||||
| 			if(m_blacklist && m_blacklist->matches(inner_offset)) | ||||
| 			{ | ||||
| 				continue; | ||||
| 			} | ||||
| 			if(!operator()(inner_offset)) | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return OK; | ||||
| 	else | ||||
| 	{ | ||||
| 		qCritical() << "Copy ERROR: Unknown filesystem object:" << src; | ||||
| 		return false; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
|  | ||||
| #if defined Q_OS_WIN32 | ||||
| #include <windows.h> | ||||
| #include <string> | ||||
| #endif | ||||
| bool FS::deletePath(QString path) | ||||
| bool deletePath(QString path) | ||||
| { | ||||
| 	bool OK = true; | ||||
| 	QDir dir(path); | ||||
| @@ -138,7 +161,7 @@ bool FS::deletePath(QString path) | ||||
| 										QDir::AllDirs | QDir::Files, | ||||
| 										QDir::DirsFirst); | ||||
|  | ||||
| 	for(QFileInfo info: allEntries) | ||||
| 	for(auto & info: allEntries) | ||||
| 	{ | ||||
| #if defined Q_OS_WIN32 | ||||
| 		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()) | ||||
| 		return path2; | ||||
| @@ -191,17 +214,17 @@ QString FS::PathCombine(QString path1, QString 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); | ||||
| } | ||||
|  | ||||
| QString FS::AbsolutePath(QString path) | ||||
| QString AbsolutePath(QString path) | ||||
| { | ||||
| 	return QFileInfo(path).absolutePath(); | ||||
| } | ||||
|  | ||||
| QString FS::ResolveExecutable(QString path) | ||||
| QString ResolveExecutable(QString path) | ||||
| { | ||||
| 	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) | ||||
|  * Other paths will be made absolute | ||||
|  */ | ||||
| QString FS::NormalizePath(QString path) | ||||
| QString NormalizePath(QString path) | ||||
| { | ||||
| 	QDir a = QDir::currentPath(); | ||||
| 	QString currentAbsolute = a.absolutePath(); | ||||
| @@ -245,7 +268,7 @@ QString FS::NormalizePath(QString path) | ||||
|  | ||||
| QString badFilenameChars = "\"\\/?<>:*|!"; | ||||
|  | ||||
| QString FS::RemoveInvalidFilenameChars(QString string, QChar replaceWith) | ||||
| QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) | ||||
| { | ||||
| 	for (int i = 0; i < string.length(); i++) | ||||
| 	{ | ||||
| @@ -257,7 +280,7 @@ QString FS::RemoveInvalidFilenameChars(QString string, QChar replaceWith) | ||||
| 	return string; | ||||
| } | ||||
|  | ||||
| QString FS::DirNameFromString(QString string, QString inDir) | ||||
| QString DirNameFromString(QString string, QString inDir) | ||||
| { | ||||
| 	int num = 0; | ||||
| 	QString baseName = RemoveInvalidFilenameChars(string, '-'); | ||||
| @@ -281,7 +304,7 @@ QString FS::DirNameFromString(QString string, QString inDir) | ||||
| 	return dirName; | ||||
| } | ||||
|  | ||||
| void FS::openDirInDefaultProgram(QString path, bool ensureExists) | ||||
| void openDirInDefaultProgram(QString path, bool ensureExists) | ||||
| { | ||||
| 	QDir parentPath; | ||||
| 	QDir dir(path); | ||||
| @@ -292,14 +315,14 @@ void FS::openDirInDefaultProgram(QString path, bool ensureExists) | ||||
| 	QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); | ||||
| } | ||||
|  | ||||
| void FS::openFileInDefaultProgram(QString filename) | ||||
| void openFileInDefaultProgram(QString filename) | ||||
| { | ||||
| 	QDesktopServices::openUrl(QUrl::fromLocalFile(filename)); | ||||
| } | ||||
|  | ||||
| // Does the directory path contain any '!'? If yes, return true, otherwise false. | ||||
| // (This is a problem for Java) | ||||
| bool FS::checkProblemticPathJava(QDir folder) | ||||
| bool checkProblemticPathJava(QDir folder) | ||||
| { | ||||
| 	QString pathfoldername = folder.absolutePath(); | ||||
| 	return pathfoldername.contains("!", Qt::CaseInsensitive); | ||||
| @@ -366,13 +389,13 @@ HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args) | ||||
|  | ||||
| #endif | ||||
|  | ||||
| QString FS::getDesktopDir() | ||||
| QString getDesktopDir() | ||||
| { | ||||
| 	return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); | ||||
| } | ||||
|  | ||||
| // 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) | ||||
| { | ||||
| #if defined Q_OS_LINUX | ||||
| @@ -426,3 +449,4 @@ bool FS::createShortCut(QString location, QString dest, QStringList args, QStrin | ||||
| 	return false; | ||||
| #endif | ||||
| } | ||||
| } | ||||
| @@ -3,9 +3,11 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "Exception.h" | ||||
| #include "pathmatcher/IPathMatcher.h" | ||||
|  | ||||
| #include "multimc_logic_export.h" | ||||
| #include <QDir> | ||||
| #include <QFlags> | ||||
|  | ||||
| namespace FS | ||||
| { | ||||
| @@ -38,10 +40,39 @@ MULTIMC_LOGIC_EXPORT bool ensureFilePathExists(QString filenamepath); | ||||
|  */ | ||||
| MULTIMC_LOGIC_EXPORT bool ensureFolderPathExists(QString filenamepath); | ||||
|  | ||||
| /** | ||||
|  * Copy a folder recursively | ||||
|  */ | ||||
| MULTIMC_LOGIC_EXPORT bool copyPath(const QString &src, const QString &dst, bool follow_symlinks = true); | ||||
| class MULTIMC_LOGIC_EXPORT copy | ||||
| { | ||||
| public: | ||||
| 	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 | ||||
|   | ||||
| @@ -38,6 +38,7 @@ | ||||
| #include "ftb/FTBPlugin.h" | ||||
| #include "NullInstance.h" | ||||
| #include "FileSystem.h" | ||||
| #include "pathmatcher/RegexpMatcher.h" | ||||
|  | ||||
| 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) | ||||
| { | ||||
| 	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(); | ||||
| 	if (!FS::copyPath(oldInstance->instanceRoot(), instDir, false)) | ||||
| 	FS::copy folderCopy(oldInstance->instanceRoot(), instDir); | ||||
| 	folderCopy.followSymlinks(false).blacklist(matcher.get()); | ||||
| 	if (!folderCopy()) | ||||
| 	{ | ||||
| 		FS::deletePath(instDir); | ||||
| 		return InstanceList::CantCreateDir; | ||||
|   | ||||
| @@ -278,7 +278,7 @@ bool Mod::replace(Mod &with) | ||||
| 	} | ||||
| 	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) | ||||
| 	{ | ||||
|   | ||||
| @@ -286,7 +286,7 @@ bool ModList::installMod(const QFileInfo &filename, int index) | ||||
|  | ||||
| 		QString from = filename.filePath(); | ||||
| 		QString to = FS::PathCombine(m_dir.path(), filename.fileName()); | ||||
| 		if (!FS::copyPath(from, to)) | ||||
| 		if (!FS::copy(from, to)()) | ||||
| 			return false; | ||||
| 		m.repath(to); | ||||
| 		beginInsertRows(QModelIndex(), index, index); | ||||
|   | ||||
| @@ -197,7 +197,7 @@ bool World::install(const QString &to, const QString &name) | ||||
| 	else if(m_containerFile.isDir()) | ||||
| 	{ | ||||
| 		QString from = m_containerFile.filePath(); | ||||
| 		ok = FS::copyPath(from, finalPath); | ||||
| 		ok = FS::copy(from, finalPath)(); | ||||
| 	} | ||||
|  | ||||
| 	if(ok && !name.isEmpty() && m_actualName != name) | ||||
| @@ -350,7 +350,7 @@ bool World::replace(World &with) | ||||
| { | ||||
| 	if (!destroy()) | ||||
| 		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) | ||||
| 	{ | ||||
| 		m_folderName = with.m_folderName; | ||||
|   | ||||
| @@ -8,5 +8,5 @@ public: | ||||
|  | ||||
| public: | ||||
| 	virtual ~IPathMatcher(){}; | ||||
| 	virtual bool matches(const QString &string) = 0; | ||||
| 	virtual bool matches(const QString &string) const = 0; | ||||
| }; | ||||
|   | ||||
| @@ -15,7 +15,7 @@ public: | ||||
| 		return *this; | ||||
| 	} | ||||
|  | ||||
| 	virtual bool matches(const QString &string)  override | ||||
| 	virtual bool matches(const QString &string) const override | ||||
| 	{ | ||||
| 		for(auto iter: m_matchers) | ||||
| 		{ | ||||
|   | ||||
| @@ -5,13 +5,26 @@ class RegexpMatcher : public IPathMatcher | ||||
| { | ||||
| public: | ||||
| 	virtual ~RegexpMatcher() {}; | ||||
| 	RegexpMatcher(QString regexp) | ||||
| 	RegexpMatcher(const QString ®exp) | ||||
| 	{ | ||||
| 		m_regexp.setPattern(regexp); | ||||
| 		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) | ||||
| 		{ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user