Repos can be refreshed through Project Manager individually or all at once

Signed-off-by: nggieber <nggieber@amazon.com>
monroegm-disable-blank-issue-2
nggieber 4 years ago
parent 74d74050f2
commit b4a85a2ed6

@ -108,7 +108,7 @@ namespace O3DE::ProjectManager
// Draw refresh button
painter->drawPixmap(
repoUpdatedDateRect.left() + repoUpdatedDateRect.width() + s_refreshIconSpacing,
repoUpdatedDateRect.left() + s_updatedMaxWidth + s_refreshIconSpacing,
contentRect.center().y() - s_refreshIconSize / 3, // Dividing size by 3 centers much better
m_refreshIcon);
@ -150,6 +150,11 @@ namespace O3DE::ProjectManager
emit RemoveRepo(modelIndex);
return true;
}
else if (keyEvent->key() == Qt::Key_R)
{
emit RefreshRepo(modelIndex);
return true;
}
}
if (event->type() == QEvent::MouseButtonPress)
@ -160,6 +165,7 @@ namespace O3DE::ProjectManager
CalcRects(option, fullRect, itemRect, contentRect);
const QRect buttonRect = CalcButtonRect(contentRect);
const QRect deleteButtonRect = CalcDeleteButtonRect(contentRect);
const QRect refreshButtonRect = CalcRefreshButtonRect(contentRect, buttonRect);
if (buttonRect.contains(mouseEvent->pos()))
{
@ -172,6 +178,11 @@ namespace O3DE::ProjectManager
emit RemoveRepo(modelIndex);
return true;
}
else if (refreshButtonRect.contains(mouseEvent->pos()))
{
emit RefreshRepo(modelIndex);
return true;
}
}
return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
@ -231,6 +242,13 @@ namespace O3DE::ProjectManager
return QRect(topLeft, QSize(s_iconSize, s_iconSize));
}
QRect GemRepoItemDelegate::CalcRefreshButtonRect(const QRect& contentRect, const QRect& buttonRect) const
{
const int topLeftX = buttonRect.left() + s_buttonWidth + s_buttonSpacing + s_nameMaxWidth + s_creatorMaxWidth + s_updatedMaxWidth + s_contentSpacing * 2 + s_refreshIconSpacing;
const QPoint topLeft = QPoint(topLeftX, contentRect.center().y() - s_refreshIconSize / 3);
return QRect(topLeft, QSize(s_refreshIconSize, s_refreshIconSize));
}
void GemRepoItemDelegate::DrawEditButtons(QPainter* painter, const QRect& contentRect) const
{
painter->drawPixmap(contentRect.right() - s_iconSize, contentRect.center().y() - s_iconSize / 2, m_deleteIcon);

@ -68,12 +68,14 @@ namespace O3DE::ProjectManager
signals:
void RemoveRepo(const QModelIndex& modelIndex);
void RefreshRepo(const QModelIndex& modelIndex);
protected:
void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
QRect CalcButtonRect(const QRect& contentRect) const;
QRect CalcDeleteButtonRect(const QRect& contentRect) const;
QRect CalcRefreshButtonRect(const QRect& contentRect, const QRect& buttonRect) const;
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
void DrawEditButtons(QPainter* painter, const QRect& contentRect) const;

@ -24,6 +24,7 @@ namespace O3DE::ProjectManager
GemRepoItemDelegate* itemDelegate = new GemRepoItemDelegate(model, this);
connect(itemDelegate, &GemRepoItemDelegate::RemoveRepo, this, &GemRepoListView::RemoveRepo);
connect(itemDelegate, &GemRepoItemDelegate::RefreshRepo, this, &GemRepoListView::RefreshRepo);
setItemDelegate(itemDelegate);
}
} // namespace O3DE::ProjectManager

@ -28,5 +28,6 @@ namespace O3DE::ProjectManager
signals:
void RemoveRepo(const QModelIndex& modelIndex);
void RefreshRepo(const QModelIndex& modelIndex);
};
} // namespace O3DE::ProjectManager

