Improved error handling for GuiThemeDownloader

This commit is contained in:
Leon Styhre 2023-04-01 19:27:54 +02:00
parent 56831f1785
commit 8a54b0d6fe
3 changed files with 55 additions and 44 deletions

View file

@ -1797,6 +1797,7 @@ void GuiMenu::openThemeDownloader(GuiSettings* settings)
LOG(LogDebug) << "GuiMenu::openThemeDownloader(): Theme sets were updated, reloading menu"; LOG(LogDebug) << "GuiMenu::openThemeDownloader(): Theme sets were updated, reloading menu";
delete settings; delete settings;
openUIOptions(); openUIOptions();
mWindow->invalidateCachedBackground();
}; };
mWindow->pushGui(new GuiThemeDownloader(updateFunc)); mWindow->pushGui(new GuiThemeDownloader(updateFunc));

View file

@ -40,18 +40,18 @@ GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
// Set up main grid. // Set up main grid.
mTitle = std::make_shared<TextComponent>("THEME DOWNLOADER", Font::get(FONT_SIZE_LARGE), mTitle = std::make_shared<TextComponent>("THEME DOWNLOADER", Font::get(FONT_SIZE_LARGE),
0x555555FF, ALIGN_CENTER); 0x555555FF, ALIGN_CENTER);
mGrid.setEntry(mTitle, glm::ivec2 {0, 0}, false, true, glm::ivec2 {2, 2}); mGrid.setEntry(mTitle, glm::ivec2 {0, 0}, false, true, glm::ivec2 {2, 2},
GridFlags::BORDER_BOTTOM);
// We need a center grid embedded within the main grid in order for navigation and helpsystem // We need a center grid embedded within the main grid in order for navigation and helpsystem
// entries to work and display correctly. // entries to work and display correctly.
mCenterGrid = std::make_shared<ComponentGrid>(glm::ivec2 {8, 5}); mCenterGrid = std::make_shared<ComponentGrid>(glm::ivec2 {8, 5});
mCenterGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {0, 0}, false, false, mCenterGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {0, 0}, false, false,
glm::ivec2 {1, 5}, GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM); glm::ivec2 {1, 5});
mVariantsLabel = mVariantsLabel =
std::make_shared<TextComponent>("", Font::get(fontSizeSmall), 0x555555FF, ALIGN_LEFT); std::make_shared<TextComponent>("", Font::get(fontSizeSmall), 0x555555FF, ALIGN_LEFT);
mCenterGrid->setEntry(mVariantsLabel, glm::ivec2 {1, 0}, false, true, glm::ivec2 {1, 1}, mCenterGrid->setEntry(mVariantsLabel, glm::ivec2 {1, 0}, false, true, glm::ivec2 {1, 1});
GridFlags::BORDER_TOP);
mColorSchemesLabel = mColorSchemesLabel =
std::make_shared<TextComponent>("", Font::get(fontSizeSmall), 0x555555FF, ALIGN_LEFT); std::make_shared<TextComponent>("", Font::get(fontSizeSmall), 0x555555FF, ALIGN_LEFT);
@ -59,20 +59,18 @@ GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
mAspectRatiosLabel = mAspectRatiosLabel =
std::make_shared<TextComponent>("", Font::get(fontSizeSmall), 0x555555FF, ALIGN_LEFT); std::make_shared<TextComponent>("", Font::get(fontSizeSmall), 0x555555FF, ALIGN_LEFT);
mCenterGrid->setEntry(mAspectRatiosLabel, glm::ivec2 {3, 0}, false, true, glm::ivec2 {1, 1}, mCenterGrid->setEntry(mAspectRatiosLabel, glm::ivec2 {3, 0}, false, true, glm::ivec2 {1, 1});
GridFlags::BORDER_TOP);
mFutureUseLabel = mFutureUseLabel =
std::make_shared<TextComponent>("", Font::get(fontSizeSmall), 0x555555FF, ALIGN_LEFT); std::make_shared<TextComponent>("", Font::get(fontSizeSmall), 0x555555FF, ALIGN_LEFT);
mCenterGrid->setEntry(mFutureUseLabel, glm::ivec2 {3, 1}, false, true, glm::ivec2 {1, 1}); mCenterGrid->setEntry(mFutureUseLabel, glm::ivec2 {3, 1}, false, true, glm::ivec2 {1, 1});
mCenterGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {5, 0}, false, false, mCenterGrid->setEntry(std::make_shared<GuiComponent>(), glm::ivec2 {5, 0}, false, false,
glm::ivec2 {1, 5}, GridFlags::BORDER_TOP | GridFlags::BORDER_BOTTOM); glm::ivec2 {1, 5});
mVariantCount = std::make_shared<TextComponent>("", Font::get(fontSizeSmall, FONT_PATH_LIGHT), mVariantCount = std::make_shared<TextComponent>("", Font::get(fontSizeSmall, FONT_PATH_LIGHT),
0x555555FF, ALIGN_LEFT); 0x555555FF, ALIGN_LEFT);
mCenterGrid->setEntry(mVariantCount, glm::ivec2 {2, 0}, false, true, glm::ivec2 {1, 1}, mCenterGrid->setEntry(mVariantCount, glm::ivec2 {2, 0}, false, true, glm::ivec2 {1, 1});
GridFlags::BORDER_TOP);
mColorSchemesCount = std::make_shared<TextComponent>( mColorSchemesCount = std::make_shared<TextComponent>(
"", Font::get(fontSizeSmall, FONT_PATH_LIGHT), 0x555555FF, ALIGN_LEFT); "", Font::get(fontSizeSmall, FONT_PATH_LIGHT), 0x555555FF, ALIGN_LEFT);
@ -80,8 +78,7 @@ GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
mAspectRatiosCount = std::make_shared<TextComponent>( mAspectRatiosCount = std::make_shared<TextComponent>(
"", Font::get(fontSizeSmall, FONT_PATH_LIGHT), 0x555555FF, ALIGN_LEFT); "", Font::get(fontSizeSmall, FONT_PATH_LIGHT), 0x555555FF, ALIGN_LEFT);
mCenterGrid->setEntry(mAspectRatiosCount, glm::ivec2 {4, 0}, false, true, glm::ivec2 {1, 1}, mCenterGrid->setEntry(mAspectRatiosCount, glm::ivec2 {4, 0}, false, true, glm::ivec2 {1, 1});
GridFlags::BORDER_TOP);
mFutureUseCount = std::make_shared<TextComponent>("", Font::get(fontSizeSmall, FONT_PATH_LIGHT), mFutureUseCount = std::make_shared<TextComponent>("", Font::get(fontSizeSmall, FONT_PATH_LIGHT),
0x555555FF, ALIGN_LEFT); 0x555555FF, ALIGN_LEFT);
@ -101,13 +98,11 @@ GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
mAuthor = std::make_shared<TextComponent>("", Font::get(FONT_SIZE_MINI * 0.9f, FONT_PATH_LIGHT), mAuthor = std::make_shared<TextComponent>("", Font::get(FONT_SIZE_MINI * 0.9f, FONT_PATH_LIGHT),
0x555555FF, ALIGN_LEFT); 0x555555FF, ALIGN_LEFT);
mCenterGrid->setEntry(mAuthor, glm::ivec2 {1, 4}, false, true, glm::ivec2 {4, 1}, mCenterGrid->setEntry(mAuthor, glm::ivec2 {1, 4}, false, true, glm::ivec2 {4, 1});
GridFlags::BORDER_BOTTOM);
mList = std::make_shared<ComponentList>(); mList = std::make_shared<ComponentList>();
mCenterGrid->setEntry(mList, glm::ivec2 {6, 0}, true, true, glm::ivec2 {2, 5}, mCenterGrid->setEntry(mList, glm::ivec2 {6, 0}, true, true, glm::ivec2 {2, 5},
GridFlags::BORDER_TOP | GridFlags::BORDER_LEFT | GridFlags::BORDER_LEFT);
GridFlags::BORDER_BOTTOM);
mGrid.setEntry(mCenterGrid, glm::ivec2 {0, 2}, true, false, glm::ivec2 {2, 1}); mGrid.setEntry(mCenterGrid, glm::ivec2 {0, 2}, true, false, glm::ivec2 {2, 1});
@ -129,7 +124,8 @@ GuiThemeDownloader::GuiThemeDownloader(std::function<void()> updateCallback)
std::vector<std::shared_ptr<ButtonComponent>> buttons; std::vector<std::shared_ptr<ButtonComponent>> buttons;
buttons.push_back(std::make_shared<ButtonComponent>("CLOSE", "CLOSE", [&] { delete this; })); buttons.push_back(std::make_shared<ButtonComponent>("CLOSE", "CLOSE", [&] { delete this; }));
mButtons = makeButtonGrid(buttons); mButtons = makeButtonGrid(buttons);
mGrid.setEntry(mButtons, glm::ivec2 {0, 3}, true, false, glm::ivec2 {2, 1}); mGrid.setEntry(mButtons, glm::ivec2 {0, 3}, true, false, glm::ivec2 {2, 1},
GridFlags::BORDER_TOP);
// Limit the width of the GUI on ultrawide monitors. The 1.778 aspect ratio value is // Limit the width of the GUI on ultrawide monitors. The 1.778 aspect ratio value is
// the 16:9 reference. // the 16:9 reference.
@ -184,11 +180,11 @@ GuiThemeDownloader::~GuiThemeDownloader()
if (mUpdateCallback) if (mUpdateCallback)
mUpdateCallback(); mUpdateCallback();
} }
mWindow->stopInfoPopup();
} }
bool GuiThemeDownloader::fetchRepository(const std::string& repositoryName, bool GuiThemeDownloader::fetchRepository(const std::string& repositoryName, bool allowReset)
const std::string& url,
bool allowReset)
{ {
int errorCode {0}; int errorCode {0};
const std::string path {mThemeDirectory + repositoryName}; const std::string path {mThemeDirectory + repositoryName};
@ -222,13 +218,14 @@ bool GuiThemeDownloader::fetchRepository(const std::string& repositoryName,
errorCode = git_remote_fetch(gitRemote, nullptr, &fetchOptions, nullptr); errorCode = git_remote_fetch(gitRemote, nullptr, &fetchOptions, nullptr);
if (errorCode != 0) if (errorCode != 0)
throw std::runtime_error("Couldn't pull latest commits, "); throw std::runtime_error("Couldn't fetch latest commits for \"" + repositoryName +
"\", ");
git_annotated_commit* annotated {nullptr}; git_annotated_commit* annotated {nullptr};
git_object* object {nullptr}; git_object* object {nullptr};
if (git_repository_head_detached(repository)) { if (git_repository_head_detached(repository)) {
LOG(LogWarning) << "Repository \"" << repositoryName LOG(LogWarning) << "GuiThemeDownloader: Repository \"" << repositoryName
<< "\" has HEAD detached, resetting it"; << "\" has HEAD detached, resetting it";
git_buf buffer {}; git_buf buffer {};
errorCode = git_remote_default_branch(&buffer, gitRemote); errorCode = git_remote_default_branch(&buffer, gitRemote);
@ -267,13 +264,13 @@ bool GuiThemeDownloader::fetchRepository(const std::string& repositoryName,
if (errorCode != 0) { if (errorCode != 0) {
git_object_free(object); git_object_free(object);
git_annotated_commit_free(annotated); git_annotated_commit_free(annotated);
throw std::runtime_error("Couldn't run Git merge analysis, "); throw std::runtime_error("GuiThemeDownloader: Couldn't run Git merge analysis, ");
} }
if (!(mergeAnalysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) && if (!(mergeAnalysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) &&
!(mergeAnalysis & GIT_MERGE_ANALYSIS_FASTFORWARD)) { !(mergeAnalysis & GIT_MERGE_ANALYSIS_FASTFORWARD)) {
if (allowReset) { if (allowReset) {
LOG(LogWarning) << "Repository \"" << repositoryName LOG(LogWarning) << "GuiThemeDownloader: Repository \"" << repositoryName
<< "\" has diverged from origin, performing hard reset"; << "\" has diverged from origin, performing hard reset";
git_object* objectHead {nullptr}; git_object* objectHead {nullptr};
errorCode = git_revparse_single(&objectHead, repository, "HEAD"); errorCode = git_revparse_single(&objectHead, repository, "HEAD");
@ -283,7 +280,7 @@ bool GuiThemeDownloader::fetchRepository(const std::string& repositoryName,
mHasThemeUpdates = true; mHasThemeUpdates = true;
} }
else { else {
LOG(LogWarning) << "Repository \"" << repositoryName LOG(LogWarning) << "GuiThemeDownloader: Repository \"" << repositoryName
<< "\" has diverged from origin, can't fast-forward"; << "\" has diverged from origin, can't fast-forward";
git_annotated_commit_free(annotated); git_annotated_commit_free(annotated);
git_object_free(object); git_object_free(object);
@ -294,7 +291,7 @@ bool GuiThemeDownloader::fetchRepository(const std::string& repositoryName,
} }
if (allowReset && checkLocalChanges(repository)) { if (allowReset && checkLocalChanges(repository)) {
LOG(LogInfo) << "Repository \"" << repositoryName LOG(LogWarning) << "GuiThemeDownloader: Repository \"" << repositoryName
<< "\" contains local changes, performing hard reset"; << "\" contains local changes, performing hard reset";
resetRepository(repository); resetRepository(repository);
if (repositoryName != "themes-list") if (repositoryName != "themes-list")
@ -314,7 +311,8 @@ bool GuiThemeDownloader::fetchRepository(const std::string& repositoryName,
return false; return false;
} }
LOG(LogInfo) << "Performing Git fast-forward of repository \"" << repositoryName << "\""; LOG(LogInfo) << "GuiThemeDownloader: Performing fast-forward of repository \""
<< repositoryName << "\"";
git_reference* oldTargetRef {nullptr}; git_reference* oldTargetRef {nullptr};
git_repository_head(&oldTargetRef, repository); git_repository_head(&oldTargetRef, repository);
@ -353,6 +351,7 @@ bool GuiThemeDownloader::fetchRepository(const std::string& repositoryName,
catch (std::runtime_error& runtimeError) { catch (std::runtime_error& runtimeError) {
const git_error* gitError {git_error_last()}; const git_error* gitError {git_error_last()};
LOG(LogError) << "GuiThemeDownloader: " << runtimeError.what() << gitError->message; LOG(LogError) << "GuiThemeDownloader: " << runtimeError.what() << gitError->message;
mRepositoryError = RepositoryError::FETCH_ERROR;
mMessage = gitError->message; mMessage = gitError->message;
git_error_clear(); git_error_clear();
if (gitRemote != nullptr) if (gitRemote != nullptr)
@ -661,7 +660,7 @@ void GuiThemeDownloader::populateGUI()
std::promise<bool>().swap(mPromise); std::promise<bool>().swap(mPromise);
mFuture = mPromise.get_future(); mFuture = mPromise.get_future();
mFetchThread = std::thread(&GuiThemeDownloader::fetchRepository, this, mFetchThread = std::thread(&GuiThemeDownloader::fetchRepository, this,
theme.reponame, theme.url, true); theme.reponame, true);
mStatusType = StatusType::STATUS_UPDATING; mStatusType = StatusType::STATUS_UPDATING;
mStatusText = "UPDATING THEME"; mStatusText = "UPDATING THEME";
}, },
@ -672,8 +671,8 @@ void GuiThemeDownloader::populateGUI()
} }
else if (theme.isCloned) { else if (theme.isCloned) {
mFuture = mPromise.get_future(); mFuture = mPromise.get_future();
mFetchThread = std::thread(&GuiThemeDownloader::fetchRepository, this, mFetchThread =
theme.reponame, theme.url, false); std::thread(&GuiThemeDownloader::fetchRepository, this, theme.reponame, false);
mStatusType = StatusType::STATUS_UPDATING; mStatusType = StatusType::STATUS_UPDATING;
mStatusText = "UPDATING THEME"; mStatusText = "UPDATING THEME";
} }
@ -823,17 +822,24 @@ void GuiThemeDownloader::update(int deltaTime)
mFetching = false; mFetching = false;
if (mRepositoryError != RepositoryError::NO_REPO_ERROR) { if (mRepositoryError != RepositoryError::NO_REPO_ERROR) {
std::string errorMessage {"ERROR: "}; std::string errorMessage {"ERROR: "};
if (mThemeSets.empty()) {
errorMessage.append("COULDN'T DOWNLOAD THEMES LIST, ");
mGrid.removeEntry(mCenterGrid);
mGrid.setCursorTo(mButtons);
}
errorMessage.append(Utils::String::toUpper(mMessage)); errorMessage.append(Utils::String::toUpper(mMessage));
mWindow->queueInfoPopup(errorMessage, 6000); mWindow->pushGui(new GuiMsgBox(
LOG(LogError) << "Error: " << mMessage; getHelpStyle(), errorMessage, "OK", [] { return; }, "", nullptr, "",
nullptr, true));
mMessage = ""; mMessage = "";
getHelpPrompts();
} }
if (mThemeSets.empty() && mLatestThemesList) { if (mThemeSets.empty() && mLatestThemesList) {
parseThemesList(); parseThemesList();
makeInventory(); makeInventory();
populateGUI(); populateGUI();
} }
else { else if (!mThemeSets.empty()) {
makeInventory(); makeInventory();
updateGUI(); updateGUI();
} }
@ -870,7 +876,7 @@ void GuiThemeDownloader::update(int deltaTime)
mBusyAnim.update(deltaTime); mBusyAnim.update(deltaTime);
} }
if (mMessage != "") { if (mRepositoryError == RepositoryError::NO_REPO_ERROR && mMessage != "") {
mWindow->queueInfoPopup(mMessage, 6000); mWindow->queueInfoPopup(mMessage, 6000);
mMessage = ""; mMessage = "";
} }
@ -994,10 +1000,12 @@ bool GuiThemeDownloader::input(InputConfig* config, Input input)
std::vector<HelpPrompt> GuiThemeDownloader::getHelpPrompts() std::vector<HelpPrompt> GuiThemeDownloader::getHelpPrompts()
{ {
std::vector<HelpPrompt> prompts {mGrid.getHelpPrompts()}; std::vector<HelpPrompt> prompts;
prompts.push_back(HelpPrompt("b", "close"));
if (mList->size() > 0) { if (mList->size() > 0) {
prompts = mGrid.getHelpPrompts();
prompts.push_back(HelpPrompt("b", "close"));
if (mGrid.getSelectedComponent() == mCenterGrid) if (mGrid.getSelectedComponent() == mCenterGrid)
prompts.push_back(HelpPrompt("x", "view screenshots")); prompts.push_back(HelpPrompt("x", "view screenshots"));
@ -1007,7 +1015,7 @@ std::vector<HelpPrompt> GuiThemeDownloader::getHelpPrompts()
prompts.push_back(HelpPrompt("a", "download")); prompts.push_back(HelpPrompt("a", "download"));
} }
else { else {
prompts.clear(); prompts.push_back(HelpPrompt("b", "close"));
} }
return prompts; return prompts;
@ -1041,7 +1049,7 @@ bool GuiThemeDownloader::fetchThemesList()
git_repository_free(repository); git_repository_free(repository);
mFetchThread = mFetchThread =
std::thread(&GuiThemeDownloader::fetchRepository, this, repositoryName, url, false); std::thread(&GuiThemeDownloader::fetchRepository, this, repositoryName, false);
mStatusType = StatusType::STATUS_UPDATING; mStatusType = StatusType::STATUS_UPDATING;
mStatusText = "UPDATING THEMES LIST"; mStatusText = "UPDATING THEMES LIST";
} }
@ -1135,8 +1143,10 @@ bool GuiThemeDownloader::cloneRepository(const std::string& repositoryName, cons
if (errorCode != 0) { if (errorCode != 0) {
const git_error* gitError {git_error_last()}; const git_error* gitError {git_error_last()};
LOG(LogWarning) << "GuiThemeDownloader: Git returned error code " << errorCode LOG(LogError) << "GuiThemeDownloader: Couldn't clone repository \"" << repositoryName
<< ", error message: \"" << gitError->message << "\""; << "\", error code: " << errorCode << ", error message: \""
<< gitError->message << "\"";
mRepositoryError = RepositoryError::CLONE_ERROR;
mMessage = gitError->message; mMessage = gitError->message;
git_error_clear(); git_error_clear();
mPromise.set_value(true); mPromise.set_value(true);

View file

@ -84,9 +84,7 @@ private:
}; };
bool fetchThemesList(); bool fetchThemesList();
bool fetchRepository(const std::string& repositoryName, bool fetchRepository(const std::string& repositoryName, bool allowReset = false);
const std::string& url,
bool allowReset = false);
bool cloneRepository(const std::string& repositoryName, const std::string& url); bool cloneRepository(const std::string& repositoryName, const std::string& url);
bool checkLocalChanges(git_repository* repository, bool hasFetched = false); bool checkLocalChanges(git_repository* repository, bool hasFetched = false);
@ -125,7 +123,9 @@ private:
NO_REPO_ERROR, NO_REPO_ERROR,
NOT_A_REPOSITORY, NOT_A_REPOSITORY,
INVALID_ORIGIN, INVALID_ORIGIN,
HAS_DIVERGED HAS_DIVERGED,
CLONE_ERROR,
FETCH_ERROR
}; };
RepositoryError mRepositoryError; RepositoryError mRepositoryError;