Register show command fix (#2408)

* Updated print_registration functions to fix "register-show" command

Added unit test to validate the argparse options to the register show
command.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated the register.py script to once again register an engine list

Previosly each engine were registered into a dictionary with multiple
keys, but once the engine.json started to self describe the registered
content that came with it, it was reduced to a single 'path' key.
Therefore it has been changed to a list to be consistent with other o3de
object paths

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated the SettingsRegistryMergeUtitls Code which parses the attempts to locate the engine path associated associated with the project.json engine key to check the 'engines_path' object within the o3de_manifest.json

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Updated print registration unit test to patch the get_project_path

This is to make sure that the existence of the placeholder project path
isn't validated when running the test

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Typo and formatting fixes for the print_registration script

Also corrected indentation in unit_test_print_registration script

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
This commit is contained in:
lumberyard-employee-dm
2021-07-28 16:21:37 -05:00
committed by GitHub
parent 567b4a7f28
commit 055df37482
6 changed files with 591 additions and 186 deletions
@@ -57,6 +57,7 @@ namespace AZ::Internal
// and avoid all this logic.
using namespace AZ::SettingsRegistryMergeUtils;
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
AZ::IO::FixedMaxPath engineRoot;
if (auto engineManifestPath = AZ::Utils::GetEngineManifestPath(); !engineManifestPath.empty())
@@ -72,45 +73,16 @@ namespace AZ::Internal
struct EngineInfo
{
AZ::IO::FixedMaxPath m_path;
AZ::SettingsRegistryInterface::FixedValueString m_moniker;
FixedValueString m_moniker;
};
struct EnginePathsVisitor : public AZ::SettingsRegistryInterface::Visitor
{
void Visit(
[[maybe_unused]] AZStd::string_view path, [[maybe_unused]] AZStd::string_view valueName,
[[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName,
[[maybe_unused]] AZ::SettingsRegistryInterface::Type type, AZStd::string_view value) override
{
m_enginePaths.emplace_back(EngineInfo{AZ::IO::FixedMaxPath{value}.LexicallyNormal(), {}});
}
AZ::SettingsRegistryInterface::VisitResponse Traverse(
[[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName,
AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type type) override
{
auto response = AZ::SettingsRegistryInterface::VisitResponse::Continue;
if (action == AZ::SettingsRegistryInterface::VisitAction::Begin)
{
if (type == AZ::SettingsRegistryInterface::Type::Array)
{
if (valueName.compare("engines") != 0)
{
response = AZ::SettingsRegistryInterface::VisitResponse::Skip;
}
}
}
else if (action == AZ::SettingsRegistryInterface::VisitAction::Value)
{
if (type == AZ::SettingsRegistryInterface::Type::String)
{
if (valueName.compare("path") != 0)
{
response = AZ::SettingsRegistryInterface::VisitResponse::Skip;
}
}
}
return response;
m_enginePaths.emplace_back(EngineInfo{ AZ::IO::FixedMaxPath{value}.LexicallyNormal(), FixedValueString{valueName} });
}
AZStd::vector<EngineInfo> m_enginePaths{};
@@ -119,11 +91,11 @@ namespace AZ::Internal
EnginePathsVisitor pathVisitor;
if (manifestLoaded)
{
auto enginePathsKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engines", EngineManifestRootKey);
auto enginePathsKey = FixedValueString::format("%s/engines_path", EngineManifestRootKey);
settingsRegistry.Visit(pathVisitor, enginePathsKey);
}
const auto engineMonikerKey = AZ::SettingsRegistryInterface::FixedValueString::format("%s/engine_name", EngineSettingsRootKey);
const auto engineMonikerKey = FixedValueString::format("%s/engine_name", EngineSettingsRootKey);
AZStd::set<AZ::IO::FixedMaxPath> projectPathsNotFound;
@@ -135,7 +107,15 @@ namespace AZ::Internal
if (settingsRegistry.MergeSettingsFile(
engineSettingsPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, EngineSettingsRootKey))
{
settingsRegistry.Get(engineInfo.m_moniker, engineMonikerKey);
FixedValueString engineName;
settingsRegistry.Get(engineName, engineMonikerKey);
AZ_Warning("SettingsRegistryMergeUtils",engineInfo.m_moniker == engineName,
R"(The engine name key "%s" mapped to engine path "%s" within the global manifest of "%s")"
R"( does not match the "engine_name" field "%s" in the engine.json)" "\n"
"This engine should be re-registered.",
engineInfo.m_moniker.c_str(), engineInfo.m_path.c_str(), engineManifestPath.c_str(),
engineName.c_str())
engineInfo.m_moniker = engineName;
}
}
+12 -23
View File
@@ -236,15 +236,13 @@ def get_gems_from_subdirectories(external_subdirs: list) -> list:
# Data query methods
def get_this_engine() -> dict:
json_data = load_o3de_manifest()
engine_data = find_engine_data(json_data)
return engine_data
def get_engines() -> list:
json_data = load_o3de_manifest()
return json_data['engines'] if 'engines' in json_data else []
engine_list = json_data['engines'] if 'engines' in json_data else []
# Convert each engine dict entry into a string entry
return list(map(
lambda engine_object: engine_object.get('path', '') if isinstance(engine_object, dict) else engine_object,
engine_list))
def get_projects() -> list:
@@ -424,20 +422,6 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa
return list(filter(filter_project_and_gem_templates_out, get_all_templates()))
def find_engine_data(json_data: dict,
engine_path: str or pathlib.Path = None) -> dict or None:
if not engine_path:
engine_path = get_this_engine_path()
engine_path = pathlib.Path(engine_path).resolve()
for engine_object in json_data['engines']:
engine_object_path = pathlib.Path(engine_object['path']).resolve()
if engine_path == engine_object_path:
return engine_object
return None
def get_engine_json_data(engine_name: str = None,
engine_path: str or pathlib.Path = None) -> dict or None:
if not engine_name and not engine_path:
@@ -639,8 +623,13 @@ def get_registered(engine_name: str = None,
# check global first then this engine
if isinstance(engine_name, str):
for engine in json_data['engines']:
engine_path = pathlib.Path(engine['path']).resolve()
engines = get_engines()
for engine in engines:
if isinstance(engine, dict):
engine_path = pathlib.Path(engine['path']).resolve()
else:
engine_path = pathlib.Path(engine_object).resolve()
engine_json = engine_path / 'engine.json'
with engine_json.open('r') as f:
try:
+145 -76
View File
@@ -40,61 +40,67 @@ def get_project_path(project_path: pathlib.Path, project_name: str) -> pathlib.P
def print_this_engine(verbose: int) -> int:
engine_data = manifest.get_this_engine()
print(json.dumps(engine_data, indent=4))
result = True
this_engine_path = manifest.get_this_engine_path()
print(f'This Engine:\n{json.dumps(str(this_engine_path), indent=4)}')
if verbose > 0:
result = print_manifest_json_data(engine_data, 'engine.json', 'This Engine',
return print_manifest_json_data([this_engine_path], 'This Engine',
manifest.get_engine_json_data, 'engine_path')
return 0 if result else 1
return 0
def print_engines(verbose: int) -> None:
engines_data = manifest.get_engines()
print(json.dumps(engines_data, indent=4))
print(f'Engine Paths:\n{json.dumps(engines_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(engines_data, 'engine.json', 'Engines',
return print_manifest_json_data(engines_data, 'Engine Jsons',
manifest.get_engine_json_data, 'engine_path')
return 0
def print_projects(verbose: int) -> int:
projects_data = manifest.get_projects()
print(json.dumps(projects_data, indent=4))
print(f'Project Paths:\n{json.dumps(projects_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(projects_data, 'project.json', 'Projects',
return print_manifest_json_data(projects_data, 'Project Jsons',
manifest.get_project_json_data, 'project_path')
return 0
def print_gems(verbose: int) -> int:
gems_data = manifest.get_gems()
print(json.dumps(gems_data, indent=4))
print(f'Gem Paths:\n{json.dumps(gems_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(gems_data, 'gem.json', 'Gems',
return print_manifest_json_data(gems_data, 'Gem Jsons',
manifest.get_gem_json_data, 'gem_path')
return 0
def print_external_subdirectories(verbose: int) -> int:
external_subdirs_data = manifest.get_external_subdirectories()
print(f'External Subdirectories:\n{json.dumps(external_subdirs_data, indent=4)}')
return 0
def print_templates(verbose: int) -> int:
templates_data = manifest.get_templates()
print(json.dumps(templates_data, indent=4))
print(f'Template Paths:\n{json.dumps(templates_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(templates_data, 'template.json', 'Templates',
return print_manifest_json_data(templates_data, 'Template Jsons',
manifest.get_template_json_data, 'template_path')
return 0
def print_restricted(verbose: int) -> int:
restricted_data = manifest.get_restricted()
print(json.dumps(restricted_data, indent=4))
print(f'Restricted Paths:\n{json.dumps(restricted_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(restricted_data, 'restricted.json', 'Restricted',
return print_manifest_json_data(restricted_data, 'Restricted Jsons',
manifest.get_restricted_json_data, 'restricted_path')
return 0
@@ -102,47 +108,47 @@ def print_restricted(verbose: int) -> int:
# Engine output methods
def print_engine_projects(verbose: int) -> int:
engine_projects_data = manifest.get_engine_projects()
print(json.dumps(engine_projects_data, indent=4))
print(f'Project Paths:\n{json.dumps(engine_projects_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(engine_projects_data, 'project.json', 'Projects',
return print_manifest_json_data(engine_projects_data, 'Project Jsons',
manifest.get_project_json_data, 'project_path')
return 0
def print_engine_gems(verbose: int) -> int:
engine_gems_data = manifest.get_engine_gems()
print(json.dumps(engine_gems_data, indent=4))
print(f'Gem Paths:\n{json.dumps(engine_gems_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(engine_gems_data, 'gem.json', 'Gems',
return print_manifest_json_data(engine_gems_data, 'Gem Jsons',
manifest.get_gem_json_data, 'gem_path')
return 0
def print_engine_templates(verbose: int) -> int:
engine_templates_data = manifest.get_engine_templates()
print(json.dumps(engine_templates_data, indent=4))
print(f'Template Paths:\n{json.dumps(engine_templates_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(engine_templates_data, 'template.json', 'Templates',
return print_manifest_json_data(engine_templates_data, 'Template Jsons',
manifest.get_template_json_data, 'template_path')
return 0
def print_engine_restricted(verbose: int) -> int:
engine_restricted_data = manifest.get_engine_restricted()
print(json.dumps(engine_restricted_data, indent=4))
print(f'Restricted Paths:\n{json.dumps(engine_restricted_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(engine_restricted_data, 'restricted.json', 'Restricted',
return print_manifest_json_data(engine_restricted_data, 'Restricted Jsons',
manifest.get_restricted_json_data, 'restricted_path')
return 0
def print_engine_external_subdirectories() -> int:
def print_engine_external_subdirectories(verbose: int) -> int:
external_subdirs_data = manifest.get_engine_external_subdirectories()
print(json.dumps(external_subdirs_data, indent=4))
print(f'External Subdirectories:\n{json.dumps(external_subdirs_data, indent=4)}')
return 0
@@ -153,21 +159,21 @@ def print_project_gems(verbose: int, project_path: pathlib.Path, project_name: s
return 1
project_gems_data = manifest.get_project_gems(project_path)
print(json.dumps(project_gems_data, indent=4))
print(f'Gem Paths:\n{json.dumps(project_gems_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(project_gems_data, 'gem.json', 'Gems',
return print_manifest_json_data(project_gems_data, 'Gems Jsons',
manifest.get_gem_json_data, 'gem_path')
return 0
def print_project_external_subdirectories(project_path: pathlib.Path, project_name: str) -> int:
def print_project_external_subdirectories(verbose: int, project_path: pathlib.Path, project_name: str) -> int:
project_path = get_project_path(project_path, project_name)
if not project_path:
return 1
external_subdirs_data = manifest.get_project_external_subdirectories(project_path)
print(json.dumps(external_subdirs_data, indent=4))
print(f'External Subdirectories:\n{json.dumps(external_subdirs_data, indent=4)}')
return 0
@@ -177,9 +183,9 @@ def print_project_templates(verbose: int, project_path: pathlib.Path, project_na
return 1
project_templates_data = manifest.get_project_templates(project_path)
print(json.dumps(project_templates_data, indent=4))
print(f'Template Paths:\n{json.dumps(project_templates_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(project_templates_data, 'template.json', 'Templates',
return print_manifest_json_data(project_templates_data, 'Template Jsons',
manifest.get_template_json_data, 'template_path')
return 0
@@ -190,73 +196,118 @@ def print_project_restricted(verbose: int, project_path: pathlib.Path, project_n
return 1
project_restricted_data = manifest.get_project_restricted(project_path)
print(json.dumps(project_restricted_data, indent=4))
print(f'Restricted Paths:\n{json.dumps(project_restricted_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(project_restricted_data, 'restricted.json', 'Restricted',
return print_manifest_json_data(project_restricted_data, 'Restricted Jsons',
manifest.get_restricted_json_data, 'restricted_path')
return 0
def print_all_projects(verbose: int) -> int:
all_projects_data = manifest.get_all_projects()
print(json.dumps(all_projects_data, indent=4))
print(f'Project Paths:\n{json.dumps(all_projects_data, indent=4)}')
if verbose > 0:
return print_manifest_json_data(all_projects_data, 'project.json', 'Projects',
return print_manifest_json_data(all_projects_data, 'Project Jsons',
manifest.get_project_json_data, 'project_path')
return 0
def print_all_gems(verbose: int) -> int:
all_gems_data = manifest.get_all_gems()
print(json.dumps(all_gems_data, indent=4))
def print_all_gems(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int:
all_gems = manifest.get_gems()
all_gems.extend(manifest.get_engine_gems())
# If a project path or project name is supplied query the gems from that project, otherwise query the gems from
# all projects
project_path = get_project_path(project_path, project_name) if project_path or project_name else None
projects = [project_path] if project_path else manifest.get_all_projects()
for project in projects:
all_gems.extend(manifest.get_project_gems(project))
# Filter out duplicates
all_gems = list(dict.fromkeys(all_gems))
print(f'Gem Paths:\n{json.dumps(all_gems, indent=4)}')
if verbose > 0:
return print_manifest_json_data(all_gems_data, 'gem.json', 'Gems',
return print_manifest_json_data(all_gems, 'Gem Jsons',
manifest.get_gem_json_data, 'gem_path')
return 0
def print_all_external_subdirectories() -> int:
all_external_subdirectories_data = manifest.get_all_external_subdirectories()
print(json.dumps(all_external_subdirectories_data, indent=4))
def print_all_external_subdirectories(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int:
all_external_subdirectories = manifest.get_external_subdirectories()
all_external_subdirectories.extend(manifest.get_engine_external_subdirectories())
# If a project path or project name is supplied query the external subdirectories from that project,
# otherwise query the external subdirectories from all projects
project_path = get_project_path(project_path, project_name) if project_path or project_name else None
projects = [project_path] if project_path else manifest.get_all_projects()
for project in projects:
all_external_subdirectories.extend(manifest.get_project_external_subdirectories(project))
# Filter out duplicates
all_external_subdirectories = list(dict.fromkeys(all_external_subdirectories))
print(f'External Subdirectories:\n{json.dumps(all_external_subdirectories, indent=4)}')
return 0
def print_all_templates(verbose: int) -> int:
all_templates_data = manifest.get_all_templates()
print(json.dumps(all_templates_data, indent=4))
def print_all_templates(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int:
all_templates = manifest.get_templates()
all_templates.extend(manifest.get_engine_templates())
# If a project path or project name is supplied query the templates from that project,
# otherwise query the templates from all projects
project_path = get_project_path(project_path, project_name) if project_path or project_name else None
projects = [project_path] if project_path else manifest.get_all_projects()
for project in projects:
all_templates.extend(manifest.get_project_templates(project))
# Filter out duplicates
all_templates = list(dict.fromkeys(all_templates))
print(f'Template Paths:\n{json.dumps(all_templates, indent=4)}')
if verbose > 0:
return print_manifest_json_data(all_templates_data, 'template.json', 'Templates',
return print_manifest_json_data(all_templates, 'Template Jsons',
manifest.get_template_json_data, 'template_path')
return 0
def print_all_restricted(verbose: int) -> int:
all_restricted_data = manifest.get_all_restricted()
print(json.dumps(all_restricted_data, indent=4))
def print_all_restricted(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int:
all_restricted = manifest.get_restricted()
all_restricted.extend(manifest.get_engine_restricted())
# If a project path or project name is supplied query the restricted from that project,
# otherwise query the restricted from all projects
project_path = get_project_path(project_path, project_name) if project_path or project_name else None
projects = [project_path] if project_path else manifest.get_all_projects()
for project in projects:
all_restricted.extend(manifest.get_project_restricted(project))
# Filter out duplicates
all_restricted = list(dict.fromkeys(all_restricted))
print(f'Restricted Paths:\n{json.dumps(all_restricted, indent=4)}')
if verbose > 0:
return print_manifest_json_data(all_restricted_data, 'restricted.json', 'Restricted',
return print_manifest_json_data(all_restricted, 'Restricted Jsons',
manifest.get_restricted_json_data, 'restricted_path')
return 0
def print_manifest_json_data(uri_json_data: dict, json_filename: str,
def print_manifest_json_data(uri_json_data: list,
print_prefix: str, get_json_func: callable, get_json_data_kw: str) -> int:
print('\n')
print(f"{print_prefix}================================================")
for manifest_uri in uri_json_data:
# if it's not local it should be in the cache
parsed_uri = urllib.parse.urlparse(manifest_uri)
parsed_uri = urllib.parse.urlparse(pathlib.Path(manifest_uri).as_posix())
if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']:
repo_sha256 = hashlib.sha256(manifest_uri.encode())
cache_folder = manifest.get_o3de_cache_folder()
manifest_json_path = cache_folder / str(repo_sha256.hexdigest() + '.json')
else:
manifest_json_path = pathlib.Path(manifest_uri).resolve() / json_filename
manifest_json_path = pathlib.Path(manifest_uri).resolve()
json_data = get_json_func(**{get_json_data_kwargs: manifest_json_path})
json_data = get_json_func(**{get_json_data_kw: manifest_json_path})
if json_data:
print(manifest_json_path)
print(json.dumps(json_data, indent=4) + '\n')
@@ -284,29 +335,30 @@ def print_repos_data(repos_data: dict) -> int:
return 0
def register_show_repos(verbose: int) -> None:
def print_repos(verbose: int) -> int:
repos_data = manifest.get_repos()
print(json.dumps(repos_data, indent=4))
if verbose > 0:
return print_repos_data(repos_data) == 0
return print_repos_data(repos_data)
return 0
def register_show(verbose: int) -> None:
def register_show(verbose: int, project_path: pathlib.Path = None, project_name: str = None) -> int:
json_data = manifest.load_o3de_manifest()
print(f"{manifest.get_o3de_manifest()}:")
print(json.dumps(json_data, indent=4))
result = True
result = 0
if verbose > 0:
result = print_manifest_json_data(manifest.get_engines()) == 0 and result
result = print_manifest_json_data(manifest.get_all_projects()) == 0 and result
result = print_manifest_json_data(manifest.get_gems()) == 0 and result
result = print_manifest_json_data(manifest.get_all_templates()) == 0 and result
result = print_manifest_json_data(manifest.get_all_restricted()) == 0 and result
result = print_repos_data(manifest.get_repos()) == 0 and result
return 0 if result else 1
result = print_engines(verbose) or result
result = print_all_projects(verbose) or result
result = print_all_gems(verbose, project_path, project_name) or result
result = print_all_templates(verbose, project_path, project_name) or result
result = print_all_restricted(verbose, project_path, project_name) or result
result = print_repos(verbose) or result
return result
def _run_register_show(args: argparse) -> int:
@@ -321,6 +373,8 @@ def _run_register_show(args: argparse) -> int:
return print_projects(args.verbose)
elif args.gems:
return print_gems(args.verbose)
elif args.external_subdirectories:
return print_external_subdirectories(args.verbose)
elif args.templates:
return print_templates(args.verbose)
elif args.repos:
@@ -333,7 +387,7 @@ def _run_register_show(args: argparse) -> int:
elif args.engine_gems:
return print_engine_gems(args.verbose)
elif args.engine_external_subdirectories:
return print_engine_external_subdirectories()
return print_engine_external_subdirectories(args.verbose)
elif args.engine_templates:
return print_engine_templates(args.verbose)
elif args.engine_restricted:
@@ -342,7 +396,7 @@ def _run_register_show(args: argparse) -> int:
elif args.project_gems:
return print_project_gems(args.verbose, args.project_path, args.project_name)
elif args.project_external_subdirectories:
return print_project_external_subdirectories(args.project_path, args.project_name)
return print_project_external_subdirectories(args.verbose, args.project_path, args.project_name)
elif args.project_templates:
return print_project_templates(args.verbose, args.project_path, args.project_name)
elif args.project_restricted:
@@ -351,16 +405,16 @@ def _run_register_show(args: argparse) -> int:
elif args.all_projects:
return print_all_projects(args.verbose)
elif args.all_gems:
return print_all_gems(args.verbose)
return print_all_gems(args.verbose, args.project_path, args.project_name)
elif args.all_external_subdirectories:
return print_all_external_subdirectories()
return print_all_external_subdirectories(args.verbose, args.project_path, args.project_name)
elif args.all_templates:
return print_all_templates(args.verbose)
return print_all_templates(args.verbose, args.project_path, args.project_name)
elif args.all_restricted:
return print_all_restricted(args.verbose)
return print_all_restricted(args.verbose, args.project_path, args.project_name)
else:
return register_show(args.verbose)
return register_show(args.verbose, args.project_path, args.project_name)
def add_parser_args(parser):
@@ -393,6 +447,9 @@ def add_parser_args(parser):
group.add_argument('-rs', '--restricted', action='store_true', required=False,
default=False,
help='Output the restricted directories registered in the global ~/.o3de/o3de_manifest.json.')
group.add_argument('-es', '--external-subdirectories', action='store_true', required=False,
default=False,
help='Output the external subdirectories registered in the global ~/.o3de/o3de_manifest.json.')
group.add_argument('-ep', '--engine-projects', action='store_true', required=False,
default=False,
@@ -428,16 +485,28 @@ def add_parser_args(parser):
help='Output all projects registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos.')
group.add_argument('-ag', '--all-gems', action='store_true', required=False,
default=False,
help='Output all gems registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos')
help='Output all gems registered in the ~/.o3de/o3de_manifest.json and the current engine.json.'
' If --project-path or --project-name option is supplied, outputs gems registered in'
' that project\'s project.json otherwise outputs registered gems from all registered projects.'
' Ignores repos')
group.add_argument('-at', '--all-templates', action='store_true', required=False,
default=False,
help='Output all templates registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos.')
help='Output all templates registered in the ~/.o3de/o3de_manifest.json and the current engine.json.'
' If --project-path or --project-name option is supplied, outputs templates registered in'
' that project\'s project.json otherwise outputs registered templates from all registered'
' projects. Ignores repos')
group.add_argument('-ares', '--all-restricted', action='store_true', required=False,
default=False,
help='Output all restricted directory registered in the ~/.o3de/o3de_manifest.json and the current engine.json.')
help='Output all restricted directory registered in the ~/.o3de/o3de_manifest.json and the current engine.json.'
' If --project-path or --project-name option is supplied, outputs restricted'
' directories registered in that project\'s project.json otherwise outputs restricted'
' directories registered from all registered projects. Ignores repos')
group.add_argument('-aes', '--all-external-subdirectories', action='store_true',
default=False,
help='Output all external subdirectories registered in the ~/.o3de/o3de_manifest.json and the current engine.json.')
help='Output all external subdirectories registered in the ~/.o3de/o3de_manifest.json and the current engine.json.'
' If --project-path or --project-name options is supplied, outputs external'
' subdirectories registered in that project\'s project.json otherwise outputs external'
' subdirectories registered from all registered projects. Ignores repos')
parser.add_argument('-v', '--verbose', action='count', required=False,
default=0,
+28 -51
View File
@@ -261,43 +261,6 @@ def add_engine_name_to_path(json_data: dict, engine_path: pathlib.Path, force: b
return 0
def register_engine_path(json_data: dict,
engine_path: pathlib.Path,
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.get('engines', []):
if isinstance(engine_object, dict):
engine_object_path = pathlib.Path(engine_object['path']).resolve()
else:
engine_object_path = pathlib.Path(engine_object).resolve()
if engine_object_path == engine_path:
json_data['engines'].remove(engine_object)
if remove:
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.')
return 1
engine_json = engine_path / 'engine.json'
if not validation.valid_o3de_engine_json(engine_json):
logger.error(f'Engine json {engine_json} is not valid.')
return 1
engine_object = {}
engine_object.update({'path': engine_path.as_posix()})
json_data.setdefault('engines', []).insert(0, engine_object)
return add_engine_name_to_path(json_data, engine_path, force)
def register_o3de_object_path(json_data: dict,
o3de_object_path: str or pathlib.Path,
o3de_object_key: str,
@@ -343,7 +306,7 @@ def register_o3de_object_path(json_data: dict,
try:
paths_to_remove.append(o3de_object_path.relative_to(save_path.parent))
except ValueError:
pass # It is OK relative path cannot be formed
pass # It is not an error if a relative path cannot be formed
manifest_data[o3de_object_key] = list(filter(lambda p: pathlib.Path(p) not in paths_to_remove,
manifest_data.setdefault(o3de_object_key, [])))
@@ -358,7 +321,7 @@ def register_o3de_object_path(json_data: dict,
manifest_json_path = o3de_object_path / o3de_json_filename
if validation_func and not validation_func(manifest_json_path):
logger.error(f'o3de json {manifest_json_path} is not valid.')
logger.error(f'Manifest at path {manifest_json_path} is not valid.')
return 1
# if there is a save path make it relative the directory containing o3de object json file
@@ -374,6 +337,27 @@ def register_o3de_object_path(json_data: dict,
return 0
def register_engine_path(json_data: dict,
engine_path: pathlib.Path,
remove: bool = False,
force: bool = False) -> int:
# If the o3de_manifest.json 'engines' key is list containing dictionary entries, transform it to a list of strings
engine_list = json_data.get('engines', [])
def transform_engine_dict_to_string(engine): return engine.get('path', '') if isinstance(engine, dict) else engine
json_data['engines'] = list(map(transform_engine_dict_to_string, engine_list))
result = register_o3de_object_path(json_data, engine_path, 'engines', 'engine.json',
validation.valid_o3de_engine_json, remove)
if result != 0:
return result
if remove:
return remove_engine_name_to_path(json_data, engine_path)
return add_engine_name_to_path(json_data, engine_path, force)
def register_external_subdirectory(json_data: dict,
external_subdir_path: pathlib.Path,
remove: bool = False,
@@ -677,37 +661,30 @@ def remove_invalid_o3de_projects(manifest_path: pathlib.Path = None) -> int:
return result
def remove_invalid_o3de_objects() -> None:
json_data = manifest.load_o3de_manifest()
for engine_object in json_data.get('engines', []):
engine_path = engine_object.get('path', '')
for engine_path in manifest.get_engines():
if not validation.valid_o3de_engine_json(pathlib.Path(engine_path).resolve() / 'engine.json'):
logger.warn(f"Engine path {engine_path} is invalid.")
register(engine_path=engine_path, remove=True)
remove_invalid_o3de_projects()
for gem in json_data.get('gems', []):
if not validation.valid_o3de_gem_json(pathlib.Path(gem).resolve() / 'gem.json'):
logger.warn(f"Gem path {gem} is invalid.")
register(gem_path=gem, remove=True)
for external in json_data.get('external_subdirectories', []):
for external in manifest.get_external_subdirectories():
external = pathlib.Path(external).resolve()
if not external.is_dir():
logger.warn(f"External subdirectory {external} is invalid.")
register(engine_path=engine_path, external_subdir_path=external, remove=True)
for template in json_data.get('templates', []):
for template in manifest.get_templates():
if not validation.valid_o3de_template_json(pathlib.Path(template).resolve() / 'template.json'):
logger.warn(f"Template path {template} is invalid.")
register(template_path=template, remove=True)
for restricted in json_data.get('restricted', []):
for restricted in manifest.get_restricted():
if not validation.valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'):
logger.warn(f"Restricted path {restricted} is invalid.")
register(restricted_path=restricted, remove=True)
json_data = manifest.load_o3de_manifest()
default_engines_folder = pathlib.Path(json_data.get('default_engines_folder', manifest.get_o3de_engines_folder())).resolve()
if not default_engines_folder.is_dir():
new_default_engines_folder = manifest.get_o3de_folder() / 'Engines'
+8 -1
View File
@@ -65,4 +65,11 @@ ly_add_pytest(
PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_engine_template.py
TEST_SUITE smoke
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
)
)
ly_add_pytest(
NAME o3de_register_show
PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_print_registration.py
TEST_SUITE smoke
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
)
@@ -0,0 +1,383 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
import argparse
import json
import logging
import pytest
import pathlib
from unittest.mock import patch
from o3de import print_registration
TEST_PROJECT_JSON_PAYLOAD = '''
{
"project_name": "MinimalProject",
"origin": "The primary repo for MinimalProject goes here: i.e. http://www.mydomain.com",
"license": "What license MinimalProject uses goes here: i.e. https://opensource.org/licenses/MIT",
"display_name": "MinimalProject",
"summary": "A short description of MinimalProject.",
"canonical_tags": [
"Project"
],
"user_tags": [
"MinimalProject"
],
"icon_path": "preview.png",
"engine": "o3de-install",
"external_subdirectories": [
"D:/TestGem"
]
}
'''
TEST_ENGINE_JSON_PAYLOAD = '''
{
"engine_name": "o3de",
"restricted_name": "o3de",
"FileVersion": 1,
"O3DEVersion": "0.0.0.0",
"O3DECopyrightYear": 2021,
"O3DEBuildNumber": 0,
"external_subdirectories": [
"Gems/TestGem2"
],
"projects": [
],
"templates": [
"Templates/MinimalProject"
]
}
'''
TEST_GEM_JSON_PAYLOAD = '''
{
"gem_name": "TestGem",
"display_name": "TestGem",
"license": "What license TestGem uses goes here: i.e. https://opensource.org/licenses/MIT",
"origin": "The primary repo for TestGem goes here: i.e. http://www.mydomain.com",
"type": "Code",
"summary": "A short description of TestGem.",
"canonical_tags": [
"Gem"
],
"user_tags": [
"TestGem"
],
"icon_path": "preview.png",
"requirements": ""
}
'''
TEST_TEMPLATE_JSON_PAYLOAD = '''
{
"template_name": "AssetGem",
"origin": "The primary repo for AssetGem goes here: i.e. http://www.mydomain.com",
"license": "What license AssetGem uses goes here: i.e. https://opensource.org/licenses/MIT",
"display_name": "AssetGem",
"summary": "A short description of AssetGem template.",
"canonical_tags": [],
"user_tags": [
"AssetGem"
],
"icon_path": "preview.png",
"copyFiles": [
{
"file": "CMakeLists.txt",
"origin": "CMakeLists.txt",
"isTemplated": true,
"isOptional": false
},
{
"file": "gem.json",
"origin": "gem.json",
"isTemplated": true,
"isOptional": false
},
{
"file": "preview.png",
"origin": "preview.png",
"isTemplated": false,
"isOptional": false
}
],
"createDirectories": [
{
"dir": "Assets",
"origin": "Assets"
}
]
}
'''
TEST_RESTRICTED_JSON_PAYLOAD = '''
{
"restricted_name": "o3de"
}
'''
TEST_O3DE_MANIFEST_JSON_PAYLOAD = '''
{
"o3de_manifest_name": "testuser",
"origin": "C:/Users/testuser/.o3de",
"default_engines_folder": "C:/Users/testuser/.o3de/Engines",
"default_projects_folder": "C:/Users/testuser/.o3de/Projects",
"default_gems_folder": "C:/Users/testuser/.o3de/Gems",
"default_templates_folder": "C:/Users/testuser/.o3de/Templates",
"default_restricted_folder": "C:/Users/testuser/.o3de/Restricted",
"default_third_party_folder": "C:/Users/testuser/.o3de/3rdParty",
"projects": [
"D:/MinimalProject"
],
"external_subdirectories": [],
"templates": [],
"restricted": [],
"repos": [],
"engines": [
"D:/o3de/o3de"
],
"engines_path": {
"o3de": "D:/o3de/o3de"
}
}
'''
class TestPrintRegistration:
@staticmethod
def load_manifest_json():
return json.loads(TEST_O3DE_MANIFEST_JSON_PAYLOAD)
@staticmethod
def get_engine_json_data(engine_path: pathlib.Path = None):
return json.loads(TEST_ENGINE_JSON_PAYLOAD)
@staticmethod
def get_project_json_data(project_path: pathlib.Path = None):
return json.loads(TEST_PROJECT_JSON_PAYLOAD)
@staticmethod
def get_gem_json_data(gem_path: pathlib.Path = None):
return json.loads(TEST_GEM_JSON_PAYLOAD)
@staticmethod
def get_template_json_data(template_path: pathlib.Path = None):
return json.loads(TEST_TEMPLATE_JSON_PAYLOAD)
@staticmethod
def get_restricted_json_data(restricted_path: pathlib.Path = None):
return json.loads(TEST_RESTRICTED_JSON_PAYLOAD)
@pytest.mark.parametrize("project_path, verbose", [
pytest.param(None, 0),
pytest.param(None, 1),
pytest.param(pathlib.Path("D:/MinimalProject"), 0),
pytest.param(pathlib.Path("D:/MinimalProject"), 1)
])
def test_print_registration_no_option(self, project_path, verbose):
parser = argparse.ArgumentParser()
# Register the registration script subparsers with the current argument parser
print_registration.add_parser_args(parser)
arg_list = []
if project_path:
arg_list += ['--project-path', project_path.as_posix()]
if verbose:
arg_list += ['-' + 'v' * verbose]
test_args = parser.parse_args(arg_list)
with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \
patch('o3de.manifest.get_engine_json_data',
side_effect=self.get_engine_json_data) as get_engine_json_data_patch, \
patch('o3de.manifest.get_project_json_data',
side_effect=self.get_project_json_data) as get_project_json_patch, \
patch('o3de.manifest.get_gem_json_data', side_effect=self.get_gem_json_data) as get_gem_json_patch, \
patch('o3de.manifest.get_template_json_data', side_effect=self.get_template_json_data) as get_template_json_patch, \
patch('o3de.manifest.get_restricted_json_data', side_effect=self.get_restricted_json_data) as get_json_patch:
result = print_registration._run_register_show(test_args)
assert result == 0
@pytest.mark.parametrize("engine_arg_option, verbose", [
pytest.param("--this-engine", 0),
pytest.param("--this-engine", 1),
pytest.param("--engines", 0),
pytest.param("--engines", 1)
])
def test_print_engine_registration(self, engine_arg_option, verbose):
parser = argparse.ArgumentParser()
# Register the registration script subparsers with the current argument parser
print_registration.add_parser_args(parser)
arg_list = [engine_arg_option]
if verbose:
arg_list += ['-' + 'v' * verbose]
test_args = parser.parse_args(arg_list)
with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \
patch('o3de.manifest.get_engine_json_data', side_effect=self.get_engine_json_data) as get_engine_json_data_patch:
result = print_registration._run_register_show(test_args)
assert result == 0
@pytest.mark.parametrize("arg_option, verbose", [
pytest.param("--projects", 0),
pytest.param("--projects", 1),
pytest.param("--engine-projects", 0),
pytest.param("--engine-projects", 1),
pytest.param("--all-projects", 0),
pytest.param("--all-projects", 1)
])
def test_print_project_registration(self, arg_option, verbose):
parser = argparse.ArgumentParser()
# Register the registration script subparsers with the current argument parser
print_registration.add_parser_args(parser)
arg_list = [arg_option]
if verbose:
arg_list += ['-' + 'v' * verbose]
test_args = parser.parse_args(arg_list)
with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \
patch('o3de.manifest.get_project_json_data', side_effect=self.get_project_json_data) as get_json_data_patch:
result = print_registration._run_register_show(test_args)
assert result == 0
@pytest.mark.parametrize("arg_option, project_path, verbose", [
pytest.param("--gems", None, 0),
pytest.param("--gems", None, 1),
pytest.param("--engine-gems", None, 0),
pytest.param("--engine-gems", None, 1),
pytest.param("--project-gems", pathlib.Path("D:/MinimalProject"), 0),
pytest.param("--project-gems", pathlib.Path("D:/MinimalProject"), 1),
pytest.param("--all-gems", pathlib.Path("D:/MinimalProject"), 0),
pytest.param("--all-gems", None, 0),
pytest.param("--all-gems", pathlib.Path("D:/MinimalProject"), 1),
pytest.param("--all-gems", None, 1)
])
def test_print_gem_registration(self, arg_option, project_path, verbose):
parser = argparse.ArgumentParser()
# Register the registration script subparsers with the current argument parser
print_registration.add_parser_args(parser)
arg_list = [arg_option]
if project_path:
arg_list += ['--project-path', project_path.as_posix()]
if verbose:
arg_list += ['-' + 'v' * verbose]
test_args = parser.parse_args(arg_list)
# Patch the manifest.py function to locate gem.json files in external subdirectories
# to just return a fake path to a single test gem
def get_gems_from_subdirectories(external_subdirs: list) -> list:
return ["D:/TestGem"]
with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \
patch('o3de.manifest.get_gem_json_data', side_effect=self.get_gem_json_data) as get_json_patch, \
patch('o3de.manifest.get_project_json_data', side_effect=self.get_project_json_data) as get_project_json_patch, \
patch('o3de.manifest.get_gems_from_subdirectories', side_effect=get_gems_from_subdirectories) as get_gems_from_subdirs_patch, \
patch('o3de.print_registration.get_project_path', return_value=project_path) as get_project_path_patch:
result = print_registration._run_register_show(test_args)
assert result == 0
@pytest.mark.parametrize("arg_option, project_path, verbose", [
pytest.param("--templates", None, 0),
pytest.param("--templates", None, 1),
pytest.param("--engine-templates", None, 0),
pytest.param("--engine-templates", None, 1),
pytest.param("--project-templates", pathlib.Path("D:/MinimalProject"), 0),
pytest.param("--project-templates", pathlib.Path("D:/MinimalProject"), 1),
pytest.param("--all-templates", pathlib.Path("D:/MinimalProject"), 0),
pytest.param("--all-templates", None, 0),
pytest.param("--all-templates", pathlib.Path("D:/MinimalProject"), 1),
pytest.param("--all-templates", None, 1)
])
def test_print_template_registration(self, arg_option, project_path, verbose):
parser = argparse.ArgumentParser()
# Register the registration script subparsers with the current argument parser
print_registration.add_parser_args(parser)
arg_list = [arg_option]
if project_path:
arg_list += ['--project-path', project_path.as_posix()]
if verbose:
arg_list += ['-' + 'v' * verbose]
test_args = parser.parse_args(arg_list)
with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \
patch('o3de.manifest.get_template_json_data', side_effect=self.get_template_json_data) as get_json_patch, \
patch('o3de.manifest.get_project_json_data', side_effect=self.get_project_json_data) as get_project_json_patch, \
patch('o3de.print_registration.get_project_path', return_value=project_path) as get_project_path_patch:
result = print_registration._run_register_show(test_args)
assert result == 0
@pytest.mark.parametrize("arg_option, project_path, verbose", [
pytest.param("--restricted", None, 0),
pytest.param("--restricted", None, 1),
pytest.param("--engine-restricted", None, 0),
pytest.param("--engine-restricted", None, 1),
pytest.param("--project-restricted", pathlib.Path("D:/MinimalProject"), 0),
pytest.param("--project-restricted", pathlib.Path("D:/MinimalProject"), 1),
pytest.param("--all-restricted", pathlib.Path("D:/MinimalProject"), 0),
pytest.param("--all-restricted", None, 0),
pytest.param("--all-restricted", pathlib.Path("D:/MinimalProject"), 1),
pytest.param("--all-restricted", None, 1)
])
def test_print_restricted_registration(self, arg_option, project_path, verbose):
parser = argparse.ArgumentParser()
# Register the registration script subparsers with the current argument parser
print_registration.add_parser_args(parser)
arg_list = [arg_option]
if project_path:
arg_list += ['--project-path', project_path.as_posix()]
if verbose:
arg_list += ['-' + 'v' * verbose]
test_args = parser.parse_args(arg_list)
with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \
patch('o3de.manifest.get_restricted_json_data', side_effect=self.get_restricted_json_data) as get_json_patch, \
patch('o3de.manifest.get_project_json_data', side_effect=self.get_project_json_data) as get_project_json_patch, \
patch('o3de.print_registration.get_project_path', return_value=project_path) as get_project_path_patch:
result = print_registration._run_register_show(test_args)
assert result == 0
# Setting --verbose with the --*external-subdirectories option doesn't result in any additional output
# So it is only parameterized as 0
@pytest.mark.parametrize("arg_option, project_path, verbose", [
pytest.param("--external-subdirectories", None, 0),
pytest.param("--engine-external-subdirectories", None, 0),
pytest.param("--project-external-subdirectories", pathlib.Path("D:/MinimalProject"), 0),
pytest.param("--all-external-subdirectories", pathlib.Path("D:/MinimalProject"), 0),
pytest.param("--all-external-subdirectories", None, 0),
])
def test_print_external_subdirectories_registration(self, arg_option, project_path, verbose):
parser = argparse.ArgumentParser()
# Register the registration script subparsers with the current argument parser
print_registration.add_parser_args(parser)
arg_list = [arg_option]
if project_path:
arg_list += ['--project-path', project_path.as_posix()]
if verbose:
arg_list += ['-' + 'v' * verbose]
test_args = parser.parse_args(arg_list)
with patch('o3de.manifest.load_o3de_manifest', side_effect=self.load_manifest_json) as load_manifest_patch, \
patch('o3de.manifest.get_project_json_data',
side_effect=self.get_project_json_data) as get_project_json_patch, \
patch('o3de.print_registration.get_project_path', return_value=project_path) as get_project_path_patch:
result = print_registration._run_register_show(test_args)
assert result == 0