Clear Build and Cache Directory After Project Move or Copy (#2184)

* Clear build and Cache directories when copying or moving projects

Signed-off-by: nggieber <nggieber@amazon.com>

* Updated tests for moving projects and Added tests for copying projects and skipping build files

Signed-off-by: nggieber <nggieber@amazon.com>

* Address PR feedback and fix a few minor UX issues, and request project be rebuild after copying or moving

Signed-off-by: nggieber <nggieber@amazon.com>

* Include ProjectInfo.h in ProjectUtils.h so linux will compile

Signed-off-by: nggieber <nggieber@amazon.com>
This commit is contained in:
AMZN-nggieber
2021-07-15 17:48:04 -07:00
committed by GitHub
parent e6ddc29cb4
commit 69312a5e56
18 changed files with 334 additions and 64 deletions
+119 -22
View File
@@ -6,6 +6,7 @@
*/
#include <ProjectUtils.h>
#include <ProjectManagerDefs.h>
#include <PythonBindingsInterface.h>
#include <QFileDialog>
@@ -59,29 +60,63 @@ namespace O3DE::ProjectManager
return false;
}
static bool SkipFilePaths(const QString& curPath, QStringList& skippedPaths, QStringList& deeperSkippedPaths)
{
bool skip = false;
for (const QString& skippedPath : skippedPaths)
{
QString nativeSkippedPath = QDir::toNativeSeparators(skippedPath);
QString firstSectionSkippedPath = nativeSkippedPath.section(QDir::separator(), 0, 0);
if (curPath == firstSectionSkippedPath)
{
// We are at the end of the path to skip, so skip it
if (nativeSkippedPath == firstSectionSkippedPath)
{
skippedPaths.removeAll(skippedPath);
skip = true;
break;
}
// Append the next section of the skipped path
else
{
deeperSkippedPaths.append(nativeSkippedPath.section(QDir::separator(), 1));
}
}
}
return skip;
}
typedef AZStd::function<void(/*fileCount=*/int, /*totalSizeInBytes=*/int)> StatusFunction;
static void RecursiveGetAllFiles(const QDir& directory, QStringList& outFileList, qint64& outTotalSizeInBytes, StatusFunction statusCallback)
static void RecursiveGetAllFiles(const QDir& directory, QStringList& skippedPaths, int& outFileCount, qint64& outTotalSizeInBytes, StatusFunction statusCallback)
{
const QStringList entries = directory.entryList(QDir::Dirs | QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
for (const QString& entryPath : entries)
{
const QString filePath = QDir::toNativeSeparators(QString("%1/%2").arg(directory.path()).arg(entryPath));
QStringList deeperSkippedPaths;
if (SkipFilePaths(entryPath, skippedPaths, deeperSkippedPaths))
{
continue;
}
QFileInfo fileInfo(filePath);
if (fileInfo.isDir())
{
QDir subDirectory(filePath);
RecursiveGetAllFiles(subDirectory, outFileList, outTotalSizeInBytes, statusCallback);
RecursiveGetAllFiles(subDirectory, deeperSkippedPaths, outFileCount, outTotalSizeInBytes, statusCallback);
}
else
{
outFileList.push_back(filePath);
++outFileCount;
outTotalSizeInBytes += fileInfo.size();
const int updateStatusEvery = 64;
if (outFileList.size() % updateStatusEvery == 0)
if (outFileCount % updateStatusEvery == 0)
{
statusCallback(outFileList.size(), outTotalSizeInBytes);
statusCallback(outFileCount, outTotalSizeInBytes);
}
}
}
@@ -90,7 +125,8 @@ namespace O3DE::ProjectManager
static bool CopyDirectory(QProgressDialog* progressDialog,
const QString& origPath,
const QString& newPath,
QStringList& filesToCopy,
QStringList& skippedPaths,
int filesToCopyCount,
int& outNumCopiedFiles,
qint64 totalSizeToCopy,
qint64& outCopiedFileSize,
@@ -102,18 +138,24 @@ namespace O3DE::ProjectManager
return false;
}
for (QString directory : original.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
for (const QString& directory : original.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
{
if (progressDialog->wasCanceled())
{
return false;
}
QStringList deeperSkippedPaths;
if (SkipFilePaths(directory, skippedPaths, deeperSkippedPaths))
{
continue;
}
QString newDirectoryPath = newPath + QDir::separator() + directory;
original.mkpath(newDirectoryPath);
if (!CopyDirectory(progressDialog, origPath + QDir::separator() + directory,
newDirectoryPath, filesToCopy, outNumCopiedFiles, totalSizeToCopy, outCopiedFileSize, showIgnoreFileDialog))
if (!CopyDirectory(progressDialog, origPath + QDir::separator() + directory, newDirectoryPath, deeperSkippedPaths,
filesToCopyCount, outNumCopiedFiles, totalSizeToCopy, outCopiedFileSize, showIgnoreFileDialog))
{
return false;
}
@@ -121,18 +163,25 @@ namespace O3DE::ProjectManager
QLocale locale;
const float progressDialogRangeHalf = qFabs(progressDialog->maximum() - progressDialog->minimum()) * 0.5f;
for (QString file : original.entryList(QDir::Files))
for (const QString& file : original.entryList(QDir::Files))
{
if (progressDialog->wasCanceled())
{
return false;
}
// Unused by this function but neccesary to pass in to SkipFilePaths
QStringList deeperSkippedPaths;
if (SkipFilePaths(file, skippedPaths, deeperSkippedPaths))
{
continue;
}
// Progress window update
{
// Weight in the number of already copied files as well as the copied bytes to get a better progress indication
// for cases combining many small files and some really large files.
const float normalizedNumFiles = static_cast<float>(outNumCopiedFiles) / filesToCopy.count();
const float normalizedNumFiles = static_cast<float>(outNumCopiedFiles) / filesToCopyCount;
const float normalizedFileSize = static_cast<float>(outCopiedFileSize) / totalSizeToCopy;
const int progress = normalizedNumFiles * progressDialogRangeHalf + normalizedFileSize * progressDialogRangeHalf;
progressDialog->setValue(progress);
@@ -140,7 +189,7 @@ namespace O3DE::ProjectManager
const QString copiedFileSizeString = locale.formattedDataSize(outCopiedFileSize);
const QString totalFileSizeString = locale.formattedDataSize(totalSizeToCopy);
progressDialog->setLabelText(QString("Coping file %1 of %2 (%3 of %4) ...").arg(QString::number(outNumCopiedFiles),
QString::number(filesToCopy.count()),
QString::number(filesToCopyCount),
copiedFileSizeString,
totalFileSizeString));
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
@@ -194,6 +243,39 @@ namespace O3DE::ProjectManager
return true;
}
static bool ClearProjectBuildArtifactsAndCache(const QString& origPath, const QString& newPath, QWidget* parent)
{
QDir buildDirectory = QDir(newPath);
if ((!buildDirectory.cd(ProjectBuildDirectoryName) || !DeleteProjectFiles(buildDirectory.path(), true))
&& QDir(origPath).cd(ProjectBuildDirectoryName))
{
QMessageBox::warning(
parent,
QObject::tr("Clear Build Artifacts"),
QObject::tr("Build artifacts failed to delete for moved project. Please manually delete build directory at \"%1\"")
.arg(buildDirectory.path()),
QMessageBox::Close);
return false;
}
QDir cacheDirectory = QDir(newPath);
if ((!cacheDirectory.cd(ProjectCacheDirectoryName) || !DeleteProjectFiles(cacheDirectory.path(), true))
&& QDir(origPath).cd(ProjectCacheDirectoryName))
{
QMessageBox::warning(
parent,
QObject::tr("Clear Asset Cache"),
QObject::tr("Asset cache failed to delete for moved project. Please manually delete cache directory at \"%1\"")
.arg(cacheDirectory.path()),
QMessageBox::Close);
return false;
}
return false;
}
bool AddProjectDialog(QWidget* parent)
{
QString path = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(parent, QObject::tr("Select Project Directory")));
@@ -215,7 +297,7 @@ namespace O3DE::ProjectManager
return PythonBindingsInterface::Get()->RemoveProject(path);
}
bool CopyProjectDialog(const QString& origPath, QWidget* parent)
bool CopyProjectDialog(const QString& origPath, ProjectInfo& newProjectInfo, QWidget* parent)
{
bool copyResult = false;
@@ -225,6 +307,8 @@ namespace O3DE::ProjectManager
QFileDialog::getExistingDirectory(parent, QObject::tr("Select New Project Directory"), parentOrigDir.path()));
if (!newPath.isEmpty())
{
newProjectInfo.m_path = newPath;
if (!WarnDirectoryOverwrite(newPath, parent))
{
return false;
@@ -236,7 +320,7 @@ namespace O3DE::ProjectManager
return copyResult;
}
bool CopyProject(const QString& origPath, const QString& newPath, QWidget* parent)
bool CopyProject(const QString& origPath, const QString& newPath, QWidget* parent, bool skipRegister)
{
// Disallow copying from or into subdirectory
if (IsDirectoryDescedent(origPath, newPath) || IsDirectoryDescedent(newPath, origPath))
@@ -244,8 +328,13 @@ namespace O3DE::ProjectManager
return false;
}
QStringList filesToCopy;
int filesToCopyCount = 0;
qint64 totalSizeInBytes = 0;
QStringList skippedPaths
{
ProjectBuildDirectoryName,
ProjectCacheDirectoryName
};
QProgressDialog* progressDialog = new QProgressDialog(parent);
progressDialog->setAutoClose(true);
@@ -256,7 +345,8 @@ namespace O3DE::ProjectManager
progressDialog->show();
QLocale locale;
RecursiveGetAllFiles(origPath, filesToCopy, totalSizeInBytes, [=](int fileCount, int sizeInBytes)
QStringList getFilesSkippedPaths(skippedPaths);
RecursiveGetAllFiles(origPath, getFilesSkippedPaths, filesToCopyCount, totalSizeInBytes, [=](int fileCount, int sizeInBytes)
{
// Create a human-readable version of the file size.
const QString fileSizeString = locale.formattedDataSize(sizeInBytes);
@@ -275,8 +365,10 @@ namespace O3DE::ProjectManager
// Phase 1: Copy files
bool showIgnoreFileDialog = true;
bool success = CopyDirectory(progressDialog, origPath, newPath, filesToCopy, numFilesCopied, totalSizeInBytes, copiedFileSize, showIgnoreFileDialog);
if (success)
QStringList copyFilesSkippedPaths(skippedPaths);
bool success = CopyDirectory(progressDialog, origPath, newPath, copyFilesSkippedPaths, filesToCopyCount, numFilesCopied,
totalSizeInBytes, copiedFileSize, showIgnoreFileDialog);
if (success && !skipRegister)
{
// Phase 2: Register project
success = RegisterProject(newPath);
@@ -299,7 +391,7 @@ namespace O3DE::ProjectManager
QDir projectDirectory(path);
if (projectDirectory.exists())
{
// Check if there is an actual project hereor just force it
// Check if there is an actual project here or just force it
if (force || PythonBindingsInterface::Get()->GetProject(path).IsSuccess())
{
return projectDirectory.removeRecursively();
@@ -309,12 +401,12 @@ namespace O3DE::ProjectManager
return false;
}
bool MoveProject(QString origPath, QString newPath, QWidget* parent, bool ignoreRegister)
bool MoveProject(QString origPath, QString newPath, QWidget* parent, bool skipRegister)
{
origPath = QDir::toNativeSeparators(origPath);
newPath = QDir::toNativeSeparators(newPath);
if (!WarnDirectoryOverwrite(newPath, parent) || (!ignoreRegister && !UnregisterProject(origPath)))
if (!WarnDirectoryOverwrite(newPath, parent) || (!skipRegister && !UnregisterProject(origPath)))
{
return false;
}
@@ -334,8 +426,13 @@ namespace O3DE::ProjectManager
DeleteProjectFiles(origPath, true);
}
else
{
// If directoy rename succeeded then build and cache directories need to be deleted seperately
ClearProjectBuildArtifactsAndCache(origPath, newPath, parent);
}
if (!ignoreRegister && !RegisterProject(newPath))
if (!skipRegister && !RegisterProject(newPath))
{
return false;
}