diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index b3ecd96e43..da30758308 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -115,6 +115,8 @@ namespace O3DE::ProjectManager QFrame* ProjectsScreen::CreateProjectsContent(QString buildProjectPath, ProjectButton** projectButton) { + RemoveInvalidProjects(); + QFrame* frame = new QFrame(this); frame->setObjectName("projectsContent"); { @@ -495,6 +497,11 @@ namespace O3DE::ProjectManager return displayFirstTimeContent; } + bool ProjectsScreen::RemoveInvalidProjects() + { + return PythonBindingsInterface::Get()->RemoveInvalidProjects(); + } + bool ProjectsScreen::StartProjectBuild(const ProjectInfo& projectInfo) { if (ProjectUtils::IsVS2019Installed()) diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.h b/Code/Tools/ProjectManager/Source/ProjectsScreen.h index 1ca8448134..787db16c59 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.h +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.h @@ -62,6 +62,7 @@ namespace O3DE::ProjectManager ProjectButton* CreateProjectButton(ProjectInfo& project, QLayout* flowLayout, bool processing = false); void ResetProjectsContent(); bool ShouldDisplayFirstTimeContent(); + bool RemoveInvalidProjects(); bool StartProjectBuild(const ProjectInfo& projectInfo); QList::iterator RequiresBuildProjectIterator(const QString& projectPath); diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index f8c45bedeb..00b6940255 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -755,6 +755,21 @@ namespace O3DE::ProjectManager }); } + bool PythonBindings::RemoveInvalidProjects() + { + bool removalResult = false; + bool result = ExecuteWithLock( + [&] + { + auto pythonRemovalResult = m_register.attr("remove_invalid_o3de_projects")(); + + // Returns an exit code so boolify it then invert result + removalResult = !pythonRemovalResult.cast(); + }); + + return result && removalResult; + } + AZ::Outcome PythonBindings::UpdateProject(const ProjectInfo& projectInfo) { bool updateProjectSucceeded = false; diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 1d98505457..98ca8e90f0 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -50,6 +50,7 @@ namespace O3DE::ProjectManager AZ::Outcome UpdateProject(const ProjectInfo& projectInfo) override; AZ::Outcome AddGemToProject(const QString& gemPath, const QString& projectPath) override; AZ::Outcome RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override; + bool RemoveInvalidProjects() override; // ProjectTemplate AZ::Outcome> GetProjectTemplates(const QString& projectPath = {}) override; diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index 0adc842a05..8580087737 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -141,6 +141,11 @@ namespace O3DE::ProjectManager */ virtual AZ::Outcome RemoveGemFromProject(const QString& gemPath, const QString& projectPath) = 0; + /** + * Removes invalid projects from the manifest + */ + virtual bool RemoveInvalidProjects() = 0; + // Project Templates diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 40556205de..ff4ccdc0a6 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -404,26 +404,27 @@ def register_project_path(json_data: dict, if result != 0: return result - # registering a project has the additional step of setting the project.json 'engine' field - this_engine_json = manifest.get_engine_json_data(engine_path=manifest.get_this_engine_path()) - if not this_engine_json: - return 1 - project_json_data = manifest.get_project_json_data(project_path=project_path) - if not project_json_data: - return 1 - - update_project_json = False - try: - update_project_json = project_json_data['engine'] != this_engine_json['engine_name'] - except KeyError as e: - update_project_json = True - - if update_project_json: - project_json_path = project_path / 'project.json' - project_json_data['engine'] = this_engine_json['engine_name'] - utils.backup_file(project_json_path) - if not manifest.save_o3de_manifest(project_json_data, project_json_path): + if not remove: + # registering a project has the additional step of setting the project.json 'engine' field + this_engine_json = manifest.get_engine_json_data(engine_path=manifest.get_this_engine_path()) + if not this_engine_json: return 1 + project_json_data = manifest.get_project_json_data(project_path=project_path) + if not project_json_data: + return 1 + + update_project_json = False + try: + update_project_json = project_json_data['engine'] != this_engine_json['engine_name'] + except KeyError as e: + update_project_json = True + + if update_project_json: + project_json_path = project_path / 'project.json' + project_json_data['engine'] = this_engine_json['engine_name'] + utils.backup_file(project_json_path) + if not manifest.save_o3de_manifest(project_json_data, project_json_path): + return 1 return 0 @@ -656,6 +657,22 @@ def register(engine_path: pathlib.Path = None, return result +def remove_invalid_o3de_projects(manifest_path: pathlib.Path = None) -> int: + if not manifest_path: + manifest_path = manifest.get_o3de_manifest() + + json_data = manifest.load_o3de_manifest(manifest_path) + + result = 0 + + for project in json_data['projects']: + if not validation.valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): + logger.warn(f"Project path {project} is invalid.") + # Attempt to unregister all invalid projects even if previous projects failed to unregister + # but combine the result codes of each command. + result = register(project_path=pathlib.Path(project), remove=True) or result + + return result def remove_invalid_o3de_objects() -> None: json_data = manifest.load_o3de_manifest() @@ -666,10 +683,7 @@ def remove_invalid_o3de_objects() -> None: logger.warn(f"Engine path {engine_path} is invalid.") register(engine_path=engine_path, remove=True) - for project in json_data['projects']: - if not validation.valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): - logger.warn(f"Project path {project} is invalid.") - register(project_path=project, remove=True) + remove_invalid_o3de_projects() for gem in json_data['gems']: if not validation.valid_o3de_gem_json(pathlib.Path(gem).resolve() / 'gem.json'):