Merge branch 'main' into cpack_installer
This commit is contained in:
@@ -12,5 +12,4 @@
|
||||
add_subdirectory(detect_file_changes)
|
||||
add_subdirectory(commit_validation)
|
||||
add_subdirectory(o3de)
|
||||
add_subdirectory(project_manager)
|
||||
add_subdirectory(ctest)
|
||||
|
||||
@@ -14,6 +14,7 @@ set -o errexit # exit on the first failure encountered
|
||||
|
||||
BASEDIR=$(dirname "$0")
|
||||
source $BASEDIR/env_linux.sh
|
||||
source $BASEDIR/clean_linux.sh
|
||||
|
||||
mkdir -p ${OUTPUT_DIRECTORY}
|
||||
SOURCE_DIRECTORY=${PWD}
|
||||
@@ -46,4 +47,4 @@ fi
|
||||
echo [ci_build] cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS}
|
||||
cmake --build . --target ${CMAKE_TARGET} --config ${CONFIGURATION} -j $(grep -c processor /proc/cpuinfo) -- ${CMAKE_NATIVE_BUILD_ARGS}
|
||||
|
||||
popd
|
||||
popd
|
||||
|
||||
@@ -12,6 +12,16 @@
|
||||
|
||||
set -o errexit # exit on the first failure encountered
|
||||
|
||||
# Jenkins defines environment variables for parameters and passes "false" to variables
|
||||
# that are not set. Here we clear them if they are false so we can also just define them
|
||||
# from command line
|
||||
if [[ "${CLEAN_ASSETS}" == "false" ]]; then
|
||||
CLEAN_ASSETS=
|
||||
fi
|
||||
if [[ "${CLEAN_OUTPUT_DIRECTORY}" == "false" ]]; then
|
||||
CLEAN_OUTPUT_DIRECTORY=
|
||||
fi
|
||||
|
||||
if [[ -n "$CLEAN_ASSETS" ]]; then
|
||||
echo "[ci_build] CLEAN_ASSETS option set"
|
||||
for project in $(echo $CMAKE_LY_PROJECTS | sed "s/;/ /g")
|
||||
@@ -23,10 +33,35 @@ if [[ -n "$CLEAN_ASSETS" ]]; then
|
||||
done
|
||||
fi
|
||||
|
||||
# If the node label changes, we issue a clean output since node changes can change SDK/CMake/toolchains/etc
|
||||
LAST_CONFIGURE_NODE_LABEL_FILE=ci_last_node_label.txt
|
||||
if [[ -n "$NODE_LABEL" ]]; then
|
||||
if [[ -d $OUTPUT_DIRECTORY ]]; then
|
||||
pushd $OUTPUT_DIRECTORY
|
||||
if [[ -e ${LAST_CONFIGURE_NODE_LABEL_FILE} ]]; then
|
||||
LAST_NODE_LABEL=$(<${LAST_CONFIGURE_NODE_LABEL_FILE})
|
||||
else
|
||||
LAST_NODE_LABEL=
|
||||
fi
|
||||
# Detect if the node label has changed
|
||||
if [[ "${LAST_NODE_LABEL}" != "${NODE_LABEL}" ]]; then
|
||||
echo [ci_build] Last run was done with node label \"${LAST_NODE_LABEL}\", new node label is \"${NODE_LABEL}\", forcing CLEAN_OUTPUT_DIRECTORY
|
||||
CLEAN_OUTPUT_DIRECTORY=1
|
||||
fi
|
||||
popd
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$CLEAN_OUTPUT_DIRECTORY" ]]; then
|
||||
echo "[ci_build] CLEAN_OUTPUT_DIRECTORY option set"
|
||||
if [[ -d $OUTPUT_DIRECTORY ]]; then
|
||||
echo "[ci_build] Deleting \"${OUTPUT_DIRECTORY}\""
|
||||
rm -rf ${OUTPUT_DIRECTORY}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p ${OUTPUT_DIRECTORY}
|
||||
# Save the node label
|
||||
pushd $OUTPUT_DIRECTORY
|
||||
echo "${NODE_LABEL}" > ${LAST_CONFIGURE_NODE_LABEL_FILE}
|
||||
popd
|
||||
|
||||
@@ -14,6 +14,7 @@ set -o errexit # exit on the first failure encountered
|
||||
|
||||
BASEDIR=$(dirname "$0")
|
||||
source $BASEDIR/env_mac.sh
|
||||
source $BASEDIR/clean_mac.sh
|
||||
|
||||
mkdir -p ${OUTPUT_DIRECTORY}
|
||||
SOURCE_DIRECTORY=${PWD}
|
||||
|
||||
@@ -12,6 +12,16 @@
|
||||
|
||||
set -o errexit # exit on the first failure encountered
|
||||
|
||||
# Jenkins defines environment variables for parameters and passes "false" to variables
|
||||
# that are not set. Here we clear them if they are false so we can also just define them
|
||||
# from command line
|
||||
if [[ "${CLEAN_ASSETS}" == "false" ]]; then
|
||||
CLEAN_ASSETS=
|
||||
fi
|
||||
if [[ "${CLEAN_OUTPUT_DIRECTORY}" == "false" ]]; then
|
||||
CLEAN_OUTPUT_DIRECTORY=
|
||||
fi
|
||||
|
||||
if [[ -n "$CLEAN_ASSETS" ]]; then
|
||||
echo "[ci_build] CLEAN_ASSETS option set"
|
||||
for project in $(echo $CMAKE_LY_PROJECTS | sed "s/;/ /g")
|
||||
@@ -23,10 +33,35 @@ if [[ -n "$CLEAN_ASSETS" ]]; then
|
||||
done
|
||||
fi
|
||||
|
||||
# If the node label changes, we issue a clean output since node changes can change SDK/CMake/toolchains/etc
|
||||
LAST_CONFIGURE_NODE_LABEL_FILE=ci_last_node_label.txt
|
||||
if [[ -n "$NODE_LABEL" ]]; then
|
||||
if [[ -d $OUTPUT_DIRECTORY ]]; then
|
||||
pushd $OUTPUT_DIRECTORY
|
||||
if [[ -e ${LAST_CONFIGURE_NODE_LABEL_FILE} ]]; then
|
||||
LAST_NODE_LABEL=$(<${LAST_CONFIGURE_NODE_LABEL_FILE})
|
||||
else
|
||||
LAST_NODE_LABEL=
|
||||
fi
|
||||
# Detect if the node label has changed
|
||||
if [[ "${LAST_NODE_LABEL}" != "${NODE_LABEL}" ]]; then
|
||||
echo [ci_build] Last run was done with node label \"${LAST_NODE_LABEL}\", new node label is \"${NODE_LABEL}\", forcing CLEAN_OUTPUT_DIRECTORY
|
||||
CLEAN_OUTPUT_DIRECTORY=1
|
||||
fi
|
||||
popd
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$CLEAN_OUTPUT_DIRECTORY" ]]; then
|
||||
echo "[ci_build] CLEAN_OUTPUT_DIRECTORY option set"
|
||||
if [[ -d $OUTPUT_DIRECTORY ]]; then
|
||||
echo "[ci_build] Deleting \"${OUTPUT_DIRECTORY}\""
|
||||
rm -rf ${OUTPUT_DIRECTORY}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p ${OUTPUT_DIRECTORY}
|
||||
# Save the node label
|
||||
pushd $OUTPUT_DIRECTORY
|
||||
echo "${NODE_LABEL}" > ${LAST_CONFIGURE_NODE_LABEL_FILE}
|
||||
popd
|
||||
|
||||
@@ -13,6 +13,7 @@ REM
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
CALL %~dp0env_windows.cmd
|
||||
CALL %~dp0clean_windows.cmd
|
||||
|
||||
IF NOT EXIST "%OUTPUT_DIRECTORY%" (
|
||||
MKDIR %OUTPUT_DIRECTORY%.
|
||||
@@ -70,4 +71,4 @@ EXIT /b 0
|
||||
|
||||
:error
|
||||
POPD
|
||||
EXIT /b 1
|
||||
EXIT /b 1
|
||||
|
||||
@@ -12,6 +12,16 @@ REM
|
||||
|
||||
SETLOCAL EnableDelayedExpansion
|
||||
|
||||
REM Jenkins defines environment variables for parameters and passes "false" to variables
|
||||
REM that are not set. Here we clear them if they are false so we can also just define them
|
||||
REM from command line
|
||||
IF "%CLEAN_ASSETS%"=="false" (
|
||||
set CLEAN_ASSETS=
|
||||
)
|
||||
IF "%CLEAN_OUTPUT_DIRECTORY%"=="false" (
|
||||
set CLEAN_OUTPUT_DIRECTORY=
|
||||
)
|
||||
|
||||
IF DEFINED CLEAN_ASSETS (
|
||||
ECHO [ci_build] CLEAN_ASSETS option set
|
||||
FOR %%P in (%CMAKE_LY_PROJECTS%) do (
|
||||
@@ -19,7 +29,26 @@ IF DEFINED CLEAN_ASSETS (
|
||||
ECHO [ci_build] Deleting "%%P\Cache"
|
||||
DEL /s /q /f %%P\Cache 1>nul
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
REM If the node label changes, we issue a clean output since node changes can change SDK/CMake/toolchains/etc
|
||||
SET LAST_CONFIGURE_NODE_LABEL_FILE=ci_last_node_label.txt
|
||||
IF DEFINED NODE_LABEL (
|
||||
IF EXIST %OUTPUT_DIRECTORY% (
|
||||
PUSHD %OUTPUT_DIRECTORY%
|
||||
IF EXIST !LAST_CONFIGURE_NODE_LABEL_FILE! (
|
||||
FOR /F "delims=" %%x in (%LAST_CONFIGURE_NODE_LABEL_FILE%) DO SET LAST_NODE_LABEL=%%x
|
||||
) ELSE (
|
||||
SET LAST_NODE_LABEL=
|
||||
)
|
||||
REM Detect if the node label has changed
|
||||
IF !LAST_NODE_LABEL! NEQ !NODE_LABEL! (
|
||||
ECHO [ci_build] Last run was done with node label "!LAST_NODE_LABEL!", new node label is "!NODE_LABEL!", forcing CLEAN_OUTPUT_DIRECTORY
|
||||
SET CLEAN_OUTPUT_DIRECTORY=1
|
||||
)
|
||||
POPD
|
||||
)
|
||||
)
|
||||
|
||||
IF DEFINED CLEAN_OUTPUT_DIRECTORY (
|
||||
@@ -28,4 +57,12 @@ IF DEFINED CLEAN_OUTPUT_DIRECTORY (
|
||||
ECHO [ci_build] Deleting "%OUTPUT_DIRECTORY%"
|
||||
DEL /s /q /f %OUTPUT_DIRECTORY% 1>nul
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
IF NOT EXIST "%OUTPUT_DIRECTORY%" (
|
||||
MKDIR %OUTPUT_DIRECTORY%.
|
||||
)
|
||||
REM Save the node label
|
||||
PUSHD %OUTPUT_DIRECTORY%
|
||||
ECHO !NODE_LABEL!> !LAST_CONFIGURE_NODE_LABEL_FILE!
|
||||
POPD
|
||||
|
||||
+5
-2
@@ -32,7 +32,7 @@ def add_args(parser, subparsers) -> None:
|
||||
# add the scripts/o3de directory to the front of the sys.path
|
||||
sys.path.insert(0, str(o3de_package_dir))
|
||||
from o3de import engine_template, global_project, register, print_registration, get_registration, \
|
||||
enable_gem, disable_gem, sha256
|
||||
enable_gem, disable_gem, project_properties, sha256
|
||||
# Remove the temporarily added path
|
||||
sys.path = sys.path[1:]
|
||||
|
||||
@@ -55,7 +55,10 @@ def add_args(parser, subparsers) -> None:
|
||||
|
||||
# remove a gem from a project
|
||||
disable_gem.add_args(subparsers)
|
||||
|
||||
|
||||
# modify project properties
|
||||
project_properties.add_args(subparsers)
|
||||
|
||||
# sha256
|
||||
sha256.add_args(subparsers)
|
||||
|
||||
|
||||
@@ -97,6 +97,12 @@ def get_o3de_logs_folder() -> pathlib.Path:
|
||||
return logs_folder
|
||||
|
||||
|
||||
def get_o3de_third_party_folder() -> pathlib.Path:
|
||||
third_party_folder = get_o3de_folder() / '3rdParty'
|
||||
third_party_folder.mkdir(parents=True, exist_ok=True)
|
||||
return third_party_folder
|
||||
|
||||
|
||||
# o3de manifest file methods
|
||||
def get_o3de_manifest() -> pathlib.Path:
|
||||
manifest_path = get_o3de_folder() / 'o3de_manifest.json'
|
||||
@@ -113,6 +119,7 @@ def get_o3de_manifest() -> pathlib.Path:
|
||||
default_gems_folder = get_o3de_gems_folder()
|
||||
default_templates_folder = get_o3de_templates_folder()
|
||||
default_restricted_folder = get_o3de_restricted_folder()
|
||||
default_third_party_folder = get_o3de_third_party_folder()
|
||||
|
||||
default_projects_restricted_folder = default_projects_folder / 'Restricted'
|
||||
default_projects_restricted_folder.mkdir(parents=True, exist_ok=True)
|
||||
@@ -129,6 +136,7 @@ def get_o3de_manifest() -> pathlib.Path:
|
||||
json_data.update({'default_gems_folder': default_gems_folder.as_posix()})
|
||||
json_data.update({'default_templates_folder': default_templates_folder.as_posix()})
|
||||
json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()})
|
||||
json_data.update({'default_third_party_folder': default_third_party_folder.as_posix()})
|
||||
|
||||
json_data.update({'projects': []})
|
||||
json_data.update({'external_subdirectories': []})
|
||||
@@ -302,64 +310,95 @@ def get_project_external_subdirectories(project_path: pathlib.Path) -> list:
|
||||
project_object['external_subdirectories'])) if 'external_subdirectories' in project_object else []
|
||||
|
||||
|
||||
def get_project_templates(project_path: pathlib.Path) -> list:
|
||||
project_object = get_project_json_data(project_path=project_path)
|
||||
return list(map(lambda rel_path: (pathlib.Path(project_path) / rel_path).as_posix(),
|
||||
project_object['templates']))
|
||||
|
||||
|
||||
def get_project_restricted(project_path: pathlib.Path) -> list:
|
||||
project_object = get_project_json_data(project_path=project_path)
|
||||
return list(map(lambda rel_path: (pathlib.Path(project_path) / rel_path).as_posix(),
|
||||
project_object['restricted'])) if 'restricted' in project_object else []
|
||||
|
||||
|
||||
# Combined manifest queries
|
||||
def get_all_projects() -> list:
|
||||
projects_data = set(get_projects())
|
||||
projects_data.update(get_engine_projects())
|
||||
return list(projects_data)
|
||||
projects_data = get_projects()
|
||||
projects_data.extend(get_engine_projects())
|
||||
# Remove duplicates from the list
|
||||
return list(dict.fromkeys(projects_data))
|
||||
|
||||
|
||||
def get_all_gems(project_path: pathlib.Path = None) -> list:
|
||||
gems_data = set(get_gems())
|
||||
gems_data.update(get_engine_gems())
|
||||
gems_data = get_gems()
|
||||
gems_data.extend(get_engine_gems())
|
||||
if project_path:
|
||||
gems_data.update(get_project_gems(project_path))
|
||||
return list(gems_data)
|
||||
gems_data.extend(get_project_gems(project_path))
|
||||
return list(dict.fromkeys(gems_data))
|
||||
|
||||
|
||||
def get_all_external_subdirectories(project_path: pathlib.Path = None) -> list:
|
||||
external_subdirectories_data = set(get_external_subdirectories())
|
||||
external_subdirectories_data.update(get_engine_external_subdirectories())
|
||||
external_subdirectories_data = get_external_subdirectories()
|
||||
external_subdirectories_data.extend(get_engine_external_subdirectories())
|
||||
if project_path:
|
||||
external_subdirectories_data.update(get_project_external_subdirectories(project_path))
|
||||
return list(templates_data)
|
||||
external_subdirectories_data.extend(get_project_external_subdirectories(project_path))
|
||||
return list(dict.fromkeys(external_subdirectories_data))
|
||||
|
||||
|
||||
def get_all_templates() -> list:
|
||||
templates_data = set(get_templates())
|
||||
templates_data.update(get_engine_templates())
|
||||
return list(templates_data)
|
||||
def get_all_templates(project_path: pathlib.Path = None) -> list:
|
||||
templates_data = get_templates()
|
||||
templates_data.extend(get_engine_templates())
|
||||
if project_path:
|
||||
templates_data.extend(get_project_templates(project_path))
|
||||
return list(dict.fromkeys(templates_data))
|
||||
|
||||
|
||||
def get_all_restricted() -> list:
|
||||
restricted_data = set(get_restricted())
|
||||
restricted_data.update(get_engine_restricted())
|
||||
return list(gems_data)
|
||||
restricted_data = get_restricted()
|
||||
restricted_data.extend(get_engine_restricted())
|
||||
if project_path:
|
||||
restricted_data.extend(get_project_restricted(project_path))
|
||||
return list(dict.fromkeys(restricted_data))
|
||||
|
||||
|
||||
# Template functions
|
||||
def get_project_templates(): # temporary until we have a better way to do this... maybe template_type element
|
||||
def get_templates_for_project_creation():
|
||||
project_templates = []
|
||||
for template in get_all_templates():
|
||||
if 'Project' in template:
|
||||
project_templates.append(template)
|
||||
for template_path in get_all_templates():
|
||||
template_path = pathlib.Path(template_path)
|
||||
template_json_path = pathlib.Path(template_path) / 'template.json'
|
||||
if not validation.valid_o3de_template_json(template_json_path):
|
||||
continue
|
||||
|
||||
project_json_path = template_path / 'Template' / 'project.json'
|
||||
if validation.valid_o3de_project_json(project_json_path):
|
||||
project_templates.append(template_path)
|
||||
return project_templates
|
||||
|
||||
|
||||
def get_gem_templates(): # temporary until we have a better way to do this... maybe template_type element
|
||||
def get_templates_for_gem_creation():
|
||||
gem_templates = []
|
||||
for template in get_all_templates():
|
||||
if 'Gem' in template:
|
||||
gem_templates.append(template)
|
||||
for template_path in get_all_templates():
|
||||
template_path = pathlib.Path(template_path)
|
||||
template_json_path = pathlib.Path(template_path) / 'template.json'
|
||||
if not validation.valid_o3de_template_json(template_json_path):
|
||||
continue
|
||||
|
||||
gem_json_path = template_path / 'Template' / 'gem.json'
|
||||
if validation.valid_o3de_gem_json(gem_json_path):
|
||||
gem_templates.append(template_path)
|
||||
return gem_templates
|
||||
|
||||
|
||||
def get_generic_templates(): # temporary until we have a better way to do this... maybe template_type element
|
||||
generic_templates = []
|
||||
for template in get_all_templates():
|
||||
if 'Project' not in template and 'Gem' not in template:
|
||||
generic_templates.append(template)
|
||||
return generic_templates
|
||||
def get_templates_for_generic_creation(): # temporary until we have a better way to do this... maybe template_type element
|
||||
def filter_project_and_gem_templates_out(template_path,
|
||||
templates_for_project_creation = get_templates_for_project_creation(),
|
||||
templates_for_gem_creation = get_templates_for_gem_creation()):
|
||||
template_path = pathlib.Path(template_path)
|
||||
return template_path not in templates_for_project_creation and template_path not in templates_for_gem_creation
|
||||
|
||||
return list(filter(filter_project_and_gem_templates_out, get_all_templates()))
|
||||
|
||||
|
||||
def get_all_restricted() -> list:
|
||||
@@ -515,7 +554,7 @@ def get_template_json_data(template_name: str = None,
|
||||
return None
|
||||
|
||||
|
||||
def get_restricted_data(restricted_name: str = None,
|
||||
def get_restricted_json_data(restricted_name: str = None,
|
||||
restricted_path: str or pathlib.Path = None) -> dict or None:
|
||||
if not restricted_name and not restricted_path:
|
||||
logger.error('Must specify either a Restricted name or Restricted Path.')
|
||||
@@ -573,9 +612,7 @@ def get_registered(engine_name: str = None,
|
||||
return engine_path
|
||||
|
||||
elif isinstance(project_name, str):
|
||||
enging_projects = get_engine_projects()
|
||||
projects = json_data['projects'].copy()
|
||||
projects.extend(engine_object['projects'])
|
||||
projects = get_all_projects()
|
||||
for project_path in projects:
|
||||
project_path = pathlib.Path(project_path).resolve()
|
||||
project_json = project_path / 'project.json'
|
||||
@@ -605,9 +642,7 @@ def get_registered(engine_name: str = None,
|
||||
return gem_path
|
||||
|
||||
elif isinstance(template_name, str):
|
||||
engine_templates = get_engine_templates()
|
||||
templates = json_data['templates'].copy()
|
||||
templates.extend(engine_templates)
|
||||
templates = get_all_templates()
|
||||
for template_path in templates:
|
||||
template_path = pathlib.Path(template_path).resolve()
|
||||
template_json = template_path / 'template.json'
|
||||
@@ -622,9 +657,7 @@ def get_registered(engine_name: str = None,
|
||||
return template_path
|
||||
|
||||
elif isinstance(restricted_name, str):
|
||||
engine_restricted = get_engine_restricted()
|
||||
restricted = json_data['restricted'].copy()
|
||||
restricted.extend(engine_restricted)
|
||||
restricted = get_all_restricted()
|
||||
for restricted_path in restricted:
|
||||
restricted_path = pathlib.Path(restricted_path).resolve()
|
||||
restricted_json = restricted_path / 'restricted.json'
|
||||
|
||||
@@ -13,6 +13,7 @@ import argparse
|
||||
import json
|
||||
import hashlib
|
||||
import logging
|
||||
import pathlib
|
||||
import sys
|
||||
import urllib.parse
|
||||
|
||||
@@ -21,219 +22,251 @@ from o3de import manifest, validation
|
||||
logger = logging.getLogger()
|
||||
logging.basicConfig()
|
||||
|
||||
def print_this_engine(verbose: int) -> None:
|
||||
|
||||
def get_project_path(project_path: pathlib.Path, project_name: str) -> pathlib.Path:
|
||||
if not project_name and not project_path:
|
||||
logger.error(f'Must either specify a Project path or Project Name.')
|
||||
return None
|
||||
|
||||
if not project_path:
|
||||
project_path = manifest.get_registered(project_name=project_name)
|
||||
if not project_path:
|
||||
logger.error(f'Unable to locate project path from the registered manifest json files:'
|
||||
f' {str(pathlib.Path("~/.o3de/o3de_manifest.json").expanduser())}, engine.json')
|
||||
return None
|
||||
|
||||
if not project_path.is_dir():
|
||||
logger.error(f'Project path {project_path} is not a folder.')
|
||||
return None
|
||||
|
||||
return project_path
|
||||
|
||||
|
||||
def print_this_engine(verbose: int) -> int:
|
||||
engine_data = manifest.get_this_engine()
|
||||
print(json.dumps(engine_data, indent=4))
|
||||
result = True
|
||||
if verbose > 0:
|
||||
print_engines_data(engine_data)
|
||||
result = print_manifest_json_data(engine_data, 'engine.json', 'This Engine',
|
||||
manifest.get_engine_json_data, 'engine_path')
|
||||
return 0 if result else 1
|
||||
|
||||
|
||||
def print_engines(verbose: int) -> None:
|
||||
engines_data = manifest.get_engines()
|
||||
print(json.dumps(engines_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_engines_data(engines_data)
|
||||
return print_manifest_json_data(engines_data, 'engine.json', 'Engines',
|
||||
manifest.get_engine_json_data, 'engine_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_projects(verbose: int) -> None:
|
||||
def print_projects(verbose: int) -> int:
|
||||
projects_data = manifest.get_projects()
|
||||
print(json.dumps(projects_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_projects_data(projects_data)
|
||||
return print_manifest_json_data(projects_data, 'project.json', 'Projects',
|
||||
manifest.get_project_json_data, 'project_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_gems(verbose: int) -> None:
|
||||
def print_gems(verbose: int) -> int:
|
||||
gems_data = manifest.get_gems()
|
||||
print(json.dumps(gems_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_gems_data(gems_data)
|
||||
return print_manifest_json_data(gems_data, 'gem.json', 'Gems',
|
||||
manifest.get_gem_json_data, 'gem_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_templates(verbose: int) -> None:
|
||||
def print_templates(verbose: int) -> int:
|
||||
templates_data = manifest.get_templates()
|
||||
print(json.dumps(templates_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_templates_data(templates_data)
|
||||
return print_manifest_json_data(templates_data, 'template.json', 'Templates',
|
||||
manifest.get_template_json_data, 'template_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_restricted(verbose: int) -> None:
|
||||
def print_restricted(verbose: int) -> int:
|
||||
restricted_data = manifest.get_restricted()
|
||||
print(json.dumps(restricted_data, indent=4))
|
||||
if verbose > 0:
|
||||
print_restricted_data(restricted_data)
|
||||
|
||||
def print_engine_projects(verbose: int) -> None:
|
||||
if verbose > 0:
|
||||
return print_manifest_json_data(restricted_data, 'restricted.json', 'Restricted',
|
||||
manifest.get_restricted_json_data, 'restricted_path')
|
||||
return 0
|
||||
|
||||
|
||||
# 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))
|
||||
|
||||
if verbose > 0:
|
||||
print_projects_data(engine_projects_data)
|
||||
return print_manifest_json_data(engine_projects_data, 'project.json', 'Projects',
|
||||
manifest.get_project_json_data, 'project_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_engine_gems(verbose: int) -> None:
|
||||
def print_engine_gems(verbose: int) -> int:
|
||||
engine_gems_data = manifest.get_engine_gems()
|
||||
print(json.dumps(engine_gems_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_gems_data(engine_gems_data)
|
||||
return print_manifest_json_data(engine_gems_data, 'gem.json', 'Gems',
|
||||
manifest.get_gem_json_data, 'gem_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_engine_templates(verbose: int) -> None:
|
||||
def print_engine_templates(verbose: int) -> int:
|
||||
engine_templates_data = manifest.get_engine_templates()
|
||||
print(json.dumps(engine_templates_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_templates_data(engine_templates_data)
|
||||
return print_manifest_json_data(engine_templates_data, 'template.json', 'Templates',
|
||||
manifest.get_template_json_data, 'template_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_engine_restricted(verbose: int) -> None:
|
||||
def print_engine_restricted(verbose: int) -> int:
|
||||
engine_restricted_data = manifest.get_engine_restricted()
|
||||
print(json.dumps(engine_restricted_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_restricted_data(engine_restricted_data)
|
||||
return print_manifest_json_data(engine_restricted_data, 'restricted.json', 'Restricted',
|
||||
manifest.get_restricted_json_data, 'restricted_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_engine_external_subdirectories(verbose: int) -> None:
|
||||
def print_engine_external_subdirectories() -> int:
|
||||
external_subdirs_data = manifest.get_engine_external_subdirectories()
|
||||
print(json.dumps(external_subdirs_data, indent=4))
|
||||
return 0
|
||||
|
||||
|
||||
def print_all_projects(verbose: int) -> None:
|
||||
# Project output methods
|
||||
def print_project_gems(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
|
||||
|
||||
project_gems_data = manifest.get_project_gems(project_path)
|
||||
print(json.dumps(project_gems_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
return print_manifest_json_data(project_gems_data, 'gem.json', 'Gems',
|
||||
manifest.get_gem_json_data, 'gem_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_project_external_subdirectories(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))
|
||||
return 0
|
||||
|
||||
|
||||
def print_project_templates(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
|
||||
|
||||
project_templates_data = manifest.get_project_templates(project_path)
|
||||
print(json.dumps(project_templates_data, indent=4))
|
||||
if verbose > 0:
|
||||
return print_manifest_json_data(project_templates_data, 'template.json', 'Templates',
|
||||
manifest.get_template_json_data, 'template_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_project_restricted(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
|
||||
|
||||
project_restricted_data = manifest.get_project_restricted(project_path)
|
||||
print(json.dumps(project_restricted_data, indent=4))
|
||||
if verbose > 0:
|
||||
return print_manifest_json_data(project_restricted_data, 'restricted.json', 'Restricted',
|
||||
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))
|
||||
|
||||
if verbose > 0:
|
||||
print_projects_data(all_projects_data)
|
||||
return print_manifest_json_data(all_projects_data, 'project.json', 'Projects',
|
||||
manifest.get_project_json_data, 'project_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_all_gems(verbose: int) -> None:
|
||||
def print_all_gems(verbose: int) -> int:
|
||||
all_gems_data = manifest.get_all_gems()
|
||||
print(json.dumps(all_gems_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_gems_data(all_gems_data)
|
||||
return print_manifest_json_data(all_gems_data, 'gem.json', 'Gems',
|
||||
manifest.get_gem_json_data, 'gem_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_all_templates(verbose: int) -> None:
|
||||
def print_all_external_subdirectories() -> int:
|
||||
all_external_subdirectories_data = manifest.get_all_external_subdirectories()
|
||||
print(json.dumps(all_external_subdirectories_data, 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))
|
||||
|
||||
if verbose > 0:
|
||||
print_templates_data(all_templates_data)
|
||||
return print_manifest_json_data(all_templates_data, 'template.json', 'Templates',
|
||||
manifest.get_template_json_data, 'template_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_all_restricted(verbose: int) -> None:
|
||||
def print_all_restricted(verbose: int) -> int:
|
||||
all_restricted_data = manifest.get_all_restricted()
|
||||
print(json.dumps(all_restricted_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_restricted_data(all_restricted_data)
|
||||
return print_manifest_json_data(all_restricted_data, 'restricted.json', 'Restricted',
|
||||
manifest.get_restricted_json_data, 'restricted_path')
|
||||
return 0
|
||||
|
||||
|
||||
def print_engines_data(engines_data: dict) -> None:
|
||||
def print_manifest_json_data(uri_json_data: dict, json_filename: str,
|
||||
print_prefix: str, get_json_func: callable, get_json_data_kw: str) -> int:
|
||||
print('\n')
|
||||
print("Engines================================================")
|
||||
for engine_object in engines_data:
|
||||
print(f"{print_prefix}================================================")
|
||||
for manifest_uri in uri_json_data:
|
||||
# if it's not local it should be in the cache
|
||||
engine_uri = engine_object['path']
|
||||
parsed_uri = urllib.parse.urlparse(engine_uri)
|
||||
if parsed_uri.scheme == 'http' or \
|
||||
parsed_uri.scheme == 'https' or \
|
||||
parsed_uri.scheme == 'ftp' or \
|
||||
parsed_uri.scheme == 'ftps':
|
||||
repo_sha256 = hashlib.sha256(engine_uri.encode())
|
||||
parsed_uri = urllib.parse.urlparse(manifest_uri)
|
||||
if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']:
|
||||
repo_sha256 = hashlib.sha256(manifest_uri.encode())
|
||||
cache_folder = manifest.get_o3de_cache_folder()
|
||||
engine = cache_folder / str(repo_sha256.hexdigest() + '.json')
|
||||
print(f'{engine_uri}/engine.json cached as:')
|
||||
manifest_json_path = cache_folder / str(repo_sha256.hexdigest() + '.json')
|
||||
else:
|
||||
engine_json = pathlib.Path(engine_uri).resolve() / 'engine.json'
|
||||
manifest_json_path = pathlib.Path(manifest_uri).resolve() / json_filename
|
||||
|
||||
with engine_json.open('r') as f:
|
||||
try:
|
||||
engine_json_data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warn(f'{engine_json} failed to load: {str(e)}')
|
||||
else:
|
||||
print(engine_json)
|
||||
print(json.dumps(engine_json_data, indent=4))
|
||||
print('\n')
|
||||
json_data = get_json_func(**{get_json_data_kwargs: manifest_json_path})
|
||||
if json_data:
|
||||
print(manifest_json_path)
|
||||
print(json.dumps(json_data, indent=4) + '\n')
|
||||
return 0
|
||||
|
||||
|
||||
def print_projects_data(projects_data: dict) -> None:
|
||||
print('\n')
|
||||
print("Projects================================================")
|
||||
for project_uri in projects_data:
|
||||
# if it's not local it should be in the cache
|
||||
parsed_uri = urllib.parse.urlparse(project_uri)
|
||||
if parsed_uri.scheme == 'http' or \
|
||||
parsed_uri.scheme == 'https' or \
|
||||
parsed_uri.scheme == 'ftp' or \
|
||||
parsed_uri.scheme == 'ftps':
|
||||
repo_sha256 = hashlib.sha256(project_uri.encode())
|
||||
cache_folder = manifest.get_o3de_cache_folder()
|
||||
project_json = cache_folder / str(repo_sha256.hexdigest() + '.json')
|
||||
else:
|
||||
project_json = pathlib.Path(project_uri).resolve() / 'project.json'
|
||||
|
||||
with project_json.open('r') as f:
|
||||
try:
|
||||
project_json_data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warn(f'{project_json} failed to load: {str(e)}')
|
||||
else:
|
||||
print(project_json)
|
||||
print(json.dumps(project_json_data, indent=4))
|
||||
print('\n')
|
||||
|
||||
|
||||
def print_gems_data(gems_data: dict) -> None:
|
||||
print('\n')
|
||||
print("Gems================================================")
|
||||
for gem_uri in gems_data:
|
||||
# if it's not local it should be in the cache
|
||||
parsed_uri = urllib.parse.urlparse(gem_uri)
|
||||
if parsed_uri.scheme == 'http' or \
|
||||
parsed_uri.scheme == 'https' or \
|
||||
parsed_uri.scheme == 'ftp' or \
|
||||
parsed_uri.scheme == 'ftps':
|
||||
repo_sha256 = hashlib.sha256(gem_uri.encode())
|
||||
cache_folder = manifest.get_o3de_cache_folder()
|
||||
gem_json = cache_folder / str(repo_sha256.hexdigest() + '.json')
|
||||
else:
|
||||
gem_json = pathlib.Path(gem_uri).resolve() / 'gem.json'
|
||||
|
||||
with gem_json.open('r') as f:
|
||||
try:
|
||||
gem_json_data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warn(f'{gem_json} failed to load: {str(e)}')
|
||||
else:
|
||||
print(gem_json)
|
||||
print(json.dumps(gem_json_data, indent=4))
|
||||
print('\n')
|
||||
|
||||
|
||||
def print_templates_data(templates_data: dict) -> None:
|
||||
print('\n')
|
||||
print("Templates================================================")
|
||||
for template_uri in templates_data:
|
||||
# if it's not local it should be in the cache
|
||||
parsed_uri = urllib.parse.urlparse(template_uri)
|
||||
if parsed_uri.scheme == 'http' or \
|
||||
parsed_uri.scheme == 'https' or \
|
||||
parsed_uri.scheme == 'ftp' or \
|
||||
parsed_uri.scheme == 'ftps':
|
||||
repo_sha256 = hashlib.sha256(template_uri.encode())
|
||||
cache_folder = manifest.get_o3de_cache_folder()
|
||||
template_json = cache_folder / str(repo_sha256.hexdigest() + '.json')
|
||||
else:
|
||||
template_json = pathlib.Path(template_uri).resolve() / 'template.json'
|
||||
|
||||
with template_json.open('r') as f:
|
||||
try:
|
||||
template_json_data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warn(f'{template_json} failed to load: {str(e)}')
|
||||
else:
|
||||
print(template_json)
|
||||
print(json.dumps(template_json_data, indent=4))
|
||||
print('\n')
|
||||
|
||||
|
||||
def print_repos_data(repos_data: dict) -> None:
|
||||
def print_repos_data(repos_data: dict) -> int:
|
||||
print('\n')
|
||||
print("Repos================================================")
|
||||
cache_folder = manifest.get_o3de_cache_folder()
|
||||
@@ -251,29 +284,16 @@ def print_repos_data(repos_data: dict) -> None:
|
||||
print(cache_file)
|
||||
print(json.dumps(repo_json_data, indent=4))
|
||||
print('\n')
|
||||
|
||||
|
||||
def print_restricted_data(restricted_data: dict) -> None:
|
||||
print('\n')
|
||||
print("Restricted================================================")
|
||||
for restricted_path in restricted_data:
|
||||
restricted_json = pathlib.Path(restricted_path).resolve() / 'restricted.json'
|
||||
with restricted_json.open('r') as f:
|
||||
try:
|
||||
restricted_json_data = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warn(f'{restricted_json} failed to load: {str(e)}')
|
||||
else:
|
||||
print(restricted_json)
|
||||
print(json.dumps(restricted_json_data, indent=4))
|
||||
print('\n')
|
||||
return 0
|
||||
|
||||
|
||||
def register_show_repos(verbose: int) -> None:
|
||||
repos_data = get_repos()
|
||||
repos_data = manifest.get_repos()
|
||||
print(json.dumps(repos_data, indent=4))
|
||||
|
||||
if verbose > 0:
|
||||
print_repos_data(repos_data)
|
||||
return print_repos_data(repos_data) == 0
|
||||
return 0
|
||||
|
||||
|
||||
def register_show(verbose: int) -> None:
|
||||
@@ -281,13 +301,15 @@ def register_show(verbose: int) -> None:
|
||||
print(f"{manifest.get_o3de_manifest()}:")
|
||||
print(json.dumps(json_data, indent=4))
|
||||
|
||||
result = True
|
||||
if verbose > 0:
|
||||
print_engines_data(manifest.get_engines())
|
||||
print_projects_data(manifest.get_all_projects())
|
||||
print_gems_data(manifest.get_gems())
|
||||
print_templates_data(manifest.get_all_templates())
|
||||
print_restricted_data(manifest.get_all_restricted())
|
||||
print_repos_data(manifest.get_repos())
|
||||
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
|
||||
|
||||
|
||||
def _run_register_show(args: argparse) -> int:
|
||||
@@ -295,75 +317,53 @@ def _run_register_show(args: argparse) -> int:
|
||||
manifest.override_home_folder = args.override_home_folder
|
||||
|
||||
if args.this_engine:
|
||||
print_this_engine(args.verbose)
|
||||
return 0
|
||||
|
||||
return print_this_engine(args.verbose)
|
||||
elif args.engines:
|
||||
print_engines(args.verbose)
|
||||
return 0
|
||||
return print_engines(args.verbose)
|
||||
elif args.projects:
|
||||
print_projects(args.verbose)
|
||||
return 0
|
||||
return print_projects(args.verbose)
|
||||
elif args.gems:
|
||||
print_gems(args.verbose)
|
||||
return 0
|
||||
return print_gems(args.verbose)
|
||||
elif args.templates:
|
||||
print_templates(args.verbose)
|
||||
return 0
|
||||
return print_templates(args.verbose)
|
||||
elif args.repos:
|
||||
register_show_repos(args.verbose)
|
||||
return 0
|
||||
return register_show_repos(args.verbose)
|
||||
elif args.restricted:
|
||||
print_restricted(args.verbose)
|
||||
return 0
|
||||
return print_restricted(args.verbose)
|
||||
|
||||
elif args.engine_projects:
|
||||
print_engine_projects(args.verbose)
|
||||
return 0
|
||||
return print_engine_projects(args.verbose)
|
||||
elif args.engine_gems:
|
||||
print_engine_gems(args.verbose)
|
||||
return 0
|
||||
elif args.engine_templates:
|
||||
print_engine_templates(args.verbose)
|
||||
return 0
|
||||
elif args.engine_restricted:
|
||||
print_engine_restricted(args.verbose)
|
||||
return 0
|
||||
return print_engine_gems(args.verbose)
|
||||
elif args.engine_external_subdirectories:
|
||||
print_engine_external_subdirectories(args.verbose)
|
||||
return 0
|
||||
return print_engine_external_subdirectories()
|
||||
elif args.engine_templates:
|
||||
return print_engine_templates(args.verbose)
|
||||
elif args.engine_restricted:
|
||||
return print_engine_restricted(args.verbose)
|
||||
|
||||
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)
|
||||
elif args.project_templates:
|
||||
return print_project_templates(args.verbose, args.project_path, args.project_name)
|
||||
elif args.project_restricted:
|
||||
return print_project_restricted(args.verbose, args.project_path, args.project_name)
|
||||
|
||||
elif args.all_projects:
|
||||
print_all_projects(args.verbose)
|
||||
return 0
|
||||
return print_all_projects(args.verbose)
|
||||
elif args.all_gems:
|
||||
print_all_gems(args.verbose)
|
||||
return 0
|
||||
return print_all_gems(args.verbose)
|
||||
elif args.all_external_subdirectories:
|
||||
return print_all_external_subdirectories()
|
||||
elif args.all_templates:
|
||||
print_all_templates(args.verbose)
|
||||
return 0
|
||||
return print_all_templates(args.verbose)
|
||||
elif args.all_restricted:
|
||||
print_all_restricted(args.verbose)
|
||||
return 0
|
||||
return print_all_restricted(args.verbose)
|
||||
|
||||
elif args.downloadables:
|
||||
print_downloadables(args.verbose)
|
||||
return 0
|
||||
if args.downloadable_engines:
|
||||
print_downloadable_engines(args.verbose)
|
||||
return 0
|
||||
elif args.downloadable_projects:
|
||||
print_downloadable_projects(args.verbose)
|
||||
return 0
|
||||
elif args.downloadable_gems:
|
||||
print_downloadable_gems(args.verbose)
|
||||
return 0
|
||||
elif args.downloadable_templates:
|
||||
print_downloadable_templates(args.verbose)
|
||||
return 0
|
||||
else:
|
||||
register_show(args.verbose)
|
||||
return 0
|
||||
return register_show(args.verbose)
|
||||
|
||||
|
||||
def add_parser_args(parser):
|
||||
@@ -376,78 +376,84 @@ def add_parser_args(parser):
|
||||
group = parser.add_mutually_exclusive_group(required=False)
|
||||
group.add_argument('-te', '--this-engine', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local engines.')
|
||||
help='Output the current engine path.')
|
||||
|
||||
group.add_argument('-e', '--engines', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local engines.')
|
||||
help='Output the engines registered in the global ~/.o3de/o3de_manifest.json.')
|
||||
group.add_argument('-p', '--projects', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local projects.')
|
||||
help='Output the projects registered in the global ~/.o3de/o3de_manifest.json.')
|
||||
group.add_argument('-g', '--gems', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local gems.')
|
||||
help='Output the gems registered in the global ~/.o3de/o3de_manifest.json.')
|
||||
group.add_argument('-t', '--templates', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local templates.')
|
||||
help='Output the templates registered in the global ~/.o3de/o3de_manifest.json.')
|
||||
group.add_argument('-r', '--repos', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local repos. Ignores repos.')
|
||||
help='Output the repos registered in the global ~/.o3de/o3de_manifest.json. Ignores repos.')
|
||||
group.add_argument('-rs', '--restricted', action='store_true', required=False,
|
||||
default=False,
|
||||
help='The local restricted folders.')
|
||||
help='Output the restricted directories registered in the global ~/.o3de/o3de_manifest.json.')
|
||||
|
||||
group.add_argument('-ep', '--engine-projects', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local projects. Ignores repos.')
|
||||
help='Output the projects registered in the current engine engine.json. Ignores repos.')
|
||||
group.add_argument('-eg', '--engine-gems', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local gems. Ignores repos')
|
||||
help='Output the gems registered in the current engine engine.json. Ignores repos')
|
||||
group.add_argument('-et', '--engine-templates', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local templates. Ignores repos.')
|
||||
help='Output the templates registered in the current engine engine.json. Ignores repos.')
|
||||
group.add_argument('-ers', '--engine-restricted', action='store_true', required=False,
|
||||
default=False,
|
||||
help='The restricted folders.')
|
||||
group.add_argument('-x', '--engine-external-subdirectories', action='store_true', required=False,
|
||||
help='Output the restricted directories registered in the current engine engine.json.')
|
||||
group.add_argument('-ees', '--engine-external-subdirectories', action='store_true', required=False,
|
||||
default=False,
|
||||
help='The external subdirectories.')
|
||||
help='Output the external subdirectories registered in the current engine engine.json.')
|
||||
|
||||
group.add_argument('-pg', '--project-gems', action='store_true',
|
||||
default=False,
|
||||
help='Returns the gems registered with the project.json.')
|
||||
group.add_argument('-pt', '--project-templates', action='store_true',
|
||||
default=False,
|
||||
help='Returns the templates registered with the project.json.')
|
||||
group.add_argument('-prs', '--project-restricted', action='store_true',
|
||||
default=False,
|
||||
help='Returns the restricted directories registered with the project.json.')
|
||||
group.add_argument('-pes', '--project-external-subdirectories', action='store_true',
|
||||
default=False,
|
||||
help='Returns the external subdirectories register with the project.json.')
|
||||
|
||||
group.add_argument('-ap', '--all-projects', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local projects. Ignores repos.')
|
||||
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='Just the local gems. Ignores repos')
|
||||
help='Output all gems registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos')
|
||||
group.add_argument('-at', '--all-templates', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Just the local templates. Ignores repos.')
|
||||
group.add_argument('-ars', '--all-restricted', action='store_true', required=False,
|
||||
help='Output all templates registered in the ~/.o3de/o3de_manifest.json and the current engine.json. Ignores repos.')
|
||||
group.add_argument('-ares', '--all-restricted', action='store_true', required=False,
|
||||
default=False,
|
||||
help='The restricted folders.')
|
||||
|
||||
group.add_argument('-d', '--downloadables', action='store_true', required=False,
|
||||
help='Output all restricted directory registered in the ~/.o3de/o3de_manifest.json and the current engine.json.')
|
||||
group.add_argument('-aes', '--all-external-subdirectories', action='store_true',
|
||||
default=False,
|
||||
help='Combine all repos into a single list of resources.')
|
||||
group.add_argument('-de', '--downloadable-engines', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Combine all repos engines into a single list of resources.')
|
||||
group.add_argument('-dp', '--downloadable-projects', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Combine all repos projects into a single list of resources.')
|
||||
group.add_argument('-dg', '--downloadable-gems', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Combine all repos gems into a single list of resources.')
|
||||
group.add_argument('-dt', '--downloadable-templates', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Combine all repos templates into a single list of resources.')
|
||||
help='Output all external subdirectories registered in the ~/.o3de/o3de_manifest.json and the current engine.json.')
|
||||
|
||||
parser.add_argument('-v', '--verbose', action='count', required=False,
|
||||
default=0,
|
||||
help='How verbose do you want the output to be.')
|
||||
default=0,
|
||||
help='How verbose do you want the output to be.')
|
||||
|
||||
project_group = parser.add_mutually_exclusive_group(required=False)
|
||||
project_group.add_argument('-pp', '--project-path', type=pathlib.Path,
|
||||
help='The path to a project.')
|
||||
project_group.add_argument('-pn', '--project-name', type=str,
|
||||
help='The name of a project.')
|
||||
|
||||
parser.add_argument('-ohf', '--override-home-folder', type=str, required=False,
|
||||
help='By default the home folder is the user folder, override it to this folder.')
|
||||
help='By default the home folder is the user folder, override it to this folder.')
|
||||
|
||||
parser.set_defaults(func=_run_register_show)
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#
|
||||
# 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 os
|
||||
import pathlib
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from o3de import manifest
|
||||
|
||||
logger = logging.getLogger()
|
||||
logging.basicConfig()
|
||||
|
||||
def get_project_props(name: str = None, path: pathlib.Path = None) -> dict:
|
||||
proj_json = manifest.get_project_json_data(project_name=name, project_path=path)
|
||||
if not proj_json:
|
||||
param = name if name else path
|
||||
logger.error(f'Could not retrieve project.json file for {param}')
|
||||
return None
|
||||
return proj_json
|
||||
|
||||
def edit_project_props(proj_path, proj_name, new_origin, new_display,
|
||||
new_summary, new_icon, new_tag, remove_tag) -> int:
|
||||
proj_json = get_project_props(proj_name, proj_path)
|
||||
|
||||
if not proj_json:
|
||||
return 1
|
||||
|
||||
if new_origin:
|
||||
proj_json['origin'] = new_origin
|
||||
if new_display:
|
||||
proj_json['display_name'] = new_display
|
||||
if new_summary:
|
||||
proj_json['summary'] = new_summary
|
||||
if new_icon:
|
||||
proj_json['icon_path'] = new_icon
|
||||
if new_tag:
|
||||
proj_json.setdefault('user_tags', []).append(new_tag)
|
||||
if remove_tag:
|
||||
if 'user_tags' in proj_json:
|
||||
if remove_tag in proj_json['user_tags']:
|
||||
proj_json['user_tags'].remove(remove_tag)
|
||||
else:
|
||||
logger.warn(f'{remove_tag} not found in user_tags for removal.')
|
||||
else:
|
||||
logger.warn(f'user_tags property not found for removal of tag {remove_tag}.')
|
||||
|
||||
manifest.save_o3de_manifest(proj_json, pathlib.Path(proj_path) / 'project.json')
|
||||
return 0
|
||||
|
||||
def _edit_project_props(args: argparse) -> int:
|
||||
return edit_project_props(args.project_path,
|
||||
args.project_name,
|
||||
args.project_origin,
|
||||
args.project_display,
|
||||
args.project_summary,
|
||||
args.project_icon,
|
||||
args.project_tag,
|
||||
args.remove_tag)
|
||||
|
||||
def add_parser_args(parser):
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument('-pp', '--project-path', type=pathlib.Path, required=False,
|
||||
help='The path to the project.')
|
||||
group.add_argument('-pn', '--project-name', type=str, required=False,
|
||||
help='The name of the project.')
|
||||
group = parser.add_argument_group('properties', 'arguments for modifying individual project properties.')
|
||||
group.add_argument('-po', '--project-origin', type=str, required=False,
|
||||
help='Sets description or url for project origin (such as project host, repository, owner...etc).')
|
||||
group.add_argument('-pd', '--project-display', type=str, required=False,
|
||||
help='Sets the project display name.')
|
||||
group.add_argument('-ps', '--project-summary', type=str, required=False,
|
||||
help='Sets the summary description of the project.')
|
||||
group.add_argument('-pi', '--project-icon', type=str, required=False,
|
||||
help='Sets the path to the projects icon resource.')
|
||||
group.add_argument('-pt', '--project-tag', type=str, required=False,
|
||||
help='Adds a tag to user_tags property. These tags are intended for documentation and filtering.')
|
||||
group.add_argument('-rt', '--remove-tag', type=str, required=False,
|
||||
help='Removes a tag from the user_tags property.')
|
||||
parser.set_defaults(func=_edit_project_props)
|
||||
|
||||
def add_args(subparsers) -> None:
|
||||
enable_project_props_subparser = subparsers.add_parser('edit-project-properties')
|
||||
add_parser_args(enable_project_props_subparser)
|
||||
|
||||
def main():
|
||||
the_parser = argparse.ArgumentParser()
|
||||
add_parser_args(the_parser)
|
||||
the_args = the_parser.parse_args()
|
||||
ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1
|
||||
sys.exit(ret)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -486,7 +486,7 @@ def register_default_engines_folder(json_data: dict,
|
||||
remove: bool = False) -> int:
|
||||
return register_default_o3de_object_folder(json_data,
|
||||
manifest.get_o3de_engines_folder() if remove else default_engines_folder,
|
||||
'default_engines_folder', remove)
|
||||
'default_engines_folder')
|
||||
|
||||
|
||||
def register_default_projects_folder(json_data: dict,
|
||||
@@ -494,7 +494,7 @@ def register_default_projects_folder(json_data: dict,
|
||||
remove: bool = False) -> int:
|
||||
return register_default_o3de_object_folder(json_data,
|
||||
manifest.get_o3de_projects_folder() if remove else default_projects_folder,
|
||||
'default_projects_folder', remove)
|
||||
'default_projects_folder')
|
||||
|
||||
|
||||
def register_default_gems_folder(json_data: dict,
|
||||
@@ -502,7 +502,7 @@ def register_default_gems_folder(json_data: dict,
|
||||
remove: bool = False) -> int:
|
||||
return register_default_o3de_object_folder(json_data,
|
||||
manifest.get_o3de_gems_folder() if remove else default_gems_folder,
|
||||
'default_gems_folder', remove)
|
||||
'default_gems_folder')
|
||||
|
||||
|
||||
def register_default_templates_folder(json_data: dict,
|
||||
@@ -510,16 +510,22 @@ def register_default_templates_folder(json_data: dict,
|
||||
remove: bool = False) -> int:
|
||||
return register_default_o3de_object_folder(json_data,
|
||||
manifest.get_o3de_templates_folder() if remove else default_templates_folder,
|
||||
'default_templates_folder', remove)
|
||||
'default_templates_folder')
|
||||
|
||||
|
||||
def register_default_restricted_folder(json_data: dict,
|
||||
default_restricted_folder: str or pathlib.Path,
|
||||
reset_to_default: bool = False) -> int:
|
||||
remove: bool = False) -> int:
|
||||
return register_default_o3de_object_folder(json_data,
|
||||
manifest.get_o3de_restricted_folder() if remove else default_restricted_folder,
|
||||
'default_restricted_folder', remove)
|
||||
'default_restricted_folder')
|
||||
|
||||
def register_default_third_party_folder(json_data: dict,
|
||||
default_third_party_folder: pathlib.Path,
|
||||
remove: bool = False) -> int:
|
||||
return register_default_o3de_object_folder(json_data,
|
||||
manifest.get_o3de_third_party_folder() if remove else default_third_party_folder,
|
||||
'default_third_party_folder')
|
||||
|
||||
def register(engine_path: str or pathlib.Path = None,
|
||||
project_path: str or pathlib.Path = None,
|
||||
@@ -533,6 +539,7 @@ def register(engine_path: str or pathlib.Path = None,
|
||||
default_gems_folder: str or pathlib.Path = None,
|
||||
default_templates_folder: str or pathlib.Path = None,
|
||||
default_restricted_folder: str or pathlib.Path = None,
|
||||
default_third_party_folder: pathlib.Path = None,
|
||||
external_subdir_engine_path: pathlib.Path = None,
|
||||
external_subdir_project_path: pathlib.Path = None,
|
||||
remove: bool = False,
|
||||
@@ -553,6 +560,7 @@ def register(engine_path: str or pathlib.Path = None,
|
||||
:param default_gems_folder: default gems folder
|
||||
:param default_templates_folder: default templates folder
|
||||
:param default_restricted_folder: default restricted code folder
|
||||
:param default_third_party_folder: default 3rd party cache folder
|
||||
:param external_subdir_engine_path: Path to the engine to use when registering an external subdirectory.
|
||||
The registration occurs in the engine.json file in this case
|
||||
:param external_subdir_engine_path: Path to the project to use when registering an external subdirectory.
|
||||
@@ -620,6 +628,9 @@ def register(engine_path: str or pathlib.Path = None,
|
||||
elif isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath):
|
||||
result = register_default_restricted_folder(json_data, default_restricted_folder, remove)
|
||||
|
||||
elif default_third_party_folder:
|
||||
result = register_default_third_party_folder(json_data, default_third_party_folder, remove)
|
||||
|
||||
# engine is done LAST
|
||||
# Now that everything that could have an engine context is done, if the engine is supplied that means this is
|
||||
# registering the engine itself
|
||||
@@ -712,6 +723,15 @@ def remove_invalid_o3de_objects() -> None:
|
||||
f" Set default {default_restricted_folder}")
|
||||
register(default_restricted_folder=default_restricted_folder.as_posix())
|
||||
|
||||
default_third_party_folder = pathlib.Path(json_data['default_third_party_folder']).resolve()
|
||||
if not default_third_party_folder.is_dir():
|
||||
default_third_party_folder = manifest.get_o3de_folder() / '3rdParty'
|
||||
default_third_party_folder.mkdir(parents=True, exist_ok=True)
|
||||
logger.warn(
|
||||
f"Default 3rd Party folder {default_third_party_folder} is invalid."
|
||||
f" Set default {default_third_party_folder}")
|
||||
register(default_third_party_folder=default_third_party_folder.as_posix())
|
||||
|
||||
|
||||
def _run_register(args: argparse) -> int:
|
||||
if args.override_home_folder:
|
||||
@@ -751,6 +771,7 @@ def _run_register(args: argparse) -> int:
|
||||
default_gems_folder=args.default_gems_folder,
|
||||
default_templates_folder=args.default_templates_folder,
|
||||
default_restricted_folder=args.default_restricted_folder,
|
||||
default_third_party_folder=args.default_third_party_folder,
|
||||
external_subdir_engine_path=args.external_subdirectory_engine_path,
|
||||
external_subdir_project_path=args.external_subdirectory_project_path,
|
||||
remove=args.remove,
|
||||
@@ -804,6 +825,8 @@ def add_parser_args(parser):
|
||||
help='The default templates folder to register/remove.')
|
||||
group.add_argument('-drf', '--default-restricted-folder', type=str, required=False,
|
||||
help='The default restricted folder to register/remove.')
|
||||
group.add_argument('-dtpf', '--default-third-party-folder', type=pathlib.Path, required=False,
|
||||
help='The default 3rd Party folder to register/remove.')
|
||||
group.add_argument('-u', '--update', action='store_true', required=False,
|
||||
default=False,
|
||||
help='Refresh the repo cache.')
|
||||
|
||||
@@ -34,3 +34,10 @@ ly_add_pytest(
|
||||
TEST_SUITE smoke
|
||||
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME o3de_manifest
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_manifest.py
|
||||
TEST_SUITE smoke
|
||||
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
|
||||
)
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#
|
||||
# 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 o3de import manifest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("valid_project_json_paths, valid_gem_json_paths", [
|
||||
pytest.param([pathlib.Path('D:/o3de/Templates/DefaultProject/Template/project.json')],
|
||||
[pathlib.Path('D:/o3de/Templates/DefaultGem/Template/gem.json')])
|
||||
])
|
||||
class TestGetTemplatesForCreation:
|
||||
@staticmethod
|
||||
def get_templates() -> list:
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def get_project_templates() -> list:
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def get_engine_templates() -> list:
|
||||
return [pathlib.Path('D:/o3de/Templates/DefaultProject'), pathlib.Path('D:/o3de/Templates/DefaultGem')]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_template_paths", [
|
||||
pytest.param([])
|
||||
]
|
||||
)
|
||||
def test_get_templates_for_generic_creation(self, valid_project_json_paths, valid_gem_json_paths,
|
||||
expected_template_paths):
|
||||
def validate_project_json(template_path) -> bool:
|
||||
return pathlib.Path(template_path) in valid_project_json_paths
|
||||
|
||||
def validate_gem_json(template_path) -> bool:
|
||||
return pathlib.Path(template_path) in valid_gem_json_paths
|
||||
|
||||
with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \
|
||||
patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates)\
|
||||
as get_project_templates_patch, \
|
||||
patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates)\
|
||||
as get_engine_templates_patch, \
|
||||
patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json,\
|
||||
patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) as validate_project_json,\
|
||||
patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json:
|
||||
templates = manifest.get_templates_for_generic_creation()
|
||||
assert templates == expected_template_paths
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_template_paths", [
|
||||
pytest.param([pathlib.Path('D:/o3de/Templates/DefaultProject')])
|
||||
]
|
||||
)
|
||||
def test_get_templates_for_gem_creation(self, valid_project_json_paths, valid_gem_json_paths,
|
||||
expected_template_paths):
|
||||
def validate_project_json(template_path) -> bool:
|
||||
return pathlib.Path(template_path) in valid_project_json_paths
|
||||
|
||||
def validate_gem_json(template_path) -> bool:
|
||||
return pathlib.Path(template_path) in valid_gem_json_paths
|
||||
|
||||
with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \
|
||||
patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \
|
||||
as get_project_templates_patch, \
|
||||
patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \
|
||||
as get_engine_templates_patch, \
|
||||
patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json, \
|
||||
patch('o3de.validation.valid_o3de_project_json',
|
||||
side_effect=validate_project_json) as validate_project_json, \
|
||||
patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json:
|
||||
templates = manifest.get_templates_for_project_creation()
|
||||
assert templates == expected_template_paths
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_template_paths", [
|
||||
pytest.param([pathlib.Path('D:/o3de/Templates/DefaultGem')])
|
||||
]
|
||||
)
|
||||
def test_get_templates_for_project_creation(self, valid_project_json_paths, valid_gem_json_paths,
|
||||
expected_template_paths):
|
||||
def validate_project_json(template_path) -> bool:
|
||||
return pathlib.Path(template_path) in valid_project_json_paths
|
||||
|
||||
def validate_gem_json(template_path) -> bool:
|
||||
return pathlib.Path(template_path) in valid_gem_json_paths
|
||||
|
||||
with patch('o3de.manifest.get_templates', side_effect=self.get_templates) as get_templates_patch, \
|
||||
patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \
|
||||
as get_project_templates_patch, \
|
||||
patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \
|
||||
as get_engine_templates_patch, \
|
||||
patch('o3de.validation.valid_o3de_template_json', return_value=True) as validate_template_json, \
|
||||
patch('o3de.validation.valid_o3de_project_json',
|
||||
side_effect=validate_project_json) as validate_project_json, \
|
||||
patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) as validate_gem_json:
|
||||
templates = manifest.get_templates_for_gem_creation()
|
||||
assert templates == expected_template_paths
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from . import utils
|
||||
from o3de import utils
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value, expected_result", [
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
ly_download_associated_package(pyside2)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME test_pyside
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/tests/test_pyside.py
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME test_projects
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/tests/test_projects.py
|
||||
)
|
||||
@@ -1,10 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
@@ -1,804 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
# PySide project and gem selector GUI
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import subprocess
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from typing import List
|
||||
from pyside import add_pyside_environment, is_pyside_ready, uninstall_env
|
||||
|
||||
engine_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
sys.path.append(engine_path)
|
||||
executable_path = ''
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
from o3de import disable_gem, enable_gem, cmake, engine_template, manifest, register
|
||||
|
||||
o3de_folder = manifest.get_o3de_folder()
|
||||
o3de_logs_folder = manifest.get_o3de_logs_folder()
|
||||
project_manager_log_file_path = o3de_logs_folder / "project_manager.log"
|
||||
log_file_handler = RotatingFileHandler(filename=project_manager_log_file_path, maxBytes=1024 * 1024, backupCount=1)
|
||||
formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s')
|
||||
log_file_handler.setFormatter(formatter)
|
||||
logger.addHandler(log_file_handler)
|
||||
|
||||
logger.info("Starting Project Manager")
|
||||
|
||||
|
||||
def initialize_pyside_from_parser():
|
||||
# Parse arguments up top. We need to know the path to our binaries and QT libs in particular to load up
|
||||
# PySide
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--executable-path', required=True, help='Path to Executable to launch with project')
|
||||
parser.add_argument('--binaries-path', default=None, help='Path to QT Binaries necessary for PySide. If not'
|
||||
' provided executable_path folder is assumed')
|
||||
parser.add_argument('--parent-pid', default=0, help='Process ID of launching process')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
logger.info(f"parent_pid is {args.parent_pid}")
|
||||
global executable_path
|
||||
executable_path = args.executable_path
|
||||
binaries_path = args.binaries_path or os.path.dirname(executable_path)
|
||||
|
||||
# Initialize PySide before imports below. This adds both PySide python modules to the python system interpreter
|
||||
# path and adds the necessary paths to binaries for the DLLs to be found and load their dependencies
|
||||
add_pyside_environment(binaries_path)
|
||||
|
||||
|
||||
if not is_pyside_ready():
|
||||
initialize_pyside_from_parser()
|
||||
|
||||
try:
|
||||
from PySide2.QtWidgets import QApplication, QDialogButtonBox, QPushButton, QComboBox, QMessageBox, QFileDialog
|
||||
from PySide2.QtWidgets import QListView, QLabel
|
||||
from PySide2.QtUiTools import QUiLoader
|
||||
from PySide2.QtCore import QFile, QObject, Qt, Signal, Slot
|
||||
from PySide2.QtGui import QIcon, QStandardItemModel, QStandardItem
|
||||
except ImportError as e:
|
||||
logger.error(f"Failed to import PySide2 with error {e}")
|
||||
exit(-1)
|
||||
|
||||
logger.error(f"PySide2 imports successful")
|
||||
|
||||
|
||||
class DialogLoggerSignaller(QObject):
|
||||
send_to_dialog = Signal(str)
|
||||
|
||||
def __init__(self, dialog_logger):
|
||||
super(DialogLoggerSignaller, self).__init__()
|
||||
|
||||
self.dialog_logger = dialog_logger
|
||||
|
||||
|
||||
# Independent class to handle log forwarding. Logger and qt signals both use emit method.
|
||||
# This class's job is to receive the logger record and then emit the formatted message through
|
||||
# DialogLoggerSignaller which is what the ProjectDialog handler listens for
|
||||
class DialogLogger(logging.Handler):
|
||||
|
||||
def __init__(self, log_dialog, log_level=logging.INFO, forward_log_level=logging.WARNING,
|
||||
message_box_log_level=logging.ERROR):
|
||||
super(DialogLogger, self).__init__()
|
||||
|
||||
self.log_dialog = log_dialog
|
||||
self.log_level = log_level
|
||||
self.forward_log_level = forward_log_level
|
||||
self.message_box_log_level = message_box_log_level
|
||||
self.log_records = []
|
||||
self.formatter = logging.Formatter('%(levelname)s : %(message)s')
|
||||
self.setFormatter(self.formatter)
|
||||
self.signaller = DialogLoggerSignaller(self)
|
||||
|
||||
def emit(self, record):
|
||||
self.log_records.append(record)
|
||||
if record.levelno >= self.message_box_log_level:
|
||||
QMessageBox.warning(None, record.levelname, record.message)
|
||||
elif record.levelno >= self.forward_log_level:
|
||||
self.signaller.send_to_dialog.emit(self.format(record))
|
||||
|
||||
|
||||
class ProjectManagerDialog(QObject):
|
||||
"""
|
||||
Main project manager dialog is responsible for displaying the project selection list and output pane
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(ProjectManagerDialog, self).__init__(parent)
|
||||
|
||||
self.ui_path = (pathlib.Path(__file__).parent / 'ui').resolve()
|
||||
self.home_folder = manifest.get_home_folder()
|
||||
|
||||
self.log_display = None
|
||||
self.dialog_logger = DialogLogger(self)
|
||||
logger.addHandler(self.dialog_logger)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
self.dialog_logger.signaller.send_to_dialog.connect(self.handle_log_message)
|
||||
self.mru_file_path = o3de_folder / 'mru.json'
|
||||
|
||||
self.create_from_template_ui_file_path = self.ui_path / 'create_from_template.ui'
|
||||
self.create_gem_ui_file_path = self.ui_path / 'create_gem.ui'
|
||||
self.create_project_ui_file_path = self.ui_path / 'create_project.ui'
|
||||
self.manage_project_gem_targets_ui_file_path = self.ui_path / 'manage_gem_targets.ui'
|
||||
self.project_manager_icon_file_path = self.ui_path / 'project_manager.ico'
|
||||
self.project_manager_ui_file_path = self.ui_path / 'project_manager.ui'
|
||||
|
||||
self.project_manager_ui_file = QFile(self.project_manager_ui_file_path.as_posix())
|
||||
self.project_manager_ui_file.open(QFile.ReadOnly)
|
||||
|
||||
loader = QUiLoader()
|
||||
self.dialog = loader.load(self.project_manager_ui_file)
|
||||
self.dialog.setWindowIcon(QIcon(self.project_manager_icon_file_path.as_posix()))
|
||||
self.dialog.setFixedSize(self.dialog.size())
|
||||
|
||||
self.project_list_box = self.dialog.findChild(QComboBox, 'projectListBox')
|
||||
self.refresh_project_list()
|
||||
mru = self.get_mru_list()
|
||||
if len(mru):
|
||||
last_mru = pathlib.Path(mru[0]).resolve()
|
||||
for this_slot in range(self.project_list_box.count()):
|
||||
item_text = self.project_list_box.itemText(this_slot)
|
||||
if last_mru.as_posix() in item_text:
|
||||
self.project_list_box.setCurrentIndex(this_slot)
|
||||
break
|
||||
|
||||
self.create_project_button = self.dialog.findChild(QPushButton, 'createProjectButton')
|
||||
self.create_project_button.clicked.connect(self.create_project_handler)
|
||||
self.create_gem_button = self.dialog.findChild(QPushButton, 'createGemButton')
|
||||
self.create_gem_button.clicked.connect(self.create_gem_handler)
|
||||
self.create_template_button = self.dialog.findChild(QPushButton, 'createTemplateButton')
|
||||
self.create_template_button.clicked.connect(self.create_template_handler)
|
||||
self.create_from_template_button = self.dialog.findChild(QPushButton, 'createFromTemplateButton')
|
||||
self.create_from_template_button.clicked.connect(self.create_from_template_handler)
|
||||
|
||||
self.add_project_button = self.dialog.findChild(QPushButton, 'addProjectButton')
|
||||
self.add_project_button.clicked.connect(self.add_project_handler)
|
||||
self.add_gem_button = self.dialog.findChild(QPushButton, 'addGemButton')
|
||||
self.add_gem_button.clicked.connect(self.add_gem_handler)
|
||||
self.add_template_button = self.dialog.findChild(QPushButton, 'addTemplateButton')
|
||||
self.add_template_button.clicked.connect(self.add_template_handler)
|
||||
self.add_restricted_button = self.dialog.findChild(QPushButton, 'addRestrictedButton')
|
||||
self.add_restricted_button.clicked.connect(self.add_restricted_handler)
|
||||
|
||||
self.remove_project_button = self.dialog.findChild(QPushButton, 'removeProjectButton')
|
||||
self.remove_project_button.clicked.connect(self.remove_project_handler)
|
||||
self.remove_gem_button = self.dialog.findChild(QPushButton, 'removeGemButton')
|
||||
self.remove_gem_button.clicked.connect(self.remove_gem_handler)
|
||||
self.remove_template_button = self.dialog.findChild(QPushButton, 'removeTemplateButton')
|
||||
self.remove_template_button.clicked.connect(self.remove_template_handler)
|
||||
self.remove_restricted_button = self.dialog.findChild(QPushButton, 'removeRestrictedButton')
|
||||
self.remove_restricted_button.clicked.connect(self.remove_restricted_handler)
|
||||
|
||||
self.manage_project_gem_targets_button = self.dialog.findChild(QPushButton, 'manageRuntimeGemTargetsButton')
|
||||
self.manage_project_gem_targets_button.clicked.connect(self.manage_project_gem_targets_handler)
|
||||
|
||||
self.log_display = self.dialog.findChild(QLabel, 'logDisplay')
|
||||
|
||||
self.ok_cancel_button = self.dialog.findChild(QDialogButtonBox, 'okCancel')
|
||||
self.ok_cancel_button.accepted.connect(self.accepted_handler)
|
||||
|
||||
self.dialog.show()
|
||||
|
||||
def refresh_project_list(self) -> None:
|
||||
projects = manifest.get_all_projects()
|
||||
self.project_list_box.clear()
|
||||
for this_slot in range(len(projects)):
|
||||
display_name = f'{os.path.basename(os.path.normpath(projects[this_slot]))} ({projects[this_slot]})'
|
||||
self.project_list_box.addItem(display_name)
|
||||
self.project_list_box.setItemData(self.project_list_box.count() - 1, projects[this_slot],
|
||||
Qt.ToolTipRole)
|
||||
|
||||
def accepted_handler(self) -> None:
|
||||
"""
|
||||
Override for handling "Ok" on main project dialog to first check whether the user has selected a project and
|
||||
prompt them to if not. If a project is selected will attempt to open it.
|
||||
:return: None
|
||||
"""
|
||||
if not self.project_list_box.currentText():
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText("Please select a project")
|
||||
msg_box.exec()
|
||||
return
|
||||
self.launch_with_project_path(self.get_selected_project_path())
|
||||
|
||||
def get_launch_project(self) -> str:
|
||||
return os.path.normpath(self.get_selected_project_path())
|
||||
|
||||
def get_executable_launch_params(self) -> list:
|
||||
"""
|
||||
Retrieve the necessary launch parameters to make the subprocess launch call with - this is the path
|
||||
to the executable such as the Editor and the path to the selected project
|
||||
:return: list of params
|
||||
"""
|
||||
launch_params = [executable_path,
|
||||
f'-regset="/Amazon/AzCore/Bootstrap/project_path={self.get_launch_project()}"']
|
||||
return launch_params
|
||||
|
||||
def launch_with_project_path(self, project_path: str) -> None:
|
||||
"""
|
||||
Launch the desired application given the selected project
|
||||
:param project_path: Path to currently selected project
|
||||
:return: None
|
||||
"""
|
||||
logger.info(f'Attempting to open {project_path}')
|
||||
self.update_mru_list(project_path)
|
||||
launch_params = self.get_executable_launch_params()
|
||||
logger.info(f'Launching with params {launch_params}')
|
||||
subprocess.run(launch_params, env=uninstall_env())
|
||||
|
||||
def get_selected_project_path(self) -> str:
|
||||
if self.project_list_box.currentIndex() == -1:
|
||||
logger.warning("No project selected")
|
||||
return ""
|
||||
return self.project_list_box.itemData(self.project_list_box.currentIndex(), Qt.ToolTipRole)
|
||||
|
||||
def get_selected_project_name(self) -> str:
|
||||
project_data = manifest.get_project_json_data(project_path=self.get_selected_project_path())
|
||||
return project_data['project_name']
|
||||
|
||||
def create_project_handler(self):
|
||||
"""
|
||||
Opens the Create Project pane. Retrieves a list of available templates for display
|
||||
:return: None
|
||||
"""
|
||||
loader = QUiLoader()
|
||||
self.create_project_file = QFile(self.create_project_ui_file_path.as_posix())
|
||||
|
||||
if not self.create_project_file:
|
||||
logger.error(f'Failed to create project UI file at {self.create_project_file}')
|
||||
return
|
||||
|
||||
self.create_project_dialog = loader.load(self.create_project_file)
|
||||
|
||||
if not self.create_project_dialog:
|
||||
logger.error(f'Failed to load create project dialog file at {self.create_project_file}')
|
||||
return
|
||||
|
||||
self.create_project_ok_button = self.create_project_dialog.findChild(QDialogButtonBox, 'okCancel')
|
||||
self.create_project_ok_button.accepted.connect(self.create_project_accepted_handler)
|
||||
|
||||
self.create_project_template_list = self.create_project_dialog.findChild(QListView, 'projectTemplates')
|
||||
self.refresh_create_project_template_list()
|
||||
|
||||
self.create_project_dialog.exec()
|
||||
|
||||
def create_project_accepted_handler(self) -> None:
|
||||
"""
|
||||
Searches the available gems list for selected gems and attempts to add each one to the current project.
|
||||
Updates UI after completion.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
selected_item = self.create_project_template_list.selectionModel().currentIndex()
|
||||
project_template_path = self.create_project_template_list.model().data(selected_item)
|
||||
if not project_template_path:
|
||||
return
|
||||
|
||||
folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Project Name",
|
||||
manifest.get_o3de_projects_folder().as_posix())
|
||||
folder_dialog.setFileMode(QFileDialog.AnyFile)
|
||||
folder_dialog.setOptions(QFileDialog.ShowDirsOnly)
|
||||
project_count = 0
|
||||
project_name = "MyNewProject"
|
||||
while os.path.exists(os.path.join(engine_path, project_name)):
|
||||
project_name = f"MyNewProject{project_count}"
|
||||
project_count += 1
|
||||
folder_dialog.selectFile(project_name)
|
||||
project_folder = None
|
||||
if folder_dialog.exec():
|
||||
project_folder = folder_dialog.selectedFiles()
|
||||
if project_folder:
|
||||
if engine_template.create_project(project_path=project_folder[0],
|
||||
template_path=project_template_path) == 0:
|
||||
# Success
|
||||
register.register(project_path=project_folder[0])
|
||||
self.refresh_project_list()
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Project {project_folder[0]} created.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def create_gem_handler(self):
|
||||
"""
|
||||
Opens the Create Gem pane. Retrieves a list of available templates for display
|
||||
:return: None
|
||||
"""
|
||||
loader = QUiLoader()
|
||||
self.create_gem_file = QFile(self.create_gem_ui_file_path.as_posix())
|
||||
|
||||
if not self.create_gem_file:
|
||||
logger.error(f'Failed to create gem UI file at {self.create_gem_file}')
|
||||
return
|
||||
|
||||
self.create_gem_dialog = loader.load(self.create_gem_file)
|
||||
|
||||
if not self.create_gem_dialog:
|
||||
logger.error(f'Failed to load create gem dialog file at {self.create_gem_file}')
|
||||
return
|
||||
|
||||
self.create_gem_ok_button = self.create_gem_dialog.findChild(QDialogButtonBox, 'okCancel')
|
||||
self.create_gem_ok_button.accepted.connect(self.create_gem_accepted_handler)
|
||||
|
||||
self.create_gem_template_list = self.create_gem_dialog.findChild(QListView, 'gemTemplates')
|
||||
self.refresh_create_gem_template_list()
|
||||
|
||||
self.create_gem_dialog.exec()
|
||||
|
||||
def create_gem_accepted_handler(self) -> None:
|
||||
"""
|
||||
Searches the available gems list for selected gems and attempts to add each one to the current gem.
|
||||
Updates UI after completion.
|
||||
:return: None
|
||||
"""
|
||||
selected_item = self.create_gem_template_list.selectionModel().currentIndex()
|
||||
gem_template_path = self.create_gem_template_list.model().data(selected_item)
|
||||
if not gem_template_path:
|
||||
return
|
||||
|
||||
folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name",
|
||||
manifest.get_o3de_gems_folder().as_posix())
|
||||
folder_dialog.setFileMode(QFileDialog.AnyFile)
|
||||
folder_dialog.setOptions(QFileDialog.ShowDirsOnly)
|
||||
gem_count = 0
|
||||
gem_name = "MyNewGem"
|
||||
while os.path.exists(os.path.join(engine_path, gem_name)):
|
||||
gem_name = f"MyNewGem{gem_count}"
|
||||
gem_count += 1
|
||||
folder_dialog.selectFile(gem_name)
|
||||
gem_folder = None
|
||||
if folder_dialog.exec():
|
||||
gem_folder = folder_dialog.selectedFiles()
|
||||
if gem_folder:
|
||||
if engine_template.create_gem(gem_path=gem_folder[0],
|
||||
template_path=gem_template_path) == 0:
|
||||
# Success
|
||||
register.register(gem_path=gem_folder[0])
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Gem {gem_folder[0]} created.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def create_template_handler(self):
|
||||
"""
|
||||
Opens a foldr select dialog and lets the user select the source folder they want to make a template
|
||||
out of, then opens a second folder select dialog to get where they want to put the template and it name
|
||||
:return: None
|
||||
"""
|
||||
|
||||
source_folder = QFileDialog.getExistingDirectory(self.dialog,
|
||||
"Select a Folder to make a template out of.",
|
||||
manifest.get_o3de_folder().as_posix())
|
||||
if not source_folder:
|
||||
return
|
||||
|
||||
destination_template_folder_dialog = QFileDialog(self.dialog,
|
||||
"Select where the template is to be created and named.",
|
||||
manifest.get_o3de_templates_folder().as_posix())
|
||||
destination_template_folder_dialog.setFileMode(QFileDialog.AnyFile)
|
||||
destination_template_folder_dialog.setOptions(QFileDialog.ShowDirsOnly)
|
||||
destination_folder = None
|
||||
if destination_template_folder_dialog.exec():
|
||||
destination_folder = destination_template_folder_dialog.selectedFiles()
|
||||
if not destination_folder:
|
||||
return
|
||||
|
||||
if engine_template.create_template(source_path=source_folder,
|
||||
template_path=destination_folder[0]) == 0:
|
||||
# Success
|
||||
register.register(template_path=destination_folder[0])
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Template {destination_folder[0]} created.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def create_from_template_handler(self):
|
||||
"""
|
||||
Opens the Create from_template pane. Retrieves a list of available from_templates for display
|
||||
:return: None
|
||||
"""
|
||||
loader = QUiLoader()
|
||||
self.create_from_template_file = QFile(self.create_from_template_ui_file_path.as_posix())
|
||||
|
||||
if not self.create_from_template_file:
|
||||
logger.error(f'Failed to create from_template UI file at {self.create_from_template_file}')
|
||||
return
|
||||
|
||||
self.create_from_template_dialog = loader.load(self.create_from_template_file)
|
||||
|
||||
if not self.create_from_template_dialog:
|
||||
logger.error(f'Failed to load create from_template dialog file at {self.create_from_template_file}')
|
||||
return
|
||||
|
||||
self.create_from_template_ok_button = self.create_from_template_dialog.findChild(QDialogButtonBox, 'okCancel')
|
||||
self.create_from_template_ok_button.accepted.connect(self.create_from_template_accepted_handler)
|
||||
|
||||
self.create_from_template_list = self.create_from_template_dialog.findChild(QListView, 'genericTemplates')
|
||||
self.refresh_create_from_template_list()
|
||||
|
||||
self.create_from_template_dialog.exec()
|
||||
|
||||
def create_from_template_accepted_handler(self) -> None:
|
||||
"""
|
||||
Searches the available gems list for selected gems and attempts to add each one to the current gem.
|
||||
Updates UI after completion.
|
||||
:return: None
|
||||
"""
|
||||
create_gem_item = self.get_selected_gem_template()
|
||||
if not create_gem_item:
|
||||
return
|
||||
|
||||
folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name",
|
||||
manifest.get_o3de_gems_folder().as_posix())
|
||||
folder_dialog.setFileMode(QFileDialog.AnyFile)
|
||||
folder_dialog.setOptions(QFileDialog.ShowDirsOnly)
|
||||
gem_count = 0
|
||||
gem_name = "MyNewGem"
|
||||
while os.path.exists(os.path.join(engine_path, gem_name)):
|
||||
gem_name = f"MyNewGem{gem_count}"
|
||||
gem_count += 1
|
||||
folder_dialog.selectFile(gem_name)
|
||||
gem_folder = None
|
||||
if folder_dialog.exec():
|
||||
gem_folder = folder_dialog.selectedFiles()
|
||||
if gem_folder:
|
||||
if engine_template.create_gem(gem_folder[0], create_gem_item[1]) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"gem {os.path.basename(os.path.normpath(gem_folder[0]))} created."
|
||||
" Build your\nnew gem before hitting OK to launch.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def add_project_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid project. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder",
|
||||
manifest.get_o3de_projects_folder().as_posix())
|
||||
if project_folder:
|
||||
if register.register(project_path=project_folder) == 0:
|
||||
# Success
|
||||
self.refresh_project_list()
|
||||
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Added Project {project_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def add_gem_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a gem. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder",
|
||||
manifest.get_o3de_gems_folder().as_posix())
|
||||
if gem_folder:
|
||||
if register.register(gem_path=gem_folder) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Added Gem {gem_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def add_template_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid template. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder",
|
||||
manifest.get_o3de_templates_folder().as_posix())
|
||||
if template_folder:
|
||||
if register.register(template_path=template_folder) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Added Template {template_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def add_restricted_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid template. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder",
|
||||
manifest.get_o3de_restricted_folder().as_posix())
|
||||
if restricted_folder:
|
||||
if register.register(restricted_path=restricted_folder) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Added Restricted {restricted_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def remove_project_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid project. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder",
|
||||
manifest.get_o3de_projects_folder().as_posix())
|
||||
if project_folder:
|
||||
if register.register(project_path=project_folder, remove=True) == 0:
|
||||
# Success
|
||||
self.refresh_project_list()
|
||||
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Removed Project {project_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def remove_gem_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a gem. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder",
|
||||
manifest.get_o3de_gems_folder().as_posix())
|
||||
if gem_folder:
|
||||
if register.register(gem_path=gem_folder, remove=True) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Removed Gem {gem_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def remove_template_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid template. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder",
|
||||
manifest.get_o3de_templates_folder().as_posix())
|
||||
if template_folder:
|
||||
if register.register(template_path=template_folder, remove=True) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Removed Template {template_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def remove_restricted_handler(self):
|
||||
"""
|
||||
Open a file search dialog looking for a folder which contains a valid template. If valid
|
||||
will update the mru list with the new entry, if invalid will warn the user.
|
||||
:return: None
|
||||
"""
|
||||
restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder",
|
||||
manifest.get_o3de_restricted_folder().as_posix())
|
||||
if restricted_folder:
|
||||
if register.register(restricted_path=restricted_folder, remove=True) == 0:
|
||||
# Success
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText(f"Removed Restricted {restricted_folder}.")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
def manage_project_gem_targets_handler(self):
|
||||
"""
|
||||
Opens the Gem management pane. Waits for the load thread to complete if still running and displays all
|
||||
active gems for the current project as well as all available gems which aren't currently active.
|
||||
:return: None
|
||||
"""
|
||||
|
||||
if not self.get_selected_project_path():
|
||||
msg_box = QMessageBox(parent=self.dialog)
|
||||
msg_box.setWindowTitle("O3DE")
|
||||
msg_box.setText("Please select a project")
|
||||
msg_box.exec()
|
||||
return
|
||||
|
||||
loader = QUiLoader()
|
||||
self.manage_project_gem_targets_file = QFile(self.manage_project_gem_targets_ui_file_path.as_posix())
|
||||
|
||||
if not self.manage_project_gem_targets_file:
|
||||
logger.error(f'Failed to load manage gem targets UI file at {self.manage_project_gem_targets_ui_file_path}')
|
||||
return
|
||||
|
||||
self.manage_project_gem_targets_dialog = loader.load(self.manage_project_gem_targets_file)
|
||||
|
||||
if not self.manage_project_gem_targets_dialog:
|
||||
logger.error(f'Failed to load gems dialog file at {self.manage_project_gem_targets_ui_file_path.as_posix()}')
|
||||
return
|
||||
|
||||
self.manage_project_gem_targets_dialog.setWindowTitle(f"Manage Gems for Project:"
|
||||
f" {self.get_selected_project_name()}")
|
||||
|
||||
self.add_gem_button = self.manage_project_gem_targets_dialog.findChild(QPushButton, 'addGemTargetsButton')
|
||||
self.add_gem_button.clicked.connect(self.add_project_gem_targets_handler)
|
||||
|
||||
self.available_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView,
|
||||
'availableGemTargetsList')
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
|
||||
self.remove_project_gem_targets_button = self.manage_project_gem_targets_dialog.findChild(QPushButton,
|
||||
'removeGemTargetsButton')
|
||||
self.remove_project_gem_targets_button.clicked.connect(self.remove_project_gem_targets_handler)
|
||||
|
||||
self.enabled_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView,
|
||||
'enabledGemTargetsList')
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
|
||||
self.manage_project_gem_targets_dialog.exec()
|
||||
|
||||
|
||||
def manage_project_gem_targets_get_selected_available_gems(self) -> list:
|
||||
selected_items = self.available_gem_targets_list.selectionModel().selectedRows()
|
||||
return [(self.available_gem_targets_list.model().data(item)) for item in selected_items]
|
||||
|
||||
def manage_project_gem_targets_get_selected_enabled_gems(self) -> list:
|
||||
selected_items = self.enabled_gem_targets_list.selectionModel().selectedRows()
|
||||
return [(self.enabled_gem_targets_list.model().data(item)) for item in selected_items]
|
||||
|
||||
def add_project_gem_targets_handler(self) -> None:
|
||||
gem_paths = manifest.get_all_gems()
|
||||
for gem_target in self.manage_project_gem_targets_get_selected_available_gems():
|
||||
for gem_path in gem_paths:
|
||||
enable_gem.enable_gem_in_project(gem_path=gem_path,
|
||||
project_path=self.get_selected_project_path())
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
return
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
|
||||
def remove_project_gem_targets_handler(self):
|
||||
gem_paths = manifest.get_all_gems()
|
||||
for gem_target in self.manage_project_gem_targets_get_selected_enabled_gems():
|
||||
for gem_path in gem_paths:
|
||||
disable_gem.disable_gem_in_project(gem_path=gem_path,
|
||||
project_path=self.get_selected_project_path())
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
return
|
||||
self.refresh_project_gem_targets_available_list()
|
||||
self.refresh_project_gem_targets_enabled_list()
|
||||
|
||||
def refresh_project_gem_targets_enabled_list(self) -> None:
|
||||
enabled_project_gem_targets_model = QStandardItemModel()
|
||||
enabled_project_gems = cmake.get_project_gems(project_path=self.get_selected_project_path())
|
||||
for gem_target in sorted(enabled_project_gems):
|
||||
model_item = QStandardItem(gem_target)
|
||||
enabled_project_gem_targets_model.appendRow(model_item)
|
||||
self.enabled_gem_targets_list.setModel(enabled_project_gem_targets_model)
|
||||
|
||||
|
||||
def refresh_project_gem_targets_available_list(self) -> None:
|
||||
available_project_gem_targets_model = QStandardItemModel()
|
||||
enabled_project_gem_targets = cmake.get_project_gems(project_path=self.get_selected_project_path())
|
||||
all_gem_targets = manifest.get_all_gems()
|
||||
for gem_target in sorted(all_gem_targets):
|
||||
if gem_target not in enabled_project_gem_targets:
|
||||
model_item = QStandardItem(gem_target)
|
||||
available_project_gem_targets_model.appendRow(model_item)
|
||||
self.available_gem_targets_list.setModel(available_project_gem_targets_model)
|
||||
|
||||
|
||||
def refresh_create_project_template_list(self) -> None:
|
||||
self.create_project_template_model = QStandardItemModel()
|
||||
for project_template_path in manifest.get_project_templates():
|
||||
model_item = QStandardItem(project_template_path)
|
||||
self.create_project_template_model.appendRow(model_item)
|
||||
self.create_project_template_list.setModel(self.create_project_template_model)
|
||||
|
||||
def refresh_create_gem_template_list(self) -> None:
|
||||
self.create_gem_template_model = QStandardItemModel()
|
||||
for gem_template_path in manifest.get_gem_templates():
|
||||
model_item = QStandardItem(gem_template_path)
|
||||
self.create_gem_template_model.appendRow(model_item)
|
||||
self.create_gem_template_list.setModel(self.create_gem_template_model)
|
||||
|
||||
def refresh_create_from_template_list(self) -> None:
|
||||
self.create_from_template_model = QStandardItemModel()
|
||||
for generic_template_path in manifest.get_generic_templates():
|
||||
model_item = QStandardItem(generic_template_path)
|
||||
self.create_from_template_model.appendRow(model_item)
|
||||
self.create_from_template_list.setModel(self.create_from_template_model)
|
||||
|
||||
def update_mru_list(self, used_project: str) -> None:
|
||||
"""
|
||||
Promote a supplied project name to the "most recent" in a given MRU list.
|
||||
:param used_project: path to project to promote
|
||||
:param file_path: path to mru list file
|
||||
:return: None
|
||||
"""
|
||||
used_project = os.path.normpath(used_project)
|
||||
if not os.path.exists(os.path.dirname(self.mru_file_path)):
|
||||
os.makedirs(os.path.dirname(self.mru_file_path), exist_ok=True)
|
||||
mru_data = {}
|
||||
try:
|
||||
with open(self.mru_file_path, 'r') as mru_file:
|
||||
mru_data = json.loads(mru_file.read())
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
|
||||
recent_list = mru_data.get('Projects', [])
|
||||
recent_list = [item for item in recent_list if item.get('Path') != used_project and
|
||||
self.is_project_folder(item.get('Path'))]
|
||||
|
||||
new_list = [{'Path': used_project}]
|
||||
new_list.extend(recent_list)
|
||||
|
||||
mru_data['Projects'] = new_list
|
||||
try:
|
||||
with open(self.mru_file_path, 'w') as mru_file:
|
||||
mru_file.write(json.dumps(mru_data, indent=1))
|
||||
except PermissionError as e:
|
||||
logger.warning(f"Failed to write {self.mru_file_path} with error {e}")
|
||||
|
||||
def get_mru_list(self) -> List[str]:
|
||||
"""
|
||||
Retrieve the current MRU list. Does not perform validation that the projects still appear valid
|
||||
:return: list of full path strings to project folders
|
||||
"""
|
||||
if not os.path.exists(os.path.dirname(self.mru_file_path)):
|
||||
return []
|
||||
try:
|
||||
with open(self.mru_file_path, 'r') as mru_file:
|
||||
mru_data = json.loads(mru_file.read())
|
||||
except FileNotFoundError:
|
||||
return []
|
||||
except json.JSONDecodeError:
|
||||
logger.error(f'MRU list at {self.mru_file_path} is not valid JSON')
|
||||
return []
|
||||
|
||||
recent_list = mru_data.get('Projects', [])
|
||||
return [item.get('Path') for item in recent_list if item.get('Path') is not None]
|
||||
|
||||
@Slot(str)
|
||||
def handle_log_message(self, message: str) -> None:
|
||||
"""
|
||||
Signal handler for messages from the logger. Displays the most recent warning/error
|
||||
:param message: formatted log message from DialogLoggerSignaller
|
||||
:return:
|
||||
"""
|
||||
if not self.log_display:
|
||||
return
|
||||
self.log_display.setText(message)
|
||||
self.log_display.setToolTip(message)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
dialog_app = QApplication(sys.argv)
|
||||
my_dialog = ProjectManagerDialog()
|
||||
dialog_app.exec_()
|
||||
sys.exit(0)
|
||||
@@ -1,61 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
pyside_initialized = False
|
||||
old_env = os.environ.copy()
|
||||
|
||||
# Helper to extend OS PATH for pyside to locate our QT binaries based on our build folder
|
||||
def add_pyside_environment(bin_path):
|
||||
if is_pyside_ready():
|
||||
# No need to reinitialize currently
|
||||
logger.info("Pyside environment already initialized")
|
||||
return
|
||||
global old_env
|
||||
old_env = os.environ.copy()
|
||||
binaries_path = Path(os.path.normpath(bin_path))
|
||||
platforms_path = binaries_path.joinpath("platforms")
|
||||
logger.info(f'Adding binaries path {binaries_path}')
|
||||
os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = str(platforms_path)
|
||||
|
||||
path = os.environ['PATH']
|
||||
|
||||
new_path = os.pathsep.join([str(binaries_path), str(platforms_path), path])
|
||||
os.environ['PATH'] = new_path
|
||||
|
||||
global pyside_initialized
|
||||
pyside_initialized = True
|
||||
|
||||
|
||||
def is_pyside_ready():
|
||||
return pyside_initialized
|
||||
|
||||
|
||||
def is_configuration_valid(workspace):
|
||||
return os.path.basename(workspace.paths.build_directory()) != "debug"
|
||||
|
||||
|
||||
def uninstall_env():
|
||||
if not is_pyside_ready():
|
||||
logger.warning("Pyside not initialized")
|
||||
return os.environ
|
||||
|
||||
global old_env
|
||||
if old_env.get("QT_QPA_PLATFORM_PLUGIN_PATH"):
|
||||
old_env.pop("QT_QPA_PLATFORM_PLUGIN_PATH")
|
||||
os.environ = old_env
|
||||
return old_env
|
||||
@@ -1,10 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
@@ -1,255 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
|
||||
import pytest
|
||||
'''
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import logging
|
||||
import pathlib
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
# Code lives one folder above
|
||||
project_manager_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
sys.path.append(project_manager_path)
|
||||
|
||||
from pyside import add_pyside_environment, is_configuration_valid
|
||||
from ly_test_tools import WINDOWS
|
||||
|
||||
sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..', '..')))
|
||||
executable_path = ''
|
||||
from cmake.Tools import registration
|
||||
from cmake.Tools import engine_template
|
||||
|
||||
|
||||
class ProjectHelper:
|
||||
def __init__(self):
|
||||
self._temp_directory = pathlib.Path(tempfile.TemporaryDirectory().name).resolve()
|
||||
self._temp_directory.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
self.home_path = self._temp_directory
|
||||
registration.override_home_folder = self.home_path
|
||||
self.engine_path = registration.get_this_engine_path()
|
||||
if registration.register(engine_path=self.engine_path):
|
||||
assert True, f"Failed to register the engine."
|
||||
|
||||
if registration.register_shipped_engine_o3de_objects():
|
||||
assert True, f"Failed to register shipped engine objects."
|
||||
|
||||
self.projects_folder = registration.get_o3de_projects_folder()
|
||||
if not self.projects_folder.is_dir():
|
||||
assert True
|
||||
|
||||
self.application = None
|
||||
self.dialog = None
|
||||
|
||||
def create_empty_projects(self):
|
||||
self.project_1_dir = self.projects_folder / "Project1"
|
||||
if engine_template.create_project(project_manager_path=self.project_1_dir):
|
||||
assert True, f"Failed to create Project1."
|
||||
|
||||
self.project_2_dir = self.projects_folder / "Project2"
|
||||
if engine_template.create_project(project_manager_path=self.project_2_dir):
|
||||
assert True, f"Failed to create Project2."
|
||||
|
||||
self.project_3_dir = self.projects_folder / "Project3"
|
||||
if engine_template.create_project(project_manager_path=self.project_3_dir):
|
||||
assert True, f"Failed to create Project3."
|
||||
|
||||
self.invalid_project_dir = self.projects_folder / "InvalidProject"
|
||||
self.invalid_project_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def setup_dialog_test(self, workspace):
|
||||
add_pyside_environment(workspace.paths.build_directory())
|
||||
|
||||
if not is_configuration_valid(workspace):
|
||||
# This is essentially skipif debug. Our debug tests use our profile version of python, but that means we'd
|
||||
# need to use the profile version of PySide which works with the profile QT libs which aren't in the debug
|
||||
# folder we've built.
|
||||
return None
|
||||
|
||||
from PySide2.QtWidgets import QApplication, QMessageBox
|
||||
|
||||
if QApplication.instance():
|
||||
self.application = QApplication.instance()
|
||||
else:
|
||||
self.application = QApplication(sys.argv)
|
||||
assert self.application
|
||||
|
||||
from projects import ProjectManagerDialog
|
||||
|
||||
try:
|
||||
self.dialog = ProjectManagerDialog(settings_folder=self.home_path)
|
||||
return self.dialog
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to create ProjectManagerDialog with error {e}')
|
||||
return None
|
||||
|
||||
def create_project_from_template(self, project_name) -> bool:
|
||||
"""
|
||||
Uses the dialog to create a temporary project based on the first template found
|
||||
:param project_name: Name of project to create. Will be created under temp_project_root
|
||||
:return: True for Success, False for failure
|
||||
"""
|
||||
from PySide2.QtWidgets import QWidget, QFileDialog
|
||||
from projects import ProjectManagerDialog
|
||||
|
||||
QWidget.exec = MagicMock()
|
||||
self.dialog.create_project_handler()
|
||||
QWidget.exec.assert_called_once()
|
||||
|
||||
assert len(self.dialog.project_templates), 'Failed to find any project templates'
|
||||
ProjectManagerDialog.get_selected_project_template = MagicMock(return_value=self.dialog.project_templates[0])
|
||||
|
||||
QFileDialog.exec = MagicMock()
|
||||
create_project_path = self.projects_folder / project_name
|
||||
QFileDialog.selectedFiles = MagicMock(return_value=[create_project_path])
|
||||
self.dialog.create_project_accepted_handler()
|
||||
if create_project_path.is_dir():
|
||||
assert True, f"Expected project creation folder not found at {create_project_path}"
|
||||
|
||||
if QWidget.exec.call_count == 2:
|
||||
assert True, "Message box confirming project creation failed to show"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def project_helper():
|
||||
return ProjectHelper()
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently")
|
||||
@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent
|
||||
def test_logger_handler(workspace, project_helper):
|
||||
my_dialog = project_helper.setup_dialog_test(workspace)
|
||||
if not my_dialog:
|
||||
return
|
||||
|
||||
from PySide2.QtWidgets import QMessageBox
|
||||
QMessageBox.warning = MagicMock()
|
||||
logger.error(f'Testing logger')
|
||||
QMessageBox.warning.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently")
|
||||
@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent
|
||||
def test_mru_list(workspace, project_helper):
|
||||
my_dialog = project_helper.setup_dialog_test(workspace)
|
||||
if not my_dialog:
|
||||
return
|
||||
|
||||
project_helper.create_empty_projects()
|
||||
|
||||
from PySide2.QtWidgets import QMessageBox
|
||||
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 0, f'MRU list unexpectedly had entries: {mru_list}'
|
||||
|
||||
QMessageBox.warning = MagicMock()
|
||||
my_dialog.add_project(project_helper.invalid_project_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 0, f'MRU list unexpectedly added an invalid project : {mru_list}'
|
||||
QMessageBox.warning.assert_called_once()
|
||||
|
||||
my_dialog.add_project(project_helper.project_1_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 1, f'MRU list failed to add project at {project_helper.project_1_dir}'
|
||||
|
||||
my_dialog.add_project(project_helper.project_1_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 1, f'MRU list added project at {project_helper.project_1_dir} a second time : {mru_list}'
|
||||
|
||||
my_dialog.update_mru_list(project_helper.project_1_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 1, f'MRU list added project at {project_helper.project_1_dir} a second time : {mru_list}'
|
||||
|
||||
my_dialog.add_project(project_helper.project_2_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 2, f'MRU list failed to add project at {project_helper.project_2_dir}'
|
||||
|
||||
assert mru_list[0] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't first item"
|
||||
assert mru_list[1] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't second item"
|
||||
|
||||
my_dialog.update_mru_list(project_helper.project_1_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 2, f'MRU list added wrong items {mru_list}'
|
||||
assert mru_list[0] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't first item"
|
||||
assert mru_list[1] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't second item"
|
||||
|
||||
my_dialog.add_project(project_helper.invalid_project_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 2, f'MRU list added invalid item {mru_list}'
|
||||
assert mru_list[0] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't first item"
|
||||
assert mru_list[1] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't second item"
|
||||
|
||||
my_dialog.add_project(project_helper.project_3_dir)
|
||||
mru_list = my_dialog.get_mru_list()
|
||||
assert len(mru_list) == 3, f'MRU list failed to add {project_helper.project_3_dir} : {mru_list}'
|
||||
assert mru_list[0] == project_helper.project_3_dir, f"{project_helper.project_3_dir} wasn't first item"
|
||||
assert mru_list[1] == project_helper.project_1_dir, f"{project_helper.project_1_dir} wasn't second item"
|
||||
assert mru_list[2] == project_helper.project_2_dir, f"{project_helper.project_2_dir} wasn't third item"
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently")
|
||||
@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent
|
||||
def test_create_project(workspace, project_helper):
|
||||
my_dialog = project_helper.setup_dialog_test(workspace)
|
||||
if not my_dialog:
|
||||
return
|
||||
|
||||
project_helper.create_project_from_template("TestCreateProject")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently")
|
||||
@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent
|
||||
def test_add_remove_gems(workspace, project_helper):
|
||||
my_dialog = project_helper.setup_dialog_test(workspace)
|
||||
if not my_dialog:
|
||||
return
|
||||
|
||||
my_project_name = "TestAddRemoveGems"
|
||||
|
||||
project_helper.create_project_from_template(project_manager_path=my_project_name)
|
||||
my_project_path = project_helper.projects_folder / my_project_name
|
||||
|
||||
from PySide2.QtWidgets import QWidget, QFileDialog
|
||||
from projects import ProjectManagerDialog
|
||||
|
||||
assert my_dialog.get_selected_project_path() == my_project_path, "TestAddRemoveGems project not selected"
|
||||
QWidget.exec = MagicMock()
|
||||
my_dialog.manage_gems_handler()
|
||||
assert my_dialog.manage_gem_targets_dialog, "No gem management dialog created"
|
||||
QWidget.exec.assert_called_once()
|
||||
|
||||
if not len(my_dialog.all_gems_list):
|
||||
assert True, 'Failed to find any gems'
|
||||
|
||||
my_test_gem_path = my_dialog.all_gems_list[0]
|
||||
gem_data = registration.get_gem_data(my_test_gem_path)
|
||||
my_test_gem_selection = (my_test_gem_name, my_test_gem_path)
|
||||
ProjectManagerDialog.get_selected_add_gems = MagicMock(return_value=[my_test_gem_selection])
|
||||
|
||||
assert my_test_gem_name, "No Name set in test gem"
|
||||
assert my_test_gem_name not in my_dialog.project_gem_list, f'Gem {my_test_gem_name} already in project gem list'
|
||||
|
||||
my_dialog.add_gems_handler()
|
||||
assert my_test_gem_name in my_dialog.project_gem_list, f'Gem {my_test_gem_name} failed to add to gem list'
|
||||
|
||||
ProjectManagerDialog.get_selected_project_gems = MagicMock(return_value=[my_test_gem_name])
|
||||
my_dialog.remove_gems_handler()
|
||||
assert my_test_gem_name not in my_dialog.project_gem_list, f'Gem {my_test_gem_name} still in project gem list'
|
||||
'''
|
||||
|
||||
def test_project_place_holder():
|
||||
pass
|
||||
@@ -1,54 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
import pytest
|
||||
import sys
|
||||
import os
|
||||
|
||||
pyside_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
sys.path.append(pyside_path)
|
||||
|
||||
from pyside import add_pyside_environment, is_pyside_ready, is_configuration_valid
|
||||
|
||||
from ly_test_tools import WINDOWS
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger()
|
||||
|
||||
@pytest.mark.skipif(not WINDOWS, reason="PySide2 only works on windows currently")
|
||||
@pytest.mark.parametrize('project', ['']) # Workspace wants a project, but this test is not project dependent
|
||||
def test_add_pyside_environment(workspace):
|
||||
import_failed = False
|
||||
try:
|
||||
import PySide2
|
||||
except ImportError:
|
||||
import_failed = True
|
||||
|
||||
if not import_failed:
|
||||
cur_path = sys.path
|
||||
logger.warning(f"Expected to fail initial import but passed. Sys path was {cur_path}")
|
||||
|
||||
assert is_pyside_ready() is False, "Expected pyside not to be initialized yet"
|
||||
add_pyside_environment(workspace.paths.build_directory())
|
||||
assert is_pyside_ready() is True, "Expected pyside to be initialized yet"
|
||||
|
||||
try:
|
||||
import PySide2
|
||||
if not is_configuration_valid(workspace):
|
||||
return
|
||||
from PySide2.QtWidgets import QApplication
|
||||
except ImportError as e:
|
||||
assert False, f"Failed to import PySide2 with error {e}"
|
||||
try:
|
||||
from PySide2.QtWidgets import QApplication
|
||||
except ImportError as e:
|
||||
assert False, f"Failed to import QApplication from PySide2.QtWidgets with error {e}"
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>createFromTemplateDialog</class>
|
||||
<widget class="QDialog" name="createFromTemplateDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>467</width>
|
||||
<height>288</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create From Template</string>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="okCancel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>50</x>
|
||||
<y>250</y>
|
||||
<width>400</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListView" name="genericTemplates">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>449</width>
|
||||
<height>221</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Available Templates</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>okCancel</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>createFromTemplateDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>okCancel</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>createFromTemplateDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,94 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>createGemDialog</class>
|
||||
<widget class="QDialog" name="createGemDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>467</width>
|
||||
<height>288</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Gem</string>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="okCancel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>50</x>
|
||||
<y>250</y>
|
||||
<width>400</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListView" name="gemTemplates">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>449</width>
|
||||
<height>221</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Available Templates</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>okCancel</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>createGemDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>okCancel</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>createGemDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,94 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>createProjectDialog</class>
|
||||
<widget class="QDialog" name="createProjectDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>467</width>
|
||||
<height>288</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Create Project</string>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="okCancel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>50</x>
|
||||
<y>250</y>
|
||||
<width>400</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListView" name="projectTemplates">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>449</width>
|
||||
<height>221</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Available Templates</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>okCancel</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>createProjectDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>okCancel</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>createProjectDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,165 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>manageGemTargetsDialog</class>
|
||||
<widget class="QDialog" name="manageGemTargetsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>702</width>
|
||||
<height>297</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Manage Gem Targets</string>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="close">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>310</x>
|
||||
<y>260</y>
|
||||
<width>71</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListView" name="availableGemTargetsList">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>440</x>
|
||||
<y>50</y>
|
||||
<width>250</width>
|
||||
<height>221</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListView" name="enabledGemTargetsList">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>50</y>
|
||||
<width>250</width>
|
||||
<height>221</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>440</x>
|
||||
<y>30</y>
|
||||
<width>251</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Available Gem Targets</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>30</y>
|
||||
<width>251</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enabled Gem Targets</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="removeGemTargetsButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>264</x>
|
||||
<y>130</y>
|
||||
<width>171</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove Gem Targets >></string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="addGemTargetsButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>264</x>
|
||||
<y>100</y>
|
||||
<width>171</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><< Add Gem Targets</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>5</y>
|
||||
<width>400</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Adding new Gem Targets may require rebuilding</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>close</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>manageGemTargetsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>close</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>manageGemTargetsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:113be7ded1969e0d535722382b6d3730eed052a10430cf23804ae7f20414b999
|
||||
size 108278
|
||||
@@ -1,407 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>712</width>
|
||||
<height>395</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>O3DE</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Select and manage your projects for O3DE</string>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="okCancel">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>540</x>
|
||||
<y>360</y>
|
||||
<width>161</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QComboBox" name="projectListBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>30</y>
|
||||
<width>691</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Current project to launch or manage gems for.</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>47</width>
|
||||
<height>13</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Project</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="logDisplay">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>270</x>
|
||||
<y>220</y>
|
||||
<width>431</width>
|
||||
<height>141</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="createGroupBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>70</y>
|
||||
<width>241</width>
|
||||
<height>151</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Create</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="createFromTemplateButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>110</y>
|
||||
<width>221</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Create a new O3DE object from a pre configured template.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create From Template</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="createProjectButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>221</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Create a new O3DE object from a pre configured template.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create Project</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="createGemButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>11</x>
|
||||
<y>50</y>
|
||||
<width>221</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Create a new O3DE object from a pre configured template.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create Gem</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="createTemplateButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>11</x>
|
||||
<y>80</y>
|
||||
<width>221</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Create a new O3DE object from a pre configured template.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create Template</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="addRemoveGroupBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>260</x>
|
||||
<y>70</y>
|
||||
<width>451</width>
|
||||
<height>141</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Registration</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="addTemplateButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>80</y>
|
||||
<width>211</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Browse for an existing O3DE project.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add Template</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="addProjectButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>211</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Browse for an existing O3DE project.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add Project</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="addGemButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>50</y>
|
||||
<width>211</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Browse for an existing O3DE project.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add Gem</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="addRestrictedButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>110</y>
|
||||
<width>211</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Browse for an existing O3DE project.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add Restricted</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="removeRestrictedButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>230</x>
|
||||
<y>110</y>
|
||||
<width>211</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Browse for an existing O3DE project.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove Restricted</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="removeProjectButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>230</x>
|
||||
<y>20</y>
|
||||
<width>211</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Browse for an existing O3DE project.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove Project</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="removeGemButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>230</x>
|
||||
<y>50</y>
|
||||
<width>211</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Browse for an existing O3DE project.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove Gem</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="removeTemplateButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>230</x>
|
||||
<y>80</y>
|
||||
<width>211</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Browse for an existing O3DE project.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove Template</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="manageProjectGroupBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>230</y>
|
||||
<width>241</width>
|
||||
<height>121</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Manage Project</string>
|
||||
</property>
|
||||
<widget class="QPushButton" name="manageServerGemTargetsButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>80</y>
|
||||
<width>221</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Add or remove gems from your selected project. Gems add and remove additional assets and features to projects.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Manage Server Gem Targets</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="manageToolGemTargetsButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>50</y>
|
||||
<width>221</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Add or remove gems from your selected project. Gems add and remove additional assets and features to projects.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Manage Tool Gem Targets</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" name="manageRuntimeGemTargetsButton">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>221</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Add or remove gems from your selected project. Gems add and remove additional assets and features to projects.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Manage Runtime Gem Targets</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>okCancel</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>okCancel</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
Reference in New Issue
Block a user