Change to optionally show all python error strings

Signed-off-by: AMZN-Phil <pconroy@amazon.com>
This commit is contained in:
AMZN-Phil
2021-11-16 17:40:12 -08:00
parent 808c783109
commit ba5102b37d
8 changed files with 69 additions and 31 deletions
@@ -73,13 +73,25 @@ namespace O3DE::ProjectManager
emit GemDownloadProgress(m_gemNames.front(), bytesDownloaded, totalBytes);
}
void DownloadController::HandleResults(const QString& result)
void DownloadController::HandleResults(const QString& result, const QString& detailedError)
{
bool succeeded = true;
if (!result.isEmpty())
{
QMessageBox::critical(nullptr, tr("Gem download"), result);
if (!detailedError.isEmpty())
{
QMessageBox gemDownloadError;
gemDownloadError.setIcon(QMessageBox::Critical);
gemDownloadError.setWindowTitle(tr("Gem download"));
gemDownloadError.setText(result);
gemDownloadError.setDetailedText(detailedError);
gemDownloadError.exec();
}
else
{
QMessageBox::critical(nullptr, tr("Gem download"), result);
}
succeeded = false;
}
@@ -54,7 +54,7 @@ namespace O3DE::ProjectManager
}
public slots:
void UpdateUIProgress(int bytesDownloaded, int totalBytes);
void HandleResults(const QString& result);
void HandleResults(const QString& result, const QString& detailedError);
signals:
void StartGemDownload(const QString& gemName);
@@ -24,16 +24,16 @@ namespace O3DE::ProjectManager
{
emit UpdateProgress(bytesDownloaded, totalBytes);
};
AZ::Outcome<void, AZStd::string> gemInfoResult =
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> gemInfoResult =
PythonBindingsInterface::Get()->DownloadGem(m_gemName, gemDownloadProgress, /*force*/true);
if (gemInfoResult.IsSuccess())
{
emit Done("");
emit Done("", "");
}
else
{
emit Done(gemInfoResult.GetError().c_str());
emit Done(gemInfoResult.GetError().first.c_str(), gemInfoResult.GetError().second.c_str());
}
}
@@ -32,7 +32,7 @@ namespace O3DE::ProjectManager
signals:
void UpdateProgress(int bytesDownloaded, int totalBytes);
void Done(QString result = "");
void Done(QString result = "", QString detailedResult = "");
private:
@@ -92,7 +92,8 @@ namespace O3DE::ProjectManager
return;
}
AZ::Outcome<void, AZStd::string> addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri);
AZ::Outcome < void,
AZStd::pair<AZStd::string, AZStd::string>> addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri);
if (addGemRepoResult.IsSuccess())
{
Reinit();
@@ -101,7 +102,20 @@ namespace O3DE::ProjectManager
else
{
QString failureMessage = tr("Failed to add gem repo: %1.").arg(repoUri);
QMessageBox::critical(this, failureMessage, addGemRepoResult.GetError().c_str());
if (!addGemRepoResult.GetError().second.empty())
{
QMessageBox gemDownloadError;
gemDownloadError.setIcon(QMessageBox::Critical);
gemDownloadError.setWindowTitle(failureMessage);
gemDownloadError.setText(addGemRepoResult.GetError().first.c_str());
gemDownloadError.setDetailedText(addGemRepoResult.GetError().second.c_str());
gemDownloadError.exec();
}
else
{
QMessageBox::critical(this, failureMessage, addGemRepoResult.GetError().first.c_str());
}
AZ_Error("Project Manager", false, failureMessage.toUtf8());
}
}
@@ -23,6 +23,7 @@
#include <AzCore/IO/SystemFile.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/numeric.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <QDir>
@@ -61,7 +62,7 @@ namespace Platform
namespace RedirectOutput
{
using RedirectOutputFunc = AZStd::function<void(const char*)>;
AZStd::string lastPythonError;
AZStd::vector<AZStd::string> pythonErrorStrings;
struct RedirectOutput
{
@@ -211,16 +212,16 @@ namespace RedirectOutput
});
SetRedirection("stderr", g_redirect_stderr_saved, g_redirect_stderr, []([[maybe_unused]] const char* msg) {
if (lastPythonError.empty())
AZStd::string lastPythonError = msg;
constexpr const char* pythonErrorPrefix = "ERROR:root:";
constexpr size_t lengthOfErrorPrefix = AZStd::char_traits<char>::length(pythonErrorPrefix);
auto errorPrefix = lastPythonError.find(pythonErrorPrefix);
if (errorPrefix != AZStd::string::npos)
{
lastPythonError = msg;
const int lengthOfErrorPrefix = 11;
auto errorPrefix = lastPythonError.find("ERROR:root:");
if (errorPrefix != AZStd::string::npos)
{
lastPythonError.erase(errorPrefix, lengthOfErrorPrefix);
}
lastPythonError.erase(errorPrefix, lengthOfErrorPrefix);
}
pythonErrorStrings.push_back(lastPythonError);
AZ_TracePrintf("Python", msg);
});
@@ -387,6 +388,8 @@ namespace O3DE::ProjectManager
pybind11::gil_scoped_release release;
pybind11::gil_scoped_acquire acquire;
RedirectOutput::pythonErrorStrings.clear();
try
{
executionCallback();
@@ -1062,13 +1065,12 @@ namespace O3DE::ProjectManager
return result && refreshResult;
}
AZ::Outcome<void, AZStd::string> PythonBindings::AddGemRepo(const QString& repoUri)
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> PythonBindings::AddGemRepo(const QString& repoUri)
{
bool registrationResult = false;
bool result = ExecuteWithLock(
[&]
{
RedirectOutput::lastPythonError.clear();
auto pyUri = QString_To_Py_String(repoUri);
auto pythonRegistrationResult = m_register.attr("register")(
pybind11::none(), pybind11::none(), pybind11::none(), pybind11::none(), pybind11::none(), pybind11::none(), pyUri);
@@ -1079,7 +1081,7 @@ namespace O3DE::ProjectManager
if (!result || !registrationResult)
{
return AZ::Failure<AZStd::string>(AZStd::move(RedirectOutput::lastPythonError));
return AZ::Failure<AZStd::pair<AZStd::string, AZStd::string>>(GetSimpleDetailedErrorPair());
}
return AZ::Success();
@@ -1232,7 +1234,7 @@ namespace O3DE::ProjectManager
return AZ::Success(AZStd::move(gemInfos));
}
AZ::Outcome<void, AZStd::string> PythonBindings::DownloadGem(
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> PythonBindings::DownloadGem(
const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force)
{
// This process is currently limited to download a single gem at a time.
@@ -1242,7 +1244,6 @@ namespace O3DE::ProjectManager
auto result = ExecuteWithLockErrorHandling(
[&]
{
RedirectOutput::lastPythonError.clear();
auto downloadResult = m_download.attr("download_gem")(
QString_To_Py_String(gemName), // gem name
pybind11::none(), // destination path
@@ -1262,11 +1263,12 @@ namespace O3DE::ProjectManager
if (!result.IsSuccess())
{
return result;
AZStd::pair<AZStd::string, AZStd::string> pythonRunError(result.GetError(), result.GetError());
return AZ::Failure<AZStd::pair<AZStd::string, AZStd::string>>(AZStd::move(pythonRunError));
}
else if (!downloadSucceeded)
{
return AZ::Failure<AZStd::string>(AZStd::move(RedirectOutput::lastPythonError));
return AZ::Failure<AZStd::pair<AZStd::string, AZStd::string>>(GetSimpleDetailedErrorPair());
}
return AZ::Success();
@@ -1292,4 +1294,12 @@ namespace O3DE::ProjectManager
return result && updateAvaliableResult;
}
AZStd::pair<AZStd::string, AZStd::string> PythonBindings::GetSimpleDetailedErrorPair()
{
AZStd::string detailedString = RedirectOutput::pythonErrorStrings.size() == 1 ? "" : AZStd::accumulate(
RedirectOutput::pythonErrorStrings.begin(), RedirectOutput::pythonErrorStrings.end(), AZStd::string(""));
return AZStd::pair<AZStd::string, AZStd::string>(RedirectOutput::pythonErrorStrings.front(), detailedString);
}
}
@@ -62,11 +62,12 @@ namespace O3DE::ProjectManager
// Gem Repos
AZ::Outcome<void, AZStd::string> RefreshGemRepo(const QString& repoUri) override;
bool RefreshAllGemRepos() override;
AZ::Outcome<void, AZStd::string> AddGemRepo(const QString& repoUri) override;
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> AddGemRepo(const QString& repoUri) override;
bool RemoveGemRepo(const QString& repoUri) override;
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() override;
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetAllGemRepoGemsInfos() override;
AZ::Outcome<void, AZStd::string> DownloadGem(const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force = false) override;
AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> DownloadGem(
const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force = false) override;
void CancelDownload() override;
bool IsGemUpdateAvaliable(const QString& gemName, const QString& lastUpdated) override;
@@ -82,6 +83,7 @@ namespace O3DE::ProjectManager
AZ::Outcome<void, AZStd::string> GemRegistration(const QString& gemPath, const QString& projectPath, bool remove = false);
bool RegisterThisEngine();
bool StopPython();
AZStd::pair<AZStd::string, AZStd::string> GetSimpleDetailedErrorPair();
bool m_pythonStarted = false;
@@ -200,9 +200,9 @@ namespace O3DE::ProjectManager
/**
* Registers this gem repo with the current engine.
* @param repoUri the absolute filesystem path or url to the gem repo.
* @return an outcome with a string error message on failure.
* @return an outcome with a pair of string error and detailed messages on failure.
*/
virtual AZ::Outcome<void, AZStd::string> AddGemRepo(const QString& repoUri) = 0;
virtual AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> AddGemRepo(const QString& repoUri) = 0;
/**
* Unregisters this gem repo with the current engine.
@@ -228,9 +228,9 @@ namespace O3DE::ProjectManager
* @param gemName the name of the Gem to download.
* @param gemProgressCallback a callback function that is called with an int percentage download value.
* @param force should we forcibly overwrite the old version of the gem.
* @return an outcome with a string error message on failure.
* @return an outcome with a pair of string error and detailed messages on failure.
*/
virtual AZ::Outcome<void, AZStd::string> DownloadGem(
virtual AZ::Outcome<void, AZStd::pair<AZStd::string, AZStd::string>> DownloadGem(
const QString& gemName, std::function<void(int, int)> gemProgressCallback, bool force = false) = 0;
/**