diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index cbe36400cf..47cc37a836 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -106,6 +106,20 @@ namespace O3DE::ProjectManager m_gemModel->AddGem(gemInfo); } + AZ::Outcome, AZStd::string> allRepoGemInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoGemsInfos(); + if (allRepoGemInfosResult.IsSuccess()) + { + const QVector allRepoGemInfos = allRepoGemInfosResult.GetValue(); + for (const GemInfo& gemInfo : allRepoGemInfos) + { + m_gemModel->AddGem(gemInfo); + } + } + else + { + QMessageBox::critical(nullptr, tr("Operation failed"), QString("Cannot retrieve gems from repos.

Error:
%1").arg(allRepoGemInfosResult.GetError().c_str())); + } + m_gemModel->UpdateGemDependencies(); // Gather enabled gems for the given project. @@ -131,12 +145,12 @@ namespace O3DE::ProjectManager } else { - QMessageBox::critical(nullptr, tr("Operation failed"), QString("Cannot retrieve enabled gems for project %1.\n\nError:\n%2").arg(projectPath, enabledGemNamesResult.GetError().c_str())); + QMessageBox::critical(nullptr, tr("Operation failed"), QString("Cannot retrieve enabled gems for project %1.

Error:
%2").arg(projectPath, enabledGemNamesResult.GetError().c_str())); } } else { - QMessageBox::critical(nullptr, tr("Operation failed"), QString("Cannot retrieve gems for %1.\n\nError:\n%2").arg(projectPath, allGemInfosResult.GetError().c_str())); + QMessageBox::critical(nullptr, tr("Operation failed"), QString("Cannot retrieve gems for %1.

Error:
%2").arg(projectPath, allGemInfosResult.GetError().c_str())); } } diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index bc8773b0c8..37671963b2 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -302,6 +302,7 @@ namespace O3DE::ProjectManager m_disableGemProject = pybind11::module::import("o3de.disable_gem"); m_editProjectProperties = pybind11::module::import("o3de.project_properties"); m_download = pybind11::module::import("o3de.download"); + m_repo = pybind11::module::import("o3de.repo"); m_pathlib = pybind11::module::import("pathlib"); // make sure the engine is registered @@ -645,13 +646,13 @@ namespace O3DE::ProjectManager } } - GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath) + GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath, bool fullPathGiven) { GemInfo gemInfo; gemInfo.m_path = Py_To_String(path); gemInfo.m_directoryLink = gemInfo.m_path; - auto data = m_manifest.attr("get_gem_json_data")(pybind11::none(), path, pyProjectPath); + auto data = m_manifest.attr("get_gem_json_data")(pybind11::none(), path, pyProjectPath, fullPathGiven); if (pybind11::isinstance(data)) { try @@ -685,6 +686,10 @@ namespace O3DE::ProjectManager { gemInfo.m_downloadStatus = GemInfo::DownloadStatus::Downloaded; } + if (fullPathGiven) + { + gemInfo.m_downloadStatus = GemInfo::DownloadStatus::NotDownloaded; + } if (data.contains("user_tags")) { @@ -1102,4 +1107,29 @@ namespace O3DE::ProjectManager return AZ::Success(); } + + AZ::Outcome, AZStd::string> PythonBindings::GetAllGemRepoGemsInfos() + { + QVector gemInfos; + AZ::Outcome result = ExecuteWithLockErrorHandling( + [&] + { + auto gemPaths = m_repo.attr("get_gem_json_paths_from_all_cached_repos")(); + + if (pybind11::isinstance(gemPaths)) + { + for (auto path : gemPaths) + { + gemInfos.push_back(GemInfoFromPath(path, pybind11::none(), true)); + } + } + }); + + if (!result.IsSuccess()) + { + return AZ::Failure(result.GetError()); + } + + return AZ::Success(AZStd::move(gemInfos)); + } } diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 638ce6b1d4..0bde3caec2 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -62,13 +62,14 @@ namespace O3DE::ProjectManager bool RemoveGemRepo(const QString& repoUri) override; AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override; AZ::Outcome DownloadGem(const QString& gemName, std::function gemProgressCallback) override; + AZ::Outcome, AZStd::string> GetAllGemRepoGemsInfos() override; private: AZ_DISABLE_COPY_MOVE(PythonBindings); AZ::Outcome ExecuteWithLockErrorHandling(AZStd::function executionCallback); bool ExecuteWithLock(AZStd::function executionCallback); - GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath); + GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath, bool fullPathGiven = false); GemRepoInfo GetGemRepoInfo(pybind11::handle repoUri); ProjectInfo ProjectInfoFromPath(pybind11::handle path); ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath); @@ -89,6 +90,7 @@ namespace O3DE::ProjectManager pybind11::handle m_disableGemProject; pybind11::handle m_editProjectProperties; pybind11::handle m_download; + pybind11::handle m_repo; pybind11::handle m_pathlib; }; } diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 19442540a4..b9c6bdda02 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -189,6 +189,12 @@ namespace O3DE::ProjectManager virtual AZ::Outcome, AZStd::string> GetAllGemRepoInfos() = 0; virtual AZ::Outcome DownloadGem(const QString& gemName, std::function gemProgressCallback) = 0; + + /** + * Gathers all gem infos for all gems registered from repos. + * @return A list of gem infos. + */ + virtual AZ::Outcome, AZStd::string> GetAllGemRepoGemsInfos() = 0; }; using PythonBindingsInterface = AZ::Interface; diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index fc778591c4..0caa0a0062 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -494,7 +494,7 @@ def get_project_json_data(project_name: str = None, def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None, - project_path: pathlib.Path = None) -> dict or None: + project_path: pathlib.Path = None, full_path_given: bool = False) -> dict or None: if not gem_name and not gem_path: logger.error('Must specify either a Gem name or Gem Path.') return None @@ -502,7 +502,10 @@ def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None if gem_name and not gem_path: gem_path = get_registered(gem_name=gem_name, project_path=project_path) - return get_json_data('gem', gem_path, validation.valid_o3de_gem_json) + if not full_path_given: + return get_json_data('gem', gem_path, validation.valid_o3de_gem_json) + else: + return get_json_data_file(gem_path, 'gem', validation.valid_o3de_gem_json) def get_template_json_data(template_name: str = None, template_path: str or pathlib.Path = None, diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py index 5c47c2bee8..100bc6ffaf 100644 --- a/scripts/o3de/o3de/repo.py +++ b/scripts/o3de/o3de/repo.py @@ -92,13 +92,13 @@ def process_add_o3de_repo(file_name: str or pathlib.Path, return 0 -def get_gem_json_paths_from_cached_repo(repo_uri: str) -> list: +def get_gem_json_paths_from_cached_repo(repo_uri: str) -> set: url = f'{repo_uri}/repo.json' repo_sha256 = hashlib.sha256(url.encode()) cache_folder = manifest.get_o3de_cache_folder() cache_filename = cache_folder / str(repo_sha256.hexdigest() + '.json') - gem_list = [] + gem_set = set() file_name = pathlib.Path(cache_filename).resolve() if not file_name.is_file(): @@ -125,10 +125,21 @@ def get_gem_json_paths_from_cached_repo(repo_uri: str) -> list: manifest_json_sha256 = hashlib.sha256(manifest_json_uri.encode()) cache_gem_json_filepath = cache_folder / str(manifest_json_sha256.hexdigest() + '.json') if cache_gem_json_filepath.is_file(): - logger.warn(f'Could not find cached gem json file for {o3de_object_uri} in repo {repo_uri}') - gem_list.append(cache_gem_json_filepath) + gem_set.add(cache_gem_json_filepath) + else: + logger.warn(f'Could not find cached gem json file {cache_gem_json_filepath} for {o3de_object_uri} in repo {repo_uri}') + + return gem_set + +def get_gem_json_paths_from_all_cached_repos() -> set: + json_data = manifest.load_o3de_manifest() + gem_list = set() + + for repo_uri in json_data['repos']: + gem_list.update(get_gem_json_paths_from_cached_repo(repo_uri)) return gem_list + def refresh_repos() -> int: json_data = manifest.load_o3de_manifest()