Merge branch 'stabilization/2106' into daimini/gitflow_210716_o3de
Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> # Conflicts: # scripts/build/bootstrap/incremental_build_util.py
This commit is contained in:
@@ -277,7 +277,7 @@ namespace AZ::IO
|
||||
//! then their hash values are also equal
|
||||
//! For example : path "a//b" equals "a/b", the
|
||||
//! hash value of "a//b" would also equal the hash value of "a/b"
|
||||
constexpr size_t hash_value(const PathView& pathToHash) noexcept;
|
||||
size_t hash_value(const PathView& pathToHash) noexcept;
|
||||
|
||||
// path.comparison
|
||||
constexpr bool operator==(const PathView& lhs, const PathView& rhs) noexcept;
|
||||
@@ -622,7 +622,7 @@ namespace AZ::IO
|
||||
//! For example : path "a//b" equals "a/b", the
|
||||
//! hash value of "a//b" would also equal the hash value of "a/b"
|
||||
template <typename StringType>
|
||||
constexpr size_t hash_value(const BasicPath<StringType>& pathToHash);
|
||||
size_t hash_value(const BasicPath<StringType>& pathToHash);
|
||||
|
||||
// path.append
|
||||
template <typename StringType>
|
||||
|
||||
@@ -1951,7 +1951,7 @@ namespace AZ::IO
|
||||
}
|
||||
|
||||
template <typename StringType>
|
||||
constexpr size_t hash_value(const BasicPath<StringType>& pathToHash)
|
||||
inline size_t hash_value(const BasicPath<StringType>& pathToHash)
|
||||
{
|
||||
return AZStd::hash<BasicPath<StringType>>{}(pathToHash);
|
||||
}
|
||||
@@ -2082,13 +2082,28 @@ namespace AZStd
|
||||
template <>
|
||||
struct hash<AZ::IO::PathView>
|
||||
{
|
||||
constexpr size_t operator()(const AZ::IO::PathView& pathToHash) noexcept
|
||||
/// Path is using FNV-1a algorithm 64 bit version.
|
||||
static size_t hash_path(AZStd::string_view pathSegment, const char pathSeparator)
|
||||
{
|
||||
size_t hash = 14695981039346656037ULL;
|
||||
constexpr size_t fnvPrime = 1099511628211ULL;
|
||||
|
||||
for (const char first : pathSegment)
|
||||
{
|
||||
hash ^= static_cast<size_t>((pathSeparator == AZ::IO::PosixPathSeparator)
|
||||
? first : tolower(first));
|
||||
hash *= fnvPrime;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
size_t operator()(const AZ::IO::PathView& pathToHash) noexcept
|
||||
{
|
||||
auto pathParser = AZ::IO::parser::PathParser::CreateBegin(pathToHash.Native(), pathToHash.m_preferred_separator);
|
||||
size_t hash_value = 0;
|
||||
while (pathParser)
|
||||
{
|
||||
AZStd::hash_combine(hash_value, AZStd::hash<AZStd::string_view>{}(*pathParser));
|
||||
AZStd::hash_combine(hash_value, hash_path(*pathParser, pathToHash.m_preferred_separator));
|
||||
++pathParser;
|
||||
}
|
||||
return hash_value;
|
||||
@@ -2097,7 +2112,7 @@ namespace AZStd
|
||||
template <typename StringType>
|
||||
struct hash<AZ::IO::BasicPath<StringType>>
|
||||
{
|
||||
constexpr size_t operator()(const AZ::IO::BasicPath<StringType>& pathToHash) noexcept
|
||||
const size_t operator()(const AZ::IO::BasicPath<StringType>& pathToHash) noexcept
|
||||
{
|
||||
return AZStd::hash<AZ::IO::PathView>{}(pathToHash);
|
||||
}
|
||||
@@ -2108,11 +2123,11 @@ namespace AZStd
|
||||
template struct hash<AZ::IO::FixedMaxPath>;
|
||||
}
|
||||
|
||||
// Explicit instantations of our support Path classes
|
||||
// Explicit instantiations of our support Path classes
|
||||
namespace AZ::IO
|
||||
{
|
||||
// PathView hash
|
||||
constexpr size_t hash_value(const PathView& pathToHash) noexcept
|
||||
inline size_t hash_value(const PathView& pathToHash) noexcept
|
||||
{
|
||||
return AZStd::hash<PathView>{}(pathToHash);
|
||||
}
|
||||
|
||||
@@ -182,6 +182,36 @@ namespace UnitTest
|
||||
AZStd::tuple<AZStd::string_view, AZStd::string_view>(R"(foO/Bar)", "foo/bar")
|
||||
));
|
||||
|
||||
using PathHashParamFixture = PathParamFixture;
|
||||
TEST_P(PathHashParamFixture, HashOperator_HashesCaseInsensitiveForWindowsPaths)
|
||||
{
|
||||
AZ::IO::Path path1{ AZStd::get<0>(GetParam()), AZ::IO::WindowsPathSeparator };
|
||||
AZ::IO::Path path2{ AZStd::get<1>(GetParam()), AZ::IO::WindowsPathSeparator };
|
||||
size_t path1Hash = AZStd::hash<AZ::IO::PathView>{}(path1);
|
||||
size_t path2Hash = AZStd::hash<AZ::IO::PathView>{}(path2);
|
||||
EXPECT_EQ(path1Hash, path2Hash) << AZStd::string::format(R"(path1 "%s" should hash to path2 "%s"\n)",
|
||||
path1.c_str(), path2.c_str()).c_str();
|
||||
}
|
||||
|
||||
TEST_P(PathHashParamFixture, HashOperator_HashesCaseSensitiveForPosixPaths)
|
||||
{
|
||||
AZ::IO::Path path1{ AZStd::get<0>(GetParam()), AZ::IO::PosixPathSeparator };
|
||||
AZ::IO::Path path2{ AZStd::get<1>(GetParam()), AZ::IO::PosixPathSeparator };
|
||||
size_t path1Hash = AZStd::hash<AZ::IO::PathView>{}(path1);
|
||||
size_t path2Hash = AZStd::hash<AZ::IO::PathView>{}(path2);
|
||||
EXPECT_NE(path1Hash, path2Hash) << AZStd::string::format(R"(path1 "%s" should NOT hash to path2 "%s"\n)",
|
||||
path1.c_str(), path2.c_str()).c_str();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
HashPaths,
|
||||
PathHashParamFixture,
|
||||
::testing::Values(
|
||||
AZStd::tuple<AZStd::string_view, AZStd::string_view>("C:/test/foo", R"(c:\test/foo)"),
|
||||
AZStd::tuple<AZStd::string_view, AZStd::string_view>(R"(D:\test/bar/baz//foo)", "d:/test/bar/baz\\\\\\foo"),
|
||||
AZStd::tuple<AZStd::string_view, AZStd::string_view>(R"(foO/Bar)", "foo/bar")
|
||||
));
|
||||
|
||||
class PathSingleParamFixture
|
||||
: public ScopedAllocatorSetupFixture
|
||||
, public ::testing::WithParamInterface<AZStd::tuple<AZStd::string_view>>
|
||||
|
||||
@@ -38,8 +38,19 @@ ly_add_target(
|
||||
string(REPLACE "." ";" version_list "${LY_VERSION_STRING}")
|
||||
list(GET version_list 0 EXE_VERSION_INFO_0)
|
||||
list(GET version_list 1 EXE_VERSION_INFO_1)
|
||||
list(GET version_list 2 EXE_VERSION_INFO_2)
|
||||
list(GET version_list 3 EXE_VERSION_INFO_3)
|
||||
|
||||
list(LENGTH version_list version_component_count)
|
||||
if(${version_component_count} GREATER_EQUAL 3)
|
||||
list(GET version_list 2 EXE_VERSION_INFO_2)
|
||||
else()
|
||||
set(EXE_VERSION_INFO_2 0)
|
||||
endif()
|
||||
|
||||
if(${version_component_count} GREATER_EQUAL 4)
|
||||
list(GET version_list 3 EXE_VERSION_INFO_3)
|
||||
else()
|
||||
set(EXE_VERSION_INFO_3 0)
|
||||
endif()
|
||||
|
||||
ly_add_source_properties(
|
||||
SOURCES Shared/CrashHandler.cpp
|
||||
|
||||
@@ -8,4 +8,6 @@
|
||||
set(FILES
|
||||
Python_linux.cpp
|
||||
ProjectBuilderWorker_linux.cpp
|
||||
ProjectUtils_linux.cpp
|
||||
ProjectManagerDefs_linux.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectManagerDefs.h>
|
||||
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
const QString ProjectBuildPathPostfix = ProjectBuildDirectoryName + "/linux";
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectUtils.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
namespace ProjectUtils
|
||||
{
|
||||
AZ::Outcome<void, QString> FindSupportedCompilerForPlatform()
|
||||
{
|
||||
// Compiler detection not supported on platform
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -8,4 +8,6 @@
|
||||
set(FILES
|
||||
Python_mac.cpp
|
||||
ProjectBuilderWorker_mac.cpp
|
||||
ProjectUtils_mac.cpp
|
||||
ProjectManagerDefs_mac.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectManagerDefs.h>
|
||||
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
const QString ProjectBuildPathPostfix = ProjectBuildDirectoryName + "/mac_xcode";
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectUtils.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
namespace ProjectUtils
|
||||
{
|
||||
AZ::Outcome<void, QString> FindSupportedCompilerForPlatform()
|
||||
{
|
||||
// Compiler detection not supported on platform
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -8,4 +8,6 @@
|
||||
set(FILES
|
||||
Python_windows.cpp
|
||||
ProjectBuilderWorker_windows.cpp
|
||||
ProjectUtils_windows.cpp
|
||||
ProjectManagerDefs_windows.cpp
|
||||
)
|
||||
|
||||
@@ -75,8 +75,17 @@ namespace O3DE::ProjectManager
|
||||
|
||||
m_configProjectProcess->start(
|
||||
"cmake",
|
||||
QStringList{ "-B", QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix), "-S", m_projectInfo.m_path, "-G",
|
||||
"Visual Studio 16", "-DLY_3RDPARTY_PATH=" + engineInfo.m_thirdPartyPath });
|
||||
QStringList
|
||||
{
|
||||
"-B",
|
||||
QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix),
|
||||
"-S",
|
||||
m_projectInfo.m_path,
|
||||
"-G",
|
||||
"Visual Studio 16",
|
||||
"-DLY_3RDPARTY_PATH=" + engineInfo.m_thirdPartyPath,
|
||||
"-DLY_UNITY_BUILD=1"
|
||||
});
|
||||
|
||||
if (!m_configProjectProcess->waitForStarted())
|
||||
{
|
||||
@@ -124,8 +133,16 @@ namespace O3DE::ProjectManager
|
||||
|
||||
m_buildProjectProcess->start(
|
||||
"cmake",
|
||||
QStringList{ "--build", QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix), "--target",
|
||||
m_projectInfo.m_projectName + ".GameLauncher", "Editor", "--config", "profile" });
|
||||
QStringList
|
||||
{
|
||||
"--build",
|
||||
QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix),
|
||||
"--target",
|
||||
m_projectInfo.m_projectName + ".GameLauncher",
|
||||
"Editor",
|
||||
"--config",
|
||||
"profile"
|
||||
});
|
||||
|
||||
if (!m_buildProjectProcess->waitForStarted())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectManagerDefs.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
const QString ProjectBuildPathPostfix = ProjectBuildDirectoryName + "/windows_vs2019";
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ProjectUtils.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
namespace ProjectUtils
|
||||
{
|
||||
AZ::Outcome<void, QString> FindSupportedCompilerForPlatform()
|
||||
{
|
||||
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
|
||||
QString programFilesPath = environment.value("ProgramFiles(x86)");
|
||||
QString vsWherePath = QDir(programFilesPath).filePath("Microsoft Visual Studio/Installer/vswhere.exe");
|
||||
|
||||
QFileInfo vsWhereFile(vsWherePath);
|
||||
if (vsWhereFile.exists() && vsWhereFile.isFile())
|
||||
{
|
||||
QProcess vsWhereProcess;
|
||||
vsWhereProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
vsWhereProcess.start(
|
||||
vsWherePath,
|
||||
QStringList{
|
||||
"-version",
|
||||
"16.0",
|
||||
"-latest",
|
||||
"-requires",
|
||||
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
||||
"-property",
|
||||
"isComplete"
|
||||
});
|
||||
|
||||
if (vsWhereProcess.waitForStarted() && vsWhereProcess.waitForFinished())
|
||||
{
|
||||
QString vsWhereOutput(vsWhereProcess.readAllStandardOutput());
|
||||
if (vsWhereOutput.startsWith("1"))
|
||||
{
|
||||
return AZ::Success();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Failure(QObject::tr("Visual Studio 2019 not found.\n\n"
|
||||
"Visual Studio 2019 is required to build this project."
|
||||
" Install any edition of <a href='https://visualstudio.microsoft.com/downloads/'>Visual Studio 2019</a>"
|
||||
" before proceeding to the next step."));
|
||||
}
|
||||
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <ScreenHeaderWidget.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <GemCatalog/GemCatalogScreen.h>
|
||||
#include <ProjectUtils.h>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHBoxLayout>
|
||||
@@ -222,38 +223,42 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void CreateProjectCtrl::CreateProject()
|
||||
{
|
||||
if (m_newProjectSettingsScreen->Validate())
|
||||
if (ProjectUtils::FindSupportedCompiler(this))
|
||||
{
|
||||
ProjectInfo projectInfo = m_newProjectSettingsScreen->GetProjectInfo();
|
||||
QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath();
|
||||
|
||||
auto result = PythonBindingsInterface::Get()->CreateProject(projectTemplatePath, projectInfo);
|
||||
if (result.IsSuccess())
|
||||
if (m_newProjectSettingsScreen->Validate())
|
||||
{
|
||||
// automatically register the project
|
||||
PythonBindingsInterface::Get()->AddProject(projectInfo.m_path);
|
||||
ProjectInfo projectInfo = m_newProjectSettingsScreen->GetProjectInfo();
|
||||
QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath();
|
||||
|
||||
auto result = PythonBindingsInterface::Get()->CreateProject(projectTemplatePath, projectInfo);
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
// automatically register the project
|
||||
PythonBindingsInterface::Get()->AddProject(projectInfo.m_path);
|
||||
|
||||
#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED
|
||||
if (!m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for template."));
|
||||
return;
|
||||
}
|
||||
if (!m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for template."));
|
||||
return;
|
||||
}
|
||||
#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
|
||||
|
||||
projectInfo.m_needsBuild = true;
|
||||
emit NotifyBuildProject(projectInfo);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
projectInfo.m_needsBuild = true;
|
||||
emit NotifyBuildProject(projectInfo);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project creation failed"), tr("Failed to create project."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project creation failed"), tr("Failed to create project."));
|
||||
QMessageBox::warning(
|
||||
this, tr("Invalid project settings"), tr("Please correct the indicated project settings and try again."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid project settings"), tr("Please correct the indicated project settings and try again."));
|
||||
}
|
||||
}
|
||||
|
||||
void CreateProjectCtrl::ReinitGemCatalogForSelectedTemplate()
|
||||
|
||||
@@ -70,8 +70,9 @@ namespace O3DE::ProjectManager
|
||||
m_lastProgress = progress;
|
||||
if (m_projectButton)
|
||||
{
|
||||
m_projectButton->SetButtonOverlayText(QString("%1 (%2%)\n\n").arg(tr("Building Project..."), QString::number(progress)));
|
||||
m_projectButton->SetButtonOverlayText(QString("%1 (%2%)<br>%3<br>").arg(tr("Building Project..."), QString::number(progress), tr("Click to <a href=\"logs\">view logs</a>.")));
|
||||
m_projectButton->SetProgressBarValue(progress);
|
||||
m_projectButton->SetBuildLogsLink(m_worker->GetLogFilePath());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
const QString ProjectBuilderWorker::BuildCancelled = QObject::tr("Build Cancelled.");
|
||||
|
||||
ProjectBuilderWorker::ProjectBuilderWorker(const ProjectInfo& projectInfo)
|
||||
: QObject()
|
||||
, m_projectInfo(projectInfo)
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace O3DE::ProjectManager
|
||||
// QProcess::waitForFinished uses -1 to indicate that the process should not timeout
|
||||
static constexpr int MaxBuildTimeMSecs = -1;
|
||||
// Build was cancelled
|
||||
static const QString BuildCancelled;
|
||||
inline static const QString BuildCancelled = QObject::tr("Build Cancelled.");
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -39,7 +39,9 @@ namespace O3DE::ProjectManager
|
||||
m_overlayLabel->setObjectName("labelButtonOverlay");
|
||||
m_overlayLabel->setWordWrap(true);
|
||||
m_overlayLabel->setAlignment(Qt::AlignCenter);
|
||||
m_overlayLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse);
|
||||
m_overlayLabel->setVisible(false);
|
||||
connect(m_overlayLabel, &QLabel::linkActivated, this, &LabelButton::OnLinkActivated);
|
||||
vLayout->addWidget(m_overlayLabel);
|
||||
|
||||
m_buildOverlayLayout = new QVBoxLayout();
|
||||
@@ -231,7 +233,7 @@ namespace O3DE::ProjectManager
|
||||
AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path);
|
||||
});
|
||||
menu->addSeparator();
|
||||
menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo.m_path); });
|
||||
menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); });
|
||||
menu->addSeparator();
|
||||
menu->addAction(tr("Remove from O3DE"), this, [this]() { emit RemoveProject(m_projectInfo.m_path); });
|
||||
menu->addAction(tr("Delete this Project"), this, [this]() { emit DeleteProject(m_projectInfo.m_path); });
|
||||
@@ -266,6 +268,11 @@ namespace O3DE::ProjectManager
|
||||
SetProjectButtonAction(tr("Build Project"), [this]() { emit BuildProject(m_projectInfo); });
|
||||
}
|
||||
|
||||
void ProjectButton::SetBuildLogsLink(const QUrl& logUrl)
|
||||
{
|
||||
m_projectImageLabel->SetLogUrl(logUrl);
|
||||
}
|
||||
|
||||
void ProjectButton::ShowBuildFailed(bool show, const QUrl& logUrl)
|
||||
{
|
||||
if (!logUrl.isEmpty())
|
||||
|
||||
@@ -77,6 +77,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void SetProjectButtonAction(const QString& text, AZStd::function<void()> lambda);
|
||||
void SetProjectBuildButtonAction();
|
||||
void SetBuildLogsLink(const QUrl& logUrl);
|
||||
void ShowBuildFailed(bool show, const QUrl& logUrl);
|
||||
|
||||
void SetLaunchButtonEnabled(bool enabled);
|
||||
@@ -87,7 +88,7 @@ namespace O3DE::ProjectManager
|
||||
signals:
|
||||
void OpenProject(const QString& projectName);
|
||||
void EditProject(const QString& projectName);
|
||||
void CopyProject(const QString& projectName);
|
||||
void CopyProject(const ProjectInfo& projectInfo);
|
||||
void RemoveProject(const QString& projectName);
|
||||
void DeleteProject(const QString& projectName);
|
||||
void BuildProject(const ProjectInfo& projectInfo);
|
||||
|
||||
@@ -14,8 +14,10 @@ namespace O3DE::ProjectManager
|
||||
inline constexpr static int ProjectPreviewImageHeight = 280;
|
||||
inline constexpr static int ProjectTemplateImageWidth = 92;
|
||||
|
||||
static const QString ProjectBuildPathPostfix = "build/windows_vs2019";
|
||||
static const QString ProjectBuildDirectoryName = "build";
|
||||
extern const QString ProjectBuildPathPostfix;
|
||||
static const QString ProjectBuildPathCmakeFiles = "CMakeFiles";
|
||||
static const QString ProjectBuildErrorLogName = "CMakeProjectBuildError.log";
|
||||
static const QString ProjectCacheDirectoryName = "Cache";
|
||||
static const QString ProjectPreviewImagePath = "preview.png";
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <ProjectUtils.h>
|
||||
#include <ProjectManagerDefs.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <QFileDialog>
|
||||
@@ -17,6 +18,8 @@
|
||||
#include <QProcessEnvironment>
|
||||
#include <QGuiApplication>
|
||||
#include <QProgressDialog>
|
||||
#include <QSpacerItem>
|
||||
#include <QGridLayout>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -57,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,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,
|
||||
@@ -100,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;
|
||||
}
|
||||
@@ -119,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);
|
||||
@@ -138,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);
|
||||
@@ -192,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")));
|
||||
@@ -213,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;
|
||||
|
||||
@@ -223,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;
|
||||
@@ -234,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))
|
||||
@@ -242,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);
|
||||
@@ -254,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);
|
||||
@@ -273,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);
|
||||
@@ -297,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();
|
||||
@@ -307,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;
|
||||
}
|
||||
@@ -332,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;
|
||||
}
|
||||
@@ -374,46 +473,27 @@ namespace O3DE::ProjectManager
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsVS2019Installed_internal()
|
||||
bool FindSupportedCompiler(QWidget* parent)
|
||||
{
|
||||
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
|
||||
QString programFilesPath = environment.value("ProgramFiles(x86)");
|
||||
QString vsWherePath = programFilesPath + "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
|
||||
auto findCompilerResult = FindSupportedCompilerForPlatform();
|
||||
|
||||
QFileInfo vsWhereFile(vsWherePath);
|
||||
if (vsWhereFile.exists() && vsWhereFile.isFile())
|
||||
if (!findCompilerResult.IsSuccess())
|
||||
{
|
||||
QProcess vsWhereProcess;
|
||||
vsWhereProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
QMessageBox vsWarningMessage(parent);
|
||||
vsWarningMessage.setIcon(QMessageBox::Warning);
|
||||
vsWarningMessage.setWindowTitle(QObject::tr("Create Project"));
|
||||
// Makes link clickable
|
||||
vsWarningMessage.setTextFormat(Qt::RichText);
|
||||
vsWarningMessage.setText(findCompilerResult.GetError());
|
||||
vsWarningMessage.setStandardButtons(QMessageBox::Close);
|
||||
|
||||
vsWhereProcess.start(
|
||||
vsWherePath,
|
||||
QStringList{ "-version", "16.0", "-latest", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
||||
"-property", "isComplete" });
|
||||
|
||||
if (!vsWhereProcess.waitForStarted())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (vsWhereProcess.waitForReadyRead())
|
||||
{
|
||||
}
|
||||
|
||||
QString vsWhereOutput(vsWhereProcess.readAllStandardOutput());
|
||||
if (vsWhereOutput.startsWith("1"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
QSpacerItem* horizontalSpacer = new QSpacerItem(600, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
QGridLayout* layout = reinterpret_cast<QGridLayout*>(vsWarningMessage.layout());
|
||||
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
|
||||
vsWarningMessage.exec();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsVS2019Installed()
|
||||
{
|
||||
static bool vs2019Installed = IsVS2019Installed_internal();
|
||||
return vs2019Installed;
|
||||
return findCompilerResult.IsSuccess();
|
||||
}
|
||||
|
||||
ProjectManagerScreen GetProjectManagerScreen(const QString& screen)
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <ScreenDefs.h>
|
||||
#include <ProjectInfo.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -16,14 +19,15 @@ namespace O3DE::ProjectManager
|
||||
bool AddProjectDialog(QWidget* parent = nullptr);
|
||||
bool RegisterProject(const QString& path);
|
||||
bool UnregisterProject(const QString& path);
|
||||
bool CopyProjectDialog(const QString& origPath, QWidget* parent = nullptr);
|
||||
bool CopyProject(const QString& origPath, const QString& newPath, QWidget* parent);
|
||||
bool CopyProjectDialog(const QString& origPath, ProjectInfo& newProjectInfo, QWidget* parent = nullptr);
|
||||
bool CopyProject(const QString& origPath, const QString& newPath, QWidget* parent, bool skipRegister = false);
|
||||
bool DeleteProjectFiles(const QString& path, bool force = false);
|
||||
bool MoveProject(QString origPath, QString newPath, QWidget* parent = nullptr, bool ignoreRegister = false);
|
||||
bool MoveProject(QString origPath, QString newPath, QWidget* parent, bool skipRegister = false);
|
||||
|
||||
bool ReplaceFile(const QString& origFile, const QString& newFile, QWidget* parent = nullptr, bool interactive = true);
|
||||
|
||||
bool IsVS2019Installed();
|
||||
bool FindSupportedCompiler(QWidget* parent = nullptr);
|
||||
AZ::Outcome<void, QString> FindSupportedCompilerForPlatform();
|
||||
|
||||
ProjectManagerScreen GetProjectManagerScreen(const QString& screen);
|
||||
} // namespace ProjectUtils
|
||||
|
||||
@@ -384,14 +384,17 @@ namespace O3DE::ProjectManager
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::UpdateProject);
|
||||
}
|
||||
}
|
||||
void ProjectsScreen::HandleCopyProject(const QString& projectPath)
|
||||
void ProjectsScreen::HandleCopyProject(const ProjectInfo& projectInfo)
|
||||
{
|
||||
if (!WarnIfInBuildQueue(projectPath))
|
||||
if (!WarnIfInBuildQueue(projectInfo.m_path))
|
||||
{
|
||||
ProjectInfo newProjectInfo(projectInfo);
|
||||
|
||||
// Open file dialog and choose location for copied project then register copy with O3DE
|
||||
if (ProjectUtils::CopyProjectDialog(projectPath, this))
|
||||
if (ProjectUtils::CopyProjectDialog(projectInfo.m_path, newProjectInfo, this))
|
||||
{
|
||||
ResetProjectsContent();
|
||||
emit NotifyBuildProject(newProjectInfo);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
}
|
||||
}
|
||||
@@ -516,7 +519,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
bool ProjectsScreen::StartProjectBuild(const ProjectInfo& projectInfo)
|
||||
{
|
||||
if (ProjectUtils::IsVS2019Installed())
|
||||
if (ProjectUtils::FindSupportedCompiler(this))
|
||||
{
|
||||
QMessageBox::StandardButton buildProject = QMessageBox::information(
|
||||
this,
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace O3DE::ProjectManager
|
||||
void HandleAddProjectButton();
|
||||
void HandleOpenProject(const QString& projectPath);
|
||||
void HandleEditProject(const QString& projectPath);
|
||||
void HandleCopyProject(const QString& projectPath);
|
||||
void HandleCopyProject(const ProjectInfo& projectInfo);
|
||||
void HandleRemoveProject(const QString& projectPath);
|
||||
void HandleDeleteProject(const QString& projectPath);
|
||||
|
||||
|
||||
@@ -219,11 +219,13 @@ namespace O3DE::ProjectManager
|
||||
// Move project first to avoid trying to update settings at the new location before it has been moved there
|
||||
if (newProjectSettings.m_path != m_projectInfo.m_path)
|
||||
{
|
||||
if (!ProjectUtils::MoveProject(m_projectInfo.m_path, newProjectSettings.m_path))
|
||||
if (!ProjectUtils::MoveProject(m_projectInfo.m_path, newProjectSettings.m_path, this))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project move failed"), tr("Failed to move project."));
|
||||
return false;
|
||||
}
|
||||
|
||||
emit NotifyBuildProject(newProjectSettings);
|
||||
}
|
||||
|
||||
// Update project if settings changed
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <Application.h>
|
||||
#include <ProjectUtils.h>
|
||||
#include <ProjectManagerDefs.h>
|
||||
#include <ProjectManager_Test_Traits_Platform.h>
|
||||
|
||||
#include <QFile>
|
||||
@@ -25,16 +26,31 @@ namespace O3DE::ProjectManager
|
||||
: public ::UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
static inline QString ReplaceFirstAWithB(const QString& originalString)
|
||||
{
|
||||
QString bString(originalString);
|
||||
return bString.replace(bString.indexOf('A'), 1, 'B');
|
||||
}
|
||||
|
||||
ProjectManagerUtilsTests()
|
||||
{
|
||||
m_application = AZStd::make_unique<ProjectManager::Application>();
|
||||
m_application->Init(false);
|
||||
|
||||
QDir dir;
|
||||
dir.mkdir("ProjectA");
|
||||
dir.mkdir("ProjectB");
|
||||
m_projectAPath = "ProjectA";
|
||||
|
||||
QFile origFile("ProjectA/origFile.txt");
|
||||
// Replaces first 'A' with 'B'
|
||||
m_projectBPath = ReplaceFirstAWithB(m_projectAPath);
|
||||
m_projectABuildPath = QString("%1%2%3").arg(m_projectAPath, QDir::separator(), ProjectBuildDirectoryName);
|
||||
m_projectBBuildPath = ReplaceFirstAWithB(m_projectABuildPath);
|
||||
|
||||
QDir dir;
|
||||
dir.mkpath(m_projectABuildPath);
|
||||
dir.mkdir(m_projectBPath);
|
||||
|
||||
m_projectAOrigFilePath = QString("%1%2%3").arg(m_projectAPath, QDir::separator(), "origFile.txt");
|
||||
m_projectBOrigFilePath = ReplaceFirstAWithB(m_projectAOrigFilePath);
|
||||
QFile origFile(m_projectAOrigFilePath);
|
||||
if (origFile.open(QIODevice::ReadWrite))
|
||||
{
|
||||
QTextStream stream(&origFile);
|
||||
@@ -42,63 +58,153 @@ namespace O3DE::ProjectManager
|
||||
origFile.close();
|
||||
}
|
||||
|
||||
QFile replaceFile("ProjectA/replaceFile.txt");
|
||||
m_projectAReplaceFilePath = QString("%1%2%3").arg(m_projectAPath, QDir::separator(), "replaceFile.txt");
|
||||
m_projectBReplaceFilePath = ReplaceFirstAWithB(m_projectAReplaceFilePath);
|
||||
QFile replaceFile(m_projectAReplaceFilePath);
|
||||
if (replaceFile.open(QIODevice::ReadWrite))
|
||||
{
|
||||
QTextStream stream(&replaceFile);
|
||||
stream << "replace" << Qt::endl;
|
||||
replaceFile.close();
|
||||
}
|
||||
|
||||
m_projectABuildFilePath = QString("%1%2%3").arg(m_projectABuildPath, QDir::separator(), "build.obj");
|
||||
m_projectBBuildFilePath = ReplaceFirstAWithB(m_projectABuildFilePath);
|
||||
QFile buildFile(m_projectABuildFilePath);
|
||||
if (buildFile.open(QIODevice::ReadWrite))
|
||||
{
|
||||
QTextStream stream(&buildFile);
|
||||
stream << "x0FFFFFFFF" << Qt::endl;
|
||||
buildFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
~ProjectManagerUtilsTests()
|
||||
{
|
||||
QDir dirA("ProjectA");
|
||||
QDir dirA(m_projectAPath);
|
||||
dirA.removeRecursively();
|
||||
|
||||
QDir dirB("ProjectB");
|
||||
QDir dirB(m_projectBPath);
|
||||
dirB.removeRecursively();
|
||||
|
||||
m_application.reset();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<ProjectManager::Application> m_application;
|
||||
|
||||
QString m_projectAPath;
|
||||
QString m_projectAOrigFilePath;
|
||||
QString m_projectAReplaceFilePath;
|
||||
QString m_projectABuildPath;
|
||||
QString m_projectABuildFilePath;
|
||||
QString m_projectBPath;
|
||||
QString m_projectBOrigFilePath;
|
||||
QString m_projectBReplaceFilePath;
|
||||
QString m_projectBBuildPath;
|
||||
QString m_projectBBuildFilePath;
|
||||
|
||||
};
|
||||
|
||||
#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
TEST_F(ProjectManagerUtilsTests, DISABLED_MoveProject_Succeeds)
|
||||
TEST_F(ProjectManagerUtilsTests, DISABLED_MoveProject_MovesExpectedFiles)
|
||||
#else
|
||||
TEST_F(ProjectManagerUtilsTests, MoveProject_Succeeds)
|
||||
TEST_F(ProjectManagerUtilsTests, MoveProject_MovesExpectedFiles)
|
||||
#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
{
|
||||
EXPECT_TRUE(MoveProject(
|
||||
QDir::currentPath() + QDir::separator() + "ProjectA",
|
||||
QDir::currentPath() + QDir::separator() + "ProjectB",
|
||||
QDir::currentPath() + QDir::separator() + m_projectAPath,
|
||||
QDir::currentPath() + QDir::separator() + m_projectBPath,
|
||||
nullptr, true));
|
||||
|
||||
QFileInfo origFile("ProjectA/origFile.txt");
|
||||
EXPECT_TRUE(!origFile.exists());
|
||||
QFileInfo origFile(m_projectAOrigFilePath);
|
||||
EXPECT_FALSE(origFile.exists());
|
||||
|
||||
QFileInfo replaceFile("ProjectA/replaceFile.txt");
|
||||
EXPECT_TRUE(!replaceFile.exists());
|
||||
QFileInfo replaceFile(m_projectAReplaceFilePath);
|
||||
EXPECT_FALSE(replaceFile.exists());
|
||||
|
||||
QFileInfo origFileMoved("ProjectB/origFile.txt");
|
||||
QFileInfo origFileMoved(m_projectBOrigFilePath);
|
||||
EXPECT_TRUE(origFileMoved.exists() && origFileMoved.isFile());
|
||||
|
||||
QFileInfo replaceFileMoved("ProjectB/replaceFile.txt");
|
||||
QFileInfo replaceFileMoved(m_projectBReplaceFilePath);
|
||||
EXPECT_TRUE(replaceFileMoved.exists() && replaceFileMoved.isFile());
|
||||
}
|
||||
|
||||
#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
TEST_F(ProjectManagerUtilsTests, DISABLED_MoveProject_DoesntMoveBuild)
|
||||
#else
|
||||
TEST_F(ProjectManagerUtilsTests, MoveProject_DoesntMoveBuild)
|
||||
#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
{
|
||||
EXPECT_TRUE(MoveProject(
|
||||
QDir::currentPath() + QDir::separator() + m_projectAPath,
|
||||
QDir::currentPath() + QDir::separator() + m_projectBPath,
|
||||
nullptr, true));
|
||||
|
||||
QFileInfo origFile(m_projectAOrigFilePath);
|
||||
EXPECT_FALSE(origFile.exists());
|
||||
|
||||
QFileInfo origFileMoved(m_projectBOrigFilePath);
|
||||
EXPECT_TRUE(origFileMoved.exists() && origFileMoved.isFile());
|
||||
|
||||
QDir buildDir(m_projectBBuildPath);
|
||||
EXPECT_FALSE(buildDir.exists());
|
||||
}
|
||||
|
||||
#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
TEST_F(ProjectManagerUtilsTests, DISABLED_CopyProject_CopiesExpectedFiles)
|
||||
#else
|
||||
TEST_F(ProjectManagerUtilsTests, CopyProject_CopiesExpectedFiles)
|
||||
#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
{
|
||||
EXPECT_TRUE(CopyProject(
|
||||
QDir::currentPath() + QDir::separator() + m_projectAPath,
|
||||
QDir::currentPath() + QDir::separator() + m_projectBPath,
|
||||
nullptr, true));
|
||||
|
||||
QFileInfo origFile(m_projectAOrigFilePath);
|
||||
EXPECT_TRUE(origFile.exists());
|
||||
|
||||
QFileInfo replaceFile(m_projectAReplaceFilePath);
|
||||
EXPECT_TRUE(replaceFile.exists());
|
||||
|
||||
QFileInfo origFileMoved(m_projectBOrigFilePath);
|
||||
EXPECT_TRUE(origFileMoved.exists() && origFileMoved.isFile());
|
||||
|
||||
QFileInfo replaceFileMoved(m_projectBReplaceFilePath);
|
||||
EXPECT_TRUE(replaceFileMoved.exists() && replaceFileMoved.isFile());
|
||||
}
|
||||
|
||||
#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
TEST_F(ProjectManagerUtilsTests, DISABLED_CopyProject_DoesntCopyBuild)
|
||||
#else
|
||||
TEST_F(ProjectManagerUtilsTests, CopyProject_DoesntCopyBuild)
|
||||
#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
{
|
||||
EXPECT_TRUE(CopyProject(
|
||||
QDir::currentPath() + QDir::separator() + m_projectAPath,
|
||||
QDir::currentPath() + QDir::separator() + m_projectBPath,
|
||||
nullptr, true));
|
||||
|
||||
QFileInfo origFile(m_projectAOrigFilePath);
|
||||
EXPECT_TRUE(origFile.exists());
|
||||
|
||||
QFileInfo origFileMoved(m_projectBOrigFilePath);
|
||||
EXPECT_TRUE(origFileMoved.exists() && origFileMoved.isFile());
|
||||
|
||||
QDir buildDir(m_projectBBuildPath);
|
||||
EXPECT_FALSE(buildDir.exists());
|
||||
}
|
||||
|
||||
#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
TEST_F(ProjectManagerUtilsTests, DISABLED_ReplaceFile_Succeeds)
|
||||
#else
|
||||
TEST_F(ProjectManagerUtilsTests, ReplaceFile_Succeeds)
|
||||
#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS
|
||||
{
|
||||
EXPECT_TRUE(ReplaceFile("ProjectA/origFile.txt", "ProjectA/replaceFile.txt", nullptr, false));
|
||||
EXPECT_TRUE(ReplaceFile(m_projectAOrigFilePath, m_projectAReplaceFilePath, nullptr, false));
|
||||
|
||||
QFile origFile("ProjectA/origFile.txt");
|
||||
if (origFile.open(QIODevice::ReadOnly))
|
||||
QFile origFile(m_projectAOrigFilePath);
|
||||
EXPECT_TRUE(origFile.open(QIODevice::ReadOnly));
|
||||
{
|
||||
QTextStream stream(&origFile);
|
||||
QString line = stream.readLine();
|
||||
@@ -106,10 +212,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
origFile.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
Reference in New Issue
Block a user