@ -126,6 +126,36 @@ namespace O3DE::ProjectManager
}
}
void GemRepoScreen::HandleRefreshAllButton()
{
bool refreshResult = PythonBindingsInterface::Get()->RefreshAllGemRepos();
Reinit();
if (!refreshResult)
{
QMessageBox::critical(
this, tr("Operation failed"), QString("Some repos failed to refresh."));
}
}
void GemRepoScreen::HandleRefreshRepoButton(const QModelIndex& modelIndex)
{
const QString repoUri = m_gemRepoModel->GetRepoUri(modelIndex);
AZ::Outcome<void, AZStd::string> refreshResult = PythonBindingsInterface::Get()->RefreshGemRepo(repoUri);
if (refreshResult.IsSuccess())
{
Reinit();
}
else
{
QMessageBox::critical(
this, tr("Operation failed"),
QString("Failed to refresh gem repo %1<br>Error:<br>%2")
.arg(m_gemRepoModel->GetName(modelIndex), refreshResult.GetError().c_str()));
}
}
void GemRepoScreen::FillModel()
{
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos();
@ -237,6 +267,8 @@ namespace O3DE::ProjectManager
m_AllUpdateButton->setObjectName("gemRepoHeaderRefreshButton");
topMiddleHLayout->addWidget(m_AllUpdateButton);
connect(m_AllUpdateButton, &QPushButton::clicked, this, &GemRepoScreen::HandleRefreshAllButton);
topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
QPushButton* addRepoButton = new QPushButton(tr("Add Repository"), this);
@ -280,6 +312,7 @@ namespace O3DE::ProjectManager
middleVLayout->addWidget(m_gemRepoListView);
connect(m_gemRepoListView, &GemRepoListView::RemoveRepo, this, &GemRepoScreen::HandleRemoveRepoButton);
connect(m_gemRepoListView, &GemRepoListView::RefreshRepo, this, &GemRepoScreen::HandleRefreshRepoButton);
hLayout->addLayout(middleVLayout);

@ -40,6 +40,8 @@ namespace O3DE::ProjectManager
public slots:
void HandleAddRepoButton();
void HandleRemoveRepoButton(const QModelIndex& modelIndex);
void HandleRefreshAllButton();
void HandleRefreshRepoButton(const QModelIndex& modelIndex);
private:
void FillModel();

@ -301,6 +301,7 @@ namespace O3DE::ProjectManager
m_enableGemProject = pybind11::module::import("o3de.enable_gem");
m_disableGemProject = pybind11::module::import("o3de.disable_gem");
m_editProjectProperties = pybind11::module::import("o3de.project_properties");
m_repo = pybind11::module::import("o3de.repo");
m_pathlib = pybind11::module::import("pathlib");
// make sure the engine is registered
@ -939,6 +940,46 @@ namespace O3DE::ProjectManager
}
}
AZ::Outcome<void, AZStd::string> PythonBindings::RefreshGemRepo(const QString& repoUri)
{
bool refreshResult = false;
AZ::Outcome<void, AZStd::string> result = ExecuteWithLockErrorHandling(
[&]
{
auto pyUri = QString_To_Py_String(repoUri);
auto pythonRefreshResult = m_repo.attr("refresh_repo")(pyUri);
// Returns an exit code so boolify it then invert result
refreshResult = !pythonRefreshResult.cast<bool>();
});
if (!result.IsSuccess())
{
return result;
}
else if (!refreshResult)
{
return AZ::Failure<AZStd::string>("Failed to refresh repo.");
}
return AZ::Success();
}
bool PythonBindings::RefreshAllGemRepos()
{
bool refreshResult = false;
bool result = ExecuteWithLock(
[&]
{
auto pythonRefreshResult = m_repo.attr("refresh_repos")();
// Returns an exit code so boolify it then invert result
refreshResult = !pythonRefreshResult.cast<bool>();
});
return result && refreshResult;
}
bool PythonBindings::AddGemRepo(const QString& repoUri)
{
bool registrationResult = false;

@ -58,6 +58,8 @@ namespace O3DE::ProjectManager
AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates(const QString& projectPath = {}) override;
// Gem Repos
AZ::Outcome<void, AZStd::string> RefreshGemRepo(const QString& repoUri) override;
bool RefreshAllGemRepos() override;
bool AddGemRepo(const QString& repoUri) override;
bool RemoveGemRepo(const QString& repoUri) override;
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() override;
@ -87,6 +89,7 @@ namespace O3DE::ProjectManager
pybind11::handle m_enableGemProject;
pybind11::handle m_disableGemProject;
pybind11::handle m_editProjectProperties;
pybind11::handle m_repo;
pybind11::handle m_pathlib;
};
}

