From d4a0eb3a246e2afcc10e9322638e3a420ef32bca Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 17 May 2021 13:03:37 -0500 Subject: [PATCH 01/10] Moving o3de registration scripts to the scripts/o3de folder --- {cmake/Tools => scripts/o3de}/engine_template.py | 0 {cmake/Tools => scripts/o3de}/global_project.py | 0 {cmake/Tools => scripts/o3de}/registration.py | 0 {cmake/Tools => scripts/o3de}/unit_test_add_remove_gem.py | 0 {cmake/Tools => scripts/o3de}/unit_test_current_project.py | 0 {cmake/Tools => scripts/o3de}/unit_test_engine_template.py | 0 {cmake/Tools => scripts/o3de}/unit_test_utils.py | 0 {cmake/Tools => scripts/o3de}/utils.py | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename {cmake/Tools => scripts/o3de}/engine_template.py (100%) rename {cmake/Tools => scripts/o3de}/global_project.py (100%) rename {cmake/Tools => scripts/o3de}/registration.py (100%) rename {cmake/Tools => scripts/o3de}/unit_test_add_remove_gem.py (100%) rename {cmake/Tools => scripts/o3de}/unit_test_current_project.py (100%) rename {cmake/Tools => scripts/o3de}/unit_test_engine_template.py (100%) rename {cmake/Tools => scripts/o3de}/unit_test_utils.py (100%) rename {cmake/Tools => scripts/o3de}/utils.py (100%) diff --git a/cmake/Tools/engine_template.py b/scripts/o3de/engine_template.py similarity index 100% rename from cmake/Tools/engine_template.py rename to scripts/o3de/engine_template.py diff --git a/cmake/Tools/global_project.py b/scripts/o3de/global_project.py similarity index 100% rename from cmake/Tools/global_project.py rename to scripts/o3de/global_project.py diff --git a/cmake/Tools/registration.py b/scripts/o3de/registration.py similarity index 100% rename from cmake/Tools/registration.py rename to scripts/o3de/registration.py diff --git a/cmake/Tools/unit_test_add_remove_gem.py b/scripts/o3de/unit_test_add_remove_gem.py similarity index 100% rename from cmake/Tools/unit_test_add_remove_gem.py rename to scripts/o3de/unit_test_add_remove_gem.py diff --git a/cmake/Tools/unit_test_current_project.py b/scripts/o3de/unit_test_current_project.py similarity index 100% rename from cmake/Tools/unit_test_current_project.py rename to scripts/o3de/unit_test_current_project.py diff --git a/cmake/Tools/unit_test_engine_template.py b/scripts/o3de/unit_test_engine_template.py similarity index 100% rename from cmake/Tools/unit_test_engine_template.py rename to scripts/o3de/unit_test_engine_template.py diff --git a/cmake/Tools/unit_test_utils.py b/scripts/o3de/unit_test_utils.py similarity index 100% rename from cmake/Tools/unit_test_utils.py rename to scripts/o3de/unit_test_utils.py diff --git a/cmake/Tools/utils.py b/scripts/o3de/utils.py similarity index 100% rename from cmake/Tools/utils.py rename to scripts/o3de/utils.py From 680a8e6fbd80466015161cf7d24aba4c56f83773 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 21:43:13 -0500 Subject: [PATCH 02/10] Moving the o3de UnitTest files to script/o3de/test folder to help with file organization --- scripts/o3de/{ => test}/unit_test_add_remove_gem.py | 0 scripts/o3de/{ => test}/unit_test_current_project.py | 0 scripts/o3de/{ => test}/unit_test_engine_template.py | 0 scripts/o3de/{ => test}/unit_test_utils.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename scripts/o3de/{ => test}/unit_test_add_remove_gem.py (100%) rename scripts/o3de/{ => test}/unit_test_current_project.py (100%) rename scripts/o3de/{ => test}/unit_test_engine_template.py (100%) rename scripts/o3de/{ => test}/unit_test_utils.py (100%) diff --git a/scripts/o3de/unit_test_add_remove_gem.py b/scripts/o3de/test/unit_test_add_remove_gem.py similarity index 100% rename from scripts/o3de/unit_test_add_remove_gem.py rename to scripts/o3de/test/unit_test_add_remove_gem.py diff --git a/scripts/o3de/unit_test_current_project.py b/scripts/o3de/test/unit_test_current_project.py similarity index 100% rename from scripts/o3de/unit_test_current_project.py rename to scripts/o3de/test/unit_test_current_project.py diff --git a/scripts/o3de/unit_test_engine_template.py b/scripts/o3de/test/unit_test_engine_template.py similarity index 100% rename from scripts/o3de/unit_test_engine_template.py rename to scripts/o3de/test/unit_test_engine_template.py diff --git a/scripts/o3de/unit_test_utils.py b/scripts/o3de/test/unit_test_utils.py similarity index 100% rename from scripts/o3de/unit_test_utils.py rename to scripts/o3de/test/unit_test_utils.py From f34661491774ed36587047bbd91ebd46da8ed32b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 21:47:03 -0500 Subject: [PATCH 03/10] Adding __init__.py scripts to allow the name of o3de to be structured as a package --- scripts/o3de/__init__.py | 10 ++++++++++ scripts/o3de/test/__init__.py | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 scripts/o3de/__init__.py create mode 100644 scripts/o3de/test/__init__.py diff --git a/scripts/o3de/__init__.py b/scripts/o3de/__init__.py new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/scripts/o3de/__init__.py @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/scripts/o3de/test/__init__.py b/scripts/o3de/test/__init__.py new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/scripts/o3de/test/__init__.py @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# From 548219d1174a9598d554844e4aff5f8b52bdbbb9 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 22:19:09 -0500 Subject: [PATCH 04/10] Updated the registration.py script register_engine_path function to add a key, value mapping of engine name to engine path in the o3de_manifest.json file Added a pytest to validate the new engine_name -> engine_path functionality and registered those test with CTest. Fixed miscellaneous issues in the registration.py around incorrect return values for get_*_data functions where some of the returns values were integers where the return value should have been None --- scripts/CMakeLists.txt | 1 + scripts/o3de/CMakeLists.txt | 12 ++ scripts/o3de/registration.py | 172 +++++++++++++------- scripts/o3de/test/CMakeLists.txt | 22 +++ scripts/o3de/test/unit_test_registration.py | 66 ++++++++ 5 files changed, 212 insertions(+), 61 deletions(-) create mode 100644 scripts/o3de/CMakeLists.txt create mode 100644 scripts/o3de/test/CMakeLists.txt create mode 100644 scripts/o3de/test/unit_test_registration.py diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index d2843a9013..d3c9640665 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -11,5 +11,6 @@ add_subdirectory(detect_file_changes) add_subdirectory(commit_validation) +add_subdirectory(o3de) add_subdirectory(project_manager) add_subdirectory(ctest) diff --git a/scripts/o3de/CMakeLists.txt b/scripts/o3de/CMakeLists.txt new file mode 100644 index 0000000000..0744845784 --- /dev/null +++ b/scripts/o3de/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +add_subdirectory(test) diff --git a/scripts/o3de/registration.py b/scripts/o3de/registration.py index 184d2cdb31..eb7224c8ea 100755 --- a/scripts/o3de/registration.py +++ b/scripts/o3de/registration.py @@ -128,7 +128,7 @@ def get_o3de_logs_folder() -> pathlib.Path: return restricted_folder -def register_shipped_engine_o3de_objects() -> int: +def register_shipped_engine_o3de_objects(force: bool = False) -> int: engine_path = get_this_engine_path() ret_val = 0 @@ -137,7 +137,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_engines_directories = [ ] for engines_directory in sorted(starting_engines_directories, reverse=True): - error_code = register_all_engines_in_folder(engines_path=engines_directory) + error_code = register_all_engines_in_folder(engines_path=engines_directory, force=force) if error_code: ret_val = error_code @@ -145,7 +145,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_engines = [ ] for engine_path in sorted(starting_engines): - error_code = register(engine_path=engine_path) + error_code = register(engine_path=engine_path, force=force) if error_code: ret_val = error_code @@ -162,7 +162,7 @@ def register_shipped_engine_o3de_objects() -> int: f'{engine_path}/AutomatedTesting' ] for project_path in sorted(starting_projects, reverse=True): - error_code = register(engine_path=engine_path, project_path=project_path) + error_code = register(engine_path=engine_path, project_path=project_path, force=force) if error_code: ret_val = error_code @@ -179,7 +179,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_gems = [ ] for gem_path in sorted(starting_gems, reverse=True): - error_code = register(engine_path=engine_path, gem_path=gem_path) + error_code = register(engine_path=engine_path, gem_path=gem_path, force=force) if error_code: ret_val = error_code @@ -196,7 +196,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_templates = [ ] for template_path in sorted(starting_templates, reverse=True): - error_code = register(engine_path=engine_path, template_path=template_path) + error_code = register(engine_path=engine_path, template_path=template_path, force=force) if error_code: ret_val = error_code @@ -212,7 +212,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_restricted = [ ] for restricted_path in sorted(starting_restricted, reverse=True): - error_code = register(engine_path=engine_path, restricted_path=restricted_path) + error_code = register(engine_path=engine_path, restricted_path=restricted_path, force=force) if error_code: ret_val = error_code @@ -228,12 +228,12 @@ def register_shipped_engine_o3de_objects() -> int: starting_repos = [ ] for repo_uri in sorted(starting_repos, reverse=True): - error_code = register(repo_uri=repo_uri) + error_code = register(repo_uri=repo_uri, force=force) if error_code: ret_val = error_code # register anything in the users default folders globally - error_code = register_all_engines_in_folder(get_registered(default_folder='engines')) + error_code = register_all_engines_in_folder(get_registered(default_folder='engines'), force=force) if error_code: ret_val = error_code error_code = register_all_projects_in_folder(get_registered(default_folder='projects')) @@ -266,7 +266,7 @@ def register_shipped_engine_o3de_objects() -> int: gem_path = pathlib.Path(gem_path).resolve() gem_cmake_lists_txt = gem_path / 'CMakeLists.txt' if gem_cmake_lists_txt.is_file(): - add_gem_to_cmake(engine_path=engine_path, gem_path=gem_path, supress_errors=True) # don't care about errors + add_gem_to_cmake(engine_path=engine_path, gem_path=gem_path, suppress_errors=True) # don't care about errors return ret_val @@ -344,7 +344,8 @@ def register_all_in_folder(folder_path: str or pathlib.Path, def register_all_engines_in_folder(engines_path: str or pathlib.Path, - remove: bool = False) -> int: + remove: bool = False, + force: bool = False) -> int: if not engines_path: logger.error(f'Engines path cannot be empty.') return 1 @@ -360,10 +361,10 @@ def register_all_engines_in_folder(engines_path: str or pathlib.Path, for root, dirs, files in os.walk(engines_path): for name in files: if name == 'engine.json': - engines_set.add(name) + engines_set.add(root) for engine in sorted(engines_set, reverse=True): - error_code = register(engine_path=engine, remove=remove) + error_code = register(engine_path=engine, remove=remove, force=force) if error_code: ret_val = error_code @@ -602,21 +603,65 @@ def save_o3de_manifest(json_data: dict) -> None: logger.error(f'Manifest json failed to save: {str(e)}') +def remove_engine_name_to_path(json_data: dict, + engine_path: pathlib.Path) -> int: + """ + Remove the engine at the specified path if it exist in the o3de manifest + :param json_data in-memory json view of the o3de_manifest.json data + :param engine_path path to engine to remove from the manifest data + + returns 0 to indicate no issues has occurred with removal + """ + if engine_path.is_dir() and valid_o3de_engine_json(engine_path): + engine_json_data = get_engine_data(engine_path=engine_path) + if 'engine_name' in engine_json_data and 'engines_path' in json_data: + engine_name = engine_json_data['engine_name'] + try: + del json_data['engines_path'][engine_name] + except KeyError: + # Attempting to remove a non-existent engine_name is fine + pass + return 0 + + +def add_engine_name_to_path(json_data: dict, engine_path: pathlib.Path, force: bool): + # Add an engine path JSON object which maps the "engine_name" -> "engine_path" + engine_json_data = get_engine_data(engine_path=engine_path) + if not engine_json_data: + logger.error(f'Unable to retrieve json data from engine.json at path {engine_path.as_posix()}') + return 1 + engines_path_json = json_data.setdefault('engines_path', {}) + if 'engine_name' not in engine_json_data: + logger.error(f'engine.json at path {engine_path.as_posix()} is missing "engine_name" key') + return 1 + + engine_name = engine_json_data['engine_name'] + if not force and engine_name in engines_path_json and \ + pathlib.PurePath(engines_path_json[engine_name]) != engine_path: + logger.error( + f'Attempting to register existing engine "{engine_name}" with a new path of {engine_path.as_posix()}.' + f' The current path is {pathlib.Path(engines_path_json[engine_name]).as_posix()}.' + f' To force registration of a new engine path, specify the -f/--force option.') + return 1 + engines_path_json[engine_name] = engine_path.as_posix() + return 0 + def register_engine_path(json_data: dict, engine_path: str or pathlib.Path, - remove: bool = False) -> int: + remove: bool = False, + force: bool = False) -> int: if not engine_path: logger.error(f'Engine path cannot be empty.') return 1 engine_path = pathlib.Path(engine_path).resolve() - for engine_object in json_data['engines']: + for engine_object in json_data.get('engines', {}): engine_object_path = pathlib.Path(engine_object['path']).resolve() if engine_object_path == engine_path: json_data['engines'].remove(engine_object) if remove: - return 0 + return remove_engine_name_to_path(json_data, engine_path) if not engine_path.is_dir(): logger.error(f'Engine path {engine_path} does not exist.') @@ -635,9 +680,9 @@ def register_engine_path(json_data: dict, engine_object.update({'restricted': []}) engine_object.update({'external_subdirectories': []}) - json_data['engines'].insert(0, engine_object) + json_data.setdefault('engines', []).insert(0, engine_object) - return 0 + return add_engine_name_to_path(json_data, engine_path, force) def register_gem_path(json_data: dict, @@ -1234,7 +1279,8 @@ def register(engine_path: str or pathlib.Path = None, default_gems_folder: str or pathlib.Path = None, default_templates_folder: str or pathlib.Path = None, default_restricted_folder: str or pathlib.Path = None, - remove: bool = False + remove: bool = False, + force: bool = False ) -> int: """ Adds/Updates entries to the .o3de/o3de_manifest.json @@ -1251,6 +1297,7 @@ def register(engine_path: str or pathlib.Path = None, :param default_templates_folder: default templates folder :param default_restricted_folder: default restricted code folder :param remove: add/remove the entries + :param force: force update of the engine_path for specified "engine_name" from the engine.json file :return: 0 for success or non 0 failure code """ @@ -1312,7 +1359,7 @@ def register(engine_path: str or pathlib.Path = None, if not engine_path: logger.error(f'Engine path cannot be empty.') return 1 - result = register_engine_path(json_data, engine_path, remove) + result = register_engine_path(json_data, engine_path, remove, force) if not result: save_o3de_manifest(json_data) @@ -2122,23 +2169,23 @@ def get_engine_data(engine_name: str = None, engine_path: str or pathlib.Path = None, ) -> dict or None: if not engine_name and not engine_path: logger.error('Must specify either a Engine name or Engine Path.') - return 1 + return None if engine_name and not engine_path: engine_path = get_registered(engine_name=engine_name) if not engine_path: logger.error(f'Engine Path {engine_path} has not been registered.') - return 1 + return None engine_path = pathlib.Path(engine_path).resolve() engine_json = engine_path / 'engine.json' if not engine_json.is_file(): logger.error(f'Engine json {engine_json} is not present.') - return 1 + return None if not valid_o3de_engine_json(engine_json): logger.error(f'Engine json {engine_json} is not valid.') - return 1 + return None with engine_json.open('r') as f: try: @@ -2155,23 +2202,23 @@ def get_project_data(project_name: str = None, project_path: str or pathlib.Path = None, ) -> dict or None: if not project_name and not project_path: logger.error('Must specify either a Project name or Project Path.') - return 1 + return None if project_name and not project_path: project_path = get_registered(project_name=project_name) if not project_path: logger.error(f'Project Path {project_path} has not been registered.') - return 1 + return None project_path = pathlib.Path(project_path).resolve() project_json = project_path / 'project.json' if not project_json.is_file(): logger.error(f'Project json {project_json} is not present.') - return 1 + return None if not valid_o3de_project_json(project_json): logger.error(f'Project json {project_json} is not valid.') - return 1 + return None with project_json.open('r') as f: try: @@ -2188,23 +2235,23 @@ def get_gem_data(gem_name: str = None, gem_path: str or pathlib.Path = None, ) -> dict or None: if not gem_name and not gem_path: logger.error('Must specify either a Gem name or Gem Path.') - return 1 + return None if gem_name and not gem_path: gem_path = get_registered(gem_name=gem_name) if not gem_path: logger.error(f'Gem Path {gem_path} has not been registered.') - return 1 + return None gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' if not gem_json.is_file(): logger.error(f'Gem json {gem_json} is not present.') - return 1 + return None if not valid_o3de_gem_json(gem_json): logger.error(f'Gem json {gem_json} is not valid.') - return 1 + return None with gem_json.open('r') as f: try: @@ -2221,23 +2268,23 @@ def get_template_data(template_name: str = None, template_path: str or pathlib.Path = None, ) -> dict or None: if not template_name and not template_path: logger.error('Must specify either a Template name or Template Path.') - return 1 + return None if template_name and not template_path: template_path = get_registered(template_name=template_name) if not template_path: logger.error(f'Template Path {template_path} has not been registered.') - return 1 + return None template_path = pathlib.Path(template_path).resolve() template_json = template_path / 'template.json' if not template_json.is_file(): logger.error(f'Template json {template_json} is not present.') - return 1 + return None if not valid_o3de_template_json(template_json): logger.error(f'Template json {template_json} is not valid.') - return 1 + return None with template_json.open('r') as f: try: @@ -2254,23 +2301,23 @@ def get_restricted_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None, ) -> dict or None: if not restricted_name and not restricted_path: logger.error('Must specify either a Restricted name or Restricted Path.') - return 1 + return None if restricted_name and not restricted_path: restricted_path = get_registered(restricted_name=restricted_name) if not restricted_path: logger.error(f'Restricted Path {restricted_path} has not been registered.') - return 1 + return None restricted_path = pathlib.Path(restricted_path).resolve() restricted_json = restricted_path / 'restricted.json' if not restricted_json.is_file(): logger.error(f'Restricted json {restricted_json} is not present.') - return 1 + return None if not valid_o3de_restricted_json(restricted_json): logger.error(f'Restricted json {restricted_json} is not valid.') - return 1 + return None with restricted_json.open('r') as f: try: @@ -3259,30 +3306,30 @@ def get_gem_targets(gem_name: str = None, def add_external_subdirectory(external_subdir: str or pathlib.Path, engine_path: str or pathlib.Path = None, - supress_errors: bool = False) -> int: + suppress_errors: bool = False) -> int: """ add external subdirectory to a cmake :param external_subdir: external subdirectory to add to cmake :param engine_path: optional engine path, defaults to this engine - :param supress_errors: optional silence errors + :param suppress_errors: optional silence errors :return: 0 for success or non 0 failure code """ external_subdir = pathlib.Path(external_subdir).resolve() if not external_subdir.is_dir(): - if not supress_errors: + if not suppress_errors: logger.error(f'Add External Subdirectory Failed: {external_subdir} does not exist.') return 1 external_subdir_cmake = external_subdir / 'CMakeLists.txt' if not external_subdir_cmake.is_file(): - if not supress_errors: + if not suppress_errors: logger.error(f'Add External Subdirectory Failed: {external_subdir} does not contain a CMakeLists.txt.') return 1 json_data = load_o3de_manifest() engine_object = find_engine_data(json_data, engine_path) if not engine_object: - if not supress_errors: + if not suppress_errors: logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') return 1 @@ -3290,7 +3337,7 @@ def add_external_subdirectory(external_subdir: str or pathlib.Path, engine_object['external_subdirectories'].remove(external_subdir.as_posix()) def parse_cmake_file(cmake: str or pathlib.Path, - files: set()): + files: set): cmake_path = pathlib.Path(cmake).resolve() cmake_file = cmake_path if cmake_path.is_dir(): @@ -3335,7 +3382,7 @@ def add_external_subdirectory(external_subdir: str or pathlib.Path, if external_subdir in cmake_files: save_o3de_manifest(json_data) - if not supress_errors: + if not suppress_errors: logger.error(f'External subdirectory {external_subdir.as_posix()} already included by add_subdirectory().') return 1 @@ -3374,18 +3421,18 @@ def add_gem_to_cmake(gem_name: str = None, gem_path: str or pathlib.Path = None, engine_name: str = None, engine_path: str or pathlib.Path = None, - supress_errors: bool = False) -> int: + suppress_errors: bool = False) -> int: """ add a gem to a cmake as an external subdirectory for an engine :param gem_name: name of the gem to add to cmake :param gem_path: the path of the gem to add to cmake :param engine_name: name of the engine to add to cmake :param engine_path: the path of the engine to add external subdirectory to, default to this engine - :param supress_errors: optional silence errors + :param suppress_errors: optional silence errors :return: 0 for success or non 0 failure code """ if not gem_name and not gem_path: - if not supress_errors: + if not suppress_errors: logger.error('Must specify either a Gem name or Gem Path.') return 1 @@ -3393,18 +3440,18 @@ def add_gem_to_cmake(gem_name: str = None, gem_path = get_registered(gem_name=gem_name) if not gem_path: - if not supress_errors: + if not suppress_errors: logger.error(f'Gem Path {gem_path} has not been registered.') return 1 gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' if not gem_json.is_file(): - if not supress_errors: + if not suppress_errors: logger.error(f'Gem json {gem_json} is not present.') return 1 if not valid_o3de_gem_json(gem_json): - if not supress_errors: + if not suppress_errors: logger.error(f'Gem json {gem_json} is not valid.') return 1 @@ -3415,21 +3462,21 @@ def add_gem_to_cmake(gem_name: str = None, engine_path = get_registered(engine_name=engine_name) if not engine_path: - if not supress_errors: + if not suppress_errors: logger.error(f'Engine Path {engine_path} has not been registered.') return 1 engine_json = engine_path / 'engine.json' if not engine_json.is_file(): - if not supress_errors: + if not suppress_errors: logger.error(f'Engine json {engine_json} is not present.') return 1 if not valid_o3de_engine_json(engine_json): - if not supress_errors: + if not suppress_errors: logger.error(f'Engine json {engine_json} is not valid.') return 1 - return add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path, supress_errors=supress_errors) + return add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path, suppress_errors=suppress_errors) def remove_gem_from_cmake(gem_name: str = None, @@ -3930,13 +3977,13 @@ def _run_register(args: argparse) -> int: remove_invalid_o3de_objects() return refresh_repos() elif args.this_engine: - ret_val = register(engine_path=get_this_engine_path()) - error_code = register_shipped_engine_o3de_objects() + ret_val = register(engine_path=get_this_engine_path(), force=args.force) + error_code = register_shipped_engine_o3de_objects(force=args.force) if error_code: ret_val = error_code return ret_val elif args.all_engines_path: - return register_all_engines_in_folder(args.all_engines_path, args.remove) + return register_all_engines_in_folder(args.all_engines_path, args.remove, args.force) elif args.all_projects_path: return register_all_projects_in_folder(args.all_projects_path, args.remove) elif args.all_gems_path: @@ -3959,7 +4006,8 @@ def _run_register(args: argparse) -> int: default_gems_folder=args.default_gems_folder, default_templates_folder=args.default_templates_folder, default_restricted_folder=args.default_restricted_folder, - remove=args.remove) + remove=args.remove, + force=args.force) def _run_add_external_subdirectory(args: argparse) -> int: @@ -4096,6 +4144,8 @@ def add_args(parser, subparsers) -> None: register_subparser.add_argument('-r', '--remove', action='store_true', required=False, default=False, help='Remove entry.') + register_subparser.add_argument('-f', '--force', action='store_true', default=False, + help='For the update of the registration field being modified.') register_subparser.set_defaults(func=_run_register) # show diff --git a/scripts/o3de/test/CMakeLists.txt b/scripts/o3de/test/CMakeLists.txt new file mode 100644 index 0000000000..29410e3523 --- /dev/null +++ b/scripts/o3de/test/CMakeLists.txt @@ -0,0 +1,22 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +if(NOT PAL_TRAIT_BUILD_TESTS_SUPPORTED) + return() +endif() + +# Add a test to test out the o3de package `o3de.py register` command +ly_add_pytest( + NAME o3de_register + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_registration.py + TEST_SUITE smoke + EXCLUDE_TEST_RUN_TARGET_FROM_IDE +) diff --git a/scripts/o3de/test/unit_test_registration.py b/scripts/o3de/test/unit_test_registration.py new file mode 100644 index 0000000000..31a2dcb2f0 --- /dev/null +++ b/scripts/o3de/test/unit_test_registration.py @@ -0,0 +1,66 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +import argparse +import json +import logging +import pytest +import pathlib +from unittest.mock import patch + +from .. import registration + +string_manifest_data = '{}' + +@pytest.mark.parametrize( + "engine_path, engine_name, force, expected_result", [ + pytest.param(pathlib.PurePath('D:/o3de/o3de'), "o3de", False, 0), + # Same engine_name and path should result in valid registration + pytest.param(pathlib.PurePath('D:/o3de/o3de'), "o3de", False, 0), + # Same engine_name and but different path should fail + pytest.param(pathlib.PurePath('D:/o3de/engine-path'), "o3de", False, 1), + # New engine_name should result in valid registration + pytest.param(pathlib.PurePath('D:/o3de/engine-path'), "o3de-other", False, 0), + # Same engine_name and but different path with --force should result in valid registration + pytest.param(pathlib.PurePath('F:/Open3DEngine'), "o3de", True, 0), + ] +) +def test_register_engine_path(engine_path, engine_name, force, expected_result): + parser = argparse.ArgumentParser() + subparser = parser.add_subparsers(help='sub-command help') + + # Register the registration script subparsers with the current argument parser + registration.add_args(parser, subparser) + arg_list = ['register', '--engine-path', str(engine_path)] + if force: + arg_list += ['--force'] + args = parser.parse_args(arg_list) + + def load_manifest_from_string() -> dict: + try: + manifest_json = json.loads(string_manifest_data) + except json.JSONDecodeError as err: + logging.error("Error decoding Json from Manifest file") + else: + return manifest_json + def save_manifest_to_string(manifest_json: dict) -> None: + global string_manifest_data + string_manifest_data = json.dumps(manifest_json) + + engine_json_data = {'engine_name': engine_name} + with patch('o3de.registration.load_o3de_manifest', side_effect=load_manifest_from_string) as load_manifest_mock, \ + patch('o3de.registration.save_o3de_manifest', side_effect=save_manifest_to_string) as save_manifest_mock, \ + patch('o3de.registration.get_engine_data', return_value=engine_json_data) as engine_paths_mock, \ + patch('o3de.registration.valid_o3de_engine_json', return_value=True) as valid_engine_mock, \ + patch('pathlib.Path.is_dir', return_value=True) as pathlib_is_dir_mock: + result = registration._run_register(args) + assert result == expected_result + From 5d42b64ff979d36e2617287ab39712b3d6116fba Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 23:05:55 -0500 Subject: [PATCH 05/10] Moving the o3de test scripts to the tests subfolder of the package --- scripts/o3de/{test => tests}/CMakeLists.txt | 0 scripts/o3de/{test => tests}/__init__.py | 0 scripts/o3de/{test => tests}/unit_test_add_remove_gem.py | 0 scripts/o3de/{test => tests}/unit_test_current_project.py | 0 scripts/o3de/{test => tests}/unit_test_registration.py | 0 scripts/o3de/{test => tests}/unit_test_utils.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename scripts/o3de/{test => tests}/CMakeLists.txt (100%) rename scripts/o3de/{test => tests}/__init__.py (100%) rename scripts/o3de/{test => tests}/unit_test_add_remove_gem.py (100%) rename scripts/o3de/{test => tests}/unit_test_current_project.py (100%) rename scripts/o3de/{test => tests}/unit_test_registration.py (100%) rename scripts/o3de/{test => tests}/unit_test_utils.py (100%) diff --git a/scripts/o3de/test/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt similarity index 100% rename from scripts/o3de/test/CMakeLists.txt rename to scripts/o3de/tests/CMakeLists.txt diff --git a/scripts/o3de/test/__init__.py b/scripts/o3de/tests/__init__.py similarity index 100% rename from scripts/o3de/test/__init__.py rename to scripts/o3de/tests/__init__.py diff --git a/scripts/o3de/test/unit_test_add_remove_gem.py b/scripts/o3de/tests/unit_test_add_remove_gem.py similarity index 100% rename from scripts/o3de/test/unit_test_add_remove_gem.py rename to scripts/o3de/tests/unit_test_add_remove_gem.py diff --git a/scripts/o3de/test/unit_test_current_project.py b/scripts/o3de/tests/unit_test_current_project.py similarity index 100% rename from scripts/o3de/test/unit_test_current_project.py rename to scripts/o3de/tests/unit_test_current_project.py diff --git a/scripts/o3de/test/unit_test_registration.py b/scripts/o3de/tests/unit_test_registration.py similarity index 100% rename from scripts/o3de/test/unit_test_registration.py rename to scripts/o3de/tests/unit_test_registration.py diff --git a/scripts/o3de/test/unit_test_utils.py b/scripts/o3de/tests/unit_test_utils.py similarity index 100% rename from scripts/o3de/test/unit_test_utils.py rename to scripts/o3de/tests/unit_test_utils.py From 6fc1257f7344b57199e3e1e1a69675e2d07ebd5f Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 23:13:25 -0500 Subject: [PATCH 06/10] Moving the o3de python scripts to be underneath another o3de folder to allow `import o3de` to succeed. The path is now scripts/o3de/o3de --- scripts/o3de/{ => o3de}/__init__.py | 0 scripts/o3de/{ => o3de}/engine_template.py | 0 scripts/o3de/{ => o3de}/global_project.py | 0 scripts/o3de/{ => o3de}/registration.py | 0 scripts/o3de/{ => o3de}/utils.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename scripts/o3de/{ => o3de}/__init__.py (100%) rename scripts/o3de/{ => o3de}/engine_template.py (100%) rename scripts/o3de/{ => o3de}/global_project.py (100%) rename scripts/o3de/{ => o3de}/registration.py (100%) rename scripts/o3de/{ => o3de}/utils.py (100%) diff --git a/scripts/o3de/__init__.py b/scripts/o3de/o3de/__init__.py similarity index 100% rename from scripts/o3de/__init__.py rename to scripts/o3de/o3de/__init__.py diff --git a/scripts/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py similarity index 100% rename from scripts/o3de/engine_template.py rename to scripts/o3de/o3de/engine_template.py diff --git a/scripts/o3de/global_project.py b/scripts/o3de/o3de/global_project.py similarity index 100% rename from scripts/o3de/global_project.py rename to scripts/o3de/o3de/global_project.py diff --git a/scripts/o3de/registration.py b/scripts/o3de/o3de/registration.py similarity index 100% rename from scripts/o3de/registration.py rename to scripts/o3de/o3de/registration.py diff --git a/scripts/o3de/utils.py b/scripts/o3de/o3de/utils.py similarity index 100% rename from scripts/o3de/utils.py rename to scripts/o3de/o3de/utils.py From ec7f4c3fdcde2a46f90532494757a835c340455b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 23:15:50 -0500 Subject: [PATCH 07/10] Moving the engine template unit test files into the o3de/tests folder --- scripts/o3de/{test => tests}/unit_test_engine_template.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/o3de/{test => tests}/unit_test_engine_template.py (100%) diff --git a/scripts/o3de/test/unit_test_engine_template.py b/scripts/o3de/tests/unit_test_engine_template.py similarity index 100% rename from scripts/o3de/test/unit_test_engine_template.py rename to scripts/o3de/tests/unit_test_engine_template.py From 703c268e40107de3abac5bf8c4b2fe520f0cc0da Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 23:48:35 -0500 Subject: [PATCH 08/10] Adding a setup.py and a README to the scripts/o3de folder so it can be linked as a package into the engine python runtime when python is installed via python/get_python.bat --- scripts/o3de/README.txt | 41 ++++++++++++++++++++++++++++++++++++++++ scripts/o3de/setup.py | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 scripts/o3de/README.txt create mode 100644 scripts/o3de/setup.py diff --git a/scripts/o3de/README.txt b/scripts/o3de/README.txt new file mode 100644 index 0000000000..51bbf78cbd --- /dev/null +++ b/scripts/o3de/README.txt @@ -0,0 +1,41 @@ +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +INTRODUCTION +------------ + +o3de is a package of scripts containing functionality to register engine, projects, gems, +templates and download repositories with the o3de manifests +It also contains functionality for creating new projects, gems and templates as well +as querying existing gems and templates + + +REQUIREMENTS +------------ + + * Python 3.7.10 (64-bit) + +INSTALL +----------- +It is recommended to set up these these tools with O3DE's CMake build commands. +Assuming CMake is already setup on your operating system, below are some sample build commands: + cd /path/to/od3e/ + cmake -B windows_vs2019 -S . -G"Visual Studio 16" -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%" + +To manually install the project in development mode using your own installed Python interpreter: + cd /path/to/od3e/o3de + /path/to/your/python -m pip install -e . + + +UNINSTALLATION +-------------- + +The preferred way to uninstall the project is: + /path/to/your/python -m pip uninstall o3de diff --git a/scripts/o3de/setup.py b/scripts/o3de/setup.py new file mode 100644 index 0000000000..595f477c45 --- /dev/null +++ b/scripts/o3de/setup.py @@ -0,0 +1,42 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" +import os +import platform + +from setuptools import setup, find_packages +from setuptools.command.develop import develop +from setuptools.command.build_py import build_py + +PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__)) + +PYTHON_64 = platform.architecture()[0] == '64bit' + + +if __name__ == '__main__': + if not PYTHON_64: + raise RuntimeError("32-bit Python is not a supported platform.") + + with open(os.path.join(PACKAGE_ROOT, 'README.txt')) as f: + long_description = f.read() + + setup( + name="o3de", + version="1.0.0", + description='O3DE editor Python bindings test tools', + long_description=long_description, + packages=find_packages(where='o3de', exclude=['tests']), + install_requires=[ + ], + tests_require=[ + ], + entry_points={ + }, + ) From c6b0e3562e3f35b2bb0eb21c77e365453da0bdc7 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 19 May 2021 00:52:28 -0500 Subject: [PATCH 09/10] Updating the python import paths for the o3de scripts to use the new package o3de package location --- .../ProjectManager/Source/PythonBindings.cpp | 70 +++++++++---------- scripts/o3de.py | 25 ++++--- scripts/o3de/CMakeLists.txt | 2 +- scripts/o3de/o3de/engine_template.py | 9 +-- scripts/o3de/o3de/global_project.py | 6 +- scripts/o3de/o3de/registration.py | 4 +- scripts/project_manager/projects.py | 5 +- 7 files changed, 64 insertions(+), 57 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index cc5348fd22..bc154ea059 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -53,7 +53,7 @@ namespace Platform #define Py_To_String(obj) obj.cast().c_str() #define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string -namespace O3DE::ProjectManager +namespace O3DE::ProjectManager { PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath) : m_enginePath(enginePath) @@ -112,7 +112,7 @@ namespace O3DE::ProjectManager AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed"); // import required modules - m_registration = pybind11::module::import("cmake.Tools.registration"); + m_registration = pybind11::module::import("o3de.registration"); return result == 0 && !PyErr_Occurred(); } catch ([[maybe_unused]] const std::exception& e) @@ -153,22 +153,22 @@ namespace O3DE::ProjectManager } } - AZ::Outcome PythonBindings::GetEngineInfo() + AZ::Outcome PythonBindings::GetEngineInfo() { return AZ::Failure(); } - bool PythonBindings::SetEngineInfo([[maybe_unused]] const EngineInfo& engineInfo) + bool PythonBindings::SetEngineInfo([[maybe_unused]] const EngineInfo& engineInfo) { return false; } - AZ::Outcome PythonBindings::GetGem(const QString& path) + AZ::Outcome PythonBindings::GetGem(const QString& path) { GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString())); if (gemInfo.IsValid()) { - return AZ::Success(AZStd::move(gemInfo)); + return AZ::Success(AZStd::move(gemInfo)); } else { @@ -176,18 +176,18 @@ namespace O3DE::ProjectManager } } - AZ::Outcome> PythonBindings::GetGems() + AZ::Outcome> PythonBindings::GetGems() { QVector gems; bool result = ExecuteWithLock([&] { - // external gems + // external gems for (auto path : m_registration.attr("get_gems")()) { gems.push_back(GemInfoFromPath(path)); } - // gems from the engine + // gems from the engine for (auto path : m_registration.attr("get_engine_gems")()) { gems.push_back(GemInfoFromPath(path)); @@ -200,21 +200,21 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(gems)); + return AZ::Success(AZStd::move(gems)); } } - AZ::Outcome PythonBindings::CreateProject([[maybe_unused]] const ProjectTemplateInfo& projectTemplate,[[maybe_unused]] const ProjectInfo& projectInfo) + AZ::Outcome PythonBindings::CreateProject([[maybe_unused]] const ProjectTemplateInfo& projectTemplate,[[maybe_unused]] const ProjectInfo& projectInfo) { return AZ::Failure(); } - AZ::Outcome PythonBindings::GetProject(const QString& path) + AZ::Outcome PythonBindings::GetProject(const QString& path) { ProjectInfo projectInfo = ProjectInfoFromPath(pybind11::str(path.toStdString())); if (projectInfo.IsValid()) { - return AZ::Success(AZStd::move(projectInfo)); + return AZ::Success(AZStd::move(projectInfo)); } else { @@ -225,7 +225,7 @@ namespace O3DE::ProjectManager GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path) { GemInfo gemInfo; - gemInfo.m_path = Py_To_String(path); + gemInfo.m_path = Py_To_String(path); auto data = m_registration.attr("get_gem_data")(pybind11::none(), path); if (pybind11::isinstance(data)) @@ -233,13 +233,13 @@ namespace O3DE::ProjectManager try { // required - gemInfo.m_name = Py_To_String(data["Name"]); - gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"])); + gemInfo.m_name = Py_To_String(data["Name"]); + gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"])); // optional - gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name); - gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); - gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); + gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name); + gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); + gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); if (data.contains("Dependencies")) { @@ -268,7 +268,7 @@ namespace O3DE::ProjectManager ProjectInfo PythonBindings::ProjectInfoFromPath(pybind11::handle path) { ProjectInfo projectInfo; - projectInfo.m_path = Py_To_String(path); + projectInfo.m_path = Py_To_String(path); auto projectData = m_registration.attr("get_project_data")(pybind11::none(), path); if (pybind11::isinstance(projectData)) @@ -276,9 +276,9 @@ namespace O3DE::ProjectManager try { // required fields - projectInfo.m_productName = Py_To_String(projectData["product_name"]); - projectInfo.m_projectName = Py_To_String(projectData["project_name"]); - projectInfo.m_projectId = AZ::Uuid(Py_To_String(projectData["project_id"])); + projectInfo.m_productName = Py_To_String(projectData["product_name"]); + projectInfo.m_projectName = Py_To_String(projectData["project_name"]); + projectInfo.m_projectId = AZ::Uuid(Py_To_String(projectData["project_id"])); } catch ([[maybe_unused]] const std::exception& e) { @@ -289,18 +289,18 @@ namespace O3DE::ProjectManager return projectInfo; } - AZ::Outcome> PythonBindings::GetProjects() + AZ::Outcome> PythonBindings::GetProjects() { QVector projects; bool result = ExecuteWithLock([&] { - // external projects + // external projects for (auto path : m_registration.attr("get_projects")()) { projects.push_back(ProjectInfoFromPath(path)); } - // projects from the engine + // projects from the engine for (auto path : m_registration.attr("get_engine_projects")()) { projects.push_back(ProjectInfoFromPath(path)); @@ -313,11 +313,11 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(projects)); + return AZ::Success(AZStd::move(projects)); } } - bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) + bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) { return false; } @@ -325,7 +325,7 @@ namespace O3DE::ProjectManager ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path) { ProjectTemplateInfo templateInfo; - templateInfo.m_path = Py_To_String(path); + templateInfo.m_path = Py_To_String(path); auto data = m_registration.attr("get_template_data")(pybind11::none(), path); if (pybind11::isinstance(data)) @@ -333,10 +333,10 @@ namespace O3DE::ProjectManager try { // required - templateInfo.m_displayName = Py_To_String(data["display_name"]); - templateInfo.m_name = Py_To_String(data["template_name"]); - templateInfo.m_summary = Py_To_String(data["summary"]); - + templateInfo.m_displayName = Py_To_String(data["display_name"]); + templateInfo.m_name = Py_To_String(data["template_name"]); + templateInfo.m_summary = Py_To_String(data["summary"]); + // optional if (data.contains("canonical_tags")) { @@ -362,7 +362,7 @@ namespace O3DE::ProjectManager return templateInfo; } - AZ::Outcome> PythonBindings::GetProjectTemplates() + AZ::Outcome> PythonBindings::GetProjectTemplates() { QVector templates; @@ -379,7 +379,7 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(templates)); + return AZ::Success(AZStd::move(templates)); } } } diff --git a/scripts/o3de.py b/scripts/o3de.py index dbb9c53e4b..7bc1c4a9fb 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -10,17 +10,24 @@ # import argparse +import pathlib import sys -import os -# Resolve the common python module -ROOT_DEV_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) -if ROOT_DEV_PATH not in sys.path: - sys.path.append(ROOT_DEV_PATH) - -from cmake.Tools import engine_template -from cmake.Tools import global_project -from cmake.Tools import registration +# As o3de.py shares the same name as the o3de package attempting to use a regular +# from o3de import line tries to import from the current o3de.py script and not the package +# So the current script directory is removed from the sys.path temporary +SCRIPT_DIR_REMOVED = False +SCRIPT_DIR = pathlib.Path(__file__).parent.resolve() +if str(SCRIPT_DIR) in sys.path: + SCRIPT_DIR_REMOVED = True + sys.path.remove(str(SCRIPT_DIR)) + +from o3de import engine_template +from o3de import global_project +from o3de import registration + +if SCRIPT_DIR_REMOVED: + sys.path.insert(0, str(SCRIPT_DIR)) def add_args(parser, subparsers) -> None: diff --git a/scripts/o3de/CMakeLists.txt b/scripts/o3de/CMakeLists.txt index 0744845784..9819c1cd6e 100644 --- a/scripts/o3de/CMakeLists.txt +++ b/scripts/o3de/CMakeLists.txt @@ -9,4 +9,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -add_subdirectory(test) +add_subdirectory(tests) diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index eefb8c5541..23acab33d4 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -20,8 +20,8 @@ import json import uuid import re -from cmake.Tools import utils -import cmake.Tools.registration as registration + +from o3de import utils, registration logger = logging.getLogger() logging.basicConfig() @@ -2423,7 +2423,7 @@ if __name__ == "__main__": the_parser = argparse.ArgumentParser() # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') + the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) # add args to the parser add_args(the_parser, the_subparsers) @@ -2432,7 +2432,8 @@ if __name__ == "__main__": the_args = the_parser.parse_args() # run - ret = the_args.func(the_args) + + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 # return sys.exit(ret) diff --git a/scripts/o3de/o3de/global_project.py b/scripts/o3de/o3de/global_project.py index 1d84d9dcfb..da1b5dfa80 100644 --- a/scripts/o3de/o3de/global_project.py +++ b/scripts/o3de/o3de/global_project.py @@ -16,7 +16,7 @@ import sys import re import pathlib import json -import cmake.Tools.registration as registration +from o3de import registration logger = logging.getLogger() logging.basicConfig() @@ -153,7 +153,7 @@ if __name__ == "__main__": the_parser = argparse.ArgumentParser() # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') + the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) # add args to the parser add_args(the_parser, the_subparsers) @@ -162,7 +162,7 @@ if __name__ == "__main__": the_args = the_parser.parse_args() # run - ret = the_args.func(the_args) + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 # return sys.exit(ret) diff --git a/scripts/o3de/o3de/registration.py b/scripts/o3de/o3de/registration.py index eb7224c8ea..a4afecd740 100755 --- a/scripts/o3de/o3de/registration.py +++ b/scripts/o3de/o3de/registration.py @@ -4416,7 +4416,7 @@ if __name__ == "__main__": the_parser = argparse.ArgumentParser() # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') + the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) # add args to the parser add_args(the_parser, the_subparsers) @@ -4425,7 +4425,7 @@ if __name__ == "__main__": the_args = the_parser.parse_args() # run - ret = the_args.func(the_args) + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 # return sys.exit(ret) diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index 51db7a6440..e50c8d8a2d 100755 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -29,12 +29,11 @@ executable_path = '' logger = logging.getLogger() logger.setLevel(logging.INFO) -from cmake.Tools import engine_template -from cmake.Tools import registration +from o3de import engine_template, registration o3de_folder = registration.get_o3de_folder() o3de_logs_folder = registration.get_o3de_logs_folder() -project_manager_log_file_path = o3de_log_folder / "project_manager.log" +project_manager_log_file_path = o3de_logs_folder / "project_manager.log" log_file_handler = RotatingFileHandler(filename=project_manager_log_file_path, maxBytes=1024 * 1024, backupCount=1) formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s') log_file_handler.setFormatter(formatter) From f3d264292654eba10a2693fa195cc4b1d0a6103f Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 19 May 2021 00:54:31 -0500 Subject: [PATCH 10/10] Added an installation of the scripts/o3de folder as a local package for the o3de python that is installed through cmake --- cmake/LYPython.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/LYPython.cmake b/cmake/LYPython.cmake index 546d5f66db..a7c18e4dbe 100644 --- a/cmake/LYPython.cmake +++ b/cmake/LYPython.cmake @@ -270,6 +270,8 @@ if (NOT CMAKE_SCRIPT_MODE_FILE) ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/Tools/RemoteConsole/ly_remote_console ly-remote-console) ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools editor-python-test-tools) endif() + + ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/scripts/o3de o3de) endif() endif()