Merge branch 'development' into Prism/ShowRepoList
This commit is contained in:
@@ -68,17 +68,46 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
|
||||
m_pythonBindings = AZStd::make_unique<PythonBindings>(GetEngineRoot());
|
||||
if (!m_pythonBindings || !m_pythonBindings->PythonStarted())
|
||||
AZ_Assert(m_pythonBindings, "Failed to create PythonBindings");
|
||||
if (!m_pythonBindings->PythonStarted())
|
||||
{
|
||||
if (interactive)
|
||||
if (!interactive)
|
||||
{
|
||||
QMessageBox::critical(nullptr, QObject::tr("Failed to start Python"),
|
||||
QObject::tr("This tool requires an O3DE engine with a Python runtime, "
|
||||
"but either Python is missing or mis-configured. Please rename "
|
||||
"your python/runtime folder to python/runtime_bak, then run "
|
||||
"python/get_python.bat to restore the Python runtime folder."));
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = QMessageBox::warning(nullptr, QObject::tr("Failed to start Python"),
|
||||
QObject::tr("This tool requires an O3DE engine with a Python runtime, "
|
||||
"but either Python is missing or mis-configured.<br><br>Press 'OK' to "
|
||||
"run the %1 script automatically, or 'Cancel' "
|
||||
" if you want to manually resolve the issue by renaming your "
|
||||
" python/runtime folder and running %1 yourself.")
|
||||
.arg(GetPythonScriptPath),
|
||||
QMessageBox::Cancel, QMessageBox::Ok);
|
||||
if (result == QMessageBox::Ok)
|
||||
{
|
||||
auto getPythonResult = ProjectUtils::RunGetPythonScript(GetEngineRoot());
|
||||
if (!getPythonResult.IsSuccess())
|
||||
{
|
||||
QMessageBox::critical(
|
||||
nullptr, QObject::tr("Failed to run %1 script").arg(GetPythonScriptPath),
|
||||
QObject::tr("The %1 script failed, was canceled, or could not be run. "
|
||||
"Please rename your python/runtime folder and then run "
|
||||
"<pre>%1</pre>").arg(GetPythonScriptPath));
|
||||
}
|
||||
else if (!m_pythonBindings->StartPython())
|
||||
{
|
||||
QMessageBox::critical(
|
||||
nullptr, QObject::tr("Failed to start Python"),
|
||||
QObject::tr("Failed to start Python after running %1")
|
||||
.arg(GetPythonScriptPath));
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_pythonBindings->PythonStarted())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const AZ::CommandLine* commandLine = GetCommandLine();
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
static const QString ProjectBuildDirectoryName = "build";
|
||||
extern const QString ProjectBuildPathPostfix;
|
||||
extern const QString GetPythonScriptPath;
|
||||
static const QString ProjectBuildPathCmakeFiles = "CMakeFiles";
|
||||
static const QString ProjectBuildErrorLogName = "CMakeProjectBuildError.log";
|
||||
static const QString ProjectCacheDirectoryName = "Cache";
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
#include <QProgressDialog>
|
||||
#include <QSpacerItem>
|
||||
#include <QGridLayout>
|
||||
#include <QTextEdit>
|
||||
#include <QByteArray>
|
||||
#include <QScrollBar>
|
||||
#include <QProgressBar>
|
||||
#include <QLabel>
|
||||
|
||||
#include <AzCore/std/chrono/chrono.h>
|
||||
|
||||
@@ -512,6 +517,97 @@ namespace O3DE::ProjectManager
|
||||
return ProjectManagerScreen::Invalid;
|
||||
}
|
||||
|
||||
AZ::Outcome<QString, QString> ExecuteCommandResultModalDialog(
|
||||
const QString& cmd,
|
||||
const QStringList& arguments,
|
||||
const QProcessEnvironment& processEnv,
|
||||
const QString& title)
|
||||
{
|
||||
QString resultOutput;
|
||||
QProcess execProcess;
|
||||
execProcess.setProcessEnvironment(processEnv);
|
||||
execProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
QProgressDialog dialog(title, QObject::tr("Cancel"), /*minimum=*/0, /*maximum=*/0);
|
||||
dialog.setMinimumWidth(500);
|
||||
dialog.setAutoClose(false);
|
||||
|
||||
QProgressBar* bar = new QProgressBar(&dialog);
|
||||
bar->setTextVisible(false);
|
||||
bar->setMaximum(0); // infinite
|
||||
dialog.setBar(bar);
|
||||
|
||||
QLabel* progressLabel = new QLabel(&dialog);
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
|
||||
// pre-fill the field with the title and command
|
||||
const QString commandOutput = QString("%1<br>%2 %3<br>").arg(title).arg(cmd).arg(arguments.join(' '));
|
||||
|
||||
// replace the label with a scrollable text edit
|
||||
QTextEdit* detailTextEdit = new QTextEdit(commandOutput, &dialog);
|
||||
detailTextEdit->setReadOnly(true);
|
||||
layout->addWidget(detailTextEdit);
|
||||
layout->setMargin(0);
|
||||
progressLabel->setLayout(layout);
|
||||
progressLabel->setMinimumHeight(150);
|
||||
dialog.setLabel(progressLabel);
|
||||
|
||||
auto readConnection = QObject::connect(&execProcess, &QProcess::readyReadStandardOutput,
|
||||
[&]()
|
||||
{
|
||||
QScrollBar* scrollBar = detailTextEdit->verticalScrollBar();
|
||||
bool autoScroll = scrollBar->value() == scrollBar->maximum();
|
||||
|
||||
QString output = execProcess.readAllStandardOutput();
|
||||
detailTextEdit->append(output);
|
||||
resultOutput.append(output);
|
||||
|
||||
if (autoScroll)
|
||||
{
|
||||
scrollBar->setValue(scrollBar->maximum());
|
||||
}
|
||||
});
|
||||
|
||||
auto exitConnection = QObject::connect(&execProcess,
|
||||
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
[&](int exitCode, [[maybe_unused]] QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
QScrollBar* scrollBar = detailTextEdit->verticalScrollBar();
|
||||
dialog.setMaximum(100);
|
||||
dialog.setValue(dialog.maximum());
|
||||
if (exitCode == 0 && scrollBar->value() == scrollBar->maximum())
|
||||
{
|
||||
dialog.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// keep the dialog open so the user can look at the output
|
||||
dialog.setCancelButtonText(QObject::tr("Continue"));
|
||||
}
|
||||
});
|
||||
|
||||
execProcess.start(cmd, arguments);
|
||||
|
||||
dialog.exec();
|
||||
|
||||
QObject::disconnect(readConnection);
|
||||
QObject::disconnect(exitConnection);
|
||||
|
||||
if (execProcess.state() == QProcess::Running)
|
||||
{
|
||||
execProcess.kill();
|
||||
return AZ::Failure(QObject::tr("Process for command '%1' was canceled").arg(cmd));
|
||||
}
|
||||
|
||||
int resultCode = execProcess.exitCode();
|
||||
if (resultCode != 0)
|
||||
{
|
||||
return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2").arg(cmd).arg(resultCode));
|
||||
}
|
||||
|
||||
return AZ::Success(resultOutput);
|
||||
}
|
||||
|
||||
AZ::Outcome<QString, QString> ExecuteCommandResult(
|
||||
const QString& cmd,
|
||||
const QStringList& arguments,
|
||||
|
||||
@@ -35,15 +35,39 @@ namespace O3DE::ProjectManager
|
||||
|
||||
ProjectManagerScreen GetProjectManagerScreen(const QString& screen);
|
||||
|
||||
/**
|
||||
* Execute a console command and return the result.
|
||||
* @param cmd the command
|
||||
* @param arguments the command argument list
|
||||
* @param processEnv the environment
|
||||
* @param commandTimeoutSeconds the amount of time in seconds to let the command run before terminating it
|
||||
* @return AZ::Outcome with the command result on success
|
||||
*/
|
||||
AZ::Outcome<QString, QString> ExecuteCommandResult(
|
||||
const QString& cmd,
|
||||
const QStringList& arguments,
|
||||
const QProcessEnvironment& processEnv,
|
||||
int commandTimeoutSeconds = ProjectCommandLineTimeoutSeconds);
|
||||
|
||||
/**
|
||||
* Execute a console command, display the progress in a modal dialog and return the result.
|
||||
* @param cmd the command
|
||||
* @param arguments the command argument list
|
||||
* @param processEnv the environment
|
||||
* @param commandTimeoutSeconds the amount of time in seconds to let the command run before terminating it
|
||||
* @return AZ::Outcome with the command result on success
|
||||
*/
|
||||
AZ::Outcome<QString, QString> ExecuteCommandResultModalDialog(
|
||||
const QString& cmd,
|
||||
const QStringList& arguments,
|
||||
const QProcessEnvironment& processEnv,
|
||||
const QString& title);
|
||||
|
||||
AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment();
|
||||
AZ::Outcome<QString, QString> GetProjectBuildPath(const QString& projectPath);
|
||||
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath);
|
||||
AZ::Outcome<QString, QString> RunGetPythonScript(const QString& enginePath);
|
||||
|
||||
|
||||
} // namespace ProjectUtils
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -246,9 +246,11 @@ namespace O3DE::ProjectManager
|
||||
if (Py_IsInitialized())
|
||||
{
|
||||
AZ_Warning("python", false, "Python is already active");
|
||||
return false;
|
||||
return m_pythonStarted;
|
||||
}
|
||||
|
||||
m_pythonStarted = false;
|
||||
|
||||
// set PYTHON_HOME
|
||||
AZStd::string pyBasePath = Platform::GetPythonHomePath(PY_PACKAGE, m_enginePath.c_str());
|
||||
if (!AZ::IO::SystemFile::Exists(pyBasePath.c_str()))
|
||||
@@ -304,7 +306,8 @@ namespace O3DE::ProjectManager
|
||||
// make sure the engine is registered
|
||||
RegisterThisEngine();
|
||||
|
||||
return !PyErr_Occurred();
|
||||
m_pythonStarted = !PyErr_Occurred();
|
||||
return m_pythonStarted;
|
||||
}
|
||||
catch ([[maybe_unused]] const std::exception& e)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
// PythonBindings overrides
|
||||
bool PythonStarted() override;
|
||||
bool StartPython() override;
|
||||
|
||||
// Engine
|
||||
AZ::Outcome<EngineInfo> GetEngineInfo() override;
|
||||
@@ -70,7 +71,6 @@ namespace O3DE::ProjectManager
|
||||
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
|
||||
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
|
||||
bool RegisterThisEngine();
|
||||
bool StartPython();
|
||||
bool StopPython();
|
||||
|
||||
|
||||
|
||||
@@ -38,6 +38,14 @@ namespace O3DE::ProjectManager
|
||||
*/
|
||||
virtual bool PythonStarted() = 0;
|
||||
|
||||
/**
|
||||
* Attempt to start Python. Normally, Python is started when the bindings are created,
|
||||
* but this method allows you to attempt to retry starting Python in case the configuration
|
||||
* has changed.
|
||||
* @return true if Python was started successfully, false on failure
|
||||
*/
|
||||
virtual bool StartPython() = 0;
|
||||
|
||||
// Engine
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user