From 394ac7ab6a1255bd34099dbcba214544801fa952 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 16:44:50 -0500 Subject: [PATCH] Updated the enable gem and disable gem API (#54) * Updated the enable gem and disable gem API Renamed remove_gem_project.py -> disable_gem.py Renamed add_gem_project.py -> enable_gem.py Renamed the "add-gem-to-project" command -> "enable-gem" Renamed the "remove-gem-from-project" command -> "disable-gem" Fixed the parsing of the enabled gems from the enabled_gems.cmake file * Adding newline to the end of the CMakeLists.txt --- .../ProjectManager/Source/PythonBindings.cpp | 8 +- .../ProjectManager/Source/PythonBindings.h | 4 +- scripts/o3de.py | 6 +- scripts/o3de/o3de/cmake.py | 28 +- .../{remove_gem_project.py => disable_gem.py} | 74 ++--- .../{add_gem_project.py => enable_gem.py} | 66 ++--- scripts/o3de/o3de/manifest.py | 68 +++-- scripts/o3de/tests/CMakeLists.txt | 7 + .../o3de/tests/unit_test_add_remove_gem.py | 259 ------------------ scripts/o3de/tests/unit_test_cmake.py | 69 +++++ scripts/project_manager/projects.py | 10 +- 11 files changed, 208 insertions(+), 391 deletions(-) rename scripts/o3de/o3de/{remove_gem_project.py => disable_gem.py} (69%) rename scripts/o3de/o3de/{add_gem_project.py => enable_gem.py} (76%) delete mode 100755 scripts/o3de/tests/unit_test_add_remove_gem.py create mode 100644 scripts/o3de/tests/unit_test_cmake.py diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index c1e62f9c04..71d3c6de63 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -286,8 +286,8 @@ namespace O3DE::ProjectManager m_register = pybind11::module::import("o3de.register"); m_manifest = pybind11::module::import("o3de.manifest"); m_engineTemplate = pybind11::module::import("o3de.engine_template"); - m_addGemProject = pybind11::module::import("o3de.add_gem_project"); - m_removeGemProject = pybind11::module::import("o3de.remove_gem_project"); + m_enableGemProject = pybind11::module::import("o3de.enable_gem"); + m_disableGemProject = pybind11::module::import("o3de.disable_gem"); return result == 0 && !PyErr_Occurred(); } catch ([[maybe_unused]] const std::exception& e) @@ -588,7 +588,7 @@ namespace O3DE::ProjectManager pybind11::str pyGemPath = gemPath.toStdString(); pybind11::str pyProjectPath = projectPath.toStdString(); - m_addGemProject.attr("add_gem_to_project")( + m_enableGemProject.attr("enable_gem_in_project")( pybind11::none(), // gem_name pyGemPath, pybind11::none(), // project_name @@ -605,7 +605,7 @@ namespace O3DE::ProjectManager pybind11::str pyGemPath = gemPath.toStdString(); pybind11::str pyProjectPath = projectPath.toStdString(); - m_removeGemProject.attr("remove_gem_from_project")( + m_disableGemProject.attr("disable_gem_in_project")( pybind11::none(), // gem_name pyGemPath, pybind11::none(), // project_name diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 2dc15bd574..88bd0c1911 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -68,7 +68,7 @@ namespace O3DE::ProjectManager AZStd::recursive_mutex m_lock; pybind11::handle m_register; pybind11::handle m_manifest; - pybind11::handle m_addGemProject; - pybind11::handle m_removeGemProject; + pybind11::handle m_enableGemProject; + pybind11::handle m_disableGemProject; }; } diff --git a/scripts/o3de.py b/scripts/o3de.py index f91d5a25a0..24ba862529 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -32,7 +32,7 @@ def add_args(parser, subparsers) -> None: # add the scripts/o3de directory to the front of the sys.path sys.path.insert(0, str(o3de_package_dir)) from o3de import engine_template, global_project, register, print_registration, get_registration, download, \ - add_gem_project, remove_gem_project, sha256 + enable_gem, disable_gem, sha256 # Remove the temporarily added path sys.path = sys.path[1:] @@ -54,10 +54,10 @@ def add_args(parser, subparsers) -> None: download.add_args(subparsers) # add a gem to a project - add_gem_project.add_args(subparsers) + enable_gem.add_args(subparsers) # remove a gem from a project - remove_gem_project.add_args(subparsers) + disable_gem.add_args(subparsers) # sha256 sha256.add_args(subparsers) diff --git a/scripts/o3de/o3de/cmake.py b/scripts/o3de/o3de/cmake.py index eb8e3957ad..dfcce708eb 100644 --- a/scripts/o3de/o3de/cmake.py +++ b/scripts/o3de/o3de/cmake.py @@ -26,9 +26,9 @@ def get_project_gems(project_path: pathlib.Path, return get_gems_from_cmake_file(get_enabled_gem_cmake_file(project_path=project_path, platform=platform)) -def get_gem_from_cmake_file(cmake_file: pathlib.Path) -> set: +def get_enabled_gems(cmake_file: pathlib.Path) -> set: """ - Gets a list of declared gem targets dependencies of a cmake file + Gets a list of enabled gems from the cmake file :param cmake_file: path to the cmake file :return: set of gem targets found """ @@ -38,11 +38,29 @@ def get_gem_from_cmake_file(cmake_file: pathlib.Path) -> set: logger.error(f'Failed to locate cmake file {cmake_file}') return set() + enable_gem_start_marker = 'set(ENABLED_GEMS' + enable_gem_end_marker = ')' gem_target_set = set() with cmake_file.open('r') as s: + in_gem_list = False for line in s: - gem_name = line.strip() - gem_target_set.add(gem_name) + line = line.strip() + if line.startswith(enable_gem_start_marker): + # Set the flag to indicate that we are in the ENABLED_GEMS variable + in_gem_list = True + # Skip pass the 'set(ENABLED_GEMS' marker just in case their are gems declared on the same line + line = line[len(enable_gem_start_marker):] + if in_gem_list: + # Since we are inside the ENABLED_GEMS variable determine if the line has the end_marker of ')' + if line.endswith(enable_gem_end_marker): + # Strip away the line end marker + line = line[:-len(enable_gem_end_marker)] + # Set the flag to indicate that we are no longer in the ENABLED_GEMS variable after this line + in_gem_list = False + # Split the rest of the line on whitespace just in case there are multiple gems in a line + gem_name_list = line.split() + gem_target_set.update(gem_name_list) + return gem_target_set @@ -72,7 +90,7 @@ def get_enabled_gem_cmake_file(project_name: str = None, project_path = manifest.get_registered(project_name=project_name) project_path = pathlib.Path(project_path).resolve() - enable_gem_filename = "enabled_gem.cmake" + enable_gem_filename = "enabled_gems.cmake" if platform == 'Common': project_code_dir = project_path / 'Gem/Code' diff --git a/scripts/o3de/o3de/remove_gem_project.py b/scripts/o3de/o3de/disable_gem.py similarity index 69% rename from scripts/o3de/o3de/remove_gem_project.py rename to scripts/o3de/o3de/disable_gem.py index 72c51f0e2c..6c466c3631 100644 --- a/scripts/o3de/o3de/remove_gem_project.py +++ b/scripts/o3de/o3de/disable_gem.py @@ -58,20 +58,18 @@ def remove_gem_dependency(cmake_file: pathlib.Path, return 0 -def remove_gem_from_project(gem_name: str = None, - gem_path: pathlib.Path = None, - project_name: str = None, - project_path: pathlib.Path = None, - enabled_gem_file: pathlib.Path = None, - platforms: str = 'Common') -> int: +def disable_gem_in_project(gem_name: str = None, + gem_path: pathlib.Path = None, + project_name: str = None, + project_path: pathlib.Path = None, + enabled_gem_file: pathlib.Path = None) -> int: """ - remove a gem from a project + disable a gem in a projects enabled_gems.cmake file :param gem_name: name of the gem to add :param gem_path: path to the gem to add :param project_name: name of the project to add the gem to :param project_path: path to the project to add the gem to :param enabled_gem_file: File to remove enabled gem from - :param platforms: str to specify common or which specific platforms :return: 0 for success or non 0 failure code """ @@ -122,53 +120,37 @@ def remove_gem_from_project(gem_name: str = None, # when removing we will try to do as much as possible even with failures so ret_val will be the last error code ret_val = 0 - # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags - if enabled_gem_file: - # make sure this is a project has an enabled_gem file - if not enabled_gem_file.is_file(): - logger.error(f'Enabled gem file {enabled_gem_file} is not present.') - return 1 - # remove the dependency - error_code = remove_gem_dependency(dependencies_file, gem_json_data['gem_name']) - if error_code: - ret_val = error_code - else: - if ',' in platforms: - platforms = platforms.split(',') - else: - platforms = [platforms] - for platform in platforms: - # make sure this is a project has a enabled_gem.cmake file - project_enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path, platform=platform) - if not project_enabled_gem_file.is_file(): - logger.error(f'Enabled gem file {project_enabled_gem_file} is not present.') - else: - # remove the dependency - error_code = remove_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) - if error_code: - ret_val = error_code + if not enabled_gem_file: + enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path) + # make sure this is a project has an enabled gems file + if not enabled_gem_file.is_file(): + logger.error(f'Enabled gem file {enabled_gem_file} is not present.') + return 1 + # remove the gem + error_code = remove_gem_dependency(enabled_gem_file, gem_json_data['gem_name']) + if error_code: + ret_val = error_code return ret_val -def _run_remove_gem_from_project(args: argparse) -> int: +def _run_disable_gem_in_project(args: argparse) -> int: if args.override_home_folder: manifest.override_home_folder = args.override_home_folder - return remove_gem_from_project(args.gem_name, + return disable_gem_in_project(args.gem_name, args.gem_path, args.project_name, args.project_path, - args.enabled_gem_file, - args.platforms) + args.enabled_gem_file) def add_parser_args(parser): """ add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python remove_gem_project.py --project-path D:/Test --gem-name Atom + Ex. Directly run from this file alone with: python disable_gem.py --project-path D:/Test --gem-name Atom :param parser: the caller passes an argparse parser like instance to this method """ group = parser.add_mutually_exclusive_group(required=True) @@ -182,17 +164,13 @@ def add_parser_args(parser): group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') parser.add_argument('-egf', '--enabled-gem-file', type=pathlib.Path, required=False, - help='The cmake enabled gem file in which gem dependencies are to be removed from.' + help='The cmake enabled gem file in which gem names are to be removed from.' 'If not specified it will assume ') - parser.add_argument('-pl', '--platforms', type=str, required=False, - default='Common', - help='Optional list of platforms this gem should be removed from' - ' Ex. --platforms Mac,Windows,Linux') parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, help='By default the home folder is the user folder, override it to this folder.') - parser.set_defaults(func=_run_remove_gem_from_project) + parser.set_defaults(func=_run_disable_gem_in_project) def add_args(subparsers) -> None: @@ -200,16 +178,16 @@ def add_args(subparsers) -> None: add_args is called to add subparsers arguments to each command such that it can be a central python file such as o3de.py. It can be run from the o3de.py script as follows - call add_args and execute: python o3de.py remove-gem-from-project --project-path D:/Test --gem-name Atom + call add_args and execute: python o3de.py disable-gem-from-cmake --project-path D:/Test --gem-name Atom :param subparsers: the caller instantiates subparsers and passes it in here """ - remove_gem_project_subparser = subparsers.add_parser('remove-gem-from-project') - add_parser_args(remove_gem_project_subparser) + disable_gem_project_subparser = subparsers.add_parser('disable-gem') + add_parser_args(disable_gem_project_subparser) def main(): """ - Runs remove_gem_project.py script as standalone script + Runs disable_gem_project.py script as standalone script """ # parse the command line args the_parser = argparse.ArgumentParser() diff --git a/scripts/o3de/o3de/add_gem_project.py b/scripts/o3de/o3de/enable_gem.py similarity index 76% rename from scripts/o3de/o3de/add_gem_project.py rename to scripts/o3de/o3de/enable_gem.py index 42db0a97bd..73fc2ea3cf 100644 --- a/scripts/o3de/o3de/add_gem_project.py +++ b/scripts/o3de/o3de/enable_gem.py @@ -75,20 +75,18 @@ def add_gem_dependency(cmake_file: pathlib.Path, return 0 -def add_gem_to_project(gem_name: str = None, - gem_path: pathlib.Path = None, - project_name: str = None, - project_path: pathlib.Path = None, - enabled_gem_file: pathlib.Path = None, - platforms: str = 'Common') -> int: +def enable_gem_in_project(gem_name: str = None, + gem_path: pathlib.Path = None, + project_name: str = None, + project_path: pathlib.Path = None, + enabled_gem_file: pathlib.Path = None) -> int: """ - add a gem to a project + enable a gem in a projects enabled_gems.cmake file :param gem_name: name of the gem to add :param gem_path: path to the gem to add :param project_name: name of to the project to add the gem to :param project_path: path to the project to add the gem to :param enabled_gem_file_file: if this dependency goes/is in a specific file - :param platforms: str to specify common or which specific platforms :return: 0 for success or non 0 failure code """ # we need either a project name or path @@ -138,47 +136,41 @@ def add_gem_to_project(gem_name: str = None, ret_val = 0 if enabled_gem_file: - # make sure this is a project has a dependencies_file + # make sure this is a project has an enabled gems file if not enabled_gem_file.is_file(): logger.error(f'Enabled gem file {enabled_gem_file} is not present.') return 1 - # add the dependency + # add the gem ret_val = add_gem_dependency(enabled_gem_file, gem_json_data['gem_name']) else: - if ',' in platforms: - platforms = platforms.split(',') - else: - platforms = [platforms] - for platform in platforms: - # Find the path to enabled gem file. - # It will be created by add_gem_dependency if it doesn't exist - project_enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path, platform=platform) - if not project_enabled_gem_file.is_file(): - project_enabled_gem_file.touch() - # add the dependency - ret_val = add_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) + # Find the path to enabled gem file. + # It will be created if it doesn't exist + project_enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path) + if not project_enabled_gem_file.is_file(): + project_enabled_gem_file.touch() + # add the gem + ret_val = add_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) return ret_val -def _run_add_gem_to_project(args: argparse) -> int: +def _run_enable_gem_in_project(args: argparse) -> int: if args.override_home_folder: manifest.override_home_folder = args.override_home_folder - return add_gem_to_project(args.gem_name, - args.gem_path, - args.project_name, - args.project_path, - args.enabled_gem_file, - args.platforms) + return enable_gem_in_project(args.gem_name, + args.gem_path, + args.project_name, + args.project_path, + args.enabled_gem_file) def add_parser_args(parser): """ add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python add_gem_project.py --project-path "D:/TestProject" --gem-path "D:/TestGem" + Ex. Directly run from this file alone with: python enable_gem.py --project-path "D:/TestProject" --gem-path "D:/TestGem" :param parser: the caller passes an argparse parser like instance to this method """ group = parser.add_mutually_exclusive_group(required=True) @@ -192,17 +184,13 @@ def add_parser_args(parser): group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') parser.add_argument('-egf', '--enabled-gem-file', type=pathlib.Path, required=False, - help='The cmake enabled_gem file in which the gem dependencies are specified.' + help='The cmake enabled_gem file in which the gem names are specified.' 'If not specified it will assume enabled_gems.cmake') - parser.add_argument('-pl', '--platforms', type=str, required=False, - default='Common', - help='Optional list of platforms this gem should be added to.' - ' Ex. --platforms Mac,Windows,Linux') parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, help='By default the home folder is the user folder, override it to this folder.') - parser.set_defaults(func=_run_add_gem_to_project) + parser.set_defaults(func=_run_enable_gem_in_project) def add_args(subparsers) -> None: @@ -213,13 +201,13 @@ def add_args(subparsers) -> None: call add_args and execute: python o3de.py add-gem-to-project --project-path "D:/TestProject" --gem-path "D:/TestGem" :param subparsers: the caller instantiates subparsers and passes it in here """ - add_gem_project_subparser = subparsers.add_parser('add-gem-to-project') - add_parser_args(add_gem_project_subparser) + enable_gem_project_subparser = subparsers.add_parser('enable-gem') + add_parser_args(enable_gem_project_subparser) def main(): """ - Runs add_gem_project.py script as standalone script + Runs enable_gem.py script as standalone script """ # parse the command line args the_parser = argparse.ArgumentParser() diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index c3b327641c..092430500f 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -231,6 +231,11 @@ def get_gems() -> list: return list(filter(is_gem_subdirectory, external_subdirs)) if external_subdirs else [] +def get_external_subdirectories() -> list: + json_data = load_o3de_manifest() + return json_data['external_subdirectories'] + + def get_templates() -> list: json_data = load_o3de_manifest() return json_data['templates'] @@ -241,11 +246,6 @@ def get_restricted() -> list: return json_data['restricted'] -def get_external_subdirectories() -> list: - json_data = load_o3de_manifest() - return json_data['external_subdirectories'] - - def get_repos() -> list: json_data = load_o3de_manifest() return json_data['repos'] @@ -266,6 +266,13 @@ def get_engine_gems() -> list: return list(filter(is_gem_subdirectory, external_subdirs)) if external_subdirs else [] +def get_engine_external_subdirectories() -> list: + engine_path = get_this_engine_path() + engine_object = get_engine_json_data(engine_path=engine_path) + return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), + engine_object['external_subdirectories'])) if 'external_subdirectories' in engine_object else [] + + def get_engine_templates() -> list: engine_path = get_this_engine_path() engine_object = get_engine_json_data(engine_path=engine_path) @@ -280,19 +287,12 @@ def get_engine_restricted() -> list: engine_object['restricted'])) if 'restricted' in engine_object else [] -def get_engine_external_subdirectories() -> list: - engine_path = get_this_engine_path() - engine_object = get_engine_json_data(engine_path=engine_path) - return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), - engine_object['external_subdirectories'])) if 'external_subdirectories' in engine_object else [] - - # project.json queries def get_project_gems(project_path: pathlib.Path) -> list: def is_gem_subdirectory(subdir): return (pathlib.Path(subdir) / 'gem.json').exists() - external_subdirs = get_project_external_subdirectories() + external_subdirs = get_project_external_subdirectories(project_path) return list(filter(is_gem_subdirectory, external_subdirs)) if external_subdirs else [] @@ -302,26 +302,42 @@ def get_project_external_subdirectories(project_path: pathlib.Path) -> list: project_object['external_subdirectories'])) if 'external_subdirectories' in project_object else [] +# Combined manifest queries def get_all_projects() -> list: - engine_projects = get_engine_projects() - projects_data = get_projects() - projects_data.extend(engine_projects) - return projects_data + projects_data = set(get_projects()) + projects_data.update(get_engine_projects()) + return list(projects_data) -def get_all_gems() -> list: - engine_gems = get_engine_gems() - gems_data = get_gems() - gems_data.extend(engine_gems) - return gems_data +def get_all_gems(project_path: pathlib.Path = None) -> list: + gems_data = set(get_gems()) + gems_data.update(get_engine_gems()) + if project_path: + gems_data.update(get_project_gems(project_path)) + return list(gems_data) + + +def get_all_external_subdirectories(project_path: pathlib.Path = None) -> list: + external_subdirectories_data = set(get_external_subdirectories()) + external_subdirectories_data.update(get_engine_external_subdirectories()) + if project_path: + external_subdirectories_data.update(get_project_external_subdirectories(project_path)) + return list(templates_data) def get_all_templates() -> list: - engine_templates = get_engine_templates() - templates_data = get_templates() - templates_data.extend(engine_templates) - return templates_data + templates_data = set(get_templates()) + templates_data.update(get_engine_templates()) + return list(templates_data) + +def get_all_restricted() -> list: + restricted_data = set(get_restricted()) + restricted_data.update(get_engine_restricted()) + return list(gems_data) + + +# Template functions def get_project_templates(): # temporary until we have a better way to do this... maybe template_type element project_templates = [] for template in get_all_templates(): diff --git a/scripts/o3de/tests/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt index 7abc22a030..5c83f4112b 100644 --- a/scripts/o3de/tests/CMakeLists.txt +++ b/scripts/o3de/tests/CMakeLists.txt @@ -20,3 +20,10 @@ ly_add_pytest( TEST_SUITE smoke EXCLUDE_TEST_RUN_TARGET_FROM_IDE ) + +ly_add_pytest( + NAME o3de_cmake + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_cmake.py + TEST_SUITE smoke + EXCLUDE_TEST_RUN_TARGET_FROM_IDE +) diff --git a/scripts/o3de/tests/unit_test_add_remove_gem.py b/scripts/o3de/tests/unit_test_add_remove_gem.py deleted file mode 100755 index cc793bf32b..0000000000 --- a/scripts/o3de/tests/unit_test_add_remove_gem.py +++ /dev/null @@ -1,259 +0,0 @@ -# -# 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 pytest - -from o3de import add_gem_project - -TEST_WITHOUT_NO_GEM_CONTENT = """ -# {BEGIN_LICENSE} -# 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. -# {END_LICENSE} - -set(GEM_DEPENDENCIES -) -""" - -TEST_WITHOUT_ONLY_GEM_CONTENT = """ -# {BEGIN_LICENSE} -# 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. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::TestGem -) -""" - -TEST_WITHOUT_ADDED_GEM_CONTENT = """ -# {BEGIN_LICENSE} -# 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. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::ExistingGem -) -""" - -TEST_WITH_ADDED_GEM_CONTENT = """ -# {BEGIN_LICENSE} -# 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. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::TestGem - Gem::ExistingGem -) -""" - - -@pytest.mark.parametrize( - "contents, gem, expected_result, runtime_present, expect_failure", [ - pytest.param(TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", TEST_WITH_ADDED_GEM_CONTENT, True, False), - pytest.param(TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", TEST_WITH_ADDED_GEM_CONTENT, False, True), - pytest.param(TEST_WITHOUT_ADDED_GEM_CONTENT, "/TestGem", TEST_WITH_ADDED_GEM_CONTENT, True, True), - pytest.param(TEST_WITHOUT_NO_GEM_CONTENT, "TestGem", TEST_WITHOUT_ONLY_GEM_CONTENT, True, False), - ] -) -def test_add_gem_dependency(tmpdir, contents, gem, expected_result, runtime_present, expect_failure): - dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/') - os.makedirs(dev_root, exist_ok=True) - - dev_project_gem_code = f'{dev_root}/TestProject/Gem/Code' - os.makedirs(dev_project_gem_code, exist_ok=True) - - runtime_dependencies_cmake_file = f'{dev_project_gem_code}/runtime_dependencies.cmake' - if runtime_present: - if os.path.isfile(runtime_dependencies_cmake_file): - os.unlink(runtime_dependencies_cmake_file) - with open(runtime_dependencies_cmake_file, 'a') as s: - s.write(contents) - - result = add_gem_project.add_gem_dependency(runtime_dependencies_cmake_file, gem) - - if expect_failure: - assert result != 0 - else: - assert result == 0 - with open(runtime_dependencies_cmake_file, 'r') as s: - s_data = s.read() - assert s_data == expected_result - - -@pytest.mark.parametrize( - "contents, gem, expected_result, runtime_present, expect_failure", [ - pytest.param(TEST_WITH_ADDED_GEM_CONTENT, "TestGem", TEST_WITHOUT_ADDED_GEM_CONTENT, True, False), - pytest.param(TEST_WITH_ADDED_GEM_CONTENT, "TestGem", TEST_WITHOUT_ADDED_GEM_CONTENT, False, True), - pytest.param(TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", TEST_WITHOUT_ADDED_GEM_CONTENT, True, True) - ] -) -def test_remove_gem_dependency(tmpdir, contents, gem, expected_result, runtime_present, expect_failure): - dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/') - os.makedirs(dev_root, exist_ok=True) - - dev_project_gem_code = f'{dev_root}/TestProject/Gem/Code' - os.makedirs(dev_project_gem_code, exist_ok=True) - - runtime_dependencies_cmake_file = f'{dev_project_gem_code}/runtime_dependencies.cmake' - if runtime_present: - if os.path.isfile(runtime_dependencies_cmake_file): - os.unlink(runtime_dependencies_cmake_file) - with open(runtime_dependencies_cmake_file, 'a') as s: - s.write(contents) - - result = add_remove_gem.remove_gem_dependency(runtime_dependencies_cmake_file, gem) - - if expect_failure: - assert result != 0 - else: - assert result == 0 - with open(runtime_dependencies_cmake_file, 'r') as s: - s_data = s.read() - assert s_data == expected_result - - -@pytest.mark.parametrize("add," - " contents, gem, project, expected_result," - " runtime_present, tool_present," - " ask_for_runtime, ask_for_tool," - " expect_failure", [ - pytest.param(True, - TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITH_ADDED_GEM_CONTENT, - True, True, - True, True, - False), - pytest.param(True, - TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITH_ADDED_GEM_CONTENT, - True, False, - True, True, - True), - pytest.param(True, - TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITH_ADDED_GEM_CONTENT, - False, True, - True, True, - True), - pytest.param(True, - TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITH_ADDED_GEM_CONTENT, - False, False, - True, True, - True), - - pytest.param(False, - TEST_WITH_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITHOUT_ADDED_GEM_CONTENT, - True, True, - True, True, - False), - pytest.param(False, - TEST_WITH_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITHOUT_ADDED_GEM_CONTENT, - True, False, - True, True, - True), - pytest.param(False, - TEST_WITH_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITHOUT_ADDED_GEM_CONTENT, - False, True, - True, True, - True), - pytest.param(False, - TEST_WITH_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITHOUT_ADDED_GEM_CONTENT, - False, False, - True, True, - True) - ] - ) -def test_add_remove_gem(tmpdir, - add, - contents, gem, project, - expected_result, - runtime_present, tool_present, - ask_for_runtime, ask_for_tool, - expect_failure): - dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/') - os.makedirs(dev_root, exist_ok=True) - - dev_project_gem_code = f'{dev_root}/TestProject/Gem/Code' - os.makedirs(dev_project_gem_code, exist_ok=True) - - runtime_dependencies_cmake_file = f'{dev_project_gem_code}/runtime_dependencies.cmake' - if runtime_present: - if os.path.isfile(runtime_dependencies_cmake_file): - os.unlink(runtime_dependencies_cmake_file) - with open(runtime_dependencies_cmake_file, 'a') as s: - s.write(contents) - - tool_dependencies_cmake_file = f'{dev_project_gem_code}/tool_dependencies.cmake' - os.makedirs(dev_project_gem_code, exist_ok=True) - - if tool_present: - if os.path.isfile(tool_dependencies_cmake_file): - os.unlink(tool_dependencies_cmake_file) - with open(tool_dependencies_cmake_file, 'w') as s: - s.write(contents) - - project_folder = f'{dev_root}/TestProject' - os.makedirs(project_folder, exist_ok=True) - - gems_folder = f'{dev_root}/Gems' - os.makedirs(gems_folder, exist_ok=True) - - gem_folder = f'{gems_folder}/{gem}' - os.makedirs(gem_folder, exist_ok=True) - - result = add_remove_gem.add_remove_gem(add, dev_root, gem, project, ask_for_runtime, ask_for_tool) - - if expect_failure: - assert result != 0 - else: - assert result == 0 - if runtime_present: - with open(runtime_dependencies_cmake_file, 'r') as s: - s_data = s.read() - assert s_data == expected_result - if tool_present: - with open(tool_dependencies_cmake_file, 'r') as s: - s_data = s.read() - assert s_data == expected_result - diff --git a/scripts/o3de/tests/unit_test_cmake.py b/scripts/o3de/tests/unit_test_cmake.py new file mode 100644 index 0000000000..e5ce17dc03 --- /dev/null +++ b/scripts/o3de/tests/unit_test_cmake.py @@ -0,0 +1,69 @@ +# +# 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 io +import json +import logging +import pytest +import pathlib +from unittest.mock import patch + +from o3de import cmake + + +class TestGetEnabledGems: + @pytest.mark.parametrize( + "enable_gems_cmake_data, expected_set", [ + pytest.param(""" + # Comment + set(ENABLED_GEMS foo bar baz) + """, set(['foo', 'bar', 'baz'])), + pytest.param(""" + # Comment + set(ENABLED_GEMS + foo + bar + baz + ) + """, set(['foo', 'bar', 'baz'])), + pytest.param(""" + # Comment + set(ENABLED_GEMS + foo + bar + baz) + """, set(['foo', 'bar', 'baz'])), + pytest.param(""" + # Comment + set(ENABLED_GEMS + foo bar + baz) + """, set(['foo', 'bar', 'baz'])), + pytest.param(""" + # Comment + set(RANDOM_VARIABLE TestGame, TestProject Test Engine) + set(ENABLED_GEMS HelloWorld IceCream + foo + baz bar + baz baz baz baz baz morebaz lessbaz + ) + Random Text + """, set(['HelloWorld', 'IceCream', 'foo', 'bar', 'baz', 'morebaz', 'lessbaz'])), + ] + ) + def test_get_enabled_gems(self, enable_gems_cmake_data, expected_set): + enabled_gems_set = set() + with patch('pathlib.Path.resolve', return_value=pathlib.Path('enabled_gems.cmake')) as pathlib_is_resolve_mock,\ + patch('pathlib.Path.is_file', return_value=True) as pathlib_is_file_mock,\ + patch('pathlib.Path.open', return_value=io.StringIO(enable_gems_cmake_data)) as pathlib_open_mock: + enabled_gems_set = cmake.get_enabled_gems(pathlib.Path('enabled_gems.cmake')) + + assert enabled_gems_set == expected_set diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index d062343662..f9f40aa4bf 100755 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -29,7 +29,7 @@ executable_path = '' logger = logging.getLogger() logger.setLevel(logging.INFO) -from o3de import add_gem_project, cmake, engine_template, manifest, register, remove_gem_project +from o3de import disable_gem, enable_gem, cmake, engine_template, manifest, register o3de_folder = manifest.get_o3de_folder() o3de_logs_folder = manifest.get_o3de_logs_folder() @@ -671,8 +671,8 @@ class ProjectManagerDialog(QObject): gem_paths = manifest.get_all_gems() for gem_target in self.manage_project_gem_targets_get_selected_available_gems(): for gem_path in gem_paths: - add_gem_project.add_gem_to_project(gem_path=gem_path, - project_path=self.get_selected_project_path()) + enable_gem.enable_gem_in_project(gem_path=gem_path, + project_path=self.get_selected_project_path()) self.refresh_project_gem_targets_available_list() self.refresh_project_gem_targets_enabled_list() return @@ -683,8 +683,8 @@ class ProjectManagerDialog(QObject): gem_paths = manifest.get_all_gems() for gem_target in self.manage_project_gem_targets_get_selected_enabled_gems(): for gem_path in gem_paths: - remove_gem_project.remove_gem_from_project(gem_path=gem_path, - project_path=self.get_selected_project_path()) + disable_gem.disable_gem_in_project(gem_path=gem_path, + project_path=self.get_selected_project_path()) self.refresh_project_gem_targets_available_list() self.refresh_project_gem_targets_enabled_list() return