@ -168,6 +168,19 @@ namespace O3DE::ProjectManager
// Gem Repos
/**
* Refresh gem repo in the current engine.
* @param repoUri the absolute filesystem path or url to the gem repo.
* @return An outcome with the success flag as well as an error message in case of a failure.
*/
virtual AZ::Outcome<void, AZStd::string> RefreshGemRepo(const QString& repoUri) = 0;
/**
* Refresh all gem repos in the current engine.
* @return true on success, false on failure.
*/
virtual bool RefreshAllGemRepos() = 0;
/**
* Registers this gem repo with the current engine.
* @param repoUri the absolute filesystem path or url to the gem repo.

@ -13,7 +13,7 @@ import shutil
import urllib.parse
import urllib.request
import hashlib
from datetime import datetime
from o3de import manifest, utils, validation
logger = logging.getLogger()
@ -27,6 +27,7 @@ def process_add_o3de_repo(file_name: str or pathlib.Path,
return 1
cache_folder = manifest.get_o3de_cache_folder()
repo_data = {}
with file_name.open('r') as f:
try:
repo_data = json.load(f)
@ -34,6 +35,17 @@ def process_add_o3de_repo(file_name: str or pathlib.Path,
logger.error(f'{file_name} failed to load: {str(e)}')
return 1
with file_name.open('w') as f:
try:
time_now = datetime.now()
# Convert to lower case because AM/PM is capitalized
time_str = time_now.strftime('%d/%m/%Y %I:%M%p').lower()
repo_data.update({'last_updated': time_str})
f.write(json.dumps(repo_data, indent=4) + '\n')
except Exception as e:
logger.error(f'{file_name} failed to save: {str(e)}')
return 1
# A repo may not contain all types of object.
manifest_download_list = []
try:
@ -130,6 +142,29 @@ def get_gem_json_paths_from_cached_repo(repo_uri: str) -> list:
return gem_list
def refresh_repo(repo_uri: str,
cache_folder: str = None,
repo_set: set = None) -> int:
if not cache_folder:
cache_folder = manifest.get_o3de_cache_folder()
if not repo_set:
repo_set = set()
parsed_uri = urllib.parse.urlparse(f'{repo_uri}/repo.json')
repo_sha256 = hashlib.sha256(parsed_uri.geturl().encode())
cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json')
download_file_result = utils.download_file(parsed_uri, cache_file)
if download_file_result != 0:
return download_file_result
if not validation.valid_o3de_repo_json(cache_file):
logger.error(f'Repo json {repo_uri} is not valid.')
cache_file.unlink()
return 1
return process_add_o3de_repo(cache_file, repo_set)
def refresh_repos() -> int:
json_data = manifest.load_o3de_manifest()
@ -147,20 +182,7 @@ def refresh_repos() -> int:
if repo_uri not in repo_set:
repo_set.add(repo_uri)
parsed_uri = urllib.parse.urlparse(f'{repo_uri}/repo.json')
repo_sha256 = hashlib.sha256(parsed_uri.geturl().encode())
cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json')
if not cache_file.is_file():
download_file_result = utils.download_file(parsed_uri, cache_file)
if download_file_result != 0:
return download_file_result
if not validation.valid_o3de_repo_json(cache_file):
logger.error(f'Repo json {repo_uri} is not valid.')
cache_file.unlink()
return 1
last_failure = process_add_o3de_repo(cache_file, repo_set)
last_failure = refresh_repo(repo_uri, cache_folder, repo_set)
if last_failure:
result = last_failure

Loading…
Cancel
Save