Merge branch 'ly-as-sdk/LYN-2948' into ly-as-sdk/LYN-2948-phistere

main
phistere 5 years ago
commit 77a035f015

@ -53,7 +53,7 @@ namespace Platform
#define Py_To_String(obj) obj.cast<std::string>().c_str() #define Py_To_String(obj) obj.cast<std::string>().c_str()
#define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string #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) PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath)
: m_enginePath(enginePath) : m_enginePath(enginePath)
@ -112,7 +112,7 @@ namespace O3DE::ProjectManager
AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed"); AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed");
// import required modules // import required modules
m_registration = pybind11::module::import("cmake.Tools.registration"); m_registration = pybind11::module::import("o3de.registration");
return result == 0 && !PyErr_Occurred(); return result == 0 && !PyErr_Occurred();
} catch ([[maybe_unused]] const std::exception& e) } catch ([[maybe_unused]] const std::exception& e)
@ -153,22 +153,22 @@ namespace O3DE::ProjectManager
} }
} }
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo() AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo()
{ {
return AZ::Failure(); return AZ::Failure();
} }
bool PythonBindings::SetEngineInfo([[maybe_unused]] const EngineInfo& engineInfo) bool PythonBindings::SetEngineInfo([[maybe_unused]] const EngineInfo& engineInfo)
{ {
return false; return false;
} }
AZ::Outcome<GemInfo> PythonBindings::GetGem(const QString& path) AZ::Outcome<GemInfo> PythonBindings::GetGem(const QString& path)
{ {
GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString())); GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString()));
if (gemInfo.IsValid()) if (gemInfo.IsValid())
{ {
return AZ::Success(AZStd::move(gemInfo)); return AZ::Success(AZStd::move(gemInfo));
} }
else else
{ {
@ -176,18 +176,18 @@ namespace O3DE::ProjectManager
} }
} }
AZ::Outcome<QVector<GemInfo>> PythonBindings::GetGems() AZ::Outcome<QVector<GemInfo>> PythonBindings::GetGems()
{ {
QVector<GemInfo> gems; QVector<GemInfo> gems;
bool result = ExecuteWithLock([&] { bool result = ExecuteWithLock([&] {
// external gems // external gems
for (auto path : m_registration.attr("get_gems")()) for (auto path : m_registration.attr("get_gems")())
{ {
gems.push_back(GemInfoFromPath(path)); gems.push_back(GemInfoFromPath(path));
} }
// gems from the engine // gems from the engine
for (auto path : m_registration.attr("get_engine_gems")()) for (auto path : m_registration.attr("get_engine_gems")())
{ {
gems.push_back(GemInfoFromPath(path)); gems.push_back(GemInfoFromPath(path));
@ -200,21 +200,21 @@ namespace O3DE::ProjectManager
} }
else else
{ {
return AZ::Success(AZStd::move(gems)); return AZ::Success(AZStd::move(gems));
} }
} }
AZ::Outcome<ProjectInfo> PythonBindings::CreateProject([[maybe_unused]] const ProjectTemplateInfo& projectTemplate,[[maybe_unused]] const ProjectInfo& projectInfo) AZ::Outcome<ProjectInfo> PythonBindings::CreateProject([[maybe_unused]] const ProjectTemplateInfo& projectTemplate,[[maybe_unused]] const ProjectInfo& projectInfo)
{ {
return AZ::Failure(); return AZ::Failure();
} }
AZ::Outcome<ProjectInfo> PythonBindings::GetProject(const QString& path) AZ::Outcome<ProjectInfo> PythonBindings::GetProject(const QString& path)
{ {
ProjectInfo projectInfo = ProjectInfoFromPath(pybind11::str(path.toStdString())); ProjectInfo projectInfo = ProjectInfoFromPath(pybind11::str(path.toStdString()));
if (projectInfo.IsValid()) if (projectInfo.IsValid())
{ {
return AZ::Success(AZStd::move(projectInfo)); return AZ::Success(AZStd::move(projectInfo));
} }
else else
{ {
@ -225,7 +225,7 @@ namespace O3DE::ProjectManager
GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path) GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path)
{ {
GemInfo gemInfo; 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); auto data = m_registration.attr("get_gem_data")(pybind11::none(), path);
if (pybind11::isinstance<pybind11::dict>(data)) if (pybind11::isinstance<pybind11::dict>(data))
@ -233,13 +233,13 @@ namespace O3DE::ProjectManager
try try
{ {
// required // required
gemInfo.m_name = Py_To_String(data["Name"]); gemInfo.m_name = Py_To_String(data["Name"]);
gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"])); gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"]));
// optional // optional
gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name); gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name);
gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); gemInfo.m_summary = Py_To_String_Optional(data, "Summary", "");
gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); gemInfo.m_version = Py_To_String_Optional(data, "Version", "");
if (data.contains("Dependencies")) if (data.contains("Dependencies"))
{ {
@ -268,7 +268,7 @@ namespace O3DE::ProjectManager
ProjectInfo PythonBindings::ProjectInfoFromPath(pybind11::handle path) ProjectInfo PythonBindings::ProjectInfoFromPath(pybind11::handle path)
{ {
ProjectInfo projectInfo; 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); auto projectData = m_registration.attr("get_project_data")(pybind11::none(), path);
if (pybind11::isinstance<pybind11::dict>(projectData)) if (pybind11::isinstance<pybind11::dict>(projectData))
@ -276,9 +276,9 @@ namespace O3DE::ProjectManager
try try
{ {
// required fields // required fields
projectInfo.m_productName = Py_To_String(projectData["product_name"]); projectInfo.m_productName = Py_To_String(projectData["product_name"]);
projectInfo.m_projectName = Py_To_String(projectData["project_name"]); projectInfo.m_projectName = Py_To_String(projectData["project_name"]);
projectInfo.m_projectId = AZ::Uuid(Py_To_String(projectData["project_id"])); projectInfo.m_projectId = AZ::Uuid(Py_To_String(projectData["project_id"]));
} }
catch ([[maybe_unused]] const std::exception& e) catch ([[maybe_unused]] const std::exception& e)
{ {
@ -289,18 +289,18 @@ namespace O3DE::ProjectManager
return projectInfo; return projectInfo;
} }
AZ::Outcome<QVector<ProjectInfo>> PythonBindings::GetProjects() AZ::Outcome<QVector<ProjectInfo>> PythonBindings::GetProjects()
{ {
QVector<ProjectInfo> projects; QVector<ProjectInfo> projects;
bool result = ExecuteWithLock([&] { bool result = ExecuteWithLock([&] {
// external projects // external projects
for (auto path : m_registration.attr("get_projects")()) for (auto path : m_registration.attr("get_projects")())
{ {
projects.push_back(ProjectInfoFromPath(path)); projects.push_back(ProjectInfoFromPath(path));
} }
// projects from the engine // projects from the engine
for (auto path : m_registration.attr("get_engine_projects")()) for (auto path : m_registration.attr("get_engine_projects")())
{ {
projects.push_back(ProjectInfoFromPath(path)); projects.push_back(ProjectInfoFromPath(path));
@ -313,11 +313,11 @@ namespace O3DE::ProjectManager
} }
else 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; return false;
} }
@ -325,7 +325,7 @@ namespace O3DE::ProjectManager
ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path) ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path)
{ {
ProjectTemplateInfo templateInfo; 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); auto data = m_registration.attr("get_template_data")(pybind11::none(), path);
if (pybind11::isinstance<pybind11::dict>(data)) if (pybind11::isinstance<pybind11::dict>(data))
@ -333,10 +333,10 @@ namespace O3DE::ProjectManager
try try
{ {
// required // required
templateInfo.m_displayName = Py_To_String(data["display_name"]); templateInfo.m_displayName = Py_To_String(data["display_name"]);
templateInfo.m_name = Py_To_String(data["template_name"]); templateInfo.m_name = Py_To_String(data["template_name"]);
templateInfo.m_summary = Py_To_String(data["summary"]); templateInfo.m_summary = Py_To_String(data["summary"]);
// optional // optional
if (data.contains("canonical_tags")) if (data.contains("canonical_tags"))
{ {
@ -362,7 +362,7 @@ namespace O3DE::ProjectManager
return templateInfo; return templateInfo;
} }
AZ::Outcome<QVector<ProjectTemplateInfo>> PythonBindings::GetProjectTemplates() AZ::Outcome<QVector<ProjectTemplateInfo>> PythonBindings::GetProjectTemplates()
{ {
QVector<ProjectTemplateInfo> templates; QVector<ProjectTemplateInfo> templates;
@ -379,7 +379,7 @@ namespace O3DE::ProjectManager
} }
else else
{ {
return AZ::Success(AZStd::move(templates)); return AZ::Success(AZStd::move(templates));
} }
} }
} }

@ -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}/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) ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools editor-python-test-tools)
endif() endif()
ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/scripts/o3de o3de)
endif() endif()
endif() endif()

@ -11,5 +11,6 @@
add_subdirectory(detect_file_changes) add_subdirectory(detect_file_changes)
add_subdirectory(commit_validation) add_subdirectory(commit_validation)
add_subdirectory(o3de)
add_subdirectory(project_manager) add_subdirectory(project_manager)
add_subdirectory(ctest) add_subdirectory(ctest)

@ -10,17 +10,24 @@
# #
import argparse import argparse
import pathlib
import sys import sys
import os
# Resolve the common python module # As o3de.py shares the same name as the o3de package attempting to use a regular
ROOT_DEV_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) # from o3de import <module> line tries to import from the current o3de.py script and not the package
if ROOT_DEV_PATH not in sys.path: # So the current script directory is removed from the sys.path temporary
sys.path.append(ROOT_DEV_PATH) SCRIPT_DIR_REMOVED = False
SCRIPT_DIR = pathlib.Path(__file__).parent.resolve()
from cmake.Tools import engine_template if str(SCRIPT_DIR) in sys.path:
from cmake.Tools import global_project SCRIPT_DIR_REMOVED = True
from cmake.Tools import registration 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: def add_args(parser, subparsers) -> None:

@ -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(tests)

@ -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

@ -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.
#

@ -20,8 +20,8 @@ import json
import uuid import uuid
import re import re
from cmake.Tools import utils
import cmake.Tools.registration as registration from o3de import utils, registration
logger = logging.getLogger() logger = logging.getLogger()
logging.basicConfig() logging.basicConfig()
@ -2423,7 +2423,7 @@ if __name__ == "__main__":
the_parser = argparse.ArgumentParser() the_parser = argparse.ArgumentParser()
# add subparsers # 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 to the parser
add_args(the_parser, the_subparsers) add_args(the_parser, the_subparsers)
@ -2432,7 +2432,8 @@ if __name__ == "__main__":
the_args = the_parser.parse_args() the_args = the_parser.parse_args()
# run # run
ret = the_args.func(the_args)
ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1
# return # return
sys.exit(ret) sys.exit(ret)

@ -16,7 +16,7 @@ import sys
import re import re
import pathlib import pathlib
import json import json
import cmake.Tools.registration as registration from o3de import registration
logger = logging.getLogger() logger = logging.getLogger()
logging.basicConfig() logging.basicConfig()
@ -153,7 +153,7 @@ if __name__ == "__main__":
the_parser = argparse.ArgumentParser() the_parser = argparse.ArgumentParser()
# add subparsers # 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 to the parser
add_args(the_parser, the_subparsers) add_args(the_parser, the_subparsers)
@ -162,7 +162,7 @@ if __name__ == "__main__":
the_args = the_parser.parse_args() the_args = the_parser.parse_args()
# run # run
ret = the_args.func(the_args) ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1
# return # return
sys.exit(ret) sys.exit(ret)

@ -128,7 +128,7 @@ def get_o3de_logs_folder() -> pathlib.Path:
return restricted_folder 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() engine_path = get_this_engine_path()
ret_val = 0 ret_val = 0
@ -137,7 +137,7 @@ def register_shipped_engine_o3de_objects() -> int:
starting_engines_directories = [ starting_engines_directories = [
] ]
for engines_directory in sorted(starting_engines_directories, reverse=True): 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: if error_code:
ret_val = error_code ret_val = error_code
@ -145,7 +145,7 @@ def register_shipped_engine_o3de_objects() -> int:
starting_engines = [ starting_engines = [
] ]
for engine_path in sorted(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: if error_code:
ret_val = error_code ret_val = error_code
@ -162,7 +162,7 @@ def register_shipped_engine_o3de_objects() -> int:
f'{engine_path}/AutomatedTesting' f'{engine_path}/AutomatedTesting'
] ]
for project_path in sorted(starting_projects, reverse=True): 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: if error_code:
ret_val = error_code ret_val = error_code
@ -179,7 +179,7 @@ def register_shipped_engine_o3de_objects() -> int:
starting_gems = [ starting_gems = [
] ]
for gem_path in sorted(starting_gems, reverse=True): 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: if error_code:
ret_val = error_code ret_val = error_code
@ -196,7 +196,7 @@ def register_shipped_engine_o3de_objects() -> int:
starting_templates = [ starting_templates = [
] ]
for template_path in sorted(starting_templates, reverse=True): 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: if error_code:
ret_val = error_code ret_val = error_code
@ -212,7 +212,7 @@ def register_shipped_engine_o3de_objects() -> int:
starting_restricted = [ starting_restricted = [
] ]
for restricted_path in sorted(starting_restricted, reverse=True): 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: if error_code:
ret_val = error_code ret_val = error_code
@ -228,12 +228,12 @@ def register_shipped_engine_o3de_objects() -> int:
starting_repos = [ starting_repos = [
] ]
for repo_uri in sorted(starting_repos, reverse=True): 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: if error_code:
ret_val = error_code ret_val = error_code
# register anything in the users default folders globally # 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: if error_code:
ret_val = error_code ret_val = error_code
error_code = register_all_projects_in_folder(get_registered(default_folder='projects')) 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_path = pathlib.Path(gem_path).resolve()
gem_cmake_lists_txt = gem_path / 'CMakeLists.txt' gem_cmake_lists_txt = gem_path / 'CMakeLists.txt'
if gem_cmake_lists_txt.is_file(): 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 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, 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: if not engines_path:
logger.error(f'Engines path cannot be empty.') logger.error(f'Engines path cannot be empty.')
return 1 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 root, dirs, files in os.walk(engines_path):
for name in files: for name in files:
if name == 'engine.json': if name == 'engine.json':
engines_set.add(name) engines_set.add(root)
for engine in sorted(engines_set, reverse=True): 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: if error_code:
ret_val = 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)}') 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, def register_engine_path(json_data: dict,
engine_path: str or pathlib.Path, engine_path: str or pathlib.Path,
remove: bool = False) -> int: remove: bool = False,
force: bool = False) -> int:
if not engine_path: if not engine_path:
logger.error(f'Engine path cannot be empty.') logger.error(f'Engine path cannot be empty.')
return 1 return 1
engine_path = pathlib.Path(engine_path).resolve() 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() engine_object_path = pathlib.Path(engine_object['path']).resolve()
if engine_object_path == engine_path: if engine_object_path == engine_path:
json_data['engines'].remove(engine_object) json_data['engines'].remove(engine_object)
if remove: if remove:
return 0 return remove_engine_name_to_path(json_data, engine_path)
if not engine_path.is_dir(): if not engine_path.is_dir():
logger.error(f'Engine path {engine_path} does not exist.') 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({'restricted': []})
engine_object.update({'external_subdirectories': []}) 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, 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_gems_folder: str or pathlib.Path = None,
default_templates_folder: str or pathlib.Path = None, default_templates_folder: str or pathlib.Path = None,
default_restricted_folder: str or pathlib.Path = None, default_restricted_folder: str or pathlib.Path = None,
remove: bool = False remove: bool = False,
force: bool = False
) -> int: ) -> int:
""" """
Adds/Updates entries to the .o3de/o3de_manifest.json 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_templates_folder: default templates folder
:param default_restricted_folder: default restricted code folder :param default_restricted_folder: default restricted code folder
:param remove: add/remove the entries :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 :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: if not engine_path:
logger.error(f'Engine path cannot be empty.') logger.error(f'Engine path cannot be empty.')
return 1 return 1
result = register_engine_path(json_data, engine_path, remove) result = register_engine_path(json_data, engine_path, remove, force)
if not result: if not result:
save_o3de_manifest(json_data) 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: engine_path: str or pathlib.Path = None, ) -> dict or None:
if not engine_name and not engine_path: if not engine_name and not engine_path:
logger.error('Must specify either a Engine name or Engine Path.') logger.error('Must specify either a Engine name or Engine Path.')
return 1 return None
if engine_name and not engine_path: if engine_name and not engine_path:
engine_path = get_registered(engine_name=engine_name) engine_path = get_registered(engine_name=engine_name)
if not engine_path: if not engine_path:
logger.error(f'Engine Path {engine_path} has not been registered.') logger.error(f'Engine Path {engine_path} has not been registered.')
return 1 return None
engine_path = pathlib.Path(engine_path).resolve() engine_path = pathlib.Path(engine_path).resolve()
engine_json = engine_path / 'engine.json' engine_json = engine_path / 'engine.json'
if not engine_json.is_file(): if not engine_json.is_file():
logger.error(f'Engine json {engine_json} is not present.') logger.error(f'Engine json {engine_json} is not present.')
return 1 return None
if not valid_o3de_engine_json(engine_json): if not valid_o3de_engine_json(engine_json):
logger.error(f'Engine json {engine_json} is not valid.') logger.error(f'Engine json {engine_json} is not valid.')
return 1 return None
with engine_json.open('r') as f: with engine_json.open('r') as f:
try: try:
@ -2155,23 +2202,23 @@ def get_project_data(project_name: str = None,
project_path: str or pathlib.Path = None, ) -> dict or None: project_path: str or pathlib.Path = None, ) -> dict or None:
if not project_name and not project_path: if not project_name and not project_path:
logger.error('Must specify either a Project name or Project Path.') logger.error('Must specify either a Project name or Project Path.')
return 1 return None
if project_name and not project_path: if project_name and not project_path:
project_path = get_registered(project_name=project_name) project_path = get_registered(project_name=project_name)
if not project_path: if not project_path:
logger.error(f'Project Path {project_path} has not been registered.') logger.error(f'Project Path {project_path} has not been registered.')
return 1 return None
project_path = pathlib.Path(project_path).resolve() project_path = pathlib.Path(project_path).resolve()
project_json = project_path / 'project.json' project_json = project_path / 'project.json'
if not project_json.is_file(): if not project_json.is_file():
logger.error(f'Project json {project_json} is not present.') logger.error(f'Project json {project_json} is not present.')
return 1 return None
if not valid_o3de_project_json(project_json): if not valid_o3de_project_json(project_json):
logger.error(f'Project json {project_json} is not valid.') logger.error(f'Project json {project_json} is not valid.')
return 1 return None
with project_json.open('r') as f: with project_json.open('r') as f:
try: try:
@ -2188,23 +2235,23 @@ def get_gem_data(gem_name: str = None,
gem_path: str or pathlib.Path = None, ) -> dict or None: gem_path: str or pathlib.Path = None, ) -> dict or None:
if not gem_name and not gem_path: if not gem_name and not gem_path:
logger.error('Must specify either a Gem name or Gem Path.') logger.error('Must specify either a Gem name or Gem Path.')
return 1 return None
if gem_name and not gem_path: if gem_name and not gem_path:
gem_path = get_registered(gem_name=gem_name) gem_path = get_registered(gem_name=gem_name)
if not gem_path: if not gem_path:
logger.error(f'Gem Path {gem_path} has not been registered.') logger.error(f'Gem Path {gem_path} has not been registered.')
return 1 return None
gem_path = pathlib.Path(gem_path).resolve() gem_path = pathlib.Path(gem_path).resolve()
gem_json = gem_path / 'gem.json' gem_json = gem_path / 'gem.json'
if not gem_json.is_file(): if not gem_json.is_file():
logger.error(f'Gem json {gem_json} is not present.') logger.error(f'Gem json {gem_json} is not present.')
return 1 return None
if not valid_o3de_gem_json(gem_json): if not valid_o3de_gem_json(gem_json):
logger.error(f'Gem json {gem_json} is not valid.') logger.error(f'Gem json {gem_json} is not valid.')
return 1 return None
with gem_json.open('r') as f: with gem_json.open('r') as f:
try: try:
@ -2221,23 +2268,23 @@ def get_template_data(template_name: str = None,
template_path: str or pathlib.Path = None, ) -> dict or None: template_path: str or pathlib.Path = None, ) -> dict or None:
if not template_name and not template_path: if not template_name and not template_path:
logger.error('Must specify either a Template name or Template Path.') logger.error('Must specify either a Template name or Template Path.')
return 1 return None
if template_name and not template_path: if template_name and not template_path:
template_path = get_registered(template_name=template_name) template_path = get_registered(template_name=template_name)
if not template_path: if not template_path:
logger.error(f'Template Path {template_path} has not been registered.') logger.error(f'Template Path {template_path} has not been registered.')
return 1 return None
template_path = pathlib.Path(template_path).resolve() template_path = pathlib.Path(template_path).resolve()
template_json = template_path / 'template.json' template_json = template_path / 'template.json'
if not template_json.is_file(): if not template_json.is_file():
logger.error(f'Template json {template_json} is not present.') logger.error(f'Template json {template_json} is not present.')
return 1 return None
if not valid_o3de_template_json(template_json): if not valid_o3de_template_json(template_json):
logger.error(f'Template json {template_json} is not valid.') logger.error(f'Template json {template_json} is not valid.')
return 1 return None
with template_json.open('r') as f: with template_json.open('r') as f:
try: try:
@ -2254,23 +2301,23 @@ def get_restricted_data(restricted_name: str = None,
restricted_path: str or pathlib.Path = None, ) -> dict or None: restricted_path: str or pathlib.Path = None, ) -> dict or None:
if not restricted_name and not restricted_path: if not restricted_name and not restricted_path:
logger.error('Must specify either a Restricted name or Restricted Path.') logger.error('Must specify either a Restricted name or Restricted Path.')
return 1 return None
if restricted_name and not restricted_path: if restricted_name and not restricted_path:
restricted_path = get_registered(restricted_name=restricted_name) restricted_path = get_registered(restricted_name=restricted_name)
if not restricted_path: if not restricted_path:
logger.error(f'Restricted Path {restricted_path} has not been registered.') logger.error(f'Restricted Path {restricted_path} has not been registered.')
return 1 return None
restricted_path = pathlib.Path(restricted_path).resolve() restricted_path = pathlib.Path(restricted_path).resolve()
restricted_json = restricted_path / 'restricted.json' restricted_json = restricted_path / 'restricted.json'
if not restricted_json.is_file(): if not restricted_json.is_file():
logger.error(f'Restricted json {restricted_json} is not present.') logger.error(f'Restricted json {restricted_json} is not present.')
return 1 return None
if not valid_o3de_restricted_json(restricted_json): if not valid_o3de_restricted_json(restricted_json):
logger.error(f'Restricted json {restricted_json} is not valid.') logger.error(f'Restricted json {restricted_json} is not valid.')
return 1 return None
with restricted_json.open('r') as f: with restricted_json.open('r') as f:
try: try:
@ -3259,30 +3306,30 @@ def get_gem_targets(gem_name: str = None,
def add_external_subdirectory(external_subdir: str or pathlib.Path, def add_external_subdirectory(external_subdir: str or pathlib.Path,
engine_path: str or pathlib.Path = None, engine_path: str or pathlib.Path = None,
supress_errors: bool = False) -> int: suppress_errors: bool = False) -> int:
""" """
add external subdirectory to a cmake add external subdirectory to a cmake
:param external_subdir: external subdirectory to add to cmake :param external_subdir: external subdirectory to add to cmake
:param engine_path: optional engine path, defaults to this engine :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 :return: 0 for success or non 0 failure code
""" """
external_subdir = pathlib.Path(external_subdir).resolve() external_subdir = pathlib.Path(external_subdir).resolve()
if not external_subdir.is_dir(): 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.') logger.error(f'Add External Subdirectory Failed: {external_subdir} does not exist.')
return 1 return 1
external_subdir_cmake = external_subdir / 'CMakeLists.txt' external_subdir_cmake = external_subdir / 'CMakeLists.txt'
if not external_subdir_cmake.is_file(): 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.') logger.error(f'Add External Subdirectory Failed: {external_subdir} does not contain a CMakeLists.txt.')
return 1 return 1
json_data = load_o3de_manifest() json_data = load_o3de_manifest()
engine_object = find_engine_data(json_data, engine_path) engine_object = find_engine_data(json_data, engine_path)
if not engine_object: if not engine_object:
if not supress_errors: if not suppress_errors:
logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.')
return 1 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()) engine_object['external_subdirectories'].remove(external_subdir.as_posix())
def parse_cmake_file(cmake: str or pathlib.Path, def parse_cmake_file(cmake: str or pathlib.Path,
files: set()): files: set):
cmake_path = pathlib.Path(cmake).resolve() cmake_path = pathlib.Path(cmake).resolve()
cmake_file = cmake_path cmake_file = cmake_path
if cmake_path.is_dir(): 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: if external_subdir in cmake_files:
save_o3de_manifest(json_data) 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().') logger.error(f'External subdirectory {external_subdir.as_posix()} already included by add_subdirectory().')
return 1 return 1
@ -3374,18 +3421,18 @@ def add_gem_to_cmake(gem_name: str = None,
gem_path: str or pathlib.Path = None, gem_path: str or pathlib.Path = None,
engine_name: str = None, engine_name: str = None,
engine_path: str or pathlib.Path = 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 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_name: name of the gem to add to cmake
:param gem_path: the path 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_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 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 :return: 0 for success or non 0 failure code
""" """
if not gem_name and not gem_path: 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.') logger.error('Must specify either a Gem name or Gem Path.')
return 1 return 1
@ -3393,18 +3440,18 @@ def add_gem_to_cmake(gem_name: str = None,
gem_path = get_registered(gem_name=gem_name) gem_path = get_registered(gem_name=gem_name)
if not gem_path: if not gem_path:
if not supress_errors: if not suppress_errors:
logger.error(f'Gem Path {gem_path} has not been registered.') logger.error(f'Gem Path {gem_path} has not been registered.')
return 1 return 1
gem_path = pathlib.Path(gem_path).resolve() gem_path = pathlib.Path(gem_path).resolve()
gem_json = gem_path / 'gem.json' gem_json = gem_path / 'gem.json'
if not gem_json.is_file(): if not gem_json.is_file():
if not supress_errors: if not suppress_errors:
logger.error(f'Gem json {gem_json} is not present.') logger.error(f'Gem json {gem_json} is not present.')
return 1 return 1
if not valid_o3de_gem_json(gem_json): 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.') logger.error(f'Gem json {gem_json} is not valid.')
return 1 return 1
@ -3415,21 +3462,21 @@ def add_gem_to_cmake(gem_name: str = None,
engine_path = get_registered(engine_name=engine_name) engine_path = get_registered(engine_name=engine_name)
if not engine_path: if not engine_path:
if not supress_errors: if not suppress_errors:
logger.error(f'Engine Path {engine_path} has not been registered.') logger.error(f'Engine Path {engine_path} has not been registered.')
return 1 return 1
engine_json = engine_path / 'engine.json' engine_json = engine_path / 'engine.json'
if not engine_json.is_file(): if not engine_json.is_file():
if not supress_errors: if not suppress_errors:
logger.error(f'Engine json {engine_json} is not present.') logger.error(f'Engine json {engine_json} is not present.')
return 1 return 1
if not valid_o3de_engine_json(engine_json): 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.') logger.error(f'Engine json {engine_json} is not valid.')
return 1 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, def remove_gem_from_cmake(gem_name: str = None,
@ -3930,13 +3977,13 @@ def _run_register(args: argparse) -> int:
remove_invalid_o3de_objects() remove_invalid_o3de_objects()
return refresh_repos() return refresh_repos()
elif args.this_engine: elif args.this_engine:
ret_val = register(engine_path=get_this_engine_path()) ret_val = register(engine_path=get_this_engine_path(), force=args.force)
error_code = register_shipped_engine_o3de_objects() error_code = register_shipped_engine_o3de_objects(force=args.force)
if error_code: if error_code:
ret_val = error_code ret_val = error_code
return ret_val return ret_val
elif args.all_engines_path: 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: elif args.all_projects_path:
return register_all_projects_in_folder(args.all_projects_path, args.remove) return register_all_projects_in_folder(args.all_projects_path, args.remove)
elif args.all_gems_path: elif args.all_gems_path:
@ -3959,7 +4006,8 @@ def _run_register(args: argparse) -> int:
default_gems_folder=args.default_gems_folder, default_gems_folder=args.default_gems_folder,
default_templates_folder=args.default_templates_folder, default_templates_folder=args.default_templates_folder,
default_restricted_folder=args.default_restricted_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: 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, register_subparser.add_argument('-r', '--remove', action='store_true', required=False,
default=False, default=False,
help='Remove entry.') 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) register_subparser.set_defaults(func=_run_register)
# show # show
@ -4366,7 +4416,7 @@ if __name__ == "__main__":
the_parser = argparse.ArgumentParser() the_parser = argparse.ArgumentParser()
# add subparsers # 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 to the parser
add_args(the_parser, the_subparsers) add_args(the_parser, the_subparsers)
@ -4375,7 +4425,7 @@ if __name__ == "__main__":
the_args = the_parser.parse_args() the_args = the_parser.parse_args()
# run # run
ret = the_args.func(the_args) ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1
# return # return
sys.exit(ret) sys.exit(ret)

@ -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={
},
)

@ -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
)

@ -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.
#

@ -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

@ -29,12 +29,11 @@ executable_path = ''
logger = logging.getLogger() logger = logging.getLogger()
logger.setLevel(logging.INFO) logger.setLevel(logging.INFO)
from cmake.Tools import engine_template from o3de import engine_template, registration
from cmake.Tools import registration
o3de_folder = registration.get_o3de_folder() o3de_folder = registration.get_o3de_folder()
o3de_logs_folder = registration.get_o3de_logs_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) log_file_handler = RotatingFileHandler(filename=project_manager_log_file_path, maxBytes=1024 * 1024, backupCount=1)
formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s') formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s')
log_file_handler.setFormatter(formatter) log_file_handler.setFormatter(formatter)

Loading…
Cancel
Save