From 4630c82df0f5280414b01aa5cf884a06df1dd38c Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 28 Apr 2021 14:05:36 -0700 Subject: [PATCH 001/140] Preventing certain projects from showing up in the project's solution --- CMakeLists.txt | 62 +++++++++++++++++++++--------------------- cmake/CMakeFiles.cmake | 12 ++++---- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ad5cd9f431..20c964ed06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,50 +58,50 @@ include(cmake/CMakeFiles.cmake) include(cmake/Projects.cmake) if(NOT INSTALLED_ENGINE) + # Add the rest of the targets add_subdirectory(Code) add_subdirectory(Gems) -else() - ly_find_o3de_packages() -endif() + add_subdirectory(scripts) -set(enabled_platforms + # SPEC-1417 will investigate and fix this + if(NOT PAL_PLATFORM_NAME STREQUAL "Mac") + add_subdirectory(Tools/LyTestTools/tests/) + add_subdirectory(Tools/RemoteConsole/ly_remote_console/tests/) + endif() + + set(enabled_platforms ${PAL_PLATFORM_NAME} ${LY_PAL_TOOLS_ENABLED}) -foreach(restricted_platform ${PAL_RESTRICTED_PLATFORMS}) - if(restricted_platform IN_LIST enabled_platforms) - add_subdirectory(restricted/${restricted_platform}) - endif() -endforeach() + foreach(restricted_platform ${PAL_RESTRICTED_PLATFORMS}) + if(restricted_platform IN_LIST enabled_platforms) + add_subdirectory(restricted/${restricted_platform}) + endif() + endforeach() -add_subdirectory(scripts) + # Loop over the additional external subdirectories and invoke add_subdirectory on them + foreach(external_directory ${LY_EXTERNAL_SUBDIRS}) + # Hash the extenal_directory name and append it to the Binary Directory section of add_subdirectory + # This is to deal with potential situations where multiple external directories has the same last directory name + # For example if D:/Company1/RayTracingGem and F:/Company2/Path/RayTracingGem were both added as a subdirectory + file(REAL_PATH ${external_directory} full_directory_path) + string(SHA256 full_directory_hash ${full_directory_path}) + # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit + # when the external subdirectory contains relative paths of significant length + string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash) + # Use the last directory as the suffix path to use for the Binary Directory + get_filename_component(directory_name ${external_directory} NAME) + add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/${directory_name}-${full_directory_hash}) + endforeach() -# SPEC-1417 will investigate and fix this -if(NOT PAL_PLATFORM_NAME STREQUAL "Mac") - add_subdirectory(Tools/LyTestTools/tests/) - add_subdirectory(Tools/RemoteConsole/ly_remote_console/tests/) +else() + ly_find_o3de_packages() endif() ################################################################################ # Post-processing ################################################################################ - -# Loop over the additional external subdirectories and invoke add_subdirectory on them -foreach(external_directory ${LY_EXTERNAL_SUBDIRS}) - # Hash the extenal_directory name and append it to the Binary Directory section of add_subdirectory - # This is to deal with potential situations where multiple external directories has the same last directory name - # For example if D:/Company1/RayTracingGem and F:/Company2/Path/RayTracingGem were both added as a subdirectory - file(REAL_PATH ${external_directory} full_directory_path) - string(SHA256 full_directory_hash ${full_directory_path}) - # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit - # when the external subdirectory contains relative paths of significant length - string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash) - # Use the last directory as the suffix path to use for the Binary Directory - get_filename_component(directory_name ${external_directory} NAME) - add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/${directory_name}-${full_directory_hash}) -endforeach() - # The following steps have to be done after all targets are registered: # 1. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls # to provide applications with the filenames of gem modules to load @@ -124,6 +124,6 @@ ly_test_impact_post_step() if(NOT INSTALLED_ENGINE) ly_setup_o3de_install() - # IMPORTANT: must be included last + # 7. CPack information (to be included after install) include(cmake/CPack.cmake) endif() diff --git a/cmake/CMakeFiles.cmake b/cmake/CMakeFiles.cmake index 952f9b5eb8..77c2eb75e1 100644 --- a/cmake/CMakeFiles.cmake +++ b/cmake/CMakeFiles.cmake @@ -9,8 +9,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# Add all cmake files in a project so they can be handled from within the IDE -ly_include_cmake_file_list(cmake/cmake_files.cmake) -add_custom_target(CMakeFiles SOURCES ${ALLFILES}) -ly_source_groups_from_folders("${ALLFILES}") -unset(ALLFILES) \ No newline at end of file +if(NOT INSTALLED_ENGINE) + # Add all cmake files in a project so they can be handled from within the IDE + ly_include_cmake_file_list(cmake/cmake_files.cmake) + add_custom_target(CMakeFiles SOURCES ${ALLFILES}) + ly_source_groups_from_folders("${ALLFILES}") + unset(ALLFILES) +endif() \ No newline at end of file From 9681eb4a4d811933df309c18d32779f60fbfc321 Mon Sep 17 00:00:00 2001 From: pappeste Date: Fri, 30 Apr 2021 14:20:15 -0700 Subject: [PATCH 002/140] Improving projects shown in the IDE for projects building from installed sdk --- cmake/3rdParty.cmake | 9 ++++++--- cmake/Install.cmake | 12 ++++++++++-- cmake/LYPython.cmake | 9 +++++---- cmake/cmake_files.cmake | 1 + 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/cmake/3rdParty.cmake b/cmake/3rdParty.cmake index 7385f34e5a..eb11404237 100644 --- a/cmake/3rdParty.cmake +++ b/cmake/3rdParty.cmake @@ -313,6 +313,9 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/3rdParty) ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/3rdParty/Platform/${PAL_PLATFORM_NAME}) list(APPEND CMAKE_MODULE_PATH ${pal_dir}) -ly_include_cmake_file_list(cmake/3rdParty/cmake_files.cmake) -ly_get_absolute_pal_filename(pal_3rdparty_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}) -ly_include_cmake_file_list(${pal_3rdparty_dir}/cmake_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake) +if(NOT INSTALLED_ENGINE) + # Add the 3rdParty cmake files to the IDE + ly_include_cmake_file_list(cmake/3rdParty/cmake_files.cmake) + ly_get_absolute_pal_filename(pal_3rdparty_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}) + ly_include_cmake_file_list(${pal_3rdparty_dir}/cmake_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake) +endif() \ No newline at end of file diff --git a/cmake/Install.cmake b/cmake/Install.cmake index b56f5ced85..73a3273dfa 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -9,5 +9,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) -include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) \ No newline at end of file +if(NOT INSTALLED_ENGINE) + ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) + include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +else() + + # Provide empty implementation so ly_add_target continues working + function(ly_install_target ly_install_target_NAME) + endfunction() + +endif() \ No newline at end of file diff --git a/cmake/LYPython.cmake b/cmake/LYPython.cmake index ff5132097c..546d5f66db 100644 --- a/cmake/LYPython.cmake +++ b/cmake/LYPython.cmake @@ -265,10 +265,11 @@ if (NOT CMAKE_SCRIPT_MODE_FILE) # we also need to make sure any custom packages are installed. # this costs a moment of time though, so we'll only do it based on stamp files. - - ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/Tools/LyTestTools ly-test-tools) - ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/Tools/RemoteConsole/ly_remote_console ly-remote-console) - ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools editor-python-test-tools) + if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND NOT INSTALLED_ENGINE) + ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/Tools/LyTestTools ly-test-tools) + ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/Tools/RemoteConsole/ly_remote_console ly-remote-console) + ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools editor-python-test-tools) + endif() endif() endif() diff --git a/cmake/cmake_files.cmake b/cmake/cmake_files.cmake index 5045a42cbe..bd5976b494 100644 --- a/cmake/cmake_files.cmake +++ b/cmake/cmake_files.cmake @@ -12,6 +12,7 @@ set(FILES 3rdParty.cmake 3rdPartyPackages.cmake + CMakeFiles.cmake CommandExecution.cmake Configurations.cmake CPack.cmake From d046bae20babb0c876a52e61cd60956270777c1f Mon Sep 17 00:00:00 2001 From: pappeste Date: Fri, 30 Apr 2021 18:06:03 -0700 Subject: [PATCH 003/140] removing duplicate message --- cmake/Platform/Windows/Configurations_windows.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/Platform/Windows/Configurations_windows.cmake b/cmake/Platform/Windows/Configurations_windows.cmake index 6ab376ed0b..9ef535e455 100644 --- a/cmake/Platform/Windows/Configurations_windows.cmake +++ b/cmake/Platform/Windows/Configurations_windows.cmake @@ -106,7 +106,7 @@ if(NOT CMAKE_GENERATOR MATCHES "Visual Studio") endforeach() if(NOT version VERSION_EQUAL CMAKE_SYSTEM_VERSION) - message(STATUS "Selecting Windows SDK version ${version} to target Windows ${CMAKE_SYSTEM_VERSION}.") + message(STATUS "Using Windows SDK version ${version} to target Windows ${CMAKE_SYSTEM_VERSION}") endif() ly_set(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION "${version}") @@ -116,4 +116,3 @@ endif() if(NOT CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION MATCHES "10.0") message(FATAL_ERROR "Unsupported version of Windows SDK ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}, specify \"-DCMAKE_SYSTEM_VERSION=10.0\" when invoking cmake") endif() -message(STATUS "Using Windows target SDK ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}") From a905f38cc4c2513ee018523cf86fc6e247d5043a Mon Sep 17 00:00:00 2001 From: pappeste Date: Fri, 30 Apr 2021 18:06:30 -0700 Subject: [PATCH 004/140] qt deploy --- cmake/Platform/Common/Install_common.cmake | 46 ++++++++++++++-------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index fb3a7b1b09..dac12d8a50 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -13,6 +13,10 @@ set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise ly_set(LY_DEFAULT_INSTALL_COMPONENT "Core") +file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) +set(install_output_folder "${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$") + #! ly_install_target: registers the target to be installed by cmake install. # # \arg:NAME name of the target @@ -47,13 +51,11 @@ function(ly_install_target ly_install_target_NAME) if(target_runtime_output_directory) file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) endif() - file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) get_target_property(target_library_output_directory ${ly_install_target_NAME} LIBRARY_OUTPUT_DIRECTORY) if(target_library_output_directory) file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) endif() - file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) install( TARGETS ${ly_install_target_NAME} @@ -85,6 +87,28 @@ function(ly_install_target ly_install_target_NAME) COMPONENT ${ly_install_target_COMPONENT} ) + get_target_property(target_type ${ly_install_target_NAME} TYPE) + set(runtime_dependencies_list SHARED MODULE EXECUTABLE APPLICATION) # Only have to deploy for dlls/exes + if(target_type IN_LIST runtime_dependencies_list) + get_property(has_qt_dependency GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${ly_install_target_NAME}) + if(has_qt_dependency) + # Qt deploy needs to be done after the binary is copied to the output, so we do a install(CODE) which effectively + # puts it as a postbuild step of the "install" target. Binaries are copied at that point. + if(NOT EXISTS ${WINDEPLOYQT_EXECUTABLE}) + message(FATAL_ERROR "Qt deploy executable not found: ${WINDEPLOYQT_EXECUTABLE}") + endif() + set(target_output "${install_output_folder}/${target_runtime_output_subdirectory}/$") + install(CODE +"execute_process(COMMAND \"${WINDEPLOYQT_EXECUTABLE}\" --verbose 0 --no-compiler-runtime \"${target_output}\" ERROR_VARIABLE deploy_error RESULT_VARIABLE deploy_result) +if (NOT \${deploy_result} EQUAL 0) + if(NOT deploy_result MATCHES \"does not seem to be a Qt executable\" ) + message(SEND_ERROR \"Deploying qt for ${target_output} returned \${result}: \${deploy_error}\") + endif() +endif() +") + endif() + endif() + endfunction() @@ -310,8 +334,8 @@ function(ly_setup_others) # Registry install(DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/bin/$/Registry - DESTINATION ./bin/$ + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/Registry + DESTINATION ./${runtime_output_directory}/${PAL_PLATFORM_NAME}/$ COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(DIRECTORY @@ -329,8 +353,7 @@ function(ly_setup_others) # Gem Source Assets and Registry # Find all gem directories relative to the CMake Source Dir - file( - GLOB_RECURSE + file(GLOB_RECURSE gems_assets_path LIST_DIRECTORIES TRUE RELATIVE "${CMAKE_SOURCE_DIR}/" @@ -350,17 +373,6 @@ function(ly_setup_others) endif() endforeach() - - # Qt Binaries - set(QT_BIN_DIRS bearer iconengines imageformats platforms styles translations) - foreach(qt_dir ${QT_BIN_DIRS}) - install(DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/bin/$/${qt_dir} - DESTINATION ./bin/$ - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} - ) - endforeach() - # Templates install(DIRECTORY ${CMAKE_SOURCE_DIR}/Templates From ed17d01028d1a582df72e7149bf1a46b907430e1 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 3 May 2021 17:10:40 -0700 Subject: [PATCH 005/140] making the runtime_dependencies a function so we can reuse internal functions for the install --- CMakeLists.txt | 3 +- .../Common/RuntimeDependencies_common.cmake | 82 ++++++++-------- .../iOS/RuntimeDependencies_ios.cmake | 94 ++++++++++--------- 3 files changed, 94 insertions(+), 85 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2504bd625d..bd55e91e08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ include(cmake/GeneralSettings.cmake) include(cmake/FileUtil.cmake) include(cmake/PAL.cmake) include(cmake/PALTools.cmake) +include(cmake/RuntimeDependencies.cmake) include(cmake/Install.cmake) include(cmake/Configurations.cmake) # Requires to be after PAL so we get platform variable definitions include(cmake/Dependencies.cmake) @@ -117,7 +118,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) endif() # 4. inject runtime dependencies to the targets. We need to do this after (1) since we are going to walk through # the dependencies -include(cmake/RuntimeDependencies.cmake) +ly_delayed_generate_runtime_dependencies() # 5. Perform test impact framework post steps once all of the targets have been enumerated ly_test_impact_post_step() # 6. Generate the O3DE find file and setup install locations for scripts, tools, assets etc., required by the engine diff --git a/cmake/Platform/Common/RuntimeDependencies_common.cmake b/cmake/Platform/Common/RuntimeDependencies_common.cmake index 6ac5215a01..859d1d21e3 100644 --- a/cmake/Platform/Common/RuntimeDependencies_common.cmake +++ b/cmake/Platform/Common/RuntimeDependencies_common.cmake @@ -10,7 +10,7 @@ # set(LY_COPY_PERMISSIONS "OWNER_READ OWNER_WRITE OWNER_EXECUTE") -set(LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS MODULE_LIBRARY SHARED_LIBRARY EXECUTABLE) +set(LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS MODULE_LIBRARY SHARED_LIBRARY EXECUTABLE APPLICATION) # There are several runtime dependencies to handle: # 1. Dependencies to 3rdparty libraries. This involves copying IMPORTED_LOCATION to the folder where the target is. @@ -183,7 +183,7 @@ function(ly_get_runtime_dependency_command ly_RUNTIME_COMMAND ly_TARGET) # To support platforms where the binaries end in different places, we are going to assume that all dependencies, # including the ones we are building, need to be copied over. However, we add a check to prevent copying something # over itself. This detection cannot happen now because the target we are copying for varies. - set(runtime_command "ly_copy(\"${source_file}\" \"$${target_directory}\")\n") + set(runtime_command "ly_copy(\"${source_file}\" \"@target_file_dir@${target_directory}\")\n") # Tentative optimization: this is an attempt to solve the first "if" at generation time, making the runtime_dependencies # file smaller and faster to run. In platforms where the built target and the dependencies targets end up in the same @@ -206,47 +206,51 @@ function(ly_get_runtime_dependency_command ly_RUNTIME_COMMAND ly_TARGET) endfunction() -get_property(additional_module_paths GLOBAL PROPERTY LY_ADDITIONAL_MODULE_PATH) -list(APPEND CMAKE_MODULE_PATH ${additional_module_paths}) +function(ly_delayed_generate_runtime_dependencies) -get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) -foreach(target IN LISTS all_targets) + get_property(additional_module_paths GLOBAL PROPERTY LY_ADDITIONAL_MODULE_PATH) + list(APPEND CMAKE_MODULE_PATH ${additional_module_paths}) - # Exclude targets that dont produce runtime outputs - get_target_property(target_type ${target} TYPE) - if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS) - continue() - endif() + get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) + foreach(target IN LISTS all_targets) - unset(runtime_dependencies) - set(runtime_commands " -function(ly_copy source_file target_directory) - get_filename_component(target_filename \"\${source_file}\" NAME) - if(NOT \"\${source_file}\" STREQUAL \"\${target_directory}/\${target_filename}\") - if(NOT EXISTS \"\${target_directory}\") - file(MAKE_DIRECTORY \"\${target_directory}\") + # Exclude targets that dont produce runtime outputs + get_target_property(target_type ${target} TYPE) + if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS) + continue() endif() - if(\"\${source_file}\" IS_NEWER_THAN \"\${target_directory}/\${target_filename}\") - file(LOCK \"\${target_directory}/\${target_filename}.lock\" GUARD FUNCTION TIMEOUT 30) - file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) - endif() - endif() -endfunction() -\n") - ly_get_runtime_dependencies(runtime_dependencies ${target}) - foreach(runtime_dependency ${runtime_dependencies}) - unset(runtime_command) - ly_get_runtime_dependency_command(runtime_command ${runtime_dependency}) - string(APPEND runtime_commands ${runtime_command}) + unset(runtime_dependencies) + set(runtime_commands " + function(ly_copy source_file target_directory) + get_filename_component(target_filename \"\${source_file}\" NAME) + if(NOT \"\${source_file}\" STREQUAL \"\${target_directory}/\${target_filename}\") + if(NOT EXISTS \"\${target_directory}\") + file(MAKE_DIRECTORY \"\${target_directory}\") + endif() + if(\"\${source_file}\" IS_NEWER_THAN \"\${target_directory}/\${target_filename}\") + file(LOCK \"\${target_directory}/\${target_filename}.lock\" GUARD FUNCTION TIMEOUT 30) + file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) + endif() + endif() + endfunction() + \n") + + ly_get_runtime_dependencies(runtime_dependencies ${target}) + foreach(runtime_dependency ${runtime_dependencies}) + unset(runtime_command) + ly_get_runtime_dependency_command(runtime_command ${runtime_dependency}) + string(APPEND runtime_commands ${runtime_command}) + endforeach() + + # Generate the output file + set(target_file_dir "$") + string(CONFIGURE "${runtime_commands}" generated_commands @ONLY) + file(GENERATE + OUTPUT ${CMAKE_BINARY_DIR}/runtime_dependencies/$/${target}.cmake + CONTENT "${generated_commands}" + ) + endforeach() - - # Generate the output file - string(CONFIGURE "${runtime_commands}" generated_commands @ONLY) - file(GENERATE - OUTPUT ${CMAKE_BINARY_DIR}/runtime_dependencies/$/${target}.cmake - CONTENT "${generated_commands}" - ) - -endforeach() +endfunction() diff --git a/cmake/Platform/iOS/RuntimeDependencies_ios.cmake b/cmake/Platform/iOS/RuntimeDependencies_ios.cmake index d558c6f12a..034ab750ff 100644 --- a/cmake/Platform/iOS/RuntimeDependencies_ios.cmake +++ b/cmake/Platform/iOS/RuntimeDependencies_ios.cmake @@ -118,57 +118,61 @@ function(ios_get_dependencies_recursive ios_DEPENDENCIES ly_TARGET) endfunction() -# For each (non-monolithic) game project, find runtime dependencies and tell XCode to embed/sign them -if(NOT LY_MONOLITHIC_GAME) +function(ly_delayed_generate_runtime_dependencies) - foreach(game_project ${LY_PROJECTS}) + # For each (non-monolithic) game project, find runtime dependencies and tell XCode to embed/sign them + if(NOT LY_MONOLITHIC_GAME) - # Recursively get all dependent frameworks for the game project. - unset(dependencies) - ios_get_dependencies_recursive(dependencies ${game_project}.GameLauncher) - if(dependencies) - set_target_properties(${game_project}.GameLauncher - PROPERTIES - XCODE_EMBED_FRAMEWORKS "${dependencies}" - XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY TRUE - XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks" - ) + foreach(game_project ${LY_PROJECTS}) + + # Recursively get all dependent frameworks for the game project. + unset(dependencies) + ios_get_dependencies_recursive(dependencies ${game_project}.GameLauncher) + if(dependencies) + set_target_properties(${game_project}.GameLauncher + PROPERTIES + XCODE_EMBED_FRAMEWORKS "${dependencies}" + XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY TRUE + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks" + ) + endif() + + endforeach() + + endif() + + get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) + unset(test_runner_dependencies) + foreach(target IN LISTS all_targets) + # Exclude targets that dont produce runtime outputs + get_target_property(target_type ${target} TYPE) + if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS) + continue() endif() + + file(GENERATE + OUTPUT ${CMAKE_BINARY_DIR}/runtime_dependencies/$/${target}.cmake + CONTENT "" + ) + if(target_type IN_LIST IOS_FRAMEWORK_TARGET_TYPES) + list(APPEND test_runner_dependencies ${target}) + endif() endforeach() -endif() + if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + add_dependencies("AzTestRunner" ${test_runner_dependencies}) + + # We still need to add indirect dependencies(eg. 3rdParty) + unset(all_dependencies) + ios_get_dependencies_recursive(all_dependencies AzTestRunner) -get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) -unset(test_runner_dependencies) -foreach(target IN LISTS all_targets) - # Exclude targets that dont produce runtime outputs - get_target_property(target_type ${target} TYPE) - if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS) - continue() + set_target_properties("AzTestRunner" + PROPERTIES + XCODE_EMBED_FRAMEWORKS "${all_dependencies}" + XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY TRUE + XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks" + ) endif() - - file(GENERATE - OUTPUT ${CMAKE_BINARY_DIR}/runtime_dependencies/$/${target}.cmake - CONTENT "" - ) - if(target_type IN_LIST IOS_FRAMEWORK_TARGET_TYPES) - list(APPEND test_runner_dependencies ${target}) - endif() -endforeach() - -if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) - add_dependencies("AzTestRunner" ${test_runner_dependencies}) - - # We still need to add indirect dependencies(eg. 3rdParty) - unset(all_dependencies) - ios_get_dependencies_recursive(all_dependencies AzTestRunner) - - set_target_properties("AzTestRunner" - PROPERTIES - XCODE_EMBED_FRAMEWORKS "${all_dependencies}" - XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY TRUE - XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks" - ) -endif() \ No newline at end of file +endfunction() \ No newline at end of file From fd9bac8684a31b143921ad3b7415e08afbf430dc Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 3 May 2021 17:11:03 -0700 Subject: [PATCH 006/140] Unnecessary empty line --- Gems/ImageProcessing/Code/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/ImageProcessing/Code/CMakeLists.txt b/Gems/ImageProcessing/Code/CMakeLists.txt index a5cb6f6cb9..41d4b95179 100644 --- a/Gems/ImageProcessing/Code/CMakeLists.txt +++ b/Gems/ImageProcessing/Code/CMakeLists.txt @@ -81,7 +81,6 @@ ly_add_source_properties( ly_add_target( NAME ImageProcessing.Editor GEM_MODULE - NAMESPACE Gem AUTOMOC AUTORCC From 04032d37bc5254bb87b65dee7dd5f672c8d515af Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 3 May 2021 17:11:25 -0700 Subject: [PATCH 007/140] leftover for a parameter it never existed --- cmake/LYWrappers.cmake | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index f6a36afc89..47515ba663 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -333,10 +333,6 @@ function(ly_add_target) endif() if(NOT ly_add_target_IMPORTED) - if(NOT ly_add_target_INSTALL_COMPONENT) - set(ly_add_target_INSTALL_COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT}) - endif() - ly_install_target( ${ly_add_target_NAME} NAMESPACE ${ly_add_target_NAMESPACE} @@ -344,7 +340,7 @@ function(ly_add_target) BUILD_DEPENDENCIES ${ly_add_target_BUILD_DEPENDENCIES} RUNTIME_DEPENDENCIES ${ly_add_target_RUNTIME_DEPENDENCIES} COMPILE_DEFINITIONS ${ly_add_target_COMPILE_DEFINITIONS} - COMPONENT ${ly_add_target_INSTALL_COMPONENT} + COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endif() From 5c68647b6b4bfebea1742cc66d1ce4b016f72394 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 3 May 2021 17:16:03 -0700 Subject: [PATCH 008/140] fixing qt deploy and adding install of runtime dependencies --- cmake/Platform/Common/Install_common.cmake | 91 ++++++++++++++++------ 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index dac12d8a50..a2fa54b503 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -17,6 +17,7 @@ file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_ file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) set(install_output_folder "${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$") + #! ly_install_target: registers the target to be installed by cmake install. # # \arg:NAME name of the target @@ -87,28 +88,6 @@ function(ly_install_target ly_install_target_NAME) COMPONENT ${ly_install_target_COMPONENT} ) - get_target_property(target_type ${ly_install_target_NAME} TYPE) - set(runtime_dependencies_list SHARED MODULE EXECUTABLE APPLICATION) # Only have to deploy for dlls/exes - if(target_type IN_LIST runtime_dependencies_list) - get_property(has_qt_dependency GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${ly_install_target_NAME}) - if(has_qt_dependency) - # Qt deploy needs to be done after the binary is copied to the output, so we do a install(CODE) which effectively - # puts it as a postbuild step of the "install" target. Binaries are copied at that point. - if(NOT EXISTS ${WINDEPLOYQT_EXECUTABLE}) - message(FATAL_ERROR "Qt deploy executable not found: ${WINDEPLOYQT_EXECUTABLE}") - endif() - set(target_output "${install_output_folder}/${target_runtime_output_subdirectory}/$") - install(CODE -"execute_process(COMMAND \"${WINDEPLOYQT_EXECUTABLE}\" --verbose 0 --no-compiler-runtime \"${target_output}\" ERROR_VARIABLE deploy_error RESULT_VARIABLE deploy_result) -if (NOT \${deploy_result} EQUAL 0) - if(NOT deploy_result MATCHES \"does not seem to be a Qt executable\" ) - message(SEND_ERROR \"Deploying qt for ${target_output} returned \${result}: \${deploy_error}\") - endif() -endif() -") - endif() - endif() - endfunction() @@ -235,6 +214,7 @@ function(ly_setup_o3de_install) ly_setup_cmake_install() ly_setup_target_generator() + ly_setup_runtime_dependencies() ly_setup_others() endfunction() @@ -306,6 +286,73 @@ function(ly_setup_cmake_install) endfunction() +#! ly_setup_runtime_dependencies: install runtime dependencies +function(ly_setup_runtime_dependencies) + + # Common functions used by the bellow code + install(CODE +"function(ly_deploy_qt_install target_output) + execute_process(COMMAND \"${WINDEPLOYQT_EXECUTABLE}\" --verbose 0 --no-compiler-runtime \"\${target_output}\" ERROR_VARIABLE deploy_error RESULT_VARIABLE deploy_result) + if (NOT \${deploy_result} EQUAL 0) + if(NOT deploy_error MATCHES \"does not seem to be a Qt executable\" ) + message(SEND_ERROR \"Deploying qt for \${target_output} returned \${deploy_result}: \${deploy_error}\") + endif() + endif() +endfunction() + +function(ly_copy source_file target_directory) + file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) +endfunction()" + COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + ) + + unset(runtime_commands) + get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) + foreach(target IN LISTS all_targets) + + # Exclude targets that dont produce runtime outputs + get_target_property(target_type ${target} TYPE) + if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS) + continue() + endif() + + get_target_property(target_runtime_output_directory ${target} RUNTIME_OUTPUT_DIRECTORY) + if(target_runtime_output_directory) + file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) + endif() + + # Qt + get_property(has_qt_dependency GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${target}) + if(has_qt_dependency) + # Qt deploy needs to be done after the binary is copied to the output, so we do a install(CODE) which effectively + # puts it as a postbuild step of the "install" target. Binaries are copied at that point. + if(NOT EXISTS ${WINDEPLOYQT_EXECUTABLE}) + message(FATAL_ERROR "Qt deploy executable not found: ${WINDEPLOYQT_EXECUTABLE}") + endif() + set(target_output "${install_output_folder}/${target_runtime_output_subdirectory}/$") + list(APPEND runtime_commands "ly_deploy_qt_install(\"${target_output}\")\n") + endif() + + # runtime dependencies that need to be copied to the output + set(target_file_dir "${install_output_folder}/${target_runtime_output_subdirectory}") + ly_get_runtime_dependencies(runtime_dependencies ${target}) + foreach(runtime_dependency ${runtime_dependencies}) + unset(runtime_command) + ly_get_runtime_dependency_command(runtime_command ${runtime_dependency}) + string(CONFIGURE "${runtime_command}" runtime_command @ONLY) + list(APPEND runtime_commands ${runtime_command}) + endforeach() + + endforeach() + + list(REMOVE_DUPLICATES runtime_commands) + list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file + install(CODE "${runtime_commands_str}" + COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + ) + +endfunction() + #! ly_setup_others: install directories required by the engine function(ly_setup_others) From d1416d53e08d4645aaae0fe8024e975bfda49c07 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 3 May 2021 18:16:08 -0700 Subject: [PATCH 009/140] adding a file for ImageProcessing --- cmake/Platform/Common/Install_common.cmake | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index a2fa54b503..0686b27fe7 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -420,6 +420,13 @@ function(ly_setup_others) endif() endforeach() + # Additional files needed by gems + install(FILES + ${CMAKE_SOURCE_DIR}/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings + DESTINATION Gems/ImageProcessing/Code/Source + COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + ) + # Templates install(DIRECTORY ${CMAKE_SOURCE_DIR}/Templates From b0732dd494231d2b600ee382fae2e776296b8434 Mon Sep 17 00:00:00 2001 From: pappeste Date: Tue, 4 May 2021 13:52:19 -0700 Subject: [PATCH 010/140] Changing find files to add_subdirectory to be able to have SettingsRegistry.cmake finding the path to the gems --- cmake/LYWrappers.cmake | 12 +++-- cmake/Platform/Common/Install_common.cmake | 45 ++++++++++--------- cmake/SettingsRegistry.cmake | 9 ++-- cmake/{ => install}/Findo3de.cmake.in | 0 .../TargetCMakeLists.txt.in} | 6 +-- 5 files changed, 35 insertions(+), 37 deletions(-) rename cmake/{ => install}/Findo3de.cmake.in (100%) rename cmake/{FindTarget.cmake.in => install/TargetCMakeLists.txt.in} (82%) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 47515ba663..62509582a1 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -52,7 +52,6 @@ define_property(TARGET PROPERTY GEM_MODULE # \arg:HEADERONLY (bool) defines this target to be a header only library. A ${NAME}_HEADERS project will be created for the IDE # \arg:EXECUTABLE (bool) defines this target to be an executable # \arg:APPLICATION (bool) defines this target to be an application (executable that is not a console) -# \arg:UNKNOWN (bool) defines this target to be unknown. This is used when importing installed targets from Find files # \arg:IMPORTED (bool) defines this target to be imported. # \arg:NAMESPACE namespace declaration for this target. It will be used for IDE and dependencies # \arg:OUTPUT_NAME (optional) overrides the name of the output target. If not specified, the name will be used. @@ -76,7 +75,7 @@ define_property(TARGET PROPERTY GEM_MODULE # \arg:AUTOGEN_RULES a set of AutoGeneration rules to be passed to the AzAutoGen expansion system function(ly_add_target) - set(options STATIC SHARED MODULE GEM_MODULE HEADERONLY EXECUTABLE APPLICATION UNKNOWN IMPORTED AUTOMOC AUTOUIC AUTORCC NO_UNITY) + set(options STATIC SHARED MODULE GEM_MODULE HEADERONLY EXECUTABLE APPLICATION IMPORTED AUTOMOC AUTOUIC AUTORCC NO_UNITY) set(oneValueArgs NAME NAMESPACE OUTPUT_SUBDIRECTORY OUTPUT_NAME) set(multiValueArgs FILES_CMAKE GENERATED_FILES INCLUDE_DIRECTORIES COMPILE_DEFINITIONS BUILD_DEPENDENCIES RUNTIME_DEPENDENCIES PLATFORM_INCLUDE_FILES TARGET_PROPERTIES AUTOGEN_RULES) @@ -128,12 +127,12 @@ function(ly_add_target) set(linking_options APPLICATION) set(linking_count "${linking_count}1") endif() - if(ly_add_target_UNKNOWN) - set(linking_options UNKNOWN) + if(ly_add_target_IMPORTED) + set(linking_options UNKNOWN IMPORTED GLOBAL) set(linking_count "${linking_count}1") endif() if(NOT ("${linking_count}" STREQUAL "1")) - message(FATAL_ERROR "More than one of the following options [STATIC | SHARED | MODULE | HEADERONLY | EXECUTABLE | APPLICATION | UNKNOWN] was specified and they are mutually exclusive") + message(FATAL_ERROR "More than one of the following options [STATIC | SHARED | MODULE | HEADERONLY | EXECUTABLE | APPLICATION | IMPORTED] was specified and they are mutually exclusive") endif() if(ly_add_target_NAMESPACE) @@ -159,10 +158,9 @@ function(ly_add_target) ${linking_options} ${ALLFILES} ${ly_add_target_GENERATED_FILES} ) - elseif(ly_add_target_UNKNOWN) + elseif(ly_add_target_IMPORTED) add_library(${ly_add_target_NAME} ${linking_options} - IMPORTED ) else() add_library(${ly_add_target_NAME} diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index edbcdc473b..e9726fb949 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -11,7 +11,7 @@ set(CMAKE_INSTALL_MESSAGE NEVER) # Simplify messages to reduce output noise -ly_set(LY_DEFAULT_INSTALL_COMPONENT "Core") +ly_set(LY_DEFAULT_INSTALL_COMPONENT Core) file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) @@ -74,20 +74,9 @@ function(ly_install_target ly_install_target_NAME) COMPONENT ${ly_install_target_COMPONENT} ) - ly_generate_target_find_file( - NAME ${ly_install_target_NAME} - ${ARGN} - ) + ly_generate_target_find_file(NAME ${ly_install_target_NAME} ${ARGN}) ly_generate_target_config_file(${ly_install_target_NAME}) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${ly_install_target_NAME}_$.cmake" - DESTINATION cmake_autogen/${ly_install_target_NAME} - COMPONENT ${ly_install_target_COMPONENT} - ) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Find${ly_install_target_NAME}.cmake" - DESTINATION cmake - COMPONENT ${ly_install_target_COMPONENT} - ) - + endfunction() @@ -129,16 +118,21 @@ function(ly_generate_target_find_file) # Includes need additional processing to add the install root foreach(include ${include_directories_interface_props}) - set(installed_include_prefix "\${LY_ROOT_FOLDER}/include/") file(RELATIVE_PATH relative_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${include}) - list(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "include/${relative_path}") + string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${relative_path}\n") endforeach() - string(REPLACE ";" "\n" INCLUDE_DIRECTORIES_PLACEHOLDER "${INCLUDE_DIRECTORIES_PLACEHOLDER}") string(REPLACE ";" "\n" BUILD_DEPENDENCIES_PLACEHOLDER "${BUILD_DEPENDENCIES_PLACEHOLDER}") string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") - configure_file(${LY_ROOT_FOLDER}/cmake/FindTarget.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/Find${ly_generate_target_find_file_NAME}.cmake @ONLY) + # Since a CMakeLists could contain multiple targets, we generate it in a folder per target + configure_file(${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in ${CMAKE_CURRENT_BINARY_DIR}/install/${ly_generate_target_find_file_NAME}/CMakeLists.txt @ONLY) + get_target_property(target_source_dir ${ly_generate_target_find_file_NAME} SOURCE_DIR) + file(RELATIVE_PATH target_source_dir_relative ${CMAKE_SOURCE_DIR} ${target_source_dir}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${ly_generate_target_find_file_NAME}/CMakeLists.txt" + DESTINATION ${target_source_dir_relative}/${ly_generate_target_find_file_NAME} + COMPONENT ${ly_install_target_COMPONENT} + ) endfunction() @@ -183,7 +177,13 @@ endif() ") endif() - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${NAME}_$.cmake" CONTENT "${target_file_contents}") + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME}/${NAME}_$.cmake" CONTENT "${target_file_contents}") + get_target_property(target_source_dir ${NAME} SOURCE_DIR) + file(RELATIVE_PATH target_source_dir_relative ${CMAKE_SOURCE_DIR} ${target_source_dir}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME}_$.cmake" + DESTINATION ${target_source_dir_relative}/${NAME} + COMPONENT ${ly_install_target_COMPONENT} + ) endfunction() @@ -254,11 +254,12 @@ function(ly_setup_cmake_install) get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) unset(FIND_PACKAGES_PLACEHOLDER) foreach(target IN LISTS all_targets) - string(APPEND FIND_PACKAGES_PLACEHOLDER " find_package(${target})\n") + get_target_property(target_source_dir ${target} SOURCE_DIR) + file(RELATIVE_PATH target_source_dir_relative ${CMAKE_SOURCE_DIR} ${target_source_dir}) + string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${target_source_dir_relative}/${target})\n") endforeach() - configure_file(${LY_ROOT_FOLDER}/cmake/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) - + configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" DESTINATION cmake COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index fd5985a5a1..1bc2b2344e 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -126,15 +126,16 @@ function(ly_delayed_generate_settings_registry) get_property(gem_relative_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) if(gem_relative_source_dir) # Most gems CMakeLists.txt files reside in the /Code/ so remove "Code/" from the path - if(gem_relative_source_dir MATCHES ".*/Code$") + while(gem_relative_source_dir MATCHES ".*/Code$") get_filename_component(gem_relative_source_dir ${gem_relative_source_dir} DIRECTORY) - endif() + endwhile() file(TO_CMAKE_PATH ${LY_ROOT_FOLDER} ly_root_folder_cmake) file(RELATIVE_PATH gem_relative_source_dir ${ly_root_folder_cmake} ${gem_relative_source_dir}) endif() - # Strip target namespace from gem targets before configuring them into the json template - ly_strip_target_namespace(TARGET ${gem_target} OUTPUT_VARIABLE stripped_gem_target) + message("gem_target: ${gem_target}, gem_relative_source_dir: ${gem_relative_source_dir}") + # Strip target namespace from gem targets before configuring them into the json template + ly_strip_target_namespace(TARGET ${gem_target} OUTPUT_VARIABLE stripped_gem_target) string(CONFIGURE ${gem_module_template} gem_module_json @ONLY) list(APPEND target_gem_dependencies_names ${gem_module_json}) endforeach() diff --git a/cmake/Findo3de.cmake.in b/cmake/install/Findo3de.cmake.in similarity index 100% rename from cmake/Findo3de.cmake.in rename to cmake/install/Findo3de.cmake.in diff --git a/cmake/FindTarget.cmake.in b/cmake/install/TargetCMakeLists.txt.in similarity index 82% rename from cmake/FindTarget.cmake.in rename to cmake/install/TargetCMakeLists.txt.in index 8ad9822dae..16263ecf30 100644 --- a/cmake/FindTarget.cmake.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -11,10 +11,8 @@ # Generated by O3DE -include(FindPackageHandleStandardArgs) - ly_add_target( - NAME @NAME_PLACEHOLDER@ UNKNOWN IMPORTED + NAME @NAME_PLACEHOLDER@ IMPORTED @NAMESPACE_PLACEHOLDER@ COMPILE_DEFINITIONS INTERFACE @@ -30,5 +28,5 @@ ly_add_target( ) foreach(config @CMAKE_CONFIGURATION_TYPES@) - include("${LY_ROOT_FOLDER}/cmake_autogen/@NAME_PLACEHOLDER@/@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) + include("@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) endforeach() From 84381e4c3a65986e0d83f8839e5a8eba0be984fb Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 5 May 2021 12:07:23 -0700 Subject: [PATCH 011/140] making the settings registry compute the path based on the gems.json file --- cmake/SettingsRegistry.cmake | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index 1bc2b2344e..af6ef42e31 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -125,15 +125,14 @@ function(ly_delayed_generate_settings_registry) endif() get_property(gem_relative_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) if(gem_relative_source_dir) - # Most gems CMakeLists.txt files reside in the /Code/ so remove "Code/" from the path - while(gem_relative_source_dir MATCHES ".*/Code$") + # Most gems SOURCE dir is nested in the path, we need to find the path to the gem.json file + while(NOT EXISTS ${gem_relative_source_dir}/gem.json) get_filename_component(gem_relative_source_dir ${gem_relative_source_dir} DIRECTORY) endwhile() file(TO_CMAKE_PATH ${LY_ROOT_FOLDER} ly_root_folder_cmake) file(RELATIVE_PATH gem_relative_source_dir ${ly_root_folder_cmake} ${gem_relative_source_dir}) endif() - message("gem_target: ${gem_target}, gem_relative_source_dir: ${gem_relative_source_dir}") # Strip target namespace from gem targets before configuring them into the json template ly_strip_target_namespace(TARGET ${gem_target} OUTPUT_VARIABLE stripped_gem_target) string(CONFIGURE ${gem_module_template} gem_module_json @ONLY) From 7c9837dfd4fb1e55c20c00d88fb0c9ed5587d5c9 Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 5 May 2021 12:07:45 -0700 Subject: [PATCH 012/140] installing the gems.json files --- cmake/Platform/Common/Install_common.cmake | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index e9726fb949..dbffcc8d12 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -439,6 +439,21 @@ function(ly_setup_others) endif() endforeach() + # gem.json files + file(GLOB_RECURSE + gems_json_path + LIST_DIRECTORIES FALSE + RELATIVE "${CMAKE_SOURCE_DIR}" + "Gems/*/gem.json" + ) + foreach(gem_json_path ${gems_json_path}) + get_filename_component(gem_relative_path ${gem_json_path} DIRECTORY) + install(FILES ${gem_json_path} + DESTINATION ${gem_relative_path} + COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + ) + endforeach() + # Additional files needed by gems install(FILES ${CMAKE_SOURCE_DIR}/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings From 412bf6777239da2a30378a481b47a5c07d8e4572 Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 5 May 2021 12:08:55 -0700 Subject: [PATCH 013/140] changing the default prefix (install path) to be /install to workaround the "build/*" filter in the AP This is also better since we support installing different configuraitons/platforms in the same prefix --- .gitignore | 1 + cmake/OutputDirectory.cmake | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c3af907e97..c396847560 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ __pycache__ AssetProcessorTemp/** [Bb]uild/** [Cc]ache/ +install/ Editor/EditorEventLog.xml Editor/EditorLayout.xml **/*egg-info/** diff --git a/cmake/OutputDirectory.cmake b/cmake/OutputDirectory.cmake index 9055802d39..5fe5c7a957 100644 --- a/cmake/OutputDirectory.cmake +++ b/cmake/OutputDirectory.cmake @@ -13,4 +13,8 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib CACHE PATH "Build directory for static libraries and import libraries") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Build directory for shared libraries") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Build directory for executables") -set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "Installation prefix") + +# We install outside of the binary dir because our install support muliple platforms to +# be installed together. We also have an exclusion rule in the AP that filters out the +# "build" folder which is a common binary dir +set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install CACHE PATH "Installation prefix") From 76ffff8bb5f3f7eb3d3239a3d1852622cfc0367a Mon Sep 17 00:00:00 2001 From: nggieber Date: Wed, 5 May 2021 12:29:06 -0700 Subject: [PATCH 014/140] Moved Qt files into to renamed 'S'ource --- .../Tools/ProjectManager/{source/Qt => Source}/EngineSettings.cpp | 0 Code/Tools/ProjectManager/{source/Qt => Source}/EngineSettings.h | 0 Code/Tools/ProjectManager/{source/Qt => Source}/EngineSettings.ui | 0 Code/Tools/ProjectManager/{source/Qt => Source}/FirstTimeUse.cpp | 0 Code/Tools/ProjectManager/{source/Qt => Source}/FirstTimeUse.h | 0 Code/Tools/ProjectManager/{source/Qt => Source}/FirstTimeUse.ui | 0 Code/Tools/ProjectManager/{source/Qt => Source}/GemCatalog.cpp | 0 Code/Tools/ProjectManager/{source/Qt => Source}/GemCatalog.h | 0 Code/Tools/ProjectManager/{source/Qt => Source}/GemCatalog.ui | 0 .../ProjectManager/{source/Qt => Source}/NewProjectSettings.cpp | 0 .../ProjectManager/{source/Qt => Source}/NewProjectSettings.h | 0 .../ProjectManager/{source/Qt => Source}/NewProjectSettings.ui | 0 .../ProjectManager/{source/Qt => Source}/ProjectManagerWindow.cpp | 0 .../ProjectManager/{source/Qt => Source}/ProjectManagerWindow.h | 0 .../ProjectManager/{source/Qt => Source}/ProjectManagerWindow.ui | 0 .../ProjectManager/{source/Qt => Source}/ProjectSettings.cpp | 0 Code/Tools/ProjectManager/{source/Qt => Source}/ProjectSettings.h | 0 .../Tools/ProjectManager/{source/Qt => Source}/ProjectSettings.ui | 0 Code/Tools/ProjectManager/{source/Qt => Source}/ProjectsHome.cpp | 0 Code/Tools/ProjectManager/{source/Qt => Source}/ProjectsHome.h | 0 Code/Tools/ProjectManager/{source/Qt => Source}/ProjectsHome.ui | 0 Code/Tools/ProjectManager/{source => Source}/ScreenDefs.h | 0 Code/Tools/ProjectManager/{source => Source}/ScreenFactory.cpp | 0 Code/Tools/ProjectManager/{source => Source}/ScreenFactory.h | 0 Code/Tools/ProjectManager/{source/Qt => Source}/ScreenWidget.h | 0 Code/Tools/ProjectManager/{source => Source}/main.cpp | 0 26 files changed, 0 insertions(+), 0 deletions(-) rename Code/Tools/ProjectManager/{source/Qt => Source}/EngineSettings.cpp (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/EngineSettings.h (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/EngineSettings.ui (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/FirstTimeUse.cpp (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/FirstTimeUse.h (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/FirstTimeUse.ui (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/GemCatalog.cpp (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/GemCatalog.h (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/GemCatalog.ui (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/NewProjectSettings.cpp (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/NewProjectSettings.h (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/NewProjectSettings.ui (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ProjectManagerWindow.cpp (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ProjectManagerWindow.h (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ProjectManagerWindow.ui (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ProjectSettings.cpp (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ProjectSettings.h (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ProjectSettings.ui (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ProjectsHome.cpp (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ProjectsHome.h (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ProjectsHome.ui (100%) rename Code/Tools/ProjectManager/{source => Source}/ScreenDefs.h (100%) rename Code/Tools/ProjectManager/{source => Source}/ScreenFactory.cpp (100%) rename Code/Tools/ProjectManager/{source => Source}/ScreenFactory.h (100%) rename Code/Tools/ProjectManager/{source/Qt => Source}/ScreenWidget.h (100%) rename Code/Tools/ProjectManager/{source => Source}/main.cpp (100%) diff --git a/Code/Tools/ProjectManager/source/Qt/EngineSettings.cpp b/Code/Tools/ProjectManager/Source/EngineSettings.cpp similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/EngineSettings.cpp rename to Code/Tools/ProjectManager/Source/EngineSettings.cpp diff --git a/Code/Tools/ProjectManager/source/Qt/EngineSettings.h b/Code/Tools/ProjectManager/Source/EngineSettings.h similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/EngineSettings.h rename to Code/Tools/ProjectManager/Source/EngineSettings.h diff --git a/Code/Tools/ProjectManager/source/Qt/EngineSettings.ui b/Code/Tools/ProjectManager/Source/EngineSettings.ui similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/EngineSettings.ui rename to Code/Tools/ProjectManager/Source/EngineSettings.ui diff --git a/Code/Tools/ProjectManager/source/Qt/FirstTimeUse.cpp b/Code/Tools/ProjectManager/Source/FirstTimeUse.cpp similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/FirstTimeUse.cpp rename to Code/Tools/ProjectManager/Source/FirstTimeUse.cpp diff --git a/Code/Tools/ProjectManager/source/Qt/FirstTimeUse.h b/Code/Tools/ProjectManager/Source/FirstTimeUse.h similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/FirstTimeUse.h rename to Code/Tools/ProjectManager/Source/FirstTimeUse.h diff --git a/Code/Tools/ProjectManager/source/Qt/FirstTimeUse.ui b/Code/Tools/ProjectManager/Source/FirstTimeUse.ui similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/FirstTimeUse.ui rename to Code/Tools/ProjectManager/Source/FirstTimeUse.ui diff --git a/Code/Tools/ProjectManager/source/Qt/GemCatalog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog.cpp similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/GemCatalog.cpp rename to Code/Tools/ProjectManager/Source/GemCatalog.cpp diff --git a/Code/Tools/ProjectManager/source/Qt/GemCatalog.h b/Code/Tools/ProjectManager/Source/GemCatalog.h similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/GemCatalog.h rename to Code/Tools/ProjectManager/Source/GemCatalog.h diff --git a/Code/Tools/ProjectManager/source/Qt/GemCatalog.ui b/Code/Tools/ProjectManager/Source/GemCatalog.ui similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/GemCatalog.ui rename to Code/Tools/ProjectManager/Source/GemCatalog.ui diff --git a/Code/Tools/ProjectManager/source/Qt/NewProjectSettings.cpp b/Code/Tools/ProjectManager/Source/NewProjectSettings.cpp similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/NewProjectSettings.cpp rename to Code/Tools/ProjectManager/Source/NewProjectSettings.cpp diff --git a/Code/Tools/ProjectManager/source/Qt/NewProjectSettings.h b/Code/Tools/ProjectManager/Source/NewProjectSettings.h similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/NewProjectSettings.h rename to Code/Tools/ProjectManager/Source/NewProjectSettings.h diff --git a/Code/Tools/ProjectManager/source/Qt/NewProjectSettings.ui b/Code/Tools/ProjectManager/Source/NewProjectSettings.ui similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/NewProjectSettings.ui rename to Code/Tools/ProjectManager/Source/NewProjectSettings.ui diff --git a/Code/Tools/ProjectManager/source/Qt/ProjectManagerWindow.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ProjectManagerWindow.cpp rename to Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp diff --git a/Code/Tools/ProjectManager/source/Qt/ProjectManagerWindow.h b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ProjectManagerWindow.h rename to Code/Tools/ProjectManager/Source/ProjectManagerWindow.h diff --git a/Code/Tools/ProjectManager/source/Qt/ProjectManagerWindow.ui b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ProjectManagerWindow.ui rename to Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui diff --git a/Code/Tools/ProjectManager/source/Qt/ProjectSettings.cpp b/Code/Tools/ProjectManager/Source/ProjectSettings.cpp similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ProjectSettings.cpp rename to Code/Tools/ProjectManager/Source/ProjectSettings.cpp diff --git a/Code/Tools/ProjectManager/source/Qt/ProjectSettings.h b/Code/Tools/ProjectManager/Source/ProjectSettings.h similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ProjectSettings.h rename to Code/Tools/ProjectManager/Source/ProjectSettings.h diff --git a/Code/Tools/ProjectManager/source/Qt/ProjectSettings.ui b/Code/Tools/ProjectManager/Source/ProjectSettings.ui similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ProjectSettings.ui rename to Code/Tools/ProjectManager/Source/ProjectSettings.ui diff --git a/Code/Tools/ProjectManager/source/Qt/ProjectsHome.cpp b/Code/Tools/ProjectManager/Source/ProjectsHome.cpp similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ProjectsHome.cpp rename to Code/Tools/ProjectManager/Source/ProjectsHome.cpp diff --git a/Code/Tools/ProjectManager/source/Qt/ProjectsHome.h b/Code/Tools/ProjectManager/Source/ProjectsHome.h similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ProjectsHome.h rename to Code/Tools/ProjectManager/Source/ProjectsHome.h diff --git a/Code/Tools/ProjectManager/source/Qt/ProjectsHome.ui b/Code/Tools/ProjectManager/Source/ProjectsHome.ui similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ProjectsHome.ui rename to Code/Tools/ProjectManager/Source/ProjectsHome.ui diff --git a/Code/Tools/ProjectManager/source/ScreenDefs.h b/Code/Tools/ProjectManager/Source/ScreenDefs.h similarity index 100% rename from Code/Tools/ProjectManager/source/ScreenDefs.h rename to Code/Tools/ProjectManager/Source/ScreenDefs.h diff --git a/Code/Tools/ProjectManager/source/ScreenFactory.cpp b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp similarity index 100% rename from Code/Tools/ProjectManager/source/ScreenFactory.cpp rename to Code/Tools/ProjectManager/Source/ScreenFactory.cpp diff --git a/Code/Tools/ProjectManager/source/ScreenFactory.h b/Code/Tools/ProjectManager/Source/ScreenFactory.h similarity index 100% rename from Code/Tools/ProjectManager/source/ScreenFactory.h rename to Code/Tools/ProjectManager/Source/ScreenFactory.h diff --git a/Code/Tools/ProjectManager/source/Qt/ScreenWidget.h b/Code/Tools/ProjectManager/Source/ScreenWidget.h similarity index 100% rename from Code/Tools/ProjectManager/source/Qt/ScreenWidget.h rename to Code/Tools/ProjectManager/Source/ScreenWidget.h diff --git a/Code/Tools/ProjectManager/source/main.cpp b/Code/Tools/ProjectManager/Source/main.cpp similarity index 100% rename from Code/Tools/ProjectManager/source/main.cpp rename to Code/Tools/ProjectManager/Source/main.cpp From 625aa14aa8eac6699accbd38e11afe9133c9279f Mon Sep 17 00:00:00 2001 From: nggieber Date: Wed, 5 May 2021 12:31:17 -0700 Subject: [PATCH 015/140] Updated files after moving all Qt folder into Source --- Code/Tools/ProjectManager/CMakeLists.txt | 2 +- .../ProjectManager/Source/EngineSettings.cpp | 4 +- .../ProjectManager/Source/EngineSettings.h | 2 +- .../ProjectManager/Source/FirstTimeUse.cpp | 4 +- .../ProjectManager/Source/FirstTimeUse.h | 2 +- .../ProjectManager/Source/GemCatalog.cpp | 4 +- Code/Tools/ProjectManager/Source/GemCatalog.h | 2 +- .../Source/NewProjectSettings.cpp | 4 +- .../Source/NewProjectSettings.h | 2 +- .../Source/ProjectManagerWindow.cpp | 4 +- .../ProjectManager/Source/ProjectSettings.cpp | 4 +- .../ProjectManager/Source/ProjectSettings.h | 2 +- .../ProjectManager/Source/ProjectsHome.cpp | 4 +- .../ProjectManager/Source/ProjectsHome.h | 2 +- .../ProjectManager/Source/ScreenFactory.cpp | 12 ++--- .../ProjectManager/Source/ScreenFactory.h | 2 +- .../ProjectManager/Source/ScreenWidget.h | 2 +- Code/Tools/ProjectManager/Source/main.cpp | 2 +- .../project_manager_files.cmake | 44 +++++++++---------- 19 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Code/Tools/ProjectManager/CMakeLists.txt b/Code/Tools/ProjectManager/CMakeLists.txt index 0961acd354..e4354bac32 100644 --- a/Code/Tools/ProjectManager/CMakeLists.txt +++ b/Code/Tools/ProjectManager/CMakeLists.txt @@ -27,7 +27,7 @@ ly_add_target( PUBLIC . PRIVATE - source + Source BUILD_DEPENDENCIES PRIVATE diff --git a/Code/Tools/ProjectManager/Source/EngineSettings.cpp b/Code/Tools/ProjectManager/Source/EngineSettings.cpp index 03040781f7..bc359637e4 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettings.cpp +++ b/Code/Tools/ProjectManager/Source/EngineSettings.cpp @@ -10,9 +10,9 @@ * */ -#include +#include -#include +#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/EngineSettings.h b/Code/Tools/ProjectManager/Source/EngineSettings.h index 5f2aa5310a..f90f760798 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettings.h +++ b/Code/Tools/ProjectManager/Source/EngineSettings.h @@ -12,7 +12,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #endif namespace Ui diff --git a/Code/Tools/ProjectManager/Source/FirstTimeUse.cpp b/Code/Tools/ProjectManager/Source/FirstTimeUse.cpp index 9ba4eba2a6..5f5dcd5087 100644 --- a/Code/Tools/ProjectManager/Source/FirstTimeUse.cpp +++ b/Code/Tools/ProjectManager/Source/FirstTimeUse.cpp @@ -10,9 +10,9 @@ * */ -#include +#include -#include +#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/FirstTimeUse.h b/Code/Tools/ProjectManager/Source/FirstTimeUse.h index 677ca398fa..708513d493 100644 --- a/Code/Tools/ProjectManager/Source/FirstTimeUse.h +++ b/Code/Tools/ProjectManager/Source/FirstTimeUse.h @@ -12,7 +12,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #endif namespace Ui diff --git a/Code/Tools/ProjectManager/Source/GemCatalog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog.cpp index 6377eb5c8d..9d89740816 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog.cpp @@ -10,9 +10,9 @@ * */ -#include +#include -#include +#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/GemCatalog.h b/Code/Tools/ProjectManager/Source/GemCatalog.h index aee7b3a988..e45d865e58 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog.h @@ -12,7 +12,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #endif namespace Ui diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettings.cpp b/Code/Tools/ProjectManager/Source/NewProjectSettings.cpp index 7289c73329..2ebe54e682 100644 --- a/Code/Tools/ProjectManager/Source/NewProjectSettings.cpp +++ b/Code/Tools/ProjectManager/Source/NewProjectSettings.cpp @@ -10,9 +10,9 @@ * */ -#include +#include -#include +#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettings.h b/Code/Tools/ProjectManager/Source/NewProjectSettings.h index 5790772a0c..f5fa91a9b9 100644 --- a/Code/Tools/ProjectManager/Source/NewProjectSettings.h +++ b/Code/Tools/ProjectManager/Source/NewProjectSettings.h @@ -12,7 +12,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #endif namespace Ui diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp index b37f73a0c5..12980fc836 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp @@ -10,7 +10,7 @@ * */ -#include +#include #include #include @@ -18,7 +18,7 @@ #include -#include +#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/ProjectSettings.cpp b/Code/Tools/ProjectManager/Source/ProjectSettings.cpp index 56b27f5fe3..bc653f9c5b 100644 --- a/Code/Tools/ProjectManager/Source/ProjectSettings.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectSettings.cpp @@ -10,9 +10,9 @@ * */ -#include +#include -#include +#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/ProjectSettings.h b/Code/Tools/ProjectManager/Source/ProjectSettings.h index c9356db9bf..e7781d3a2a 100644 --- a/Code/Tools/ProjectManager/Source/ProjectSettings.h +++ b/Code/Tools/ProjectManager/Source/ProjectSettings.h @@ -12,7 +12,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #endif namespace Ui diff --git a/Code/Tools/ProjectManager/Source/ProjectsHome.cpp b/Code/Tools/ProjectManager/Source/ProjectsHome.cpp index ef85d71950..1a451f3d10 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsHome.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsHome.cpp @@ -10,9 +10,9 @@ * */ -#include +#include -#include +#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/ProjectsHome.h b/Code/Tools/ProjectManager/Source/ProjectsHome.h index b5a062f2dd..4cc2918a38 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsHome.h +++ b/Code/Tools/ProjectManager/Source/ProjectsHome.h @@ -12,7 +12,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #endif namespace Ui diff --git a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp index e29994d162..b07816e69e 100644 --- a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp +++ b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp @@ -11,12 +11,12 @@ */ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/ScreenFactory.h b/Code/Tools/ProjectManager/Source/ScreenFactory.h index addc868dfa..ea68534a08 100644 --- a/Code/Tools/ProjectManager/Source/ScreenFactory.h +++ b/Code/Tools/ProjectManager/Source/ScreenFactory.h @@ -13,7 +13,7 @@ #include -#include +#include #include diff --git a/Code/Tools/ProjectManager/Source/ScreenWidget.h b/Code/Tools/ProjectManager/Source/ScreenWidget.h index 0cec4bed03..b4c4fd190c 100644 --- a/Code/Tools/ProjectManager/Source/ScreenWidget.h +++ b/Code/Tools/ProjectManager/Source/ScreenWidget.h @@ -12,7 +12,7 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include #include #endif diff --git a/Code/Tools/ProjectManager/Source/main.cpp b/Code/Tools/ProjectManager/Source/main.cpp index 7ae977818b..149da79491 100644 --- a/Code/Tools/ProjectManager/Source/main.cpp +++ b/Code/Tools/ProjectManager/Source/main.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 0616b28e1e..2a7656c8c4 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -15,26 +15,26 @@ set(FILES source/ScreenDefs.h source/ScreenFactory.h source/ScreenFactory.cpp - source/Qt/ScreenWidget.h - source/Qt/FirstTimeUse.h - source/Qt/FirstTimeUse.cpp - source/Qt/FirstTimeUse.ui - source/Qt/ProjectManagerWindow.h - source/Qt/ProjectManagerWindow.cpp - source/Qt/ProjectManagerWindow.ui - source/Qt/NewProjectSettings.h - source/Qt/NewProjectSettings.cpp - source/Qt/NewProjectSettings.ui - source/Qt/GemCatalog.h - source/Qt/GemCatalog.cpp - source/Qt/GemCatalog.ui - source/Qt/ProjectsHome.h - source/Qt/ProjectsHome.cpp - source/Qt/ProjectsHome.ui - source/Qt/ProjectSettings.h - source/Qt/ProjectSettings.cpp - source/Qt/ProjectSettings.ui - source/Qt/EngineSettings.h - source/Qt/EngineSettings.cpp - source/Qt/EngineSettings.ui + source/ScreenWidget.h + source/FirstTimeUse.h + source/FirstTimeUse.cpp + source/FirstTimeUse.ui + source/ProjectManagerWindow.h + source/ProjectManagerWindow.cpp + source/ProjectManagerWindow.ui + source/NewProjectSettings.h + source/NewProjectSettings.cpp + source/NewProjectSettings.ui + source/GemCatalog.h + source/GemCatalog.cpp + source/GemCatalog.ui + source/ProjectsHome.h + source/ProjectsHome.cpp + source/ProjectsHome.ui + source/ProjectSettings.h + source/ProjectSettings.cpp + source/ProjectSettings.ui + source/EngineSettings.h + source/EngineSettings.cpp + source/EngineSettings.ui ) \ No newline at end of file From d27aa0f5846c82cd5f1b56f90087c2628c772f88 Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 5 May 2021 12:31:34 -0700 Subject: [PATCH 016/140] replaced ly_add_dependencies with ly_add_target_files so settingsregistry is happy --- cmake/Platform/Common/Install_common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index dbffcc8d12..f351b074a0 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -157,7 +157,7 @@ function(ly_generate_target_config_file NAME) string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\"") elseif(target_type STREQUAL SHARED_LIBRARY) string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") - string(APPEND target_file_contents "ly_add_dependencies(${NAME} \"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\")\n") + string(APPEND target_file_contents "ly_add_target_files(TARGET ${NAME} FILES \"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\")\n") else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") endif() From 2044832bb1634b77cc25112bf5ad146146b26340 Mon Sep 17 00:00:00 2001 From: nggieber Date: Wed, 5 May 2021 12:41:05 -0700 Subject: [PATCH 017/140] Updated Source capitalization in cmake files list --- .../project_manager_files.cmake | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 2a7656c8c4..698027ea15 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -11,30 +11,30 @@ set(FILES project_manager.qrc - source/main.cpp - source/ScreenDefs.h - source/ScreenFactory.h - source/ScreenFactory.cpp - source/ScreenWidget.h - source/FirstTimeUse.h - source/FirstTimeUse.cpp - source/FirstTimeUse.ui - source/ProjectManagerWindow.h - source/ProjectManagerWindow.cpp - source/ProjectManagerWindow.ui - source/NewProjectSettings.h - source/NewProjectSettings.cpp - source/NewProjectSettings.ui - source/GemCatalog.h - source/GemCatalog.cpp - source/GemCatalog.ui - source/ProjectsHome.h - source/ProjectsHome.cpp - source/ProjectsHome.ui - source/ProjectSettings.h - source/ProjectSettings.cpp - source/ProjectSettings.ui - source/EngineSettings.h - source/EngineSettings.cpp - source/EngineSettings.ui + Source/main.cpp + Source/ScreenDefs.h + Source/ScreenFactory.h + Source/ScreenFactory.cpp + Source/ScreenWidget.h + Source/FirstTimeUse.h + Source/FirstTimeUse.cpp + Source/FirstTimeUse.ui + Source/ProjectManagerWindow.h + Source/ProjectManagerWindow.cpp + Source/ProjectManagerWindow.ui + Source/NewProjectSettings.h + Source/NewProjectSettings.cpp + Source/NewProjectSettings.ui + Source/GemCatalog.h + Source/GemCatalog.cpp + Source/GemCatalog.ui + Source/ProjectsHome.h + Source/ProjectsHome.cpp + Source/ProjectsHome.ui + Source/ProjectSettings.h + Source/ProjectSettings.cpp + Source/ProjectSettings.ui + Source/EngineSettings.h + Source/EngineSettings.cpp + Source/EngineSettings.ui ) \ No newline at end of file From 5b98227a773177b68999bd25fcff0b4ea2522385 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 5 May 2021 14:58:31 -0500 Subject: [PATCH 018/140] Adding newline to the end of project_manager_files.cmake --- Code/Tools/ProjectManager/project_manager_files.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 698027ea15..333180ea78 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -37,4 +37,4 @@ set(FILES Source/EngineSettings.h Source/EngineSettings.cpp Source/EngineSettings.ui -) \ No newline at end of file +) From f6187f510a10d8f05bb884a261b3ae4c7b759e46 Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 5 May 2021 16:21:25 -0700 Subject: [PATCH 019/140] config file going to the wrong place --- cmake/Platform/Common/Install_common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index f351b074a0..f6e2488126 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -180,7 +180,7 @@ endif() file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME}/${NAME}_$.cmake" CONTENT "${target_file_contents}") get_target_property(target_source_dir ${NAME} SOURCE_DIR) file(RELATIVE_PATH target_source_dir_relative ${CMAKE_SOURCE_DIR} ${target_source_dir}) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME}_$.cmake" + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME}/${NAME}_$.cmake" DESTINATION ${target_source_dir_relative}/${NAME} COMPONENT ${ly_install_target_COMPONENT} ) From e63c36019470966c54f5dda17b5b3eac79f85a6e Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 5 May 2021 16:21:41 -0700 Subject: [PATCH 020/140] small unrelated fix --- Code/Tools/ProjectManager/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/Code/Tools/ProjectManager/CMakeLists.txt b/Code/Tools/ProjectManager/CMakeLists.txt index e4354bac32..2f0603a705 100644 --- a/Code/Tools/ProjectManager/CMakeLists.txt +++ b/Code/Tools/ProjectManager/CMakeLists.txt @@ -24,11 +24,8 @@ ly_add_target( project_manager_files.cmake Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake INCLUDE_DIRECTORIES - PUBLIC - . PRIVATE Source - BUILD_DEPENDENCIES PRIVATE 3rdParty::Qt::Core From 9fe893830c6a4201c6ef5e6e4e244e853e9aa211 Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 5 May 2021 16:22:13 -0700 Subject: [PATCH 021/140] sine fixes to AP model handling, still getting some sporadic asserts in debug --- Code/Framework/AzCore/AzCore/IO/Path/Path.h | 6 ++++ Code/Framework/AzCore/AzCore/IO/Path/Path.inl | 5 +++ .../native/ui/ProductAssetTreeModel.cpp | 29 ++++++++------- .../native/ui/SourceAssetTreeModel.cpp | 36 +++++++++---------- 4 files changed, 45 insertions(+), 31 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.h b/Code/Framework/AzCore/AzCore/IO/Path/Path.h index 61294cd637..6c1b519224 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.h +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.h @@ -95,6 +95,12 @@ namespace AZ::IO constexpr int Compare(AZStd::string_view pathString) const noexcept; constexpr int Compare(const value_type* pathString) const noexcept; + // Extension for fixed strings + //! extension: fixed string types with MaxPathLength capacity + //! Returns a new instance of an AZStd::fixed_string with capacity of MaxPathLength + //! made from the internal string + constexpr AZStd::fixed_string FixedMaxPathString() const noexcept; + // decomposition //! Given a windows path of "C:\O3DE\foo\bar\name.txt" and a posix path of //! "/O3DE/foo/bar/name.txt" diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl index 1e42fc9df7..05a92c5247 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl @@ -915,6 +915,11 @@ namespace AZ::IO return compare_string_view(path); } + constexpr AZStd::fixed_string PathView::FixedMaxPathString() const noexcept + { + return AZStd::fixed_string(m_path.begin(), m_path.end()); + } + // decomposition constexpr auto PathView::RootName() const -> PathView { diff --git a/Code/Tools/AssetProcessor/native/ui/ProductAssetTreeModel.cpp b/Code/Tools/AssetProcessor/native/ui/ProductAssetTreeModel.cpp index 5efef8166c..68ba64ea1a 100644 --- a/Code/Tools/AssetProcessor/native/ui/ProductAssetTreeModel.cpp +++ b/Code/Tools/AssetProcessor/native/ui/ProductAssetTreeModel.cpp @@ -14,6 +14,7 @@ #include "ProductAssetTreeItemData.h" #include +#include #include namespace AssetProcessor @@ -159,31 +160,33 @@ namespace AssetProcessor return; } + AZ::IO::Path productNamePath(product.m_productName, AZ::IO::PosixPathSeparator); - AZStd::vector tokens; - AzFramework::StringFunc::Tokenize(product.m_productName.c_str(), tokens, AZ_CORRECT_DATABASE_SEPARATOR, false, true); - - if (tokens.empty()) + if (productNamePath.empty()) { AZ_Warning("AssetProcessor", false, "Product id %d has an invalid name: %s", product.m_productID, product.m_productName.c_str()); return; } AssetTreeItem* parentItem = m_root.get(); - AZStd::string fullFolderName; - for (int i = 0; i < tokens.size() - 1; ++i) + AZ::IO::Path currentFullFolderPath; + const AZ::IO::PathView filename = productNamePath.Filename(); + const AZ::IO::PathView fullPathWithoutFilename = productNamePath.RemoveFilename(); + AZStd::fixed_string currentPath; + for (auto pathIt = fullPathWithoutFilename.begin(); pathIt != fullPathWithoutFilename.end(); ++pathIt) { - AzFramework::StringFunc::AssetDatabasePath::Join(fullFolderName.c_str(), tokens[i].c_str(), fullFolderName); - AssetTreeItem* nextParent = parentItem->GetChildFolder(tokens[i].c_str()); + currentPath = pathIt->FixedMaxPathString(); + currentFullFolderPath /= currentPath; + AssetTreeItem* nextParent = parentItem->GetChildFolder(currentPath.c_str()); if (!nextParent) { if (!modelIsResetting) { - QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem); + QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem); beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount()); } - nextParent = parentItem->CreateChild(ProductAssetTreeItemData::MakeShared(nullptr, fullFolderName, tokens[i].c_str(), true, AZ::Uuid::CreateNull())); - m_productToTreeItem[fullFolderName] = nextParent; + nextParent = parentItem->CreateChild(ProductAssetTreeItemData::MakeShared(nullptr, currentFullFolderPath.Native(), currentPath.c_str(), true, AZ::Uuid::CreateNull())); + m_productToTreeItem[currentFullFolderPath.Native()] = nextParent; // m_productIdToTreeItem is not used for folders, folders don't have product IDs. if (!modelIsResetting) @@ -205,12 +208,12 @@ namespace AssetProcessor if (!modelIsResetting) { - QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem); + QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem); beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount()); } AZStd::shared_ptr productItemData = - ProductAssetTreeItemData::MakeShared(&product, product.m_productName, tokens[tokens.size() - 1].c_str(), false, sourceId); + ProductAssetTreeItemData::MakeShared(&product, product.m_productName, AZStd::fixed_string(filename.Native()).c_str(), false, sourceId); m_productToTreeItem[product.m_productName] = parentItem->CreateChild(productItemData); m_productIdToTreeItem[product.m_productID] = m_productToTreeItem[product.m_productName]; diff --git a/Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp b/Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp index dda0a58837..69e60f6733 100644 --- a/Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp +++ b/Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp @@ -63,8 +63,7 @@ namespace AssetProcessor } - auto fullPath = AZ::IO::Path(scanFolder.m_scanFolder) / source.m_sourceName; - + AZ::IO::Path fullPath = AZ::IO::Path(scanFolder.m_scanFolder, AZ::IO::PosixPathSeparator) / source.m_sourceName; // It's common for Open 3D Engine game projects and scan folders to be in a subfolder // of the engine install. To improve readability of the source files, strip out @@ -78,34 +77,35 @@ namespace AssetProcessor AzFramework::StringFunc::Replace(fullPath.Native(), m_assetRoot.absolutePath().toUtf8(), ""); } - - AZStd::vector tokens; - AzFramework::StringFunc::Tokenize(fullPath.c_str(), tokens, AZ_CORRECT_DATABASE_SEPARATOR, false, true); - - if (tokens.empty()) + if (fullPath.empty()) { - AZ_Warning("AssetProcessor", false, "Source id %s has an invalid name: %s", - source.m_sourceGuid.ToString().c_str(), source.m_sourceName.c_str()); + AZ_Warning( + "AssetProcessor", false, "Source id %s has an invalid name: %s", source.m_sourceGuid.ToString().c_str(), + source.m_sourceName.c_str()); return; } QModelIndex newIndicesStart; AssetTreeItem* parentItem = m_root.get(); - AZStd::string fullFolderName; - for (int i = 0; i < tokens.size() - 1; ++i) + AZ::IO::Path currentFullFolderPath; + const AZ::IO::PathView filename = fullPath.Filename(); + const AZ::IO::PathView fullPathWithoutFilename = fullPath.RemoveFilename(); + AZStd::fixed_string currentPath; + for (auto pathIt = fullPathWithoutFilename.begin(); pathIt != fullPathWithoutFilename.end(); ++pathIt) { - AzFramework::StringFunc::AssetDatabasePath::Join(fullFolderName.c_str(), tokens[i].c_str(), fullFolderName); - AssetTreeItem* nextParent = parentItem->GetChildFolder(tokens[i].c_str()); + currentPath = pathIt->FixedMaxPathString(); + currentFullFolderPath /= currentPath; + AssetTreeItem* nextParent = parentItem->GetChildFolder(currentPath.c_str()); if (!nextParent) { if (!modelIsResetting) { - QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem); + QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem); beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount()); } - nextParent = parentItem->CreateChild(SourceAssetTreeItemData::MakeShared(nullptr, nullptr, fullFolderName, tokens[i].c_str(), true)); - m_sourceToTreeItem[fullFolderName] = nextParent; + nextParent = parentItem->CreateChild(SourceAssetTreeItemData::MakeShared(nullptr, nullptr, currentFullFolderPath.Native(), currentPath.c_str(), true)); + m_sourceToTreeItem[currentFullFolderPath.Native()] = nextParent; // Folders don't have source IDs, don't add to m_sourceIdToTreeItem if (!modelIsResetting) { @@ -117,12 +117,12 @@ namespace AssetProcessor if (!modelIsResetting) { - QModelIndex parentIndex = parentItem == m_root.get() ? QModelIndex() : createIndex(parentItem->GetRow(), 0, parentItem); + QModelIndex parentIndex = createIndex(parentItem->GetRow(), 0, parentItem); beginInsertRows(parentIndex, parentItem->getChildCount(), parentItem->getChildCount()); } m_sourceToTreeItem[source.m_sourceName] = - parentItem->CreateChild(SourceAssetTreeItemData::MakeShared(&source, &scanFolder, source.m_sourceName, tokens[tokens.size() - 1].c_str(), false)); + parentItem->CreateChild(SourceAssetTreeItemData::MakeShared(&source, &scanFolder, source.m_sourceName, AZStd::fixed_string(filename.Native()).c_str(), false)); m_sourceIdToTreeItem[source.m_sourceID] = m_sourceToTreeItem[source.m_sourceName]; if (!modelIsResetting) { From 68f19644e7af2dbaedf5b4bad536f0758c041a53 Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 5 May 2021 16:42:50 -0700 Subject: [PATCH 022/140] typo --- cmake/Platform/Common/Install_common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index f6e2488126..3c372462a2 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -157,7 +157,7 @@ function(ly_generate_target_config_file NAME) string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\"") elseif(target_type STREQUAL SHARED_LIBRARY) string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") - string(APPEND target_file_contents "ly_add_target_files(TARGET ${NAME} FILES \"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\")\n") + string(APPEND target_file_contents "ly_add_target_files(TARGETS ${NAME} FILES \"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\")\n") else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") endif() From bddbe43240169c0e927329677982618acdf7afe5 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 6 May 2021 13:55:34 -0700 Subject: [PATCH 023/140] adding all the config folder for ImageProcessingAtom --- cmake/Platform/Common/Install_common.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 3c372462a2..cef3251899 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -455,11 +455,11 @@ function(ly_setup_others) endforeach() # Additional files needed by gems - install(FILES - ${CMAKE_SOURCE_DIR}/Gems/ImageProcessing/Code/Source/ImageBuilderDefaultPresets.settings - DESTINATION Gems/ImageProcessing/Code/Source + install(DIRECTORY + ${CMAKE_SOURCE_DIR}/Gems/Atom/Asset/ImageProcessingAtom/Config + DESTINATION Gems/Atom/Asset/ImageProcessingAtom COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} - ) + ) # Templates install(DIRECTORY From 2eb494f7c13764f4bdf60cf7ebac855bb2668c27 Mon Sep 17 00:00:00 2001 From: mbalfour Date: Fri, 7 May 2021 14:23:01 -0500 Subject: [PATCH 024/140] Changed the level loading code to always set the default mission name now. the mission system recently got redcoded, so nothing else was setting this name. --- Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp index d31f122d9b..8818dfa0d9 100644 --- a/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp +++ b/Code/CryEngine/CrySystem/LevelSystem/LevelSystem.cpp @@ -108,10 +108,11 @@ bool CLevelInfo::ReadInfo() AzFramework::ApplicationRequests::Bus::BroadcastResult( usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled); + // Set up a default game type for legacy code. + m_defaultGameTypeName = "Mission0"; + if (usePrefabSystemForLevels) { - // Set up a default game type for legacy code. - m_defaultGameTypeName = "Mission0"; return true; } From 7441685508759e37237d0ea4a963f16b830be86b Mon Sep 17 00:00:00 2001 From: pappeste Date: Fri, 7 May 2021 13:22:22 -0700 Subject: [PATCH 025/140] changing how we refer to this path --- cmake/Packaging.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 4f6565edc7..a4d7da5730 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -13,7 +13,7 @@ if(NOT PAL_TRAIT_BUILD_CPACK_SUPPORTED) return() endif() -ly_get_absolute_pal_filename(pal_dir ${CMAKE_SOURCE_DIR}/cmake/Platform/${PAL_HOST_PLATFORM_NAME}) +ly_get_absolute_pal_filename(pal_dir ${LY_ROOT_FOLDER}/cmake/Platform/${PAL_HOST_PLATFORM_NAME}) include(${pal_dir}/Packaging_${PAL_HOST_PLATFORM_NAME_LOWERCASE}.cmake) # if we get here and the generator hasn't been set, then a non fatal error occurred disabling packaging support From 2625e983b80b7d14638dcb97f7ab8e32f35e788b Mon Sep 17 00:00:00 2001 From: pappeste Date: Fri, 7 May 2021 13:22:54 -0700 Subject: [PATCH 026/140] fixing errors that had wrong condition --- Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp b/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp index 4b6e210522..b5829bb9da 100644 --- a/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp +++ b/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp @@ -38,8 +38,8 @@ namespace LegacyLevelSystem //------------------------------------------------------------------------ static void LoadLevel(const AZ::ConsoleCommandContainer& arguments) { - AZ_Error("SpawnableLevelSystem", arguments.empty(), "LoadLevel requires a level file name to be provided."); - AZ_Error("SpawnableLevelSystem", arguments.size() > 1, "LoadLevel requires a single level file name to be provided."); + AZ_Error("SpawnableLevelSystem", !arguments.empty(), "LoadLevel requires a level file name to be provided."); + AZ_Error("SpawnableLevelSystem", arguments.size() == 1, "LoadLevel requires a single level file name to be provided."); if (!arguments.empty() && gEnv->pSystem && gEnv->pSystem->GetILevelSystem() && !gEnv->IsEditor()) { From bedecebdcc9206d9a34277935f9295705c0ff530 Mon Sep 17 00:00:00 2001 From: phistere Date: Fri, 7 May 2021 20:05:05 -0500 Subject: [PATCH 027/140] Configures and installs an engine.json generated from a template. Fixes HEADERONLY targets for install. Fixes locating .ico resource file. Fix infinite loop in CMake configure on new projects. --- .../Windows/launcher_project_windows.cmake | 5 +++++ cmake/LYWrappers.cmake | 2 +- cmake/Platform/Common/Install_common.cmake | 16 ++++++++++++++-- cmake/SettingsRegistry.cmake | 10 +++++++--- cmake/Version.cmake | 3 ++- cmake/install/TargetCMakeLists.txt.in | 2 +- cmake/install/engine.json.in | 7 +++++++ engine.json | 3 ++- 8 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 cmake/install/engine.json.in diff --git a/Code/LauncherUnified/Platform/Windows/launcher_project_windows.cmake b/Code/LauncherUnified/Platform/Windows/launcher_project_windows.cmake index bcef59ec5a..35c89caf15 100644 --- a/Code/LauncherUnified/Platform/Windows/launcher_project_windows.cmake +++ b/Code/LauncherUnified/Platform/Windows/launcher_project_windows.cmake @@ -10,6 +10,11 @@ # set(ICON_FILE ${project_real_path}/Gem/Resources/GameSDK.ico) +if(NOT EXISTS ${ICON_FILE}) + # Try another project-relative path + set(ICON_FILE ${project_real_path}/Resources/GameSDK.ico) +endif() + if(NOT EXISTS ${ICON_FILE}) # Try the common LauncherUnified icon instead set(ICON_FILE Resources/GameSDK.ico) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 62509582a1..73586b624f 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -85,7 +85,7 @@ function(ly_add_target) if(NOT ly_add_target_NAME) message(FATAL_ERROR "You must provide a name for the target") endif() - if(NOT ly_add_target_IMPORTED) + if(NOT ly_add_target_IMPORTED AND NOT ly_add_target_HEADERONLY) if(NOT ly_add_target_FILES_CMAKE) message(FATAL_ERROR "You must provide a list of _files.cmake files for the target") endif() diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index cef3251899..141f229506 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -104,6 +104,13 @@ function(ly_generate_target_find_file) unset(INCLUDE_DIRECTORIES_PLACEHOLDER) set(RUNTIME_DEPENDENCIES_PLACEHOLDER ${ly_generate_target_find_file_RUNTIME_DEPENDENCIES}) + set(TARGET_TYPE_PLACEHOLDER "IMPORTED") + #set(TARGET_TYPE_PLACEHOLDER) + get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) + if(target_type STREQUAL INTERFACE_LIBRARY) + set(TARGET_TYPE_PLACEHOLDER "HEADERONLY") + endif() + # These targets will be imported. We will expose PUBLIC and INTERFACE properties as INTERFACE properties since # only INTERFACE properties can be exposed on imported targets ly_strip_private_properties(COMPILE_DEFINITIONS_PLACEHOLDER ${ly_generate_target_find_file_COMPILE_DEFINITIONS}) @@ -225,13 +232,17 @@ function(ly_setup_cmake_install) install(DIRECTORY "${CMAKE_SOURCE_DIR}/cmake" DESTINATION . COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + PATTERN "__pycache__" EXCLUDE REGEX "Findo3de.cmake" EXCLUDE REGEX "Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE ) + + configure_file(${CMAKE_SOURCE_DIR}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY) + install( FILES "${CMAKE_SOURCE_DIR}/CMakeLists.txt" - "${CMAKE_SOURCE_DIR}/engine.json" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json" DESTINATION . COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) @@ -369,6 +380,7 @@ function(ly_setup_others) install(DIRECTORY "${CMAKE_SOURCE_DIR}/${dir}" DESTINATION ${install_path} COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + PATTERN "__pycache__" EXCLUDE ) endforeach() @@ -450,7 +462,7 @@ function(ly_setup_others) get_filename_component(gem_relative_path ${gem_json_path} DIRECTORY) install(FILES ${gem_json_path} DESTINATION ${gem_relative_path} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endforeach() diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index af6ef42e31..31ce36c516 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -125,9 +125,13 @@ function(ly_delayed_generate_settings_registry) endif() get_property(gem_relative_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) if(gem_relative_source_dir) - # Most gems SOURCE dir is nested in the path, we need to find the path to the gem.json file - while(NOT EXISTS ${gem_relative_source_dir}/gem.json) - get_filename_component(gem_relative_source_dir ${gem_relative_source_dir} DIRECTORY) + # Most gems SOURCE dir is nested in the path, we need to find the path to the gem.json or project.json file + while(NOT EXISTS ${gem_relative_source_dir}/gem.json AND NOT EXISTS ${gem_relative_source_dir}/project.json) + get_filename_component(parent_dir ${gem_relative_source_dir} DIRECTORY) + if (${parent_dir} STREQUAL ${gem_relative_source_dir}) + message(FATAL_ERROR "Did not find gem.json or project.json while processing target ${gem_target}!") + endif() + set(gem_relative_source_dir ${parent_dir}) endwhile() file(TO_CMAKE_PATH ${LY_ROOT_FOLDER} ly_root_folder_cmake) file(RELATIVE_PATH gem_relative_source_dir ${ly_root_folder_cmake} ${gem_relative_source_dir}) diff --git a/cmake/Version.cmake b/cmake/Version.cmake index 08d79d4ce6..1d484fb059 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -12,4 +12,5 @@ string(TIMESTAMP current_year "%Y") set(LY_VERSION_COPYRIGHT_YEAR ${current_year} CACHE STRING "Open 3D Engine's copyright year") set(LY_VERSION_STRING "0.0.0.0" CACHE STRING "Open 3D Engine's version") -set(LY_VERSION_BUILD_NUMBER 0 CACHE STRING "Open 3D Engine's build number") \ No newline at end of file +set(LY_VERSION_BUILD_NUMBER 0 CACHE STRING "Open 3D Engine's build number") +set(LY_VERSION_ENGINE_NAME "o3de" CACHE STRING "Open 3D Engine's engine name") diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/TargetCMakeLists.txt.in index 16263ecf30..1c2f181368 100644 --- a/cmake/install/TargetCMakeLists.txt.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -12,7 +12,7 @@ # Generated by O3DE ly_add_target( - NAME @NAME_PLACEHOLDER@ IMPORTED + NAME @NAME_PLACEHOLDER@ @TARGET_TYPE_PLACEHOLDER@ @NAMESPACE_PLACEHOLDER@ COMPILE_DEFINITIONS INTERFACE diff --git a/cmake/install/engine.json.in b/cmake/install/engine.json.in new file mode 100644 index 0000000000..9899b169ed --- /dev/null +++ b/cmake/install/engine.json.in @@ -0,0 +1,7 @@ +{ + "engine_name": "@LY_VERSION_ENGINE_NAME@", + "FileVersion": 1, + "O3DEVersion": "@LY_VERSION_STRING@", + "O3DECopyrightYear": @LY_VERSION_COPYRIGHT_YEAR@, + "O3DEBuildNumber": @LY_VERSION_BUILD_NUMBER@ +} diff --git a/engine.json b/engine.json index 5091605f4c..f933886c44 100644 --- a/engine.json +++ b/engine.json @@ -2,5 +2,6 @@ "engine_name": "o3de", "FileVersion": 1, "O3DEVersion": "0.0.0.0", - "O3DECopyrightYear": 2021 + "O3DECopyrightYear": 2021, + "O3DEBuildNumber": 0 } From 92c74a1aaa8dab978cea802e7af3a49114f27ebe Mon Sep 17 00:00:00 2001 From: phistere Date: Fri, 7 May 2021 20:06:12 -0500 Subject: [PATCH 028/140] Fixing minor spacing, spelling, and print formatting. --- .../AzCore/AzCore/Component/ComponentApplication.cpp | 2 +- Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp | 2 +- Code/LauncherUnified/Launcher.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index d0f277a6b8..6ba985d032 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -1215,7 +1215,7 @@ namespace AZ // So auto load is turned off if option "AutoLoad" key is bool that is false if (valueName == "AutoLoad" && !value) { - // Strip off the AutoLoead entry from the path + // Strip off the AutoLoad entry from the path auto autoLoadKey = AZ::StringFunc::TokenizeLast(path, "/"); if (!autoLoadKey) { diff --git a/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp b/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp index fe41050b00..0ce3ee5d8d 100644 --- a/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp +++ b/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp @@ -512,7 +512,7 @@ namespace AZ // Load DLLs specified in the application descriptor for (const auto& moduleDescriptor : modules) { - // For each module that is loaded, attempt to set the module's folder as a path for dependent module resolution + // For each module that is loaded, attempt to set the module's folder as a path for dependent module resolution moduleSearchPathHelper.SetModuleSearchPath(moduleDescriptor); LoadModuleOutcome result = LoadDynamicModule(moduleDescriptor.m_dynamicLibraryPath.c_str(), lastStepToPerform, maintainReferences); diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index 033169ac6d..26962dfe03 100644 --- a/Code/LauncherUnified/Launcher.cpp +++ b/Code/LauncherUnified/Launcher.cpp @@ -488,8 +488,8 @@ namespace O3DELauncher const AZStd::string_view buildTargetName = GetBuildTargetName(); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(*settingsRegistry, buildTargetName); - AZ_TracePrintf("Launcher", R"(Running project "%.*s.)" "\n" - R"(The project name value has been successfully set in the Settings Registry at key "%s/project_name)" + AZ_TracePrintf("Launcher", R"(Running project "%.*s")" "\n" + R"(The project name has been successfully set in the Settings Registry at key "%s/project_name")" R"( for Launcher target "%.*s")" "\n", aznumeric_cast(launcherProjectName.size()), launcherProjectName.data(), AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey, From ac7024cc06d4c43a121ee6b28e480ca8bcd08e45 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 11:19:35 -0700 Subject: [PATCH 029/140] Making install to be completely a post-processing step. We need this so all dependencies are declared and ready when we generate the target files --- cmake/Install.cmake | 6 - cmake/LYWrappers.cmake | 83 +++---- cmake/LyAutoGen.cmake | 2 +- cmake/Platform/Common/Install_common.cmake | 229 ++++++++---------- .../Common/RuntimeDependencies_common.cmake | 29 ++- cmake/Platform/Mac/Install_mac.cmake | 6 - cmake/Platform/iOS/Install_ios.cmake | 6 - .../iOS/RuntimeDependencies_ios.cmake | 6 +- .../LYTestImpactFramework.cmake | 5 +- cmake/install/TargetCMakeLists.txt.in | 4 +- 10 files changed, 165 insertions(+), 211 deletions(-) diff --git a/cmake/Install.cmake b/cmake/Install.cmake index 73a3273dfa..205277f0e5 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -12,10 +12,4 @@ if(NOT INSTALLED_ENGINE) ly_get_absolute_pal_filename(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}) include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) -else() - - # Provide empty implementation so ly_add_target continues working - function(ly_install_target ly_install_target_NAME) - endfunction() - endif() \ No newline at end of file diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 62509582a1..8640b460de 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -202,7 +202,7 @@ function(ly_add_target) endif() if (ly_add_target_INCLUDE_DIRECTORIES) - ly_target_include_directories(${ly_add_target_NAME} + target_include_directories(${ly_add_target_NAME} ${ly_add_target_INCLUDE_DIRECTORIES} ) endif() @@ -299,7 +299,7 @@ function(ly_add_target) endif() # Store the target so we can walk through all of them in LocationDependencies.cmake - set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGETS ${ly_add_target_NAME}) + set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGETS ${interface_name}) set(runtime_dependencies_list SHARED MODULE EXECUTABLE APPLICATION) if(linking_options IN_LIST runtime_dependencies_list) @@ -330,18 +330,6 @@ function(ly_add_target) ) endif() - if(NOT ly_add_target_IMPORTED) - ly_install_target( - ${ly_add_target_NAME} - NAMESPACE ${ly_add_target_NAMESPACE} - INCLUDE_DIRECTORIES ${ly_add_target_INCLUDE_DIRECTORIES} - BUILD_DEPENDENCIES ${ly_add_target_BUILD_DEPENDENCIES} - RUNTIME_DEPENDENCIES ${ly_add_target_RUNTIME_DEPENDENCIES} - COMPILE_DEFINITIONS ${ly_add_target_COMPILE_DEFINITIONS} - COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} - ) - endif() - endfunction() #! ly_target_link_libraries: wraps target_link_libraries handling also MODULE linkage. @@ -401,7 +389,7 @@ function(ly_delayed_target_link_libraries) endif() if(item_type STREQUAL MODULE_LIBRARY) - ly_target_include_directories(${target} ${visibility} $) + target_include_directories(${target} ${visibility} $) target_link_libraries(${target} ${visibility} $) target_compile_definitions(${target} ${visibility} $) target_compile_options(${target} ${visibility} $) @@ -502,7 +490,7 @@ endfunction() # Looks at the the following variables within the platform include file to set the equivalent target properties # LY_FILES_CMAKE -> extract list of files -> target_sources # LY_FILES -> target_source -# LY_INCLUDE_DIRECTORIES -> ly_target_include_directories +# LY_INCLUDE_DIRECTORIES -> target_include_directories # LY_COMPILE_DEFINITIONS -> target_compile_definitions # LY_COMPILE_OPTIONS -> target_compile_options # LY_LINK_OPTIONS -> target_link_options @@ -528,7 +516,11 @@ macro(ly_configure_target_platform_properties) message(FATAL_ERROR "The supplied PLATFORM_INCLUDE_FILE(${platform_include_file}) cannot be included.\ Parsing of target will halt") endif() - target_sources(${ly_add_target_NAME} PRIVATE ${platform_include_file}) + if(ly_add_target_HEADERONLY) + target_sources(${ly_add_target_NAME} INTERFACE ${platform_include_file}) + else() + target_sources(${ly_add_target_NAME} PRIVATE ${platform_include_file}) + endif() ly_source_groups_from_folders("${platform_include_file}") if(LY_FILES_CMAKE) @@ -544,7 +536,7 @@ macro(ly_configure_target_platform_properties) target_sources(${ly_add_target_NAME} PRIVATE ${LY_FILES}) endif() if (LY_INCLUDE_DIRECTORIES) - ly_target_include_directories(${ly_add_target_NAME} ${LY_INCLUDE_DIRECTORIES}) + target_include_directories(${ly_add_target_NAME} ${LY_INCLUDE_DIRECTORIES}) endif() if(LY_COMPILE_DEFINITIONS) target_compile_definitions(${ly_add_target_NAME} ${LY_COMPILE_DEFINITIONS}) @@ -647,42 +639,6 @@ function(ly_add_source_properties) endfunction() -function(ly_target_include_directories TARGET) - - # Add the includes to the build and install interface - set(reserved_keywords PRIVATE PUBLIC INTERFACE) - unset(last_keyword) - foreach(include ${ARGN}) - if(${include} IN_LIST reserved_keywords) - list(APPEND adapted_includes ${include}) - elseif(IS_ABSOLUTE ${include}) - list(APPEND adapted_includes - $ - ) - else() - string(GENEX_STRIP ${include} include_genex_expr) - if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions - # We will be installing the includes using the same directory structure used in our source tree. - # The INSTALL_INTERFACE path tells CMake the location of the includes relative to the install prefix. - # When the target is imported into an external project, cmake will find these includes at /include/ - # where is the location of the lumberyard install on disk. - file(REAL_PATH ${include} include_real) - file(RELATIVE_PATH install_dir ${CMAKE_SOURCE_DIR} ${include_real}) - list(APPEND adapted_includes - $ - $ - ) - else() - list(APPEND adapted_includes - ${include} - ) - endif() - endif() - endforeach() - target_include_directories(${TARGET} ${adapted_includes}) - -endfunction() - #! ly_project_add_subdirectory: calls add_subdirectory() if the project name is in the project list # @@ -713,3 +669,22 @@ function(ly_project_add_subdirectory project_name) endif() endif() endfunction() + +# given a target name, returns the "real" name of the target if its an alias. +# this function recursively de-aliases +function(ly_de_alias_target target_name output_variable_name) + # its not okay to call get_target_property on a non-existant target + if (NOT TARGET ${target_name}) + message(FATAL_ERROR "ly_de_alias_target called on non-existant target: ${target_name}") + endif() + + while(target_name) + set(de_aliased_target_name ${target_name}) + get_target_property(target_name ${target_name} ALIASED_TARGET) + endwhile() + + if(NOT de_aliased_target_name) + message(FATAL_ERROR "Empty de_aliased for ${target_name}") + endif() + set(${output_variable_name} ${de_aliased_target_name} PARENT_SCOPE) +endfunction() \ No newline at end of file diff --git a/cmake/LyAutoGen.cmake b/cmake/LyAutoGen.cmake index 16a8a8de55..aa0e7f8d5a 100644 --- a/cmake/LyAutoGen.cmake +++ b/cmake/LyAutoGen.cmake @@ -26,7 +26,7 @@ function(ly_add_autogen) if(ly_add_autogen_AUTOGEN_RULES) set(AZCG_INPUTFILES ${ly_add_autogen_ALLFILES}) list(FILTER AZCG_INPUTFILES INCLUDE REGEX ".*\.(xml|json|jinja)$") - ly_target_include_directories(${ly_add_autogen_NAME} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/Azcg/Generated") + target_include_directories(${ly_add_autogen_NAME} PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/Azcg/Generated") execute_process( COMMAND ${LY_PYTHON_CMD} "${LY_ROOT_FOLDER}/Code/Framework/AzAutoGen/AzAutoGen.py" "${CMAKE_BINARY_DIR}/Azcg/TemplateCache/" "${CMAKE_CURRENT_BINARY_DIR}/Azcg/Generated/" "${CMAKE_CURRENT_SOURCE_DIR}" "${AZCG_INPUTFILES}" "${ly_add_autogen_AUTOGEN_RULES}" "-n" OUTPUT_VARIABLE AUTOGEN_OUTPUTS diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index cef3251899..99ff0bbbe2 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -17,49 +17,61 @@ file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_ file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) set(install_output_folder "${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$") +#! ly_setup_targets: setups all targets +function(ly_setup_targets) + get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) + foreach(target IN LISTS all_targets) + ly_setup_target(${target}) + endforeach() +endfunction() -#! ly_install_target: registers the target to be installed by cmake install. -# -# \arg:NAME name of the target -# \arg:COMPONENT the grouping string of the target used for splitting up the install -# into smaller packages. -# All other parameters are forwarded to ly_generate_target_find_file -function(ly_install_target ly_install_target_NAME) +#! ly_setup_target: setups the target to be installed by cmake install. +function(ly_setup_target ALIAS_TARGET_NAME) - set(options) - set(oneValueArgs NAMESPACE COMPONENT) - set(multiValueArgs INCLUDE_DIRECTORIES BUILD_DEPENDENCIES RUNTIME_DEPENDENCIES COMPILE_DEFINITIONS) - - cmake_parse_arguments(ly_install_target "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + unset(TARGET_NAME) + ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) + + get_target_property(absolute_target_source_dir ${TARGET_NAME} SOURCE_DIR) + file(RELATIVE_PATH target_source_dir ${CMAKE_SOURCE_DIR} ${absolute_target_source_dir}) # All include directories marked PUBLIC or INTERFACE will be installed set(include_location "include") - get_target_property(include_directories ${ly_install_target_NAME} INTERFACE_INCLUDE_DIRECTORIES) - + get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) if (include_directories) - set_target_properties(${ly_install_target_NAME} PROPERTIES PUBLIC_HEADER "${include_directories}") - # The include directories are specified relative to the CMakeLists.txt file that adds the target. - # We need to install the includes relative to our source tree root because that's where INSTALL_INTERFACE - # will point CMake when it looks for headers - file(RELATIVE_PATH relative_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) - string(APPEND include_location "/${relative_path}") + unset(public_headers) + foreach(include_directory ${include_directories}) + string(GENEX_STRIP ${include_directory} include_genex_expr) + if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions + unset(current_public_headers) + # We install all header types for the time being until we clean up certain libraries that contain all sorts + # of files in the public include directories (e.g. CryCommon) + file(GLOB_RECURSE current_public_headers + LIST_DIRECTORIES false + ${include_directory}/*.h + ${include_directory}/*.hpp + ${include_directory}/*.inl + ) + list(APPEND public_headers ${current_public_headers}) + endif() + endforeach() + set_target_properties(${TARGET_NAME} PROPERTIES PUBLIC_HEADER "${public_headers}") endif() # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target file(RELATIVE_PATH archive_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) - get_target_property(target_runtime_output_directory ${ly_install_target_NAME} RUNTIME_OUTPUT_DIRECTORY) + get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) if(target_runtime_output_directory) file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) endif() - get_target_property(target_library_output_directory ${ly_install_target_NAME} LIBRARY_OUTPUT_DIRECTORY) + get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY) if(target_library_output_directory) file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) endif() install( - TARGETS ${ly_install_target_NAME} + TARGETS ${TARGET_NAME} ARCHIVE DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ COMPONENT ${ly_install_target_COMPONENT} @@ -70,81 +82,78 @@ function(ly_install_target ly_install_target_NAME) DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} COMPONENT ${ly_install_target_COMPONENT} PUBLIC_HEADER - DESTINATION ${include_location} + # The include directories are specified relative to the CMakeLists.txt file that adds the target. + # We need to install the includes relative to our source tree root + DESTINATION ${include_location}/${target_source_dir} COMPONENT ${ly_install_target_COMPONENT} ) - ly_generate_target_find_file(NAME ${ly_install_target_NAME} ${ARGN}) - ly_generate_target_config_file(${ly_install_target_NAME}) - -endfunction() - - -#! ly_generate_target_find_file: generates the Find${target}.cmake file which is used when importing installed packages. -# -# \arg:NAME name of the target -# \arg:NAMESPACE namespace declaration for this target. It will be used for IDE and dependencies -# \arg:INCLUDE_DIRECTORIES paths to the include directories -# \arg:BUILD_DEPENDENCIES list of interfaces this target depends on (could be a compilation dependency -# if the dependency is only exposing an include path, or could be a linking -# dependency is exposing a lib) -# \arg:RUNTIME_DEPENDENCIES list of dependencies this target depends on at runtime -# \arg:COMPILE_DEFINITIONS list of compilation definitions this target will use to compile -function(ly_generate_target_find_file) - - set(options) - set(oneValueArgs NAME NAMESPACE) - set(multiValueArgs INCLUDE_DIRECTORIES COMPILE_DEFINITIONS BUILD_DEPENDENCIES RUNTIME_DEPENDENCIES) - cmake_parse_arguments(ly_generate_target_find_file "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - set(NAME_PLACEHOLDER ${ly_generate_target_find_file_NAME}) - unset(NAMESPACE_PLACEHOLDER) - unset(COMPILE_DEFINITIONS_PLACEHOLDER) - unset(include_directories_interface_props) - unset(INCLUDE_DIRECTORIES_PLACEHOLDER) - set(RUNTIME_DEPENDENCIES_PLACEHOLDER ${ly_generate_target_find_file_RUNTIME_DEPENDENCIES}) - - # These targets will be imported. We will expose PUBLIC and INTERFACE properties as INTERFACE properties since - # only INTERFACE properties can be exposed on imported targets - ly_strip_private_properties(COMPILE_DEFINITIONS_PLACEHOLDER ${ly_generate_target_find_file_COMPILE_DEFINITIONS}) - ly_strip_private_properties(include_directories_interface_props ${ly_generate_target_find_file_INCLUDE_DIRECTORIES}) - ly_strip_private_properties(BUILD_DEPENDENCIES_PLACEHOLDER ${ly_generate_target_find_file_BUILD_DEPENDENCIES}) - - if(ly_generate_target_find_file_NAMESPACE) - set(NAMESPACE_PLACEHOLDER "NAMESPACE ${ly_generate_target_find_file_NAMESPACE}") + # CMakeLists.txt file + string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME}) + if(match) + set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}") + set(NAME_PLACEHOLDER ${CMAKE_MATCH_2}) + else() + set(NAMESPACE_PLACEHOLDER "") + set(NAME_PLACEHOLDER ${TARGET_NAME}) endif() - string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") + get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) + if(COMPILE_DEFINITIONS_PLACEHOLDER) + string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") + else() + unset(COMPILE_DEFINITIONS_PLACEHOLDER) + endif() # Includes need additional processing to add the install root - foreach(include ${include_directories_interface_props}) - file(RELATIVE_PATH relative_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${include}) - string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${relative_path}\n") - endforeach() + get_target_property(include_directories_interface_props ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) + unset(INCLUDE_DIRECTORIES_PLACEHOLDER) + if(include_directories_interface_props) + foreach(include ${include_directories_interface_props}) + string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}\n") + endforeach() + endif() - string(REPLACE ";" "\n" BUILD_DEPENDENCIES_PLACEHOLDER "${BUILD_DEPENDENCIES_PLACEHOLDER}") - string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") + get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) + if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found + string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") + else() + unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) + endif() - # Since a CMakeLists could contain multiple targets, we generate it in a folder per target - configure_file(${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in ${CMAKE_CURRENT_BINARY_DIR}/install/${ly_generate_target_find_file_NAME}/CMakeLists.txt @ONLY) - get_target_property(target_source_dir ${ly_generate_target_find_file_NAME} SOURCE_DIR) - file(RELATIVE_PATH target_source_dir_relative ${CMAKE_SOURCE_DIR} ${target_source_dir}) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${ly_generate_target_find_file_NAME}/CMakeLists.txt" - DESTINATION ${target_source_dir_relative}/${ly_generate_target_find_file_NAME} + get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) + unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + if(inteface_build_dependencies_props) + foreach(build_dependency ${inteface_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + string(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}\n") + endif() + endforeach() + endif() + + # We also need to declare teh private link libraries since we will use that to generate the runtime dependencies + get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) + unset(PRIVATE_BUILD_DEPENDENCIES_PLACEHOLDER) + if(private_build_dependencies_props) + foreach(build_dependency ${private_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + string(APPEND PRIVATE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}\n") + endif() + endforeach() + endif() + + # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target + configure_file(${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in ${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/CMakeLists.txt @ONLY) + + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/CMakeLists.txt" + DESTINATION ${target_source_dir}/${NAME_PLACEHOLDER} COMPONENT ${ly_install_target_COMPONENT} ) -endfunction() - - -#! ly_generate_target_config_file: generates the ${target}_$.cmake files for a target -# -# The generated file will set the location of the target binary per configuration -# These per config files will be included by the target's find file to set the location of the binary/ -# \arg:NAME name of the target -function(ly_generate_target_config_file NAME) - - get_target_property(target_type ${NAME} TYPE) + # Config file + get_target_property(target_type ${TARGET_NAME} TYPE) set(target_file_contents "# Generated by O3DE install\n\n") if(NOT target_type STREQUAL INTERFACE_LIBRARY) @@ -152,66 +161,43 @@ function(ly_generate_target_config_file NAME) unset(target_location) set(runtime_types EXECUTABLE APPLICATION) if(target_type IN_LIST runtime_types) - string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$\"") + string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$\"") elseif(target_type STREQUAL MODULE_LIBRARY) - string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\"") + string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\"") elseif(target_type STREQUAL SHARED_LIBRARY) - string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") - string(APPEND target_file_contents "ly_add_target_files(TARGETS ${NAME} FILES \"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\")\n") + string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") + string(APPEND target_file_contents "target_link_libraries(${TARGET_NAME} INTERFACE \"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\")\n") else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY - string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") + string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") endif() string(APPEND target_file_contents "set(target_location ${target_location}) -set_target_properties(${NAME} +set_target_properties(${TARGET_NAME} PROPERTIES $<$:IMPORTED_LOCATION \"\${target_location}\"> IMPORTED_LOCATION_$> \"\${target_location}\" ) if(EXISTS \"\${target_location}\") - set(${NAME}_$_FOUND TRUE) + set(${NAME_PLACEHOLDER}_$_FOUND TRUE) else() - set(${NAME}_$_FOUND FALSE) + set(${NAME_PLACEHOLDER}_$_FOUND FALSE) endif() ") endif() - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME}/${NAME}_$.cmake" CONTENT "${target_file_contents}") - get_target_property(target_source_dir ${NAME} SOURCE_DIR) - file(RELATIVE_PATH target_source_dir_relative ${CMAKE_SOURCE_DIR} ${target_source_dir}) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME}/${NAME}_$.cmake" - DESTINATION ${target_source_dir_relative}/${NAME} + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/${NAME_PLACEHOLDER}_$.cmake" + DESTINATION ${target_source_dir}/${NAME_PLACEHOLDER} COMPONENT ${ly_install_target_COMPONENT} ) endfunction() - -#! ly_strip_private_properties: strips private properties since we're exporting an interface target -# -# \arg:INTERFACE_PROPERTIES list of interface properties to be returned -function(ly_strip_private_properties INTERFACE_PROPERTIES) - set(reserved_keywords PRIVATE PUBLIC INTERFACE) - unset(last_keyword) - unset(stripped_props) - foreach(prop ${ARGN}) - if(${prop} IN_LIST reserved_keywords) - set(last_keyword ${prop}) - else() - if (NOT last_keyword STREQUAL "PRIVATE") - list(APPEND stripped_props ${prop}) - endif() - endif() - endforeach() - - set(${INTERFACE_PROPERTIES} ${stripped_props} PARENT_SCOPE) -endfunction() - - #! ly_setup_o3de_install: orchestrates the installation of the different parts. This is the entry point from the root CMakeLists.txt function(ly_setup_o3de_install) + ly_setup_targets() ly_setup_cmake_install() ly_setup_target_generator() ly_setup_runtime_dependencies() @@ -479,7 +465,6 @@ function(ly_setup_others) endfunction() - #! ly_setup_target_generator: install source files needed for project launcher generation function(ly_setup_target_generator) diff --git a/cmake/Platform/Common/RuntimeDependencies_common.cmake b/cmake/Platform/Common/RuntimeDependencies_common.cmake index 859d1d21e3..333bbaaae2 100644 --- a/cmake/Platform/Common/RuntimeDependencies_common.cmake +++ b/cmake/Platform/Common/RuntimeDependencies_common.cmake @@ -212,7 +212,10 @@ function(ly_delayed_generate_runtime_dependencies) list(APPEND CMAKE_MODULE_PATH ${additional_module_paths}) get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) - foreach(target IN LISTS all_targets) + foreach(aliased_target IN LISTS all_targets) + + unset(target) + ly_de_alias_target(${aliased_target} target) # Exclude targets that dont produce runtime outputs get_target_property(target_type ${target} TYPE) @@ -222,18 +225,18 @@ function(ly_delayed_generate_runtime_dependencies) unset(runtime_dependencies) set(runtime_commands " - function(ly_copy source_file target_directory) - get_filename_component(target_filename \"\${source_file}\" NAME) - if(NOT \"\${source_file}\" STREQUAL \"\${target_directory}/\${target_filename}\") - if(NOT EXISTS \"\${target_directory}\") - file(MAKE_DIRECTORY \"\${target_directory}\") - endif() - if(\"\${source_file}\" IS_NEWER_THAN \"\${target_directory}/\${target_filename}\") - file(LOCK \"\${target_directory}/\${target_filename}.lock\" GUARD FUNCTION TIMEOUT 30) - file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) - endif() - endif() - endfunction() +function(ly_copy source_file target_directory) + get_filename_component(target_filename \"\${source_file}\" NAME) + if(NOT \"\${source_file}\" STREQUAL \"\${target_directory}/\${target_filename}\") + if(NOT EXISTS \"\${target_directory}\") + file(MAKE_DIRECTORY \"\${target_directory}\") + endif() + if(\"\${source_file}\" IS_NEWER_THAN \"\${target_directory}/\${target_filename}\") + file(LOCK \"\${target_directory}/\${target_filename}.lock\" GUARD FUNCTION TIMEOUT 30) + file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) + endif() + endif() +endfunction() \n") ly_get_runtime_dependencies(runtime_dependencies ${target}) diff --git a/cmake/Platform/Mac/Install_mac.cmake b/cmake/Platform/Mac/Install_mac.cmake index 8c96c199de..5c7959bf77 100644 --- a/cmake/Platform/Mac/Install_mac.cmake +++ b/cmake/Platform/Mac/Install_mac.cmake @@ -11,11 +11,5 @@ # Empty implementations for untested platforms to fix build errors. -function(ly_install_target ly_install_target_NAME) - -endfunction() - - function(ly_setup_o3de_install) - endfunction() \ No newline at end of file diff --git a/cmake/Platform/iOS/Install_ios.cmake b/cmake/Platform/iOS/Install_ios.cmake index 8c96c199de..5c7959bf77 100644 --- a/cmake/Platform/iOS/Install_ios.cmake +++ b/cmake/Platform/iOS/Install_ios.cmake @@ -11,11 +11,5 @@ # Empty implementations for untested platforms to fix build errors. -function(ly_install_target ly_install_target_NAME) - -endfunction() - - function(ly_setup_o3de_install) - endfunction() \ No newline at end of file diff --git a/cmake/Platform/iOS/RuntimeDependencies_ios.cmake b/cmake/Platform/iOS/RuntimeDependencies_ios.cmake index 034ab750ff..a2a6d30593 100644 --- a/cmake/Platform/iOS/RuntimeDependencies_ios.cmake +++ b/cmake/Platform/iOS/RuntimeDependencies_ios.cmake @@ -143,7 +143,11 @@ function(ly_delayed_generate_runtime_dependencies) get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) unset(test_runner_dependencies) - foreach(target IN LISTS all_targets) + foreach(aliased_target IN LISTS all_targets) + + unset(target) + ly_de_alias_target(${aliased_target} target) + # Exclude targets that dont produce runtime outputs get_target_property(target_type ${target} TYPE) if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS) diff --git a/cmake/TestImpactFramework/LYTestImpactFramework.cmake b/cmake/TestImpactFramework/LYTestImpactFramework.cmake index c10c5bf637..d46b16bca5 100644 --- a/cmake/TestImpactFramework/LYTestImpactFramework.cmake +++ b/cmake/TestImpactFramework/LYTestImpactFramework.cmake @@ -204,7 +204,10 @@ function(ly_test_impact_export_source_target_mappings MAPPING_TEMPLATE_FILE) get_property(LY_ALL_TARGETS GLOBAL PROPERTY LY_ALL_TARGETS) # Walk the build targets - foreach(target ${LY_ALL_TARGETS}) + foreach(aliased_target ${LY_ALL_TARGETS}) + + unset(target) + ly_de_alias_target(${aliased_target} target) message(TRACE "Exporting static source file mappings for ${target}") # Target name and path relative to root diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/TargetCMakeLists.txt.in index 16263ecf30..5542184b89 100644 --- a/cmake/install/TargetCMakeLists.txt.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -22,7 +22,9 @@ ly_add_target( @INCLUDE_DIRECTORIES_PLACEHOLDER@ BUILD_DEPENDENCIES INTERFACE -@BUILD_DEPENDENCIES_PLACEHOLDER@ +@INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER@ + PRIVATE +@PRIVATE_BUILD_DEPENDENCIES_PLACEHOLDER@ RUNTIME_DEPENDENCIES @RUNTIME_DEPENDENCIES_PLACEHOLDER@ ) From 12cea5d0299a728b472effd9cd5bba49520c36e2 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 13:58:22 -0700 Subject: [PATCH 030/140] Fixing headers and interface build dependencies --- cmake/Platform/Common/Install_common.cmake | 48 +++++++++++----------- cmake/install/TargetCMakeLists.txt.in | 2 - 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index e8ad598277..b8d8dcea18 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -34,7 +34,10 @@ function(ly_setup_target ALIAS_TARGET_NAME) get_target_property(absolute_target_source_dir ${TARGET_NAME} SOURCE_DIR) file(RELATIVE_PATH target_source_dir ${LY_ROOT_FOLDER} ${absolute_target_source_dir}) - # All include directories marked PUBLIC or INTERFACE will be installed + # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that + # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the + # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. + # Instead, we install them with install(DIRECTORY) set(include_location "include") get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) if (include_directories) @@ -43,18 +46,16 @@ function(ly_setup_target ALIAS_TARGET_NAME) string(GENEX_STRIP ${include_directory} include_genex_expr) if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions unset(current_public_headers) - # We install all header types for the time being until we clean up certain libraries that contain all sorts - # of files in the public include directories (e.g. CryCommon) - file(GLOB_RECURSE current_public_headers - LIST_DIRECTORIES false - ${include_directory}/*.h - ${include_directory}/*.hpp - ${include_directory}/*.inl + install(DIRECTORY ${include_directory} + DESTINATION ${include_location}/${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + FILES_MATCHING + PATTERN *.h + PATTERN *.hpp + PATTERN *.inl ) - list(APPEND public_headers ${current_public_headers}) endif() endforeach() - set_target_properties(${TARGET_NAME} PROPERTIES PUBLIC_HEADER "${public_headers}") endif() # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target @@ -81,11 +82,6 @@ function(ly_setup_target ALIAS_TARGET_NAME) RUNTIME DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} COMPONENT ${ly_install_target_COMPONENT} - PUBLIC_HEADER - # The include directories are specified relative to the CMakeLists.txt file that adds the target. - # We need to install the includes relative to our source tree root - DESTINATION ${include_location}/${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} ) # CMakeLists.txt file @@ -112,11 +108,13 @@ function(ly_setup_target ALIAS_TARGET_NAME) endif() # Includes need additional processing to add the install root - get_target_property(include_directories_interface_props ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) - unset(INCLUDE_DIRECTORIES_PLACEHOLDER) - if(include_directories_interface_props) - foreach(include ${include_directories_interface_props}) - string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}\n") + if(include_directories) + foreach(include ${include_directories}) + string(GENEX_STRIP ${include} include_genex_expr) + if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions + file(RELATIVE_PATH relative_include ${absolute_target_source_dir} ${include}) + string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}/${relative_include}\n") + endif() endforeach() endif() @@ -137,15 +135,13 @@ function(ly_setup_target ALIAS_TARGET_NAME) endif() endforeach() endif() - - # We also need to declare teh private link libraries since we will use that to generate the runtime dependencies + # We also need to pass the private link libraries since we will use that to generate the runtime dependencies get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) - unset(PRIVATE_BUILD_DEPENDENCIES_PLACEHOLDER) if(private_build_dependencies_props) foreach(build_dependency ${private_build_dependencies_props}) # Skip wrapping produced when targets are not created in the same directory if(NOT ${build_dependency} MATCHES "^::@") - string(APPEND PRIVATE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}\n") + string(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}\n") endif() endforeach() endif() @@ -247,7 +243,9 @@ function(ly_setup_cmake_install) # targets that are pre-built get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) unset(FIND_PACKAGES_PLACEHOLDER) - foreach(target IN LISTS all_targets) + foreach(alias_target IN LISTS all_targets) + unset(TARGET_NAME) + ly_de_alias_target(${alias_target} target) get_target_property(target_source_dir ${target} SOURCE_DIR) file(RELATIVE_PATH target_source_dir_relative ${LY_ROOT_FOLDER} ${target_source_dir}) string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${target_source_dir_relative}/${target})\n") diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/TargetCMakeLists.txt.in index 784448aeb0..ae3ca91d5b 100644 --- a/cmake/install/TargetCMakeLists.txt.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -23,8 +23,6 @@ ly_add_target( BUILD_DEPENDENCIES INTERFACE @INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER@ - PRIVATE -@PRIVATE_BUILD_DEPENDENCIES_PLACEHOLDER@ RUNTIME_DEPENDENCIES @RUNTIME_DEPENDENCIES_PLACEHOLDER@ ) From 89fc1483fe572020efbf3f3cfe99cf3d82fc05cd Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 14:52:26 -0700 Subject: [PATCH 031/140] removing unused var --- Code/Sandbox/Editor/EditorViewportWidget.cpp | 4 ---- Code/Sandbox/Editor/RenderViewport.cpp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 3803867870..23f080a777 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -656,9 +656,6 @@ CBaseObject* EditorViewportWidget::GetCameraObject() const ////////////////////////////////////////////////////////////////////////// void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event) { - static ICVar* outputToHMD = gEnv->pConsole->GetCVar("output_to_hmd"); - AZ_Assert(outputToHMD, "cvar output_to_hmd is undeclared"); - switch (event) { case eNotify_OnBeginGameMode: @@ -680,7 +677,6 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event) if (deviceInfo) { // Note: This may also need to adjust the viewport size - outputToHMD->Set(1); SetActiveWindow(); SetFocus(); SetSelected(true); diff --git a/Code/Sandbox/Editor/RenderViewport.cpp b/Code/Sandbox/Editor/RenderViewport.cpp index 49064b5bc5..32b6a5c811 100644 --- a/Code/Sandbox/Editor/RenderViewport.cpp +++ b/Code/Sandbox/Editor/RenderViewport.cpp @@ -1259,9 +1259,6 @@ CBaseObject* CRenderViewport::GetCameraObject() const ////////////////////////////////////////////////////////////////////////// void CRenderViewport::OnEditorNotifyEvent(EEditorNotifyEvent event) { - static ICVar* outputToHMD = gEnv->pConsole->GetCVar("output_to_hmd"); - AZ_Assert(outputToHMD, "cvar output_to_hmd is undeclared"); - switch (event) { case eNotify_OnBeginGameMode: @@ -1282,7 +1279,6 @@ void CRenderViewport::OnEditorNotifyEvent(EEditorNotifyEvent event) if (deviceInfo) { - outputToHMD->Set(1); m_previousContext = SetCurrentContext(deviceInfo->renderWidth, deviceInfo->renderHeight); if (m_renderer->GetIStereoRenderer()) { From 65e0bd270e1081df256dae6f7029337ee1f673b0 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 14:55:03 -0700 Subject: [PATCH 032/140] Fixing runtime dependencies (including qt deploy). Running AP/Editor again --- AutomatedTesting/EngineFinder.cmake | 4 +++- cmake/Platform/Common/Install_common.cmake | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AutomatedTesting/EngineFinder.cmake b/AutomatedTesting/EngineFinder.cmake index 1fdcef2b56..9ff8ce4d66 100644 --- a/AutomatedTesting/EngineFinder.cmake +++ b/AutomatedTesting/EngineFinder.cmake @@ -45,6 +45,8 @@ if(EXISTS ${manifest_path}) if(${json_error}) message(FATAL_ERROR "Unable to read engines[${engine_path_index}] '${manifest_path}', error: ${json_error}") endif() - list(APPEND CMAKE_MODULE_PATH "${engine_path}/cmake") + if(engine_path) + list(APPEND CMAKE_MODULE_PATH "${engine_path}/cmake") + endif() endforeach() endif() diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index b8d8dcea18..338244c05f 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -244,7 +244,6 @@ function(ly_setup_cmake_install) get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) unset(FIND_PACKAGES_PLACEHOLDER) foreach(alias_target IN LISTS all_targets) - unset(TARGET_NAME) ly_de_alias_target(${alias_target} target) get_target_property(target_source_dir ${target} SOURCE_DIR) file(RELATIVE_PATH target_source_dir_relative ${LY_ROOT_FOLDER} ${target_source_dir}) @@ -301,7 +300,8 @@ endfunction()" unset(runtime_commands) get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) - foreach(target IN LISTS all_targets) + foreach(alias_target IN LISTS all_targets) + ly_de_alias_target(${alias_target} target) # Exclude targets that dont produce runtime outputs get_target_property(target_type ${target} TYPE) From c5b6878e91777b91e604b024440fcf82283033af Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 14:55:24 -0700 Subject: [PATCH 033/140] removing more mentions to a gone cvar --- Code/Sandbox/Editor/EditorViewportWidget.cpp | 4 ---- Code/Sandbox/Editor/RenderViewport.cpp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 23f080a777..e3c7280a26 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -696,10 +696,6 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event) if (GetIEditor()->GetViewManager()->GetGameViewport() == this) { SetCurrentCursor(STD_CURSOR_DEFAULT); - if (gSettings.bEnableGameModeVR) - { - outputToHMD->Set(0); - } m_bInRotateMode = false; m_bInMoveMode = false; m_bInOrbitMode = false; diff --git a/Code/Sandbox/Editor/RenderViewport.cpp b/Code/Sandbox/Editor/RenderViewport.cpp index 32b6a5c811..c10ba41203 100644 --- a/Code/Sandbox/Editor/RenderViewport.cpp +++ b/Code/Sandbox/Editor/RenderViewport.cpp @@ -1309,10 +1309,6 @@ void CRenderViewport::OnEditorNotifyEvent(EEditorNotifyEvent event) // failed to set the context back when done, or set it back to the wrong one. CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_WARNING, "RenderViewport render context was not correctly restored by someone else."); } - if (gSettings.bEnableGameModeVR) - { - outputToHMD->Set(0); - } RestorePreviousContext(m_previousContext); m_bInRotateMode = false; m_bInMoveMode = false; From 03bde5c24467ccc14c4b7f63e16cd02423cd000c Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 15:05:17 -0700 Subject: [PATCH 034/140] getting CMakeTestbed to build again --- CMakeLists.txt | 4 +--- cmake/install/engine.json.in | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c5185127d8..78667a7161 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,14 +34,12 @@ if(NOT PROJECT_NAME) LANGUAGES C CXX VERSION ${LY_VERSION_STRING} ) - - # o3de manifest - include(cmake/o3de_manifest.cmake) endif() ################################################################################ # Resolve this engines name and restricted path ################################################################################ +include(cmake/o3de_manifest.cmake) o3de_engine_name(${o3de_engine_json} o3de_engine_name) o3de_restricted_path(${o3de_engine_json} o3de_engine_restricted_path) message(STATUS "O3DE Engine Name: ${o3de_engine_name}") diff --git a/cmake/install/engine.json.in b/cmake/install/engine.json.in index 9899b169ed..04ee6348d3 100644 --- a/cmake/install/engine.json.in +++ b/cmake/install/engine.json.in @@ -1,5 +1,6 @@ { "engine_name": "@LY_VERSION_ENGINE_NAME@", + "restricted": "@LY_VERSION_ENGINE_NAME@", "FileVersion": 1, "O3DEVersion": "@LY_VERSION_STRING@", "O3DECopyrightYear": @LY_VERSION_COPYRIGHT_YEAR@, From c2a1365279930d3d7a2833b009078867e93e0de8 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 15:05:38 -0700 Subject: [PATCH 035/140] removing debugging messages --- cmake/o3de_manifest.cmake | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/cmake/o3de_manifest.cmake b/cmake/o3de_manifest.cmake index 1585ec2d2f..632f064659 100644 --- a/cmake/o3de_manifest.cmake +++ b/cmake/o3de_manifest.cmake @@ -24,7 +24,6 @@ endif() # Optionally delete the home directory if(O3DE_DELETE_HOME_PATH) - message(STATUS "O3DE_DELETE_HOME_PATH=${O3DE_DELETE_HOME_PATH}") if(EXISTS ${home_directory}/.o3de) message(STATUS "Deleting ${home_directory}/.o3de") file(REMOVE_RECURSE ${home_directory}/.o3de) @@ -53,11 +52,7 @@ endif() # -DO3DE_REGISTER_RESTRICTED_PATHS=C:\this\engine\Restricted;C:\ThisGame\Restricted;C:\ThisGem\Restricted ######################################################################################################################## if(O3DE_REGISTER_ENGINE_PATH) - message(STATUS "O3DE_REGISTER_ENGINE_PATH=${O3DE_REGISTER_ENGINE_PATH}") - if(O3DE_REGISTER_THIS_ENGINE) - message(STATUS "O3DE_REGISTER_THIS_ENGINE=${O3DE_REGISTER_THIS_ENGINE}") - message(STATUS "register --this-engine") if(CMAKE_HOST_WIN32) execute_process( COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --this-engine --override-home-folder ${home_directory} @@ -77,7 +72,6 @@ if(O3DE_REGISTER_ENGINE_PATH) endif() if(O3DE_REGISTER_RESTRICTED_PATHS) - message(STATUS "O3DE_REGISTER_RESTRICTED_PATHS=${O3DE_REGISTER_RESTRICTED_PATHS}") foreach(restricted_path ${O3DE_REGISTER_RESTRICTED_PATHS}) if(CMAKE_HOST_WIN32) execute_process( @@ -99,7 +93,6 @@ if(O3DE_REGISTER_ENGINE_PATH) endif() if(O3DE_REGISTER_PROJECT_PATHS) - message(STATUS "O3DE_REGISTER_PROJECT_PATHS=${O3DE_REGISTER_PROJECT_PATHS}") foreach(project_path ${O3DE_REGISTER_PROJECT_PATHS}) if(CMAKE_HOST_WIN32) execute_process( @@ -121,7 +114,6 @@ if(O3DE_REGISTER_ENGINE_PATH) endif() if(O3DE_REGISTER_GEM_PATHS) - message(STATUS "O3DE_REGISTER_GEM_PATHS=${O3DE_REGISTER_GEM_PATHS}") foreach(gem_path ${O3DE_REGISTER_GEM_PATHS}) if(CMAKE_HOST_WIN32) execute_process( @@ -143,7 +135,6 @@ if(O3DE_REGISTER_ENGINE_PATH) endif() if(O3DE_REGISTER_TEMPLATE_PATHS) - message(STATUS "O3DE_REGISTER_TEMPLATE_PATHS=${O3DE_REGISTER_TEMPLATE_PATHS}") foreach(template_path ${O3DE_REGISTER_TEMPLATE_PATHS}) if(CMAKE_HOST_WIN32) execute_process( @@ -165,7 +156,6 @@ if(O3DE_REGISTER_ENGINE_PATH) endif() if(O3DE_REGISTER_REPO_URIS) - message(STATUS "O3DE_REGISTER_REPO_URIS=${O3DE_REGISTER_REPO_URIS}") foreach(repo_uri ${O3DE_REGISTER_REPO_URIS}) if(CMAKE_HOST_WIN32) execute_process( @@ -201,7 +191,6 @@ file(READ ${o3de_manifest_json_path} manifest_json_data) # o3de manifest name ################################################################################ string(JSON o3de_manifest_name ERROR_VARIABLE json_error GET ${manifest_json_data} o3de_manifest_name) -message(STATUS "o3de_manifest_name: ${o3de_manifest_name}") if(json_error) message(FATAL_ERROR "Unable to read repo_name from '${o3de_manifest_json_path}', error: ${json_error}") endif() @@ -218,7 +207,6 @@ endif() # o3de default engines folder ################################################################################ string(JSON o3de_default_engines_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_engines_folder) -message(STATUS "default_engines_folder: ${o3de_default_engines_folder}") if(json_error) message(FATAL_ERROR "Unable to read default_engines_folder from '${o3de_manifest_json_path}', error: ${json_error}") endif() @@ -227,7 +215,6 @@ endif() # o3de default projects folder ################################################################################ string(JSON o3de_default_projects_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_projects_folder) -message(STATUS "default_projects_folder: ${o3de_default_projects_folder}") if(json_error) message(FATAL_ERROR "Unable to read default_projects_folder from '${o3de_manifest_json_path}', error: ${json_error}") endif() @@ -236,7 +223,6 @@ endif() # o3de default gems folder ################################################################################ string(JSON o3de_default_gems_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_gems_folder) -message(STATUS "default_gems_folder: ${o3de_default_gems_folder}") if(json_error) message(FATAL_ERROR "Unable to read default_gems_folder from '${o3de_manifest_json_path}', error: ${json_error}") endif() @@ -245,7 +231,6 @@ endif() # o3de default templates folder ################################################################################ string(JSON o3de_default_templates_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_templates_folder) -message(STATUS "default_templates_folder: ${o3de_default_templates_folder}") if(json_error) message(FATAL_ERROR "Unable to read default_templates_folder from '${o3de_manifest_json_path}', error: ${json_error}") endif() @@ -254,7 +239,6 @@ endif() # o3de default restricted folder ################################################################################ string(JSON o3de_default_restricted_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_restricted_folder) -message(STATUS "default_restricted_folder: ${o3de_default_restricted_folder}") if(json_error) message(FATAL_ERROR "Unable to read default_restricted_folder from '${o3de_manifest_json_path}', error: ${json_error}") endif() From f222590d77b743eb37840cb71910e1c0eceba7d5 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 16:02:07 -0700 Subject: [PATCH 036/140] fixing debug --- cmake/install/TargetCMakeLists.txt.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/TargetCMakeLists.txt.in index ae3ca91d5b..dd6fddcc9b 100644 --- a/cmake/install/TargetCMakeLists.txt.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -27,6 +27,7 @@ ly_add_target( @RUNTIME_DEPENDENCIES_PLACEHOLDER@ ) -foreach(config @CMAKE_CONFIGURATION_TYPES@) +set(configs @CMAKE_CONFIGURATION_TYPES@) +foreach(config ${configs}) include("@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) endforeach() From 232f81b4ea36229d8ff4d0c2d36f4c0ddd361da9 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 16:02:21 -0700 Subject: [PATCH 037/140] wrong trait --- Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt index 1066cc33e8..d3b8c8cde7 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt @@ -12,7 +12,7 @@ ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) ly_add_target( - NAME AtomFont ${PAL_TRAIT_MONOLITHIC_DRIVEN_LIBRARY_TYPE} + NAME AtomFont ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem FILES_CMAKE atomfont_files.cmake From b3ae71a5d8442e44b5bd32d1b74ce9277e372a3f Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 10 May 2021 16:03:00 -0700 Subject: [PATCH 038/140] misc fixes --- cmake/Platform/Common/Install_common.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 338244c05f..0642e24690 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -131,7 +131,7 @@ function(ly_setup_target ALIAS_TARGET_NAME) foreach(build_dependency ${inteface_build_dependencies_props}) # Skip wrapping produced when targets are not created in the same directory if(NOT ${build_dependency} MATCHES "^::@") - string(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}\n") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") endif() endforeach() endif() @@ -141,10 +141,12 @@ function(ly_setup_target ALIAS_TARGET_NAME) foreach(build_dependency ${private_build_dependencies_props}) # Skip wrapping produced when targets are not created in the same directory if(NOT ${build_dependency} MATCHES "^::@") - string(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}\n") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") endif() endforeach() endif() + list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target configure_file(${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in ${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/CMakeLists.txt @ONLY) From 083849b444dfefe68fbd2defe369302a9743d482 Mon Sep 17 00:00:00 2001 From: pappeste Date: Tue, 11 May 2021 14:41:28 -0700 Subject: [PATCH 039/140] Fixing initialization of LyShin and removing a macro and ISystemEventListner that were not doing anything --- Code/CryEngine/CryCommon/CryMemoryManager.h | 4 -- Code/CryEngine/CrySystem/DllMain.cpp | 1 - Code/CryEngine/CrySystem/SystemInit.cpp | 5 --- Code/CryEngine/CrySystem/XML/XmlUtils.cpp | 1 - .../Code/Source/LyShineSystemComponent.cpp | 44 ++++++++----------- .../Code/Source/LyShineSystemComponent.h | 6 +++ .../Code/Source/MaestroSystemComponent.cpp | 1 - 7 files changed, 25 insertions(+), 37 deletions(-) diff --git a/Code/CryEngine/CryCommon/CryMemoryManager.h b/Code/CryEngine/CryCommon/CryMemoryManager.h index b3f8ba7c8e..e900b16761 100644 --- a/Code/CryEngine/CryCommon/CryMemoryManager.h +++ b/Code/CryEngine/CryCommon/CryMemoryManager.h @@ -50,10 +50,6 @@ #include // memalign #endif // defined(APPLE) -#ifndef STLALLOCATOR_CLEANUP -#define STLALLOCATOR_CLEANUP -#endif - #define _CRY_DEFAULT_MALLOC_ALIGNMENT 4 #if CRYMEMORYMANAGER_H_TRAIT_INCLUDE_MALLOC_H diff --git a/Code/CryEngine/CrySystem/DllMain.cpp b/Code/CryEngine/CrySystem/DllMain.cpp index aba39fb9fb..7e9047854d 100644 --- a/Code/CryEngine/CrySystem/DllMain.cpp +++ b/Code/CryEngine/CrySystem/DllMain.cpp @@ -90,7 +90,6 @@ public: case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: { CryCleanup(); - STLALLOCATOR_CLEANUP; gEnv->pSystem->SetThreadState(ESubsys_Physics, true); break; } diff --git a/Code/CryEngine/CrySystem/SystemInit.cpp b/Code/CryEngine/CrySystem/SystemInit.cpp index 83ef4fcd2b..93fa75ec3b 100644 --- a/Code/CryEngine/CrySystem/SystemInit.cpp +++ b/Code/CryEngine/CrySystem/SystemInit.cpp @@ -1393,11 +1393,6 @@ bool CSystem::InitShine([[maybe_unused]] const SSystemInitParams& initParams) EBUS_EVENT(UiSystemBus, InitializeSystem); - if (!m_env.pLyShine) - { - AZ_Error(AZ_TRACE_SYSTEM_WINDOW, false, "LYShine System did not initialize correctly. Please check that the LyShine gem is enabled for this project in ProjectConfigurator."); - return false; - } return true; } diff --git a/Code/CryEngine/CrySystem/XML/XmlUtils.cpp b/Code/CryEngine/CrySystem/XML/XmlUtils.cpp index de5a14ecd7..d4feec04f2 100644 --- a/Code/CryEngine/CrySystem/XML/XmlUtils.cpp +++ b/Code/CryEngine/CrySystem/XML/XmlUtils.cpp @@ -272,7 +272,6 @@ void CXmlUtils::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wpar case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: case ESYSTEM_EVENT_LEVEL_LOAD_END: g_pCXmlNode_PoolAlloc->FreeMemoryIfEmpty(); - STLALLOCATOR_CLEANUP; break; } } diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp index 8e8079e18e..902752a03c 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp @@ -56,26 +56,6 @@ #include "UiDynamicScrollBoxComponent.h" #include "UiNavigationSettings.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -struct CSystemEventListener_UI - : public ISystemEventListener -{ -public: - virtual void OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam) - { - switch (event) - { - case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: - { - STLALLOCATOR_CLEANUP; - break; - } - } - } -}; -static CSystemEventListener_UI g_system_event_listener_ui; - - namespace LyShine { const AZStd::list* LyShineSystemComponent::m_componentDescriptors = nullptr; @@ -228,11 +208,6 @@ namespace LyShine //////////////////////////////////////////////////////////////////////////////////////////////////// void LyShineSystemComponent::InitializeSystem() { - // Not sure if this is still required - gEnv->pSystem->GetISystemEventDispatcher()->RegisterListener(&g_system_event_listener_ui); - - m_pLyShine = new CLyShine(gEnv->pSystem); - gEnv->pLyShine = m_pLyShine; BroadcastCursorImagePathname(); } @@ -397,6 +372,25 @@ namespace LyShine } } + /////////////////////////////////////////////////////////////////////////////////////////////// + void LyShineSystemComponent::OnCrySystemInitialized(ISystem& system, [[maybe_unused]] const SSystemInitParams& startupParams) + { +#if !defined(AZ_MONOLITHIC_BUILD) + // When module is linked dynamically, we must set our gEnv pointer. + // When module is linked statically, we'll share the application's gEnv pointer. + gEnv = system.GetGlobalEnvironment(); +#endif + m_pLyShine = new CLyShine(gEnv->pSystem); + gEnv->pLyShine = m_pLyShine; + } + + void LyShineSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system) + { + gEnv->pLyShine = nullptr; + delete m_pLyShine; + m_pLyShine = nullptr; + } + //////////////////////////////////////////////////////////////////////////////////////////////////// void LyShineSystemComponent::BroadcastCursorImagePathname() { diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.h b/Gems/LyShine/Code/Source/LyShineSystemComponent.h index 5f45f22823..f65dc75463 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.h +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.h @@ -38,6 +38,7 @@ namespace LyShine , protected UiSystemToolsBus::Handler , protected LyShineAllocatorScope , protected UiFrameworkBus::Handler + , protected CrySystemEventBus::Handler { public: AZ_COMPONENT(LyShineSystemComponent, lyShineSystemComponentUuid); @@ -89,6 +90,11 @@ namespace LyShine void HandleEditorOnlyEntities(const EntityList& exportSliceEntities, const EntityIdSet& editorOnlyEntityIds) override; //////////////////////////////////////////////////////////////////////// + // CrySystemEventBus /////////////////////////////////////////////////////// + void OnCrySystemInitialized(ISystem& system, const SSystemInitParams&) override; + virtual void OnCrySystemShutdown(ISystem&) override; + //////////////////////////////////////////////////////////////////////////// + void BroadcastCursorImagePathname(); protected: // data diff --git a/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp b/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp index cd0dfb02b3..dff51d3cc7 100644 --- a/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp +++ b/Gems/Maestro/Code/Source/MaestroSystemComponent.cpp @@ -112,7 +112,6 @@ namespace Maestro { case ESYSTEM_EVENT_LEVEL_POST_UNLOAD: { - STLALLOCATOR_CLEANUP; CLightAnimWrapper::ReconstructCache(); break; } From 671f26bed4f722c8e81dbfb6930455946ab4f50b Mon Sep 17 00:00:00 2001 From: pappeste Date: Tue, 11 May 2021 19:06:07 -0700 Subject: [PATCH 040/140] fixing debug configuration and how we declare IMPORTED targets (instead of UNKNOW we use the actual type) --- cmake/LYWrappers.cmake | 26 +++++------ cmake/Platform/Common/Install_common.cmake | 46 +++++++++++-------- .../Common/RuntimeDependencies_common.cmake | 8 +++- cmake/install/TargetCMakeLists.txt.in | 2 +- 4 files changed, 46 insertions(+), 36 deletions(-) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index fcf205238c..bddd1a6c66 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -87,8 +87,8 @@ function(ly_add_target) endif() if(NOT ly_add_target_IMPORTED AND NOT ly_add_target_HEADERONLY) if(NOT ly_add_target_FILES_CMAKE) - message(FATAL_ERROR "You must provide a list of _files.cmake files for the target") - endif() + message(FATAL_ERROR "You must provide a list of _files.cmake files for the target") + endif() endif() # If the GEM_MODULE tag is passed set the normal MODULE argument @@ -114,11 +114,10 @@ function(ly_add_target) set(linking_options ${PAL_LINKOPTION_MODULE}) set(linking_count "${linking_count}1") endif() - if(ly_add_target_HEADERONLY) set(linking_options INTERFACE) set(linking_count "${linking_count}1") - endif() + endif() if(ly_add_target_EXECUTABLE) set(linking_options EXECUTABLE) set(linking_count "${linking_count}1") @@ -127,12 +126,11 @@ function(ly_add_target) set(linking_options APPLICATION) set(linking_count "${linking_count}1") endif() - if(ly_add_target_IMPORTED) - set(linking_options UNKNOWN IMPORTED GLOBAL) - set(linking_count "${linking_count}1") - endif() if(NOT ("${linking_count}" STREQUAL "1")) - message(FATAL_ERROR "More than one of the following options [STATIC | SHARED | MODULE | HEADERONLY | EXECUTABLE | APPLICATION | IMPORTED] was specified and they are mutually exclusive") + message(FATAL_ERROR "More than one of the following options [STATIC | SHARED | MODULE | HEADERONLY | EXECUTABLE | APPLICATION ] was specified and they are mutually exclusive") + endif() + if(ly_add_target_IMPORTED) + list(APPEND linking_options IMPORTED GLOBAL) endif() if(ly_add_target_NAMESPACE) @@ -147,21 +145,23 @@ function(ly_add_target) ${ALLFILES} ${ly_add_target_GENERATED_FILES} ) ly_apply_platform_properties(${ly_add_target_NAME}) + if(ly_add_target_IMPORTED) + set_target_properties(${ly_add_target_NAME} PROPERTIES LINKER_LANGUAGE CXX) + endif() elseif(ly_add_target_APPLICATION) add_executable(${ly_add_target_NAME} ${PAL_EXECUTABLE_APPLICATION_FLAG} ${ALLFILES} ${ly_add_target_GENERATED_FILES} ) ly_apply_platform_properties(${ly_add_target_NAME}) + if(ly_add_target_IMPORTED) + set_target_properties(${ly_add_target_NAME} PROPERTIES LINKER_LANGUAGE CXX) + endif() elseif(ly_add_target_HEADERONLY) add_library(${ly_add_target_NAME} ${linking_options} ${ALLFILES} ${ly_add_target_GENERATED_FILES} ) - elseif(ly_add_target_IMPORTED) - add_library(${ly_add_target_NAME} - ${linking_options} - ) else() add_library(${ly_add_target_NAME} ${linking_options} diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 0642e24690..64fc973701 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -94,10 +94,17 @@ function(ly_setup_target ALIAS_TARGET_NAME) set(NAME_PLACEHOLDER ${TARGET_NAME}) endif() - set(TARGET_TYPE_PLACEHOLDER "IMPORTED") + set(TARGET_TYPE_PLACEHOLDER "") get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) - if(target_type STREQUAL INTERFACE_LIBRARY) - set(TARGET_TYPE_PLACEHOLDER "HEADERONLY") + # Remove the _LIBRARY since we dont need to pass that to ly_add_targets + string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) + # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead + string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) + if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") + get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) + if(gem_module) + set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") + endif() endif() get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) @@ -155,7 +162,7 @@ function(ly_setup_target ALIAS_TARGET_NAME) DESTINATION ${target_source_dir}/${NAME_PLACEHOLDER} COMPONENT ${ly_install_target_COMPONENT} ) - + # Config file set(target_file_contents "# Generated by O3DE install\n\n") if(NOT target_type STREQUAL INTERFACE_LIBRARY) @@ -163,29 +170,28 @@ function(ly_setup_target ALIAS_TARGET_NAME) unset(target_location) set(runtime_types EXECUTABLE APPLICATION) if(target_type IN_LIST runtime_types) - string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$\"") + set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$") elseif(target_type STREQUAL MODULE_LIBRARY) - string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\"") + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") elseif(target_type STREQUAL SHARED_LIBRARY) - string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") - string(APPEND target_file_contents "target_link_libraries(${TARGET_NAME} INTERFACE \"\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$\")\n") + string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$ \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\")\n") + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY - string(APPEND target_location "\"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\"") + set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$") endif() - string(APPEND target_file_contents -"set(target_location ${target_location}) -set_target_properties(${TARGET_NAME} - PROPERTIES - $<$:IMPORTED_LOCATION \"\${target_location}\"> - IMPORTED_LOCATION_$> \"\${target_location}\" + if(target_location) + string(APPEND target_file_contents +"set_property(TARGET ${TARGET_NAME} + APPEND_STRING PROPERTY IMPORTED_LOCATION + $<$$:${target_location}$ +) +set_property(TARGET ${TARGET_NAME} + PROPERTY IMPORTED_LOCATION_$> + ${target_location} ) -if(EXISTS \"\${target_location}\") - set(${NAME_PLACEHOLDER}_$_FOUND TRUE) -else() - set(${NAME_PLACEHOLDER}_$_FOUND FALSE) -endif() ") + endif() endif() file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") diff --git a/cmake/Platform/Common/RuntimeDependencies_common.cmake b/cmake/Platform/Common/RuntimeDependencies_common.cmake index 333bbaaae2..d9d0fe4c7f 100644 --- a/cmake/Platform/Common/RuntimeDependencies_common.cmake +++ b/cmake/Platform/Common/RuntimeDependencies_common.cmake @@ -61,7 +61,7 @@ function(ly_get_runtime_dependencies ly_RUNTIME_DEPENDENCIES ly_TARGET) if(dependencies) list(APPEND link_dependencies ${dependencies}) endif() - if(NOT target_type MATCHES "INTERFACE") + if(NOT target_type STREQUAL "INTERFACE_LIBRARY") unset(dependencies) get_target_property(dependencies ${ly_TARGET} LINK_LIBRARIES) if(dependencies) @@ -105,11 +105,15 @@ function(ly_get_runtime_dependencies ly_RUNTIME_DEPENDENCIES ly_TARGET) set(skip_imported TRUE) endif() endif() + if(target_type MATCHES "(INTERFACE_LIBRARY|STATIC_LIBRARY)") + # No need to copy these dependencies since the outputs are not used at runtime + set(skip_imported TRUE) + endif() if(NOT skip_imported) # Add imported locations - if(target_type MATCHES "INTERFACE") + if(target_type STREQUAL "INTERFACE_LIBRARY") set(imported_property INTERFACE_IMPORTED_LOCATION) else() set(imported_property IMPORTED_LOCATION) diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/TargetCMakeLists.txt.in index dd6fddcc9b..b2c8b9b6f6 100644 --- a/cmake/install/TargetCMakeLists.txt.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -12,7 +12,7 @@ # Generated by O3DE ly_add_target( - NAME @NAME_PLACEHOLDER@ @TARGET_TYPE_PLACEHOLDER@ + NAME @NAME_PLACEHOLDER@ IMPORTED @TARGET_TYPE_PLACEHOLDER@ @NAMESPACE_PLACEHOLDER@ COMPILE_DEFINITIONS INTERFACE From 99c2c3b07be18aa95d0381e7eca5c8d80a004215 Mon Sep 17 00:00:00 2001 From: phistere Date: Thu, 13 May 2021 19:04:20 -0500 Subject: [PATCH 041/140] Updates the settings registry visitor that walks through 'engines' from the manifest --- .../Settings/SettingsRegistryMergeUtils.cpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 56dfbdcb71..10a830bcc6 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -88,6 +88,35 @@ namespace AZ::Internal m_enginePaths.emplace_back(EngineInfo{AZ::IO::FixedMaxPath{value}.LexicallyNormal(), {}}); } + AZ::SettingsRegistryInterface::VisitResponse Traverse( + [[maybe_unused]] AZStd::string_view path, AZStd::string_view valueName, + AZ::SettingsRegistryInterface::VisitAction action, AZ::SettingsRegistryInterface::Type type) override + { + auto response = AZ::SettingsRegistryInterface::VisitResponse::Continue; + if (action == AZ::SettingsRegistryInterface::VisitAction::Begin) + { + if (type == AZ::SettingsRegistryInterface::Type::Array) + { + if (valueName.compare("engines") != 0) + { + response = AZ::SettingsRegistryInterface::VisitResponse::Skip; + } + } + } + else if (action == AZ::SettingsRegistryInterface::VisitAction::Value) + { + if (type == AZ::SettingsRegistryInterface::Type::String) + { + if (valueName.compare("path") != 0) + { + response = AZ::SettingsRegistryInterface::VisitResponse::Skip; + } + } + } + + return response; + } + AZStd::vector m_enginePaths{}; }; From 74fda49ca4e99348da42c41da774ea32d04eab69 Mon Sep 17 00:00:00 2001 From: phistere Date: Sun, 16 May 2021 11:39:49 -0500 Subject: [PATCH 042/140] Fixes paths to AssetProcessor when being run from SDK. --- .../AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp | 3 ++- .../Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp | 3 ++- .../AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp index 1ae3945bd6..d501271f59 100644 --- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp @@ -35,7 +35,8 @@ namespace AzFramework::AssetSystem::Platform if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { // Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure. - assetProcessorPath = AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor"; + assetProcessorPath = + AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_TRAIT_OS_PLATFORM_NAME / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor"; if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp index 6f1f860932..890b6b32c3 100644 --- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp @@ -34,7 +34,8 @@ namespace AzFramework::AssetSystem::Platform if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { // Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure. - assetProcessorPath = AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor.app"; + assetProcessorPath = + AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_TRAIT_OS_PLATFORM_NAME / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor.app"; if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp index b716778cf4..b0debfd3b0 100644 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Asset/AssetSystemComponentHelper_Windows.cpp @@ -71,7 +71,8 @@ namespace AzFramework::AssetSystem::Platform if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { // Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure. - assetProcessorPath = AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor.exe"; + assetProcessorPath = + AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_TRAIT_OS_PLATFORM_NAME / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor.exe"; if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { From f30b1f2c75977a32a69732815ed32962e46ee2d4 Mon Sep 17 00:00:00 2001 From: phistere Date: Mon, 17 May 2021 11:41:10 -0500 Subject: [PATCH 043/140] Work in Progress: template changes, getting external projects w/ SDK to work --- .../DefaultProject/Template/CMakeLists.txt | 155 ++++++++++++------ .../Template/EngineFinder.cmake | 64 ++++++++ Templates/DefaultProject/template.json | 6 + 3 files changed, 176 insertions(+), 49 deletions(-) create mode 100644 Templates/DefaultProject/Template/EngineFinder.cmake diff --git a/Templates/DefaultProject/Template/CMakeLists.txt b/Templates/DefaultProject/Template/CMakeLists.txt index ad0a4c869d..c92607a789 100644 --- a/Templates/DefaultProject/Template/CMakeLists.txt +++ b/Templates/DefaultProject/Template/CMakeLists.txt @@ -23,64 +23,121 @@ function(add_vs_debugger_arguments) endforeach() endfunction() -set(o3de_project_path ${CMAKE_CURRENT_LIST_DIR}) -set(o3de_project_json ${o3de_project_path}/project.json) - if(NOT PROJECT_NAME) cmake_minimum_required(VERSION 3.19) project(${Name} LANGUAGES C CXX VERSION 1.0.0.0 ) + include(EngineFinder.cmake OPTIONAL) + find_package(o3de REQUIRED) + o3de_initialize() + add_vs_debugger_arguments() +else() + # Add the project_name to global LY_PROJECTS_TARGET_NAME property + file(READ "${CMAKE_CURRENT_LIST_DIR}/project.json" project_json) - # set this project as the only project - set(LY_PROJECTS ${CMAKE_CURRENT_LIST_DIR}) - - # o3de manifest - include(o3de_manifest.cmake) - - ################################################################################ - # Set the engine_path and resolve this engines restricted path if it has one - ################################################################################ - o3de_engine_path(${o3de_project_json} o3de_engine_path) - o3de_project_name(${o3de_project_json} o3de_project_name) - o3de_restricted_path(${o3de_project_json} o3de_project_restricted_path) - message(STATUS "O3DE Project Name: ${o3de_project_name}") - message(STATUS "O3DE Project Path: ${o3de_project_path}") - if(o3de_project_restricted_path) - message(STATUS "O3DE Project Restricted Path: ${o3de_project_restricted_path}") + string(JSON project_target_name ERROR_VARIABLE json_error GET ${project_json} "project_name") + if(json_error) + message(FATAL_ERROR "Unable to read key 'project_name' from 'project.json'") endif() - # add the engines cmake folder to the CMAKE_MODULE_PATH - list(APPEND CMAKE_MODULE_PATH "${o3de_engine_path}/cmake") - - # add subdirectory on the engine path for this project - add_subdirectory(${o3de_engine_path} o3de) - - # add this --project-path arguments to visual studio debugger - add_vs_debugger_arguments() - -else() - ###################################################### - # the engine is calling add sub_directory() on us - ###################################################### - o3de_project_name(${o3de_project_json} o3de_project_name) - o3de_restricted_path(${o3de_project_json} o3de_project_restricted_path) - - # Currently we are in the folder: ${CMAKE_CURRENT_LIST_DIR} - # Get the platform specific folder ${pal_dir} for the folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} - # Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform - # in which case it will see if that platform is present here or in the restricted folder. - # i.e. It could here: TestDP/Platform/ or - # //TestDP - ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_project_restricted_path} ${o3de_project_path} ${o3de_project_name}) - - # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the - # project cmake for this platform. - include(${pal_dir}/${PAL_PLATFORM_NAME_LOWERCASE}_project.cmake) - - # Add the project_name to global LY_PROJECTS_TARGET_NAME property - set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${o3de_project_name}) + set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${project_target_name}) add_subdirectory(Code) endif() + + + +# #! Adds the --project-path argument to the VS IDE debugger command arguments +# function(add_vs_debugger_arguments) +# # Inject the project root into the --project-path argument into the Visual Studio Debugger arguments by defaults +# list(APPEND app_targets ${Name}.GameLauncher ${Name}.ServerLauncher) +# list(APPEND app_targets AssetBuilder AssetProcessor AssetProcessorBatch Editor) +# foreach(app_target IN LISTS app_targets) +# if (TARGET ${app_target}) +# set_property(TARGET ${app_target} APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${CMAKE_CURRENT_LIST_DIR}\"") +# endif() +# endforeach() +# endfunction() + +# set(o3de_project_path ${CMAKE_CURRENT_LIST_DIR}) +# set(o3de_project_json ${o3de_project_path}/project.json) + +# if(NOT PROJECT_NAME) +# cmake_minimum_required(VERSION 3.19) +# project(${Name} +# LANGUAGES C CXX +# VERSION 1.0.0.0 +# ) + +# # set this project as the only project +# set(LY_PROJECTS ${CMAKE_CURRENT_LIST_DIR}) + +# # o3de manifest +# include(o3de_manifest.cmake) + +# ################################################################################ +# # Set the engine_path and resolve this engines restricted path if it has one +# ################################################################################ +# o3de_engine_path(${o3de_project_json} o3de_engine_path) +# o3de_project_name(${o3de_project_json} o3de_project_name) +# o3de_restricted_path(${o3de_project_json} o3de_project_restricted_path) +# message(STATUS "O3DE Project Name: ${o3de_project_name}") +# message(STATUS "O3DE Project Path: ${o3de_project_path}") +# if(o3de_project_restricted_path) +# message(STATUS "O3DE Project Restricted Path: ${o3de_project_restricted_path}") +# endif() + +# # add the engines cmake folder to the CMAKE_MODULE_PATH +# list(APPEND CMAKE_MODULE_PATH "${o3de_engine_path}/cmake") + +# # add subdirectory on the engine path for this project +# #add_subdirectory(${o3de_engine_path} o3de) +# find_package(o3de REQUIRED) +# o3de_initialize() + +# # add this --project-path arguments to visual studio debugger +# add_vs_debugger_arguments() + +# else() +# ###################################################### +# # the engine is calling add sub_directory() on us +# ###################################################### +# o3de_project_name(${o3de_project_json} o3de_project_name) +# o3de_restricted_path(${o3de_project_json} o3de_project_restricted_path) + +# # Currently we are in the folder: ${CMAKE_CURRENT_LIST_DIR} +# # Get the platform specific folder ${pal_dir} for the folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} +# # Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform +# # in which case it will see if that platform is present here or in the restricted folder. +# # i.e. It could here: TestDP/Platform/ or +# # //TestDP +# ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_project_restricted_path} ${o3de_project_path} ${o3de_project_name}) + +# # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the +# # project cmake for this platform. +# include(${pal_dir}/${PAL_PLATFORM_NAME_LOWERCASE}_project.cmake) + +# # Add the project_name to global LY_PROJECTS_TARGET_NAME property +# set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${o3de_project_name}) + +# add_subdirectory(Code) +# endif() + + + + + + + + + + + + + + + + + diff --git a/Templates/DefaultProject/Template/EngineFinder.cmake b/Templates/DefaultProject/Template/EngineFinder.cmake new file mode 100644 index 0000000000..5f791f5e3d --- /dev/null +++ b/Templates/DefaultProject/Template/EngineFinder.cmake @@ -0,0 +1,64 @@ +# +# 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. +# +# This file is copied during engine registration. Edits to this file will be lost next +# time a registration happens. + +include_guard() + +# Read the engine name from the project_json file +file(READ ${CMAKE_CURRENT_LIST_DIR}/project.json project_json) +string(JSON LY_ENGINE_NAME_TO_USE ERROR_VARIABLE json_error GET ${project_json} engine) +if(json_error) + message(FATAL_ERROR "Unable to read key 'engine' from 'project.json', error: ${json_error}") +endif() + +# Read the list of paths from ~.o3de/o3de_manifest.json +if($ENV{USERPROFILE} AND EXISTS $ENV{USERPROFILE}) + set(manifest_path $ENV{USERPROFILE}/.o3de/o3de_manifest.json) # Windows +else() + set(manifest_path $ENV{HOME}/.o3de/o3de_manifest.json) # Unix +endif() + +if(EXISTS ${manifest_path}) + file(READ ${manifest_path} manifest_json) + + string(JSON engine_paths_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engine_paths) + if(json_error) + message(FATAL_ERROR "Unable to read key 'engine_paths' from '${manifest_path}', error: ${json_error}") + endif() + + string(JSON engine_paths_type ERROR_VARIABLE json_error TYPE ${manifest_json} engine_paths) + if(json_error OR NOT ${engine_paths_type} STREQUAL "OBJECT") + message(FATAL_ERROR "Type of 'engine_paths' in '${manifest_path}' is not a JSON Object, error: ${json_error}") + endif() + + math(EXPR engine_paths_count "${engine_paths_count}-1") + foreach(engine_path_index RANGE ${engine_paths_count}) + string(JSON engine_name ERROR_VARIABLE json_error MEMBER ${manifest_json} engine_paths ${engine_path_index}) + if(json_error) + message(FATAL_ERROR "Unable to read 'engine_paths/${engine_path_index}' from '${manifest_path}', error: ${json_error}") + endif() + + if(LY_ENGINE_NAME_TO_USE STREQUAL engine_name) + string(JSON engine_path ERROR_VARIABLE json_error GET ${manifest_json} engine_paths ${engine_name}) + if(json_error) + message(FATAL_ERROR "Unable to read value from 'engine_paths/${engine_name}', error: ${json_error}") + endif() + + if(engine_path) + list(APPEND CMAKE_MODULE_PATH "${engine_path}/cmake") + break() + endif() + endif() + endforeach() +else() + message(FATAL_ERROR "Engine registration is required before configuring a project. Please register an engine by running 'scripts/o3de register --this-engine'") +endif() diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index 56278a6b04..e823b6df19 100644 --- a/Templates/DefaultProject/template.json +++ b/Templates/DefaultProject/template.json @@ -24,6 +24,12 @@ "isTemplated": true, "isOptional": false }, + { + "file": "EngineFinder.cmake", + "origin": "EngineFinder.cmake", + "isTemplated": false, + "isOptional": false + }, { "file": "Code/${NameLower}_files.cmake", "origin": "Code/${NameLower}_files.cmake", From d4a0eb3a246e2afcc10e9322638e3a420ef32bca Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 17 May 2021 13:03:37 -0500 Subject: [PATCH 044/140] Moving o3de registration scripts to the scripts/o3de folder --- {cmake/Tools => scripts/o3de}/engine_template.py | 0 {cmake/Tools => scripts/o3de}/global_project.py | 0 {cmake/Tools => scripts/o3de}/registration.py | 0 {cmake/Tools => scripts/o3de}/unit_test_add_remove_gem.py | 0 {cmake/Tools => scripts/o3de}/unit_test_current_project.py | 0 {cmake/Tools => scripts/o3de}/unit_test_engine_template.py | 0 {cmake/Tools => scripts/o3de}/unit_test_utils.py | 0 {cmake/Tools => scripts/o3de}/utils.py | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename {cmake/Tools => scripts/o3de}/engine_template.py (100%) rename {cmake/Tools => scripts/o3de}/global_project.py (100%) rename {cmake/Tools => scripts/o3de}/registration.py (100%) rename {cmake/Tools => scripts/o3de}/unit_test_add_remove_gem.py (100%) rename {cmake/Tools => scripts/o3de}/unit_test_current_project.py (100%) rename {cmake/Tools => scripts/o3de}/unit_test_engine_template.py (100%) rename {cmake/Tools => scripts/o3de}/unit_test_utils.py (100%) rename {cmake/Tools => scripts/o3de}/utils.py (100%) diff --git a/cmake/Tools/engine_template.py b/scripts/o3de/engine_template.py similarity index 100% rename from cmake/Tools/engine_template.py rename to scripts/o3de/engine_template.py diff --git a/cmake/Tools/global_project.py b/scripts/o3de/global_project.py similarity index 100% rename from cmake/Tools/global_project.py rename to scripts/o3de/global_project.py diff --git a/cmake/Tools/registration.py b/scripts/o3de/registration.py similarity index 100% rename from cmake/Tools/registration.py rename to scripts/o3de/registration.py diff --git a/cmake/Tools/unit_test_add_remove_gem.py b/scripts/o3de/unit_test_add_remove_gem.py similarity index 100% rename from cmake/Tools/unit_test_add_remove_gem.py rename to scripts/o3de/unit_test_add_remove_gem.py diff --git a/cmake/Tools/unit_test_current_project.py b/scripts/o3de/unit_test_current_project.py similarity index 100% rename from cmake/Tools/unit_test_current_project.py rename to scripts/o3de/unit_test_current_project.py diff --git a/cmake/Tools/unit_test_engine_template.py b/scripts/o3de/unit_test_engine_template.py similarity index 100% rename from cmake/Tools/unit_test_engine_template.py rename to scripts/o3de/unit_test_engine_template.py diff --git a/cmake/Tools/unit_test_utils.py b/scripts/o3de/unit_test_utils.py similarity index 100% rename from cmake/Tools/unit_test_utils.py rename to scripts/o3de/unit_test_utils.py diff --git a/cmake/Tools/utils.py b/scripts/o3de/utils.py similarity index 100% rename from cmake/Tools/utils.py rename to scripts/o3de/utils.py From 680a8e6fbd80466015161cf7d24aba4c56f83773 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 21:43:13 -0500 Subject: [PATCH 045/140] Moving the o3de UnitTest files to script/o3de/test folder to help with file organization --- scripts/o3de/{ => test}/unit_test_add_remove_gem.py | 0 scripts/o3de/{ => test}/unit_test_current_project.py | 0 scripts/o3de/{ => test}/unit_test_engine_template.py | 0 scripts/o3de/{ => test}/unit_test_utils.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename scripts/o3de/{ => test}/unit_test_add_remove_gem.py (100%) rename scripts/o3de/{ => test}/unit_test_current_project.py (100%) rename scripts/o3de/{ => test}/unit_test_engine_template.py (100%) rename scripts/o3de/{ => test}/unit_test_utils.py (100%) diff --git a/scripts/o3de/unit_test_add_remove_gem.py b/scripts/o3de/test/unit_test_add_remove_gem.py similarity index 100% rename from scripts/o3de/unit_test_add_remove_gem.py rename to scripts/o3de/test/unit_test_add_remove_gem.py diff --git a/scripts/o3de/unit_test_current_project.py b/scripts/o3de/test/unit_test_current_project.py similarity index 100% rename from scripts/o3de/unit_test_current_project.py rename to scripts/o3de/test/unit_test_current_project.py diff --git a/scripts/o3de/unit_test_engine_template.py b/scripts/o3de/test/unit_test_engine_template.py similarity index 100% rename from scripts/o3de/unit_test_engine_template.py rename to scripts/o3de/test/unit_test_engine_template.py diff --git a/scripts/o3de/unit_test_utils.py b/scripts/o3de/test/unit_test_utils.py similarity index 100% rename from scripts/o3de/unit_test_utils.py rename to scripts/o3de/test/unit_test_utils.py From f34661491774ed36587047bbd91ebd46da8ed32b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 21:47:03 -0500 Subject: [PATCH 046/140] Adding __init__.py scripts to allow the name of o3de to be structured as a package --- scripts/o3de/__init__.py | 10 ++++++++++ scripts/o3de/test/__init__.py | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 scripts/o3de/__init__.py create mode 100644 scripts/o3de/test/__init__.py diff --git a/scripts/o3de/__init__.py b/scripts/o3de/__init__.py new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/scripts/o3de/__init__.py @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/scripts/o3de/test/__init__.py b/scripts/o3de/test/__init__.py new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/scripts/o3de/test/__init__.py @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# From 548219d1174a9598d554844e4aff5f8b52bdbbb9 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 22:19:09 -0500 Subject: [PATCH 047/140] Updated the registration.py script register_engine_path function to add a key, value mapping of engine name to engine path in the o3de_manifest.json file Added a pytest to validate the new engine_name -> engine_path functionality and registered those test with CTest. Fixed miscellaneous issues in the registration.py around incorrect return values for get_*_data functions where some of the returns values were integers where the return value should have been None --- scripts/CMakeLists.txt | 1 + scripts/o3de/CMakeLists.txt | 12 ++ scripts/o3de/registration.py | 172 +++++++++++++------- scripts/o3de/test/CMakeLists.txt | 22 +++ scripts/o3de/test/unit_test_registration.py | 66 ++++++++ 5 files changed, 212 insertions(+), 61 deletions(-) create mode 100644 scripts/o3de/CMakeLists.txt create mode 100644 scripts/o3de/test/CMakeLists.txt create mode 100644 scripts/o3de/test/unit_test_registration.py diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index d2843a9013..d3c9640665 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -11,5 +11,6 @@ add_subdirectory(detect_file_changes) add_subdirectory(commit_validation) +add_subdirectory(o3de) add_subdirectory(project_manager) add_subdirectory(ctest) diff --git a/scripts/o3de/CMakeLists.txt b/scripts/o3de/CMakeLists.txt new file mode 100644 index 0000000000..0744845784 --- /dev/null +++ b/scripts/o3de/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +add_subdirectory(test) diff --git a/scripts/o3de/registration.py b/scripts/o3de/registration.py index 184d2cdb31..eb7224c8ea 100755 --- a/scripts/o3de/registration.py +++ b/scripts/o3de/registration.py @@ -128,7 +128,7 @@ def get_o3de_logs_folder() -> pathlib.Path: return restricted_folder -def register_shipped_engine_o3de_objects() -> int: +def register_shipped_engine_o3de_objects(force: bool = False) -> int: engine_path = get_this_engine_path() ret_val = 0 @@ -137,7 +137,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_engines_directories = [ ] for engines_directory in sorted(starting_engines_directories, reverse=True): - error_code = register_all_engines_in_folder(engines_path=engines_directory) + error_code = register_all_engines_in_folder(engines_path=engines_directory, force=force) if error_code: ret_val = error_code @@ -145,7 +145,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_engines = [ ] for engine_path in sorted(starting_engines): - error_code = register(engine_path=engine_path) + error_code = register(engine_path=engine_path, force=force) if error_code: ret_val = error_code @@ -162,7 +162,7 @@ def register_shipped_engine_o3de_objects() -> int: f'{engine_path}/AutomatedTesting' ] for project_path in sorted(starting_projects, reverse=True): - error_code = register(engine_path=engine_path, project_path=project_path) + error_code = register(engine_path=engine_path, project_path=project_path, force=force) if error_code: ret_val = error_code @@ -179,7 +179,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_gems = [ ] for gem_path in sorted(starting_gems, reverse=True): - error_code = register(engine_path=engine_path, gem_path=gem_path) + error_code = register(engine_path=engine_path, gem_path=gem_path, force=force) if error_code: ret_val = error_code @@ -196,7 +196,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_templates = [ ] for template_path in sorted(starting_templates, reverse=True): - error_code = register(engine_path=engine_path, template_path=template_path) + error_code = register(engine_path=engine_path, template_path=template_path, force=force) if error_code: ret_val = error_code @@ -212,7 +212,7 @@ def register_shipped_engine_o3de_objects() -> int: starting_restricted = [ ] for restricted_path in sorted(starting_restricted, reverse=True): - error_code = register(engine_path=engine_path, restricted_path=restricted_path) + error_code = register(engine_path=engine_path, restricted_path=restricted_path, force=force) if error_code: ret_val = error_code @@ -228,12 +228,12 @@ def register_shipped_engine_o3de_objects() -> int: starting_repos = [ ] for repo_uri in sorted(starting_repos, reverse=True): - error_code = register(repo_uri=repo_uri) + error_code = register(repo_uri=repo_uri, force=force) if error_code: ret_val = error_code # register anything in the users default folders globally - error_code = register_all_engines_in_folder(get_registered(default_folder='engines')) + error_code = register_all_engines_in_folder(get_registered(default_folder='engines'), force=force) if error_code: ret_val = error_code error_code = register_all_projects_in_folder(get_registered(default_folder='projects')) @@ -266,7 +266,7 @@ def register_shipped_engine_o3de_objects() -> int: gem_path = pathlib.Path(gem_path).resolve() gem_cmake_lists_txt = gem_path / 'CMakeLists.txt' if gem_cmake_lists_txt.is_file(): - add_gem_to_cmake(engine_path=engine_path, gem_path=gem_path, supress_errors=True) # don't care about errors + add_gem_to_cmake(engine_path=engine_path, gem_path=gem_path, suppress_errors=True) # don't care about errors return ret_val @@ -344,7 +344,8 @@ def register_all_in_folder(folder_path: str or pathlib.Path, def register_all_engines_in_folder(engines_path: str or pathlib.Path, - remove: bool = False) -> int: + remove: bool = False, + force: bool = False) -> int: if not engines_path: logger.error(f'Engines path cannot be empty.') return 1 @@ -360,10 +361,10 @@ def register_all_engines_in_folder(engines_path: str or pathlib.Path, for root, dirs, files in os.walk(engines_path): for name in files: if name == 'engine.json': - engines_set.add(name) + engines_set.add(root) for engine in sorted(engines_set, reverse=True): - error_code = register(engine_path=engine, remove=remove) + error_code = register(engine_path=engine, remove=remove, force=force) if error_code: ret_val = error_code @@ -602,21 +603,65 @@ def save_o3de_manifest(json_data: dict) -> None: logger.error(f'Manifest json failed to save: {str(e)}') +def remove_engine_name_to_path(json_data: dict, + engine_path: pathlib.Path) -> int: + """ + Remove the engine at the specified path if it exist in the o3de manifest + :param json_data in-memory json view of the o3de_manifest.json data + :param engine_path path to engine to remove from the manifest data + + returns 0 to indicate no issues has occurred with removal + """ + if engine_path.is_dir() and valid_o3de_engine_json(engine_path): + engine_json_data = get_engine_data(engine_path=engine_path) + if 'engine_name' in engine_json_data and 'engines_path' in json_data: + engine_name = engine_json_data['engine_name'] + try: + del json_data['engines_path'][engine_name] + except KeyError: + # Attempting to remove a non-existent engine_name is fine + pass + return 0 + + +def add_engine_name_to_path(json_data: dict, engine_path: pathlib.Path, force: bool): + # Add an engine path JSON object which maps the "engine_name" -> "engine_path" + engine_json_data = get_engine_data(engine_path=engine_path) + if not engine_json_data: + logger.error(f'Unable to retrieve json data from engine.json at path {engine_path.as_posix()}') + return 1 + engines_path_json = json_data.setdefault('engines_path', {}) + if 'engine_name' not in engine_json_data: + logger.error(f'engine.json at path {engine_path.as_posix()} is missing "engine_name" key') + return 1 + + engine_name = engine_json_data['engine_name'] + if not force and engine_name in engines_path_json and \ + pathlib.PurePath(engines_path_json[engine_name]) != engine_path: + logger.error( + f'Attempting to register existing engine "{engine_name}" with a new path of {engine_path.as_posix()}.' + f' The current path is {pathlib.Path(engines_path_json[engine_name]).as_posix()}.' + f' To force registration of a new engine path, specify the -f/--force option.') + return 1 + engines_path_json[engine_name] = engine_path.as_posix() + return 0 + def register_engine_path(json_data: dict, engine_path: str or pathlib.Path, - remove: bool = False) -> int: + remove: bool = False, + force: bool = False) -> int: if not engine_path: logger.error(f'Engine path cannot be empty.') return 1 engine_path = pathlib.Path(engine_path).resolve() - for engine_object in json_data['engines']: + for engine_object in json_data.get('engines', {}): engine_object_path = pathlib.Path(engine_object['path']).resolve() if engine_object_path == engine_path: json_data['engines'].remove(engine_object) if remove: - return 0 + return remove_engine_name_to_path(json_data, engine_path) if not engine_path.is_dir(): logger.error(f'Engine path {engine_path} does not exist.') @@ -635,9 +680,9 @@ def register_engine_path(json_data: dict, engine_object.update({'restricted': []}) engine_object.update({'external_subdirectories': []}) - json_data['engines'].insert(0, engine_object) + json_data.setdefault('engines', []).insert(0, engine_object) - return 0 + return add_engine_name_to_path(json_data, engine_path, force) def register_gem_path(json_data: dict, @@ -1234,7 +1279,8 @@ def register(engine_path: str or pathlib.Path = None, default_gems_folder: str or pathlib.Path = None, default_templates_folder: str or pathlib.Path = None, default_restricted_folder: str or pathlib.Path = None, - remove: bool = False + remove: bool = False, + force: bool = False ) -> int: """ Adds/Updates entries to the .o3de/o3de_manifest.json @@ -1251,6 +1297,7 @@ def register(engine_path: str or pathlib.Path = None, :param default_templates_folder: default templates folder :param default_restricted_folder: default restricted code folder :param remove: add/remove the entries + :param force: force update of the engine_path for specified "engine_name" from the engine.json file :return: 0 for success or non 0 failure code """ @@ -1312,7 +1359,7 @@ def register(engine_path: str or pathlib.Path = None, if not engine_path: logger.error(f'Engine path cannot be empty.') return 1 - result = register_engine_path(json_data, engine_path, remove) + result = register_engine_path(json_data, engine_path, remove, force) if not result: save_o3de_manifest(json_data) @@ -2122,23 +2169,23 @@ def get_engine_data(engine_name: str = None, engine_path: str or pathlib.Path = None, ) -> dict or None: if not engine_name and not engine_path: logger.error('Must specify either a Engine name or Engine Path.') - return 1 + return None if engine_name and not engine_path: engine_path = get_registered(engine_name=engine_name) if not engine_path: logger.error(f'Engine Path {engine_path} has not been registered.') - return 1 + return None engine_path = pathlib.Path(engine_path).resolve() engine_json = engine_path / 'engine.json' if not engine_json.is_file(): logger.error(f'Engine json {engine_json} is not present.') - return 1 + return None if not valid_o3de_engine_json(engine_json): logger.error(f'Engine json {engine_json} is not valid.') - return 1 + return None with engine_json.open('r') as f: try: @@ -2155,23 +2202,23 @@ def get_project_data(project_name: str = None, project_path: str or pathlib.Path = None, ) -> dict or None: if not project_name and not project_path: logger.error('Must specify either a Project name or Project Path.') - return 1 + return None if project_name and not project_path: project_path = get_registered(project_name=project_name) if not project_path: logger.error(f'Project Path {project_path} has not been registered.') - return 1 + return None project_path = pathlib.Path(project_path).resolve() project_json = project_path / 'project.json' if not project_json.is_file(): logger.error(f'Project json {project_json} is not present.') - return 1 + return None if not valid_o3de_project_json(project_json): logger.error(f'Project json {project_json} is not valid.') - return 1 + return None with project_json.open('r') as f: try: @@ -2188,23 +2235,23 @@ def get_gem_data(gem_name: str = None, gem_path: str or pathlib.Path = None, ) -> dict or None: if not gem_name and not gem_path: logger.error('Must specify either a Gem name or Gem Path.') - return 1 + return None if gem_name and not gem_path: gem_path = get_registered(gem_name=gem_name) if not gem_path: logger.error(f'Gem Path {gem_path} has not been registered.') - return 1 + return None gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' if not gem_json.is_file(): logger.error(f'Gem json {gem_json} is not present.') - return 1 + return None if not valid_o3de_gem_json(gem_json): logger.error(f'Gem json {gem_json} is not valid.') - return 1 + return None with gem_json.open('r') as f: try: @@ -2221,23 +2268,23 @@ def get_template_data(template_name: str = None, template_path: str or pathlib.Path = None, ) -> dict or None: if not template_name and not template_path: logger.error('Must specify either a Template name or Template Path.') - return 1 + return None if template_name and not template_path: template_path = get_registered(template_name=template_name) if not template_path: logger.error(f'Template Path {template_path} has not been registered.') - return 1 + return None template_path = pathlib.Path(template_path).resolve() template_json = template_path / 'template.json' if not template_json.is_file(): logger.error(f'Template json {template_json} is not present.') - return 1 + return None if not valid_o3de_template_json(template_json): logger.error(f'Template json {template_json} is not valid.') - return 1 + return None with template_json.open('r') as f: try: @@ -2254,23 +2301,23 @@ def get_restricted_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None, ) -> dict or None: if not restricted_name and not restricted_path: logger.error('Must specify either a Restricted name or Restricted Path.') - return 1 + return None if restricted_name and not restricted_path: restricted_path = get_registered(restricted_name=restricted_name) if not restricted_path: logger.error(f'Restricted Path {restricted_path} has not been registered.') - return 1 + return None restricted_path = pathlib.Path(restricted_path).resolve() restricted_json = restricted_path / 'restricted.json' if not restricted_json.is_file(): logger.error(f'Restricted json {restricted_json} is not present.') - return 1 + return None if not valid_o3de_restricted_json(restricted_json): logger.error(f'Restricted json {restricted_json} is not valid.') - return 1 + return None with restricted_json.open('r') as f: try: @@ -3259,30 +3306,30 @@ def get_gem_targets(gem_name: str = None, def add_external_subdirectory(external_subdir: str or pathlib.Path, engine_path: str or pathlib.Path = None, - supress_errors: bool = False) -> int: + suppress_errors: bool = False) -> int: """ add external subdirectory to a cmake :param external_subdir: external subdirectory to add to cmake :param engine_path: optional engine path, defaults to this engine - :param supress_errors: optional silence errors + :param suppress_errors: optional silence errors :return: 0 for success or non 0 failure code """ external_subdir = pathlib.Path(external_subdir).resolve() if not external_subdir.is_dir(): - if not supress_errors: + if not suppress_errors: logger.error(f'Add External Subdirectory Failed: {external_subdir} does not exist.') return 1 external_subdir_cmake = external_subdir / 'CMakeLists.txt' if not external_subdir_cmake.is_file(): - if not supress_errors: + if not suppress_errors: logger.error(f'Add External Subdirectory Failed: {external_subdir} does not contain a CMakeLists.txt.') return 1 json_data = load_o3de_manifest() engine_object = find_engine_data(json_data, engine_path) if not engine_object: - if not supress_errors: + if not suppress_errors: logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') return 1 @@ -3290,7 +3337,7 @@ def add_external_subdirectory(external_subdir: str or pathlib.Path, engine_object['external_subdirectories'].remove(external_subdir.as_posix()) def parse_cmake_file(cmake: str or pathlib.Path, - files: set()): + files: set): cmake_path = pathlib.Path(cmake).resolve() cmake_file = cmake_path if cmake_path.is_dir(): @@ -3335,7 +3382,7 @@ def add_external_subdirectory(external_subdir: str or pathlib.Path, if external_subdir in cmake_files: save_o3de_manifest(json_data) - if not supress_errors: + if not suppress_errors: logger.error(f'External subdirectory {external_subdir.as_posix()} already included by add_subdirectory().') return 1 @@ -3374,18 +3421,18 @@ def add_gem_to_cmake(gem_name: str = None, gem_path: str or pathlib.Path = None, engine_name: str = None, engine_path: str or pathlib.Path = None, - supress_errors: bool = False) -> int: + suppress_errors: bool = False) -> int: """ add a gem to a cmake as an external subdirectory for an engine :param gem_name: name of the gem to add to cmake :param gem_path: the path of the gem to add to cmake :param engine_name: name of the engine to add to cmake :param engine_path: the path of the engine to add external subdirectory to, default to this engine - :param supress_errors: optional silence errors + :param suppress_errors: optional silence errors :return: 0 for success or non 0 failure code """ if not gem_name and not gem_path: - if not supress_errors: + if not suppress_errors: logger.error('Must specify either a Gem name or Gem Path.') return 1 @@ -3393,18 +3440,18 @@ def add_gem_to_cmake(gem_name: str = None, gem_path = get_registered(gem_name=gem_name) if not gem_path: - if not supress_errors: + if not suppress_errors: logger.error(f'Gem Path {gem_path} has not been registered.') return 1 gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' if not gem_json.is_file(): - if not supress_errors: + if not suppress_errors: logger.error(f'Gem json {gem_json} is not present.') return 1 if not valid_o3de_gem_json(gem_json): - if not supress_errors: + if not suppress_errors: logger.error(f'Gem json {gem_json} is not valid.') return 1 @@ -3415,21 +3462,21 @@ def add_gem_to_cmake(gem_name: str = None, engine_path = get_registered(engine_name=engine_name) if not engine_path: - if not supress_errors: + if not suppress_errors: logger.error(f'Engine Path {engine_path} has not been registered.') return 1 engine_json = engine_path / 'engine.json' if not engine_json.is_file(): - if not supress_errors: + if not suppress_errors: logger.error(f'Engine json {engine_json} is not present.') return 1 if not valid_o3de_engine_json(engine_json): - if not supress_errors: + if not suppress_errors: logger.error(f'Engine json {engine_json} is not valid.') return 1 - return add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path, supress_errors=supress_errors) + return add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path, suppress_errors=suppress_errors) def remove_gem_from_cmake(gem_name: str = None, @@ -3930,13 +3977,13 @@ def _run_register(args: argparse) -> int: remove_invalid_o3de_objects() return refresh_repos() elif args.this_engine: - ret_val = register(engine_path=get_this_engine_path()) - error_code = register_shipped_engine_o3de_objects() + ret_val = register(engine_path=get_this_engine_path(), force=args.force) + error_code = register_shipped_engine_o3de_objects(force=args.force) if error_code: ret_val = error_code return ret_val elif args.all_engines_path: - return register_all_engines_in_folder(args.all_engines_path, args.remove) + return register_all_engines_in_folder(args.all_engines_path, args.remove, args.force) elif args.all_projects_path: return register_all_projects_in_folder(args.all_projects_path, args.remove) elif args.all_gems_path: @@ -3959,7 +4006,8 @@ def _run_register(args: argparse) -> int: default_gems_folder=args.default_gems_folder, default_templates_folder=args.default_templates_folder, default_restricted_folder=args.default_restricted_folder, - remove=args.remove) + remove=args.remove, + force=args.force) def _run_add_external_subdirectory(args: argparse) -> int: @@ -4096,6 +4144,8 @@ def add_args(parser, subparsers) -> None: register_subparser.add_argument('-r', '--remove', action='store_true', required=False, default=False, help='Remove entry.') + register_subparser.add_argument('-f', '--force', action='store_true', default=False, + help='For the update of the registration field being modified.') register_subparser.set_defaults(func=_run_register) # show diff --git a/scripts/o3de/test/CMakeLists.txt b/scripts/o3de/test/CMakeLists.txt new file mode 100644 index 0000000000..29410e3523 --- /dev/null +++ b/scripts/o3de/test/CMakeLists.txt @@ -0,0 +1,22 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +if(NOT PAL_TRAIT_BUILD_TESTS_SUPPORTED) + return() +endif() + +# Add a test to test out the o3de package `o3de.py register` command +ly_add_pytest( + NAME o3de_register + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_registration.py + TEST_SUITE smoke + EXCLUDE_TEST_RUN_TARGET_FROM_IDE +) diff --git a/scripts/o3de/test/unit_test_registration.py b/scripts/o3de/test/unit_test_registration.py new file mode 100644 index 0000000000..31a2dcb2f0 --- /dev/null +++ b/scripts/o3de/test/unit_test_registration.py @@ -0,0 +1,66 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +import argparse +import json +import logging +import pytest +import pathlib +from unittest.mock import patch + +from .. import registration + +string_manifest_data = '{}' + +@pytest.mark.parametrize( + "engine_path, engine_name, force, expected_result", [ + pytest.param(pathlib.PurePath('D:/o3de/o3de'), "o3de", False, 0), + # Same engine_name and path should result in valid registration + pytest.param(pathlib.PurePath('D:/o3de/o3de'), "o3de", False, 0), + # Same engine_name and but different path should fail + pytest.param(pathlib.PurePath('D:/o3de/engine-path'), "o3de", False, 1), + # New engine_name should result in valid registration + pytest.param(pathlib.PurePath('D:/o3de/engine-path'), "o3de-other", False, 0), + # Same engine_name and but different path with --force should result in valid registration + pytest.param(pathlib.PurePath('F:/Open3DEngine'), "o3de", True, 0), + ] +) +def test_register_engine_path(engine_path, engine_name, force, expected_result): + parser = argparse.ArgumentParser() + subparser = parser.add_subparsers(help='sub-command help') + + # Register the registration script subparsers with the current argument parser + registration.add_args(parser, subparser) + arg_list = ['register', '--engine-path', str(engine_path)] + if force: + arg_list += ['--force'] + args = parser.parse_args(arg_list) + + def load_manifest_from_string() -> dict: + try: + manifest_json = json.loads(string_manifest_data) + except json.JSONDecodeError as err: + logging.error("Error decoding Json from Manifest file") + else: + return manifest_json + def save_manifest_to_string(manifest_json: dict) -> None: + global string_manifest_data + string_manifest_data = json.dumps(manifest_json) + + engine_json_data = {'engine_name': engine_name} + with patch('o3de.registration.load_o3de_manifest', side_effect=load_manifest_from_string) as load_manifest_mock, \ + patch('o3de.registration.save_o3de_manifest', side_effect=save_manifest_to_string) as save_manifest_mock, \ + patch('o3de.registration.get_engine_data', return_value=engine_json_data) as engine_paths_mock, \ + patch('o3de.registration.valid_o3de_engine_json', return_value=True) as valid_engine_mock, \ + patch('pathlib.Path.is_dir', return_value=True) as pathlib_is_dir_mock: + result = registration._run_register(args) + assert result == expected_result + From 5d42b64ff979d36e2617287ab39712b3d6116fba Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 23:05:55 -0500 Subject: [PATCH 048/140] Moving the o3de test scripts to the tests subfolder of the package --- scripts/o3de/{test => tests}/CMakeLists.txt | 0 scripts/o3de/{test => tests}/__init__.py | 0 scripts/o3de/{test => tests}/unit_test_add_remove_gem.py | 0 scripts/o3de/{test => tests}/unit_test_current_project.py | 0 scripts/o3de/{test => tests}/unit_test_registration.py | 0 scripts/o3de/{test => tests}/unit_test_utils.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename scripts/o3de/{test => tests}/CMakeLists.txt (100%) rename scripts/o3de/{test => tests}/__init__.py (100%) rename scripts/o3de/{test => tests}/unit_test_add_remove_gem.py (100%) rename scripts/o3de/{test => tests}/unit_test_current_project.py (100%) rename scripts/o3de/{test => tests}/unit_test_registration.py (100%) rename scripts/o3de/{test => tests}/unit_test_utils.py (100%) diff --git a/scripts/o3de/test/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt similarity index 100% rename from scripts/o3de/test/CMakeLists.txt rename to scripts/o3de/tests/CMakeLists.txt diff --git a/scripts/o3de/test/__init__.py b/scripts/o3de/tests/__init__.py similarity index 100% rename from scripts/o3de/test/__init__.py rename to scripts/o3de/tests/__init__.py diff --git a/scripts/o3de/test/unit_test_add_remove_gem.py b/scripts/o3de/tests/unit_test_add_remove_gem.py similarity index 100% rename from scripts/o3de/test/unit_test_add_remove_gem.py rename to scripts/o3de/tests/unit_test_add_remove_gem.py diff --git a/scripts/o3de/test/unit_test_current_project.py b/scripts/o3de/tests/unit_test_current_project.py similarity index 100% rename from scripts/o3de/test/unit_test_current_project.py rename to scripts/o3de/tests/unit_test_current_project.py diff --git a/scripts/o3de/test/unit_test_registration.py b/scripts/o3de/tests/unit_test_registration.py similarity index 100% rename from scripts/o3de/test/unit_test_registration.py rename to scripts/o3de/tests/unit_test_registration.py diff --git a/scripts/o3de/test/unit_test_utils.py b/scripts/o3de/tests/unit_test_utils.py similarity index 100% rename from scripts/o3de/test/unit_test_utils.py rename to scripts/o3de/tests/unit_test_utils.py From 6fc1257f7344b57199e3e1e1a69675e2d07ebd5f Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 23:13:25 -0500 Subject: [PATCH 049/140] Moving the o3de python scripts to be underneath another o3de folder to allow `import o3de` to succeed. The path is now scripts/o3de/o3de --- scripts/o3de/{ => o3de}/__init__.py | 0 scripts/o3de/{ => o3de}/engine_template.py | 0 scripts/o3de/{ => o3de}/global_project.py | 0 scripts/o3de/{ => o3de}/registration.py | 0 scripts/o3de/{ => o3de}/utils.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename scripts/o3de/{ => o3de}/__init__.py (100%) rename scripts/o3de/{ => o3de}/engine_template.py (100%) rename scripts/o3de/{ => o3de}/global_project.py (100%) rename scripts/o3de/{ => o3de}/registration.py (100%) rename scripts/o3de/{ => o3de}/utils.py (100%) diff --git a/scripts/o3de/__init__.py b/scripts/o3de/o3de/__init__.py similarity index 100% rename from scripts/o3de/__init__.py rename to scripts/o3de/o3de/__init__.py diff --git a/scripts/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py similarity index 100% rename from scripts/o3de/engine_template.py rename to scripts/o3de/o3de/engine_template.py diff --git a/scripts/o3de/global_project.py b/scripts/o3de/o3de/global_project.py similarity index 100% rename from scripts/o3de/global_project.py rename to scripts/o3de/o3de/global_project.py diff --git a/scripts/o3de/registration.py b/scripts/o3de/o3de/registration.py similarity index 100% rename from scripts/o3de/registration.py rename to scripts/o3de/o3de/registration.py diff --git a/scripts/o3de/utils.py b/scripts/o3de/o3de/utils.py similarity index 100% rename from scripts/o3de/utils.py rename to scripts/o3de/o3de/utils.py From ec7f4c3fdcde2a46f90532494757a835c340455b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 23:15:50 -0500 Subject: [PATCH 050/140] Moving the engine template unit test files into the o3de/tests folder --- scripts/o3de/{test => tests}/unit_test_engine_template.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/o3de/{test => tests}/unit_test_engine_template.py (100%) diff --git a/scripts/o3de/test/unit_test_engine_template.py b/scripts/o3de/tests/unit_test_engine_template.py similarity index 100% rename from scripts/o3de/test/unit_test_engine_template.py rename to scripts/o3de/tests/unit_test_engine_template.py From 703c268e40107de3abac5bf8c4b2fe520f0cc0da Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 18 May 2021 23:48:35 -0500 Subject: [PATCH 051/140] Adding a setup.py and a README to the scripts/o3de folder so it can be linked as a package into the engine python runtime when python is installed via python/get_python.bat --- scripts/o3de/README.txt | 41 ++++++++++++++++++++++++++++++++++++++++ scripts/o3de/setup.py | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 scripts/o3de/README.txt create mode 100644 scripts/o3de/setup.py diff --git a/scripts/o3de/README.txt b/scripts/o3de/README.txt new file mode 100644 index 0000000000..51bbf78cbd --- /dev/null +++ b/scripts/o3de/README.txt @@ -0,0 +1,41 @@ +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + +INTRODUCTION +------------ + +o3de is a package of scripts containing functionality to register engine, projects, gems, +templates and download repositories with the o3de manifests +It also contains functionality for creating new projects, gems and templates as well +as querying existing gems and templates + + +REQUIREMENTS +------------ + + * Python 3.7.10 (64-bit) + +INSTALL +----------- +It is recommended to set up these these tools with O3DE's CMake build commands. +Assuming CMake is already setup on your operating system, below are some sample build commands: + cd /path/to/od3e/ + cmake -B windows_vs2019 -S . -G"Visual Studio 16" -DLY_3RDPARTY_PATH="%LY_3RDPARTY_PATH%" + +To manually install the project in development mode using your own installed Python interpreter: + cd /path/to/od3e/o3de + /path/to/your/python -m pip install -e . + + +UNINSTALLATION +-------------- + +The preferred way to uninstall the project is: + /path/to/your/python -m pip uninstall o3de diff --git a/scripts/o3de/setup.py b/scripts/o3de/setup.py new file mode 100644 index 0000000000..595f477c45 --- /dev/null +++ b/scripts/o3de/setup.py @@ -0,0 +1,42 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" +import os +import platform + +from setuptools import setup, find_packages +from setuptools.command.develop import develop +from setuptools.command.build_py import build_py + +PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__)) + +PYTHON_64 = platform.architecture()[0] == '64bit' + + +if __name__ == '__main__': + if not PYTHON_64: + raise RuntimeError("32-bit Python is not a supported platform.") + + with open(os.path.join(PACKAGE_ROOT, 'README.txt')) as f: + long_description = f.read() + + setup( + name="o3de", + version="1.0.0", + description='O3DE editor Python bindings test tools', + long_description=long_description, + packages=find_packages(where='o3de', exclude=['tests']), + install_requires=[ + ], + tests_require=[ + ], + entry_points={ + }, + ) From c6b0e3562e3f35b2bb0eb21c77e365453da0bdc7 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 19 May 2021 00:52:28 -0500 Subject: [PATCH 052/140] Updating the python import paths for the o3de scripts to use the new package o3de package location --- .../ProjectManager/Source/PythonBindings.cpp | 70 +++++++++---------- scripts/o3de.py | 23 +++--- scripts/o3de/CMakeLists.txt | 2 +- scripts/o3de/o3de/engine_template.py | 9 +-- scripts/o3de/o3de/global_project.py | 6 +- scripts/o3de/o3de/registration.py | 4 +- scripts/project_manager/projects.py | 5 +- 7 files changed, 63 insertions(+), 56 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index cc5348fd22..bc154ea059 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -53,7 +53,7 @@ namespace Platform #define Py_To_String(obj) obj.cast().c_str() #define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string -namespace O3DE::ProjectManager +namespace O3DE::ProjectManager { PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath) : m_enginePath(enginePath) @@ -112,7 +112,7 @@ namespace O3DE::ProjectManager AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed"); // import required modules - m_registration = pybind11::module::import("cmake.Tools.registration"); + m_registration = pybind11::module::import("o3de.registration"); return result == 0 && !PyErr_Occurred(); } catch ([[maybe_unused]] const std::exception& e) @@ -153,22 +153,22 @@ namespace O3DE::ProjectManager } } - AZ::Outcome PythonBindings::GetEngineInfo() + AZ::Outcome PythonBindings::GetEngineInfo() { return AZ::Failure(); } - bool PythonBindings::SetEngineInfo([[maybe_unused]] const EngineInfo& engineInfo) + bool PythonBindings::SetEngineInfo([[maybe_unused]] const EngineInfo& engineInfo) { return false; } - AZ::Outcome PythonBindings::GetGem(const QString& path) + AZ::Outcome PythonBindings::GetGem(const QString& path) { GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString())); if (gemInfo.IsValid()) { - return AZ::Success(AZStd::move(gemInfo)); + return AZ::Success(AZStd::move(gemInfo)); } else { @@ -176,18 +176,18 @@ namespace O3DE::ProjectManager } } - AZ::Outcome> PythonBindings::GetGems() + AZ::Outcome> PythonBindings::GetGems() { QVector gems; bool result = ExecuteWithLock([&] { - // external gems + // external gems for (auto path : m_registration.attr("get_gems")()) { gems.push_back(GemInfoFromPath(path)); } - // gems from the engine + // gems from the engine for (auto path : m_registration.attr("get_engine_gems")()) { gems.push_back(GemInfoFromPath(path)); @@ -200,21 +200,21 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(gems)); + return AZ::Success(AZStd::move(gems)); } } - AZ::Outcome PythonBindings::CreateProject([[maybe_unused]] const ProjectTemplateInfo& projectTemplate,[[maybe_unused]] const ProjectInfo& projectInfo) + AZ::Outcome PythonBindings::CreateProject([[maybe_unused]] const ProjectTemplateInfo& projectTemplate,[[maybe_unused]] const ProjectInfo& projectInfo) { return AZ::Failure(); } - AZ::Outcome PythonBindings::GetProject(const QString& path) + AZ::Outcome PythonBindings::GetProject(const QString& path) { ProjectInfo projectInfo = ProjectInfoFromPath(pybind11::str(path.toStdString())); if (projectInfo.IsValid()) { - return AZ::Success(AZStd::move(projectInfo)); + return AZ::Success(AZStd::move(projectInfo)); } else { @@ -225,7 +225,7 @@ namespace O3DE::ProjectManager GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path) { GemInfo gemInfo; - gemInfo.m_path = Py_To_String(path); + gemInfo.m_path = Py_To_String(path); auto data = m_registration.attr("get_gem_data")(pybind11::none(), path); if (pybind11::isinstance(data)) @@ -233,13 +233,13 @@ namespace O3DE::ProjectManager try { // required - gemInfo.m_name = Py_To_String(data["Name"]); - gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"])); + gemInfo.m_name = Py_To_String(data["Name"]); + gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"])); // optional - gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name); - gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); - gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); + gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name); + gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); + gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); if (data.contains("Dependencies")) { @@ -268,7 +268,7 @@ namespace O3DE::ProjectManager ProjectInfo PythonBindings::ProjectInfoFromPath(pybind11::handle path) { ProjectInfo projectInfo; - projectInfo.m_path = Py_To_String(path); + projectInfo.m_path = Py_To_String(path); auto projectData = m_registration.attr("get_project_data")(pybind11::none(), path); if (pybind11::isinstance(projectData)) @@ -276,9 +276,9 @@ namespace O3DE::ProjectManager try { // required fields - projectInfo.m_productName = Py_To_String(projectData["product_name"]); - projectInfo.m_projectName = Py_To_String(projectData["project_name"]); - projectInfo.m_projectId = AZ::Uuid(Py_To_String(projectData["project_id"])); + projectInfo.m_productName = Py_To_String(projectData["product_name"]); + projectInfo.m_projectName = Py_To_String(projectData["project_name"]); + projectInfo.m_projectId = AZ::Uuid(Py_To_String(projectData["project_id"])); } catch ([[maybe_unused]] const std::exception& e) { @@ -289,18 +289,18 @@ namespace O3DE::ProjectManager return projectInfo; } - AZ::Outcome> PythonBindings::GetProjects() + AZ::Outcome> PythonBindings::GetProjects() { QVector projects; bool result = ExecuteWithLock([&] { - // external projects + // external projects for (auto path : m_registration.attr("get_projects")()) { projects.push_back(ProjectInfoFromPath(path)); } - // projects from the engine + // projects from the engine for (auto path : m_registration.attr("get_engine_projects")()) { projects.push_back(ProjectInfoFromPath(path)); @@ -313,11 +313,11 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(projects)); + return AZ::Success(AZStd::move(projects)); } } - bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) + bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) { return false; } @@ -325,7 +325,7 @@ namespace O3DE::ProjectManager ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path) { ProjectTemplateInfo templateInfo; - templateInfo.m_path = Py_To_String(path); + templateInfo.m_path = Py_To_String(path); auto data = m_registration.attr("get_template_data")(pybind11::none(), path); if (pybind11::isinstance(data)) @@ -333,10 +333,10 @@ namespace O3DE::ProjectManager try { // required - templateInfo.m_displayName = Py_To_String(data["display_name"]); - templateInfo.m_name = Py_To_String(data["template_name"]); - templateInfo.m_summary = Py_To_String(data["summary"]); - + templateInfo.m_displayName = Py_To_String(data["display_name"]); + templateInfo.m_name = Py_To_String(data["template_name"]); + templateInfo.m_summary = Py_To_String(data["summary"]); + // optional if (data.contains("canonical_tags")) { @@ -362,7 +362,7 @@ namespace O3DE::ProjectManager return templateInfo; } - AZ::Outcome> PythonBindings::GetProjectTemplates() + AZ::Outcome> PythonBindings::GetProjectTemplates() { QVector templates; @@ -379,7 +379,7 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(templates)); + return AZ::Success(AZStd::move(templates)); } } } diff --git a/scripts/o3de.py b/scripts/o3de.py index dbb9c53e4b..7bc1c4a9fb 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -10,17 +10,24 @@ # import argparse +import pathlib import sys -import os -# Resolve the common python module -ROOT_DEV_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), '..')) -if ROOT_DEV_PATH not in sys.path: - sys.path.append(ROOT_DEV_PATH) +# As o3de.py shares the same name as the o3de package attempting to use a regular +# from o3de import line tries to import from the current o3de.py script and not the package +# So the current script directory is removed from the sys.path temporary +SCRIPT_DIR_REMOVED = False +SCRIPT_DIR = pathlib.Path(__file__).parent.resolve() +if str(SCRIPT_DIR) in sys.path: + SCRIPT_DIR_REMOVED = True + sys.path.remove(str(SCRIPT_DIR)) -from cmake.Tools import engine_template -from cmake.Tools import global_project -from cmake.Tools import registration +from o3de import engine_template +from o3de import global_project +from o3de import registration + +if SCRIPT_DIR_REMOVED: + sys.path.insert(0, str(SCRIPT_DIR)) def add_args(parser, subparsers) -> None: diff --git a/scripts/o3de/CMakeLists.txt b/scripts/o3de/CMakeLists.txt index 0744845784..9819c1cd6e 100644 --- a/scripts/o3de/CMakeLists.txt +++ b/scripts/o3de/CMakeLists.txt @@ -9,4 +9,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -add_subdirectory(test) +add_subdirectory(tests) diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index eefb8c5541..23acab33d4 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -20,8 +20,8 @@ import json import uuid import re -from cmake.Tools import utils -import cmake.Tools.registration as registration + +from o3de import utils, registration logger = logging.getLogger() logging.basicConfig() @@ -2423,7 +2423,7 @@ if __name__ == "__main__": the_parser = argparse.ArgumentParser() # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') + the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) # add args to the parser add_args(the_parser, the_subparsers) @@ -2432,7 +2432,8 @@ if __name__ == "__main__": the_args = the_parser.parse_args() # run - ret = the_args.func(the_args) + + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 # return sys.exit(ret) diff --git a/scripts/o3de/o3de/global_project.py b/scripts/o3de/o3de/global_project.py index 1d84d9dcfb..da1b5dfa80 100644 --- a/scripts/o3de/o3de/global_project.py +++ b/scripts/o3de/o3de/global_project.py @@ -16,7 +16,7 @@ import sys import re import pathlib import json -import cmake.Tools.registration as registration +from o3de import registration logger = logging.getLogger() logging.basicConfig() @@ -153,7 +153,7 @@ if __name__ == "__main__": the_parser = argparse.ArgumentParser() # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') + the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) # add args to the parser add_args(the_parser, the_subparsers) @@ -162,7 +162,7 @@ if __name__ == "__main__": the_args = the_parser.parse_args() # run - ret = the_args.func(the_args) + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 # return sys.exit(ret) diff --git a/scripts/o3de/o3de/registration.py b/scripts/o3de/o3de/registration.py index eb7224c8ea..a4afecd740 100755 --- a/scripts/o3de/o3de/registration.py +++ b/scripts/o3de/o3de/registration.py @@ -4416,7 +4416,7 @@ if __name__ == "__main__": the_parser = argparse.ArgumentParser() # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') + the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) # add args to the parser add_args(the_parser, the_subparsers) @@ -4425,7 +4425,7 @@ if __name__ == "__main__": the_args = the_parser.parse_args() # run - ret = the_args.func(the_args) + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 # return sys.exit(ret) diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index 51db7a6440..e50c8d8a2d 100755 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -29,12 +29,11 @@ executable_path = '' logger = logging.getLogger() logger.setLevel(logging.INFO) -from cmake.Tools import engine_template -from cmake.Tools import registration +from o3de import engine_template, registration o3de_folder = registration.get_o3de_folder() o3de_logs_folder = registration.get_o3de_logs_folder() -project_manager_log_file_path = o3de_log_folder / "project_manager.log" +project_manager_log_file_path = o3de_logs_folder / "project_manager.log" log_file_handler = RotatingFileHandler(filename=project_manager_log_file_path, maxBytes=1024 * 1024, backupCount=1) formatter = logging.Formatter('%(asctime)s | %(levelname)s : %(message)s') log_file_handler.setFormatter(formatter) From f3d264292654eba10a2693fa195cc4b1d0a6103f Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 19 May 2021 00:54:31 -0500 Subject: [PATCH 053/140] Added an installation of the scripts/o3de folder as a local package for the o3de python that is installed through cmake --- cmake/LYPython.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/LYPython.cmake b/cmake/LYPython.cmake index 546d5f66db..a7c18e4dbe 100644 --- a/cmake/LYPython.cmake +++ b/cmake/LYPython.cmake @@ -270,6 +270,8 @@ if (NOT CMAKE_SCRIPT_MODE_FILE) ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/Tools/RemoteConsole/ly_remote_console ly-remote-console) ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools editor-python-test-tools) endif() + + ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/scripts/o3de o3de) endif() endif() From f972edee010845160615370f66391cbe3c552448 Mon Sep 17 00:00:00 2001 From: phistere Date: Wed, 19 May 2021 10:49:17 -0500 Subject: [PATCH 054/140] Fixes an issue with RUNTIME_DEPENDENCIES including too many targets during install --- CMakeLists.txt | 2 +- cmake/LYWrappers.cmake | 7 +++++++ cmake/Platform/Common/Install_common.cmake | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78667a7161..50670c0b85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ endif() # The following steps have to be done after all targets are registered: # 1. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls # to provide applications with the filenames of gem modules to load -# This must be done before ly_delayed_target_link_libraries() as that inserts BUILD_DEPENDENCIE as MANUALLY_ADDED_DEPENDENCIES +# This must be done before ly_delayed_target_link_libraries() as that inserts BUILD_DEPENDENCIES as MANUALLY_ADDED_DEPENDENCIES # if the build dependency is a MODULE_LIBRARY. That would cause a false load dependency to be generated ly_delayed_generate_settings_registry() # 2. link targets where the dependency was yet not declared, we need to have the declaration so we do different diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index bddd1a6c66..2ad80851b9 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -372,9 +372,16 @@ function(ly_delayed_target_link_libraries) list(APPEND CMAKE_MODULE_PATH ${additional_module_paths}) get_property(delayed_targets GLOBAL PROPERTY LY_DELAYED_LINK_TARGETS) + foreach(target ${delayed_targets}) get_property(delayed_link GLOBAL PROPERTY LY_DELAYED_LINK_${target}) + + # Cache off the original MANUALLY_ADDED_DEPENDENCIES that were associated with the target + # via previous ly_add_dependencies() calls either explicitly or through RUNTIME_DEPENDENCIES + get_target_property(target_orig_manually_added_dependencies ${target} MANUALLY_ADDED_DEPENDENCIES) + set_property(TARGET ${target} PROPERTY LY_ORIGINAL_MANUALLY_ADDED_DEPENDENCIES ${target_orig_manually_added_dependencies}) + if(delayed_link) cmake_parse_arguments(ly_delayed_target_link_libraries "" "" "${visibilities}" ${delayed_link}) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 64fc973701..b501e3db03 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -125,7 +125,7 @@ function(ly_setup_target ALIAS_TARGET_NAME) endforeach() endif() - get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) + get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} LY_ORIGINAL_MANUALLY_ADDED_DEPENDENCIES) if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") else() From 5f82d8e3ebcee713b0921144d0dfc93222e9da30 Mon Sep 17 00:00:00 2001 From: phistere Date: Wed, 19 May 2021 11:49:18 -0500 Subject: [PATCH 055/140] Updates EngineFinder.cmake to correct the key that it's looking for --- .../Template/EngineFinder.cmake | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Templates/DefaultProject/Template/EngineFinder.cmake b/Templates/DefaultProject/Template/EngineFinder.cmake index 5f791f5e3d..7dfddf2c5f 100644 --- a/Templates/DefaultProject/Template/EngineFinder.cmake +++ b/Templates/DefaultProject/Template/EngineFinder.cmake @@ -30,27 +30,27 @@ endif() if(EXISTS ${manifest_path}) file(READ ${manifest_path} manifest_json) - string(JSON engine_paths_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engine_paths) + string(JSON engines_path_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines_path) if(json_error) - message(FATAL_ERROR "Unable to read key 'engine_paths' from '${manifest_path}', error: ${json_error}") + message(FATAL_ERROR "Unable to read key 'engines_path' from '${manifest_path}', error: ${json_error}") endif() - string(JSON engine_paths_type ERROR_VARIABLE json_error TYPE ${manifest_json} engine_paths) - if(json_error OR NOT ${engine_paths_type} STREQUAL "OBJECT") - message(FATAL_ERROR "Type of 'engine_paths' in '${manifest_path}' is not a JSON Object, error: ${json_error}") + string(JSON engines_path_type ERROR_VARIABLE json_error TYPE ${manifest_json} engines_path) + if(json_error OR NOT ${engines_path_type} STREQUAL "OBJECT") + message(FATAL_ERROR "Type of 'engines_path' in '${manifest_path}' is not a JSON Object, error: ${json_error}") endif() - math(EXPR engine_paths_count "${engine_paths_count}-1") - foreach(engine_path_index RANGE ${engine_paths_count}) - string(JSON engine_name ERROR_VARIABLE json_error MEMBER ${manifest_json} engine_paths ${engine_path_index}) + math(EXPR engines_path_count "${engines_path_count}-1") + foreach(engine_path_index RANGE ${engines_path_count}) + string(JSON engine_name ERROR_VARIABLE json_error MEMBER ${manifest_json} engines_path ${engine_path_index}) if(json_error) - message(FATAL_ERROR "Unable to read 'engine_paths/${engine_path_index}' from '${manifest_path}', error: ${json_error}") + message(FATAL_ERROR "Unable to read 'engines_path/${engine_path_index}' from '${manifest_path}', error: ${json_error}") endif() if(LY_ENGINE_NAME_TO_USE STREQUAL engine_name) - string(JSON engine_path ERROR_VARIABLE json_error GET ${manifest_json} engine_paths ${engine_name}) + string(JSON engine_path ERROR_VARIABLE json_error GET ${manifest_json} engines_path ${engine_name}) if(json_error) - message(FATAL_ERROR "Unable to read value from 'engine_paths/${engine_name}', error: ${json_error}") + message(FATAL_ERROR "Unable to read value from 'engines_path/${engine_name}', error: ${json_error}") endif() if(engine_path) From b5b9f7b7e9480ae5157b3a2b196ae8e38a237343 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 19 May 2021 12:14:47 -0500 Subject: [PATCH 056/140] Removing leftover ScriptCanvasDiagnosticLibrary files --- .../Code/Source/precompiled.cpp | 13 ------ .../Code/Source/precompiled.h | 28 ------------ .../ScriptCanvasDiagnosticLibraryTest.cpp | 44 ------------------- 3 files changed, 85 deletions(-) delete mode 100644 Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.cpp delete mode 100644 Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.h delete mode 100644 Gems/ScriptCanvasDiagnosticLibrary/Code/Tests/ScriptCanvasDiagnosticLibraryTest.cpp diff --git a/Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.cpp b/Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.cpp deleted file mode 100644 index 6fdd7bdc45..0000000000 --- a/Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.cpp +++ /dev/null @@ -1,13 +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. -* -*/ - -#include "precompiled.h" diff --git a/Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.h b/Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.h deleted file mode 100644 index 01688d8dc7..0000000000 --- a/Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.h +++ /dev/null @@ -1,28 +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. -* -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#if !defined(SCRIPTCANVASDIAGNOSTICSLIBRARY_EDITOR) - -#include - -#else - -#endif diff --git a/Gems/ScriptCanvasDiagnosticLibrary/Code/Tests/ScriptCanvasDiagnosticLibraryTest.cpp b/Gems/ScriptCanvasDiagnosticLibrary/Code/Tests/ScriptCanvasDiagnosticLibraryTest.cpp deleted file mode 100644 index 4052b9dee4..0000000000 --- a/Gems/ScriptCanvasDiagnosticLibrary/Code/Tests/ScriptCanvasDiagnosticLibraryTest.cpp +++ /dev/null @@ -1,44 +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. -* -*/ -#include "precompiled.h" - -#include - -class ScriptCanvasDiagnosticLibraryTest - : public ::testing::Test -{ -protected: - static void SetUpTestCase() - { - } - - static void TearDownTestCase() - { - } - - void SetUp() override - { - } - - void TearDown() override - { - } - -}; - -TEST_F(ScriptCanvasDiagnosticLibraryTest, Sanity_Pass) -{ - EXPECT_TRUE(true); -} - - -AZ_UNIT_TEST_HOOK(); From 0ba2900fdd2c6021f4f580f026b7fcff459a728a Mon Sep 17 00:00:00 2001 From: phistere Date: Wed, 19 May 2021 12:27:02 -0500 Subject: [PATCH 057/140] Fixes and issue with o3de scripts assuming the wrong directory as the engine directory --- scripts/o3de/o3de/registration.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/o3de/o3de/registration.py b/scripts/o3de/o3de/registration.py index a4afecd740..6a165cbea5 100755 --- a/scripts/o3de/o3de/registration.py +++ b/scripts/o3de/o3de/registration.py @@ -55,7 +55,7 @@ def backup_folder(folder: str or pathlib.Path) -> None: def get_this_engine_path() -> pathlib.Path: - return pathlib.Path(os.path.realpath(__file__)).parents[2].resolve() + return pathlib.Path(os.path.realpath(__file__)).parents[3].resolve() override_home_folder = None @@ -123,9 +123,9 @@ def get_o3de_restricted_folder() -> pathlib.Path: def get_o3de_logs_folder() -> pathlib.Path: - restricted_folder = get_o3de_folder() / 'Logs' - restricted_folder.mkdir(parents=True, exist_ok=True) - return restricted_folder + logs_folder = get_o3de_folder() / 'Logs' + logs_folder.mkdir(parents=True, exist_ok=True) + return logs_folder def register_shipped_engine_o3de_objects(force: bool = False) -> int: From cef7eacd241ce7a654d7b752094c5386e4f38d5d Mon Sep 17 00:00:00 2001 From: phistere Date: Wed, 19 May 2021 13:25:51 -0500 Subject: [PATCH 058/140] Fixes install of scripts to include o3de folder --- cmake/Platform/Common/Install_common.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index b501e3db03..ebe31a4cfa 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -385,6 +385,7 @@ function(ly_setup_others) install(DIRECTORY ${LY_ROOT_FOLDER}/scripts/bundler ${LY_ROOT_FOLDER}/scripts/project_manager + ${LY_ROOT_FOLDER}/scripts/o3de DESTINATION ./scripts COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} PATTERN "__pycache__" EXCLUDE From 4ca30afa9ee19615b2680e9c74b7e62c8f8750b5 Mon Sep 17 00:00:00 2001 From: phistere Date: Wed, 19 May 2021 14:24:31 -0500 Subject: [PATCH 059/140] Updates pip install flags for consistency and installs the o3de module --- cmake/LYPython.cmake | 2 +- python/get_python.bat | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/cmake/LYPython.cmake b/cmake/LYPython.cmake index a7c18e4dbe..238889d829 100644 --- a/cmake/LYPython.cmake +++ b/cmake/LYPython.cmake @@ -81,7 +81,7 @@ function(update_pip_requirements requirements_file_path unique_name) set(ENV{PYTHONNOUSERSITE} 1) execute_process(COMMAND - ${LY_PYTHON_CMD} -m pip install --no-deps -r "${requirements_file_path}" --disable-pip-version-check --no-warn-script-location + ${LY_PYTHON_CMD} -m pip install -r "${requirements_file_path}" --disable-pip-version-check --no-warn-script-location WORKING_DIRECTORY ${Python_BINFOLDER} RESULT_VARIABLE PIP_RESULT OUTPUT_VARIABLE PIP_OUT diff --git a/python/get_python.bat b/python/get_python.bat index e9f18441b5..e11c4ab92f 100644 --- a/python/get_python.bat +++ b/python/get_python.bat @@ -25,7 +25,8 @@ call python.cmd --version > NUL IF !ERRORLEVEL!==0 ( echo get_python.bat: Python is already installed: call python.cmd --version - call "%CMD_DIR%\pip.cmd" install -r "%CMD_DIR%/requirements.txt" --quiet --disable-pip-version-check + call "%CMD_DIR%\pip.cmd" install -r "%CMD_DIR%/requirements.txt" --quiet --disable-pip-version-check --no-warn-script-location + call "%CMD_DIR%\pip.cmd" install -e "%CMD_DIR%/../scripts/o3de" --quiet --disable-pip-version-check --no-warn-script-location --no-deps exit /B 0 ) @@ -65,6 +66,7 @@ if ERRORLEVEL 1 ( ) echo calling PIP to install requirements... -call "%CMD_DIR%\pip.cmd" install -r "%CMD_DIR%/requirements.txt" --disable-pip-version-check +call "%CMD_DIR%\pip.cmd" install -r "%CMD_DIR%/requirements.txt" --disable-pip-version-check --no-warn-script-location +call "%CMD_DIR%\pip.cmd" install -e "%CMD_DIR%/../scripts/o3de" --disable-pip-version-check --no-warn-script-location --no-deps exit /B %ERRORLEVEL% From 7a25a17fae641fef241d3fecf80d6ea6cdd8fb5d Mon Sep 17 00:00:00 2001 From: phistere Date: Thu, 20 May 2021 09:13:01 -0500 Subject: [PATCH 060/140] Fixes a few issues when using an engine name different from the default --- .../Template/EngineFinder.cmake | 5 ++- cmake/install/engine.json.in | 2 +- scripts/o3de/o3de/engine_template.py | 43 +++++++++++++++++-- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Templates/DefaultProject/Template/EngineFinder.cmake b/Templates/DefaultProject/Template/EngineFinder.cmake index 7dfddf2c5f..a7dbf671fd 100644 --- a/Templates/DefaultProject/Template/EngineFinder.cmake +++ b/Templates/DefaultProject/Template/EngineFinder.cmake @@ -20,13 +20,14 @@ if(json_error) message(FATAL_ERROR "Unable to read key 'engine' from 'project.json', error: ${json_error}") endif() -# Read the list of paths from ~.o3de/o3de_manifest.json -if($ENV{USERPROFILE} AND EXISTS $ENV{USERPROFILE}) +if(DEFINED ENV{USERPROFILE} AND EXISTS $ENV{USERPROFILE}) set(manifest_path $ENV{USERPROFILE}/.o3de/o3de_manifest.json) # Windows else() set(manifest_path $ENV{HOME}/.o3de/o3de_manifest.json) # Unix endif() +# Read the ~/.o3de/o3de_manifest.json file and look through the 'engines_path' object. +# Find a key that matches LY_ENGINE_NAME_TO_USE and use that as the engine path. if(EXISTS ${manifest_path}) file(READ ${manifest_path} manifest_json) diff --git a/cmake/install/engine.json.in b/cmake/install/engine.json.in index 04ee6348d3..4a8579d864 100644 --- a/cmake/install/engine.json.in +++ b/cmake/install/engine.json.in @@ -1,6 +1,6 @@ { "engine_name": "@LY_VERSION_ENGINE_NAME@", - "restricted": "@LY_VERSION_ENGINE_NAME@", + "restricted": "o3de", "FileVersion": 1, "O3DEVersion": "@LY_VERSION_STRING@", "O3DECopyrightYear": @LY_VERSION_COPYRIGHT_YEAR@, diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index 23acab33d4..ad7ec55e1f 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -1652,10 +1652,45 @@ def create_project(project_path: str, d.write('# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n') d.write('# {END_LICENSE}\n') - # copy the o3de_manifest.cmake into the project root - engine_path = registration.get_this_engine_path() - o3de_manifest_cmake = f'{engine_path}/cmake/o3de_manifest.cmake' - shutil.copy(o3de_manifest_cmake, project_path) + # set the "engine" element of the project.json + engine_json = f'{registration.get_this_engine_path()}/engine.json' + if not registration.valid_o3de_engine_json(engine_json): + logger.error(f"Engine json {engine_json} is not valid.") + return 1 + + with open(engine_json) as s: + try: + engine_json_data = json.load(s) + except Exception as e: + logger.error(f"Failed to read engine json {engine_json}: {str(e)}") + return 1 + + try: + engine_name = engine_json_data['engine_name'] + except Exception as e: + logger.error(f"Engine json {engine_json} engine_name not found.") + return 1 + + project_json = f"{project_path}/project.json".replace('//', '/') + if not registration.valid_o3de_project_json(project_json): + logger.error(f'Project json {project_json} is not valid.') + return 1 + + with open(project_json, 'r') as s: + try: + project_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to load project json {project_json}.') + return 1 + + project_json_data.update({"engine": engine_name}) + os.unlink(project_json) + with open(project_json, 'w') as s: + try: + s.write(json.dumps(project_json_data, indent=4)) + except Exception as e: + logger.error(f'Failed to write project json {project_json}.') + return 1 return 0 From 0f4e00e48f940eab016cf3f01be27821c0236f1e Mon Sep 17 00:00:00 2001 From: phistere Date: Thu, 20 May 2021 10:38:44 -0500 Subject: [PATCH 061/140] Updating the Gems selctions for the DefaultProject template --- .../Template/Code/runtime_dependencies.cmake | 10 ---------- .../Template/Code/tool_dependencies.cmake | 15 --------------- 2 files changed, 25 deletions(-) diff --git a/Templates/DefaultProject/Template/Code/runtime_dependencies.cmake b/Templates/DefaultProject/Template/Code/runtime_dependencies.cmake index ce8df8152d..f55677a9b6 100644 --- a/Templates/DefaultProject/Template/Code/runtime_dependencies.cmake +++ b/Templates/DefaultProject/Template/Code/runtime_dependencies.cmake @@ -18,19 +18,9 @@ set(GEM_DEPENDENCIES Gem::LyShine Gem::Camera Gem::CameraFramework - Gem::Atom_RHI.Private Gem::EMotionFX - Gem::Atom_RPI.Private - Gem::Atom_Feature_Common Gem::ImGui - Gem::Atom_Bootstrap - Gem::Atom_Component_DebugCamera - Gem::AtomImGuiTools - Gem::AtomLyIntegration_CommonFeatures - Gem::EMotionFX_Atom - Gem::ImguiAtom Gem::Atom_AtomBridge Gem::GradientSignal - Gem::AtomFont Gem::WhiteBox ) diff --git a/Templates/DefaultProject/Template/Code/tool_dependencies.cmake b/Templates/DefaultProject/Template/Code/tool_dependencies.cmake index 010d45bd0f..c6a782c17e 100644 --- a/Templates/DefaultProject/Template/Code/tool_dependencies.cmake +++ b/Templates/DefaultProject/Template/Code/tool_dependencies.cmake @@ -20,24 +20,9 @@ set(GEM_DEPENDENCIES Gem::EditorPythonBindings.Editor Gem::Camera.Editor Gem::CameraFramework - Gem::Atom_RHI.Private Gem::EMotionFX.Editor - Gem::Atom_RPI.Builders - Gem::Atom_RPI.Editor - Gem::Atom_Feature_Common.Builders - Gem::Atom_Feature_Common.Editor Gem::ImGui.Editor - Gem::Atom_Bootstrap - Gem::Atom_Asset_Shader.Builders - Gem::Atom_Component_DebugCamera - Gem::AtomImGuiTools - Gem::AtomLyIntegration_CommonFeatures.Editor - Gem::EMotionFX_Atom.Editor - Gem::ImageProcessingAtom.Editor Gem::Atom_AtomBridge.Editor - Gem::ImguiAtom - Gem::AtomFont - Gem::AtomToolsFramework.Editor Gem::GradientSignal.Editor Gem::WhiteBox.Editor ) From a4243f4be37473003b4f896712185dedc8caa286 Mon Sep 17 00:00:00 2001 From: phistere Date: Thu, 20 May 2021 10:42:06 -0500 Subject: [PATCH 062/140] Temporarily fixes an issue with some Gems where asset paths aren't properly generated for asset processor --- cmake/SettingsRegistry.cmake | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index 31ce36c516..dcfbd8a1f0 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -124,12 +124,13 @@ function(ly_delayed_generate_settings_registry) message(FATAL_ERROR "Dependency ${gem_target} from ${target} does not exist") endif() get_property(gem_relative_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) + if(gem_relative_source_dir) - # Most gems SOURCE dir is nested in the path, we need to find the path to the gem.json or project.json file - while(NOT EXISTS ${gem_relative_source_dir}/gem.json AND NOT EXISTS ${gem_relative_source_dir}/project.json) + # Most gems SOURCE dir is nested in the path, we need to find the path where an 'Assets' or 'Code' folder resides + while(NOT EXISTS ${gem_relative_source_dir}/Assets AND NOT EXISTS ${gem_relative_source_dir}/Code) get_filename_component(parent_dir ${gem_relative_source_dir} DIRECTORY) if (${parent_dir} STREQUAL ${gem_relative_source_dir}) - message(FATAL_ERROR "Did not find gem.json or project.json while processing target ${gem_target}!") + message(FATAL_ERROR "Did not find a Gem source dir while processing target ${gem_target}!") endif() set(gem_relative_source_dir ${parent_dir}) endwhile() From c9d5d7fb779b4354ffd70a3acca9d5f07a0c645f Mon Sep 17 00:00:00 2001 From: Nicholas Lawson <70027408+lawsonamzn@users.noreply.github.com> Date: Tue, 27 Apr 2021 17:09:57 -0700 Subject: [PATCH 063/140] The new gem registration and usage system Merge from mainline (Rebase) --- AutomatedTesting/Gem/Code/CMakeLists.txt | 20 ++ AutomatedTesting/Gem/Code/enabled_gems.cmake | 57 +++++ .../Gem/Code/runtime_dependencies.cmake | 51 ----- .../Gem/Code/tool_dependencies.cmake | 63 ------ CMakeLists.txt | 21 +- Gems/AWSClientAuth/Code/CMakeLists.txt | 4 + Gems/AWSCore/Code/CMakeLists.txt | 9 + Gems/AWSMetrics/Code/CMakeLists.txt | 4 + Gems/Achievements/Code/CMakeLists.txt | 3 + Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt | 5 + Gems/AssetValidation/Code/CMakeLists.txt | 5 + Gems/AudioEngineWwise/Code/CMakeLists.txt | 7 + Gems/AudioSystem/Code/CMakeLists.txt | 25 +-- .../Code/CMakeLists.txt | 4 + Gems/Blast/Code/CMakeLists.txt | 8 + Gems/Camera/Code/CMakeLists.txt | 7 + Gems/CameraFramework/Code/CMakeLists.txt | 6 + Gems/CertificateManager/Code/CMakeLists.txt | 4 + Gems/CrashReporting/Code/CMakeLists.txt | 5 + Gems/CustomAssetExample/Code/CMakeLists.txt | 9 + Gems/DebugDraw/Code/CMakeLists.txt | 8 + Gems/EMotionFX/Code/CMakeLists.txt | 9 + Gems/EditorPythonBindings/Code/CMakeLists.txt | 4 + Gems/ExpressionEvaluation/Code/CMakeLists.txt | 6 + Gems/FastNoise/Code/CMakeLists.txt | 10 + Gems/GameState/Code/CMakeLists.txt | 4 + Gems/GameStateSamples/Code/CMakeLists.txt | 4 + Gems/Gestures/Code/CMakeLists.txt | 6 + Gems/GradientSignal/Code/CMakeLists.txt | 9 + Gems/GraphCanvas/Code/CMakeLists.txt | 6 + Gems/GraphModel/Code/CMakeLists.txt | 5 + Gems/HttpRequestor/Code/CMakeLists.txt | 6 + Gems/ImGui/Code/CMakeLists.txt | 9 + Gems/InAppPurchases/Code/CMakeLists.txt | 5 + Gems/LandscapeCanvas/Code/CMakeLists.txt | 5 + Gems/LmbrCentral/Code/CMakeLists.txt | 9 + Gems/LocalUser/Code/CMakeLists.txt | 3 + Gems/LyShine/Code/CMakeLists.txt | 7 + Gems/LyShineExamples/Code/CMakeLists.txt | 7 + Gems/Maestro/Code/CMakeLists.txt | 8 + Gems/MessagePopup/Code/CMakeLists.txt | 4 + Gems/Metastream/Code/CMakeLists.txt | 5 + Gems/Microphone/Code/CMakeLists.txt | 4 + Gems/Multiplayer/Code/CMakeLists.txt | 53 +++-- .../Code/CMakeLists.txt | 5 + Gems/NvCloth/Code/CMakeLists.txt | 8 + Gems/PhysX/Code/CMakeLists.txt | 8 + Gems/PhysXDebug/Code/CMakeLists.txt | 7 + Gems/Prefab/PrefabBuilder/CMakeLists.txt | 18 +- Gems/Presence/Code/CMakeLists.txt | 3 + Gems/PythonAssetBuilder/Code/CMakeLists.txt | 5 + Gems/QtForPython/Code/CMakeLists.txt | 6 + Gems/RADTelemetry/Code/CMakeLists.txt | 5 + Gems/SaveData/Code/CMakeLists.txt | 3 + Gems/SceneLoggingExample/Code/CMakeLists.txt | 4 + Gems/SceneProcessing/Code/CMakeLists.txt | 4 + Gems/ScriptCanvas/Code/CMakeLists.txt | 18 ++ .../ScriptCanvasDeveloper/Code/CMakeLists.txt | 9 + Gems/ScriptCanvasPhysics/Code/CMakeLists.txt | 6 + Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 3 + Gems/ScriptEvents/Code/CMakeLists.txt | 9 + .../ScriptedEntityTweener/Code/CMakeLists.txt | 6 + Gems/SliceFavorites/Code/CMakeLists.txt | 3 + Gems/StartingPointCamera/Code/CMakeLists.txt | 6 + Gems/StartingPointInput/Code/CMakeLists.txt | 9 + .../StartingPointMovement/Code/CMakeLists.txt | 6 + Gems/SurfaceData/Code/CMakeLists.txt | 7 + Gems/TestAssetBuilder/Code/CMakeLists.txt | 3 + Gems/TextureAtlas/Code/CMakeLists.txt | 6 + Gems/TickBusOrderViewer/Code/CMakeLists.txt | 6 + Gems/Twitch/Code/CMakeLists.txt | 6 + Gems/Vegetation/Code/CMakeLists.txt | 8 + .../Code/CMakeLists.txt | 5 + Gems/VirtualGamepad/Code/CMakeLists.txt | 5 + Gems/WhiteBox/Code/CMakeLists.txt | 10 + cmake/Gems.cmake | 196 ++++++++++++++++++ cmake/LYWrappers.cmake | 17 ++ cmake/SettingsRegistry.cmake | 19 +- 78 files changed, 784 insertions(+), 168 deletions(-) create mode 100644 AutomatedTesting/Gem/Code/enabled_gems.cmake delete mode 100644 AutomatedTesting/Gem/Code/runtime_dependencies.cmake delete mode 100644 AutomatedTesting/Gem/Code/tool_dependencies.cmake create mode 100644 cmake/Gems.cmake diff --git a/AutomatedTesting/Gem/Code/CMakeLists.txt b/AutomatedTesting/Gem/Code/CMakeLists.txt index 2bcc304bde..e81156c3aa 100644 --- a/AutomatedTesting/Gem/Code/CMakeLists.txt +++ b/AutomatedTesting/Gem/Code/CMakeLists.txt @@ -31,6 +31,26 @@ ly_add_target( ################################################################################ # Gem dependencies ################################################################################ + +# The GameLauncher uses "Client" gem variants: +ly_enable_gems(PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake + TARGETS AutomatedTesting.GameLauncher + VARIANTS Clients) + +# The Editor uses Tools gem variants: +ly_enable_gems( + PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake + TARGETS Editor + VARIANTS Tools) + +# The pipeline tools use Builders gem variants: +ly_enable_gems( + PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake + TARGETS AssetBuilder AssetProcessor AssetProcessorBatch + VARIANTS Builders) + +# old system (remove when all gems are ported to the new system above) + ly_add_project_dependencies( PROJECT_NAME AutomatedTesting diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake new file mode 100644 index 0000000000..32fdd11415 --- /dev/null +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -0,0 +1,57 @@ +# +# 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. +# + +set(ENABLED_GEMS + ImGui + ScriptEvents + ExpressionEvaluation + Gestures + CertificateManager + DebugDraw + SceneProcessing + GraphCanvas + InAppPurchases + AutomatedTesting + EditorPythonBindings + PythonAssetBuilder + Metastream + AudioSystem + Camera + EMotionFX + PhysX + CameraFramework + StartingPointMovement + StartingPointCamera + ScriptCanvas + ScriptCanvasPhysics + ScriptCanvasTesting + LyShineExamples + StartingPointInput + PhysXDebug + WhiteBox + FastNoise + SurfaceData + GradientSignal + Vegetation + GraphModel + LandscapeCanvas + NvCloth + Blast + Maestro + TextureAtlas + LmbrCentral + LyShine + HttpRequestor + Atom_AtomBridge + AWSCore + AWSClientAuth + AWSMetrics + ) diff --git a/AutomatedTesting/Gem/Code/runtime_dependencies.cmake b/AutomatedTesting/Gem/Code/runtime_dependencies.cmake deleted file mode 100644 index 33c2bf8d5f..0000000000 --- a/AutomatedTesting/Gem/Code/runtime_dependencies.cmake +++ /dev/null @@ -1,51 +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. -# - -# Extracted from Game -set(GEM_DEPENDENCIES - Gem::Maestro - Gem::TextureAtlas - Gem::LmbrCentral - Gem::LyShine - Gem::HttpRequestor - Gem::ScriptEvents - Gem::ExpressionEvaluation - Gem::Gestures - Gem::CertificateManager - Gem::DebugDraw - Gem::AudioSystem - Gem::InAppPurchases - Gem::AutomatedTesting - Gem::Metastream - Gem::Camera - Gem::EMotionFX - Gem::PhysX - Gem::CameraFramework - Gem::StartingPointMovement - Gem::StartingPointCamera - Gem::ScriptCanvas - Gem::ImGui - Gem::LyShineExamples - Gem::StartingPointInput - Gem::ScriptCanvasPhysics - Gem::PhysXDebug - Gem::WhiteBox - Gem::FastNoise - Gem::SurfaceData - Gem::GradientSignal - Gem::Vegetation - Gem::Atom_AtomBridge - Gem::NvCloth - Gem::Blast - Gem::AWSCore - Gem::AWSClientAuth - Gem::AWSMetrics -) diff --git a/AutomatedTesting/Gem/Code/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/tool_dependencies.cmake deleted file mode 100644 index c8eccab947..0000000000 --- a/AutomatedTesting/Gem/Code/tool_dependencies.cmake +++ /dev/null @@ -1,63 +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. -# - -# Extracted from Editor.xml -set(GEM_DEPENDENCIES - Gem::Maestro.Editor - Gem::TextureAtlas - Gem::LmbrCentral.Editor - Gem::LyShine.Editor - Gem::HttpRequestor - Gem::ScriptEvents.Editor - Gem::ExpressionEvaluation - Gem::Gestures - Gem::CertificateManager - Gem::DebugDraw.Editor - Gem::SceneProcessing.Editor - Gem::GraphCanvas.Editor - Gem::InAppPurchases - Gem::AutomatedTesting - Gem::EditorPythonBindings.Editor - Gem::PythonAssetBuilder.Editor - Gem::Metastream - Gem::AudioSystem.Editor - Gem::Camera.Editor - Gem::EMotionFX.Editor - Gem::PhysX.Editor - Gem::CameraFramework - Gem::StartingPointMovement - Gem::StartingPointCamera - Gem::ScriptCanvas.Editor - Gem::ScriptEvents.Editor - Gem::ImGui.Editor - Gem::LyShineExamples - Gem::StartingPointInput.Editor - Gem::ScriptCanvasPhysics - Gem::ScriptCanvasTesting.Editor - Gem::PhysXDebug.Editor - Gem::WhiteBox.Editor - Gem::FastNoise.Editor - Gem::SurfaceData.Editor - Gem::GradientSignal.Editor - Gem::Vegetation.Editor - Gem::GraphModel.Editor - Gem::LandscapeCanvas.Editor - Gem::EMotionFX.Editor - Gem::ImGui.Editor - Gem::Atom_RHI.Private - Gem::Atom_Feature_Common.Editor - Gem::Atom_AtomBridge.Editor - Gem::NvCloth.Editor - Gem::Blast.Editor - Gem::AWSCore.Editor - Gem::AWSClientAuth - Gem::AWSMetrics -) diff --git a/CMakeLists.txt b/CMakeLists.txt index 63177e9d60..34a54d214d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ include(cmake/Deployment.cmake) include(cmake/3rdParty.cmake) include(cmake/LYPython.cmake) include(cmake/LYWrappers.cmake) +include(cmake/Gems.cmake) include(cmake/UnitTest.cmake) include(cmake/LYTestWrappers.cmake) include(cmake/Monolithic.cmake) @@ -128,24 +129,32 @@ foreach(external_directory ${LY_EXTERNAL_SUBDIRS}) endforeach() # The following steps have to be done after all targets are registered: -# 1. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls +# 1. Add any dependencies registered via ly_enable_gems +ly_enable_gems_delayed() + +# 2. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls # to provide applications with the filenames of gem modules to load # This must be done before ly_delayed_target_link_libraries() as that inserts BUILD_DEPENDENCIES as MANUALLY_ADDED_DEPENDENCIES # if the build dependency is a MODULE_LIBRARY. That would cause a false load dependency to be generated ly_delayed_generate_settings_registry() -# 2. link targets where the dependency was yet not declared, we need to have the declaration so we do different + +# 3. link targets where the dependency was yet not declared, we need to have the declaration so we do different # linking logic depending on the type of target ly_delayed_target_link_libraries() -# 3. generate a registry file for unit testing for platforms that support unit testing + +# 4. generate a registry file for unit testing for platforms that support unit testing if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_delayed_generate_unit_test_module_registry() endif() -# 4. inject runtime dependencies to the targets. We need to do this after (1) since we are going to walk through + +# 5. inject runtime dependencies to the targets. We need to do this after (1) since we are going to walk through # the dependencies include(cmake/RuntimeDependencies.cmake) -# 5. Perform test impact framework post steps once all of the targets have been enumerated + +# 6. Perform test impact framework post steps once all of the targets have been enumerated ly_test_impact_post_step() -# 6. Generate the O3DE find file and setup install locations for scripts, tools, assets etc., required by the engine + +# 7. Generate the O3DE find file and setup install locations for scripts, tools, assets etc., required by the engine if(NOT INSTALLED_ENGINE) ly_setup_o3de_install() diff --git a/Gems/AWSClientAuth/Code/CMakeLists.txt b/Gems/AWSClientAuth/Code/CMakeLists.txt index e9f2a4ed84..a1f6f0ca59 100644 --- a/Gems/AWSClientAuth/Code/CMakeLists.txt +++ b/Gems/AWSClientAuth/Code/CMakeLists.txt @@ -51,6 +51,10 @@ ly_add_target( Gem::AWSClientAuth.Static ) +# servers and clients use the above module. +ly_create_alias(NAME AWSClientAuth.Servers NAMESPACE Gem TARGETS Gem::AWSClientAuth) +ly_create_alias(NAME AWSClientAuth.Clients NAMESPACE Gem TARGETS Gem::AWSClientAuth) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/AWSCore/Code/CMakeLists.txt b/Gems/AWSCore/Code/CMakeLists.txt index a58b02d1d4..46046c0791 100644 --- a/Gems/AWSCore/Code/CMakeLists.txt +++ b/Gems/AWSCore/Code/CMakeLists.txt @@ -45,6 +45,10 @@ ly_add_target( Gem::AWSCore.Static ) +# clients and servers will use the above Gem::AWSCore module. +ly_create_alias(NAME AWSCore.Servers NAMESPACE Gem TARGETS Gem::AWSCore) +ly_create_alias(NAME AWSCore.Clients NAMESPACE Gem TARGETS Gem::AWSCore) + if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME AWSCore.Editor.Static STATIC @@ -99,6 +103,11 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AWSCore.Editor.Static ) ly_add_dependencies(AWSCore.Editor AWSCore.ResourceMappingTool) + + # Builders and Tools (such as the Editor use AWSCore.Editor) use the .Editor module above. + ly_create_alias(NAME AWSCore.Tools NAMESPACE Gem TARGETS Gem::AWSCore.Editor) + ly_create_alias(NAME AWSCore.Builders NAMESPACE Gem TARGETS Gem::AWSCore.Editor) + endif() ################################################################################ diff --git a/Gems/AWSMetrics/Code/CMakeLists.txt b/Gems/AWSMetrics/Code/CMakeLists.txt index ffa9ac0408..413baf28ed 100644 --- a/Gems/AWSMetrics/Code/CMakeLists.txt +++ b/Gems/AWSMetrics/Code/CMakeLists.txt @@ -44,6 +44,10 @@ ly_add_target( Gem::AWSMetrics.Static ) +# Servers and Clients use the above metrics module +ly_create_alias(NAME AWSMetrics.Servers NAMESPACE Gem TARGETS Gem::AWSMetrics) +ly_create_alias(NAME AWSMetrics.Clients NAMESPACE Gem TARGETS Gem::AWSMetrics) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/Achievements/Code/CMakeLists.txt b/Gems/Achievements/Code/CMakeLists.txt index b49409bd5e..4b2aa07dab 100644 --- a/Gems/Achievements/Code/CMakeLists.txt +++ b/Gems/Achievements/Code/CMakeLists.txt @@ -44,3 +44,6 @@ ly_add_target( PRIVATE Gem::Achievements.Static ) + +# we'll load the above "Gem::Achievements" module in clients only. +ly_create_alias(NAME Achievements.Clients NAMESPACE Gem TARGETS Gem::Achievements) diff --git a/Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt b/Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt index df97feaa3f..bdf76eca60 100644 --- a/Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt +++ b/Gems/AssetMemoryAnalyzer/Code/CMakeLists.txt @@ -43,6 +43,10 @@ ly_add_target( Gem::ImGui ) +# AssetMemoryAnalyzer is available in clients and servers. +ly_create_alias(NAME AssetMemoryAnalyzer.Clients NAMESPACE Gem TARGETS Gem::AssetMemoryAnalyzer) +ly_create_alias(NAME AssetMemoryAnalyzer.Servers NAMESPACE Gem TARGETS Gem::AssetMemoryAnalyzer) + ################################################################################ # Tests ################################################################################ @@ -65,3 +69,4 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) NAME Gem::AssetMemoryAnalyzer.Tests ) endif() + diff --git a/Gems/AssetValidation/Code/CMakeLists.txt b/Gems/AssetValidation/Code/CMakeLists.txt index 983ddd9e9d..f62baf57f5 100644 --- a/Gems/AssetValidation/Code/CMakeLists.txt +++ b/Gems/AssetValidation/Code/CMakeLists.txt @@ -65,3 +65,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) NAME Gem::AssetValidation.Tests ) endif() + +# AssetValidation should be active in all clients plus tools +ly_create_alias(NAME AssetValidation.Clients NAMESPACE Gem TARGETS Gem::AssetValidation) +ly_create_alias(NAME AssetValidation.Tools NAMESPACE Gem TARGETS Gem::AssetValidation) + diff --git a/Gems/AudioEngineWwise/Code/CMakeLists.txt b/Gems/AudioEngineWwise/Code/CMakeLists.txt index 5ea6a6d461..41b8c8298e 100644 --- a/Gems/AudioEngineWwise/Code/CMakeLists.txt +++ b/Gems/AudioEngineWwise/Code/CMakeLists.txt @@ -93,6 +93,9 @@ ly_add_target( Gem::AudioEngineWwise.Static ) +# we'll load the above "Gem::AudioEngineWwise" module in clients. +ly_create_alias(NAME AudioEngineWwise.Clients NAMESPACE Gem TARGETS Gem::AudioEngineWwise) + ################################################################################ # Tests ################################################################################ @@ -230,6 +233,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AudioSystem.Editor ) + # by default, we'll load the above "Gem::AudioEngineWwise.Editor" module in builders and tools. + ly_create_alias(NAME AudioEngineWwise.Builders NAMESPACE Gem TARGETS Gem::AudioEngineWwise.Editor) + ly_create_alias(NAME AudioEngineWwise.Tools NAMESPACE Gem TARGETS Gem::AudioEngineWwise.Editor) + if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_target( NAME AudioEngineWwise.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} diff --git a/Gems/AudioSystem/Code/CMakeLists.txt b/Gems/AudioSystem/Code/CMakeLists.txt index 8a6f2c417e..dfb80a15d5 100644 --- a/Gems/AudioSystem/Code/CMakeLists.txt +++ b/Gems/AudioSystem/Code/CMakeLists.txt @@ -61,22 +61,8 @@ ly_add_target( Gem::AudioSystem.Static ) -################################################################################ -# Server -################################################################################ -if (PAL_TRAIT_BUILD_SERVER_SUPPORTED) - # Stub gem for server. Audio system is client only - ly_add_target( - NAME AudioSystem.Server GEM_MODULE - - NAMESPACE Gem - FILES_CMAKE - audiosystem_stub_files.cmake - BUILD_DEPENDENCIES - PRIVATE - AZ::AzCore - ) -endif () +# AudioSystem should use the above target on clients. +ly_create_alias(NAME AudioSystem.Clients NAMESPACE Gem TARGETS Gem::AudioSystem) ################################################################################ # Tests @@ -230,6 +216,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AudioSystem.Editor.Static ) + # use the above "Editor" target in tools and builders: + ly_create_alias(NAME AssetMemoryAnalyzer.Tools NAMESPACE Gem TARGETS Gem::AudioSystem.Editor) + ly_create_alias(NAME AssetMemoryAnalyzer.Builders NAMESPACE Gem TARGETS Gem::AudioSystem.Editor) + if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_target( NAME AudioSystem.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} @@ -253,3 +243,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) endif() endif () + + + diff --git a/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt b/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt index 551f76da02..6215ae7697 100644 --- a/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt +++ b/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt @@ -42,3 +42,7 @@ ly_add_target( RUNTIME_DEPENDENCIES Gem::LmbrCentral ) + +# servers and clients use the above module. +ly_create_alias(NAME AutomatedLauncherTesting.Servers NAMESPACE Gem TARGETS Gem::AutomatedLauncherTesting) +ly_create_alias(NAME AutomatedLauncherTesting.Clients NAMESPACE Gem TARGETS Gem::AutomatedLauncherTesting) diff --git a/Gems/Blast/Code/CMakeLists.txt b/Gems/Blast/Code/CMakeLists.txt index 6c90357364..143e3af095 100644 --- a/Gems/Blast/Code/CMakeLists.txt +++ b/Gems/Blast/Code/CMakeLists.txt @@ -59,6 +59,11 @@ ly_add_target( Gem::PhysX ) +# clients and servers use the above Gem module. +ly_create_alias(NAME Blast.Servers NAMESPACE Gem TARGETS Gem::Blast) +ly_create_alias(NAME Blast.Clients NAMESPACE Gem TARGETS Gem::Blast) + + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( @@ -110,6 +115,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::PhysX.Editor ) + # tools and builders use the above module. + ly_create_alias(NAME Blast.Tools NAMESPACE Gem TARGETS Gem::Blast.Editor) + ly_create_alias(NAME Blast.Builders NAMESPACE Gem TARGETS Gem::Blast.Editor) endif() ################################################################################ diff --git a/Gems/Camera/Code/CMakeLists.txt b/Gems/Camera/Code/CMakeLists.txt index 950ff451ff..703424416b 100644 --- a/Gems/Camera/Code/CMakeLists.txt +++ b/Gems/Camera/Code/CMakeLists.txt @@ -39,6 +39,10 @@ ly_add_target( Gem::Camera.Static ) +# clients and servers use the above module: +ly_create_alias(NAME Camera.Clients NAMESPACE Gem TARGETS Gem::Camera) +ly_create_alias(NAME Camera.Servers NAMESPACE Gem TARGETS Gem::Camera) + if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( @@ -62,4 +66,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Camera.Static ) + # tools and builders use the above module. + ly_create_alias(NAME Camera.Tools NAMESPACE Gem TARGETS Gem::Camera.Editor) + ly_create_alias(NAME Camera.Builders NAMESPACE Gem TARGETS Gem::Camera.Editor) endif() diff --git a/Gems/CameraFramework/Code/CMakeLists.txt b/Gems/CameraFramework/Code/CMakeLists.txt index 1ec9dc0ad9..6b0d084e28 100644 --- a/Gems/CameraFramework/Code/CMakeLists.txt +++ b/Gems/CameraFramework/Code/CMakeLists.txt @@ -38,3 +38,9 @@ ly_add_target( PRIVATE Gem::CameraFramework.Static ) + +# Every kind of application uses the above target module. +ly_create_alias(NAME CameraFramework.Clients NAMESPACE Gem TARGETS Gem::CameraFramework) +ly_create_alias(NAME CameraFramework.Servers NAMESPACE Gem TARGETS Gem::CameraFramework) +ly_create_alias(NAME CameraFramework.Tools NAMESPACE Gem TARGETS Gem::CameraFramework) +ly_create_alias(NAME CameraFramework.Builders NAMESPACE Gem TARGETS Gem::CameraFramework) diff --git a/Gems/CertificateManager/Code/CMakeLists.txt b/Gems/CertificateManager/Code/CMakeLists.txt index 93e78bb86a..2307ebed40 100644 --- a/Gems/CertificateManager/Code/CMakeLists.txt +++ b/Gems/CertificateManager/Code/CMakeLists.txt @@ -41,3 +41,7 @@ ly_add_target( PRIVATE Gem::CertificateManager.Static ) + +# we'll load the above "Gem::CertificateManager" module in Clients and Servers +ly_create_alias(NAME CertificateManager.Clients NAMESPACE Gem TARGETS Gem::CertificateManager) +ly_create_alias(NAME CertificateManager.Servers NAMESPACE Gem TARGETS Gem::CertificateManager) diff --git a/Gems/CrashReporting/Code/CMakeLists.txt b/Gems/CrashReporting/Code/CMakeLists.txt index d52600ea9b..2d77d563d9 100644 --- a/Gems/CrashReporting/Code/CMakeLists.txt +++ b/Gems/CrashReporting/Code/CMakeLists.txt @@ -33,6 +33,11 @@ ly_add_target( AZ::CrashHandler ) +# Load the "Gem::CrashReporting" module in Clients and Servers +ly_create_alias(NAME CrashReporting.Clients NAMESPACE Gem TARGETS Gem::CrashReporting) +ly_create_alias(NAME CrashReporting.Servers NAMESPACE Gem TARGETS Gem::CrashReporting) + + ly_add_target( NAME CrashReporting.Uploader APPLICATION NAMESPACE AZ diff --git a/Gems/CustomAssetExample/Code/CMakeLists.txt b/Gems/CustomAssetExample/Code/CMakeLists.txt index 661b1950ce..3debe27919 100644 --- a/Gems/CustomAssetExample/Code/CMakeLists.txt +++ b/Gems/CustomAssetExample/Code/CMakeLists.txt @@ -22,6 +22,10 @@ ly_add_target( AZ::AzCore ) +# clients and servers use the above module. +ly_create_alias(NAME CustomAssetExample.Clients NAMESPACE Gem TARGETS CustomAssetExample) +ly_create_alias(NAME CustomAssetExample.Servers NAMESPACE Gem TARGETS CustomAssetExample) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME CustomAssetExample.Editor GEM_MODULE @@ -37,4 +41,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzCore AZ::AssetBuilderSDK ) + + # other tools use the above tools module: + ly_create_alias(NAME CustomAssetExample.Builders NAMESPACE Gem TARGETS CustomAssetExample.Editor) + ly_create_alias(NAME CustomAssetExample.Tools NAMESPACE Gem TARGETS CustomAssetExample.Editor) + endif() diff --git a/Gems/DebugDraw/Code/CMakeLists.txt b/Gems/DebugDraw/Code/CMakeLists.txt index 5759cdaff2..44a1c15d7d 100644 --- a/Gems/DebugDraw/Code/CMakeLists.txt +++ b/Gems/DebugDraw/Code/CMakeLists.txt @@ -39,6 +39,9 @@ ly_add_target( Gem::DebugDraw.Static ) +# servers do not need debug draw components, only clients +ly_create_alias(NAME DebugDraw.Clients NAMESPACE Gem TARGETS DebugDraw) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME DebugDraw.Editor GEM_MODULE @@ -56,4 +59,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::DebugDraw.Static AZ::AzToolsFramework ) + + # builders and tools use DebugDraw.Editor + ly_create_alias(NAME DebugDraw.Builders NAMESPACE Gem TARGETS DebugDraw.Editor) + ly_create_alias(NAME DebugDraw.Tools NAMESPACE Gem TARGETS DebugDraw.Editor) + endif() diff --git a/Gems/EMotionFX/Code/CMakeLists.txt b/Gems/EMotionFX/Code/CMakeLists.txt index b90902a948..1bfc45babc 100644 --- a/Gems/EMotionFX/Code/CMakeLists.txt +++ b/Gems/EMotionFX/Code/CMakeLists.txt @@ -67,6 +67,10 @@ ly_add_target( Gem::LmbrCentral ) +# Clients and servers use the above EMotionFX module +ly_create_alias(NAME EMotionFX.Clients NAMESPACE Gem TARGETS EMotionFX) +ly_create_alias(NAME EMotionFX.Servers NAMESPACE Gem TARGETS EMotionFX) + if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( @@ -129,6 +133,11 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) + + # builders and tools use the above EMotionFX.Editor module + ly_create_alias(NAME EMotionFX.Builders NAMESPACE Gem TARGETS EMotionFX.Editor) + ly_create_alias(NAME EMotionFX.Tools NAMESPACE Gem TARGETS EMotionFX.Editor) + endif() ################################################################################ diff --git a/Gems/EditorPythonBindings/Code/CMakeLists.txt b/Gems/EditorPythonBindings/Code/CMakeLists.txt index 3a34a8491d..a8d4382b45 100644 --- a/Gems/EditorPythonBindings/Code/CMakeLists.txt +++ b/Gems/EditorPythonBindings/Code/CMakeLists.txt @@ -64,6 +64,10 @@ ly_add_target( Gem::EditorPythonBindings.Static ) +# builders and tools use EditorPythonBindings.Editor +ly_create_alias(NAME EditorPythonBindings.Builders NAMESPACE Gem TARGETS EditorPythonBindings.Editor) +ly_create_alias(NAME EditorPythonBindings.Tools NAMESPACE Gem TARGETS EditorPythonBindings.Editor) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/ExpressionEvaluation/Code/CMakeLists.txt b/Gems/ExpressionEvaluation/Code/CMakeLists.txt index 563e3f3341..456129f05d 100644 --- a/Gems/ExpressionEvaluation/Code/CMakeLists.txt +++ b/Gems/ExpressionEvaluation/Code/CMakeLists.txt @@ -41,6 +41,12 @@ ly_add_target( Gem::ExpressionEvaluation.Static ) +# all types of applications use the above module +ly_create_alias(NAME ExpressionEvaluation.Clients NAMESPACE Gem TARGETS ExpressionEvaluation) +ly_create_alias(NAME ExpressionEvaluation.Servers NAMESPACE Gem TARGETS ExpressionEvaluation) +ly_create_alias(NAME ExpressionEvaluation.Builders NAMESPACE Gem TARGETS ExpressionEvaluation) +ly_create_alias(NAME ExpressionEvaluation.Tools NAMESPACE Gem TARGETS ExpressionEvaluation) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/FastNoise/Code/CMakeLists.txt b/Gems/FastNoise/Code/CMakeLists.txt index a49126303a..ac1343844d 100644 --- a/Gems/FastNoise/Code/CMakeLists.txt +++ b/Gems/FastNoise/Code/CMakeLists.txt @@ -42,6 +42,10 @@ ly_add_target( Gem::GradientSignal ) +# Clients and Servers use the above module +ly_create_alias(NAME FastNoise.Clients NAMESPACE Gem TARGETS FastNoise) +ly_create_alias(NAME FastNoise.Servers NAMESPACE Gem TARGETS FastNoise) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME FastNoise.Editor.Static STATIC @@ -81,6 +85,12 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::LmbrCentral.Editor Gem::SurfaceData.Editor ) + + # builders and tools load the above tool module. + ly_create_alias(NAME FastNoise.Builders NAMESPACE Gem TARGETS FastNoise.Editor) + ly_create_alias(NAME FastNoise.Tools NAMESPACE Gem TARGETS FastNoise.Editor) + + endif() ################################################################################ diff --git a/Gems/GameState/Code/CMakeLists.txt b/Gems/GameState/Code/CMakeLists.txt index d57cf8feed..828dfcbb35 100644 --- a/Gems/GameState/Code/CMakeLists.txt +++ b/Gems/GameState/Code/CMakeLists.txt @@ -40,6 +40,10 @@ ly_add_target( Gem::GameState.Static ) +# Clients and Servers use the above module. There is no editor or tools module required. +ly_create_alias(NAME GameState.Clients NAMESPACE Gem TARGETS GameState) +ly_create_alias(NAME GameState.Servers NAMESPACE Gem TARGETS GameState) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/GameStateSamples/Code/CMakeLists.txt b/Gems/GameStateSamples/Code/CMakeLists.txt index e3ebc25016..2199a6689b 100644 --- a/Gems/GameStateSamples/Code/CMakeLists.txt +++ b/Gems/GameStateSamples/Code/CMakeLists.txt @@ -45,3 +45,7 @@ ly_add_target( Gem::LmbrCentral Gem::GameStateSamples.Headers ) + +# Clients and Servers use the above module. There is no editor or tools module required. +ly_create_alias(NAME GameStateSamples.Clients NAMESPACE Gem TARGETS GameStateSamples) +ly_create_alias(NAME GameStateSamples.Servers NAMESPACE Gem TARGETS GameStateSamples) diff --git a/Gems/Gestures/Code/CMakeLists.txt b/Gems/Gestures/Code/CMakeLists.txt index 677886c0ed..8c4ec5ad55 100644 --- a/Gems/Gestures/Code/CMakeLists.txt +++ b/Gems/Gestures/Code/CMakeLists.txt @@ -43,6 +43,12 @@ ly_add_target( Gem::Gestures.Static ) +# All types of applications use the same module. +ly_create_alias(NAME Gestures.Clients NAMESPACE Gem TARGETS Gestures) +ly_create_alias(NAME Gestures.Servers NAMESPACE Gem TARGETS Gestures) +ly_create_alias(NAME Gestures.Builders NAMESPACE Gem TARGETS Gestures) +ly_create_alias(NAME Gestures.Tools NAMESPACE Gem TARGETS Gestures) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/GradientSignal/Code/CMakeLists.txt b/Gems/GradientSignal/Code/CMakeLists.txt index 7b8c9813e6..ed56797c7e 100644 --- a/Gems/GradientSignal/Code/CMakeLists.txt +++ b/Gems/GradientSignal/Code/CMakeLists.txt @@ -47,6 +47,10 @@ ly_add_target( Gem::SurfaceData ) +# Load the "Gem::GradientSignal" module in Clients and Servers +ly_create_alias(NAME GradientSignal.Clients NAMESPACE Gem TARGETS Gem::GradientSignal) +ly_create_alias(NAME GradientSignal.Servers NAMESPACE Gem TARGETS Gem::GradientSignal) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( @@ -92,6 +96,11 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::SurfaceData.Editor ) + # Load the "Gem::GradientSignal.Editor" module in Builders and Tools + ly_create_alias(NAME GradientSignal.Builders NAMESPACE Gem TARGETS Gem::GradientSignal.Editor) + ly_create_alias(NAME GradientSignal.Tools NAMESPACE Gem TARGETS Gem::GradientSignal.Editor) + + endif() ################################################################################ diff --git a/Gems/GraphCanvas/Code/CMakeLists.txt b/Gems/GraphCanvas/Code/CMakeLists.txt index 683b0e4bdf..537588957e 100644 --- a/Gems/GraphCanvas/Code/CMakeLists.txt +++ b/Gems/GraphCanvas/Code/CMakeLists.txt @@ -75,4 +75,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) 3rdParty::Qt::Xml AZ::AzQtComponents ) + + # Load the "Gem::GraphCanvas" module in Builders and Tools + ly_create_alias(NAME GraphCanvas.Builders NAMESPACE Gem TARGETS Gem::GraphCanvas.Editor) + ly_create_alias(NAME GraphCanvas.Tools NAMESPACE Gem TARGETS Gem::GraphCanvas.Editor) + + endif () diff --git a/Gems/GraphModel/Code/CMakeLists.txt b/Gems/GraphModel/Code/CMakeLists.txt index 2c4fc57252..86141140ee 100644 --- a/Gems/GraphModel/Code/CMakeLists.txt +++ b/Gems/GraphModel/Code/CMakeLists.txt @@ -52,6 +52,11 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES Gem::GraphCanvas.Editor ) + + # Load the "Gem::GraphModel" module in Builders and Tools + ly_create_alias(NAME GraphModel.Builders NAMESPACE Gem TARGETS Gem::GraphModel.Editor) + ly_create_alias(NAME GraphModel.Tools NAMESPACE Gem TARGETS Gem::GraphModel.Editor) + endif() ################################################################################ diff --git a/Gems/HttpRequestor/Code/CMakeLists.txt b/Gems/HttpRequestor/Code/CMakeLists.txt index 71181f9ff4..bfbc4305b0 100644 --- a/Gems/HttpRequestor/Code/CMakeLists.txt +++ b/Gems/HttpRequestor/Code/CMakeLists.txt @@ -48,6 +48,12 @@ ly_add_target( Gem::HttpRequestor.Static ) +# Load the "Gem::HttpRequestor" module in all types of applicatons. +ly_create_alias(NAME HttpRequestor.Clients NAMESPACE Gem TARGETS Gem::HttpRequestor) +ly_create_alias(NAME HttpRequestor.Servers NAMESPACE Gem TARGETS Gem::HttpRequestor) +ly_create_alias(NAME HttpRequestor.Builders NAMESPACE Gem TARGETS Gem::HttpRequestor) +ly_create_alias(NAME HttpRequestor.Tools NAMESPACE Gem TARGETS Gem::HttpRequestor) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/ImGui/Code/CMakeLists.txt b/Gems/ImGui/Code/CMakeLists.txt index 2f7d6c6ce7..c3a324b61c 100644 --- a/Gems/ImGui/Code/CMakeLists.txt +++ b/Gems/ImGui/Code/CMakeLists.txt @@ -90,6 +90,10 @@ ly_add_target( Gem::LmbrCentral ) +# Load the above "Gem::ImGui" module in Clients and Servers: +ly_create_alias(NAME ImGui.Clients NAMESPACE Gem TARGETS Gem::ImGui) +ly_create_alias(NAME ImGui.Servers NAMESPACE Gem TARGETS Gem::ImGui) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME ImGui.Editor GEM_MODULE @@ -113,4 +117,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) + + # Load the above "Gem::ImGui.Editor" module in only tools and builders. + ly_create_alias(NAME ImGui.Builders NAMESPACE Gem TARGETS Gem::ImGui.Editor) + ly_create_alias(NAME ImGui.Tools NAMESPACE Gem TARGETS Gem::ImGui.Editor) + endif() diff --git a/Gems/InAppPurchases/Code/CMakeLists.txt b/Gems/InAppPurchases/Code/CMakeLists.txt index 61f9839841..889b651838 100644 --- a/Gems/InAppPurchases/Code/CMakeLists.txt +++ b/Gems/InAppPurchases/Code/CMakeLists.txt @@ -43,3 +43,8 @@ ly_add_target( PRIVATE Gem::InAppPurchases.Static ) +# Load the above "Gem::InAppPurchases" module in all app types +ly_create_alias(NAME InAppPurchases.Clients NAMESPACE Gem TARGETS Gem::InAppPurchases) +ly_create_alias(NAME InAppPurchases.Servers NAMESPACE Gem TARGETS Gem::InAppPurchases) +ly_create_alias(NAME InAppPurchases.Builders NAMESPACE Gem TARGETS Gem::InAppPurchases) +ly_create_alias(NAME InAppPurchases.Tools NAMESPACE Gem TARGETS Gem::InAppPurchases) diff --git a/Gems/LandscapeCanvas/Code/CMakeLists.txt b/Gems/LandscapeCanvas/Code/CMakeLists.txt index e8e2fce689..f74445b89e 100644 --- a/Gems/LandscapeCanvas/Code/CMakeLists.txt +++ b/Gems/LandscapeCanvas/Code/CMakeLists.txt @@ -72,6 +72,11 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::SurfaceData.Editor Gem::Vegetation.Editor ) + + # by default, load the above "Gem::LandscapeCanvas.Editor" module in dev applications + ly_create_alias(NAME LandscapeCanvas.Builders NAMESPACE Gem TARGETS Gem::LandscapeCanvas.Editor) + ly_create_alias(NAME LandscapeCanvas.Tools NAMESPACE Gem TARGETS Gem::LandscapeCanvas.Editor) + endif() ################################################################################ diff --git a/Gems/LmbrCentral/Code/CMakeLists.txt b/Gems/LmbrCentral/Code/CMakeLists.txt index c1fbd744e6..4d03d30923 100644 --- a/Gems/LmbrCentral/Code/CMakeLists.txt +++ b/Gems/LmbrCentral/Code/CMakeLists.txt @@ -48,6 +48,11 @@ ly_add_target( Gem::LmbrCentral.Static ) +# by default, load the above "Gem::LmbrCentral" module in Client and Server +ly_create_alias(NAME LmbrCentral.Clients NAMESPACE Gem TARGETS Gem::LmbrCentral) +ly_create_alias(NAME LmbrCentral.Servers NAMESPACE Gem TARGETS Gem::LmbrCentral) + + if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME LmbrCentral.Editor.Static STATIC @@ -102,6 +107,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) FILES ${QT_LRELEASE_EXECUTABLE} ) + # by default, load the above "Gem::LmbrCentral.Editor" module in dev tools + ly_create_alias(NAME LmbrCentral.Builders NAMESPACE Gem TARGETS Gem::LmbrCentral.Editor) + ly_create_alias(NAME LmbrCentral.Tools NAMESPACE Gem TARGETS Gem::LmbrCentral.Editor) + endif() ################################################################################ diff --git a/Gems/LocalUser/Code/CMakeLists.txt b/Gems/LocalUser/Code/CMakeLists.txt index 6198d88e15..3f2b513282 100644 --- a/Gems/LocalUser/Code/CMakeLists.txt +++ b/Gems/LocalUser/Code/CMakeLists.txt @@ -43,6 +43,9 @@ ly_add_target( Gem::LocalUser.Static ) +# by default, load the above "Gem::LocalUser" module in client applications +ly_create_alias(NAME LocalUser.Clients NAMESPACE Gem TARGETS Gem::LocalUser) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index 732bd1cfd4..9baad008dd 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -56,6 +56,9 @@ ly_add_target( Gem::TextureAtlas ) +# by default, load the above "Gem::LyShine" module in Client applications: +ly_create_alias(NAME LyShine.Clients NAMESPACE Gem TARGETS Gem::LyShine) + if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME LyShine.Editor.Static STATIC @@ -123,6 +126,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::LmbrCentral.Editor Gem::TextureAtlas ) + + # by default, load the above "Gem::LyShine.Editor" module in dev tools: + ly_create_alias(NAME LyShine.Builders NAMESPACE Gem TARGETS Gem::LyShine.Editor) + ly_create_alias(NAME LyShine.Tools NAMESPACE Gem TARGETS Gem::LyShine.Editor) endif() ################################################################################ diff --git a/Gems/LyShineExamples/Code/CMakeLists.txt b/Gems/LyShineExamples/Code/CMakeLists.txt index 372bfa948b..1eea884f78 100644 --- a/Gems/LyShineExamples/Code/CMakeLists.txt +++ b/Gems/LyShineExamples/Code/CMakeLists.txt @@ -40,3 +40,10 @@ ly_add_target( PRIVATE Gem::LyShineExamples.Static ) + +# if enabled, LyShineExamples is used by all kinds of applications +ly_create_alias(NAME LyShineExamples.Builders NAMESPACE Gem TARGETS Gem::LyShineExamples) +ly_create_alias(NAME LyShineExamples.Tools NAMESPACE Gem TARGETS Gem::LyShineExamples) +ly_create_alias(NAME LyShineExamples.Clients NAMESPACE Gem TARGETS Gem::LyShineExamples) +ly_create_alias(NAME LyShineExamples.Servers NAMESPACE Gem TARGETS Gem::LyShineExamples) + diff --git a/Gems/Maestro/Code/CMakeLists.txt b/Gems/Maestro/Code/CMakeLists.txt index fe58ba03a6..f554094cf2 100644 --- a/Gems/Maestro/Code/CMakeLists.txt +++ b/Gems/Maestro/Code/CMakeLists.txt @@ -44,6 +44,10 @@ ly_add_target( Gem::LmbrCentral ) +# if enabled, "Maestro" module is used for Clients and Servers: +ly_create_alias(NAME Maestro.Clients NAMESPACE Gem TARGETS Gem::Maestro) +ly_create_alias(NAME Maestro.Servers NAMESPACE Gem TARGETS Gem::Maestro) + if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME Maestro.Editor GEM_MODULE @@ -73,6 +77,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) + # the .Editor variant is used in dev tools: + ly_create_alias(NAME Maestro.Tools NAMESPACE Gem TARGETS Gem::Maestro.Editor) + ly_create_alias(NAME Maestro.Builders NAMESPACE Gem TARGETS Gem::Maestro.Editor) + endif() ################################################################################ diff --git a/Gems/MessagePopup/Code/CMakeLists.txt b/Gems/MessagePopup/Code/CMakeLists.txt index 2d0ad1ebcc..fa89b61f21 100644 --- a/Gems/MessagePopup/Code/CMakeLists.txt +++ b/Gems/MessagePopup/Code/CMakeLists.txt @@ -38,3 +38,7 @@ ly_add_target( PRIVATE Gem::MessagePopup.Static ) + +# MessagePopup is used only in client applications +ly_create_alias(NAME MessagePopup.Clients NAMESPACE Gem TARGETS Gem::MessagePopup) + diff --git a/Gems/Metastream/Code/CMakeLists.txt b/Gems/Metastream/Code/CMakeLists.txt index 326c21c5a9..95f7746b91 100644 --- a/Gems/Metastream/Code/CMakeLists.txt +++ b/Gems/Metastream/Code/CMakeLists.txt @@ -50,6 +50,11 @@ ly_add_target( Legacy::CryCommon ) +# The above "Metastream" target is used by all types of applications, including dev tools. +ly_create_alias(NAME Metastream.Clients NAMESPACE Gem TARGETS Gem::Metastream) +ly_create_alias(NAME Metastream.Servers NAMESPACE Gem TARGETS Gem::Metastream) +ly_create_alias(NAME Metastream.Builders NAMESPACE Gem TARGETS Gem::Metastream) +ly_create_alias(NAME Metastream.Tools NAMESPACE Gem TARGETS Gem::Metastream) ################################################################################ # Tests diff --git a/Gems/Microphone/Code/CMakeLists.txt b/Gems/Microphone/Code/CMakeLists.txt index 942899735c..17d492d786 100644 --- a/Gems/Microphone/Code/CMakeLists.txt +++ b/Gems/Microphone/Code/CMakeLists.txt @@ -46,3 +46,7 @@ ly_add_target( RUNTIME_DEPENDENCIES Gem::AudioSystem ) + +# The above "Microphone" target is used by all interactive applications +ly_create_alias(NAME Microphone.Clients NAMESPACE Gem TARGETS Gem::Microphone) +ly_create_alias(NAME Microphone.Tools NAMESPACE Gem TARGETS Gem::Microphone) diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index 019f341d0c..84a1cf7546 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -58,6 +58,33 @@ ly_add_target( Gem::CertificateManager ) +ly_add_target( + NAME Multiplayer.Debug ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} + NAMESPACE Gem + FILES_CMAKE + multiplayer_debug_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + . + PUBLIC + Include + BUILD_DEPENDENCIES + PRIVATE + AZ::AzCore + AZ::AtomCore + AZ::AzFramework + AZ::AzNetworking + Gem::Atom_Feature_Common.Static + Gem::Multiplayer.Static + Gem::ImGui.Static +) + +# The above "Multiplayer" target is used by clients and servers +# the debug is only used on Clients +ly_create_alias(NAME Multiplayer.Clients NAMESPACE Gem TARGETS Gem::Multiplayer Gem::Multiplayer.Debug) +ly_create_alias(NAME Multiplayer.Servers NAMESPACE Gem TARGETS Gem::Multiplayer) + if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME Multiplayer.Tools.Static STATIC @@ -124,6 +151,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Multiplayer.Tools ) + # use the Multiplayer.Editor module in tools and builders. Tools also get the visual debug view + ly_create_alias(NAME Multiplayer.Tools NAMESPACE Gem TARGETS Gem::Multiplayer.Editor Gem::Multiplayer.Debug Gem::Multiplayer.PrefabProcessor) + ly_create_alias(NAME Multiplayer.Builders NAMESPACE Gem TARGETS Gem::Multiplayer.Editor Gem::Multiplayer.PrefabProcessor) + endif() if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) @@ -173,25 +204,3 @@ if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) endif() endif() - -ly_add_target( - NAME Multiplayer.Debug ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} - NAMESPACE Gem - FILES_CMAKE - multiplayer_debug_files.cmake - INCLUDE_DIRECTORIES - PRIVATE - Source - . - PUBLIC - Include - BUILD_DEPENDENCIES - PRIVATE - AZ::AzCore - AZ::AtomCore - AZ::AzFramework - AZ::AzNetworking - Gem::Atom_Feature_Common.Static - Gem::Multiplayer.Static - Gem::ImGui.Static -) diff --git a/Gems/MultiplayerCompression/Code/CMakeLists.txt b/Gems/MultiplayerCompression/Code/CMakeLists.txt index 58ce546543..acc7978e88 100644 --- a/Gems/MultiplayerCompression/Code/CMakeLists.txt +++ b/Gems/MultiplayerCompression/Code/CMakeLists.txt @@ -39,6 +39,11 @@ ly_add_target( Gem::MultiplayerCompression.Static ) +# use the MultiplayerCompression module everywhere except builders: +ly_create_alias(NAME MultiplayerCompression.Clients NAMESPACE Gem TARGETS Gem::MultiplayerCompression) +ly_create_alias(NAME MultiplayerCompression.Tools NAMESPACE Gem TARGETS Gem::MultiplayerCompression) +ly_create_alias(NAME MultiplayerCompression.Servers NAMESPACE Gem TARGETS Gem::MultiplayerCompression) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/NvCloth/Code/CMakeLists.txt b/Gems/NvCloth/Code/CMakeLists.txt index 0f019a985f..d7eaf80b16 100644 --- a/Gems/NvCloth/Code/CMakeLists.txt +++ b/Gems/NvCloth/Code/CMakeLists.txt @@ -56,6 +56,10 @@ ly_add_target( Gem::AtomLyIntegration_CommonFeatures ) +# use the NvCloth module in clients and servers: +ly_create_alias(NAME NvCloth.Clients NAMESPACE Gem TARGETS Gem::NvCloth) +ly_create_alias(NAME NvCloth.Servers NAMESPACE Gem TARGETS Gem::NvCloth) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME NvCloth.Editor.Static STATIC @@ -97,6 +101,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES Gem::AtomLyIntegration_CommonFeatures.Editor ) + + # use the NvCloth.Editor module in dev tools: + ly_create_alias(NAME NvCloth.Builders NAMESPACE Gem TARGETS Gem::NvCloth.Editor) + ly_create_alias(NAME NvCloth.Tools NAMESPACE Gem TARGETS Gem::NvCloth.Editor) endif() ################################################################################ diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index b4c7b580a6..7f6fe61be7 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -70,6 +70,10 @@ ly_add_target( Gem::LmbrCentral ) +# use the PhysX module in clients and servers: +ly_create_alias(NAME PhysX.Clients NAMESPACE Gem TARGETS Gem::PhysX) +ly_create_alias(NAME PhysX.Servers NAMESPACE Gem TARGETS Gem::PhysX) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_associate_package(PACKAGE_NAME poly2tri-0.3.3-rev2-multiplatform TARGETS poly2tri PACKAGE_HASH 04092d06716f59b936b61906eaf3647db23b685d81d8b66131eb53e0aeaa1a38) @@ -136,6 +140,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::LmbrCentral.Editor ) + # use the PhysX.Editor module in dev tools: + ly_create_alias(NAME PhysX.Builders NAMESPACE Gem TARGETS Gem::PhysX.Editor) + ly_create_alias(NAME PhysX.Tools NAMESPACE Gem TARGETS Gem::PhysX.Editor) + endif() ################################################################################ diff --git a/Gems/PhysXDebug/Code/CMakeLists.txt b/Gems/PhysXDebug/Code/CMakeLists.txt index f198f6f26e..55d8044757 100644 --- a/Gems/PhysXDebug/Code/CMakeLists.txt +++ b/Gems/PhysXDebug/Code/CMakeLists.txt @@ -44,6 +44,9 @@ ly_add_target( Gem::PhysX Gem::ImGui ) +# use the PhysXDebug module in Clients and Servers: +ly_create_alias(NAME PhysXDebug.Clients NAMESPACE Gem TARGETS Gem::PhysXDebug) +ly_create_alias(NAME PhysXDebug.Servers NAMESPACE Gem TARGETS Gem::PhysXDebug) if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( @@ -73,4 +76,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::PhysX.Editor Gem::ImGui.Editor ) + # use the PhysXDebug.Editor module in dev tools: + ly_create_alias(NAME PhysXDebug.Builders NAMESPACE Gem TARGETS Gem::PhysXDebug.Editor) + ly_create_alias(NAME PhysXDebug.Tools NAMESPACE Gem TARGETS Gem::PhysXDebug.Editor) + endif() diff --git a/Gems/Prefab/PrefabBuilder/CMakeLists.txt b/Gems/Prefab/PrefabBuilder/CMakeLists.txt index 22b89287ca..dbd3c2281b 100644 --- a/Gems/Prefab/PrefabBuilder/CMakeLists.txt +++ b/Gems/Prefab/PrefabBuilder/CMakeLists.txt @@ -38,14 +38,16 @@ ly_add_target( Gem::PrefabBuilder.Static ) -ly_add_target_dependencies( - TARGETS - AssetBuilder - AssetProcessor - AssetProcessorBatch - DEPENDENT_TARGETS - Gem::PrefabBuilder -) +# the prefab builder only needs to be active in builders +# use the PrefabBuilder module in Clients and Servers: +ly_create_alias(NAME PrefabBuilder.Builders NAMESPACE Gem TARGETS Gem::PrefabBuilder) + +# we automatically add this gem, if it is present, to all our known set of builder applications: +ly_enable_gems(GEMS PrefabBuilder VARIANTS Builders TARGETS AssetProcessor AssetProcessorBatch AssetBuilder) + +# if you have a custom builder application in your project, then use ly_enable_gems() to +# add it to that application for your project, like this to make YOUR_TARGET_NAME load it automatically +# ly_enable_gems(PROJECT (YOUR_PROJECT_NAME) GEMS PrefabBuilder VARIANTS Builders TARGETS (YOUR_TARGET_NAME) ) if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_target( diff --git a/Gems/Presence/Code/CMakeLists.txt b/Gems/Presence/Code/CMakeLists.txt index 07780fc8eb..b9db324996 100644 --- a/Gems/Presence/Code/CMakeLists.txt +++ b/Gems/Presence/Code/CMakeLists.txt @@ -44,3 +44,6 @@ ly_add_target( AZ::AzFramework Gem::Presence.Headers ) + +# we activate the presence gem (if enabled) only on client applications such as the launcher: +ly_create_alias(NAME Presence.Clients NAMESPACE Gem TARGETS Gem::Presence) diff --git a/Gems/PythonAssetBuilder/Code/CMakeLists.txt b/Gems/PythonAssetBuilder/Code/CMakeLists.txt index 60af675bc6..4af266f56d 100644 --- a/Gems/PythonAssetBuilder/Code/CMakeLists.txt +++ b/Gems/PythonAssetBuilder/Code/CMakeLists.txt @@ -69,6 +69,11 @@ ly_add_target( Gem::EditorPythonBindings.Editor ) +# the above target is used in both builders like AssetProcessor and Tools like the Editor +# but is not used in clients or servers +ly_create_alias(NAME PythonAssetBuilder.Tools NAMESPACE Gem TARGETS Gem::PythonAssetBuilder.Editor) +ly_create_alias(NAME PythonAssetBuilder.Builders NAMESPACE Gem TARGETS Gem::PythonAssetBuilder.Editor) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/QtForPython/Code/CMakeLists.txt b/Gems/QtForPython/Code/CMakeLists.txt index 74c660043f..c11d93634e 100644 --- a/Gems/QtForPython/Code/CMakeLists.txt +++ b/Gems/QtForPython/Code/CMakeLists.txt @@ -55,3 +55,9 @@ ly_add_target( RUNTIME_DEPENDENCIES Gem::EditorPythonBindings.Editor ) + +# the above target is used in both builders like AssetProcessor and Tools like the Editor +# but is not used in clients or servers +ly_create_alias(NAME QtForPython.Tools NAMESPACE Gem TARGETS Gem::QtForPython.Editor) +ly_create_alias(NAME QtForPython.Builders NAMESPACE Gem TARGETS Gem::QtForPython.Editor) + diff --git a/Gems/RADTelemetry/Code/CMakeLists.txt b/Gems/RADTelemetry/Code/CMakeLists.txt index 78a5561b7c..8b3cc70570 100644 --- a/Gems/RADTelemetry/Code/CMakeLists.txt +++ b/Gems/RADTelemetry/Code/CMakeLists.txt @@ -42,3 +42,8 @@ ly_add_target( PRIVATE Gem::RADTelemetry.Static ) + +# the RADTelemetry module above can be used in all kinds of applications, but we don't enable it in asset builders +ly_create_alias(NAME RADTelemetry.Clients NAMESPACE Gem TARGETS Gem::RADTelemetry) +ly_create_alias(NAME RADTelemetry.Tools NAMESPACE Gem TARGETS Gem::RADTelemetry) +ly_create_alias(NAME RADTelemetry.Servers NAMESPACE Gem TARGETS Gem::RADTelemetry) diff --git a/Gems/SaveData/Code/CMakeLists.txt b/Gems/SaveData/Code/CMakeLists.txt index 46c6e91f58..d9dc62ef03 100644 --- a/Gems/SaveData/Code/CMakeLists.txt +++ b/Gems/SaveData/Code/CMakeLists.txt @@ -46,6 +46,9 @@ ly_add_target( Gem::SaveData.Static ) +# the SaveData module above is only used in Clients by default. +ly_create_alias(NAME SaveData.Clients NAMESPACE Gem TARGETS Gem::SaveData) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/SceneLoggingExample/Code/CMakeLists.txt b/Gems/SceneLoggingExample/Code/CMakeLists.txt index 8cd012c4c2..6370420928 100644 --- a/Gems/SceneLoggingExample/Code/CMakeLists.txt +++ b/Gems/SceneLoggingExample/Code/CMakeLists.txt @@ -40,3 +40,7 @@ ly_add_target( PRIVATE Gem::SceneLoggingExample.Static ) + +# the SceneLoggingExample module above is only used in Builders and Tools by default. +ly_create_alias(NAME SceneLoggingExample.Builders NAMESPACE Gem TARGETS Gem::SceneLoggingExample) +ly_create_alias(NAME SceneLoggingExample.Tools NAMESPACE Gem TARGETS Gem::SceneLoggingExample) diff --git a/Gems/SceneProcessing/Code/CMakeLists.txt b/Gems/SceneProcessing/Code/CMakeLists.txt index 67124a74d5..32c0331f4a 100644 --- a/Gems/SceneProcessing/Code/CMakeLists.txt +++ b/Gems/SceneProcessing/Code/CMakeLists.txt @@ -66,6 +66,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) AZ::SceneCore AZ::SceneData ) + # the SceneProcessing.Editor module above is only used in Builders and Tools. + ly_create_alias(NAME SceneProcessing.Builders NAMESPACE Gem TARGETS Gem::SceneProcessing.Editor) + ly_create_alias(NAME SceneProcessing.Tools NAMESPACE Gem TARGETS Gem::SceneProcessing.Editor) + endif() ################################################################################ diff --git a/Gems/ScriptCanvas/Code/CMakeLists.txt b/Gems/ScriptCanvas/Code/CMakeLists.txt index 32efa74520..5c9022182b 100644 --- a/Gems/ScriptCanvas/Code/CMakeLists.txt +++ b/Gems/ScriptCanvas/Code/CMakeLists.txt @@ -49,6 +49,14 @@ ly_add_target( Gem::ScriptEvents.Static ) +# the script canvas debugger is an optional gem module +# To Enable it: ly_enable_gems( ... TARGETS xxxyyzzz GEMS ScriptCanvasDebugger ...) +# in any particular target. +ly_create_alias(NAME ScriptCanvasDebugger.Builders NAMESPACE Gem TARGETS Gem::ScriptCanvasDebugger) +ly_create_alias(NAME ScriptCanvasDebugger.Tools NAMESPACE Gem TARGETS Gem::ScriptCanvasDebugger) +ly_create_alias(NAME ScriptCanvasDebugger.Clients NAMESPACE Gem TARGETS Gem::ScriptCanvasDebugger) +ly_create_alias(NAME ScriptCanvasDebugger.Servers NAMESPACE Gem TARGETS Gem::ScriptCanvasDebugger) + ly_add_target( NAME ScriptCanvas.Static STATIC NAMESPACE Gem @@ -109,6 +117,10 @@ ly_add_target( Gem::ExpressionEvaluation ) +# the "ScriptCanvas" target is active in Clients and Servers +ly_create_alias(NAME ScriptCanvas.Clients NAMESPACE Gem TARGETS Gem::ScriptCanvas) +ly_create_alias(NAME ScriptCanvas.Servers NAMESPACE Gem TARGETS Gem::ScriptCanvas) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME ScriptCanvasEditor STATIC @@ -204,6 +216,12 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::ScriptEvents.Editor Gem::ExpressionEvaluation ) + + # the "ScriptCanvas.Editor" target is active in all dev tools: + ly_create_alias(NAME ScriptCanvas.Builders NAMESPACE Gem TARGETS Gem::ScriptCanvas.Editor) + ly_create_alias(NAME ScriptCanvas.Tools NAMESPACE Gem TARGETS Gem::ScriptCanvas.Editor) + + endif() ################################################################################ diff --git a/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt b/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt index d9ce9004d3..1bdbdff12d 100644 --- a/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt @@ -54,6 +54,11 @@ ly_add_target( Gem::ScriptCanvas ) +# By default, the above module is the Client/Server module +ly_create_alias(NAME ScriptCanvasDeveloper.Clients NAMESPACE Gem TARGETS Gem::ScriptCanvasDeveloper) +ly_create_alias(NAME ScriptCanvasDeveloper.Servers NAMESPACE Gem TARGETS Gem::ScriptCanvasDeveloper) + + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME ScriptCanvasDeveloper.Editor GEM_MODULE @@ -82,4 +87,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES Gem::ScriptCanvas.Editor ) + # By Default the above module is the dev tools module + ly_create_alias(NAME ScriptCanvasDeveloper.Builders NAMESPACE Gem TARGETS Gem::ScriptCanvasDeveloper.Editor) + ly_create_alias(NAME ScriptCanvasDeveloper.Tools NAMESPACE Gem TARGETS Gem::ScriptCanvasDeveloper.Editor) + endif() diff --git a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt index 23ee6937c7..0c0560e063 100644 --- a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt @@ -38,6 +38,12 @@ ly_add_target( Gem::ScriptCanvasPhysics.Static ) +# By default, the above module is used by all application types +ly_create_alias(NAME ScriptCanvasPhysics.Clients NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics) +ly_create_alias(NAME ScriptCanvasPhysics.Servers NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics) +ly_create_alias(NAME ScriptCanvasPhysics.Tools NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics) +ly_create_alias(NAME ScriptCanvasPhysics.Builders NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index 639ef114fc..e3bdbf02e2 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -73,6 +73,9 @@ ly_add_target( Gem::ScriptCanvas.Editor ) +# By default, the above module is used only in tools: +ly_create_alias(NAME ScriptCanvasTesting.Tools NAMESPACE Gem TARGETS Gem::ScriptCanvasTesting.Editor) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/ScriptEvents/Code/CMakeLists.txt b/Gems/ScriptEvents/Code/CMakeLists.txt index 12f8cfd7b6..6f75e35d71 100644 --- a/Gems/ScriptEvents/Code/CMakeLists.txt +++ b/Gems/ScriptEvents/Code/CMakeLists.txt @@ -40,6 +40,11 @@ ly_add_target( Gem::ScriptEvents.Static ) +# the above module is for use in clients and servers +ly_create_alias(NAME ScriptEvents.Clients NAMESPACE Gem TARGETS Gem::ScriptEvents) +ly_create_alias(NAME ScriptEvents.Servers NAMESPACE Gem TARGETS Gem::ScriptEvents) + + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME ScriptEvents.Editor GEM_MODULE @@ -61,6 +66,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AssetBuilderSDK Gem::ScriptEvents.Static ) + + # the above module is for use in dev tools. + ly_create_alias(NAME ScriptEvents.Tools NAMESPACE Gem TARGETS Gem::ScriptEvents.Editor) + ly_create_alias(NAME ScriptEvents.Builders NAMESPACE Gem TARGETS Gem::ScriptEvents.Editor) endif() ################################################################################ diff --git a/Gems/ScriptedEntityTweener/Code/CMakeLists.txt b/Gems/ScriptedEntityTweener/Code/CMakeLists.txt index c5062c84b7..2488057f8c 100644 --- a/Gems/ScriptedEntityTweener/Code/CMakeLists.txt +++ b/Gems/ScriptedEntityTweener/Code/CMakeLists.txt @@ -40,3 +40,9 @@ ly_add_target( AZ::AzCore Legacy::CryCommon ) + +# the above module is for use in all application types: +ly_create_alias(NAME ScriptedEntityTweener.Tools NAMESPACE Gem TARGETS Gem::ScriptedEntityTweener) +ly_create_alias(NAME ScriptedEntityTweener.Clients NAMESPACE Gem TARGETS Gem::ScriptedEntityTweener) +ly_create_alias(NAME ScriptedEntityTweener.Builders NAMESPACE Gem TARGETS Gem::ScriptedEntityTweener) +ly_create_alias(NAME ScriptedEntityTweener.Servers NAMESPACE Gem TARGETS Gem::ScriptedEntityTweener) \ No newline at end of file diff --git a/Gems/SliceFavorites/Code/CMakeLists.txt b/Gems/SliceFavorites/Code/CMakeLists.txt index 4ad89ad6c3..35349c777c 100644 --- a/Gems/SliceFavorites/Code/CMakeLists.txt +++ b/Gems/SliceFavorites/Code/CMakeLists.txt @@ -51,3 +51,6 @@ ly_add_target( 3rdParty::Qt::Core Gem::SliceFavorites.Editor.Static ) + +# the above module is for use in Tools only (no need to load it in builders) +ly_create_alias(NAME SliceFavorites.Tools NAMESPACE Gem TARGETS Gem::SliceFavorites.Editor) \ No newline at end of file diff --git a/Gems/StartingPointCamera/Code/CMakeLists.txt b/Gems/StartingPointCamera/Code/CMakeLists.txt index d6dd1a7038..7bc57476a5 100644 --- a/Gems/StartingPointCamera/Code/CMakeLists.txt +++ b/Gems/StartingPointCamera/Code/CMakeLists.txt @@ -48,3 +48,9 @@ ly_add_target( RUNTIME_DEPENDENCIES Gem::CameraFramework ) + +# the above module is for use in all kinds of applications +ly_create_alias(NAME StartingPointCamera.Servers NAMESPACE Gem TARGETS Gem::StartingPointCamera) +ly_create_alias(NAME StartingPointCamera.Clients NAMESPACE Gem TARGETS Gem::StartingPointCamera) +ly_create_alias(NAME StartingPointCamera.Builders NAMESPACE Gem TARGETS Gem::StartingPointCamera) +ly_create_alias(NAME StartingPointCamera.Tools NAMESPACE Gem TARGETS Gem::StartingPointCamera) diff --git a/Gems/StartingPointInput/Code/CMakeLists.txt b/Gems/StartingPointInput/Code/CMakeLists.txt index 1372a79a78..c6e7fdcb52 100644 --- a/Gems/StartingPointInput/Code/CMakeLists.txt +++ b/Gems/StartingPointInput/Code/CMakeLists.txt @@ -56,6 +56,10 @@ ly_add_source_properties( VALUES ${LY_PAL_TOOLS_DEFINES} ) +# the above module is for use in clients and servers +ly_create_alias(NAME StartingPointInput.Servers NAMESPACE Gem TARGETS Gem::StartingPointInput) +ly_create_alias(NAME StartingPointInput.Clients NAMESPACE Gem TARGETS Gem::StartingPointInput) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME StartingPointInput.Editor GEM_MODULE @@ -74,6 +78,11 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzFramework Gem::StartingPointInput.Static ) + + # by default, activate the ab ove module in builders and tools: + ly_create_alias(NAME StartingPointInput.Builders NAMESPACE Gem TARGETS Gem::StartingPointInput.Editor) + ly_create_alias(NAME StartingPointInput.Tools NAMESPACE Gem TARGETS Gem::StartingPointInput.Editor) + endif() ################################################################################ diff --git a/Gems/StartingPointMovement/Code/CMakeLists.txt b/Gems/StartingPointMovement/Code/CMakeLists.txt index d6434ccf78..417dfe01ee 100644 --- a/Gems/StartingPointMovement/Code/CMakeLists.txt +++ b/Gems/StartingPointMovement/Code/CMakeLists.txt @@ -40,3 +40,9 @@ ly_add_target( AZ::AzCore AZ::AzFramework ) + +# the above module is for use in all application types (there is no tool specialization) +ly_create_alias(NAME StartingPointMovement.Servers NAMESPACE Gem TARGETS Gem::StartingPointMovement) +ly_create_alias(NAME StartingPointMovement.Clients NAMESPACE Gem TARGETS Gem::StartingPointMovement) +ly_create_alias(NAME StartingPointMovement.Builders NAMESPACE Gem TARGETS Gem::StartingPointMovement) +ly_create_alias(NAME StartingPointMovement.Tools NAMESPACE Gem TARGETS Gem::StartingPointMovement) \ No newline at end of file diff --git a/Gems/SurfaceData/Code/CMakeLists.txt b/Gems/SurfaceData/Code/CMakeLists.txt index de1aa51938..cdc1bbc4f3 100644 --- a/Gems/SurfaceData/Code/CMakeLists.txt +++ b/Gems/SurfaceData/Code/CMakeLists.txt @@ -46,6 +46,10 @@ ly_add_target( Gem::LmbrCentral ) +# the above module is for use in all client/server types +ly_create_alias(NAME SurfaceData.Servers NAMESPACE Gem TARGETS Gem::SurfaceData) +ly_create_alias(NAME SurfaceData.Clients NAMESPACE Gem TARGETS Gem::SurfaceData) + if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( @@ -70,6 +74,9 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) + # the above module is for use in dev tool situations + ly_create_alias(NAME SurfaceData.Builders NAMESPACE Gem TARGETS Gem::SurfaceData.Editor) + ly_create_alias(NAME SurfaceData.Tools NAMESPACE Gem TARGETS Gem::SurfaceData.Editor) endif() diff --git a/Gems/TestAssetBuilder/Code/CMakeLists.txt b/Gems/TestAssetBuilder/Code/CMakeLists.txt index dbd2907033..ebd34140aa 100644 --- a/Gems/TestAssetBuilder/Code/CMakeLists.txt +++ b/Gems/TestAssetBuilder/Code/CMakeLists.txt @@ -40,3 +40,6 @@ ly_add_target( PRIVATE Gem::TestAssetBuilder.Static ) + +# the above module is for use in builders only +ly_create_alias(NAME TestAssetBuilder.Builders NAMESPACE Gem TARGETS Gem::TestAssetBuilder.Editor) diff --git a/Gems/TextureAtlas/Code/CMakeLists.txt b/Gems/TextureAtlas/Code/CMakeLists.txt index b7072321dc..8f96ed6593 100644 --- a/Gems/TextureAtlas/Code/CMakeLists.txt +++ b/Gems/TextureAtlas/Code/CMakeLists.txt @@ -22,3 +22,9 @@ ly_add_target( Legacy::CryCommon AZ::AzFramework ) + +# the above module is for use in all application types (there is no tool specialization) +ly_create_alias(NAME TextureAtlas.Servers NAMESPACE Gem TARGETS Gem::TextureAtlas) +ly_create_alias(NAME TextureAtlas.Clients NAMESPACE Gem TARGETS Gem::TextureAtlas) +ly_create_alias(NAME TextureAtlas.Builders NAMESPACE Gem TARGETS Gem::TextureAtlas) +ly_create_alias(NAME TextureAtlas.Tools NAMESPACE Gem TARGETS Gem::TextureAtlas) diff --git a/Gems/TickBusOrderViewer/Code/CMakeLists.txt b/Gems/TickBusOrderViewer/Code/CMakeLists.txt index 3f56a0d554..551c62c64c 100644 --- a/Gems/TickBusOrderViewer/Code/CMakeLists.txt +++ b/Gems/TickBusOrderViewer/Code/CMakeLists.txt @@ -38,3 +38,9 @@ ly_add_target( PRIVATE Gem::TickBusOrderViewer.Static ) + + +# the above module is for use in all application types except builders +ly_create_alias(NAME TickBusOrderViewer.Servers NAMESPACE Gem TARGETS Gem::TickBusOrderViewer) +ly_create_alias(NAME TickBusOrderViewer.Clients NAMESPACE Gem TARGETS Gem::TickBusOrderViewer) +ly_create_alias(NAME TickBusOrderViewer.Tools NAMESPACE Gem TARGETS Gem::TickBusOrderViewer) diff --git a/Gems/Twitch/Code/CMakeLists.txt b/Gems/Twitch/Code/CMakeLists.txt index 14d7a41532..7369f5c7bf 100644 --- a/Gems/Twitch/Code/CMakeLists.txt +++ b/Gems/Twitch/Code/CMakeLists.txt @@ -47,3 +47,9 @@ ly_add_target( RUNTIME_DEPENDENCIES Gem::HttpRequestor ) + +# the above module is for use in all application types except builders +ly_create_alias(NAME Twitch.Servers NAMESPACE Gem TARGETS Gem::Twitch) +ly_create_alias(NAME Twitch.Clients NAMESPACE Gem TARGETS Gem::Twitch) +ly_create_alias(NAME Twitch.Tools NAMESPACE Gem TARGETS Gem::Twitch) + diff --git a/Gems/Vegetation/Code/CMakeLists.txt b/Gems/Vegetation/Code/CMakeLists.txt index c4a003bb4a..3e1cc36e77 100644 --- a/Gems/Vegetation/Code/CMakeLists.txt +++ b/Gems/Vegetation/Code/CMakeLists.txt @@ -51,6 +51,10 @@ ly_add_target( Gem::SurfaceData ) +# the above module is for use in clients and server type applications +ly_create_alias(NAME Vegetation.Servers NAMESPACE Gem TARGETS Gem::Vegetation) +ly_create_alias(NAME Vegetation.Clients NAMESPACE Gem TARGETS Gem::Vegetation) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME Vegetation.Editor GEM_MODULE @@ -75,6 +79,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::GradientSignal.Editor Gem::SurfaceData.Editor ) + # the above module is for use in dev tools + ly_create_alias(NAME Vegetation.Builders NAMESPACE Gem TARGETS Gem::Vegetation.Editor) + ly_create_alias(NAME Vegetation.Tools NAMESPACE Gem TARGETS Gem::Vegetation.Editor) + endif() ################################################################################ diff --git a/Gems/VideoPlaybackFramework/Code/CMakeLists.txt b/Gems/VideoPlaybackFramework/Code/CMakeLists.txt index 297f4cfaac..b29fe53216 100644 --- a/Gems/VideoPlaybackFramework/Code/CMakeLists.txt +++ b/Gems/VideoPlaybackFramework/Code/CMakeLists.txt @@ -42,6 +42,11 @@ ly_add_target( Gem::VideoPlaybackFramework.Static ) +# the video playback framework makes sense in everything but servers: +ly_create_alias(NAME VideoPlaybackFramework.Clients NAMESPACE Gem TARGETS Gem::VideoPlaybackFramework) +ly_create_alias(NAME VideoPlaybackFramework.Tools NAMESPACE Gem TARGETS Gem::VideoPlaybackFramework) +ly_create_alias(NAME VideoPlaybackFramework.Builders NAMESPACE Gem TARGETS Gem::VideoPlaybackFramework) + ################################################################################ # Tests ################################################################################ diff --git a/Gems/VirtualGamepad/Code/CMakeLists.txt b/Gems/VirtualGamepad/Code/CMakeLists.txt index 99a33db70b..4311796b57 100644 --- a/Gems/VirtualGamepad/Code/CMakeLists.txt +++ b/Gems/VirtualGamepad/Code/CMakeLists.txt @@ -40,3 +40,8 @@ ly_add_target( PRIVATE Gem::VirtualGamepad.Static ) + +# the virtual gamepad is needed everywhere except servers: +ly_create_alias(NAME VirtualGamepad.Clients NAMESPACE Gem TARGETS Gem::VirtualGamepad) +ly_create_alias(NAME VirtualGamepad.Tools NAMESPACE Gem TARGETS Gem::VirtualGamepad) +ly_create_alias(NAME VirtualGamepad.Builders NAMESPACE Gem TARGETS Gem::VirtualGamepad) diff --git a/Gems/WhiteBox/Code/CMakeLists.txt b/Gems/WhiteBox/Code/CMakeLists.txt index a15a4e150c..5985ff26a3 100644 --- a/Gems/WhiteBox/Code/CMakeLists.txt +++ b/Gems/WhiteBox/Code/CMakeLists.txt @@ -86,6 +86,10 @@ ly_add_target( Gem::WhiteBox.Static ) +# use the above WhiteBox module in runtimes: +ly_create_alias(NAME WhiteBox.Clients NAMESPACE Gem TARGETS Gem::WhiteBox) +ly_create_alias(NAME WhiteBox.Servers NAMESPACE Gem TARGETS Gem::WhiteBox) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME WhiteBox.Editor.Static STATIC @@ -129,6 +133,12 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PRIVATE Gem::WhiteBox.Editor.Static ) + + # use the above WhiteBox.Editor module in dev tools: + ly_create_alias(NAME WhiteBox.Tools NAMESPACE Gem TARGETS Gem::WhiteBox.Editor) + ly_create_alias(NAME WhiteBox.Builders NAMESPACE Gem TARGETS Gem::WhiteBox.Editor) + + endif() ################################################################################ diff --git a/cmake/Gems.cmake b/cmake/Gems.cmake new file mode 100644 index 0000000000..3e9ce97329 --- /dev/null +++ b/cmake/Gems.cmake @@ -0,0 +1,196 @@ +# +# 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. +# + +# This file contains utility wrappers for dealing with the Gems system. + +# ly_create_alias +# given an alias to create, and a list of one or more targets, +# this creates an alias that depends on all of the given targets. +function(ly_create_alias) + set(options) + set(oneValueArgs NAME NAMESPACE) + set(multiValueArgs TARGETS) + + cmake_parse_arguments(ly_create_alias "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT ly_create_alias_NAME) + message(FATAL_ERROR "Provide the name of the alias to create using the NAME keyword") + endif() + + if (NOT ly_create_alias_NAMESPACE) + message(FATAL_ERROR "Provide the namespace of the alias to create using the NAMESPACE keyword") + endif() + + if (NOT ly_create_alias_TARGETS) + message(FATAL_ERROR "Provide the name of the targets the alias be associated with, using the TARGETS keyword") + endif() + + if(TARGET ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME}) + message(FATAL_ERROR "Target already exists, cannot create an alias for it: ${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME}\n" + "Make sure the target wasn't copy and pasted here or elsewhere.") + endif() + + # easy version - if its juts one target, we can directly get the target, and make both aliases, + # the namespaced and non namespaced one, point at it. + list(LENGTH ly_create_alias_TARGETS number_of_targets) + if (number_of_targets EQUAL 1) + ly_de_alias_target(${ly_create_alias_TARGETS} de_aliased_target_name) + add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${de_aliased_target_name}) + if (NOT TARGET ${ly_create_alias_NAME}) + add_library(${ly_create_alias_NAME} ALIAS ${de_aliased_target_name}) + endif() + return() + endif() + + # more complex version - one alias to multiple targets. To actually achieve this + # we have to create an interface library with those dependencies, then we have to create an alias to that target. + # by convention we create one without a namespace then alias the namespaced one. + + if(TARGET ${ly_create_alias_NAME}) + message(FATAL_ERROR "Internal alias target already exists, cannot create an alias for it: ${ly_create_alias_NAME}\n" + "This could be a copy-paste error, where some part of the ly_create_alias call was changed but the other") + endif() + + add_library(${ly_create_alias_NAME} INTERFACE IMPORTED) + set_target_properties(${ly_create_alias_NAME} PROPERTIES GEM_MODULE TRUE) + + foreach(target_name ${ly_create_alias_TARGETS}) + ly_de_alias_target(${target_name} de_aliased_target_name) + if(NOT de_aliased_target_name) + message(FATAL_ERROR "Target not found in ly_create_alias call: ${target_name} - check your spelling of the target name") + endif() + list(APPEND final_targets ${de_aliased_target_name}) + endforeach() + + ly_parse_third_party_dependencies("${final_targets}") + ly_add_dependencies(${ly_create_alias_NAME} ${final_targets}) + + # now add the final alias: + add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${ly_create_alias_NAME}) +endfunction() + +# ly_enable_gems +# this function makes sure that the given gems, or gems listed in the variable ENABLED_GEMS +# in the GEM_FILE name, are set as runtime dependencies (and thus loaded) for the given targets +# in the context of the given project. +# note that it can't do this immediately, so it saves the data for later processing. +# Note: If you don't supply a project name, it will apply it across the board to all projects. +# this is useful in the case of "ly_add_gems being called for so called 'mandatory gems' inside the engine. +function(ly_enable_gems) + set(options) + set(oneValueArgs PROJECT_NAME GEM_FILE) + set(multiValueArgs GEMS TARGETS VARIANTS) + + cmake_parse_arguments(ly_enable_gems "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT ly_enable_gems_TARGETS) + message(FATAL_ERROR "You must provide the targets to add gems to using the TARGETS keyword") + endif() + + + if (NOT ly_enable_gems_PROJECT_NAME) + message(VERBOSE "Note: ly_enable_gems called with no PROJECT_NAME name, applying to all projects: \n" + " - VARIANTS ${ly_enable_gems_VARIANTS} \n" + " - GEMS ${ly_enable_gems_GEMS} \n" + " - TARGETS ${ly_enable_gems_TARGETS} \n" + " - GEM_FILE ${ly_enable_gems_GEM_FILE}") + set(ly_enable_gems_PROJECT_NAME "__NOPROJECT__") # so that the token is not blank + endif() + + if (NOT ly_enable_gems_VARIANTS) + message(FATAL_ERROR "You must provide at least 1 variant of the gem modules (Editor, Server, Client, Builder) to " + "add to your targets, using the VARIANTS keyword") + endif() + + if ((NOT ly_enable_gems_GEMS AND NOT ly_enable_gems_GEM_FILE) OR (ly_enable_gems_GEMS AND ly_enable_gems_GEM_FILE)) + message(FATAL_ERROR "Provide exactly one of either GEM_FILE (filename) or GEMS (list of gems) keywords.") + endif() + + if (ly_enable_gems_GEM_FILE) + set(store_temp ${ENABLED_GEMS}) + include(${ly_enable_gems_GEM_FILE} RESULT_VARIABLE was_able_to_load_the_file) + if(NOT was_able_to_load_the_file) + message(FATAL_ERROR "could not load the GEM_FILE ${ly_enable_gems_GEM_FILE}") + endif() + if(NOT ENABLED_GEMS) + message(FATAL_ERROR "GEM_FILE ${ly_enable_gems_GEM_FILE} did not set the value of ENABLED_GEMS.\n" + "Gem Files should contain set(ENABLED_GEMS ... )") + endif() + set(ly_enable_gems_GEMS ${ENABLED_GEMS}) + set(ENABLED_GEMS ${store_temp}) # restore value of ENABLED_GEMS just in case... + endif() + + # all the actual work has to be done later. + foreach(target_name ${ly_enable_gems_TARGETS}) + foreach(variant_name ${ly_enable_gems_VARIANTS}) + set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS "${ly_enable_gems_PROJECT_NAME},${target_name},${variant_name}") + set_property(GLOBAL APPEND PROPERTY LY_DELAYED_ENABLE_GEMS_"${ly_enable_gems_PROJECT_NAME},${target_name},${variant_name}" ${ly_enable_gems_GEMS}) + endforeach() + endforeach() +endfunction() + +# call this before runtime dependencies are used to add any relevant targets +# saved by the above function +function(ly_enable_gems_delayed) + get_property(ly_delayed_enable_gems GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS) + foreach(project_target_variant ${ly_delayed_enable_gems}) + # we expect a colon seperated list of + # PROJECT_NAME,target_name,variant_name + string(REPLACE "," ";" project_target_variant_list "${project_target_variant}") + list(LENGTH project_target_variant_list project_target_variant_length) + if(project_target_variant_length EQUAL 0) + continue() + endif() + + if(NOT project_target_variant_length EQUAL 3) + message(FATAL_ERROR "Invalid specificaiton of gems, expected 'project','target','variant' and got ${project_target_variant}") + endif() + + list(POP_BACK project_target_variant_list variant) + list(POP_BACK project_target_variant_list target) + list(POP_BACK project_target_variant_list project) + + get_property(gem_dependencies GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS_"${project_target_variant}") + if (NOT gem_dependencies) + continue() + endif() + + if(${project} STREQUAL "__NOPROJECT__") + # special case, apply to all + unset(PREFIX_CLAUSE) + else() + set(PREFIX_CLAUSE "PREFIX;${project}") + endif() + + if (NOT TARGET ${target}) + message(FATAL_ERROR "ly_enable_gems specified TARGET '${target}' but no such target was found.") + endif() + + # apply the list of gem targets. Adding a gem really just means adding the appropriate dependency. + foreach(gem_name ${gem_dependencies}) + + if (TARGET Gem::${gem_name}.${variant}) + ly_add_target_dependencies( + ${PREFIX_CLAUSE} + TARGETS ${target} + DEPENDENT_TARGETS Gem::${gem_name}.${variant} + ) + elseif(${variant} STREQUAL "Client" AND TARGET Gem::${gem_name}) + # Client can also be 'empty' for backward compatibility + ly_add_target_dependencies( + ${PREFIX_CLAUSE} + TARGETS ${target} + DEPENDENT_TARGETS Gem::${gem_name} + ) + endif() + endforeach() + endforeach() +endfunction() \ No newline at end of file diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index f6a36afc89..b4641e0ff5 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -719,3 +719,20 @@ function(ly_project_add_subdirectory project_name) endif() endif() endfunction() + +# given a target name, returns the "real" name of the target if its an alias. +# this function recursively de-aliases +function(ly_de_alias_target target_name output_variable_name) + # its not okay to call get_target_property on a non-existant target + if (NOT TARGET ${target_name}) + message(FATAL_ERROR "ly_de_alias_target called on non-existant target: ${target_name}") + endif() + + while(target_name) + set(de_aliased_target_name ${target_name}) + + get_target_property(target_name ${target_name} ALIASED_TARGET) + endwhile() + + set(${output_variable_name} ${de_aliased_target_name} PARENT_SCOPE) +endfunction() diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index fd5985a5a1..b89a810f10 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -67,6 +67,7 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) # Skip wrapping produced when targets are not created in the same directory if(NOT ${load_dependency} MATCHES "^::@") get_property(dependency_type TARGET ${load_dependency} PROPERTY TYPE) + get_property(is_gem_target TARGET ${load_dependency} PROPERTY GEM_MODULE SET) # If the dependency is a "gem module" then add it as a load dependencies # and recurse into its manually added dependencies @@ -91,12 +92,10 @@ endfunction() # This can be used for example to determine which list of gems to load with an application function(ly_delayed_generate_settings_registry) get_property(ly_delayed_load_targets GLOBAL PROPERTY LY_DELAYED_LOAD_DEPENDENCIES) - foreach(prefix_target ${ly_delayed_load_targets}) string(REPLACE "," ";" prefix_target_list "${prefix_target}") list(LENGTH prefix_target_list prefix_target_length) if(prefix_target_length EQUAL 0) - message(SEND_ERROR "Delayed load target is missing target name") continue() endif() @@ -116,6 +115,14 @@ function(ly_delayed_generate_settings_registry) endforeach() list(REMOVE_DUPLICATES all_gem_dependencies) + # de-namespace them + foreach(gem_target ${all_gem_dependencies}) + ly_strip_target_namespace(TARGET ${gem_target} OUTPUT_VARIABLE stripped_gem_target) + list(APPEND new_gem_dependencies ${stripped_gem_target}) + endforeach() + set(all_gem_dependencies ${new_gem_dependencies}) + list(REMOVE_DUPLICATES all_gem_dependencies) + unset(target_gem_dependencies_names) foreach(gem_target ${all_gem_dependencies}) unset(gem_relative_source_dir) @@ -123,6 +130,14 @@ function(ly_delayed_generate_settings_registry) if (NOT TARGET ${gem_target}) message(FATAL_ERROR "Dependency ${gem_target} from ${target} does not exist") endif() + + get_target_property(target_type ${gem_target} TYPE) + if (target_type STREQUAL "INTERFACE_LIBRARY") + # don't use interface libraries here, we only want ones which produce actual binaries. + # we have still already recursed into their dependencies - they'll show up later. + continue() + endif() + get_property(gem_relative_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) if(gem_relative_source_dir) # Most gems CMakeLists.txt files reside in the /Code/ so remove "Code/" from the path From 6a7a86062e4335a90c702111ae1837134a145da9 Mon Sep 17 00:00:00 2001 From: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> Date: Thu, 13 May 2021 14:00:05 -0700 Subject: [PATCH 064/140] Updates AutomatedTesting project and adds atom support --- AutomatedTesting/Gem/Code/CMakeLists.txt | 61 +++++++------------ .../AtomBridge/Code/CMakeLists.txt | 9 +++ Gems/AudioSystem/Code/CMakeLists.txt | 4 +- Gems/Multiplayer/Code/CMakeLists.txt | 1 - 4 files changed, 34 insertions(+), 41 deletions(-) diff --git a/AutomatedTesting/Gem/Code/CMakeLists.txt b/AutomatedTesting/Gem/Code/CMakeLists.txt index e81156c3aa..9315bf8397 100644 --- a/AutomatedTesting/Gem/Code/CMakeLists.txt +++ b/AutomatedTesting/Gem/Code/CMakeLists.txt @@ -32,46 +32,31 @@ ly_add_target( # Gem dependencies ################################################################################ -# The GameLauncher uses "Client" gem variants: +# The GameLauncher uses "Clients" gem variants: ly_enable_gems(PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake TARGETS AutomatedTesting.GameLauncher VARIANTS Clients) -# The Editor uses Tools gem variants: -ly_enable_gems( - PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake - TARGETS Editor - VARIANTS Tools) - -# The pipeline tools use Builders gem variants: -ly_enable_gems( - PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake - TARGETS AssetBuilder AssetProcessor AssetProcessorBatch - VARIANTS Builders) - -# old system (remove when all gems are ported to the new system above) - -ly_add_project_dependencies( - PROJECT_NAME - AutomatedTesting - TARGETS - AutomatedTesting.GameLauncher - DEPENDENCIES_FILES - runtime_dependencies.cmake - ${pal_dir}/runtime_dependencies.cmake -) - -if(PAL_TRAIT_BUILD_HOST_TOOLS) - ly_add_project_dependencies( - PROJECT_NAME - AutomatedTesting - TARGETS - AssetBuilder - AssetProcessor - AssetProcessorBatch - Editor - DEPENDENCIES_FILES - tool_dependencies.cmake - ${pal_dir}/tool_dependencies.cmake - ) +# If we build a server, then apply the gems to the server +if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) + # if we're making a server, then add the "Server" gem variants to it: + ly_enable_gems(PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake + TARGETS AutomatedTesting.ServerLauncher + VARIANTS Servers) + + set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS AutomatedTesting) +endif() + +if (PAL_TRAIT_BUILD_HOST_TOOLS) + # The Editor uses "Tools" gem variants: + ly_enable_gems( + PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake + TARGETS Editor + VARIANTS Tools) + + # The pipeline tools use "Builders" gem variants: + ly_enable_gems( + PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake + TARGETS AssetBuilder AssetProcessor AssetProcessorBatch + VARIANTS Builders) endif() diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt index c431746b40..85d84a5dc0 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt @@ -66,6 +66,10 @@ ly_add_target( Gem::AtomViewportDisplayInfo ) +# Any 'runtime-like' applications should use Gem::Atom_AtomBridge: +ly_create_alias(NAME Atom_AtomBridge.Clients NAMESPACE Gem TARGETS Gem::Atom_AtomBridge) +ly_create_alias(NAME Atom_AtomBridge.Servers NAMESPACE Gem TARGETS Gem::Atom_AtomBridge) + if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME Atom_AtomBridge.Editor ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} @@ -107,4 +111,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AtomToolsFramework.Editor Gem::AtomViewportDisplayInfo ) + + + # Any 'tool' and 'builder' type applications should use Gem::Atom_AtomBridge.Editor: + ly_create_alias(NAME Atom_AtomBridge.Builders NAMESPACE Gem TARGETS Gem::Atom_AtomBridge.Editor) + ly_create_alias(NAME Atom_AtomBridge.Tools NAMESPACE Gem TARGETS Gem::Atom_AtomBridge.Editor) endif() diff --git a/Gems/AudioSystem/Code/CMakeLists.txt b/Gems/AudioSystem/Code/CMakeLists.txt index dfb80a15d5..a0a8328147 100644 --- a/Gems/AudioSystem/Code/CMakeLists.txt +++ b/Gems/AudioSystem/Code/CMakeLists.txt @@ -217,8 +217,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ) # use the above "Editor" target in tools and builders: - ly_create_alias(NAME AssetMemoryAnalyzer.Tools NAMESPACE Gem TARGETS Gem::AudioSystem.Editor) - ly_create_alias(NAME AssetMemoryAnalyzer.Builders NAMESPACE Gem TARGETS Gem::AudioSystem.Editor) + ly_create_alias(NAME AudioSystem.Tools NAMESPACE Gem TARGETS Gem::AudioSystem.Editor) + ly_create_alias(NAME AudioSystem.Builders NAMESPACE Gem TARGETS Gem::AudioSystem.Editor) if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) ly_add_target( diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index 84a1cf7546..800670ff92 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -154,7 +154,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) # use the Multiplayer.Editor module in tools and builders. Tools also get the visual debug view ly_create_alias(NAME Multiplayer.Tools NAMESPACE Gem TARGETS Gem::Multiplayer.Editor Gem::Multiplayer.Debug Gem::Multiplayer.PrefabProcessor) ly_create_alias(NAME Multiplayer.Builders NAMESPACE Gem TARGETS Gem::Multiplayer.Editor Gem::Multiplayer.PrefabProcessor) - endif() if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) From 4ef357e57e2d8faf3b22d478eb3f3ef6a96f6410 Mon Sep 17 00:00:00 2001 From: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> Date: Thu, 13 May 2021 15:04:40 -0700 Subject: [PATCH 065/140] Updates the templates to use the new system Also updates the Gems.cmake file to handle namespaces being used. --- .../DefaultGem/Template/Code/CMakeLists.txt | 14 +++ .../Template/Code/${NameLower}_files.cmake | 4 +- .../Template/Code/CMakeLists.txt | 52 +++++---- .../Android/${NameLower}_android_files.cmake | 3 - .../android_runtime_dependencies.cmake | 14 --- .../Android/android_server_dependencies.cmake | 13 --- .../Android/android_tool_dependencies.cmake | 14 --- .../Linux/${NameLower}_linux_files.cmake | 3 - .../Linux/linux_runtime_dependencies.cmake | 15 --- .../Linux/linux_server_dependencies.cmake | 13 --- .../Linux/linux_tool_dependencies.cmake | 14 --- .../Platform/Mac/${NameLower}_mac_files.cmake | 3 - .../Mac/mac_runtime_dependencies.cmake | 15 --- .../Mac/mac_server_dependencies.cmake | 13 --- .../Platform/Mac/mac_tool_dependencies.cmake | 18 --- .../Windows/${NameLower}_windows_files.cmake | 3 - .../windows_runtime_dependencies.cmake | 16 --- .../Windows/windows_server_dependencies.cmake | 13 --- .../Windows/windows_tool_dependencies.cmake | 19 ---- .../Platform/iOS/${NameLower}_ios_files.cmake | 3 - .../iOS/ios_runtime_dependencies.cmake | 14 --- .../iOS/ios_server_dependencies.cmake | 13 --- .../Platform/iOS/ios_tool_dependencies.cmake | 14 --- ..._dependencies.cmake => enabled_gems.cmake} | 18 ++- .../Template/Code/runtime_dependencies.cmake | 36 ------ .../Template/Code/tool_dependencies.cmake | 43 ------- Templates/DefaultProject/template.json | 106 +----------------- cmake/Gems.cmake | 24 ++-- 28 files changed, 76 insertions(+), 454 deletions(-) delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Android/android_runtime_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Android/android_server_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Android/android_tool_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Linux/linux_runtime_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Linux/linux_server_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Linux/linux_tool_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Mac/mac_runtime_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Mac/mac_server_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Mac/mac_tool_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Windows/windows_runtime_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Windows/windows_server_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/Windows/windows_tool_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/iOS/ios_runtime_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/iOS/ios_server_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/Platform/iOS/ios_tool_dependencies.cmake rename Templates/DefaultProject/Template/Code/{server_dependencies.cmake => enabled_gems.cmake} (70%) delete mode 100644 Templates/DefaultProject/Template/Code/runtime_dependencies.cmake delete mode 100644 Templates/DefaultProject/Template/Code/tool_dependencies.cmake diff --git a/Templates/DefaultGem/Template/Code/CMakeLists.txt b/Templates/DefaultGem/Template/Code/CMakeLists.txt index 3511f8ff83..b0e52dd79f 100644 --- a/Templates/DefaultGem/Template/Code/CMakeLists.txt +++ b/Templates/DefaultGem/Template/Code/CMakeLists.txt @@ -59,6 +59,12 @@ ly_add_target( Gem::${Name}.Static ) +# By default, we will specify that the above target ${Name} would be used by +# Client and Server type targets when this gem is enabled. If you don't want it +# active in Clients or Servers by default, delete one of both of the following lines: +ly_create_alias(NAME ${Name}.Clients NAMESPACE Gem TARGETS Gem::${Name}) +ly_create_alias(NAME ${Name}.Servers NAMESPACE Gem TARGETS Gem::${Name}) + # If we are on a host platform, we want to add the host tools targets like the ${Name}.Editor target which # will also depend on ${Name}.Static if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -94,6 +100,14 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC Gem::${Name}.Editor.Static ) + + # By default, we will specify that the above target ${Name} would be used by + # Tool and Builder type targets when this gem is enabled. If you don't want it + # active in Tools or Builders by default, delete one of both of the following lines: + ly_create_alias(NAME ${Name}.Tools NAMESPACE Gem TARGETS Gem::${Name}.Editor) + ly_create_alias(NAME ${Name}.Builders NAMESPACE Gem TARGETS Gem::${Name}.Editor) + + endif() ################################################################################ diff --git a/Templates/DefaultProject/Template/Code/${NameLower}_files.cmake b/Templates/DefaultProject/Template/Code/${NameLower}_files.cmake index 459e33f547..f77348395b 100644 --- a/Templates/DefaultProject/Template/Code/${NameLower}_files.cmake +++ b/Templates/DefaultProject/Template/Code/${NameLower}_files.cmake @@ -13,7 +13,5 @@ set(FILES Include/${Name}/${Name}Bus.h Source/${Name}SystemComponent.cpp Source/${Name}SystemComponent.h - runtime_dependencies.cmake - tool_dependencies.cmake - server_dependencies.cmake + enabled_gems.cmake ) diff --git a/Templates/DefaultProject/Template/Code/CMakeLists.txt b/Templates/DefaultProject/Template/Code/CMakeLists.txt index 38999c031c..b116fb2044 100644 --- a/Templates/DefaultProject/Template/Code/CMakeLists.txt +++ b/Templates/DefaultProject/Template/Code/CMakeLists.txt @@ -64,41 +64,47 @@ ly_add_target( ################################################################################ # Gem dependencies ################################################################################ -ly_add_project_dependencies( - PROJECT_NAME - ${Name} + +# The GameLauncher uses "Clients" gem variants: +ly_enable_gems( + PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake TARGETS ${Name}.GameLauncher - DEPENDENCIES_FILES - runtime_dependencies.cmake - ${pal_dir}/${PAL_PLATFORM_NAME_LOWERCASE}_runtime_dependencies.cmake -) + VARIANTS + Clients) if(PAL_TRAIT_BUILD_HOST_TOOLS) - ly_add_project_dependencies( - PROJECT_NAME - ${Name} + + # the builder type applications use the "Builders" variants of the enabled gems. + ly_enable_gems( + PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake TARGETS AssetBuilder AssetProcessor AssetProcessorBatch + VARIANTS + Builders) + + # the Editor applications use the "Tools" variants of the enabled gems. + ly_enable_gems( + PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake + TARGETS Editor - DEPENDENCIES_FILES - tool_dependencies.cmake - ${pal_dir}/${PAL_PLATFORM_NAME_LOWERCASE}_tool_dependencies.cmake - ) + VARIANTS + Tools) endif() if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) - ly_add_project_dependencies( - PROJECT_NAME - ${Name} + # this property causes it to actually make a ServerLauncher. + # if you don't want a Server application, you can remove this and the + # following ly_enable_gems lines. + set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS ${Name}) + + # The ServerLauncher uses the "Servers" variants of enabled gems: + ly_enable_gems( + PROJECT_NAME ${Name} GEM_FILE enabled_gems.cmake TARGETS ${Name}.ServerLauncher - DEPENDENCIES_FILES - server_dependencies.cmake - ${pal_dir}/${PAL_PLATFORM_NAME_LOWERCASE}_server_dependencies.cmake - ) - set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS ${Name}) - + VARIANTS + Servers) endif() diff --git a/Templates/DefaultProject/Template/Code/Platform/Android/${NameLower}_android_files.cmake b/Templates/DefaultProject/Template/Code/Platform/Android/${NameLower}_android_files.cmake index b774cd944f..78fd98ba6c 100644 --- a/Templates/DefaultProject/Template/Code/Platform/Android/${NameLower}_android_files.cmake +++ b/Templates/DefaultProject/Template/Code/Platform/Android/${NameLower}_android_files.cmake @@ -11,7 +11,4 @@ set(FILES PAL_android.cmake - android_runtime_dependencies.cmake - android_tool_dependencies.cmake - android_server_dependencies.cmake ) diff --git a/Templates/DefaultProject/Template/Code/Platform/Android/android_runtime_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Android/android_runtime_dependencies.cmake deleted file mode 100644 index a1ebd6e455..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Android/android_runtime_dependencies.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::Atom_RHI_Vulkan.Private -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Android/android_server_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Android/android_server_dependencies.cmake deleted file mode 100644 index fe28e294e9..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Android/android_server_dependencies.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Android/android_tool_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Android/android_tool_dependencies.cmake deleted file mode 100644 index 14e6f1aa4c..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Android/android_tool_dependencies.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES -) - diff --git a/Templates/DefaultProject/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake b/Templates/DefaultProject/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake index 58fc59d265..ee0b06efc4 100644 --- a/Templates/DefaultProject/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake +++ b/Templates/DefaultProject/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake @@ -11,7 +11,4 @@ set(FILES PAL_linux.cmake - linux_runtime_dependencies.cmake - linux_tool_dependencies.cmake - linux_server_dependencies.cmake ) diff --git a/Templates/DefaultProject/Template/Code/Platform/Linux/linux_runtime_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Linux/linux_runtime_dependencies.cmake deleted file mode 100644 index a54c22de8c..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Linux/linux_runtime_dependencies.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::Atom_RHI_Vulkan.Private - Gem::Atom_RHI_Vulkan.Builders -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Linux/linux_server_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Linux/linux_server_dependencies.cmake deleted file mode 100644 index fe28e294e9..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Linux/linux_server_dependencies.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Linux/linux_tool_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Linux/linux_tool_dependencies.cmake deleted file mode 100644 index a1ebd6e455..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Linux/linux_tool_dependencies.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::Atom_RHI_Vulkan.Private -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake b/Templates/DefaultProject/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake index 7eb776e3a6..e14e028c88 100644 --- a/Templates/DefaultProject/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake +++ b/Templates/DefaultProject/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake @@ -12,7 +12,4 @@ set(FILES ../../../Resources/Platform/Mac/Info.plist PAL_mac.cmake - mac_runtime_dependencies.cmake - mac_tool_dependencies.cmake - mac_server_dependencies.cmake ) diff --git a/Templates/DefaultProject/Template/Code/Platform/Mac/mac_runtime_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Mac/mac_runtime_dependencies.cmake deleted file mode 100644 index 2821493346..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Mac/mac_runtime_dependencies.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::Atom_RHI_Metal.Private - Gem::Atom_RHI_Null.Private -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Mac/mac_server_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Mac/mac_server_dependencies.cmake deleted file mode 100644 index fe28e294e9..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Mac/mac_server_dependencies.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Mac/mac_tool_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Mac/mac_tool_dependencies.cmake deleted file mode 100644 index adf5485ed4..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Mac/mac_tool_dependencies.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::Atom_RHI_Metal.Private - Gem::Atom_RHI_Metal.Builders - Gem::Atom_RHI_Vulkan.Builders - Gem::Atom_RHI_DX12.Builders - Gem::Atom_RHI_Null.Builders -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake b/Templates/DefaultProject/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake index 8fee85a163..b6eb718a05 100644 --- a/Templates/DefaultProject/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake +++ b/Templates/DefaultProject/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake @@ -11,7 +11,4 @@ set(FILES PAL_windows.cmake - windows_runtime_dependencies.cmake - windows_tool_dependencies.cmake - windows_server_dependencies.cmake ) diff --git a/Templates/DefaultProject/Template/Code/Platform/Windows/windows_runtime_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Windows/windows_runtime_dependencies.cmake deleted file mode 100644 index 514a61aa57..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Windows/windows_runtime_dependencies.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::Atom_RHI_Vulkan.Private - Gem::Atom_RHI_DX12.Private - Gem::Atom_RHI_Null.Private -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Windows/windows_server_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Windows/windows_server_dependencies.cmake deleted file mode 100644 index fe28e294e9..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Windows/windows_server_dependencies.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES -) diff --git a/Templates/DefaultProject/Template/Code/Platform/Windows/windows_tool_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/Windows/windows_tool_dependencies.cmake deleted file mode 100644 index b7f4b82126..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/Windows/windows_tool_dependencies.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::Atom_RHI_Vulkan.Private - Gem::Atom_RHI_Vulkan.Builders - Gem::Atom_RHI_DX12.Private - Gem::Atom_RHI_DX12.Builders - Gem::Atom_RHI_Null.Private - Gem::Atom_RHI_Null.Builders -) diff --git a/Templates/DefaultProject/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake b/Templates/DefaultProject/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake index 41a6d13884..44f15538c8 100644 --- a/Templates/DefaultProject/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake +++ b/Templates/DefaultProject/Template/Code/Platform/iOS/${NameLower}_ios_files.cmake @@ -12,7 +12,4 @@ set(FILES ../Resources/Platform/iOS/Info.plist PAL_ios.cmake - ios_runtime_dependencies.cmake - ios_tool_dependencies.cmake - ios_server_dependencies.cmake ) diff --git a/Templates/DefaultProject/Template/Code/Platform/iOS/ios_runtime_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/iOS/ios_runtime_dependencies.cmake deleted file mode 100644 index e49929c6e1..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/iOS/ios_runtime_dependencies.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::Atom_RHI_Metal.Private -) diff --git a/Templates/DefaultProject/Template/Code/Platform/iOS/ios_server_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/iOS/ios_server_dependencies.cmake deleted file mode 100644 index fe28e294e9..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/iOS/ios_server_dependencies.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES -) diff --git a/Templates/DefaultProject/Template/Code/Platform/iOS/ios_tool_dependencies.cmake b/Templates/DefaultProject/Template/Code/Platform/iOS/ios_tool_dependencies.cmake deleted file mode 100644 index 14e6f1aa4c..0000000000 --- a/Templates/DefaultProject/Template/Code/Platform/iOS/ios_tool_dependencies.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES -) - diff --git a/Templates/DefaultProject/Template/Code/server_dependencies.cmake b/Templates/DefaultProject/Template/Code/enabled_gems.cmake similarity index 70% rename from Templates/DefaultProject/Template/Code/server_dependencies.cmake rename to Templates/DefaultProject/Template/Code/enabled_gems.cmake index 3982bbb166..dfb7d93233 100644 --- a/Templates/DefaultProject/Template/Code/server_dependencies.cmake +++ b/Templates/DefaultProject/Template/Code/enabled_gems.cmake @@ -9,8 +9,20 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # {END_LICENSE} -set(GEM_DEPENDENCIES +set(ENABLED_GEMS Project::${Name} - Gem::Maestro - Gem::LmbrCentral + Atom_AtomBridge + Camera + CameraFramework + EditorPythonBindings + EMotionFX + GradientSignal + ImGui + LmbrCentral + LyShine + Maestro + NvCloth + SceneProcessing + TextureAtlas + WhiteBox ) diff --git a/Templates/DefaultProject/Template/Code/runtime_dependencies.cmake b/Templates/DefaultProject/Template/Code/runtime_dependencies.cmake deleted file mode 100644 index ce8df8152d..0000000000 --- a/Templates/DefaultProject/Template/Code/runtime_dependencies.cmake +++ /dev/null @@ -1,36 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Project::${Name} - Gem::Maestro - Gem::TextureAtlas - Gem::LmbrCentral - Gem::NvCloth - Gem::LyShine - Gem::Camera - Gem::CameraFramework - Gem::Atom_RHI.Private - Gem::EMotionFX - Gem::Atom_RPI.Private - Gem::Atom_Feature_Common - Gem::ImGui - Gem::Atom_Bootstrap - Gem::Atom_Component_DebugCamera - Gem::AtomImGuiTools - Gem::AtomLyIntegration_CommonFeatures - Gem::EMotionFX_Atom - Gem::ImguiAtom - Gem::Atom_AtomBridge - Gem::GradientSignal - Gem::AtomFont - Gem::WhiteBox -) diff --git a/Templates/DefaultProject/Template/Code/tool_dependencies.cmake b/Templates/DefaultProject/Template/Code/tool_dependencies.cmake deleted file mode 100644 index 010d45bd0f..0000000000 --- a/Templates/DefaultProject/Template/Code/tool_dependencies.cmake +++ /dev/null @@ -1,43 +0,0 @@ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Project::${Name} - Gem::Maestro.Editor - Gem::TextureAtlas - Gem::LmbrCentral.Editor - Gem::NvCloth.Editor - Gem::LyShine.Editor - Gem::SceneProcessing.Editor - Gem::EditorPythonBindings.Editor - Gem::Camera.Editor - Gem::CameraFramework - Gem::Atom_RHI.Private - Gem::EMotionFX.Editor - Gem::Atom_RPI.Builders - Gem::Atom_RPI.Editor - Gem::Atom_Feature_Common.Builders - Gem::Atom_Feature_Common.Editor - Gem::ImGui.Editor - Gem::Atom_Bootstrap - Gem::Atom_Asset_Shader.Builders - Gem::Atom_Component_DebugCamera - Gem::AtomImGuiTools - Gem::AtomLyIntegration_CommonFeatures.Editor - Gem::EMotionFX_Atom.Editor - Gem::ImageProcessingAtom.Editor - Gem::Atom_AtomBridge.Editor - Gem::ImguiAtom - Gem::AtomFont - Gem::AtomToolsFramework.Editor - Gem::GradientSignal.Editor - Gem::WhiteBox.Editor -) diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index 56278a6b04..7add7e34f7 100644 --- a/Templates/DefaultProject/template.json +++ b/Templates/DefaultProject/template.json @@ -66,24 +66,6 @@ "isTemplated": true, "isOptional": false }, - { - "file": "Code/Platform/Android/android_runtime_dependencies.cmake", - "origin": "Code/Platform/Android/android_runtime_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Android/android_server_dependencies.cmake", - "origin": "Code/Platform/Android/android_server_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Android/android_tool_dependencies.cmake", - "origin": "Code/Platform/Android/android_tool_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, { "file": "Code/Platform/Linux/${NameLower}_linux_files.cmake", "origin": "Code/Platform/Linux/${NameLower}_linux_files.cmake", @@ -102,24 +84,6 @@ "isTemplated": true, "isOptional": false }, - { - "file": "Code/Platform/Linux/linux_runtime_dependencies.cmake", - "origin": "Code/Platform/Linux/linux_runtime_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Linux/linux_server_dependencies.cmake", - "origin": "Code/Platform/Linux/linux_server_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Linux/linux_tool_dependencies.cmake", - "origin": "Code/Platform/Linux/linux_tool_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, { "file": "Code/Platform/Mac/${NameLower}_mac_files.cmake", "origin": "Code/Platform/Mac/${NameLower}_mac_files.cmake", @@ -138,24 +102,6 @@ "isTemplated": true, "isOptional": false }, - { - "file": "Code/Platform/Mac/mac_runtime_dependencies.cmake", - "origin": "Code/Platform/Mac/mac_runtime_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Mac/mac_server_dependencies.cmake", - "origin": "Code/Platform/Mac/mac_server_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Mac/mac_tool_dependencies.cmake", - "origin": "Code/Platform/Mac/mac_tool_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, { "file": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", "origin": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", @@ -174,24 +120,6 @@ "isTemplated": true, "isOptional": false }, - { - "file": "Code/Platform/Windows/windows_runtime_dependencies.cmake", - "origin": "Code/Platform/Windows/windows_runtime_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Windows/windows_server_dependencies.cmake", - "origin": "Code/Platform/Windows/windows_server_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/Windows/windows_tool_dependencies.cmake", - "origin": "Code/Platform/Windows/windows_tool_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, { "file": "Code/Platform/iOS/${NameLower}_ios_files.cmake", "origin": "Code/Platform/iOS/${NameLower}_ios_files.cmake", @@ -210,24 +138,6 @@ "isTemplated": true, "isOptional": false }, - { - "file": "Code/Platform/iOS/ios_runtime_dependencies.cmake", - "origin": "Code/Platform/iOS/ios_runtime_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/iOS/ios_server_dependencies.cmake", - "origin": "Code/Platform/iOS/ios_server_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/Platform/iOS/ios_tool_dependencies.cmake", - "origin": "Code/Platform/iOS/ios_tool_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, { "file": "Code/Source/${Name}Module.cpp", "origin": "Code/Source/${Name}Module.cpp", @@ -247,20 +157,8 @@ "isOptional": false }, { - "file": "Code/runtime_dependencies.cmake", - "origin": "Code/runtime_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/server_dependencies.cmake", - "origin": "Code/server_dependencies.cmake", - "isTemplated": true, - "isOptional": false - }, - { - "file": "Code/tool_dependencies.cmake", - "origin": "Code/tool_dependencies.cmake", + "file": "Code/enabled_gems.cmake", + "origin": "Code/enabled_gems.cmake", "isTemplated": true, "isOptional": false }, diff --git a/cmake/Gems.cmake b/cmake/Gems.cmake index 3e9ce97329..caa5b74c93 100644 --- a/cmake/Gems.cmake +++ b/cmake/Gems.cmake @@ -84,6 +84,7 @@ endfunction() # note that it can't do this immediately, so it saves the data for later processing. # Note: If you don't supply a project name, it will apply it across the board to all projects. # this is useful in the case of "ly_add_gems being called for so called 'mandatory gems' inside the engine. +# if you specify a gem name with a namespace, it will be used, otherwise it will assume Gem:: function(ly_enable_gems) set(options) set(oneValueArgs PROJECT_NAME GEM_FILE) @@ -176,19 +177,24 @@ function(ly_enable_gems_delayed) # apply the list of gem targets. Adding a gem really just means adding the appropriate dependency. foreach(gem_name ${gem_dependencies}) + # the gem name may already have a namespace. If it does, we use that one + ly_strip_target_namespace(TARGET ${gem_name} OUTPUT_VARIABLE unaliased_gem_name) + if (${unaliased_gem_name} STREQUAL ${gem_name}) + # if stripping a namespace had no effect, it had no namespace + # and we supply the default Gem:: namespace. + set(gem_name_with_namespace Gem::${gem_name}) + else() + # if stripping the namespace had an effect then we use the original + # with the namespace, instead of assuming Gem:: + set(gem_name_with_namespace ${gem_name}) + endif() - if (TARGET Gem::${gem_name}.${variant}) + # if the target exists, add it. + if (TARGET ${gem_name_with_namespace}.${variant}) ly_add_target_dependencies( ${PREFIX_CLAUSE} TARGETS ${target} - DEPENDENT_TARGETS Gem::${gem_name}.${variant} - ) - elseif(${variant} STREQUAL "Client" AND TARGET Gem::${gem_name}) - # Client can also be 'empty' for backward compatibility - ly_add_target_dependencies( - ${PREFIX_CLAUSE} - TARGETS ${target} - DEPENDENT_TARGETS Gem::${gem_name} + DEPENDENT_TARGETS ${gem_name_with_namespace}.${variant} ) endif() endforeach() From e886dba77e1a91f11005529c9295ec7e7e7d3ac7 Mon Sep 17 00:00:00 2001 From: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> Date: Thu, 20 May 2021 15:27:54 -0700 Subject: [PATCH 066/140] Update Multiplayer gem to conform to the new standard The multiplayer gem had a naming conflict in it - a module was called "Tools". --- Gems/Multiplayer/Code/CMakeLists.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index 800670ff92..430fe5ca4b 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -80,14 +80,13 @@ ly_add_target( Gem::ImGui.Static ) -# The above "Multiplayer" target is used by clients and servers -# the debug is only used on Clients +# The "Multiplayer" target is used by clients and servers, Debug is used only on clients. ly_create_alias(NAME Multiplayer.Clients NAMESPACE Gem TARGETS Gem::Multiplayer Gem::Multiplayer.Debug) ly_create_alias(NAME Multiplayer.Servers NAMESPACE Gem TARGETS Gem::Multiplayer) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Multiplayer.Tools.Static STATIC + NAME Multiplayer.Builders.Static STATIC NAMESPACE Gem FILES_CMAKE multiplayer_tools_files.cmake @@ -107,10 +106,12 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Multiplayer.Static ) + # by naming this target Multiplayer.Builders it ensures that it is loaded + # in any pipeline tools (Like Asset Processor, AssetBuilder, etc) ly_add_target( - NAME Multiplayer.Tools MODULE + NAME Multiplayer.Builders GEM_MODULE NAMESPACE Gem - OUTPUT_NAME Gem.Multiplayer.Tools + OUTPUT_NAME Gem.Multiplayer.Builders FILES_CMAKE multiplayer_tools_files.cmake INCLUDE_DIRECTORIES @@ -121,7 +122,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Include BUILD_DEPENDENCIES PRIVATE - Gem::Multiplayer.Tools.Static + Gem::Multiplayer.Builders.Static ) ly_add_target( @@ -148,12 +149,11 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzNetworking AZ::AzToolsFramework Gem::Multiplayer.Static - Gem::Multiplayer.Tools + Gem::Multiplayer.Builders ) - # use the Multiplayer.Editor module in tools and builders. Tools also get the visual debug view - ly_create_alias(NAME Multiplayer.Tools NAMESPACE Gem TARGETS Gem::Multiplayer.Editor Gem::Multiplayer.Debug Gem::Multiplayer.PrefabProcessor) - ly_create_alias(NAME Multiplayer.Builders NAMESPACE Gem TARGETS Gem::Multiplayer.Editor Gem::Multiplayer.PrefabProcessor) + # use the Multiplayer.Editor module in tools like the Editor: Such tools also get the visual debug view: + ly_create_alias(NAME Multiplayer.Tools NAMESPACE Gem TARGETS Gem::Multiplayer.Editor Gem::Multiplayer.Debug) endif() if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) @@ -181,7 +181,7 @@ if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Multiplayer.Tools.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAME Multiplayer.Builders.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} NAMESPACE Gem FILES_CMAKE multiplayer_tools_tests_files.cmake @@ -195,10 +195,10 @@ if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest AZ::AzTestShared AZ::AzToolsFrameworkTestCommon - Gem::Multiplayer.Tools.Static + Gem::Multiplayer.Builders.Static ) ly_add_googletest( - NAME Gem::Multiplayer.Tools.Tests + NAME Gem::Multiplayer.Builders.Tests ) endif() From a9bc8e943d13caa3c05107126b32b6cc086def34 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 May 2021 01:58:54 -0500 Subject: [PATCH 067/140] Refactored the o3de registration.py script into several files which each contains the implementation of a subparser command. Updated the register command to be not register engine gems, templates, projects and external subdirectories to the o3de_manifest Updated the register-show command to be able to read the engine's gems, templates, projects and external subdirectories from the engine.json file --- scripts/o3de.py | 2 +- .../o3de/o3de/add_external_subdirectory.py | 140 + scripts/o3de/o3de/add_gem_cmake.py | 114 + scripts/o3de/o3de/add_gem_project.py | 311 ++ scripts/o3de/o3de/cmake.py | 234 + scripts/o3de/o3de/download.py | 598 +++ scripts/o3de/o3de/engine_template.py | 178 +- scripts/o3de/o3de/get_registration.py | 62 + scripts/o3de/o3de/global_project.py | 12 +- scripts/o3de/o3de/manifest.py | 600 +++ scripts/o3de/o3de/print_registration.py | 456 ++ scripts/o3de/o3de/register.py | 1066 ++++ scripts/o3de/o3de/registration.py | 4383 +---------------- .../o3de/o3de/remove_external_subdirectory.py | 73 + scripts/o3de/o3de/remove_gem_cmake.py | 89 + scripts/o3de/o3de/remove_gem_project.py | 270 + scripts/o3de/o3de/repo.py | 291 ++ scripts/o3de/o3de/sha256.py | 82 + scripts/o3de/o3de/utils.py | 25 + scripts/o3de/o3de/validation.py | 103 + .../o3de/tests/unit_test_add_remove_gem.py | 4 +- scripts/o3de/tests/unit_test_registration.py | 14 +- 22 files changed, 4641 insertions(+), 4466 deletions(-) create mode 100644 scripts/o3de/o3de/add_external_subdirectory.py create mode 100644 scripts/o3de/o3de/add_gem_cmake.py create mode 100644 scripts/o3de/o3de/add_gem_project.py create mode 100644 scripts/o3de/o3de/cmake.py create mode 100644 scripts/o3de/o3de/download.py create mode 100644 scripts/o3de/o3de/get_registration.py create mode 100644 scripts/o3de/o3de/manifest.py create mode 100644 scripts/o3de/o3de/print_registration.py create mode 100644 scripts/o3de/o3de/register.py create mode 100644 scripts/o3de/o3de/remove_external_subdirectory.py create mode 100644 scripts/o3de/o3de/remove_gem_cmake.py create mode 100644 scripts/o3de/o3de/remove_gem_project.py create mode 100644 scripts/o3de/o3de/repo.py create mode 100644 scripts/o3de/o3de/sha256.py create mode 100644 scripts/o3de/o3de/validation.py diff --git a/scripts/o3de.py b/scripts/o3de.py index 7bc1c4a9fb..d3b877620f 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -18,7 +18,7 @@ import sys # So the current script directory is removed from the sys.path temporary SCRIPT_DIR_REMOVED = False SCRIPT_DIR = pathlib.Path(__file__).parent.resolve() -if str(SCRIPT_DIR) in sys.path: +while str(SCRIPT_DIR) in sys.path: SCRIPT_DIR_REMOVED = True sys.path.remove(str(SCRIPT_DIR)) diff --git a/scripts/o3de/o3de/add_external_subdirectory.py b/scripts/o3de/o3de/add_external_subdirectory.py new file mode 100644 index 0000000000..15dc5163c5 --- /dev/null +++ b/scripts/o3de/o3de/add_external_subdirectory.py @@ -0,0 +1,140 @@ +# +# 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. +# +""" +Contains command to add a gem to a project's cmake scripts +""" + +import argparse +import logging +import pathlib + +from o3de import manifest + +logger = logging.getLogger() +logging.basicConfig() + +def add_external_subdirectory(external_subdir: str or pathlib.Path, + engine_path: str or pathlib.Path = None, + suppress_errors: bool = False) -> int: + """ + add external subdirectory to a cmake + :param external_subdir: external subdirectory to add to cmake + :param engine_path: optional engine path, defaults to this engine + :param suppress_errors: optional silence errors + :return: 0 for success or non 0 failure code + """ + external_subdir = pathlib.Path(external_subdir).resolve() + if not external_subdir.is_dir(): + if not suppress_errors: + logger.error(f'Add External Subdirectory Failed: {external_subdir} does not exist.') + return 1 + + external_subdir_cmake = external_subdir / 'CMakeLists.txt' + if not external_subdir_cmake.is_file(): + if not suppress_errors: + logger.error(f'Add External Subdirectory Failed: {external_subdir} does not contain a CMakeLists.txt.') + return 1 + + json_data = manifest.load_o3de_manifest() + engine_object = manifest.find_engine_data(json_data, engine_path) + if not engine_object: + if not suppress_errors: + logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') + return 1 + + while external_subdir.as_posix() in engine_object['external_subdirectories']: + engine_object['external_subdirectories'].remove(external_subdir.as_posix()) + + def parse_cmake_file(cmake: str or pathlib.Path, + files: set): + cmake_path = pathlib.Path(cmake).resolve() + cmake_file = cmake_path + if cmake_path.is_dir(): + files.add(cmake_path) + cmake_file = cmake_path / 'CMakeLists.txt' + elif cmake_path.is_file(): + cmake_path = cmake_path.parent + else: + return + + with cmake_file.open('r') as s: + lines = s.readlines() + for line in lines: + line = line.strip() + start = line.find('include(') + if start == 0: + end = line.find(')', start) + if end > start + len('include('): + try: + include_cmake_file = pathlib.Path(engine_path / line[start + len('include('): end]).resolve() + except Exception as e: + pass + else: + parse_cmake_file(include_cmake_file, files) + else: + start = line.find('add_subdirectory(') + if start == 0: + end = line.find(')', start) + if end > start + len('add_subdirectory('): + try: + include_cmake_file = pathlib.Path( + cmake_path / line[start + len('add_subdirectory('): end]).resolve() + except Exception as e: + pass + else: + parse_cmake_file(include_cmake_file, files) + + cmake_files = set() + parse_cmake_file(engine_path, cmake_files) + for external in engine_object["external_subdirectories"]: + parse_cmake_file(external, cmake_files) + + if external_subdir in cmake_files: + manifest.save_o3de_manifest(json_data) + if not suppress_errors: + logger.error(f'External subdirectory {external_subdir.as_posix()} already included by add_subdirectory().') + return 1 + + engine_object['external_subdirectories'].insert(0, external_subdir.as_posix()) + engine_object['external_subdirectories'] = sorted(engine_object['external_subdirectories']) + + manifest.save_o3de_manifest(json_data) + + return 0 + + +def _run_add_external_subdirectory(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + return add_external_subdirectory(args.external_subdirectory) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + add_external_subdirectory_subparser = subparsers.add_parser('add-external-subdirectory') + add_external_subdirectory_subparser.add_argument('external_subdirectory', metavar='external_subdirectory', type=str, + help='add an external subdirectory to cmake') + + add_external_subdirectory_subparser.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.') + + add_external_subdirectory_subparser.set_defaults(func=_run_add_external_subdirectory) + diff --git a/scripts/o3de/o3de/add_gem_cmake.py b/scripts/o3de/o3de/add_gem_cmake.py new file mode 100644 index 0000000000..fa2d2f4bb3 --- /dev/null +++ b/scripts/o3de/o3de/add_gem_cmake.py @@ -0,0 +1,114 @@ +# +# 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. +# +""" +Contains command to add a gem to a project's cmake scripts +""" + +import argparse +import logging +import pathlib + +from o3de import add_external_subdirectory, manifest, validation + +logger = logging.getLogger() +logging.basicConfig() + +def add_gem_to_cmake(gem_name: str = None, + gem_path: str or pathlib.Path = None, + engine_name: str = None, + engine_path: str or pathlib.Path = None, + suppress_errors: bool = False) -> int: + """ + add a gem to a cmake as an external subdirectory for an engine + :param gem_name: name of the gem to add to cmake + :param gem_path: the path of the gem to add to cmake + :param engine_name: name of the engine to add to cmake + :param engine_path: the path of the engine to add external subdirectory to, default to this engine + :param suppress_errors: optional silence errors + :return: 0 for success or non 0 failure code + """ + if not gem_name and not gem_path: + if not suppress_errors: + logger.error('Must specify either a Gem name or Gem Path.') + return 1 + + if gem_name and not gem_path: + gem_path = manifest.get_registered(gem_name=gem_name) + + if not gem_path: + if not suppress_errors: + logger.error(f'Gem Path {gem_path} has not been registered.') + return 1 + + gem_path = pathlib.Path(gem_path).resolve() + gem_json = gem_path / 'gem.json' + if not gem_json.is_file(): + if not suppress_errors: + logger.error(f'Gem json {gem_json} is not present.') + return 1 + if not validation.valid_o3de_gem_json(gem_json): + if not suppress_errors: + logger.error(f'Gem json {gem_json} is not valid.') + return 1 + + if not engine_name and not engine_path: + engine_path = manifest.get_this_engine_path() + + if engine_name and not engine_path: + engine_path = manifest.get_registered(engine_name=engine_name) + + if not engine_path: + if not suppress_errors: + logger.error(f'Engine Path {engine_path} has not been registered.') + return 1 + + engine_json = engine_path / 'engine.json' + if not engine_json.is_file(): + if not suppress_errors: + logger.error(f'Engine json {engine_json} is not present.') + return 1 + if not validation.valid_o3de_engine_json(engine_json): + if not suppress_errors: + logger.error(f'Engine json {engine_json} is not valid.') + return 1 + + return add_external_subdirectory.add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path, suppress_errors=suppress_errors) + + +def _run_add_gem_to_cmake(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + return add_gem_to_cmake(gem_name=args.gem_name, gem_path=args.gem_path) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + add_gem_to_cmake_subparser = subparsers.add_parser('add-gem-to-cmake') + group = add_gem_to_cmake_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-gp', '--gem-path', type=str, required=False, + help='The path to the gem.') + group.add_argument('-gn', '--gem-name', type=str, required=False, + help='The name of the gem.') + + add_gem_to_cmake_subparser.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.') + + add_gem_to_cmake_subparser.set_defaults(func=_run_add_gem_to_cmake) diff --git a/scripts/o3de/o3de/add_gem_project.py b/scripts/o3de/o3de/add_gem_project.py new file mode 100644 index 0000000000..933fd019bb --- /dev/null +++ b/scripts/o3de/o3de/add_gem_project.py @@ -0,0 +1,311 @@ +# +# 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. +# +""" +Contains command to add a gem to a project's cmake scripts +""" + +import argparse +import json +import logging +import os +import pathlib + +from o3de import add_gem_cmake, cmake, manifest, validation + +logger = logging.getLogger() +logging.basicConfig() + +def add_gem_dependency(cmake_file: str or pathlib.Path, + gem_target: str) -> int: + """ + adds a gem dependency to a cmake file + :param cmake_file: path to the cmake file + :param gem_target: name of the cmake target + :return: 0 for success or non 0 failure code + """ + if not os.path.isfile(cmake_file): + logger.error(f'Failed to locate cmake file {cmake_file}') + return 1 + + # on a line by basis, see if there already is Gem::{gem_name} + # find the first occurrence of a gem, copy its formatting and replace + # the gem name with the new one and append it + # if the gem is already present fail + t_data = [] + added = False + with open(cmake_file, 'r') as s: + for line in s: + if f'Gem::{gem_target}' in line: + logger.warning(f'{gem_target} is already a gem dependency.') + return 0 + if not added and r'Gem::' in line: + new_gem = ' ' * line.find(r'Gem::') + f'Gem::{gem_target}\n' + t_data.append(new_gem) + added = True + t_data.append(line) + + # if we didn't add it the set gem dependencies could be empty so + # add a new gem, if empty the correct format is 1 tab=4spaces + if not added: + index = 0 + for line in t_data: + index = index + 1 + if r'set(GEM_DEPENDENCIES' in line: + t_data.insert(index, f' Gem::{gem_target}\n') + added = True + break + + # if we didn't add it then it's not here, add a whole new one + if not added: + t_data.append('\n') + t_data.append('set(GEM_DEPENDENCIES\n') + t_data.append(f' Gem::{gem_target}\n') + t_data.append(')\n') + + # write the cmake + os.unlink(cmake_file) + with open(cmake_file, 'w') as s: + s.writelines(t_data) + + return 0 + + +def add_gem_to_project(gem_name: str = None, + gem_path: str or pathlib.Path = None, + gem_target: str = None, + project_name: str = None, + project_path: str or pathlib.Path = None, + dependencies_file: str or pathlib.Path = None, + runtime_dependency: bool = False, + tool_dependency: bool = False, + server_dependency: bool = False, + platforms: str = 'Common', + add_to_cmake: bool = True) -> int: + """ + add a gem to a project + :param gem_name: name of the gem to add + :param gem_path: path to the gem to add + :param gem_target: the name of the cmake gem module + :param project_name: name of to the project to add the gem to + :param project_path: path to the project to add the gem to + :param dependencies_file: if this dependency goes/is in a specific file + :param runtime_dependency: bool to specify this is a runtime gem for the game + :param tool_dependency: bool to specify this is a tool gem for the editor + :param server_dependency: bool to specify this is a server gem for the server + :param platforms: str to specify common or which specific platforms + :param add_to_cmake: bool to specify that this gem should be added to cmake + :return: 0 for success or non 0 failure code + """ + # we need either a project name or path + if not project_name and not project_path: + logger.error(f'Must either specify a Project path or Project Name.') + return 1 + + # if project name resolve it into a path + if project_name and not project_path: + project_path = manifest.get_registered(project_name=project_name) + project_path = pathlib.Path(project_path).resolve() + if not project_path.is_dir(): + logger.error(f'Project path {project_path} is not a folder.') + return 1 + + # get the engine name this project is associated with + # and resolve that engines path + project_json = project_path / 'project.json' + if not validation.valid_o3de_project_json(project_json): + logger.error(f'Project json {project_json} is not valid.') + return 1 + with project_json.open('r') as s: + try: + project_json_data = json.load(s) + except Exception as e: + logger.error(f'Error loading Project json {project_json}: {str(e)}') + return 1 + else: + try: + engine_name = project_json_data['engine'] + except Exception as e: + logger.error(f'Project json {project_json} "engine" not found: {str(e)}') + return 1 + else: + engine_path = manifest.get_registered(engine_name=engine_name) + if not engine_path: + logger.error(f'Engine {engine_name} is not registered.') + return 1 + + # we need either a gem name or path + if not gem_name and not gem_path: + logger.error(f'Must either specify a Gem path or Gem Name.') + return 1 + + # if gem name resolve it into a path + if gem_name and not gem_path: + gem_path = manifest.get_registered(gem_name=gem_name) + gem_path = pathlib.Path(gem_path).resolve() + # make sure this gem already exists if we're adding. We can always remove a gem. + if not gem_path.is_dir(): + logger.error(f'Gem Path {gem_path} does not exist.') + return 1 + + # if add to cmake, make sure the gem.json exists and valid before we proceed + if add_to_cmake: + gem_json = gem_path / 'gem.json' + if not gem_json.is_file(): + logger.error(f'Gem json {gem_json} is not present.') + return 1 + if not validation.valid_o3de_gem_json(gem_json): + logger.error(f'Gem json {gem_json} is not valid.') + return 1 + + # find all available modules in this gem_path + modules = cmake.get_gem_targets(gem_path=gem_path) + if len(modules) == 0: + logger.error(f'No gem modules found under {gem_path}.') + return 1 + + # if the gem has no modules and the user has specified a target fail + if gem_target and not modules: + logger.error(f'Gem has no targets, but gem target {gem_target} was specified.') + return 1 + + # if the gem target is not in the modules + if gem_target not in modules: + logger.error(f'Gem target not in gem modules: {modules}') + return 1 + + if gem_target: + # if the user has not specified either we will assume they meant the most common which is runtime + if not runtime_dependency and not tool_dependency and not server_dependency and not dependencies_file: + logger.warning("Dependency type not specified: Assuming '--runtime-dependency'") + runtime_dependency = True + + ret_val = 0 + + # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags + if dependencies_file: + dependencies_file = pathlib.Path(dependencies_file).resolve() + # make sure this is a project has a dependencies_file + if not dependencies_file.is_file(): + logger.error(f'Dependencies file {dependencies_file} is not present.') + return 1 + # add the dependency + ret_val = add_gem_dependency(dependencies_file, gem_target) + + else: + if ',' in platforms: + platforms = platforms.split(',') + else: + platforms = [platforms] + for platform in platforms: + if runtime_dependency: + # make sure this is a project has a runtime_dependencies.cmake file + project_runtime_dependencies_file = pathlib.Path( + cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', + platform=platform)).resolve() + if not project_runtime_dependencies_file.is_file(): + logger.error(f'Runtime dependencies file {project_runtime_dependencies_file} is not present.') + return 1 + # add the dependency + ret_val = add_gem_dependency(project_runtime_dependencies_file, gem_target) + + if (ret_val == 0) and tool_dependency: + # make sure this is a project has a tool_dependencies.cmake file + project_tool_dependencies_file = pathlib.Path( + cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', + platform=platform)).resolve() + if not project_tool_dependencies_file.is_file(): + logger.error(f'Tool dependencies file {project_tool_dependencies_file} is not present.') + return 1 + # add the dependency + ret_val = add_gem_dependency(project_tool_dependencies_file, gem_target) + + if (ret_val == 0) and server_dependency: + # make sure this is a project has a tool_dependencies.cmake file + project_server_dependencies_file = pathlib.Path( + cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='server', + platform=platform)).resolve() + if not project_server_dependencies_file.is_file(): + logger.error(f'Server dependencies file {project_server_dependencies_file} is not present.') + return 1 + # add the dependency + ret_val = add_gem_dependency(project_server_dependencies_file, gem_target) + + if not ret_val and add_to_cmake: + ret_val = add_gem_cmake.add_gem_to_cmake(gem_path=gem_path, engine_path=engine_path) + + return ret_val + + +def _run_add_gem_to_project(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + return add_gem_to_project(args.gem_name, + args.gem_path, + args.gem_target, + args.project_name, + args.project_path, + args.dependencies_file, + args.runtime_dependency, + args.tool_dependency, + args.server_dependency, + args.platforms, + args.add_to_cmake) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + add_gem_subparser = subparsers.add_parser('add-gem-to-project') + group = add_gem_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-pp', '--project-path', type=str, 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 = add_gem_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-gp', '--gem-path', type=str, required=False, + help='The path to the gem.') + group.add_argument('-gn', '--gem-name', type=str, required=False, + help='The name of the gem.') + add_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, + help='The cmake target name to add. If not specified it will assume gem_name') + add_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, + help='The cmake dependencies file in which the gem dependencies are specified.' + 'If not specified it will assume ') + add_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be added as a runtime dependency') + add_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be added as a tool dependency') + add_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be added as a server dependency') + add_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, + default='Common', + help='Optional list of platforms this gem should be added to.' + ' Ex. --platforms Mac,Windows,Linux') + add_gem_subparser.add_argument('-a', '--add-to-cmake', type=bool, required=False, + default=True, + help='Automatically call add-gem-to-cmake.') + + add_gem_subparser.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.') + + add_gem_subparser.set_defaults(func=_run_add_gem_to_project) diff --git a/scripts/o3de/o3de/cmake.py b/scripts/o3de/o3de/cmake.py new file mode 100644 index 0000000000..b5b28cbb7e --- /dev/null +++ b/scripts/o3de/o3de/cmake.py @@ -0,0 +1,234 @@ +# +# 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. +# +""" +This file contains methods for introspecting data from cmake scripts +""" + +import logging +import os +import pathlib + +from o3de import manifest + +logger = logging.getLogger() +logging.basicConfig() + +def get_project_runtime_gem_targets(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) + + +def get_project_tool_gem_targets(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) + + +def get_project_server_gem_targets(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) + + +def get_project_gem_targets(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + runtime_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) + tool_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) + server_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) + return runtime_gems.union(tool_gems.union(server_gems)) + + +def get_gem_targets_from_cmake_file(cmake_file: str or pathlib.Path) -> set: + """ + Gets a list of declared gem targets dependencies of a cmake file + :param cmake_file: path to the cmake file + :return: set of gem targets found + """ + cmake_file = pathlib.Path(cmake_file).resolve() + + if not cmake_file.is_file(): + logger.error(f'Failed to locate cmake file {cmake_file}') + return set() + + gem_target_set = set() + with cmake_file.open('r') as s: + for line in s: + gem_name = line.split('Gem::') + if len(gem_name) > 1: + # Only take the name as everything leading up to the first '.' if found + # Gem naming conventions will have GemName.Editor, GemName.Server, and GemName + # as different targets of the GemName Gem + gem_target_set.add(gem_name[1].replace('\n', '')) + return gem_target_set + + +def get_project_runtime_gem_names(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) + + +def get_project_tool_gem_names(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) + + +def get_project_server_gem_names(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) + + +def get_project_gem_names(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + runtime_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) + tool_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) + server_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) + return runtime_gem_names.union(tool_gem_names.union(server_gem_names)) + + +def get_gem_names_from_cmake_file(cmake_file: str or pathlib.Path) -> set: + """ + Gets a list of declared gem dependencies of a cmake file + :param cmake_file: path to the cmake file + :return: set of gems found + """ + cmake_file = pathlib.Path(cmake_file).resolve() + + if not cmake_file.is_file(): + logger.error(f'Failed to locate cmake file {cmake_file}') + return set() + + gem_set = set() + with cmake_file.open('r') as s: + for line in s: + gem_name = line.split('Gem::') + if len(gem_name) > 1: + # Only take the name as everything leading up to the first '.' if found + # Gem naming conventions will have GemName.Editor, GemName.Server, and GemName + # as different targets of the GemName Gem + gem_set.add(gem_name[1].split('.')[0].replace('\n', '')) + return gem_set + + +def get_project_runtime_gem_paths(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + gem_names = get_project_runtime_gem_names(project_path, platform) + gem_paths = set() + for gem_name in gem_names: + gem_paths.add(manifest.get_registered(gem_name=gem_name)) + return gem_paths + + +def get_project_tool_gem_paths(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + gem_names = get_project_tool_gem_names(project_path, platform) + gem_paths = set() + for gem_name in gem_names: + gem_paths.add(manifest.get_registered(gem_name=gem_name)) + return gem_paths + + +def get_project_server_gem_paths(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + gem_names = get_project_server_gem_names(project_path, platform) + gem_paths = set() + for gem_name in gem_names: + gem_paths.add(manifest.get_registered(gem_name=gem_name)) + return gem_paths + + +def get_project_gem_paths(project_path: str or pathlib.Path, + platform: str = 'Common') -> set: + gem_names = get_project_gem_names(project_path, platform) + gem_paths = set() + for gem_name in gem_names: + gem_paths.add(manifest.get_registered(gem_name=gem_name)) + return gem_paths + + +def get_dependencies_cmake_file(project_name: str = None, + project_path: str or pathlib.Path = None, + dependency_type: str = 'runtime', + platform: str = 'Common') -> str or None: + """ + get the standard cmake file name for a particular type of dependency + :param gem_name: name of the gem, resolves gem_path + :param gem_path: path of the gem + :return: list of gem targets + """ + if not project_name and not project_path: + logger.error(f'Must supply either a Project Name or Project Path.') + return None + + if project_name and not project_path: + project_path = manifest.get_registered(project_name=project_name) + + project_path = pathlib.Path(project_path).resolve() + + if platform == 'Common': + dependencies_file = f'{dependency_type}_dependencies.cmake' + dependencies_file_path = project_path / 'Gem/Code' / dependencies_file + if dependencies_file_path.is_file(): + return dependencies_file_path + return project_path / 'Code' / dependencies_file + else: + dependencies_file = f'{platform.lower()}_{dependency_type}_dependencies.cmake' + dependencies_file_path = project_path / 'Gem/Code/Platform' / platform / dependencies_file + if dependencies_file_path.is_file(): + return dependencies_file_path + return project_path / 'Code/Platform' / platform / dependencies_file + + +def get_all_gem_targets() -> list: + modules = [] + for gem_path in manifest.get_all_gems(): + this_gems_targets = get_gem_targets(gem_path=gem_path) + modules.extend(this_gems_targets) + return modules + + +def get_gem_targets(gem_name: str = None, + gem_path: str or pathlib.Path = None) -> list: + """ + Finds gem targets in a gem + :param gem_name: name of the gem, resolves gem_path + :param gem_path: path of the gem + :return: list of gem targets + """ + if not gem_name and not gem_path: + return [] + + if gem_name and not gem_path: + gem_path = manifest.get_registered(gem_name=gem_name) + + if not gem_path: + return [] + + gem_path = pathlib.Path(gem_path).resolve() + gem_json = gem_path / 'gem.json' + if not validation.valid_o3de_gem_json(gem_json): + return [] + + module_identifiers = [ + 'MODULE', + 'GEM_MODULE', + '${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}' + ] + modules = [] + for root, dirs, files in os.walk(gem_path): + for file in files: + if file == 'CMakeLists.txt': + with open(os.path.join(root, file), 'r') as s: + for line in s: + trimmed = line.lstrip() + if trimmed.startswith('NAME '): + trimmed = trimmed.rstrip(' \n') + split_trimmed = trimmed.split(' ') + if len(split_trimmed) == 3 and split_trimmed[2] in module_identifiers: + modules.append(split_trimmed[1]) + return modules diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py new file mode 100644 index 0000000000..218463f98b --- /dev/null +++ b/scripts/o3de/o3de/download.py @@ -0,0 +1,598 @@ +# +# 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. +# +""" +This file contains functions for querying paths from ~/.o3de directory +""" + +import argparse +import hashlib +import json +import logging +import pathlib +import shutil +import urllib.parse +import urllib.request + +from o3de import manifest, utils, validation + +logger = logging.getLogger() +logging.basicConfig() + +def download_engine(engine_name: str, + dest_path: str) -> int: + if not dest_path: + dest_path = manifest.get_registered(default_folder='engines') + if not dest_path: + logger.error(f'Destination path not cannot be empty.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True) + + download_path = manifest.get_o3de_download_folder() / 'engines' / engine_name + download_path.mkdir(exist_ok=True) + download_zip_path = download_path / 'engine.zip' + + downloadable_engine_data = get_downloadable(engine_name=engine_name) + if not downloadable_engine_data: + logger.error(f'Downloadable engine {engine_name} not found.') + return 1 + + origin = downloadable_engine_data['origin'] + url = f'{origin}/project.zip' + parsed_uri = urllib.parse.urlparse(url) + + if download_zip_path.is_file(): + logger.warn(f'Project already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Engine zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the engine.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_engine_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised engine you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised engine!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded engine.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the engine.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_engine_folder = dest_path / engine_name + if dest_engine_folder.is_dir(): + utils.backup_folder(dest_engine_folder) + with zipfile.ZipFile(download_zip_path, 'r') as project_zip: + try: + project_zip.extractall(dest_path) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_engine_json = dest_engine_folder / 'engine.json' + if not unzipped_engine_json.is_file(): + logger.error(f'Engine json {unzipped_engine_json} is missing.') + return 1 + + if not validation.valid_o3de_engine_json(unzipped_engine_json): + logger.error(f'Engine json {unzipped_engine_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable engine.json + # then compare it to the engine.json in the zip, they should now be identical + try: + del downloadable_engine_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_engine_data, indent=4).encode('utf8')).hexdigest() + with unzipped_engine_json.open('r') as s: + try: + unzipped_engine_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read engine json {unzipped_engine_json}. Unable to confirm this' + f' is the same template that was advertised.') + return 1 + sha256B = hashlib.sha256(json.dumps(unzipped_engine_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded engine.json does not match' + f' the advertised engine.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def download_project(project_name: str, + dest_path: str or pathlib.Path) -> int: + if not dest_path: + dest_path = manifest.get_registered(default_folder='projects') + if not dest_path: + logger.error(f'Destination path not specified and not default projects path.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True, parents=True) + + download_path = manifest.get_o3de_download_folder() / 'projects' / project_name + download_path.mkdir(exist_ok=True, parents=True) + download_zip_path = download_path / 'project.zip' + + downloadable_project_data = get_downloadable(project_name=project_name) + if not downloadable_project_data: + logger.error(f'Downloadable project {project_name} not found.') + return 1 + + origin = downloadable_project_data['origin'] + url = f'{origin}/project.zip' + parsed_uri = urllib.parse.urlparse(url) + + if download_zip_path.is_file(): + logger.warn(f'Project already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Project zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the project.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_project_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised project you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised project!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded project.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the project.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_project_folder = dest_path / project_name + if dest_project_folder.is_dir(): + utils.backup_folder(dest_project_folder) + with zipfile.ZipFile(download_zip_path, 'r') as project_zip: + try: + project_zip.extractall(dest_project_folder) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_project_json = dest_project_folder / 'project.json' + if not unzipped_project_json.is_file(): + logger.error(f'Project json {unzipped_project_json} is missing.') + return 1 + + if not validation.valid_o3de_project_json(unzipped_project_json): + logger.error(f'Project json {unzipped_project_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable project.json + # then compare it to the project.json in the zip, they should now be identical + try: + del downloadable_project_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_project_data, indent=4).encode('utf8')).hexdigest() + with unzipped_project_json.open('r') as s: + try: + unzipped_project_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read Project json {unzipped_project_json}. Unable to confirm this' + f' is the same project that was advertised.') + return 1 + sha256B = hashlib.sha256(json.dumps(unzipped_project_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded project.json does not match' + f' the advertised project.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def download_gem(gem_name: str, + dest_path: str or pathlib.Path) -> int: + if not dest_path: + dest_path = manifest.get_registered(default_folder='gems') + if not dest_path: + logger.error(f'Destination path not cannot be empty.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True, parents=True) + + download_path = manifest.get_o3de_download_folder() / 'gems' / gem_name + download_path.mkdir(exist_ok=True, parents=True) + download_zip_path = download_path / 'gem.zip' + + downloadable_gem_data = get_downloadable(gem_name=gem_name) + if not downloadable_gem_data: + logger.error(f'Downloadable gem {gem_name} not found.') + return 1 + + origin = downloadable_gem_data['origin'] + url = f'{origin}/gem.zip' + parsed_uri = urllib.parse.urlparse(url) + + if download_zip_path.is_file(): + logger.warn(f'Project already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Gem zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the gem.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_gem_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised gem you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised gem!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded gem.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the gem.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_gem_folder = dest_path / gem_name + if dest_gem_folder.is_dir(): + utils.backup_folder(dest_gem_folder) + with zipfile.ZipFile(download_zip_path, 'r') as gem_zip: + try: + gem_zip.extractall(dest_path) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_gem_json = dest_gem_folder / 'gem.json' + if not unzipped_gem_json.is_file(): + logger.error(f'Engine json {unzipped_gem_json} is missing.') + return 1 + + if not validation.valid_o3de_engine_json(unzipped_gem_json): + logger.error(f'Engine json {unzipped_gem_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable gem.json + # then compare it to the gem.json in the zip, they should now be identical + try: + del downloadable_gem_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_gem_data, indent=4).encode('utf8')).hexdigest() + with unzipped_gem_json.open('r') as s: + try: + unzipped_gem_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read gem json {unzipped_gem_json}. Unable to confirm this' + f' is the same gem that was advertised.') + return 1 + sha256B = hashlib.sha256(json.dumps(unzipped_gem_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded gem.json does not match' + f' the advertised gem.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def download_template(template_name: str, + dest_path: str or pathlib.Path) -> int: + if not dest_path: + dest_path = manifest.get_registered(default_folder='templates') + if not dest_path: + logger.error(f'Destination path not cannot be empty.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True, parents=True) + + download_path = manifest.get_o3de_download_folder() / 'templates' / template_name + download_path.mkdir(exist_ok=True, parents=True) + download_zip_path = download_path / 'template.zip' + + downloadable_template_data = get_downloadable(template_name=template_name) + if not downloadable_template_data: + logger.error(f'Downloadable template {template_name} not found.') + return 1 + + origin = downloadable_template_data['origin'] + url = f'{origin}/project.zip' + parsed_uri = urllib.parse.urlparse(url) + + result = 0 + + if download_zip_path.is_file(): + logger.warn(f'Project already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Template zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the template.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_template_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised template you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised template!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded template.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the template.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_template_folder = dest_path / template_name + if dest_template_folder.is_dir(): + utils.backup_folder(dest_template_folder) + with zipfile.ZipFile(download_zip_path, 'r') as project_zip: + try: + project_zip.extractall(dest_path) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_template_json = dest_template_folder / 'template.json' + if not unzipped_template_json.is_file(): + logger.error(f'Template json {unzipped_template_json} is missing.') + return 1 + + if not validation.valid_o3de_engine_json(unzipped_template_json): + logger.error(f'Template json {unzipped_template_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable template.json + # then compare it to the template.json in the zip, they should now be identical + try: + del downloadable_template_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_template_data, indent=4).encode('utf8')).hexdigest() + with unzipped_template_json.open('r') as s: + try: + unzipped_template_json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read Template json {unzipped_template_json}. Unable to confirm this' + f' is the same template that was advertised.') + return 1 + sha256B = hashlib.sha256(json.dumps(unzipped_template_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded template.json does not match' + f' the advertised template.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def download_restricted(restricted_name: str, + dest_path: str or pathlib.Path) -> int: + if not dest_path: + dest_path = manifest.get_registered(default_folder='restricted') + if not dest_path: + logger.error(f'Destination path not cannot be empty.') + return 1 + + dest_path = pathlib.Path(dest_path).resolve() + dest_path.mkdir(exist_ok=True, parents=True) + + download_path = manifest.get_o3de_download_folder() / 'restricted' / restricted_name + download_path.mkdir(exist_ok=True, parents=True) + download_zip_path = download_path / 'restricted.zip' + + downloadable_restricted_data = get_downloadable(restricted_name=restricted_name) + if not downloadable_restricted_data: + logger.error(f'Downloadable Restricted {restricted_name} not found.') + return 1 + + origin = downloadable_restricted_data['origin'] + url = f'{origin}/restricted.zip' + parsed_uri = urllib.parse.urlparse(url) + + if download_zip_path.is_file(): + logger.warn(f'Restricted already downloaded to {download_zip_path}.') + elif parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(url) as s: + with download_zip_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_zip_path) + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"Restricted zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + # if the restricted.json has a sha256 check it against a sha256 of the zip + try: + sha256A = downloadable_restricted_data['sha256'] + except Exception as e: + logger.warn(f'SECURITY WARNING: The advertised restricted you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised restricted!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded restricted.zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the restricted.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + dest_restricted_folder = dest_path / restricted_name + if dest_restricted_folder.is_dir(): + utils.backup_folder(dest_restricted_folder) + with zipfile.ZipFile(download_zip_path, 'r') as project_zip: + try: + project_zip.extractall(dest_path) + except Exception as e: + logger.error(f'UnZip exception:{str(e)}') + shutil.rmtree(dest_path) + return 1 + + unzipped_restricted_json = dest_restricted_folder / 'restricted.json' + if not unzipped_restricted_json.is_file(): + logger.error(f'Restricted json {unzipped_restricted_json} is missing.') + return 1 + + if not validation.valid_o3de_engine_json(unzipped_restricted_json): + logger.error(f'Restricted json {unzipped_restricted_json} is invalid.') + return 1 + + # remove the sha256 if present in the advertised downloadable restricted.json + # then compare it to the restricted.json in the zip, they should now be identical + try: + del downloadable_restricted_data['sha256'] + except Exception as e: + pass + + sha256A = hashlib.sha256(json.dumps(downloadable_restricted_data, indent=4).encode('utf8')).hexdigest() + with unzipped_restricted_json.open('r') as s: + try: + unzipped_restricted_json_data = json.load(s) + except Exception as e: + logger.error( + f'Failed to read Restricted json {unzipped_restricted_json}. Unable to confirm this' + f' is the same restricted that was advertised.') + return 1 + sha256B = hashlib.sha256( + json.dumps(unzipped_restricted_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded restricted.json does not match' + f' the advertised restricted.json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def _run_download(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + if args.engine_name: + return download_engine(args.engine_name, + args.dest_path) + elif args.project_name: + return download_project(args.project_name, + args.dest_path) + elif args.gem_nanme: + return download_gem(args.gem_name, + args.dest_path) + elif args.template_name: + return download_template(args.template_name, + args.dest_path) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + download_subparser = subparsers.add_parser('download') + group = download_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-e', '--engine-name', type=str, required=False, + help='Downloadable engine name.') + group.add_argument('-p', '--project-name', type=str, required=False, + help='Downloadable project name.') + group.add_argument('-g', '--gem-name', type=str, required=False, + help='Downloadable gem name.') + group.add_argument('-t', '--template-name', type=str, required=False, + help='Downloadable template name.') + download_subparser.add_argument('-dp', '--dest-path', type=str, required=False, + default=None, + help='Optional destination folder to download into.' + ' i.e. download --project-name "StarterGame" --dest-path "C:/projects"' + ' will result in C:/projects/StarterGame' + ' If blank will download to default object type folder') + + download_subparser.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.') + + download_subparser.set_defaults(func=_run_download) + diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index 23acab33d4..ec390be480 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -21,7 +21,7 @@ import uuid import re -from o3de import utils, registration +from o3de import manifest, validation, utils logger = logging.getLogger() logging.basicConfig() @@ -321,7 +321,7 @@ def _instantiate_template(template_json_data: dict, platform_json = f'{template_restricted_platform_path_rel}/{template_file_name}'.replace('//', '/') if os.path.isfile(platform_json): - if not registration.valid_o3de_template_json(platform_json): + if not validation.valid_o3de_template_json(platform_json): logger.error(f'Template json {platform_json} is invalid.') return 1 @@ -403,7 +403,7 @@ def create_template(source_path: str, template_path = source_name template_path = template_path.replace('\\', '/') if not os.path.isabs(template_path): - default_templates_folder = registration.get_registered(default_folder='templates') + default_templates_folder = manifest.get_registered(default_folder='templates') template_path = f'{default_templates_folder}/{template_path}' logger.info(f'Template path not a full path. Using default templates folder {template_path}') if os.path.isdir(template_path): @@ -419,14 +419,14 @@ def create_template(source_path: str, return 1 if source_restricted_name and not source_restricted_path: - source_restricted_path = registration.get_registered(restricted_name=source_restricted_name) + source_restricted_path = manifest.get_registered(restricted_name=source_restricted_name) # source_restricted_path if source_restricted_path: source_restricted_path = source_restricted_path.replace('\\', '/') if not os.path.isabs(source_restricted_path): - engine_json = f'{registration.get_this_engine_path()}/engine.json' - if not registration.valid_o3de_engine_json(engine_json): + engine_json = f'{manifest.get_this_engine_path()}/engine.json' + if not validation.valid_o3de_engine_json(engine_json): logger.error(f"Engine json {engine_json} is not valid.") return 1 with open(engine_json) as s: @@ -436,11 +436,11 @@ def create_template(source_path: str, logger.error(f"Failed to read engine json {engine_json}: {str(e)}") return 1 try: - engine_restricted = engine_json_data['restricted'] + engine_restricted = engine_json_data['restricted_name'] except Exception as e: logger.error(f"Engine json {engine_json} restricted not found.") return 1 - engine_restricted_folder = registration.get_registered(restricted_name=engine_restricted) + engine_restricted_folder = manifest.get_registered(restricted_name=engine_restricted) new_source_restricted_path = f'{engine_restricted_folder}/{source_restricted_path}' logger.info(f'Source restricted path {source_restricted_path} not a full path. We must assume this engines' f' restricted folder {new_source_restricted_path}') @@ -449,7 +449,7 @@ def create_template(source_path: str, return 1 if template_restricted_name and not template_restricted_path: - template_restricted_path = registration.get_registered(restricted_name=template_restricted_name) + template_restricted_path = manifest.get_registered(restricted_name=template_restricted_name) if not template_restricted_name: template_restricted_name = template_name @@ -458,7 +458,7 @@ def create_template(source_path: str, if template_restricted_path: template_restricted_path = template_restricted_path.replace('\\', '/') if not os.path.isabs(template_restricted_path): - default_templates_restricted_folder = registration.get_registered(restricted_name='templates') + default_templates_restricted_folder = manifest.get_registered(restricted_name='templates') new_template_restricted_path = f'{default_templates_restricted_folder}/{template_restricted_path}' logger.info(f'Template restricted path {template_restricted_path} not a full path. We must assume the' f' default templates restricted folder {new_template_restricted_path}') @@ -466,10 +466,10 @@ def create_template(source_path: str, if os.path.isdir(template_restricted_path): # see if this is already a restricted path, if it is get the "restricted_name" from the restricted json - # so we can set "restricted" to it for this template + # so we can set "restricted_name" to it for this template restricted_json = f'{template_restricted_path}/restricted.json' if os.path.isfile(restricted_json): - if not registration.valid_o3de_restricted_json(restricted_json): + if not validation.valid_o3de_restricted_json(restricted_json): logger.error(f'{restricted_json} is not valid.') return 1 with open(restricted_json, 'r') as s: @@ -928,7 +928,7 @@ def create_template(source_path: str, json_data.update({'user_tags': [f"{template_name}"]}) json_data.update({'icon_path': "preview.png"}) if template_restricted_path: - json_data.update({'restricted': template_restricted_name}) + json_data.update({'restricted_name': template_restricted_name}) if template_restricted_platform_relative_path != '': json_data.update({'template_restricted_platform_relative_path': template_restricted_platform_relative_path}) json_data.update({'copyFiles': copy_files}) @@ -1048,7 +1048,7 @@ def create_from_template(destination_path: str, return 1 if template_name: - template_path = registration.get_registered(template_name=template_name) + template_path = manifest.get_registered(template_name=template_name) if not os.path.isdir(template_path): logger.error(f'Could not find the template {template_name}=>{template_path}') @@ -1059,7 +1059,7 @@ def create_from_template(destination_path: str, # the template.json should be in the template_path, make sure it's there a nd valid template_json = f'{template_path}/template.json' - if not registration.valid_o3de_template_json(template_json): + if not validation.valid_o3de_template_json(template_json): logger.error(f'Template json {template_path} is invalid.') return 1 @@ -1082,57 +1082,57 @@ def create_from_template(destination_path: str, # see if the template itself specifies a restricted name if not template_restricted_name and not template_restricted_path: try: - template_json_restricted_name = template_json_data['restricted'] + template_json_restricted_name = template_json_data['restricted_name'] except Exception as e: - # the template json doesn't have a 'restricted' element warn and use it - logger.info(f'The template does not specify a "restricted".') + # the template json doesn't have a 'restricted_name' element warn and use it + logger.info(f'The template does not specify a "restricted_name".') else: template_restricted_name = template_json_restricted_name # if no restricted name or path we continue on as if there is no template restricted files. if template_restricted_name or template_restricted_path: # If the user specified a --template-restricted-name we need to check that against the templates - # 'restricted' if it has one and see if they match. If they match then we don't have a problem. + # 'restricted_name' if it has one and see if they match. If they match then we don't have a problem. # If they don't then we error out. If supplied but not present in the template we warn and use it. # If not supplied we set what's in the template. If not supplied and not in the template we continue # on as if there is no template restricted files. if template_restricted_name: # The user specified a --template-restricted-name try: - template_json_restricted_name = template_json_data['restricted'] + template_json_restricted_name = template_json_data['restricted_name'] except Exception as e: - # the template json doesn't have a 'restricted' element warn and use it - logger.info(f'The template does not specify a "restricted".' + # the template json doesn't have a 'restricted_name' element warn and use it + logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_name}') else: if template_json_restricted_name != template_restricted_name: logger.error( f'The supplied --template-restricted-name {template_restricted_name} does not match the' - f' templates "restricted". Either the the --template-restricted-name is incorrect or the' - f' templates "restricted" is wrong. Note that since this template specifies "restricted" as' + f' templates "restricted_name". Either the the --template-restricted-name is incorrect or the' + f' templates "restricted_name" is wrong. Note that since this template specifies "restricted_name" as' f' {template_json_restricted_name}, --template-restricted-name need not be supplied.') - template_restricted_path = registration.get_registered(restricted_name=template_restricted_name) + template_restricted_path = manifest.get_registered(restricted_name=template_restricted_name) else: # The user has supplied the --template-restricted-path, see if that matches the template specifies. # If it does then we do not have a problem. If it doesn't match then error out. If not specified # in the template then warn and use the --template-restricted-path template_restricted_path = template_restricted_path.replace('\\', '/') try: - template_json_restricted_name = template_json_data['restricted'] + template_json_restricted_name = template_json_data['restricted_name'] except Exception as e: - # the template json doesn't have a 'restricted' element warn and use it - logger.info(f'The template does not specify a "restricted".' + # the template json doesn't have a 'restricted_name' element warn and use it + logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_path}') else: - template_json_restricted_path = registration.get_registered( + template_json_restricted_path = manifest.get_registered( restricted_name=template_json_restricted_name) if template_json_restricted_path != template_restricted_path: logger.error( f'The supplied --template-restricted-path {template_restricted_path} does not match the' - f' templates "restricted" {template_restricted_name} => {template_json_restricted_path}.' + f' templates "restricted_name" {template_restricted_name} => {template_json_restricted_path}.' f' Either the the supplied --template-restricted-path is incorrect or the templates' - f' "restricted" is wrong. Note that since this template specifies "restricted" as' + f' "restricted_name" is wrong. Note that since this template specifies "restricted_name" as' f' {template_json_restricted_name} --template-restricted-path need not be supplied' f' and {template_json_restricted_path} will be used.') return 1 @@ -1203,19 +1203,19 @@ def create_from_template(destination_path: str, # destination restricted name if destination_restricted_name: - destination_restricted_path = registration.get_registered(restricted_name=destination_restricted_name) + destination_restricted_path = manifest.get_registered(restricted_name=destination_restricted_name) # destination restricted path elif destination_restricted_path: destination_restricted_path = destination_restricted_path.replace('\\', '/') if os.path.isabs(destination_restricted_path): - restricted_default_path = registration.get_registered(default='restricted') + restricted_default_path = manifest.get_registered(default='restricted') new_destination_restricted_path = f'{restricted_default_path}/{destination_restricted_path}' logger.info(f'{destination_restricted_path} is not a full path, making it relative' f' to default restricted path = {new_destination_restricted_path}') destination_restricted_path = new_destination_restricted_path elif template_restricted_path: - restricted_default_path = registration.get_registered(default='restricted') + restricted_default_path = manifest.get_registered(default='restricted') logger.info(f'--destination-restricted-path is not specified, using default restricted path / destination name' f' = {restricted_default_path}') destination_restricted_path = restricted_default_path @@ -1337,7 +1337,7 @@ def create_project(project_path: str, template_name = 'DefaultProject' if template_name and not template_path: - template_path = registration.get_registered(template_name=template_name) + template_path = manifest.get_registered(template_name=template_name) if not os.path.isdir(template_path): logger.error(f'Could not find the template {template_name}=>{template_path}') @@ -1348,7 +1348,7 @@ def create_project(project_path: str, # the template.json should be in the template_path, make sure it's there and valid template_json = f'{template_path}/template.json' - if not registration.valid_o3de_template_json(template_json): + if not validation.valid_o3de_template_json(template_json): logger.error(f'Template json {template_path} is not valid.') return 1 @@ -1371,57 +1371,57 @@ def create_project(project_path: str, # see if the template itself specifies a restricted name if not template_restricted_name and not template_restricted_path: try: - template_json_restricted_name = template_json_data['restricted'] + template_json_restricted_name = template_json_data['restricted_name'] except Exception as e: - # the template json doesn't have a 'restricted' element warn and use it - logger.info(f'The template does not specify a "restricted".') + # the template json doesn't have a 'restricted_name' element warn and use it + logger.info(f'The template does not specify a "restricted_name".') else: template_restricted_name = template_json_restricted_name # if no restricted name or path we continue on as if there is no template restricted files. if template_restricted_name or template_restricted_path: # If the user specified a --template-restricted-name we need to check that against the templates - # 'restricted' if it has one and see if they match. If they match then we don't have a problem. + # 'restricted_name' if it has one and see if they match. If they match then we don't have a problem. # If they don't then we error out. If supplied but not present in the template we warn and use it. # If not supplied we set what's in the template. If not supplied and not in the template we continue # on as if there is no template restricted files. if template_restricted_name and not template_restricted_path: # The user specified a --template-restricted-name try: - template_json_restricted_name = template_json_data['restricted'] + template_json_restricted_name = template_json_data['restricted_name'] except Exception as e: - # the template json doesn't have a 'restricted' element warn and use it - logger.info(f'The template does not specify a "restricted".' + # the template json doesn't have a 'restricted_name' element warn and use it + logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_name}') else: if template_json_restricted_name != template_restricted_name: logger.error( f'The supplied --template-restricted-name {template_restricted_name} does not match the' - f' templates "restricted". Either the the --template-restricted-name is incorrect or the' - f' templates "restricted" is wrong. Note that since this template specifies "restricted" as' + f' templates "restricted_name". Either the the --template-restricted-name is incorrect or the' + f' templates "restricted_name" is wrong. Note that since this template specifies "restricted_name" as' f' {template_json_restricted_name}, --template-restricted-name need not be supplied.') - template_restricted_path = registration.get_registered(restricted_name=template_restricted_name) + template_restricted_path = manifest.get_registered(restricted_name=template_restricted_name) else: # The user has supplied the --template-restricted-path, see if that matches the template specifies. # If it does then we do not have a problem. If it doesn't match then error out. If not specified # in the template then warn and use the --template-restricted-path template_restricted_path = template_restricted_path.replace('\\', '/') try: - template_json_restricted_name = template_json_data['restricted'] + template_json_restricted_name = template_json_data['restricted_name'] except Exception as e: - # the template json doesn't have a 'restricted' element warn and use it - logger.info(f'The template does not specify a "restricted".' + # the template json doesn't have a 'restricted_name' element warn and use it + logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_path}') else: - template_json_restricted_path = registration.get_registered( + template_json_restricted_path = manifest.get_registered( restricted_name=template_json_restricted_name) if template_json_restricted_path != template_restricted_path: logger.error( f'The supplied --template-restricted-path {template_restricted_path} does not match the' - f' templates "restricted" {template_restricted_name} => {template_json_restricted_path}.' + f' templates "restricted_name" {template_restricted_name} => {template_json_restricted_path}.' f' Either the the supplied --template-restricted-path is incorrect or the templates' - f' "restricted" is wrong. Note that since this template specifies "restricted" as' + f' "restricted_name" is wrong. Note that since this template specifies "restricted_name" as' f' {template_json_restricted_name} --template-restricted-path need not be supplied' f' and {template_json_restricted_path} will be used.') return 1 @@ -1475,7 +1475,7 @@ def create_project(project_path: str, return 1 project_path = project_path.replace('\\', '/') if not os.path.isabs(project_path): - default_projects_folder = registration.get_registered(default_folder='projects') + default_projects_folder = manifest.get_registered(default_folder='projects') new_project_path = f'{default_projects_folder}/{project_path}' logger.info(f'Project Path {project_path} is not a full path, we must assume its relative' f' to default projects path = {new_project_path}') @@ -1496,19 +1496,19 @@ def create_project(project_path: str, # project restricted name if project_restricted_name and not project_restricted_path: - project_restricted_path = registration.get_registered(restricted_name=project_restricted_name) + project_restricted_path = manifest.get_registered(restricted_name=project_restricted_name) # project restricted path elif project_restricted_path: project_restricted_path = project_restricted_path.replace('\\', '/') if not os.path.isabs(project_restricted_path): - default_projects_restricted_folder = registration.get_registered(restricted_name='projects') + default_projects_restricted_folder = manifest.get_registered(restricted_name='projects') new_project_restricted_path = f'{default_projects_restricted_folder}/{project_restricted_path}' logger.info(f'Project restricted path {project_restricted_path} is not a full path, we must assume its' f' relative to default projects restricted path = {new_project_restricted_path}') project_restricted_path = new_project_restricted_path elif template_restricted_path: - project_restricted_default_path = registration.get_registered(restricted_name='projects') + project_restricted_default_path = manifest.get_registered(restricted_name='projects') logger.info(f'--project-restricted-path is not specified, using default project restricted path / project name' f' = {project_restricted_default_path}') project_restricted_path = project_restricted_default_path @@ -1585,7 +1585,7 @@ def create_project(project_path: str, # read the restricted_name from the projects restricted.json restricted_json = f"{project_restricted_path}/restricted.json".replace('//', '/') if os.path.isfile(restricted_json): - if not registration.valid_o3de_restricted_json(restricted_json): + if not validation.valid_o3de_restricted_json(restricted_json): logger.error(f'Restricted json {restricted_json} is not valid.') return 1 else: @@ -1607,9 +1607,9 @@ def create_project(project_path: str, logger.error(f'Failed to read "restricted_name" from restricted json {restricted_json}.') return 1 - # set the "restricted": "restricted_name" element of the project.json + # set the "restricted_name": "restricted_name" element of the project.json project_json = f"{project_path}/project.json".replace('//', '/') - if not registration.valid_o3de_project_json(project_json): + if not validation.valid_o3de_project_json(project_json): logger.error(f'Project json {project_json} is not valid.') return 1 @@ -1620,7 +1620,7 @@ def create_project(project_path: str, logger.error(f'Failed to load project json {project_json}.') return 1 - project_json_data.update({"restricted": restricted_name}) + project_json_data.update({"restricted_name": restricted_name}) os.unlink(project_json) with open(project_json, 'w') as s: try: @@ -1653,7 +1653,7 @@ def create_project(project_path: str, d.write('# {END_LICENSE}\n') # copy the o3de_manifest.cmake into the project root - engine_path = registration.get_this_engine_path() + engine_path = manifest.get_this_engine_path() o3de_manifest_cmake = f'{engine_path}/cmake/o3de_manifest.cmake' shutil.copy(o3de_manifest_cmake, project_path) @@ -1718,7 +1718,7 @@ def create_gem(gem_path: str, template_name = 'DefaultGem' if template_name and not template_path: - template_path = registration.get_registered(template_name=template_name) + template_path = manifest.get_registered(template_name=template_name) if not os.path.isdir(template_path): logger.error(f'Could not find the template {template_name}=>{template_path}') @@ -1729,7 +1729,7 @@ def create_gem(gem_path: str, # the template.json should be in the template_path, make sure it's there and valid template_json = f'{template_path}/template.json' - if not registration.valid_o3de_template_json(template_json): + if not validation.valid_o3de_template_json(template_json): logger.error(f'Template json {template_path} is not valid.') return 1 @@ -1752,56 +1752,56 @@ def create_gem(gem_path: str, # see if the template itself specifies a restricted name if not template_restricted_name and not template_restricted_path: try: - template_json_restricted_name = template_json_data['restricted'] + template_json_restricted_name = template_json_data['restricted_name'] except Exception as e: - # the template json doesn't have a 'restricted' element warn and use it - logger.info(f'The template does not specify a "restricted".') + # the template json doesn't have a 'restricted_name' element warn and use it + logger.info(f'The template does not specify a "restricted_name".') else: template_restricted_name = template_json_restricted_name # if no restricted name or path we continue on as if there is no template restricted files. if template_restricted_name or template_restricted_path: - # if the user specified a --template-restricted-name we need to check that against the templates 'restricted' + # if the user specified a --template-restricted-name we need to check that against the templates 'restricted_name' # if it has one and see if they match. If they match then we don't have a problem. If they don't then we error # out. If supplied but not present in the template we warn and use it. If not supplied we set what's in the # template. If not supplied and not in the template we continue on as if there is no template restricted files. if template_restricted_name and not template_restricted_path: # The user specified a --template-restricted-name try: - template_json_restricted_name = template_json_data['restricted'] + template_json_restricted_name = template_json_data['restricted_name'] except Exception as e: - # the template json doesn't have a 'restricted' element warn and use it - logger.info(f'The template does not specify a "restricted".' + # the template json doesn't have a 'restricted_name' element warn and use it + logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_name}') else: if template_json_restricted_name != template_restricted_name: logger.error( f'The supplied --template-restricted-name {template_restricted_name} does not match the' - f' templates "restricted". Either the the --template-restricted-name is incorrect or the' - f' templates "restricted" is wrong. Note that since this template specifies "restricted" as' + f' templates "restricted_name". Either the the --template-restricted-name is incorrect or the' + f' templates "restricted_name" is wrong. Note that since this template specifies "restricted_name" as' f' {template_json_restricted_name}, --template-restricted-name need not be supplied.') - template_restricted_path = registration.get_registered(restricted_name=template_restricted_name) + template_restricted_path = manifest.get_registered(restricted_name=template_restricted_name) else: # The user has supplied the --template-restricted-path, see if that matches the template specifies. # If it does then we do not have a problem. If it doesn't match then error out. If not specified # in the template then warn and use the --template-restricted-path template_restricted_path = template_restricted_path.replace('\\', '/') try: - template_json_restricted_name = template_json_data['restricted'] + template_json_restricted_name = template_json_data['restricted_name'] except Exception as e: - # the template json doesn't have a 'restricted' element warn and use it - logger.info(f'The template does not specify a "restricted".' + # the template json doesn't have a 'restricted_name' element warn and use it + logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_path}') else: - template_json_restricted_path = registration.get_registered( + template_json_restricted_path = manifest.get_registered( restricted_name=template_json_restricted_name) if template_json_restricted_path != template_restricted_path: logger.error( f'The supplied --template-restricted-path {template_restricted_path} does not match the' - f' templates "restricted" {template_restricted_name} => {template_json_restricted_path}.' + f' templates "restricted_name" {template_restricted_name} => {template_json_restricted_path}.' f' Either the the supplied --template-restricted-path is incorrect or the templates' - f' "restricted" is wrong. Note that since this template specifies "restricted" as' + f' "restricted_name" is wrong. Note that since this template specifies "restricted_name" as' f' {template_json_restricted_name} --template-restricted-path need not be supplied' f' and {template_json_restricted_path} will be used.') return 1 @@ -1854,7 +1854,7 @@ def create_gem(gem_path: str, return 1 gem_path = gem_path.replace('\\', '/') if not os.path.isabs(gem_path): - default_gems_folder = registration.get_registered(default_folder='gems') + default_gems_folder = manifest.get_registered(default_folder='gems') new_gem_path = f'{default_gems_folder}/{gem_path}' logger.info(f'Gem Path {gem_path} is not a full path, we must assume its relative' f' to default gems path = {new_gem_path}') @@ -1875,19 +1875,19 @@ def create_gem(gem_path: str, # gem restricted name if gem_restricted_name and not gem_restricted_path: - gem_restricted_path = registration.get_registered(restricted_name=gem_restricted_name) + gem_restricted_path = manifest.get_registered(restricted_name=gem_restricted_name) # gem restricted path elif gem_restricted_path: gem_restricted_path = gem_restricted_path.replace('\\', '/') if not os.path.isabs(gem_restricted_path): - default_gems_restricted_folder = registration.get_registered(restricted_name='gems') + default_gems_restricted_folder = manifest.get_registered(restricted_name='gems') new_gem_restricted_path = f'{default_gems_restricted_folder}/{gem_restricted_path}' logger.info(f'Gem restricted path {gem_restricted_path} is not a full path, we must assume its' f' relative to default gems restricted path = {new_gem_restricted_path}') gem_restricted_path = new_gem_restricted_path elif template_restricted_path: - gem_restricted_default_path = registration.get_registered(restricted_name='gems') + gem_restricted_default_path = manifest.get_registered(restricted_name='gems') logger.info(f'--gem-restricted-path is not specified, using default gem restricted path / gem name' f' = {gem_restricted_default_path}') gem_restricted_path = gem_restricted_default_path @@ -1964,7 +1964,7 @@ def create_gem(gem_path: str, # read the restricted_name from the gems restricted.json restricted_json = f"{gem_restricted_path}/restricted.json".replace('//', '/') if os.path.isfile(restricted_json): - if not registration.valid_o3de_restricted_json(restricted_json): + if not validation.valid_o3de_restricted_json(restricted_json): logger.error(f'Restricted json {restricted_json} is not valid.') return 1 else: @@ -1986,9 +1986,9 @@ def create_gem(gem_path: str, logger.error(f'Failed to read "restricted_name" from restricted json {restricted_json}.') return 1 - # set the "restricted": "restricted_name" element of the gem.json + # set the "restricted_name": "restricted_name" element of the gem.json gem_json = f"{gem_path}/gem.json".replace('//', '/') - if not registration.valid_o3de_gem_json(gem_json): + if not validation.valid_o3de_gem_json(gem_json): logger.error(f'Gem json {gem_json} is not valid.') return 1 @@ -1999,7 +1999,7 @@ def create_gem(gem_path: str, logger.error(f'Failed to load gem json {gem_json}.') return 1 - gem_json_data.update({"restricted": restricted_name}) + gem_json_data.update({"restricted_name": restricted_name}) os.unlink(gem_json) with open(gem_json, 'w') as s: try: @@ -2116,7 +2116,7 @@ def add_args(parser, subparsers) -> None: create_template_subparser.add_argument('-tp', '--template-path', type=str, required=False, help='The path to the template to create, can be absolute or relative' ' to default templates path') - group = create_template_subparser.add_mutually_exclusive_group(required=True) + group = create_template_subparser.add_mutually_exclusive_group(required=False) group.add_argument('-srp', '--source-restricted-path', type=str, required=False, default=None, help='The path to the source restricted folder.') @@ -2125,7 +2125,7 @@ def add_args(parser, subparsers) -> None: help='The name of the source restricted folder. If supplied this will resolve' ' the --source-restricted-path.') - group = create_template_subparser.add_mutually_exclusive_group(required=True) + group = create_template_subparser.add_mutually_exclusive_group(required=False) group.add_argument('-trp', '--template-restricted-path', type=str, required=False, default=None, help='The path to the templates restricted folder.') diff --git a/scripts/o3de/o3de/get_registration.py b/scripts/o3de/o3de/get_registration.py new file mode 100644 index 0000000000..c38d4d1cfb --- /dev/null +++ b/scripts/o3de/o3de/get_registration.py @@ -0,0 +1,62 @@ +# +# 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 pathlib + +from o3de import manifest + +def _run_get_registered(args: argparse) -> str or pathlib.Path: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + return manifest.get_registered(args.engine_name, + args.project_name, + args.gem_name, + args.template_name, + args.default_folder, + args.repo_name, + args.restricted_name) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + get_registered_subparser = subparsers.add_parser('get-registered') + group = get_registered_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-en', '--engine-name', type=str, required=False, + help='Engine name.') + group.add_argument('-pn', '--project-name', type=str, required=False, + help='Project name.') + group.add_argument('-gn', '--gem-name', type=str, required=False, + help='Gem name.') + group.add_argument('-tn', '--template-name', type=str, required=False, + help='Template name.') + group.add_argument('-df', '--default-folder', type=str, required=False, + choices=['engines', 'projects', 'gems', 'templates', 'restricted'], + help='The default folders for o3de.') + group.add_argument('-rn', '--repo-name', type=str, required=False, + help='Repo name.') + group.add_argument('-rsn', '--restricted-name', type=str, required=False, + help='Restricted name.') + + get_registered_subparser.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.') + + get_registered_subparser.set_defaults(func=_run_get_registered) diff --git a/scripts/o3de/o3de/global_project.py b/scripts/o3de/o3de/global_project.py index da1b5dfa80..1a17e3b79e 100644 --- a/scripts/o3de/o3de/global_project.py +++ b/scripts/o3de/o3de/global_project.py @@ -16,7 +16,7 @@ import sys import re import pathlib import json -from o3de import registration +from o3de import manifest logger = logging.getLogger() logging.basicConfig() @@ -39,7 +39,7 @@ def set_global_project(project_name: str or None, return 1 if project_name and not project_path: - project_path = registration.get_registered(project_name=project_name) + project_path = manifest.get_registered(project_name=project_name) if not project_path: logger.error(f'Project Path {project_path} has not been registered.') @@ -47,7 +47,7 @@ def set_global_project(project_name: str or None, project_path = pathlib.Path(project_path).resolve() - bootstrap_setreg_file = registration.get_o3de_registry_folder() / 'bootstrap.setreg' + bootstrap_setreg_file = manifest.get_o3de_registry_folder() / 'bootstrap.setreg' if bootstrap_setreg_file.is_file(): with bootstrap_setreg_file.open('r') as f: try: @@ -80,7 +80,7 @@ def get_global_project() -> pathlib.Path or None: get what the current project set is :return: project_path or None on failure """ - bootstrap_setreg_file = registration.get_o3de_registry_folder() / 'bootstrap.setreg' + bootstrap_setreg_file = manifest.get_o3de_registry_folder() / 'bootstrap.setreg' if not bootstrap_setreg_file.is_file(): logger.error(f'Bootstrap.setreg file {bootstrap_setreg_file} does not exist.') return None @@ -101,7 +101,7 @@ def get_global_project() -> pathlib.Path or None: def _run_get_global_project(args: argparse) -> int: if args.override_home_folder: - registration.override_home_folder = args.override_home_folder + manifest.override_home_folder = args.override_home_folder project_path = get_global_project() if project_path: @@ -112,7 +112,7 @@ def _run_get_global_project(args: argparse) -> int: def _run_set_global_project(args: argparse) -> int: if args.override_home_folder: - registration.override_home_folder = args.override_home_folder + manifest.override_home_folder = args.override_home_folder return set_global_project(args.project_name, args.project_path) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py new file mode 100644 index 0000000000..b3aac6d1f3 --- /dev/null +++ b/scripts/o3de/o3de/manifest.py @@ -0,0 +1,600 @@ +# +# 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. +# +""" +This file contains functions for querying paths from ~/.o3de directory +""" + +import json +import logging +import os +import pathlib + +from o3de import validation + +logger = logging.getLogger() +logging.basicConfig() + +# Directory methods +override_home_folder = None + + +def get_this_engine_path() -> pathlib.Path: + return pathlib.Path(os.path.realpath(__file__)).parents[3].resolve() + + +def get_home_folder() -> pathlib.Path: + if override_home_folder: + return pathlib.Path(override_home_folder).resolve() + else: + return pathlib.Path(os.path.expanduser("~")).resolve() + + +def get_o3de_folder() -> pathlib.Path: + o3de_folder = get_home_folder() / '.o3de' + o3de_folder.mkdir(parents=True, exist_ok=True) + return o3de_folder + + +def get_o3de_registry_folder() -> pathlib.Path: + registry_folder = get_o3de_folder() / 'Registry' + registry_folder.mkdir(parents=True, exist_ok=True) + return registry_folder + + +def get_o3de_cache_folder() -> pathlib.Path: + cache_folder = get_o3de_folder() / 'Cache' + cache_folder.mkdir(parents=True, exist_ok=True) + return cache_folder + + +def get_o3de_download_folder() -> pathlib.Path: + download_folder = get_o3de_folder() / 'Download' + download_folder.mkdir(parents=True, exist_ok=True) + return download_folder + + +def get_o3de_engines_folder() -> pathlib.Path: + engines_folder = get_o3de_folder() / 'Engines' + engines_folder.mkdir(parents=True, exist_ok=True) + return engines_folder + + +def get_o3de_projects_folder() -> pathlib.Path: + projects_folder = get_o3de_folder() / 'Projects' + projects_folder.mkdir(parents=True, exist_ok=True) + return projects_folder + + +def get_o3de_gems_folder() -> pathlib.Path: + gems_folder = get_o3de_folder() / 'Gems' + gems_folder.mkdir(parents=True, exist_ok=True) + return gems_folder + + +def get_o3de_templates_folder() -> pathlib.Path: + templates_folder = get_o3de_folder() / 'Templates' + templates_folder.mkdir(parents=True, exist_ok=True) + return templates_folder + + +def get_o3de_restricted_folder() -> pathlib.Path: + restricted_folder = get_o3de_folder() / 'Restricted' + restricted_folder.mkdir(parents=True, exist_ok=True) + return restricted_folder + + +def get_o3de_logs_folder() -> pathlib.Path: + logs_folder = get_o3de_folder() / 'Logs' + logs_folder.mkdir(parents=True, exist_ok=True) + return logs_folder + + +# o3de manifest file methods +def get_o3de_manifest() -> pathlib.Path: + manifest_path = get_o3de_folder() / 'o3de_manifest.json' + if not manifest_path.is_file(): + username = os.path.split(get_home_folder())[-1] + + o3de_folder = get_o3de_folder() + default_registry_folder = get_o3de_registry_folder() + default_cache_folder = get_o3de_cache_folder() + default_downloads_folder = get_o3de_download_folder() + default_logs_folder = get_o3de_logs_folder() + default_engines_folder = get_o3de_engines_folder() + default_projects_folder = get_o3de_projects_folder() + default_gems_folder = get_o3de_gems_folder() + default_templates_folder = get_o3de_templates_folder() + default_restricted_folder = get_o3de_restricted_folder() + + default_projects_restricted_folder = default_projects_folder / 'Restricted' + default_projects_restricted_folder.mkdir(parents=True, exist_ok=True) + default_gems_restricted_folder = default_gems_folder / 'Restricted' + default_gems_restricted_folder.mkdir(parents=True, exist_ok=True) + default_templates_restricted_folder = default_templates_folder / 'Restricted' + default_templates_restricted_folder.mkdir(parents=True, exist_ok=True) + + json_data = {} + json_data.update({'o3de_manifest_name': f'{username}'}) + json_data.update({'origin': o3de_folder.as_posix()}) + json_data.update({'default_engines_folder': default_engines_folder.as_posix()}) + json_data.update({'default_projects_folder': default_projects_folder.as_posix()}) + 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({'projects': []}) + json_data.update({'gems': []}) + json_data.update({'templates': []}) + json_data.update({'restricted': []}) + json_data.update({'repos': []}) + json_data.update({'engines': []}) + + default_restricted_folder_json = default_restricted_folder / 'restricted.json' + if not default_restricted_folder_json.is_file(): + with default_restricted_folder_json.open('w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': 'o3de'}) + s.write(json.dumps(restricted_json_data, indent=4)) + json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) + + default_projects_restricted_folder_json = default_projects_restricted_folder / 'restricted.json' + if not default_projects_restricted_folder_json.is_file(): + with default_projects_restricted_folder_json.open('w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': 'projects'}) + s.write(json.dumps(restricted_json_data, indent=4)) + + default_gems_restricted_folder_json = default_gems_restricted_folder / 'restricted.json' + if not default_gems_restricted_folder_json.is_file(): + with default_gems_restricted_folder_json.open('w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': 'gems'}) + s.write(json.dumps(restricted_json_data, indent=4)) + + default_templates_restricted_folder_json = default_templates_restricted_folder / 'restricted.json' + if not default_templates_restricted_folder_json.is_file(): + with default_templates_restricted_folder_json.open('w') as s: + restricted_json_data = {} + restricted_json_data.update({'restricted_name': 'templates'}) + s.write(json.dumps(restricted_json_data, indent=4)) + + with manifest_path.open('w') as s: + s.write(json.dumps(json_data, indent=4)) + + return manifest_path + + +def load_o3de_manifest() -> dict: + with get_o3de_manifest().open('r') as f: + try: + json_data = json.load(f) + except Exception as e: + logger.error(f'Manifest json failed to load: {str(e)}') + return {} + else: + return json_data + + +def save_o3de_manifest(json_data: dict) -> None: + with get_o3de_manifest().open('w') as s: + try: + s.write(json.dumps(json_data, indent=4)) + except Exception as e: + logger.error(f'Manifest json failed to save: {str(e)}') + + +# Data query methods +def get_this_engine() -> dict: + json_data = load_o3de_manifest() + engine_data = find_engine_data(json_data) + return engine_data + + +def get_engines() -> dict: + json_data = load_o3de_manifest() + return json_data['engines'] + + +def get_projects() -> dict: + json_data = load_o3de_manifest() + return json_data['projects'] + + +def get_gems() -> dict: + json_data = load_o3de_manifest() + return json_data['gems'] + + +def get_templates() -> dict: + json_data = load_o3de_manifest() + return json_data['templates'] + + +def get_restricted() -> dict: + json_data = load_o3de_manifest() + return json_data['restricted'] + + +def get_repos() -> dict: + json_data = load_o3de_manifest() + return json_data['repos'] + + +def get_engine_projects() -> list: + engine_path = get_this_engine_path() + engine_object = get_engine_json_data(engine_path=engine_path) + return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), + engine_object['projects'])) if 'projects' in engine_object else [] + + +def get_engine_gems() -> list: + def is_gem_subdirectory(subdir): + return (pathlib.Path(subdir) / 'gem.json').exists() + + external_subdirs = get_engine_external_subdirectories() + return list(filter(is_gem_subdirectory, external_subdirs)) if external_subdirs else [] + + +def get_engine_templates() -> list: + engine_path = get_this_engine_path() + engine_object = get_engine_json_data(engine_path=engine_path) + return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), + engine_object['templates'])) + + +def get_engine_restricted() -> list: + engine_path = get_this_engine_path() + engine_object = get_engine_json_data(engine_path=engine_path) + return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), + engine_object['restricted'])) if 'restricted' in engine_object else [] + + +def get_engine_external_subdirectories() -> list: + engine_path = get_this_engine_path() + engine_object = get_engine_json_data(engine_path=engine_path) + return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), + engine_object['external_subdirectories'])) if 'external_subdirectories' in engine_object else [] + + +def get_all_projects() -> list: + engine_projects = get_engine_projects() + projects_data = get_projects() + projects_data.extend(engine_projects) + return projects_data + + +def get_all_gems() -> list: + engine_gems = get_engine_gems() + gems_data = get_gems() + gems_data.extend(engine_gems) + return gems_data + + +def get_all_templates() -> list: + engine_templates = get_engine_templates() + templates_data = get_templates() + templates_data.extend(engine_templates) + return templates_data + + +def get_all_restricted() -> list: + engine_restricted = get_engine_restricted() + restricted_data = get_restricted() + restricted_data.extend(engine_restricted) + return restricted_data + + +def find_engine_data(json_data: dict, + engine_path: str or pathlib.Path = None) -> dict or None: + if not engine_path: + engine_path = get_this_engine_path() + engine_path = pathlib.Path(engine_path).resolve() + + for engine_object in json_data['engines']: + engine_object_path = pathlib.Path(engine_object['path']).resolve() + if engine_path == engine_object_path: + return engine_object + + return None + + +def get_engine_json_data(engine_name: str = None, + engine_path: str or pathlib.Path = None) -> dict or None: + if not engine_name and not engine_path: + logger.error('Must specify either a Engine name or Engine Path.') + return None + + if engine_name and not engine_path: + engine_path = get_registered(engine_name=engine_name) + + if not engine_path: + logger.error(f'Engine Path {engine_path} has not been registered.') + return None + + engine_path = pathlib.Path(engine_path).resolve() + engine_json = engine_path / 'engine.json' + if not engine_json.is_file(): + logger.error(f'Engine json {engine_json} is not present.') + return None + if not validation.valid_o3de_engine_json(engine_json): + logger.error(f'Engine json {engine_json} is not valid.') + return None + + with engine_json.open('r') as f: + try: + engine_json_data = json.load(f) + except Exception as e: + logger.warn(f'{engine_json} failed to load: {str(e)}') + else: + return engine_json_data + + return None + + +def get_project_json_data(project_name: str = None, + project_path: str or pathlib.Path = None) -> dict or None: + if not project_name and not project_path: + logger.error('Must specify either a Project name or Project Path.') + return None + + if project_name and not project_path: + project_path = get_registered(project_name=project_name) + + if not project_path: + logger.error(f'Project Path {project_path} has not been registered.') + return None + + project_path = pathlib.Path(project_path).resolve() + project_json = project_path / 'project.json' + if not project_json.is_file(): + logger.error(f'Project json {project_json} is not present.') + return None + if not validation.valid_o3de_project_json(project_json): + logger.error(f'Project json {project_json} is not valid.') + return None + + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except Exception as e: + logger.warn(f'{project_json} failed to load: {str(e)}') + else: + return project_json_data + + return None + + +def get_gem_json_data(gem_name: str = None, + gem_path: str or pathlib.Path = None) -> dict or None: + if not gem_name and not gem_path: + logger.error('Must specify either a Gem name or Gem Path.') + return None + + if gem_name and not gem_path: + gem_path = get_registered(gem_name=gem_name) + + if not gem_path: + logger.error(f'Gem Path {gem_path} has not been registered.') + return None + + gem_path = pathlib.Path(gem_path).resolve() + gem_json = gem_path / 'gem.json' + if not gem_json.is_file(): + logger.error(f'Gem json {gem_json} is not present.') + return None + if not validation.valid_o3de_gem_json(gem_json): + logger.error(f'Gem json {gem_json} is not valid.') + return None + + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except Exception as e: + logger.warn(f'{gem_json} failed to load: {str(e)}') + else: + return gem_json_data + + return None + + +def get_template_json_data(template_name: str = None, + template_path: str or pathlib.Path = None) -> dict or None: + if not template_name and not template_path: + logger.error('Must specify either a Template name or Template Path.') + return None + + if template_name and not template_path: + template_path = get_registered(template_name=template_name) + + if not template_path: + logger.error(f'Template Path {template_path} has not been registered.') + return None + + template_path = pathlib.Path(template_path).resolve() + template_json = template_path / 'template.json' + if not template_json.is_file(): + logger.error(f'Template json {template_json} is not present.') + return None + if not validation.valid_o3de_template_json(template_json): + logger.error(f'Template json {template_json} is not valid.') + return None + + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except Exception as e: + logger.warn(f'{template_json} failed to load: {str(e)}') + else: + return template_json_data + + return None + + +def get_restricted_data(restricted_name: str = None, + restricted_path: str or pathlib.Path = None) -> dict or None: + if not restricted_name and not restricted_path: + logger.error('Must specify either a Restricted name or Restricted Path.') + return None + + if restricted_name and not restricted_path: + restricted_path = get_registered(restricted_name=restricted_name) + + if not restricted_path: + logger.error(f'Restricted Path {restricted_path} has not been registered.') + return None + + restricted_path = pathlib.Path(restricted_path).resolve() + restricted_json = restricted_path / 'restricted.json' + if not restricted_json.is_file(): + logger.error(f'Restricted json {restricted_json} is not present.') + return None + if not validation.valid_o3de_restricted_json(restricted_json): + logger.error(f'Restricted json {restricted_json} is not valid.') + return None + + with restricted_json.open('r') as f: + try: + restricted_json_data = json.load(f) + except Exception as e: + logger.warn(f'{restricted_json} failed to load: {str(e)}') + else: + return restricted_json_data + + return None + + +def get_registered(engine_name: str = None, + project_name: str = None, + gem_name: str = None, + template_name: str = None, + default_folder: str = None, + repo_name: str = None, + restricted_name: str = None) -> pathlib.Path or None: + json_data = load_o3de_manifest() + + # check global first then this engine + if isinstance(engine_name, str): + for engine in json_data['engines']: + engine_path = pathlib.Path(engine['path']).resolve() + engine_json = engine_path / 'engine.json' + with engine_json.open('r') as f: + try: + engine_json_data = json.load(f) + except Exception as e: + logger.warn(f'{engine_json} failed to load: {str(e)}') + else: + this_engines_name = engine_json_data['engine_name'] + if this_engines_name == engine_name: + return engine_path + + elif isinstance(project_name, str): + engine_object = find_engine_data(json_data) + projects = json_data['projects'].copy() + projects.extend(engine_object['projects']) + for project_path in projects: + project_path = pathlib.Path(project_path).resolve() + project_json = project_path / 'project.json' + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except Exception as e: + logger.warn(f'{project_json} failed to load: {str(e)}') + else: + this_projects_name = project_json_data['project_name'] + if this_projects_name == project_name: + return project_path + + elif isinstance(gem_name, str): + engine_object = find_engine_data(json_data) + gems = json_data['gems'].copy() + gems.extend(engine_object['gems']) + for gem_path in gems: + gem_path = pathlib.Path(gem_path).resolve() + gem_json = gem_path / 'gem.json' + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except Exception as e: + logger.warn(f'{gem_json} failed to load: {str(e)}') + else: + this_gems_name = gem_json_data['gem_name'] + if this_gems_name == gem_name: + return gem_path + + elif isinstance(template_name, str): + engine_object = find_engine_data(json_data) + templates = json_data['templates'].copy() + templates.extend(engine_object['templates']) + for template_path in templates: + template_path = pathlib.Path(template_path).resolve() + template_json = template_path / 'template.json' + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except Exception as e: + logger.warn(f'{template_path} failed to load: {str(e)}') + else: + this_templates_name = template_json_data['template_name'] + if this_templates_name == template_name: + return template_path + + elif isinstance(restricted_name, str): + engine_object = find_engine_data(json_data) + restricted = json_data['restricted'].copy() + restricted.extend(engine_object['restricted']) + for restricted_path in restricted: + restricted_path = pathlib.Path(restricted_path).resolve() + restricted_json = restricted_path / 'restricted.json' + with restricted_json.open('r') as f: + try: + restricted_json_data = json.load(f) + except Exception as e: + logger.warn(f'{restricted_json} failed to load: {str(e)}') + else: + this_restricted_name = restricted_json_data['restricted_name'] + if this_restricted_name == restricted_name: + return restricted_path + + elif isinstance(default_folder, str): + if default_folder == 'engines': + default_engines_folder = pathlib.Path(json_data['default_engines_folder']).resolve() + return default_engines_folder + elif default_folder == 'projects': + default_projects_folder = pathlib.Path(json_data['default_projects_folder']).resolve() + return default_projects_folder + elif default_folder == 'gems': + default_gems_folder = pathlib.Path(json_data['default_gems_folder']).resolve() + return default_gems_folder + elif default_folder == 'templates': + default_templates_folder = pathlib.Path(json_data['default_templates_folder']).resolve() + return default_templates_folder + elif default_folder == 'restricted': + default_restricted_folder = pathlib.Path(json_data['default_restricted_folder']).resolve() + return default_restricted_folder + + elif isinstance(repo_name, str): + cache_folder = get_o3de_cache_folder() + for repo_uri in json_data['repos']: + repo_uri = pathlib.Path(repo_uri).resolve() + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if cache_file.is_file(): + repo = pathlib.Path(cache_file).resolve() + with repo.open('r') as f: + try: + repo_json_data = json.load(f) + except Exception as e: + logger.warn(f'{cache_file} failed to load: {str(e)}') + else: + this_repos_name = repo_json_data['repo_name'] + if this_repos_name == repo_name: + return repo_uri + return None diff --git a/scripts/o3de/o3de/print_registration.py b/scripts/o3de/o3de/print_registration.py new file mode 100644 index 0000000000..7900fad7e4 --- /dev/null +++ b/scripts/o3de/o3de/print_registration.py @@ -0,0 +1,456 @@ +# +# 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 hashlib +import logging +import urllib.parse + +from o3de import manifest, validation + +logger = logging.getLogger() +logging.basicConfig() + +def print_this_engine(verbose: int) -> None: + engine_data = manifest.get_this_engine() + print(json.dumps(engine_data, indent=4)) + if verbose > 0: + print_engines_data(engine_data) + + +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) + + +def print_projects(verbose: int) -> None: + projects_data = manifest.get_projects() + print(json.dumps(projects_data, indent=4)) + if verbose > 0: + print_projects_data(projects_data) + + +def print_gems(verbose: int) -> None: + gems_data = manifest.get_gems() + print(json.dumps(gems_data, indent=4)) + if verbose > 0: + print_gems_data(gems_data) + + +def print_templates(verbose: int) -> None: + templates_data = manifest.get_templates() + print(json.dumps(templates_data, indent=4)) + if verbose > 0: + print_templates_data(templates_data) + + +def print_restricted(verbose: int) -> None: + 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: + engine_projects_data = manifest.get_engine_projects() + print(json.dumps(engine_projects_data, indent=4)) + if verbose > 0: + print_projects_data(engine_projects_data) + + +def print_engine_gems(verbose: int) -> None: + engine_gems_data = manifest.get_engine_gems() + print(json.dumps(engine_gems_data, indent=4)) + if verbose > 0: + print_gems_data(engine_gems_data) + + +def print_engine_templates(verbose: int) -> None: + engine_templates_data = manifest.get_engine_templates() + print(json.dumps(engine_templates_data, indent=4)) + if verbose > 0: + print_templates_data(engine_templates_data) + + +def print_engine_restricted(verbose: int) -> None: + engine_restricted_data = manifest.get_engine_restricted() + print(json.dumps(engine_restricted_data, indent=4)) + if verbose > 0: + print_restricted_data(engine_restricted_data) + + +def print_engine_external_subdirectories(verbose: int) -> None: + external_subdirs_data = manifest.get_engine_external_subdirectories() + print(json.dumps(external_subdirs_data, indent=4)) + + +def print_all_projects(verbose: int) -> None: + all_projects_data = manifest.get_all_projects() + print(json.dumps(all_projects_data, indent=4)) + if verbose > 0: + print_projects_data(all_projects_data) + + +def print_all_gems(verbose: int) -> None: + all_gems_data = manifest.get_all_gems() + print(json.dumps(all_gems_data, indent=4)) + if verbose > 0: + print_gems_data(all_gems_data) + + +def print_all_templates(verbose: int) -> None: + all_templates_data = manifest.get_all_templates() + print(json.dumps(all_templates_data, indent=4)) + if verbose > 0: + print_templates_data(all_templates_data) + + +def print_all_restricted(verbose: int) -> None: + all_restricted_data = manifest.get_all_restricted() + print(json.dumps(all_restricted_data, indent=4)) + if verbose > 0: + print_restricted_data(all_restricted_data) + + +def print_engines_data(engines_data: dict) -> None: + print('\n') + print("Engines================================================") + for engine_object in engines_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()) + cache_folder = manifest.get_o3de_cache_folder() + engine = cache_folder / str(repo_sha256.hexdigest() + '.json') + print(f'{engine_uri}/engine.json cached as:') + else: + engine_json = pathlib.Path(engine_uri).resolve() / 'engine.json' + + with engine_json.open('r') as f: + try: + engine_json_data = json.load(f) + except Exception 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') + + +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 Exception 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 Exception 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 Exception 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: + print('\n') + print("Repos================================================") + cache_folder = manifest.get_o3de_cache_folder() + for repo_uri in repos_data: + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if validation.valid_o3de_repo_json(cache_file): + with cache_file.open('r') as s: + try: + repo_json_data = json.load(s) + except Exception as e: + logger.warn(f'{cache_file} failed to load: {str(e)}') + else: + print(f'{repo_uri}/repo.json cached as:') + 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 Exception 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') + + +def register_show_repos(verbose: int) -> None: + repos_data = get_repos() + print(json.dumps(repos_data, indent=4)) + if verbose > 0: + print_repos_data(repos_data) + + +def register_show(verbose: int) -> None: + json_data = manifest.load_o3de_manifest() + print(f"{manifest.get_o3de_manifest()}:") + print(json.dumps(json_data, indent=4)) + + 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()) + + +def _run_register_show(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + if args.this_engine: + print_this_engine(args.verbose) + return 0 + + elif args.engines: + print_engines(args.verbose) + return 0 + elif args.projects: + print_projects(args.verbose) + return 0 + elif args.gems: + print_gems(args.verbose) + return 0 + elif args.templates: + print_templates(args.verbose) + return 0 + elif args.repos: + register_show_repos(args.verbose) + return 0 + elif args.restricted: + print_restricted(args.verbose) + return 0 + + elif args.engine_projects: + print_engine_projects(args.verbose) + return 0 + 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 + elif args.engine_external_subdirectories: + print_engine_external_subdirectories(args.verbose) + return 0 + + elif args.all_projects: + print_all_projects(args.verbose) + return 0 + elif args.all_gems: + print_all_gems(args.verbose) + return 0 + elif args.all_templates: + print_all_templates(args.verbose) + return 0 + elif args.all_restricted: + print_all_restricted(args.verbose) + return 0 + + 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 + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + register_show_subparser = subparsers.add_parser('register-show') + group = register_show_subparser.add_mutually_exclusive_group(required=False) + group.add_argument('-te', '--this-engine', action='store_true', required=False, + default=False, + help='Just the local engines.') + + group.add_argument('-e', '--engines', action='store_true', required=False, + default=False, + help='Just the local engines.') + group.add_argument('-p', '--projects', action='store_true', required=False, + default=False, + help='Just the local projects.') + group.add_argument('-g', '--gems', action='store_true', required=False, + default=False, + help='Just the local gems.') + group.add_argument('-t', '--templates', action='store_true', required=False, + default=False, + help='Just the local templates.') + group.add_argument('-r', '--repos', action='store_true', required=False, + default=False, + help='Just the local repos. Ignores repos.') + group.add_argument('-rs', '--restricted', action='store_true', required=False, + default=False, + help='The local restricted folders.') + + group.add_argument('-ep', '--engine-projects', action='store_true', required=False, + default=False, + help='Just the local projects. Ignores repos.') + group.add_argument('-eg', '--engine-gems', action='store_true', required=False, + default=False, + help='Just the local gems. Ignores repos') + group.add_argument('-et', '--engine-templates', action='store_true', required=False, + default=False, + help='Just the local templates. 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, + default=False, + help='The external subdirectories.') + + group.add_argument('-ap', '--all-projects', action='store_true', required=False, + default=False, + help='Just the local projects. Ignores repos.') + group.add_argument('-ag', '--all-gems', action='store_true', required=False, + default=False, + help='Just the local gems. 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, + default=False, + help='The restricted folders.') + + group.add_argument('-d', '--downloadables', action='store_true', required=False, + 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.') + + register_show_subparser.add_argument('-v', '--verbose', action='count', required=False, + default=0, + help='How verbose do you want the output to be.') + + register_show_subparser.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.') + + register_show_subparser.set_defaults(func=_run_register_show) \ No newline at end of file diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py new file mode 100644 index 0000000000..e96d057e9c --- /dev/null +++ b/scripts/o3de/o3de/register.py @@ -0,0 +1,1066 @@ +# +# 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. +# +""" +This file contains all the code that has to do with registering engines, projects, gems and templates +""" + +import argparse +import hashlib +import logging +import json +import os +import pathlib +import shutil +import urllib.parse +import urllib.request + +from o3de import add_gem_cmake, get_registration, manifest, remove_external_subdirectory, repo, utils, validation + +logger = logging.getLogger() +logging.basicConfig() + + +def register_shipped_engine_o3de_objects(force: bool = False) -> int: + engine_path = manifest.get_this_engine_path() + + ret_val = 0 + + # register anything in the users default folders globally + error_code = register_all_engines_in_folder(manifest.get_registered(default_folder='engines'), force=force) + if error_code: + ret_val = error_code + error_code = register_all_projects_in_folder(manifest.get_registered(default_folder='projects')) + if error_code: + ret_val = error_code + error_code = register_all_gems_in_folder(manifest.get_registered(default_folder='gems')) + if error_code: + ret_val = error_code + error_code = register_all_templates_in_folder(manifest.get_registered(default_folder='templates')) + if error_code: + ret_val = error_code + error_code = register_all_restricted_in_folder(manifest.get_registered(default_folder='restricted')) + if error_code: + ret_val = error_code + error_code = register_all_restricted_in_folder(manifest.get_registered(default_folder='projects')) + if error_code: + ret_val = error_code + error_code = register_all_restricted_in_folder(manifest.get_registered(default_folder='gems')) + if error_code: + ret_val = error_code + error_code = register_all_restricted_in_folder(manifest.get_registered(default_folder='templates')) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_in_folder(folder_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None, + exclude: list = None) -> int: + if not folder_path: + logger.error(f'Folder path cannot be empty.') + return 1 + + folder_path = pathlib.Path(folder_path).resolve() + if not folder_path.is_dir(): + logger.error(f'Folder path is not dir.') + return 1 + + engines_set = set() + projects_set = set() + gems_set = set() + templates_set = set() + restricted_set = set() + repo_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(folder_path): + if root in exclude: + continue + + for name in files: + if name == 'engine.json': + engines_set.add(root) + elif name == 'project.json': + projects_set.add(root) + elif name == 'gem.json': + gems_set.add(root) + elif name == 'template.json': + templates_set.add(root) + elif name == 'restricted.json': + restricted_set.add(root) + elif name == 'repo.json': + repo_set.add(root) + + for engine in sorted(engines_set, reverse=True): + error_code = register(engine_path=engine, remove=remove) + if error_code: + ret_val = error_code + + for project in sorted(projects_set, reverse=True): + error_code = register(engine_path=engine_path, project_path=project, remove=remove) + if error_code: + ret_val = error_code + + for gem in sorted(gems_set, reverse=True): + error_code = register(engine_path=engine_path, gem_path=gem, remove=remove) + if error_code: + ret_val = error_code + + for template in sorted(templates_set, reverse=True): + error_code = register(engine_path=engine_path, template_path=template, remove=remove) + if error_code: + ret_val = error_code + + for restricted in sorted(restricted_set, reverse=True): + error_code = register(engine_path=engine_path, restricted_path=restricted, remove=remove) + if error_code: + ret_val = error_code + + for repo in sorted(repo_set, reverse=True): + error_code = register(engine_path=engine_path, repo_uri=repo, remove=remove) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_engines_in_folder(engines_path: str or pathlib.Path, + remove: bool = False, + force: bool = False) -> int: + if not engines_path: + logger.error(f'Engines path cannot be empty.') + return 1 + + engines_path = pathlib.Path(engines_path).resolve() + if not engines_path.is_dir(): + logger.error(f'Engines path is not dir.') + return 1 + + engines_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(engines_path): + for name in files: + if name == 'engine.json': + engines_set.add(root) + + for engine in sorted(engines_set, reverse=True): + error_code = register(engine_path=engine, remove=remove, force=force) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_projects_in_folder(projects_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not projects_path: + logger.error(f'Projects path cannot be empty.') + return 1 + + projects_path = pathlib.Path(projects_path).resolve() + if not projects_path.is_dir(): + logger.error(f'Projects path is not dir.') + return 1 + + projects_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(projects_path): + for name in files: + if name == 'project.json': + projects_set.add(root) + + for project in sorted(projects_set, reverse=True): + error_code = register(engine_path=engine_path, project_path=project, remove=remove) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_gems_in_folder(gems_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not gems_path: + logger.error(f'Gems path cannot be empty.') + return 1 + + gems_path = pathlib.Path(gems_path).resolve() + if not gems_path.is_dir(): + logger.error(f'Gems path is not dir.') + return 1 + + gems_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(gems_path): + for name in files: + if name == 'gem.json': + gems_set.add(root) + + for gem in sorted(gems_set, reverse=True): + error_code = register(engine_path=engine_path, gem_path=gem, remove=remove) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_templates_in_folder(templates_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not templates_path: + logger.error(f'Templates path cannot be empty.') + return 1 + + templates_path = pathlib.Path(templates_path).resolve() + if not templates_path.is_dir(): + logger.error(f'Templates path is not dir.') + return 1 + + templates_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(templates_path): + for name in files: + if name == 'template.json': + templates_set.add(root) + + for template in sorted(templates_set, reverse=True): + error_code = register(engine_path=engine_path, template_path=template, remove=remove) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_restricted_in_folder(restricted_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not restricted_path: + logger.error(f'Restricted path cannot be empty.') + return 1 + + restricted_path = pathlib.Path(restricted_path).resolve() + if not restricted_path.is_dir(): + logger.error(f'Restricted path is not dir.') + return 1 + + restricted_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(restricted_path): + for name in files: + if name == 'restricted.json': + restricted_set.add(root) + + for restricted in sorted(restricted_set, reverse=True): + error_code = register(engine_path=engine_path, restricted_path=restricted, remove=remove) + if error_code: + ret_val = error_code + + return ret_val + + +def register_all_repos_in_folder(repos_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not repos_path: + logger.error(f'Repos path cannot be empty.') + return 1 + + repos_path = pathlib.Path(repos_path).resolve() + if not repos_path.is_dir(): + logger.error(f'Repos path is not dir.') + return 1 + + repo_set = set() + + ret_val = 0 + for root, dirs, files in os.walk(repos_path): + for name in files: + if name == 'repo.json': + repo_set.add(root) + + for repo in sorted(repo_set, reverse=True): + error_code = register(engine_path=engine_path, repo_uri=repo, remove=remove) + if error_code: + ret_val = error_code + + return ret_val + + +def remove_engine_name_to_path(json_data: dict, + engine_path: pathlib.Path) -> int: + """ + Remove the engine at the specified path if it exist in the o3de manifest + :param json_data in-memory json view of the o3de_manifest.json data + :param engine_path path to engine to remove from the manifest data + + returns 0 to indicate no issues has occurred with removal + """ + if engine_path.is_dir() and validation.valid_o3de_engine_json(engine_path): + engine_json_data = manifest.get_engine_json_data(engine_path=engine_path) + if 'engine_name' in engine_json_data and 'engines_path' in json_data: + engine_name = engine_json_data['engine_name'] + try: + del json_data['engines_path'][engine_name] + except KeyError: + # Attempting to remove a non-existent engine_name is fine + pass + return 0 + + +def add_engine_name_to_path(json_data: dict, engine_path: pathlib.Path, force: bool): + # Add an engine path JSON object which maps the "engine_name" -> "engine_path" + engine_json_data = manifest.get_engine_json_data(engine_path=engine_path) + if not engine_json_data: + logger.error(f'Unable to retrieve json data from engine.json at path {engine_path.as_posix()}') + return 1 + engines_path_json = json_data.setdefault('engines_path', {}) + if 'engine_name' not in engine_json_data: + logger.error(f'engine.json at path {engine_path.as_posix()} is missing "engine_name" key') + return 1 + + engine_name = engine_json_data['engine_name'] + if not force and engine_name in engines_path_json and \ + pathlib.PurePath(engines_path_json[engine_name]) != engine_path: + logger.error( + f'Attempting to register existing engine "{engine_name}" with a new path of {engine_path.as_posix()}.' + f' The current path is {pathlib.Path(engines_path_json[engine_name]).as_posix()}.' + f' To force registration of a new engine path, specify the -f/--force option.') + return 1 + engines_path_json[engine_name] = engine_path.as_posix() + return 0 + + +def register_engine_path(json_data: dict, + engine_path: str or pathlib.Path, + remove: bool = False, + force: bool = False) -> int: + if not engine_path: + logger.error(f'Engine path cannot be empty.') + return 1 + engine_path = pathlib.Path(engine_path).resolve() + + for engine_object in json_data.get('engines', {}): + engine_object_path = pathlib.Path(engine_object['path']).resolve() + if engine_object_path == engine_path: + json_data['engines'].remove(engine_object) + + if remove: + return remove_engine_name_to_path(json_data, engine_path) + + if not engine_path.is_dir(): + logger.error(f'Engine path {engine_path} does not exist.') + return 1 + + engine_json = engine_path / 'engine.json' + if not validation.valid_o3de_engine_json(engine_json): + logger.error(f'Engine json {engine_json} is not valid.') + return 1 + + engine_object = {} + engine_object.update({'path': engine_path.as_posix()}) + engine_object.update({'restricted': []}) + + json_data.setdefault('engines', []).insert(0, engine_object) + + return add_engine_name_to_path(json_data, engine_path, force) + + +def register_gem_path(json_data: dict, + gem_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not gem_path: + logger.error(f'Gem path cannot be empty.') + return 1 + gem_path = pathlib.Path(gem_path).resolve() + + if engine_path: + engine_data = manifest.find_engine_data(json_data, engine_path) + if not engine_data: + logger.error(f'Engine path {engine_path} is not registered.') + return 1 + + while gem_path in engine_data['gems']: + engine_data['gems'].remove(gem_path) + + while gem_path.as_posix() in engine_data['gems']: + engine_data['gems'].remove(gem_path.as_posix()) + + if remove: + logger.warn(f'Removing Gem path {gem_path}.') + return 0 + else: + while gem_path in json_data['gems']: + json_data['gems'].remove(gem_path) + + while gem_path.as_posix() in json_data['gems']: + json_data['gems'].remove(gem_path.as_posix()) + + if remove: + logger.warn(f'Removing Gem path {gem_path}.') + return 0 + + if not gem_path.is_dir(): + logger.error(f'Gem path {gem_path} does not exist.') + return 1 + + gem_json = gem_path / 'gem.json' + if not validation.valid_o3de_gem_json(gem_json): + logger.error(f'Gem json {gem_json} is not valid.') + return 1 + + if engine_path: + engine_data['gems'].insert(0, gem_path.as_posix()) + else: + json_data['gems'].insert(0, gem_path.as_posix()) + + return 0 + + +def register_project_path(json_data: dict, + project_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not project_path: + logger.error(f'Project path cannot be empty.') + return 1 + project_path = pathlib.Path(project_path).resolve() + + if engine_path: + engine_data = manifest.find_engine_data(json_data, engine_path) + if not engine_data: + logger.error(f'Engine path {engine_path} is not registered.') + return 1 + + while project_path in engine_data['projects']: + engine_data['projects'].remove(project_path) + + while project_path.as_posix() in engine_data['projects']: + engine_data['projects'].remove(project_path.as_posix()) + + if remove: + logger.warn(f'Engine {engine_path} removing Project path {project_path}.') + return 0 + else: + while project_path in json_data['projects']: + json_data['projects'].remove(project_path) + + while project_path.as_posix() in json_data['projects']: + json_data['projects'].remove(project_path.as_posix()) + + if remove: + logger.warn(f'Removing Project path {project_path}.') + return 0 + + if not project_path.is_dir(): + logger.error(f'Project path {project_path} does not exist.') + return 1 + + project_json = project_path / 'project.json' + if not validation.valid_o3de_project_json(project_json): + logger.error(f'Project json {project_json} is not valid.') + return 1 + + if engine_path: + engine_data['projects'].insert(0, project_path.as_posix()) + else: + json_data['projects'].insert(0, project_path.as_posix()) + + # registering a project has the additional step of setting the project.json 'engine' field + this_engine_json = manifest.get_this_engine_path() / 'engine.json' + with this_engine_json.open('r') as f: + try: + this_engine_json = json.load(f) + except Exception as e: + logger.error(f'Engine json failed to load: {str(e)}') + return 1 + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except Exception as e: + logger.error(f'Project json failed to load: {str(e)}') + return 1 + + update_project_json = False + try: + update_project_json = project_json_data['engine'] != this_engine_json['engine_name'] + except Exception as e: + update_project_json = True + + if update_project_json: + project_json_data['engine'] = this_engine_json['engine_name'] + utils.backup_file(project_json) + with project_json.open('w') as s: + try: + s.write(json.dumps(project_json_data, indent=4)) + except Exception as e: + logger.error(f'Project json failed to save: {str(e)}') + return 1 + + return 0 + + +def register_template_path(json_data: dict, + template_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not template_path: + logger.error(f'Template path cannot be empty.') + return 1 + template_path = pathlib.Path(template_path).resolve() + + if engine_path: + engine_data = manifest.find_engine_data(json_data, engine_path) + if not engine_data: + logger.error(f'Engine path {engine_path} is not registered.') + return 1 + + while template_path in engine_data['templates']: + engine_data['templates'].remove(template_path) + + while template_path.as_posix() in engine_data['templates']: + engine_data['templates'].remove(template_path.as_posix()) + + if remove: + logger.warn(f'Engine {engine_path} removing Template path {template_path}.') + return 0 + else: + while template_path in json_data['templates']: + json_data['templates'].remove(template_path) + + while template_path.as_posix() in json_data['templates']: + json_data['templates'].remove(template_path.as_posix()) + + if remove: + logger.warn(f'Removing Template path {template_path}.') + return 0 + + if not template_path.is_dir(): + logger.error(f'Template path {template_path} does not exist.') + return 1 + + template_json = template_path / 'template.json' + if not validation.valid_o3de_template_json(template_json): + logger.error(f'Template json {template_json} is not valid.') + return 1 + + if engine_path: + engine_data['templates'].insert(0, template_path.as_posix()) + else: + json_data['templates'].insert(0, template_path.as_posix()) + + return 0 + + +def register_restricted_path(json_data: dict, + restricted_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + if not restricted_path: + logger.error(f'Restricted path cannot be empty.') + return 1 + restricted_path = pathlib.Path(restricted_path).resolve() + + if engine_path: + engine_data = manifest.find_engine_data(json_data, engine_path) + if not engine_data: + logger.error(f'Engine path {engine_path} is not registered.') + return 1 + + while restricted_path in engine_data['restricted']: + engine_data['restricted'].remove(restricted_path) + + while restricted_path.as_posix() in engine_data['restricted']: + engine_data['restricted'].remove(restricted_path.as_posix()) + + if remove: + logger.warn(f'Engine {engine_path} removing Restricted path {restricted_path}.') + return 0 + else: + while restricted_path in json_data['restricted']: + json_data['restricted'].remove(restricted_path) + + while restricted_path.as_posix() in json_data['restricted']: + json_data['restricted'].remove(restricted_path.as_posix()) + + if remove: + logger.warn(f'Removing Restricted path {restricted_path}.') + return 0 + + if not restricted_path.is_dir(): + logger.error(f'Restricted path {restricted_path} does not exist.') + return 1 + + restricted_json = restricted_path / 'restricted.json' + if not validation.valid_o3de_restricted_json(restricted_json): + logger.error(f'Restricted json {restricted_json} is not valid.') + return 1 + + if engine_path: + engine_data['restricted'].insert(0, restricted_path.as_posix()) + else: + json_data['restricted'].insert(0, restricted_path.as_posix()) + + return 0 + + +def register_repo(json_data: dict, + repo_uri: str or pathlib.Path, + remove: bool = False) -> int: + if not repo_uri: + logger.error(f'Repo URI cannot be empty.') + return 1 + + url = f'{repo_uri}/repo.json' + parsed_uri = urllib.parse.urlparse(url) + + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + while repo_uri in json_data['repos']: + json_data['repos'].remove(repo_uri) + else: + repo_uri = pathlib.Path(repo_uri).resolve() + while repo_uri.as_posix() in json_data['repos']: + json_data['repos'].remove(repo_uri.as_posix()) + + if remove: + logger.warn(f'Removing repo uri {repo_uri}.') + return 0 + + repo_sha256 = hashlib.sha256(url.encode()) + cache_file = manifest.get_o3de_cache_folder() / str(repo_sha256.hexdigest() + '.json') + + result = 0 + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + if not cache_file.is_file(): + with urllib.request.urlopen(url) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + json_data['repos'].insert(0, repo_uri) + else: + if not cache_file.is_file(): + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, origin_file) + json_data['repos'].insert(0, repo_uri.as_posix()) + + repo_set = set() + result = repo.process_add_o3de_repo(cache_file, repo_set) + + return result + + +def register_default_engines_folder(json_data: dict, + default_engines_folder: str or pathlib.Path, + remove: bool = False) -> int: + if remove: + default_engines_folder = manifest.get_o3de_engines_folder() + + # make sure the path exists + default_engines_folder = pathlib.Path(default_engines_folder).resolve() + if not default_engines_folder.is_dir(): + logger.error(f'Default engines folder {default_engines_folder} does not exist.') + return 1 + + default_engines_folder = default_engines_folder.as_posix() + json_data['default_engines_folder'] = default_engines_folder + + return 0 + + +def register_default_projects_folder(json_data: dict, + default_projects_folder: str or pathlib.Path, + remove: bool = False) -> int: + if remove: + default_projects_folder = manifest.get_o3de_projects_folder() + + # make sure the path exists + default_projects_folder = pathlib.Path(default_projects_folder).resolve() + if not default_projects_folder.is_dir(): + logger.error(f'Default projects folder {default_projects_folder} does not exist.') + return 1 + + default_projects_folder = default_projects_folder.as_posix() + json_data['default_projects_folder'] = default_projects_folder + + return 0 + + +def register_default_gems_folder(json_data: dict, + default_gems_folder: str or pathlib.Path, + remove: bool = False) -> int: + if remove: + default_gems_folder = manifest.get_o3de_gems_folder() + + # make sure the path exists + default_gems_folder = pathlib.Path(default_gems_folder).resolve() + if not default_gems_folder.is_dir(): + logger.error(f'Default gems folder {default_gems_folder} does not exist.') + return 1 + + default_gems_folder = default_gems_folder.as_posix() + json_data['default_gems_folder'] = default_gems_folder + + return 0 + + +def register_default_templates_folder(json_data: dict, + default_templates_folder: str or pathlib.Path, + remove: bool = False) -> int: + if remove: + default_templates_folder = manifest.get_o3de_templates_folder() + + # make sure the path exists + default_templates_folder = pathlib.Path(default_templates_folder).resolve() + if not default_templates_folder.is_dir(): + logger.error(f'Default templates folder {default_templates_folder} does not exist.') + return 1 + + default_templates_folder = default_templates_folder.as_posix() + json_data['default_templates_folder'] = default_templates_folder + + return 0 + + +def register_default_restricted_folder(json_data: dict, + default_restricted_folder: str or pathlib.Path, + remove: bool = False) -> int: + if remove: + default_restricted_folder = manifest.get_o3de_restricted_folder() + + # make sure the path exists + default_restricted_folder = pathlib.Path(default_restricted_folder).resolve() + if not default_restricted_folder.is_dir(): + logger.error(f'Default restricted folder {default_restricted_folder} does not exist.') + return 1 + + default_restricted_folder = default_restricted_folder.as_posix() + json_data['default_restricted_folder'] = default_restricted_folder + + return 0 + + +def register(engine_path: str or pathlib.Path = None, + project_path: str or pathlib.Path = None, + gem_path: str or pathlib.Path = None, + template_path: str or pathlib.Path = None, + restricted_path: str or pathlib.Path = None, + repo_uri: str or pathlib.Path = None, + default_engines_folder: str or pathlib.Path = None, + default_projects_folder: str or pathlib.Path = None, + default_gems_folder: str or pathlib.Path = None, + default_templates_folder: str or pathlib.Path = None, + default_restricted_folder: str or pathlib.Path = None, + remove: bool = False, + force: bool = False + ) -> int: + """ + Adds/Updates entries to the .o3de/o3de_manifest.json + + :param engine_path: if engine folder is supplied the path will be added to the engine if it can, if not global + :param project_path: project folder + :param gem_path: gem folder + :param template_path: template folder + :param restricted_path: restricted folder + :param repo_uri: repo uri + :param default_engines_folder: default engines folder + :param default_projects_folder: default projects folder + :param default_gems_folder: default gems folder + :param default_templates_folder: default templates folder + :param default_restricted_folder: default restricted code folder + :param remove: add/remove the entries + :param force: force update of the engine_path for specified "engine_name" from the engine.json file + + :return: 0 for success or non 0 failure code + """ + + json_data = manifest.load_o3de_manifest() + + result = 0 + + # do anything that could require a engine context first + if isinstance(project_path, str) or isinstance(project_path, pathlib.PurePath): + if not project_path: + logger.error(f'Project path cannot be empty.') + return 1 + result = register_project_path(json_data, project_path, remove, engine_path) + + elif isinstance(gem_path, str) or isinstance(gem_path, pathlib.PurePath): + if not gem_path: + logger.error(f'Gem path cannot be empty.') + return 1 + result = register_gem_path(json_data, gem_path, remove, engine_path) + + elif isinstance(template_path, str) or isinstance(template_path, pathlib.PurePath): + if not template_path: + logger.error(f'Template path cannot be empty.') + return 1 + result = register_template_path(json_data, template_path, remove, engine_path) + + elif isinstance(restricted_path, str) or isinstance(restricted_path, pathlib.PurePath): + if not restricted_path: + logger.error(f'Restricted path cannot be empty.') + return 1 + result = register_restricted_path(json_data, restricted_path, remove, engine_path) + + elif isinstance(repo_uri, str) or isinstance(repo_uri, pathlib.PurePath): + if not repo_uri: + logger.error(f'Repo URI cannot be empty.') + return 1 + result = register_repo(json_data, repo_uri, remove) + + elif isinstance(default_engines_folder, str) or isinstance(default_engines_folder, pathlib.PurePath): + result = register_default_engines_folder(json_data, default_engines_folder, remove) + + elif isinstance(default_projects_folder, str) or isinstance(default_projects_folder, pathlib.PurePath): + result = register_default_projects_folder(json_data, default_projects_folder, remove) + + elif isinstance(default_gems_folder, str) or isinstance(default_gems_folder, pathlib.PurePath): + result = register_default_gems_folder(json_data, default_gems_folder, remove) + + elif isinstance(default_templates_folder, str) or isinstance(default_templates_folder, pathlib.PurePath): + result = register_default_templates_folder(json_data, default_templates_folder, remove) + + elif isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath): + result = register_default_restricted_folder(json_data, default_restricted_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 + elif isinstance(engine_path, str) or isinstance(engine_path, pathlib.PurePath): + if not engine_path: + logger.error(f'Engine path cannot be empty.') + return 1 + result = register_engine_path(json_data, engine_path, remove, force) + + if not result: + manifest.save_o3de_manifest(json_data) + + return result + + +def remove_invalid_o3de_objects() -> None: + json_data = manifest.load_o3de_manifest() + + for engine_object in json_data['engines']: + engine_path = engine_object['path'] + if not validation.valid_o3de_engine_json(pathlib.Path(engine_path).resolve() / 'engine.json'): + logger.warn(f"Engine path {engine_path} is invalid.") + register(engine_path=engine_path, remove=True) + else: + for project in engine_object['projects']: + if not validation.valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): + logger.warn(f"Project path {project} is invalid.") + register(engine_path=engine_path, project_path=project, remove=True) + + for gem_path in engine_object['gems']: + if not validation.valid_o3de_gem_json(pathlib.Path(gem_path).resolve() / 'gem.json'): + logger.warn(f"Gem path {gem_path} is invalid.") + register(engine_path=engine_path, gem_path=gem_path, remove=True) + + for template_path in engine_object['templates']: + if not validation.valid_o3de_template_json(pathlib.Path(template_path).resolve() / 'template.json'): + logger.warn(f"Template path {template_path} is invalid.") + register(engine_path=engine_path, template_path=template_path, remove=True) + + for restricted in engine_object['restricted']: + if not validation.valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'): + logger.warn(f"Restricted path {restricted} is invalid.") + register(engine_path=engine_path, restricted_path=restricted, remove=True) + + for external in engine_object['external_subdirectories']: + external = pathlib.Path(external).resolve() + if not external.is_dir(): + logger.warn(f"External subdirectory {external} is invalid.") + remove_external_subdirectory.remove_external_subdirectory(external) + + for project in json_data['projects']: + if not validation.valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): + logger.warn(f"Project path {project} is invalid.") + register(project_path=project, remove=True) + + for gem in json_data['gems']: + if not validation.valid_o3de_gem_json(pathlib.Path(gem).resolve() / 'gem.json'): + logger.warn(f"Gem path {gem} is invalid.") + register(gem_path=gem, remove=True) + + for template in json_data['templates']: + if not validation.valid_o3de_template_json(pathlib.Path(template).resolve() / 'template.json'): + logger.warn(f"Template path {template} is invalid.") + register(template_path=template, remove=True) + + for restricted in json_data['restricted']: + if not validation.valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'): + logger.warn(f"Restricted path {restricted} is invalid.") + register(restricted_path=restricted, remove=True) + + default_engines_folder = pathlib.Path(json_data['default_engines_folder']).resolve() + if not default_engines_folder.is_dir(): + new_default_engines_folder = manifest.get_o3de_folder() / 'Engines' + new_default_engines_folder.mkdir(parents=True, exist_ok=True) + logger.warn( + f"Default engines folder {default_engines_folder} is invalid. Set default {new_default_engines_folder}") + register(default_engines_folder=new_default_engines_folder.as_posix()) + + default_projects_folder = pathlib.Path(json_data['default_projects_folder']).resolve() + if not default_projects_folder.is_dir(): + new_default_projects_folder = manifest.get_o3de_folder() / 'Projects' + new_default_projects_folder.mkdir(parents=True, exist_ok=True) + logger.warn( + f"Default projects folder {default_projects_folder} is invalid. Set default {new_default_projects_folder}") + register(default_projects_folder=new_default_projects_folder.as_posix()) + + default_gems_folder = pathlib.Path(json_data['default_gems_folder']).resolve() + if not default_gems_folder.is_dir(): + new_default_gems_folder = manifest.get_o3de_folder() / 'Gems' + new_default_gems_folder.mkdir(parents=True, exist_ok=True) + logger.warn(f"Default gems folder {default_gems_folder} is invalid." + f" Set default {new_default_gems_folder}") + register(default_gems_folder=new_default_gems_folder.as_posix()) + + default_templates_folder = pathlib.Path(json_data['default_templates_folder']).resolve() + if not default_templates_folder.is_dir(): + new_default_templates_folder = manifest.get_o3de_folder() / 'Templates' + new_default_templates_folder.mkdir(parents=True, exist_ok=True) + logger.warn( + f"Default templates folder {default_templates_folder} is invalid." + f" Set default {new_default_templates_folder}") + register(default_templates_folder=new_default_templates_folder.as_posix()) + + default_restricted_folder = pathlib.Path(json_data['default_restricted_folder']).resolve() + if not default_restricted_folder.is_dir(): + default_restricted_folder = manifest.get_o3de_folder() / 'Restricted' + default_restricted_folder.mkdir(parents=True, exist_ok=True) + logger.warn( + f"Default restricted folder {default_restricted_folder} is invalid." + f" Set default {default_restricted_folder}") + register(default_restricted_folder=default_restricted_folder.as_posix()) + + +def _run_register(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + if args.update: + remove_invalid_o3de_objects() + return repo.refresh_repos() + elif args.this_engine: + ret_val = register(engine_path=manifest.get_this_engine_path(), force=args.force) + error_code = register_shipped_engine_o3de_objects(force=args.force) + if error_code: + ret_val = error_code + return ret_val + elif args.all_engines_path: + return register_all_engines_in_folder(args.all_engines_path, args.remove, args.force) + elif args.all_projects_path: + return register_all_projects_in_folder(args.all_projects_path, args.remove) + elif args.all_gems_path: + return register_all_gems_in_folder(args.all_gems_path, args.remove) + elif args.all_templates_path: + return register_all_templates_in_folder(args.all_templates_path, args.remove) + elif args.all_restricted_path: + return register_all_restricted_in_folder(args.all_restricted_path, args.remove) + elif args.all_repo_uri: + return register_all_repos_in_folder(args.all_restricted_path, args.remove) + else: + return register(engine_path=args.engine_path, + project_path=args.project_path, + gem_path=args.gem_path, + template_path=args.template_path, + restricted_path=args.restricted_path, + repo_uri=args.repo_uri, + default_engines_folder=args.default_engines_folder, + default_projects_folder=args.default_projects_folder, + default_gems_folder=args.default_gems_folder, + default_templates_folder=args.default_templates_folder, + default_restricted_folder=args.default_restricted_folder, + remove=args.remove, + force=args.force) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + # register + register_subparser = subparsers.add_parser('register') + group = register_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('--this-engine', action='store_true', required=False, + default=False, + help='Registers the engine this script is running from.') + group.add_argument('-ep', '--engine-path', type=str, required=False, + help='Engine path to register/remove.') + group.add_argument('-pp', '--project-path', type=str, required=False, + help='Project path to register/remove.') + group.add_argument('-gp', '--gem-path', type=str, required=False, + help='Gem path to register/remove.') + group.add_argument('-tp', '--template-path', type=str, required=False, + help='Template path to register/remove.') + group.add_argument('-rp', '--restricted-path', type=str, required=False, + help='A restricted folder to register/remove.') + group.add_argument('-ru', '--repo-uri', type=str, required=False, + help='A repo uri to register/remove.') + group.add_argument('-aep', '--all-engines-path', type=str, required=False, + help='All engines under this folder to register/remove.') + group.add_argument('-app', '--all-projects-path', type=str, required=False, + help='All projects under this folder to register/remove.') + group.add_argument('-agp', '--all-gems-path', type=str, required=False, + help='All gems under this folder to register/remove.') + group.add_argument('-atp', '--all-templates-path', type=str, required=False, + help='All templates under this folder to register/remove.') + group.add_argument('-arp', '--all-restricted-path', type=str, required=False, + help='All templates under this folder to register/remove.') + group.add_argument('-aru', '--all-repo-uri', type=str, required=False, + help='All repos under this folder to register/remove.') + group.add_argument('-def', '--default-engines-folder', type=str, required=False, + help='The default engines folder to register/remove.') + group.add_argument('-dpf', '--default-projects-folder', type=str, required=False, + help='The default projects folder to register/remove.') + group.add_argument('-dgf', '--default-gems-folder', type=str, required=False, + help='The default gems folder to register/remove.') + group.add_argument('-dtf', '--default-templates-folder', type=str, required=False, + 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('-u', '--update', action='store_true', required=False, + default=False, + help='Refresh the repo cache.') + + register_subparser.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.') + + register_subparser.add_argument('-r', '--remove', action='store_true', required=False, + default=False, + help='Remove entry.') + register_subparser.add_argument('-f', '--force', action='store_true', default=False, + help='For the update of the registration field being modified.') + register_subparser.set_defaults(func=_run_register) diff --git a/scripts/o3de/o3de/registration.py b/scripts/o3de/o3de/registration.py index 6a165cbea5..801c698ca4 100755 --- a/scripts/o3de/o3de/registration.py +++ b/scripts/o3de/o3de/registration.py @@ -13,4074 +13,7 @@ This file contains all the code that has to do with registering engines, project """ import argparse -import logging -import os import sys -import json -import pathlib -import hashlib -import shutil -import zipfile -import urllib.parse -import urllib.request - -logger = logging.getLogger() -logging.basicConfig() - - -def backup_file(file_name: str or pathlib.Path) -> None: - index = 0 - renamed = False - while not renamed: - backup_file_name = pathlib.Path(str(file_name) + '.bak' + str(index)).resolve() - index += 1 - if not backup_file_name.is_file(): - file_name = pathlib.Path(file_name).resolve() - file_name.rename(backup_file_name) - if backup_file_name.is_file(): - renamed = True - - -def backup_folder(folder: str or pathlib.Path) -> None: - index = 0 - renamed = False - while not renamed: - backup_folder_name = pathlib.Path(str(folder) + '.bak' + str(index)).resolve() - index += 1 - if not backup_folder_name.is_dir(): - folder = pathlib.Path(folder).resolve() - folder.rename(backup_folder_name) - if backup_folder_name.is_dir(): - renamed = True - - -def get_this_engine_path() -> pathlib.Path: - return pathlib.Path(os.path.realpath(__file__)).parents[3].resolve() - - -override_home_folder = None - - -def get_home_folder() -> pathlib.Path: - if override_home_folder: - return pathlib.Path(override_home_folder).resolve() - else: - return pathlib.Path(os.path.expanduser("~")).resolve() - - -def get_o3de_folder() -> pathlib.Path: - o3de_folder = get_home_folder() / '.o3de' - o3de_folder.mkdir(parents=True, exist_ok=True) - return o3de_folder - - -def get_o3de_registry_folder() -> pathlib.Path: - registry_folder = get_o3de_folder() / 'Registry' - registry_folder.mkdir(parents=True, exist_ok=True) - return registry_folder - - -def get_o3de_cache_folder() -> pathlib.Path: - cache_folder = get_o3de_folder() / 'Cache' - cache_folder.mkdir(parents=True, exist_ok=True) - return cache_folder - - -def get_o3de_download_folder() -> pathlib.Path: - download_folder = get_o3de_folder() / 'Download' - download_folder.mkdir(parents=True, exist_ok=True) - return download_folder - - -def get_o3de_engines_folder() -> pathlib.Path: - engines_folder = get_o3de_folder() / 'Engines' - engines_folder.mkdir(parents=True, exist_ok=True) - return engines_folder - - -def get_o3de_projects_folder() -> pathlib.Path: - projects_folder = get_o3de_folder() / 'Projects' - projects_folder.mkdir(parents=True, exist_ok=True) - return projects_folder - - -def get_o3de_gems_folder() -> pathlib.Path: - gems_folder = get_o3de_folder() / 'Gems' - gems_folder.mkdir(parents=True, exist_ok=True) - return gems_folder - - -def get_o3de_templates_folder() -> pathlib.Path: - templates_folder = get_o3de_folder() / 'Templates' - templates_folder.mkdir(parents=True, exist_ok=True) - return templates_folder - - -def get_o3de_restricted_folder() -> pathlib.Path: - restricted_folder = get_o3de_folder() / 'Restricted' - restricted_folder.mkdir(parents=True, exist_ok=True) - return restricted_folder - - -def get_o3de_logs_folder() -> pathlib.Path: - logs_folder = get_o3de_folder() / 'Logs' - logs_folder.mkdir(parents=True, exist_ok=True) - return logs_folder - - -def register_shipped_engine_o3de_objects(force: bool = False) -> int: - engine_path = get_this_engine_path() - - ret_val = 0 - - # directories with engines - starting_engines_directories = [ - ] - for engines_directory in sorted(starting_engines_directories, reverse=True): - error_code = register_all_engines_in_folder(engines_path=engines_directory, force=force) - if error_code: - ret_val = error_code - - # specific engines - starting_engines = [ - ] - for engine_path in sorted(starting_engines): - error_code = register(engine_path=engine_path, force=force) - if error_code: - ret_val = error_code - - # directories with projects - starting_projects_directories = [ - ] - for projects_directory in sorted(starting_projects_directories, reverse=True): - error_code = register_all_projects_in_folder(engine_path=engine_path, projects_path=projects_directory) - if error_code: - ret_val = error_code - - # specific projects - starting_projects = [ - f'{engine_path}/AutomatedTesting' - ] - for project_path in sorted(starting_projects, reverse=True): - error_code = register(engine_path=engine_path, project_path=project_path, force=force) - if error_code: - ret_val = error_code - - # directories with gems - starting_gems_directories = [ - f'{engine_path}/Gems' - ] - for gems_directory in sorted(starting_gems_directories, reverse=True): - error_code = register_all_gems_in_folder(engine_path=engine_path, gems_path=gems_directory) - if error_code: - ret_val = error_code - - # specific gems - starting_gems = [ - ] - for gem_path in sorted(starting_gems, reverse=True): - error_code = register(engine_path=engine_path, gem_path=gem_path, force=force) - if error_code: - ret_val = error_code - - # directories with templates - starting_templates_directories = [ - f'{engine_path}/Templates' - ] - for templates_directory in sorted(starting_templates_directories, reverse=True): - error_code = register_all_templates_in_folder(engine_path=engine_path, templates_path=templates_directory) - if error_code: - ret_val = error_code - - # specific templates - starting_templates = [ - ] - for template_path in sorted(starting_templates, reverse=True): - error_code = register(engine_path=engine_path, template_path=template_path, force=force) - if error_code: - ret_val = error_code - - # directories with restricted - starting_restricted_directories = [ - ] - for restricted_directory in sorted(starting_restricted_directories, reverse=True): - error_code = register_all_restricted_in_folder(engine_path=engine_path, restricted_path=restricted_directory) - if error_code: - ret_val = error_code - - # specific restricted - starting_restricted = [ - ] - for restricted_path in sorted(starting_restricted, reverse=True): - error_code = register(engine_path=engine_path, restricted_path=restricted_path, force=force) - if error_code: - ret_val = error_code - - # directories with repos - starting_repo_directories = [ - ] - for repos_directory in sorted(starting_repo_directories, reverse=True): - error_code = register_all_repos_in_folder(engine_path=engine_path, repos_path=repos_directory) - if error_code: - ret_val = error_code - - # specific repos - starting_repos = [ - ] - for repo_uri in sorted(starting_repos, reverse=True): - error_code = register(repo_uri=repo_uri, force=force) - if error_code: - ret_val = error_code - - # register anything in the users default folders globally - error_code = register_all_engines_in_folder(get_registered(default_folder='engines'), force=force) - if error_code: - ret_val = error_code - error_code = register_all_projects_in_folder(get_registered(default_folder='projects')) - if error_code: - ret_val = error_code - error_code = register_all_gems_in_folder(get_registered(default_folder='gems')) - if error_code: - ret_val = error_code - error_code = register_all_templates_in_folder(get_registered(default_folder='templates')) - if error_code: - ret_val = error_code - error_code = register_all_restricted_in_folder(get_registered(default_folder='restricted')) - if error_code: - ret_val = error_code - error_code = register_all_restricted_in_folder(get_registered(default_folder='projects')) - if error_code: - ret_val = error_code - error_code = register_all_restricted_in_folder(get_registered(default_folder='gems')) - if error_code: - ret_val = error_code - error_code = register_all_restricted_in_folder(get_registered(default_folder='templates')) - if error_code: - ret_val = error_code - - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - gems = json_data['gems'].copy() - gems.extend(engine_object['gems']) - for gem_path in sorted(gems, key=len): - gem_path = pathlib.Path(gem_path).resolve() - gem_cmake_lists_txt = gem_path / 'CMakeLists.txt' - if gem_cmake_lists_txt.is_file(): - add_gem_to_cmake(engine_path=engine_path, gem_path=gem_path, suppress_errors=True) # don't care about errors - - return ret_val - - -def register_all_in_folder(folder_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None, - exclude: list = None) -> int: - if not folder_path: - logger.error(f'Folder path cannot be empty.') - return 1 - - folder_path = pathlib.Path(folder_path).resolve() - if not folder_path.is_dir(): - logger.error(f'Folder path is not dir.') - return 1 - - engines_set = set() - projects_set = set() - gems_set = set() - templates_set = set() - restricted_set = set() - repo_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(folder_path): - if root in exclude: - continue - - for name in files: - if name == 'engine.json': - engines_set.add(root) - elif name == 'project.json': - projects_set.add(root) - elif name == 'gem.json': - gems_set.add(root) - elif name == 'template.json': - templates_set.add(root) - elif name == 'restricted.json': - restricted_set.add(root) - elif name == 'repo.json': - repo_set.add(root) - - for engine in sorted(engines_set, reverse=True): - error_code = register(engine_path=engine, remove=remove) - if error_code: - ret_val = error_code - - for project in sorted(projects_set, reverse=True): - error_code = register(engine_path=engine_path, project_path=project, remove=remove) - if error_code: - ret_val = error_code - - for gem in sorted(gems_set, reverse=True): - error_code = register(engine_path=engine_path, gem_path=gem, remove=remove) - if error_code: - ret_val = error_code - - for template in sorted(templates_set, reverse=True): - error_code = register(engine_path=engine_path, template_path=template, remove=remove) - if error_code: - ret_val = error_code - - for restricted in sorted(restricted_set, reverse=True): - error_code = register(engine_path=engine_path, restricted_path=restricted, remove=remove) - if error_code: - ret_val = error_code - - for repo in sorted(repo_set, reverse=True): - error_code = register(engine_path=engine_path, repo_uri=repo, remove=remove) - if error_code: - ret_val = error_code - - return ret_val - - -def register_all_engines_in_folder(engines_path: str or pathlib.Path, - remove: bool = False, - force: bool = False) -> int: - if not engines_path: - logger.error(f'Engines path cannot be empty.') - return 1 - - engines_path = pathlib.Path(engines_path).resolve() - if not engines_path.is_dir(): - logger.error(f'Engines path is not dir.') - return 1 - - engines_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(engines_path): - for name in files: - if name == 'engine.json': - engines_set.add(root) - - for engine in sorted(engines_set, reverse=True): - error_code = register(engine_path=engine, remove=remove, force=force) - if error_code: - ret_val = error_code - - return ret_val - - -def register_all_projects_in_folder(projects_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not projects_path: - logger.error(f'Projects path cannot be empty.') - return 1 - - projects_path = pathlib.Path(projects_path).resolve() - if not projects_path.is_dir(): - logger.error(f'Projects path is not dir.') - return 1 - - projects_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(projects_path): - for name in files: - if name == 'project.json': - projects_set.add(root) - - for project in sorted(projects_set, reverse=True): - error_code = register(engine_path=engine_path, project_path=project, remove=remove) - if error_code: - ret_val = error_code - - return ret_val - - -def register_all_gems_in_folder(gems_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not gems_path: - logger.error(f'Gems path cannot be empty.') - return 1 - - gems_path = pathlib.Path(gems_path).resolve() - if not gems_path.is_dir(): - logger.error(f'Gems path is not dir.') - return 1 - - gems_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(gems_path): - for name in files: - if name == 'gem.json': - gems_set.add(root) - - for gem in sorted(gems_set, reverse=True): - error_code = register(engine_path=engine_path, gem_path=gem, remove=remove) - if error_code: - ret_val = error_code - - return ret_val - - -def register_all_templates_in_folder(templates_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not templates_path: - logger.error(f'Templates path cannot be empty.') - return 1 - - templates_path = pathlib.Path(templates_path).resolve() - if not templates_path.is_dir(): - logger.error(f'Templates path is not dir.') - return 1 - - templates_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(templates_path): - for name in files: - if name == 'template.json': - templates_set.add(root) - - for template in sorted(templates_set, reverse=True): - error_code = register(engine_path=engine_path, template_path=template, remove=remove) - if error_code: - ret_val = error_code - - return ret_val - - -def register_all_restricted_in_folder(restricted_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not restricted_path: - logger.error(f'Restricted path cannot be empty.') - return 1 - - restricted_path = pathlib.Path(restricted_path).resolve() - if not restricted_path.is_dir(): - logger.error(f'Restricted path is not dir.') - return 1 - - restricted_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(restricted_path): - for name in files: - if name == 'restricted.json': - restricted_set.add(root) - - for restricted in sorted(restricted_set, reverse=True): - error_code = register(engine_path=engine_path, restricted_path=restricted, remove=remove) - if error_code: - ret_val = error_code - - return ret_val - - -def register_all_repos_in_folder(repos_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not repos_path: - logger.error(f'Repos path cannot be empty.') - return 1 - - repos_path = pathlib.Path(repos_path).resolve() - if not repos_path.is_dir(): - logger.error(f'Repos path is not dir.') - return 1 - - repo_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(repos_path): - for name in files: - if name == 'repo.json': - repo_set.add(root) - - for repo in sorted(repo_set, reverse=True): - error_code = register(engine_path=engine_path, repo_uri=repo, remove=remove) - if error_code: - ret_val = error_code - - return ret_val - - -def get_o3de_manifest() -> pathlib.Path: - manifest_path = get_o3de_folder() / 'o3de_manifest.json' - if not manifest_path.is_file(): - username = os.path.split(get_home_folder())[-1] - - o3de_folder = get_o3de_folder() - default_registry_folder = get_o3de_registry_folder() - default_cache_folder = get_o3de_cache_folder() - default_downloads_folder = get_o3de_download_folder() - default_logs_folder = get_o3de_logs_folder() - default_engines_folder = get_o3de_engines_folder() - default_projects_folder = get_o3de_projects_folder() - default_gems_folder = get_o3de_gems_folder() - default_templates_folder = get_o3de_templates_folder() - default_restricted_folder = get_o3de_restricted_folder() - - default_projects_restricted_folder = default_projects_folder / 'Restricted' - default_projects_restricted_folder.mkdir(parents=True, exist_ok=True) - default_gems_restricted_folder = default_gems_folder / 'Restricted' - default_gems_restricted_folder.mkdir(parents=True, exist_ok=True) - default_templates_restricted_folder = default_templates_folder / 'Restricted' - default_templates_restricted_folder.mkdir(parents=True, exist_ok=True) - - json_data = {} - json_data.update({'o3de_manifest_name': f'{username}'}) - json_data.update({'origin': o3de_folder.as_posix()}) - json_data.update({'default_engines_folder': default_engines_folder.as_posix()}) - json_data.update({'default_projects_folder': default_projects_folder.as_posix()}) - 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({'projects': []}) - json_data.update({'gems': []}) - json_data.update({'templates': []}) - json_data.update({'restricted': []}) - json_data.update({'repos': []}) - json_data.update({'engines': []}) - - default_restricted_folder_json = default_restricted_folder / 'restricted.json' - if not default_restricted_folder_json.is_file(): - with default_restricted_folder_json.open('w') as s: - restricted_json_data = {} - restricted_json_data.update({'restricted_name': 'o3de'}) - s.write(json.dumps(restricted_json_data, indent=4)) - json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) - - default_projects_restricted_folder_json = default_projects_restricted_folder / 'restricted.json' - if not default_projects_restricted_folder_json.is_file(): - with default_projects_restricted_folder_json.open('w') as s: - restricted_json_data = {} - restricted_json_data.update({'restricted_name': 'projects'}) - s.write(json.dumps(restricted_json_data, indent=4)) - - default_gems_restricted_folder_json = default_gems_restricted_folder / 'restricted.json' - if not default_gems_restricted_folder_json.is_file(): - with default_gems_restricted_folder_json.open('w') as s: - restricted_json_data = {} - restricted_json_data.update({'restricted_name': 'gems'}) - s.write(json.dumps(restricted_json_data, indent=4)) - - default_templates_restricted_folder_json = default_templates_restricted_folder / 'restricted.json' - if not default_templates_restricted_folder_json.is_file(): - with default_templates_restricted_folder_json.open('w') as s: - restricted_json_data = {} - restricted_json_data.update({'restricted_name': 'templates'}) - s.write(json.dumps(restricted_json_data, indent=4)) - - with manifest_path.open('w') as s: - s.write(json.dumps(json_data, indent=4)) - - return manifest_path - - -def load_o3de_manifest() -> dict: - with get_o3de_manifest().open('r') as f: - try: - json_data = json.load(f) - except Exception as e: - logger.error(f'Manifest json failed to load: {str(e)}') - else: - return json_data - - -def save_o3de_manifest(json_data: dict) -> None: - with get_o3de_manifest().open('w') as s: - try: - s.write(json.dumps(json_data, indent=4)) - except Exception as e: - logger.error(f'Manifest json failed to save: {str(e)}') - - -def remove_engine_name_to_path(json_data: dict, - engine_path: pathlib.Path) -> int: - """ - Remove the engine at the specified path if it exist in the o3de manifest - :param json_data in-memory json view of the o3de_manifest.json data - :param engine_path path to engine to remove from the manifest data - - returns 0 to indicate no issues has occurred with removal - """ - if engine_path.is_dir() and valid_o3de_engine_json(engine_path): - engine_json_data = get_engine_data(engine_path=engine_path) - if 'engine_name' in engine_json_data and 'engines_path' in json_data: - engine_name = engine_json_data['engine_name'] - try: - del json_data['engines_path'][engine_name] - except KeyError: - # Attempting to remove a non-existent engine_name is fine - pass - return 0 - - -def add_engine_name_to_path(json_data: dict, engine_path: pathlib.Path, force: bool): - # Add an engine path JSON object which maps the "engine_name" -> "engine_path" - engine_json_data = get_engine_data(engine_path=engine_path) - if not engine_json_data: - logger.error(f'Unable to retrieve json data from engine.json at path {engine_path.as_posix()}') - return 1 - engines_path_json = json_data.setdefault('engines_path', {}) - if 'engine_name' not in engine_json_data: - logger.error(f'engine.json at path {engine_path.as_posix()} is missing "engine_name" key') - return 1 - - engine_name = engine_json_data['engine_name'] - if not force and engine_name in engines_path_json and \ - pathlib.PurePath(engines_path_json[engine_name]) != engine_path: - logger.error( - f'Attempting to register existing engine "{engine_name}" with a new path of {engine_path.as_posix()}.' - f' The current path is {pathlib.Path(engines_path_json[engine_name]).as_posix()}.' - f' To force registration of a new engine path, specify the -f/--force option.') - return 1 - engines_path_json[engine_name] = engine_path.as_posix() - return 0 - -def register_engine_path(json_data: dict, - engine_path: str or pathlib.Path, - remove: bool = False, - force: bool = False) -> int: - if not engine_path: - logger.error(f'Engine path cannot be empty.') - return 1 - engine_path = pathlib.Path(engine_path).resolve() - - for engine_object in json_data.get('engines', {}): - engine_object_path = pathlib.Path(engine_object['path']).resolve() - if engine_object_path == engine_path: - json_data['engines'].remove(engine_object) - - if remove: - return remove_engine_name_to_path(json_data, engine_path) - - if not engine_path.is_dir(): - logger.error(f'Engine path {engine_path} does not exist.') - return 1 - - engine_json = engine_path / 'engine.json' - if not valid_o3de_engine_json(engine_json): - logger.error(f'Engine json {engine_json} is not valid.') - return 1 - - engine_object = {} - engine_object.update({'path': engine_path.as_posix()}) - engine_object.update({'projects': []}) - engine_object.update({'gems': []}) - engine_object.update({'templates': []}) - engine_object.update({'restricted': []}) - engine_object.update({'external_subdirectories': []}) - - json_data.setdefault('engines', []).insert(0, engine_object) - - return add_engine_name_to_path(json_data, engine_path, force) - - -def register_gem_path(json_data: dict, - gem_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not gem_path: - logger.error(f'Gem path cannot be empty.') - return 1 - gem_path = pathlib.Path(gem_path).resolve() - - if engine_path: - engine_data = find_engine_data(json_data, engine_path) - if not engine_data: - logger.error(f'Engine path {engine_path} is not registered.') - return 1 - - while gem_path in engine_data['gems']: - engine_data['gems'].remove(gem_path) - - while gem_path.as_posix() in engine_data['gems']: - engine_data['gems'].remove(gem_path.as_posix()) - - if remove: - logger.warn(f'Removing Gem path {gem_path}.') - return 0 - else: - while gem_path in json_data['gems']: - json_data['gems'].remove(gem_path) - - while gem_path.as_posix() in json_data['gems']: - json_data['gems'].remove(gem_path.as_posix()) - - if remove: - logger.warn(f'Removing Gem path {gem_path}.') - return 0 - - if not gem_path.is_dir(): - logger.error(f'Gem path {gem_path} does not exist.') - return 1 - - gem_json = gem_path / 'gem.json' - if not valid_o3de_gem_json(gem_json): - logger.error(f'Gem json {gem_json} is not valid.') - return 1 - - if engine_path: - engine_data['gems'].insert(0, gem_path.as_posix()) - else: - json_data['gems'].insert(0, gem_path.as_posix()) - - return 0 - - -def register_project_path(json_data: dict, - project_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not project_path: - logger.error(f'Project path cannot be empty.') - return 1 - project_path = pathlib.Path(project_path).resolve() - - if engine_path: - engine_data = find_engine_data(json_data, engine_path) - if not engine_data: - logger.error(f'Engine path {engine_path} is not registered.') - return 1 - - while project_path in engine_data['projects']: - engine_data['projects'].remove(project_path) - - while project_path.as_posix() in engine_data['projects']: - engine_data['projects'].remove(project_path.as_posix()) - - if remove: - logger.warn(f'Engine {engine_path} removing Project path {project_path}.') - return 0 - else: - while project_path in json_data['projects']: - json_data['projects'].remove(project_path) - - while project_path.as_posix() in json_data['projects']: - json_data['projects'].remove(project_path.as_posix()) - - if remove: - logger.warn(f'Removing Project path {project_path}.') - return 0 - - if not project_path.is_dir(): - logger.error(f'Project path {project_path} does not exist.') - return 1 - - project_json = project_path / 'project.json' - if not valid_o3de_project_json(project_json): - logger.error(f'Project json {project_json} is not valid.') - return 1 - - if engine_path: - engine_data['projects'].insert(0, project_path.as_posix()) - else: - json_data['projects'].insert(0, project_path.as_posix()) - - # registering a project has the additional step of setting the project.json 'engine' field - this_engine_json = get_this_engine_path() / 'engine.json' - with this_engine_json.open('r') as f: - try: - this_engine_json = json.load(f) - except Exception as e: - logger.error(f'Engine json failed to load: {str(e)}') - return 1 - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except Exception as e: - logger.error(f'Project json failed to load: {str(e)}') - return 1 - - update_project_json = False - try: - update_project_json = project_json_data['engine'] != this_engine_json['engine_name'] - except Exception as e: - update_project_json = True - - if update_project_json: - project_json_data['engine'] = this_engine_json['engine_name'] - backup_file(project_json) - with project_json.open('w') as s: - try: - s.write(json.dumps(project_json_data, indent=4)) - except Exception as e: - logger.error(f'Project json failed to save: {str(e)}') - return 1 - - return 0 - - -def register_template_path(json_data: dict, - template_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not template_path: - logger.error(f'Template path cannot be empty.') - return 1 - template_path = pathlib.Path(template_path).resolve() - - if engine_path: - engine_data = find_engine_data(json_data, engine_path) - if not engine_data: - logger.error(f'Engine path {engine_path} is not registered.') - return 1 - - while template_path in engine_data['templates']: - engine_data['templates'].remove(template_path) - - while template_path.as_posix() in engine_data['templates']: - engine_data['templates'].remove(template_path.as_posix()) - - if remove: - logger.warn(f'Engine {engine_path} removing Template path {template_path}.') - return 0 - else: - while template_path in json_data['templates']: - json_data['templates'].remove(template_path) - - while template_path.as_posix() in json_data['templates']: - json_data['templates'].remove(template_path.as_posix()) - - if remove: - logger.warn(f'Removing Template path {template_path}.') - return 0 - - if not template_path.is_dir(): - logger.error(f'Template path {template_path} does not exist.') - return 1 - - template_json = template_path / 'template.json' - if not valid_o3de_template_json(template_json): - logger.error(f'Template json {template_json} is not valid.') - return 1 - - if engine_path: - engine_data['templates'].insert(0, template_path.as_posix()) - else: - json_data['templates'].insert(0, template_path.as_posix()) - - return 0 - - -def register_restricted_path(json_data: dict, - restricted_path: str or pathlib.Path, - remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not restricted_path: - logger.error(f'Restricted path cannot be empty.') - return 1 - restricted_path = pathlib.Path(restricted_path).resolve() - - if engine_path: - engine_data = find_engine_data(json_data, engine_path) - if not engine_data: - logger.error(f'Engine path {engine_path} is not registered.') - return 1 - - while restricted_path in engine_data['restricted']: - engine_data['restricted'].remove(restricted_path) - - while restricted_path.as_posix() in engine_data['restricted']: - engine_data['restricted'].remove(restricted_path.as_posix()) - - if remove: - logger.warn(f'Engine {engine_path} removing Restricted path {restricted_path}.') - return 0 - else: - while restricted_path in json_data['restricted']: - json_data['restricted'].remove(restricted_path) - - while restricted_path.as_posix() in json_data['restricted']: - json_data['restricted'].remove(restricted_path.as_posix()) - - if remove: - logger.warn(f'Removing Restricted path {restricted_path}.') - return 0 - - if not restricted_path.is_dir(): - logger.error(f'Restricted path {restricted_path} does not exist.') - return 1 - - restricted_json = restricted_path / 'restricted.json' - if not valid_o3de_restricted_json(restricted_json): - logger.error(f'Restricted json {restricted_json} is not valid.') - return 1 - - if engine_path: - engine_data['restricted'].insert(0, restricted_path.as_posix()) - else: - json_data['restricted'].insert(0, restricted_path.as_posix()) - - return 0 - - -def valid_o3de_repo_json(file_name: str or pathlib.Path) -> bool: - file_name = pathlib.Path(file_name).resolve() - if not file_name.is_file(): - return False - - with file_name.open('r') as f: - try: - json_data = json.load(f) - test = json_data['repo_name'] - test = json_data['origin'] - except Exception as e: - return False - - return True - - -def valid_o3de_engine_json(file_name: str or pathlib.Path) -> bool: - file_name = pathlib.Path(file_name).resolve() - if not file_name.is_file(): - return False - - with file_name.open('r') as f: - try: - json_data = json.load(f) - test = json_data['engine_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: - return False - return True - - -def valid_o3de_project_json(file_name: str or pathlib.Path) -> bool: - file_name = pathlib.Path(file_name).resolve() - if not file_name.is_file(): - return False - - with file_name.open('r') as f: - try: - json_data = json.load(f) - test = json_data['project_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: - return False - return True - - -def valid_o3de_gem_json(file_name: str or pathlib.Path) -> bool: - file_name = pathlib.Path(file_name).resolve() - if not file_name.is_file(): - return False - - with file_name.open('r') as f: - try: - json_data = json.load(f) - test = json_data['gem_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: - return False - return True - - -def valid_o3de_template_json(file_name: str or pathlib.Path) -> bool: - file_name = pathlib.Path(file_name).resolve() - if not file_name.is_file(): - return False - with file_name.open('r') as f: - try: - json_data = json.load(f) - test = json_data['template_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: - return False - return True - - -def valid_o3de_restricted_json(file_name: str or pathlib.Path) -> bool: - file_name = pathlib.Path(file_name).resolve() - if not file_name.is_file(): - return False - with file_name.open('r') as f: - try: - json_data = json.load(f) - test = json_data['restricted_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: - return False - return True - - -def process_add_o3de_repo(file_name: str or pathlib.Path, - repo_set: set) -> int: - file_name = pathlib.Path(file_name).resolve() - if not valid_o3de_repo_json(file_name): - return 1 - - cache_folder = get_o3de_cache_folder() - - with file_name.open('r') as f: - try: - repo_data = json.load(f) - except Exception as e: - logger.error(f'{file_name} failed to load: {str(e)}') - return 1 - - for engine_uri in repo_data['engines']: - engine_uri = f'{engine_uri}/engine.json' - engine_sha256 = hashlib.sha256(engine_uri.encode()) - cache_file = cache_folder / str(engine_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - 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': - with urllib.request.urlopen(engine_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - engine_json = pathlib.Path(engine_uri).resolve() - if not engine_json.is_file(): - return 1 - shutil.copy(engine_json, cache_file) - - for project_uri in repo_data['projects']: - project_uri = f'{project_uri}/project.json' - project_sha256 = hashlib.sha256(project_uri.encode()) - cache_file = cache_folder / str(project_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - 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': - with urllib.request.urlopen(project_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - project_json = pathlib.Path(project_uri).resolve() - if not project_json.is_file(): - return 1 - shutil.copy(project_json, cache_file) - - for gem_uri in repo_data['gems']: - gem_uri = f'{gem_uri}/gem.json' - gem_sha256 = hashlib.sha256(gem_uri.encode()) - cache_file = cache_folder / str(gem_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - 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': - with urllib.request.urlopen(gem_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - gem_json = pathlib.Path(gem_uri).resolve() - if not gem_json.is_file(): - return 1 - shutil.copy(gem_json, cache_file) - - for template_uri in repo_data['templates']: - template_uri = f'{template_uri}/template.json' - template_sha256 = hashlib.sha256(template_uri.encode()) - cache_file = cache_folder / str(template_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - 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': - with urllib.request.urlopen(template_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - template_json = pathlib.Path(template_uri).resolve() - if not template_json.is_file(): - return 1 - shutil.copy(template_json, cache_file) - - for repo_uri in repo_data['repos']: - if repo_uri not in repo_set: - repo_set.add(repo_uri) - repo_uri = f'{repo_uri}/repo.json' - repo_sha256 = hashlib.sha256(repo_uri.encode()) - cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(repo_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - repo_json = pathlib.Path(repo_uri).resolve() - if not repo_json.is_file(): - return 1 - shutil.copy(repo_json, cache_file) - return 0 - - -def register_repo(json_data: dict, - repo_uri: str or pathlib.Path, - remove: bool = False) -> int: - if not repo_uri: - logger.error(f'Repo URI cannot be empty.') - return 1 - - url = f'{repo_uri}/repo.json' - parsed_uri = urllib.parse.urlparse(url) - - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - while repo_uri in json_data['repos']: - json_data['repos'].remove(repo_uri) - else: - repo_uri = pathlib.Path(repo_uri).resolve() - while repo_uri.as_posix() in json_data['repos']: - json_data['repos'].remove(repo_uri.as_posix()) - - if remove: - logger.warn(f'Removing repo uri {repo_uri}.') - return 0 - - repo_sha256 = hashlib.sha256(url.encode()) - cache_file = get_o3de_cache_folder() / str(repo_sha256.hexdigest() + '.json') - - result = 0 - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - if not cache_file.is_file(): - with urllib.request.urlopen(url) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - json_data['repos'].insert(0, repo_uri) - else: - if not cache_file.is_file(): - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, origin_file) - json_data['repos'].insert(0, repo_uri.as_posix()) - - repo_set = set() - result = process_add_o3de_repo(cache_file, repo_set) - - return result - - -def register_default_engines_folder(json_data: dict, - default_engines_folder: str or pathlib.Path, - remove: bool = False) -> int: - if remove: - default_engines_folder = get_o3de_engines_folder() - - # make sure the path exists - default_engines_folder = pathlib.Path(default_engines_folder).resolve() - if not default_engines_folder.is_dir(): - logger.error(f'Default engines folder {default_engines_folder} does not exist.') - return 1 - - default_engines_folder = default_engines_folder.as_posix() - json_data['default_engines_folder'] = default_engines_folder - - return 0 - - -def register_default_projects_folder(json_data: dict, - default_projects_folder: str or pathlib.Path, - remove: bool = False) -> int: - if remove: - default_projects_folder = get_o3de_projects_folder() - - # make sure the path exists - default_projects_folder = pathlib.Path(default_projects_folder).resolve() - if not default_projects_folder.is_dir(): - logger.error(f'Default projects folder {default_projects_folder} does not exist.') - return 1 - - default_projects_folder = default_projects_folder.as_posix() - json_data['default_projects_folder'] = default_projects_folder - - return 0 - - -def register_default_gems_folder(json_data: dict, - default_gems_folder: str or pathlib.Path, - remove: bool = False) -> int: - if remove: - default_gems_folder = get_o3de_gems_folder() - - # make sure the path exists - default_gems_folder = pathlib.Path(default_gems_folder).resolve() - if not default_gems_folder.is_dir(): - logger.error(f'Default gems folder {default_gems_folder} does not exist.') - return 1 - - default_gems_folder = default_gems_folder.as_posix() - json_data['default_gems_folder'] = default_gems_folder - - return 0 - - -def register_default_templates_folder(json_data: dict, - default_templates_folder: str or pathlib.Path, - remove: bool = False) -> int: - if remove: - default_templates_folder = get_o3de_templates_folder() - - # make sure the path exists - default_templates_folder = pathlib.Path(default_templates_folder).resolve() - if not default_templates_folder.is_dir(): - logger.error(f'Default templates folder {default_templates_folder} does not exist.') - return 1 - - default_templates_folder = default_templates_folder.as_posix() - json_data['default_templates_folder'] = default_templates_folder - - return 0 - - -def register_default_restricted_folder(json_data: dict, - default_restricted_folder: str or pathlib.Path, - remove: bool = False) -> int: - if remove: - default_restricted_folder = get_o3de_restricted_folder() - - # make sure the path exists - default_restricted_folder = pathlib.Path(default_restricted_folder).resolve() - if not default_restricted_folder.is_dir(): - logger.error(f'Default restricted folder {default_restricted_folder} does not exist.') - return 1 - - default_restricted_folder = default_restricted_folder.as_posix() - json_data['default_restricted_folder'] = default_restricted_folder - - return 0 - - -def register(engine_path: str or pathlib.Path = None, - project_path: str or pathlib.Path = None, - gem_path: str or pathlib.Path = None, - template_path: str or pathlib.Path = None, - restricted_path: str or pathlib.Path = None, - repo_uri: str or pathlib.Path = None, - default_engines_folder: str or pathlib.Path = None, - default_projects_folder: str or pathlib.Path = None, - default_gems_folder: str or pathlib.Path = None, - default_templates_folder: str or pathlib.Path = None, - default_restricted_folder: str or pathlib.Path = None, - remove: bool = False, - force: bool = False - ) -> int: - """ - Adds/Updates entries to the .o3de/o3de_manifest.json - - :param engine_path: if engine folder is supplied the path will be added to the engine if it can, if not global - :param project_path: project folder - :param gem_path: gem folder - :param template_path: template folder - :param restricted_path: restricted folder - :param repo_uri: repo uri - :param default_engines_folder: default engines folder - :param default_projects_folder: default projects folder - :param default_gems_folder: default gems folder - :param default_templates_folder: default templates folder - :param default_restricted_folder: default restricted code folder - :param remove: add/remove the entries - :param force: force update of the engine_path for specified "engine_name" from the engine.json file - - :return: 0 for success or non 0 failure code - """ - - json_data = load_o3de_manifest() - - result = 0 - - # do anything that could require a engine context first - if isinstance(project_path, str) or isinstance(project_path, pathlib.PurePath): - if not project_path: - logger.error(f'Project path cannot be empty.') - return 1 - result = register_project_path(json_data, project_path, remove, engine_path) - - elif isinstance(gem_path, str) or isinstance(gem_path, pathlib.PurePath): - if not gem_path: - logger.error(f'Gem path cannot be empty.') - return 1 - result = register_gem_path(json_data, gem_path, remove, engine_path) - - elif isinstance(template_path, str) or isinstance(template_path, pathlib.PurePath): - if not template_path: - logger.error(f'Template path cannot be empty.') - return 1 - result = register_template_path(json_data, template_path, remove, engine_path) - - elif isinstance(restricted_path, str) or isinstance(restricted_path, pathlib.PurePath): - if not restricted_path: - logger.error(f'Restricted path cannot be empty.') - return 1 - result = register_restricted_path(json_data, restricted_path, remove, engine_path) - - elif isinstance(repo_uri, str) or isinstance(repo_uri, pathlib.PurePath): - if not repo_uri: - logger.error(f'Repo URI cannot be empty.') - return 1 - result = register_repo(json_data, repo_uri, remove) - - elif isinstance(default_engines_folder, str) or isinstance(default_engines_folder, pathlib.PurePath): - result = register_default_engines_folder(json_data, default_engines_folder, remove) - - elif isinstance(default_projects_folder, str) or isinstance(default_projects_folder, pathlib.PurePath): - result = register_default_projects_folder(json_data, default_projects_folder, remove) - - elif isinstance(default_gems_folder, str) or isinstance(default_gems_folder, pathlib.PurePath): - result = register_default_gems_folder(json_data, default_gems_folder, remove) - - elif isinstance(default_templates_folder, str) or isinstance(default_templates_folder, pathlib.PurePath): - result = register_default_templates_folder(json_data, default_templates_folder, remove) - - elif isinstance(default_restricted_folder, str) or isinstance(default_restricted_folder, pathlib.PurePath): - result = register_default_restricted_folder(json_data, default_restricted_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 - elif isinstance(engine_path, str) or isinstance(engine_path, pathlib.PurePath): - if not engine_path: - logger.error(f'Engine path cannot be empty.') - return 1 - result = register_engine_path(json_data, engine_path, remove, force) - - if not result: - save_o3de_manifest(json_data) - - return result - - -def remove_invalid_o3de_objects() -> None: - json_data = load_o3de_manifest() - - for engine_object in json_data['engines']: - engine_path = engine_object['path'] - if not valid_o3de_engine_json(pathlib.Path(engine_path).resolve() / 'engine.json'): - logger.warn(f"Engine path {engine_path} is invalid.") - register(engine_path=engine_path, remove=True) - else: - for project in engine_object['projects']: - if not valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): - logger.warn(f"Project path {project} is invalid.") - register(engine_path=engine_path, project_path=project, remove=True) - - for gem_path in engine_object['gems']: - if not valid_o3de_gem_json(pathlib.Path(gem_path).resolve() / 'gem.json'): - logger.warn(f"Gem path {gem_path} is invalid.") - register(engine_path=engine_path, gem_path=gem_path, remove=True) - - for template_path in engine_object['templates']: - if not valid_o3de_template_json(pathlib.Path(template_path).resolve() / 'template.json'): - logger.warn(f"Template path {template_path} is invalid.") - register(engine_path=engine_path, template_path=template_path, remove=True) - - for restricted in engine_object['restricted']: - if not valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'): - logger.warn(f"Restricted path {restricted} is invalid.") - register(engine_path=engine_path, restricted_path=restricted, remove=True) - - for external in engine_object['external_subdirectories']: - external = pathlib.Path(external).resolve() - if not external.is_dir(): - logger.warn(f"External subdirectory {external} is invalid.") - remove_external_subdirectory(external) - - for project in json_data['projects']: - if not valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): - logger.warn(f"Project path {project} is invalid.") - register(project_path=project, remove=True) - - for gem in json_data['gems']: - if not valid_o3de_gem_json(pathlib.Path(gem).resolve() / 'gem.json'): - logger.warn(f"Gem path {gem} is invalid.") - register(gem_path=gem, remove=True) - - for template in json_data['templates']: - if not valid_o3de_template_json(pathlib.Path(template).resolve() / 'template.json'): - logger.warn(f"Template path {template} is invalid.") - register(template_path=template, remove=True) - - for restricted in json_data['restricted']: - if not valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'): - logger.warn(f"Restricted path {restricted} is invalid.") - register(restricted_path=restricted, remove=True) - - default_engines_folder = pathlib.Path(json_data['default_engines_folder']).resolve() - if not default_engines_folder.is_dir(): - new_default_engines_folder = get_o3de_folder() / 'Engines' - new_default_engines_folder.mkdir(parents=True, exist_ok=True) - logger.warn( - f"Default engines folder {default_engines_folder} is invalid. Set default {new_default_engines_folder}") - register(default_engines_folder=new_default_engines_folder.as_posix()) - - default_projects_folder = pathlib.Path(json_data['default_projects_folder']).resolve() - if not default_projects_folder.is_dir(): - new_default_projects_folder = get_o3de_folder() / 'Projects' - new_default_projects_folder.mkdir(parents=True, exist_ok=True) - logger.warn( - f"Default projects folder {default_projects_folder} is invalid. Set default {new_default_projects_folder}") - register(default_projects_folder=new_default_projects_folder.as_posix()) - - default_gems_folder = pathlib.Path(json_data['default_gems_folder']).resolve() - if not default_gems_folder.is_dir(): - new_default_gems_folder = get_o3de_folder() / 'Gems' - new_default_gems_folder.mkdir(parents=True, exist_ok=True) - logger.warn(f"Default gems folder {default_gems_folder} is invalid." - f" Set default {new_default_gems_folder}") - register(default_gems_folder=new_default_gems_folder.as_posix()) - - default_templates_folder = pathlib.Path(json_data['default_templates_folder']).resolve() - if not default_templates_folder.is_dir(): - new_default_templates_folder = get_o3de_folder() / 'Templates' - new_default_templates_folder.mkdir(parents=True, exist_ok=True) - logger.warn( - f"Default templates folder {default_templates_folder} is invalid." - f" Set default {new_default_templates_folder}") - register(default_templates_folder=new_default_templates_folder.as_posix()) - - default_restricted_folder = pathlib.Path(json_data['default_restricted_folder']).resolve() - if not default_restricted_folder.is_dir(): - default_restricted_folder = get_o3de_folder() / 'Restricted' - default_restricted_folder.mkdir(parents=True, exist_ok=True) - logger.warn( - f"Default restricted folder {default_restricted_folder} is invalid." - f" Set default {default_restricted_folder}") - register(default_restricted_folder=default_restricted_folder.as_posix()) - - -def refresh_repos() -> int: - json_data = load_o3de_manifest() - - # clear the cache - cache_folder = get_o3de_cache_folder() - shutil.rmtree(cache_folder) - cache_folder = get_o3de_cache_folder() # will recreate it - - result = 0 - - # set will stop circular references - repo_set = set() - - for repo_uri in json_data['repos']: - if repo_uri not in repo_set: - repo_set.add(repo_uri) - - repo_uri = f'{repo_uri}/repo.json' - repo_sha256 = hashlib.sha256(repo_uri.encode()) - cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - parsed_uri = urllib.parse.urlparse(repo_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(repo_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(repo_uri).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, cache_file) - - if not valid_o3de_repo_json(cache_file): - logger.error(f'Repo json {repo_uri} is not valid.') - cache_file.unlink() - return 1 - - last_failure = process_add_o3de_repo(cache_file, repo_set) - if last_failure: - result = last_failure - - return result - - -def search_repo(repo_set: set, - repo_json_data: dict, - engine_name: str = None, - project_name: str = None, - gem_name: str = None, - template_name: str = None, - restricted_name: str = None) -> dict or None: - cache_folder = get_o3de_cache_folder() - - if isinstance(engine_name, str) or isinstance(engine_name, pathlib.PurePath): - for engine_uri in repo_json_data['engines']: - engine_uri = f'{engine_uri}/engine.json' - engine_sha256 = hashlib.sha256(engine_uri.encode()) - engine_cache_file = cache_folder / str(engine_sha256.hexdigest() + '.json') - if engine_cache_file.is_file(): - with engine_cache_file.open('r') as f: - try: - engine_json_data = json.load(f) - except Exception as e: - logger.warn(f'{engine_cache_file} failed to load: {str(e)}') - else: - if engine_json_data['engine_name'] == engine_name: - return engine_json_data - - elif isinstance(project_name, str) or isinstance(project_name, pathlib.PurePath): - for project_uri in repo_json_data['projects']: - project_uri = f'{project_uri}/project.json' - project_sha256 = hashlib.sha256(project_uri.encode()) - project_cache_file = cache_folder / str(project_sha256.hexdigest() + '.json') - if project_cache_file.is_file(): - with project_cache_file.open('r') as f: - try: - project_json_data = json.load(f) - except Exception as e: - logger.warn(f'{project_cache_file} failed to load: {str(e)}') - else: - if project_json_data['project_name'] == project_name: - return project_json_data - - elif isinstance(gem_name, str) or isinstance(gem_name, pathlib.PurePath): - for gem_uri in repo_json_data['gems']: - gem_uri = f'{gem_uri}/gem.json' - gem_sha256 = hashlib.sha256(gem_uri.encode()) - gem_cache_file = cache_folder / str(gem_sha256.hexdigest() + '.json') - if gem_cache_file.is_file(): - with gem_cache_file.open('r') as f: - try: - gem_json_data = json.load(f) - except Exception as e: - logger.warn(f'{gem_cache_file} failed to load: {str(e)}') - else: - if gem_json_data['gem_name'] == gem_name: - return gem_json_data - - elif isinstance(template_name, str) or isinstance(template_name, pathlib.PurePath): - for template_uri in repo_json_data['templates']: - template_uri = f'{template_uri}/template.json' - template_sha256 = hashlib.sha256(template_uri.encode()) - template_cache_file = cache_folder / str(template_sha256.hexdigest() + '.json') - if template_cache_file.is_file(): - with template_cache_file.open('r') as f: - try: - template_json_data = json.load(f) - except Exception as e: - logger.warn(f'{template_cache_file} failed to load: {str(e)}') - else: - if template_json_data['template_name'] == template_name: - return template_json_data - - elif isinstance(restricted_name, str) or isinstance(restricted_name, pathlib.PurePath): - for restricted_uri in repo_json_data['restricted']: - restricted_uri = f'{restricted_uri}/restricted.json' - restricted_sha256 = hashlib.sha256(restricted_uri.encode()) - restricted_cache_file = cache_folder / str(restricted_sha256.hexdigest() + '.json') - if restricted_cache_file.is_file(): - with restricted_cache_file.open('r') as f: - try: - restricted_json_data = json.load(f) - except Exception as e: - logger.warn(f'{restricted_cache_file} failed to load: {str(e)}') - else: - if restricted_json_data['restricted_name'] == restricted_name: - return restricted_json_data - # recurse - else: - for repo_repo_uri in repo_json_data['repos']: - if repo_repo_uri not in repo_set: - repo_set.add(repo_repo_uri) - repo_repo_uri = f'{repo_repo_uri}/repo.json' - repo_repo_sha256 = hashlib.sha256(repo_repo_uri.encode()) - repo_repo_cache_file = cache_folder / str(repo_repo_sha256.hexdigest() + '.json') - if repo_repo_cache_file.is_file(): - with repo_repo_cache_file.open('r') as f: - try: - repo_repo_json_data = json.load(f) - except Exception as e: - logger.warn(f'{repo_repo_cache_file} failed to load: {str(e)}') - else: - item = search_repo(repo_set, - repo_repo_json_data, - engine_name, - project_name, - gem_name, - template_name) - if item: - return item - return None - - -def get_downloadable(engine_name: str = None, - project_name: str = None, - gem_name: str = None, - template_name: str = None, - restricted_name: str = None) -> dict or None: - json_data = load_o3de_manifest() - cache_folder = get_o3de_cache_folder() - repo_set = set() - for repo_uri in json_data['repos']: - if repo_uri not in repo_set: - repo_set.add(repo_uri) - repo_uri = f'{repo_uri}/repo.json' - repo_sha256 = hashlib.sha256(repo_uri.encode()) - repo_cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') - if repo_cache_file.is_file(): - with repo_cache_file.open('r') as f: - try: - repo_json_data = json.load(f) - except Exception as e: - logger.warn(f'{repo_cache_file} failed to load: {str(e)}') - else: - item = search_repo(repo_set, - repo_json_data, - engine_name, - project_name, - gem_name, - template_name, - restricted_name) - if item: - return item - return None - - -def get_registered(engine_name: str = None, - project_name: str = None, - gem_name: str = None, - template_name: str = None, - default_folder: str = None, - repo_name: str = None, - restricted_name: str = None) -> pathlib.Path or None: - json_data = load_o3de_manifest() - - # check global first then this engine - if isinstance(engine_name, str): - for engine in json_data['engines']: - engine_path = pathlib.Path(engine['path']).resolve() - engine_json = engine_path / 'engine.json' - with engine_json.open('r') as f: - try: - engine_json_data = json.load(f) - except Exception as e: - logger.warn(f'{engine_json} failed to load: {str(e)}') - else: - this_engines_name = engine_json_data['engine_name'] - if this_engines_name == engine_name: - return engine_path - - elif isinstance(project_name, str): - engine_object = find_engine_data(json_data) - projects = json_data['projects'].copy() - projects.extend(engine_object['projects']) - for project_path in projects: - project_path = pathlib.Path(project_path).resolve() - project_json = project_path / 'project.json' - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except Exception as e: - logger.warn(f'{project_json} failed to load: {str(e)}') - else: - this_projects_name = project_json_data['project_name'] - if this_projects_name == project_name: - return project_path - - elif isinstance(gem_name, str): - engine_object = find_engine_data(json_data) - gems = json_data['gems'].copy() - gems.extend(engine_object['gems']) - for gem_path in gems: - gem_path = pathlib.Path(gem_path).resolve() - gem_json = gem_path / 'gem.json' - with gem_json.open('r') as f: - try: - gem_json_data = json.load(f) - except Exception as e: - logger.warn(f'{gem_json} failed to load: {str(e)}') - else: - this_gems_name = gem_json_data['gem_name'] - if this_gems_name == gem_name: - return gem_path - - elif isinstance(template_name, str): - engine_object = find_engine_data(json_data) - templates = json_data['templates'].copy() - templates.extend(engine_object['templates']) - for template_path in templates: - template_path = pathlib.Path(template_path).resolve() - template_json = template_path / 'template.json' - with template_json.open('r') as f: - try: - template_json_data = json.load(f) - except Exception as e: - logger.warn(f'{template_path} failed to load: {str(e)}') - else: - this_templates_name = template_json_data['template_name'] - if this_templates_name == template_name: - return template_path - - elif isinstance(restricted_name, str): - engine_object = find_engine_data(json_data) - restricted = json_data['restricted'].copy() - restricted.extend(engine_object['restricted']) - for restricted_path in restricted: - restricted_path = pathlib.Path(restricted_path).resolve() - restricted_json = restricted_path / 'restricted.json' - with restricted_json.open('r') as f: - try: - restricted_json_data = json.load(f) - except Exception as e: - logger.warn(f'{restricted_json} failed to load: {str(e)}') - else: - this_restricted_name = restricted_json_data['restricted_name'] - if this_restricted_name == restricted_name: - return restricted_path - - elif isinstance(default_folder, str): - if default_folder == 'engines': - default_engines_folder = pathlib.Path(json_data['default_engines_folder']).resolve() - return default_engines_folder - elif default_folder == 'projects': - default_projects_folder = pathlib.Path(json_data['default_projects_folder']).resolve() - return default_projects_folder - elif default_folder == 'gems': - default_gems_folder = pathlib.Path(json_data['default_gems_folder']).resolve() - return default_gems_folder - elif default_folder == 'templates': - default_templates_folder = pathlib.Path(json_data['default_templates_folder']).resolve() - return default_templates_folder - elif default_folder == 'restricted': - default_restricted_folder = pathlib.Path(json_data['default_restricted_folder']).resolve() - return default_restricted_folder - - elif isinstance(repo_name, str): - cache_folder = get_o3de_cache_folder() - for repo_uri in json_data['repos']: - repo_uri = pathlib.Path(repo_uri).resolve() - repo_sha256 = hashlib.sha256(repo_uri.encode()) - cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') - if cache_file.is_file(): - repo = pathlib.Path(cache_file).resolve() - with repo.open('r') as f: - try: - repo_json_data = json.load(f) - except Exception as e: - logger.warn(f'{cache_file} failed to load: {str(e)}') - else: - this_repos_name = repo_json_data['repo_name'] - if this_repos_name == repo_name: - return repo_uri - return None - - -def print_engines_data(engines_data: dict) -> None: - print('\n') - print("Engines================================================") - for engine_object in engines_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()) - cache_folder = get_o3de_cache_folder() - engine = cache_folder / str(repo_sha256.hexdigest() + '.json') - print(f'{engine_uri}/engine.json cached as:') - else: - engine_json = pathlib.Path(engine_uri).resolve() / 'engine.json' - - with engine_json.open('r') as f: - try: - engine_json_data = json.load(f) - except Exception 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') - - -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 = 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 Exception 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 = 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 Exception 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 = 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 Exception 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: - print('\n') - print("Repos================================================") - cache_folder = get_o3de_cache_folder() - for repo_uri in repos_data: - repo_sha256 = hashlib.sha256(repo_uri.encode()) - cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') - if valid_o3de_repo_json(cache_file): - with cache_file.open('r') as s: - try: - repo_json_data = json.load(s) - except Exception as e: - logger.warn(f'{cache_file} failed to load: {str(e)}') - else: - print(f'{repo_uri}/repo.json cached as:') - 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 Exception 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') - - -def get_this_engine() -> dict: - json_data = load_o3de_manifest() - engine_data = find_engine_data(json_data) - return engine_data - - -def get_engines() -> dict: - json_data = load_o3de_manifest() - return json_data['engines'] - - -def get_projects() -> dict: - json_data = load_o3de_manifest() - return json_data['projects'] - - -def get_gems() -> dict: - json_data = load_o3de_manifest() - return json_data['gems'] - - -def get_templates() -> dict: - json_data = load_o3de_manifest() - return json_data['templates'] - - -def get_restricted() -> dict: - json_data = load_o3de_manifest() - return json_data['restricted'] - - -def get_repos() -> dict: - json_data = load_o3de_manifest() - return json_data['repos'] - - -def get_engine_projects() -> dict: - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - return engine_object['projects'] - - -def get_engine_gems() -> dict: - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - return engine_object['gems'] - - -def get_engine_templates() -> dict: - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - return engine_object['templates'] - - -def get_engine_restricted() -> dict: - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - return engine_object['restricted'] - - -def get_external_subdirectories() -> dict: - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - return engine_object['external_subdirectories'] - - -def get_all_projects() -> dict: - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - projects_data = json_data['projects'].copy() - projects_data.extend(engine_object['projects']) - return projects_data - - -def get_all_gems() -> dict: - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - gems_data = json_data['gems'].copy() - gems_data.extend(engine_object['gems']) - return gems_data - - -def get_all_templates() -> dict: - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - templates_data = json_data['templates'].copy() - templates_data.extend(engine_object['templates']) - return templates_data - - -def get_all_restricted() -> dict: - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data) - restricted_data = json_data['restricted'].copy() - restricted_data.extend(engine_object['restricted']) - return restricted_data - - -def print_this_engine(verbose: int) -> None: - engine_data = get_this_engine() - print(json.dumps(engine_data, indent=4)) - if verbose > 0: - print_engines_data(engine_data) - - -def print_engines(verbose: int) -> None: - engines_data = get_engines() - print(json.dumps(engines_data, indent=4)) - if verbose > 0: - print_engines_data(engines_data) - - -def print_projects(verbose: int) -> None: - projects_data = get_projects() - print(json.dumps(projects_data, indent=4)) - if verbose > 0: - print_projects_data(projects_data) - - -def print_gems(verbose: int) -> None: - gems_data = get_gems() - print(json.dumps(gems_data, indent=4)) - if verbose > 0: - print_gems_data(gems_data) - - -def print_templates(verbose: int) -> None: - templates_data = get_templates() - print(json.dumps(templates_data, indent=4)) - if verbose > 0: - print_templates_data(templates_data) - - -def print_restricted(verbose: int) -> None: - restricted_data = get_restricted() - print(json.dumps(restricted_data, indent=4)) - if verbose > 0: - print_restricted_data(restricted_data) - - -def register_show_repos(verbose: int) -> None: - repos_data = get_repos() - print(json.dumps(repos_data, indent=4)) - if verbose > 0: - print_repos_data(repos_data) - - -def print_engine_projects(verbose: int) -> None: - engine_projects_data = get_engine_projects() - print(json.dumps(engine_projects_data, indent=4)) - if verbose > 0: - print_projects_data(engine_projects_data) - - -def print_engine_gems(verbose: int) -> None: - engine_gems_data = get_engine_gems() - print(json.dumps(engine_gems_data, indent=4)) - if verbose > 0: - print_gems_data(engine_gems_data) - - -def print_engine_templates(verbose: int) -> None: - engine_templates_data = get_engine_templates() - print(json.dumps(engine_templates_data, indent=4)) - if verbose > 0: - print_templates_data(engine_templates_data) - - -def print_engine_restricted(verbose: int) -> None: - engine_restricted_data = get_engine_restricted() - print(json.dumps(engine_restricted_data, indent=4)) - if verbose > 0: - print_restricted_data(engine_restricted_data) - - -def print_external_subdirectories(verbose: int) -> None: - external_subdirs_data = get_external_subdirectories() - print(json.dumps(external_subdirs_data, indent=4)) - - -def print_all_projects(verbose: int) -> None: - all_projects_data = get_all_projects() - print(json.dumps(all_projects_data, indent=4)) - if verbose > 0: - print_projects_data(all_projects_data) - - -def print_all_gems(verbose: int) -> None: - all_gems_data = get_all_gems() - print(json.dumps(all_gems_data, indent=4)) - if verbose > 0: - print_gems_data(all_gems_data) - - -def print_all_templates(verbose: int) -> None: - all_templates_data = get_all_templates() - print(json.dumps(all_templates_data, indent=4)) - if verbose > 0: - print_templates_data(all_templates_data) - - -def print_all_restricted(verbose: int) -> None: - all_restricted_data = get_all_restricted() - print(json.dumps(all_restricted_data, indent=4)) - if verbose > 0: - print_restricted_data(all_restricted_data) - - -def register_show(verbose: int) -> None: - json_data = load_o3de_manifest() - print(f"{get_o3de_manifest()}:") - print(json.dumps(json_data, indent=4)) - - if verbose > 0: - print_engines_data(get_engines()) - print_projects_data(get_all_projects()) - print_gems_data(get_gems()) - print_templates_data(get_all_templates()) - print_restricted_data(get_all_restricted()) - print_repos_data(get_repos()) - - -def find_engine_data(json_data: dict, - engine_path: str or pathlib.Path = None) -> dict or None: - if not engine_path: - engine_path = get_this_engine_path() - engine_path = pathlib.Path(engine_path).resolve() - - for engine_object in json_data['engines']: - engine_object_path = pathlib.Path(engine_object['path']).resolve() - if engine_path == engine_object_path: - return engine_object - - return None - - -def get_engine_data(engine_name: str = None, - engine_path: str or pathlib.Path = None, ) -> dict or None: - if not engine_name and not engine_path: - logger.error('Must specify either a Engine name or Engine Path.') - return None - - if engine_name and not engine_path: - engine_path = get_registered(engine_name=engine_name) - - if not engine_path: - logger.error(f'Engine Path {engine_path} has not been registered.') - return None - - engine_path = pathlib.Path(engine_path).resolve() - engine_json = engine_path / 'engine.json' - if not engine_json.is_file(): - logger.error(f'Engine json {engine_json} is not present.') - return None - if not valid_o3de_engine_json(engine_json): - logger.error(f'Engine json {engine_json} is not valid.') - return None - - with engine_json.open('r') as f: - try: - engine_json_data = json.load(f) - except Exception as e: - logger.warn(f'{engine_json} failed to load: {str(e)}') - else: - return engine_json_data - - return None - - -def get_project_data(project_name: str = None, - project_path: str or pathlib.Path = None, ) -> dict or None: - if not project_name and not project_path: - logger.error('Must specify either a Project name or Project Path.') - return None - - if project_name and not project_path: - project_path = get_registered(project_name=project_name) - - if not project_path: - logger.error(f'Project Path {project_path} has not been registered.') - return None - - project_path = pathlib.Path(project_path).resolve() - project_json = project_path / 'project.json' - if not project_json.is_file(): - logger.error(f'Project json {project_json} is not present.') - return None - if not valid_o3de_project_json(project_json): - logger.error(f'Project json {project_json} is not valid.') - return None - - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except Exception as e: - logger.warn(f'{project_json} failed to load: {str(e)}') - else: - return project_json_data - - return None - - -def get_gem_data(gem_name: str = None, - gem_path: str or pathlib.Path = None, ) -> dict or None: - if not gem_name and not gem_path: - logger.error('Must specify either a Gem name or Gem Path.') - return None - - if gem_name and not gem_path: - gem_path = get_registered(gem_name=gem_name) - - if not gem_path: - logger.error(f'Gem Path {gem_path} has not been registered.') - return None - - gem_path = pathlib.Path(gem_path).resolve() - gem_json = gem_path / 'gem.json' - if not gem_json.is_file(): - logger.error(f'Gem json {gem_json} is not present.') - return None - if not valid_o3de_gem_json(gem_json): - logger.error(f'Gem json {gem_json} is not valid.') - return None - - with gem_json.open('r') as f: - try: - gem_json_data = json.load(f) - except Exception as e: - logger.warn(f'{gem_json} failed to load: {str(e)}') - else: - return gem_json_data - - return None - - -def get_template_data(template_name: str = None, - template_path: str or pathlib.Path = None, ) -> dict or None: - if not template_name and not template_path: - logger.error('Must specify either a Template name or Template Path.') - return None - - if template_name and not template_path: - template_path = get_registered(template_name=template_name) - - if not template_path: - logger.error(f'Template Path {template_path} has not been registered.') - return None - - template_path = pathlib.Path(template_path).resolve() - template_json = template_path / 'template.json' - if not template_json.is_file(): - logger.error(f'Template json {template_json} is not present.') - return None - if not valid_o3de_template_json(template_json): - logger.error(f'Template json {template_json} is not valid.') - return None - - with template_json.open('r') as f: - try: - template_json_data = json.load(f) - except Exception as e: - logger.warn(f'{template_json} failed to load: {str(e)}') - else: - return template_json_data - - return None - - -def get_restricted_data(restricted_name: str = None, - restricted_path: str or pathlib.Path = None, ) -> dict or None: - if not restricted_name and not restricted_path: - logger.error('Must specify either a Restricted name or Restricted Path.') - return None - - if restricted_name and not restricted_path: - restricted_path = get_registered(restricted_name=restricted_name) - - if not restricted_path: - logger.error(f'Restricted Path {restricted_path} has not been registered.') - return None - - restricted_path = pathlib.Path(restricted_path).resolve() - restricted_json = restricted_path / 'restricted.json' - if not restricted_json.is_file(): - logger.error(f'Restricted json {restricted_json} is not present.') - return None - if not valid_o3de_restricted_json(restricted_json): - logger.error(f'Restricted json {restricted_json} is not valid.') - return None - - with restricted_json.open('r') as f: - try: - restricted_json_data = json.load(f) - except Exception as e: - logger.warn(f'{restricted_json} failed to load: {str(e)}') - else: - return restricted_json_data - - return None - - -def get_downloadables() -> dict: - json_data = load_o3de_manifest() - downloadable_data = {} - downloadable_data.update({'engines': []}) - downloadable_data.update({'projects': []}) - downloadable_data.update({'gems': []}) - downloadable_data.update({'templates': []}) - downloadable_data.update({'restricted': []}) - - def recurse_downloadables(repo_uri: str or pathlib.Path) -> None: - cache_folder = get_o3de_cache_folder() - repo_sha256 = hashlib.sha256(repo_uri.encode()) - cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') - if valid_o3de_repo_json(cache_file): - with cache_file.open('r') as s: - try: - repo_json_data = json.load(s) - except Exception as e: - logger.warn(f'{cache_file} failed to load: {str(e)}') - else: - for engine in repo_json_data['engines']: - if engine not in downloadable_data['engines']: - downloadable_data['engines'].append(engine) - - for project in repo_json_data['projects']: - if project not in downloadable_data['projects']: - downloadable_data['projects'].append(project) - - for gem in repo_json_data['gems']: - if gem not in downloadable_data['gems']: - downloadable_data['gems'].append(gem) - - for template in repo_json_data['templates']: - if template not in downloadable_data['templates']: - downloadable_data['templates'].append(template) - - for restricted in repo_json_data['restricted']: - if restricted not in downloadable_data['restricted']: - downloadable_data['restricted'].append(restricted) - - for repo in repo_json_data['repos']: - if repo not in downloadable_data['repos']: - downloadable_data['repos'].append(repo) - - for repo in downloadable_data['repos']: - recurse_downloadables(repo) - - for repo_entry in json_data['repos']: - recurse_downloadables(repo_entry) - return downloadable_data - - -def get_downloadable_engines() -> dict: - downloadable_data = get_downloadables() - return downloadable_data['engines'] - - -def get_downloadable_projects() -> dict: - downloadable_data = get_downloadables() - return downloadable_data['projects'] - - -def get_downloadable_gems() -> dict: - downloadable_data = get_downloadables() - return downloadable_data['gems'] - - -def get_downloadable_templates() -> dict: - downloadable_data = get_downloadables() - return downloadable_data['templates'] - - -def get_downloadable_restricted() -> dict: - downloadable_data = get_downloadables() - return downloadable_data['restricted'] - - -def print_downloadable_engines(verbose: int) -> None: - downloadable_engines = get_downloadable_engines() - for engine_data in downloadable_engines: - print(json.dumps(engine_data, indent=4)) - if verbose > 0: - print_engines_data(downloadable_engines) - - -def print_downloadable_projects(verbose: int) -> None: - downloadable_projects = get_downloadable_projects() - for projects_data in downloadable_projects: - print(json.dumps(projects_data, indent=4)) - if verbose > 0: - print_projects_data(downloadable_projects) - - -def print_downloadable_gems(verbose: int) -> None: - downloadable_gems = get_downloadable_gems() - for gem_data in downloadable_gems: - print(json.dumps(gem_data, indent=4)) - if verbose > 0: - print_gems_data(downloadable_gems) - - -def print_downloadable_templates(verbose: int) -> None: - downloadable_templates = get_downloadable_templates() - for template_data in downloadable_templates: - print(json.dumps(template_data, indent=4)) - if verbose > 0: - print_engines_data(downloadable_templates) - - -def print_downloadable_restricted(verbose: int) -> None: - downloadable_restricted = get_downloadable_restricted() - for restricted_data in downloadable_restricted: - print(json.dumps(restricted_data, indent=4)) - if verbose > 0: - print_engines_data(downloadable_restricted) - - -def print_downloadables(verbose: int) -> None: - downloadable_data = get_downloadables() - print(json.dumps(downloadable_data, indent=4)) - if verbose > 0: - print_engines_data(downloadable_data['engines']) - print_projects_data(downloadable_data['projects']) - print_gems_data(downloadable_data['gems']) - print_templates_data(downloadable_data['templates']) - print_restricted_data(downloadable_data['templates']) - - -def download_engine(engine_name: str, - dest_path: str) -> int: - if not dest_path: - dest_path = get_registered(default_folder='engines') - if not dest_path: - logger.error(f'Destination path not cannot be empty.') - return 1 - - dest_path = pathlib.Path(dest_path).resolve() - dest_path.mkdir(exist_ok=True) - - download_path = get_o3de_download_folder() / 'engines' / engine_name - download_path.mkdir(exist_ok=True) - download_zip_path = download_path / 'engine.zip' - - downloadable_engine_data = get_downloadable(engine_name=engine_name) - if not downloadable_engine_data: - logger.error(f'Downloadable engine {engine_name} not found.') - return 1 - - origin = downloadable_engine_data['origin'] - url = f'{origin}/project.zip' - parsed_uri = urllib.parse.urlparse(url) - - if download_zip_path.is_file(): - logger.warn(f'Project already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) - - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Engine zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 - - # if the engine.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_engine_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised engine you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised engine!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded engine.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the engine.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - dest_engine_folder = dest_path / engine_name - if dest_engine_folder.is_dir(): - backup_folder(dest_engine_folder) - with zipfile.ZipFile(download_zip_path, 'r') as project_zip: - try: - project_zip.extractall(dest_path) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_engine_json = dest_engine_folder / 'engine.json' - if not unzipped_engine_json.is_file(): - logger.error(f'Engine json {unzipped_engine_json} is missing.') - return 1 - - if not valid_o3de_engine_json(unzipped_engine_json): - logger.error(f'Engine json {unzipped_engine_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable engine.json - # then compare it to the engine.json in the zip, they should now be identical - try: - del downloadable_engine_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_engine_data, indent=4).encode('utf8')).hexdigest() - with unzipped_engine_json.open('r') as s: - try: - unzipped_engine_json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to read engine json {unzipped_engine_json}. Unable to confirm this' - f' is the same template that was advertised.') - return 1 - sha256B = hashlib.sha256(json.dumps(unzipped_engine_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded engine.json does not match' - f' the advertised engine.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 - - -def download_project(project_name: str, - dest_path: str or pathlib.Path) -> int: - if not dest_path: - dest_path = get_registered(default_folder='projects') - if not dest_path: - logger.error(f'Destination path not specified and not default projects path.') - return 1 - - dest_path = pathlib.Path(dest_path).resolve() - dest_path.mkdir(exist_ok=True, parents=True) - - download_path = get_o3de_download_folder() / 'projects' / project_name - download_path.mkdir(exist_ok=True, parents=True) - download_zip_path = download_path / 'project.zip' - - downloadable_project_data = get_downloadable(project_name=project_name) - if not downloadable_project_data: - logger.error(f'Downloadable project {project_name} not found.') - return 1 - - origin = downloadable_project_data['origin'] - url = f'{origin}/project.zip' - parsed_uri = urllib.parse.urlparse(url) - - if download_zip_path.is_file(): - logger.warn(f'Project already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) - - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Project zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 - - # if the project.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_project_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised project you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised project!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded project.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the project.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - dest_project_folder = dest_path / project_name - if dest_project_folder.is_dir(): - backup_folder(dest_project_folder) - with zipfile.ZipFile(download_zip_path, 'r') as project_zip: - try: - project_zip.extractall(dest_project_folder) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_project_json = dest_project_folder / 'project.json' - if not unzipped_project_json.is_file(): - logger.error(f'Project json {unzipped_project_json} is missing.') - return 1 - - if not valid_o3de_project_json(unzipped_project_json): - logger.error(f'Project json {unzipped_project_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable project.json - # then compare it to the project.json in the zip, they should now be identical - try: - del downloadable_project_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_project_data, indent=4).encode('utf8')).hexdigest() - with unzipped_project_json.open('r') as s: - try: - unzipped_project_json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to read Project json {unzipped_project_json}. Unable to confirm this' - f' is the same project that was advertised.') - return 1 - sha256B = hashlib.sha256(json.dumps(unzipped_project_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded project.json does not match' - f' the advertised project.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 - - -def download_gem(gem_name: str, - dest_path: str or pathlib.Path) -> int: - if not dest_path: - dest_path = get_registered(default_folder='gems') - if not dest_path: - logger.error(f'Destination path not cannot be empty.') - return 1 - - dest_path = pathlib.Path(dest_path).resolve() - dest_path.mkdir(exist_ok=True, parents=True) - - download_path = get_o3de_download_folder() / 'gems' / gem_name - download_path.mkdir(exist_ok=True, parents=True) - download_zip_path = download_path / 'gem.zip' - - downloadable_gem_data = get_downloadable(gem_name=gem_name) - if not downloadable_gem_data: - logger.error(f'Downloadable gem {gem_name} not found.') - return 1 - - origin = downloadable_gem_data['origin'] - url = f'{origin}/gem.zip' - parsed_uri = urllib.parse.urlparse(url) - - if download_zip_path.is_file(): - logger.warn(f'Project already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) - - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Gem zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 - - # if the gem.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_gem_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised gem you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised gem!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded gem.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the gem.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - dest_gem_folder = dest_path / gem_name - if dest_gem_folder.is_dir(): - backup_folder(dest_gem_folder) - with zipfile.ZipFile(download_zip_path, 'r') as gem_zip: - try: - gem_zip.extractall(dest_path) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_gem_json = dest_gem_folder / 'gem.json' - if not unzipped_gem_json.is_file(): - logger.error(f'Engine json {unzipped_gem_json} is missing.') - return 1 - - if not valid_o3de_engine_json(unzipped_gem_json): - logger.error(f'Engine json {unzipped_gem_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable gem.json - # then compare it to the gem.json in the zip, they should now be identical - try: - del downloadable_gem_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_gem_data, indent=4).encode('utf8')).hexdigest() - with unzipped_gem_json.open('r') as s: - try: - unzipped_gem_json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to read gem json {unzipped_gem_json}. Unable to confirm this' - f' is the same gem that was advertised.') - return 1 - sha256B = hashlib.sha256(json.dumps(unzipped_gem_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded gem.json does not match' - f' the advertised gem.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 - - -def download_template(template_name: str, - dest_path: str or pathlib.Path) -> int: - if not dest_path: - dest_path = get_registered(default_folder='templates') - if not dest_path: - logger.error(f'Destination path not cannot be empty.') - return 1 - - dest_path = pathlib.Path(dest_path).resolve() - dest_path.mkdir(exist_ok=True, parents=True) - - download_path = get_o3de_download_folder() / 'templates' / template_name - download_path.mkdir(exist_ok=True, parents=True) - download_zip_path = download_path / 'template.zip' - - downloadable_template_data = get_downloadable(template_name=template_name) - if not downloadable_template_data: - logger.error(f'Downloadable template {template_name} not found.') - return 1 - - origin = downloadable_template_data['origin'] - url = f'{origin}/project.zip' - parsed_uri = urllib.parse.urlparse(url) - - result = 0 - - if download_zip_path.is_file(): - logger.warn(f'Project already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) - - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Template zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 - - # if the template.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_template_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised template you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised template!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded template.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the template.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - dest_template_folder = dest_path / template_name - if dest_template_folder.is_dir(): - backup_folder(dest_template_folder) - with zipfile.ZipFile(download_zip_path, 'r') as project_zip: - try: - project_zip.extractall(dest_path) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_template_json = dest_template_folder / 'template.json' - if not unzipped_template_json.is_file(): - logger.error(f'Template json {unzipped_template_json} is missing.') - return 1 - - if not valid_o3de_engine_json(unzipped_template_json): - logger.error(f'Template json {unzipped_template_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable template.json - # then compare it to the template.json in the zip, they should now be identical - try: - del downloadable_template_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_template_data, indent=4).encode('utf8')).hexdigest() - with unzipped_template_json.open('r') as s: - try: - unzipped_template_json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to read Template json {unzipped_template_json}. Unable to confirm this' - f' is the same template that was advertised.') - return 1 - sha256B = hashlib.sha256(json.dumps(unzipped_template_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded template.json does not match' - f' the advertised template.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 - - -def download_restricted(restricted_name: str, - dest_path: str or pathlib.Path) -> int: - if not dest_path: - dest_path = get_registered(default_folder='restricted') - if not dest_path: - logger.error(f'Destination path not cannot be empty.') - return 1 - - dest_path = pathlib.Path(dest_path).resolve() - dest_path.mkdir(exist_ok=True, parents=True) - - download_path = get_o3de_download_folder() / 'restricted' / restricted_name - download_path.mkdir(exist_ok=True, parents=True) - download_zip_path = download_path / 'restricted.zip' - - downloadable_restricted_data = get_downloadable(restricted_name=restricted_name) - if not downloadable_restricted_data: - logger.error(f'Downloadable Restricted {restricted_name} not found.') - return 1 - - origin = downloadable_restricted_data['origin'] - url = f'{origin}/restricted.zip' - parsed_uri = urllib.parse.urlparse(url) - - if download_zip_path.is_file(): - logger.warn(f'Restricted already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) - - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Restricted zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 - - # if the restricted.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_restricted_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised restricted you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised restricted!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded restricted.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the restricted.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - dest_restricted_folder = dest_path / restricted_name - if dest_restricted_folder.is_dir(): - backup_folder(dest_restricted_folder) - with zipfile.ZipFile(download_zip_path, 'r') as project_zip: - try: - project_zip.extractall(dest_path) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_restricted_json = dest_restricted_folder / 'restricted.json' - if not unzipped_restricted_json.is_file(): - logger.error(f'Restricted json {unzipped_restricted_json} is missing.') - return 1 - - if not valid_o3de_engine_json(unzipped_restricted_json): - logger.error(f'Restricted json {unzipped_restricted_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable restricted.json - # then compare it to the restricted.json in the zip, they should now be identical - try: - del downloadable_restricted_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_restricted_data, indent=4).encode('utf8')).hexdigest() - with unzipped_restricted_json.open('r') as s: - try: - unzipped_restricted_json_data = json.load(s) - except Exception as e: - logger.error( - f'Failed to read Restricted json {unzipped_restricted_json}. Unable to confirm this' - f' is the same restricted that was advertised.') - return 1 - sha256B = hashlib.sha256( - json.dumps(unzipped_restricted_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded restricted.json does not match' - f' the advertised restricted.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 - - -def add_gem_dependency(cmake_file: str or pathlib.Path, - gem_target: str) -> int: - """ - adds a gem dependency to a cmake file - :param cmake_file: path to the cmake file - :param gem_target: name of the cmake target - :return: 0 for success or non 0 failure code - """ - if not os.path.isfile(cmake_file): - logger.error(f'Failed to locate cmake file {cmake_file}') - return 1 - - # on a line by basis, see if there already is Gem::{gem_name} - # find the first occurrence of a gem, copy its formatting and replace - # the gem name with the new one and append it - # if the gem is already present fail - t_data = [] - added = False - with open(cmake_file, 'r') as s: - for line in s: - if f'Gem::{gem_target}' in line: - logger.warning(f'{gem_target} is already a gem dependency.') - return 0 - if not added and r'Gem::' in line: - new_gem = ' ' * line.find(r'Gem::') + f'Gem::{gem_target}\n' - t_data.append(new_gem) - added = True - t_data.append(line) - - # if we didn't add it the set gem dependencies could be empty so - # add a new gem, if empty the correct format is 1 tab=4spaces - if not added: - index = 0 - for line in t_data: - index = index + 1 - if r'set(GEM_DEPENDENCIES' in line: - t_data.insert(index, f' Gem::{gem_target}\n') - added = True - break - - # if we didn't add it then it's not here, add a whole new one - if not added: - t_data.append('\n') - t_data.append('set(GEM_DEPENDENCIES\n') - t_data.append(f' Gem::{gem_target}\n') - t_data.append(')\n') - - # write the cmake - os.unlink(cmake_file) - with open(cmake_file, 'w') as s: - s.writelines(t_data) - - return 0 - - -def get_project_runtime_gem_targets(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) - - -def get_project_tool_gem_targets(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) - - -def get_project_server_gem_targets(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) - - -def get_project_gem_targets(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - runtime_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) - tool_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) - server_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) - return runtime_gems.union(tool_gems.union(server_gems)) - - -def get_gem_targets_from_cmake_file(cmake_file: str or pathlib.Path) -> set: - """ - Gets a list of declared gem targets dependencies of a cmake file - :param cmake_file: path to the cmake file - :return: set of gem targets found - """ - cmake_file = pathlib.Path(cmake_file).resolve() - - if not cmake_file.is_file(): - logger.error(f'Failed to locate cmake file {cmake_file}') - return set() - - gem_target_set = set() - with cmake_file.open('r') as s: - for line in s: - gem_name = line.split('Gem::') - if len(gem_name) > 1: - # Only take the name as everything leading up to the first '.' if found - # Gem naming conventions will have GemName.Editor, GemName.Server, and GemName - # as different targets of the GemName Gem - gem_target_set.add(gem_name[1].replace('\n', '')) - return gem_target_set - - -def get_project_runtime_gem_names(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) - - -def get_project_tool_gem_names(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) - - -def get_project_server_gem_names(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) - - -def get_project_gem_names(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - runtime_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) - tool_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) - server_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) - return runtime_gem_names.union(tool_gem_names.union(server_gem_names)) - - -def get_gem_names_from_cmake_file(cmake_file: str or pathlib.Path) -> set: - """ - Gets a list of declared gem dependencies of a cmake file - :param cmake_file: path to the cmake file - :return: set of gems found - """ - cmake_file = pathlib.Path(cmake_file).resolve() - - if not cmake_file.is_file(): - logger.error(f'Failed to locate cmake file {cmake_file}') - return set() - - gem_set = set() - with cmake_file.open('r') as s: - for line in s: - gem_name = line.split('Gem::') - if len(gem_name) > 1: - # Only take the name as everything leading up to the first '.' if found - # Gem naming conventions will have GemName.Editor, GemName.Server, and GemName - # as different targets of the GemName Gem - gem_set.add(gem_name[1].split('.')[0].replace('\n', '')) - return gem_set - - -def get_project_runtime_gem_paths(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - gem_names = get_project_runtime_gem_names(project_path, platform) - gem_paths = set() - for gem_name in gem_names: - gem_paths.add(get_registered(gem_name=gem_name)) - return gem_paths - - -def get_project_tool_gem_paths(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - gem_names = get_project_tool_gem_names(project_path, platform) - gem_paths = set() - for gem_name in gem_names: - gem_paths.add(get_registered(gem_name=gem_name)) - return gem_paths - - -def get_project_server_gem_paths(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - gem_names = get_project_server_gem_names(project_path, platform) - gem_paths = set() - for gem_name in gem_names: - gem_paths.add(get_registered(gem_name=gem_name)) - return gem_paths - - -def get_project_gem_paths(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - gem_names = get_project_gem_names(project_path, platform) - gem_paths = set() - for gem_name in gem_names: - gem_paths.add(get_registered(gem_name=gem_name)) - return gem_paths - - -def remove_gem_dependency(cmake_file: str or pathlib.Path, - gem_target: str) -> int: - """ - removes a gem dependency from a cmake file - :param cmake_file: path to the cmake file - :param gem_target: cmake target name - :return: 0 for success or non 0 failure code - """ - if not os.path.isfile(cmake_file): - logger.error(f'Failed to locate cmake file {cmake_file}') - return 1 - - # on a line by basis, remove any line with Gem::{gem_name} - t_data = [] - # Remove the gem from the cmake_dependencies file by skipping the gem name entry - removed = False - with open(cmake_file, 'r') as s: - for line in s: - if f'Gem::{gem_target}' in line: - removed = True - else: - t_data.append(line) - - if not removed: - logger.error(f'Failed to remove Gem::{gem_target} from cmake file {cmake_file}') - return 1 - - # write the cmake - os.unlink(cmake_file) - with open(cmake_file, 'w') as s: - s.writelines(t_data) - - return 0 - - -def get_project_templates(): # temporary until we have a better way to do this... maybe template_type element - project_templates = [] - for template in get_all_templates(): - if 'Project' in template: - project_templates.append(template) - return project_templates - - -def get_gem_templates(): # temporary until we have a better way to do this... maybe template_type element - gem_templates = [] - for template in get_all_templates(): - if 'Gem' in template: - gem_templates.append(template) - 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_dependencies_cmake_file(project_name: str = None, - project_path: str or pathlib.Path = None, - dependency_type: str = 'runtime', - platform: str = 'Common') -> str or None: - """ - get the standard cmake file name for a particular type of dependency - :param gem_name: name of the gem, resolves gem_path - :param gem_path: path of the gem - :return: list of gem targets - """ - if not project_name and not project_path: - logger.error(f'Must supply either a Project Name or Project Path.') - return None - - if project_name and not project_path: - project_path = get_registered(project_name=project_name) - - project_path = pathlib.Path(project_path).resolve() - - if platform == 'Common': - dependencies_file = f'{dependency_type}_dependencies.cmake' - dependencies_file_path = project_path / 'Gem/Code' / dependencies_file - if dependencies_file_path.is_file(): - return dependencies_file_path - return project_path / 'Code' / dependencies_file - else: - dependencies_file = f'{platform.lower()}_{dependency_type}_dependencies.cmake' - dependencies_file_path = project_path / 'Gem/Code/Platform' / platform / dependencies_file - if dependencies_file_path.is_file(): - return dependencies_file_path - return project_path / 'Code/Platform' / platform / dependencies_file - - -def get_all_gem_targets() -> list: - modules = [] - for gem_path in get_all_gems(): - this_gems_targets = get_gem_targets(gem_path=gem_path) - modules.extend(this_gems_targets) - return modules - - -def get_gem_targets(gem_name: str = None, - gem_path: str or pathlib.Path = None) -> list: - """ - Finds gem targets in a gem - :param gem_name: name of the gem, resolves gem_path - :param gem_path: path of the gem - :return: list of gem targets - """ - if not gem_name and not gem_path: - return [] - - if gem_name and not gem_path: - gem_path = get_registered(gem_name=gem_name) - - if not gem_path: - return [] - - gem_path = pathlib.Path(gem_path).resolve() - gem_json = gem_path / 'gem.json' - if not valid_o3de_gem_json(gem_json): - return [] - - module_identifiers = [ - 'MODULE', - 'GEM_MODULE', - '${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}' - ] - modules = [] - for root, dirs, files in os.walk(gem_path): - for file in files: - if file == 'CMakeLists.txt': - with open(os.path.join(root, file), 'r') as s: - for line in s: - trimmed = line.lstrip() - if trimmed.startswith('NAME '): - trimmed = trimmed.rstrip(' \n') - split_trimmed = trimmed.split(' ') - if len(split_trimmed) == 3 and split_trimmed[2] in module_identifiers: - modules.append(split_trimmed[1]) - return modules - - -def add_external_subdirectory(external_subdir: str or pathlib.Path, - engine_path: str or pathlib.Path = None, - suppress_errors: bool = False) -> int: - """ - add external subdirectory to a cmake - :param external_subdir: external subdirectory to add to cmake - :param engine_path: optional engine path, defaults to this engine - :param suppress_errors: optional silence errors - :return: 0 for success or non 0 failure code - """ - external_subdir = pathlib.Path(external_subdir).resolve() - if not external_subdir.is_dir(): - if not suppress_errors: - logger.error(f'Add External Subdirectory Failed: {external_subdir} does not exist.') - return 1 - - external_subdir_cmake = external_subdir / 'CMakeLists.txt' - if not external_subdir_cmake.is_file(): - if not suppress_errors: - logger.error(f'Add External Subdirectory Failed: {external_subdir} does not contain a CMakeLists.txt.') - return 1 - - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data, engine_path) - if not engine_object: - if not suppress_errors: - logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') - return 1 - - while external_subdir.as_posix() in engine_object['external_subdirectories']: - engine_object['external_subdirectories'].remove(external_subdir.as_posix()) - - def parse_cmake_file(cmake: str or pathlib.Path, - files: set): - cmake_path = pathlib.Path(cmake).resolve() - cmake_file = cmake_path - if cmake_path.is_dir(): - files.add(cmake_path) - cmake_file = cmake_path / 'CMakeLists.txt' - elif cmake_path.is_file(): - cmake_path = cmake_path.parent - else: - return - - with cmake_file.open('r') as s: - lines = s.readlines() - for line in lines: - line = line.strip() - start = line.find('include(') - if start == 0: - end = line.find(')', start) - if end > start + len('include('): - try: - include_cmake_file = pathlib.Path(engine_path / line[start + len('include('): end]).resolve() - except Exception as e: - pass - else: - parse_cmake_file(include_cmake_file, files) - else: - start = line.find('add_subdirectory(') - if start == 0: - end = line.find(')', start) - if end > start + len('add_subdirectory('): - try: - include_cmake_file = pathlib.Path( - cmake_path / line[start + len('add_subdirectory('): end]).resolve() - except Exception as e: - pass - else: - parse_cmake_file(include_cmake_file, files) - - cmake_files = set() - parse_cmake_file(engine_path, cmake_files) - for external in engine_object["external_subdirectories"]: - parse_cmake_file(external, cmake_files) - - if external_subdir in cmake_files: - save_o3de_manifest(json_data) - if not suppress_errors: - logger.error(f'External subdirectory {external_subdir.as_posix()} already included by add_subdirectory().') - return 1 - - engine_object['external_subdirectories'].insert(0, external_subdir.as_posix()) - engine_object['external_subdirectories'] = sorted(engine_object['external_subdirectories']) - - save_o3de_manifest(json_data) - - return 0 - - -def remove_external_subdirectory(external_subdir: str or pathlib.Path, - engine_path: str or pathlib.Path = None) -> int: - """ - remove external subdirectory from cmake - :param external_subdir: external subdirectory to add to cmake - :param engine_path: optional engine path, defaults to this engine - :return: 0 for success or non 0 failure code - """ - json_data = load_o3de_manifest() - engine_object = find_engine_data(json_data, engine_path) - if not engine_object: - logger.error(f'Remove External Subdirectory Failed: {engine_path} not registered.') - return 1 - - external_subdir = pathlib.Path(external_subdir).resolve() - while external_subdir.as_posix() in engine_object['external_subdirectories']: - engine_object['external_subdirectories'].remove(external_subdir.as_posix()) - - save_o3de_manifest(json_data) - - return 0 - - -def add_gem_to_cmake(gem_name: str = None, - gem_path: str or pathlib.Path = None, - engine_name: str = None, - engine_path: str or pathlib.Path = None, - suppress_errors: bool = False) -> int: - """ - add a gem to a cmake as an external subdirectory for an engine - :param gem_name: name of the gem to add to cmake - :param gem_path: the path of the gem to add to cmake - :param engine_name: name of the engine to add to cmake - :param engine_path: the path of the engine to add external subdirectory to, default to this engine - :param suppress_errors: optional silence errors - :return: 0 for success or non 0 failure code - """ - if not gem_name and not gem_path: - if not suppress_errors: - logger.error('Must specify either a Gem name or Gem Path.') - return 1 - - if gem_name and not gem_path: - gem_path = get_registered(gem_name=gem_name) - - if not gem_path: - if not suppress_errors: - logger.error(f'Gem Path {gem_path} has not been registered.') - return 1 - - gem_path = pathlib.Path(gem_path).resolve() - gem_json = gem_path / 'gem.json' - if not gem_json.is_file(): - if not suppress_errors: - logger.error(f'Gem json {gem_json} is not present.') - return 1 - if not valid_o3de_gem_json(gem_json): - if not suppress_errors: - logger.error(f'Gem json {gem_json} is not valid.') - return 1 - - if not engine_name and not engine_path: - engine_path = get_this_engine_path() - - if engine_name and not engine_path: - engine_path = get_registered(engine_name=engine_name) - - if not engine_path: - if not suppress_errors: - logger.error(f'Engine Path {engine_path} has not been registered.') - return 1 - - engine_json = engine_path / 'engine.json' - if not engine_json.is_file(): - if not suppress_errors: - logger.error(f'Engine json {engine_json} is not present.') - return 1 - if not valid_o3de_engine_json(engine_json): - if not suppress_errors: - logger.error(f'Engine json {engine_json} is not valid.') - return 1 - - return add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path, suppress_errors=suppress_errors) - - -def remove_gem_from_cmake(gem_name: str = None, - gem_path: str or pathlib.Path = None, - engine_name: str = None, - engine_path: str or pathlib.Path = None) -> int: - """ - remove a gem to cmake as an external subdirectory - :param gem_name: name of the gem to remove from cmake - :param gem_path: the path of the gem to add to cmake - :param engine_name: optional name of the engine to remove from cmake - :param engine_path: the path of the engine to remove external subdirectory from, defaults to this engine - :return: 0 for success or non 0 failure code - """ - if not gem_name and not gem_path: - logger.error('Must specify either a Gem name or Gem Path.') - return 1 - - if gem_name and not gem_path: - gem_path = get_registered(gem_name=gem_name) - - if not gem_path: - logger.error(f'Gem Path {gem_path} has not been registered.') - return 1 - - if not engine_name and not engine_path: - engine_path = get_this_engine_path() - - if engine_name and not engine_path: - engine_path = get_registered(engine_name=engine_name) - - if not engine_path: - logger.error(f'Engine Path {engine_path} is not registered.') - return 1 - - return remove_external_subdirectory(external_subdir=gem_path, engine_path=engine_path) - - -def add_gem_to_project(gem_name: str = None, - gem_path: str or pathlib.Path = None, - gem_target: str = None, - project_name: str = None, - project_path: str or pathlib.Path = None, - dependencies_file: str or pathlib.Path = None, - runtime_dependency: bool = False, - tool_dependency: bool = False, - server_dependency: bool = False, - platforms: str = 'Common', - add_to_cmake: bool = True) -> int: - """ - add a gem to a project - :param gem_name: name of the gem to add - :param gem_path: path to the gem to add - :param gem_target: the name of the cmake gem module - :param project_name: name of to the project to add the gem to - :param project_path: path to the project to add the gem to - :param dependencies_file: if this dependency goes/is in a specific file - :param runtime_dependency: bool to specify this is a runtime gem for the game - :param tool_dependency: bool to specify this is a tool gem for the editor - :param server_dependency: bool to specify this is a server gem for the server - :param platforms: str to specify common or which specific platforms - :param add_to_cmake: bool to specify that this gem should be added to cmake - :return: 0 for success or non 0 failure code - """ - # we need either a project name or path - if not project_name and not project_path: - logger.error(f'Must either specify a Project path or Project Name.') - return 1 - - # if project name resolve it into a path - if project_name and not project_path: - project_path = get_registered(project_name=project_name) - project_path = pathlib.Path(project_path).resolve() - if not project_path.is_dir(): - logger.error(f'Project path {project_path} is not a folder.') - return 1 - - # get the engine name this project is associated with - # and resolve that engines path - project_json = project_path / 'project.json' - if not valid_o3de_project_json(project_json): - logger.error(f'Project json {project_json} is not valid.') - return 1 - with project_json.open('r') as s: - try: - project_json_data = json.load(s) - except Exception as e: - logger.error(f'Error loading Project json {project_json}: {str(e)}') - return 1 - else: - try: - engine_name = project_json_data['engine'] - except Exception as e: - logger.error(f'Project json {project_json} "engine" not found: {str(e)}') - return 1 - else: - engine_path = get_registered(engine_name=engine_name) - if not engine_path: - logger.error(f'Engine {engine_name} is not registered.') - return 1 - - # we need either a gem name or path - if not gem_name and not gem_path: - logger.error(f'Must either specify a Gem path or Gem Name.') - return 1 - - # if gem name resolve it into a path - if gem_name and not gem_path: - gem_path = get_registered(gem_name=gem_name) - gem_path = pathlib.Path(gem_path).resolve() - # make sure this gem already exists if we're adding. We can always remove a gem. - if not gem_path.is_dir(): - logger.error(f'Gem Path {gem_path} does not exist.') - return 1 - - # if add to cmake, make sure the gem.json exists and valid before we proceed - if add_to_cmake: - gem_json = gem_path / 'gem.json' - if not gem_json.is_file(): - logger.error(f'Gem json {gem_json} is not present.') - return 1 - if not valid_o3de_gem_json(gem_json): - logger.error(f'Gem json {gem_json} is not valid.') - return 1 - - # find all available modules in this gem_path - modules = get_gem_targets(gem_path=gem_path) - if len(modules) == 0: - logger.error(f'No gem modules found under {gem_path}.') - return 1 - - # if the gem has no modules and the user has specified a target fail - if gem_target and not modules: - logger.error(f'Gem has no targets, but gem target {gem_target} was specified.') - return 1 - - # if the gem target is not in the modules - if gem_target not in modules: - logger.error(f'Gem target not in gem modules: {modules}') - return 1 - - if gem_target: - # if the user has not specified either we will assume they meant the most common which is runtime - if not runtime_dependency and not tool_dependency and not server_dependency and not dependencies_file: - logger.warning("Dependency type not specified: Assuming '--runtime-dependency'") - runtime_dependency = True - - ret_val = 0 - - # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags - if dependencies_file: - dependencies_file = pathlib.Path(dependencies_file).resolve() - # make sure this is a project has a dependencies_file - if not dependencies_file.is_file(): - logger.error(f'Dependencies file {dependencies_file} is not present.') - return 1 - # add the dependency - ret_val = add_gem_dependency(dependencies_file, gem_target) - - else: - if ',' in platforms: - platforms = platforms.split(',') - else: - platforms = [platforms] - for platform in platforms: - if runtime_dependency: - # make sure this is a project has a runtime_dependencies.cmake file - project_runtime_dependencies_file = pathlib.Path( - get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)).resolve() - if not project_runtime_dependencies_file.is_file(): - logger.error(f'Runtime dependencies file {project_runtime_dependencies_file} is not present.') - return 1 - # add the dependency - ret_val = add_gem_dependency(project_runtime_dependencies_file, gem_target) - - if (ret_val == 0) and tool_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_tool_dependencies_file = pathlib.Path( - get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)).resolve() - if not project_tool_dependencies_file.is_file(): - logger.error(f'Tool dependencies file {project_tool_dependencies_file} is not present.') - return 1 - # add the dependency - ret_val = add_gem_dependency(project_tool_dependencies_file, gem_target) - - if (ret_val == 0) and server_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_server_dependencies_file = pathlib.Path( - get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)).resolve() - if not project_server_dependencies_file.is_file(): - logger.error(f'Server dependencies file {project_server_dependencies_file} is not present.') - return 1 - # add the dependency - ret_val = add_gem_dependency(project_server_dependencies_file, gem_target) - - if not ret_val and add_to_cmake: - ret_val = add_gem_to_cmake(gem_path=gem_path, engine_path=engine_path) - - return ret_val - - -def remove_gem_from_project(gem_name: str = None, - gem_path: str or pathlib.Path = None, - gem_target: str = None, - project_name: str = None, - project_path: str or pathlib.Path = None, - dependencies_file: str or pathlib.Path = None, - runtime_dependency: bool = False, - tool_dependency: bool = False, - server_dependency: bool = False, - platforms: str = 'Common', - remove_from_cmake: bool = False) -> int: - """ - remove a gem from a project - :param gem_name: name of the gem to add - :param gem_path: path to the gem to add - :param gem_target: the name of teh cmake gem module - :param project_name: name of the project to add the gem to - :param project_path: path to the project to add the gem to - :param dependencies_file: if this dependency goes/is in a specific file - :param runtime_dependency: bool to specify this is a runtime gem for the game - :param tool_dependency: bool to specify this is a tool gem for the editor - :param server_dependency: bool to specify this is a server gem for the server - :param platforms: str to specify common or which specific platforms - :param remove_from_cmake: bool to specify that this gem should be removed from cmake - :return: 0 for success or non 0 failure code - """ - - # we need either a project name or path - if not project_name and not project_path: - logger.error(f'Must either specify a Project path or Project Name.') - return 1 - - # if project name resolve it into a path - if project_name and not project_path: - project_path = get_registered(project_name=project_name) - project_path = pathlib.Path(project_path).resolve() - if not project_path.is_dir(): - logger.error(f'Project path {project_path} is not a folder.') - return 1 - - # We need either a gem name or path - if not gem_name and not gem_path: - logger.error(f'Must either specify a Gem path or Gem Name.') - return 1 - - # if gem name resolve it into a path - if gem_name and not gem_path: - gem_path = get_registered(gem_name=gem_name) - gem_path = pathlib.Path(gem_path).resolve() - # make sure this gem already exists if we're adding. We can always remove a gem. - if not gem_path.is_dir(): - logger.error(f'Gem Path {gem_path} does not exist.') - return 1 - - # find all available modules in this gem_path - modules = get_gem_targets(gem_path=gem_path) - if len(modules) == 0: - logger.error(f'No gem modules found.') - return 1 - - # if the user has not set a specific gem target remove all of them - - # if gem target not specified, see if there is only 1 module - if not gem_target: - if len(modules) == 1: - gem_target = modules[0] - else: - logger.error(f'Gem target not specified: {modules}') - return 1 - elif gem_target not in modules: - logger.error(f'Gem target not in gem modules: {modules}') - return 1 - - # if the user has not specified either we will assume they meant the most common which is runtime - if not runtime_dependency and not tool_dependency and not server_dependency and not dependencies_file: - logger.warning("Dependency type not specified: Assuming '--runtime-dependency'") - runtime_dependency = True - - # when removing we will try to do as much as possible even with failures so ret_val will be the last error code - ret_val = 0 - - # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags - if dependencies_file: - dependencies_file = pathlib.Path(dependencies_file).resolve() - # make sure this is a project has a dependencies_file - if not dependencies_file.is_file(): - logger.error(f'Dependencies file {dependencies_file} is not present.') - return 1 - # remove the dependency - error_code = remove_gem_dependency(dependencies_file, gem_target) - if error_code: - ret_val = error_code - else: - if ',' in platforms: - platforms = platforms.split(',') - else: - platforms = [platforms] - for platform in platforms: - if runtime_dependency: - # make sure this is a project has a runtime_dependencies.cmake file - project_runtime_dependencies_file = pathlib.Path( - get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)).resolve() - if not project_runtime_dependencies_file.is_file(): - logger.error(f'Runtime dependencies file {project_runtime_dependencies_file} is not present.') - else: - # remove the dependency - error_code = remove_gem_dependency(project_runtime_dependencies_file, gem_target) - if error_code: - ret_val = error_code - - if tool_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_tool_dependencies_file = pathlib.Path( - get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)).resolve() - if not project_tool_dependencies_file.is_file(): - logger.error(f'Tool dependencies file {project_tool_dependencies_file} is not present.') - else: - # remove the dependency - error_code = remove_gem_dependency(project_tool_dependencies_file, gem_target) - if error_code: - ret_val = error_code - - if server_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_server_dependencies_file = pathlib.Path( - get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)).resolve() - if not project_server_dependencies_file.is_file(): - logger.error(f'Server dependencies file {project_server_dependencies_file} is not present.') - else: - # remove the dependency - error_code = remove_gem_dependency(project_server_dependencies_file, gem_target) - if error_code: - ret_val = error_code - - if remove_from_cmake: - error_code = remove_gem_from_cmake(gem_path=gem_path) - if error_code: - ret_val = error_code - - return ret_val - - -def sha256(file_path: str or pathlib.Path, - json_path: str or pathlib.Path = None) -> int: - if not file_path: - logger.error(f'File path cannot be empty.') - return 1 - file_path = pathlib.Path(file_path).resolve() - if not file_path.is_file(): - logger.error(f'File path {file_path} does not exist.') - return 1 - - if json_path: - json_path = pathlib.Path(json_path).resolve() - if not json_path.is_file(): - logger.error(f'Json path {json_path} does not exist.') - return 1 - - sha256 = hashlib.sha256(file_path.open('rb').read()).hexdigest() - - if json_path: - with json_path.open('r') as s: - try: - json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to read Json path {json_path}: {str(e)}') - return 1 - json_data.update({"sha256": sha256}) - backup_file(json_path) - with json_path.open('w') as s: - try: - s.write(json.dumps(json_data, indent=4)) - except Exception as e: - logger.error(f'Failed to write Json path {json_path}: {str(e)}') - return 1 - else: - print(sha256) - return 0 - - -def _run_get_registered(args: argparse) -> str or pathlib.Path: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - return get_registered(args.engine_name, - args.project_name, - args.gem_name, - args.template_name, - args.default_folder, - args.repo_name, - args.restricted_name) - - -def _run_register_show(args: argparse) -> int: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - if args.this_engine: - print_this_engine(args.verbose) - return 0 - - elif args.engines: - print_engines(args.verbose) - return 0 - elif args.projects: - print_projects(args.verbose) - return 0 - elif args.gems: - print_gems(args.verbose) - return 0 - elif args.templates: - print_templates(args.verbose) - return 0 - elif args.repos: - register_show_repos(args.verbose) - return 0 - elif args.restricted: - print_restricted(args.verbose) - return 0 - - elif args.engine_projects: - print_engine_projects(args.verbose) - return 0 - 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 - elif args.external_subdirectories: - print_external_subdirectories(args.verbose) - return 0 - - elif args.all_projects: - print_all_projects(args.verbose) - return 0 - elif args.all_gems: - print_all_gems(args.verbose) - return 0 - elif args.all_templates: - print_all_templates(args.verbose) - return 0 - elif args.all_restricted: - print_all_restricted(args.verbose) - return 0 - - 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 - - -def _run_download(args: argparse) -> int: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - if args.engine_name: - return download_engine(args.engine_name, - args.dest_path) - elif args.project_name: - return download_project(args.project_name, - args.dest_path) - elif args.gem_nanme: - return download_gem(args.gem_name, - args.dest_path) - elif args.template_name: - return download_template(args.template_name, - args.dest_path) - - -def _run_register(args: argparse) -> int: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - if args.update: - remove_invalid_o3de_objects() - return refresh_repos() - elif args.this_engine: - ret_val = register(engine_path=get_this_engine_path(), force=args.force) - error_code = register_shipped_engine_o3de_objects(force=args.force) - if error_code: - ret_val = error_code - return ret_val - elif args.all_engines_path: - return register_all_engines_in_folder(args.all_engines_path, args.remove, args.force) - elif args.all_projects_path: - return register_all_projects_in_folder(args.all_projects_path, args.remove) - elif args.all_gems_path: - return register_all_gems_in_folder(args.all_gems_path, args.remove) - elif args.all_templates_path: - return register_all_templates_in_folder(args.all_templates_path, args.remove) - elif args.all_restricted_path: - return register_all_restricted_in_folder(args.all_restricted_path, args.remove) - elif args.all_repo_uri: - return register_all_repos_in_folder(args.all_restricted_path, args.remove) - else: - return register(engine_path=args.engine_path, - project_path=args.project_path, - gem_path=args.gem_path, - template_path=args.template_path, - restricted_path=args.restricted_path, - repo_uri=args.repo_uri, - default_engines_folder=args.default_engines_folder, - default_projects_folder=args.default_projects_folder, - default_gems_folder=args.default_gems_folder, - default_templates_folder=args.default_templates_folder, - default_restricted_folder=args.default_restricted_folder, - remove=args.remove, - force=args.force) - - -def _run_add_external_subdirectory(args: argparse) -> int: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - return add_external_subdirectory(args.external_subdirectory) - - -def _run_remove_external_subdirectory(args: argparse) -> int: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - return remove_external_subdirectory(args.external_subdirectory) - - -def _run_add_gem_to_cmake(args: argparse) -> int: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - return add_gem_to_cmake(gem_name=args.gem_name, gem_path=args.gem_path) - - -def _run_remove_gem_from_cmake(args: argparse) -> int: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - return remove_gem_from_cmake(args.gem_name, args.gem_path) - - -def _run_add_gem_to_project(args: argparse) -> int: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - return add_gem_to_project(args.gem_name, - args.gem_path, - args.gem_target, - args.project_name, - args.project_path, - args.dependencies_file, - args.runtime_dependency, - args.tool_dependency, - args.server_dependency, - args.platforms, - args.add_to_cmake) - - -def _run_remove_gem_from_project(args: argparse) -> int: - if args.override_home_folder: - global override_home_folder - override_home_folder = args.override_home_folder - - return remove_gem_from_project(args.gem_name, - args.gem_path, - args.gem_target, - args.project_path, - args.project_name, - args.dependencies_file, - args.runtime_dependency, - args.tool_dependency, - args.server_dependency, - args.platforms, - args.remove_from_cmake) - - -def _run_sha256(args: argparse) -> int: - return sha256(args.file_path, - args.json_path) def add_args(parser, subparsers) -> None: @@ -4095,320 +28,48 @@ def add_args(parser, subparsers) -> None: :param subparsers: the caller instantiates subparsers and passes it in here """ # register - register_subparser = subparsers.add_parser('register') - group = register_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('--this-engine', action='store_true', required=False, - default=False, - help='Registers the engine this script is running from.') - group.add_argument('-ep', '--engine-path', type=str, required=False, - help='Engine path to register/remove.') - group.add_argument('-pp', '--project-path', type=str, required=False, - help='Project path to register/remove.') - group.add_argument('-gp', '--gem-path', type=str, required=False, - help='Gem path to register/remove.') - group.add_argument('-tp', '--template-path', type=str, required=False, - help='Template path to register/remove.') - group.add_argument('-rp', '--restricted-path', type=str, required=False, - help='A restricted folder to register/remove.') - group.add_argument('-ru', '--repo-uri', type=str, required=False, - help='A repo uri to register/remove.') - group.add_argument('-aep', '--all-engines-path', type=str, required=False, - help='All engines under this folder to register/remove.') - group.add_argument('-app', '--all-projects-path', type=str, required=False, - help='All projects under this folder to register/remove.') - group.add_argument('-agp', '--all-gems-path', type=str, required=False, - help='All gems under this folder to register/remove.') - group.add_argument('-atp', '--all-templates-path', type=str, required=False, - help='All templates under this folder to register/remove.') - group.add_argument('-arp', '--all-restricted-path', type=str, required=False, - help='All templates under this folder to register/remove.') - group.add_argument('-aru', '--all-repo-uri', type=str, required=False, - help='All repos under this folder to register/remove.') - group.add_argument('-def', '--default-engines-folder', type=str, required=False, - help='The default engines folder to register/remove.') - group.add_argument('-dpf', '--default-projects-folder', type=str, required=False, - help='The default projects folder to register/remove.') - group.add_argument('-dgf', '--default-gems-folder', type=str, required=False, - help='The default gems folder to register/remove.') - group.add_argument('-dtf', '--default-templates-folder', type=str, required=False, - 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('-u', '--update', action='store_true', required=False, - default=False, - help='Refresh the repo cache.') - - register_subparser.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.') - - register_subparser.add_argument('-r', '--remove', action='store_true', required=False, - default=False, - help='Remove entry.') - register_subparser.add_argument('-f', '--force', action='store_true', default=False, - help='For the update of the registration field being modified.') - register_subparser.set_defaults(func=_run_register) + from o3de import register + register.add_args(parser, subparsers) # show - register_show_subparser = subparsers.add_parser('register-show') - group = register_show_subparser.add_mutually_exclusive_group(required=False) - group.add_argument('-te', '--this-engine', action='store_true', required=False, - default=False, - help='Just the local engines.') - - group.add_argument('-e', '--engines', action='store_true', required=False, - default=False, - help='Just the local engines.') - group.add_argument('-p', '--projects', action='store_true', required=False, - default=False, - help='Just the local projects.') - group.add_argument('-g', '--gems', action='store_true', required=False, - default=False, - help='Just the local gems.') - group.add_argument('-t', '--templates', action='store_true', required=False, - default=False, - help='Just the local templates.') - group.add_argument('-r', '--repos', action='store_true', required=False, - default=False, - help='Just the local repos. Ignores repos.') - group.add_argument('-rs', '--restricted', action='store_true', required=False, - default=False, - help='The local restricted folders.') - - group.add_argument('-ep', '--engine-projects', action='store_true', required=False, - default=False, - help='Just the local projects. Ignores repos.') - group.add_argument('-eg', '--engine-gems', action='store_true', required=False, - default=False, - help='Just the local gems. Ignores repos') - group.add_argument('-et', '--engine-templates', action='store_true', required=False, - default=False, - help='Just the local templates. Ignores repos.') - group.add_argument('-ers', '--engine-restricted', action='store_true', required=False, - default=False, - help='The restricted folders.') - group.add_argument('-x', '--external-subdirectories', action='store_true', required=False, - default=False, - help='The external subdirectories.') - - group.add_argument('-ap', '--all-projects', action='store_true', required=False, - default=False, - help='Just the local projects. Ignores repos.') - group.add_argument('-ag', '--all-gems', action='store_true', required=False, - default=False, - help='Just the local gems. 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, - default=False, - help='The restricted folders.') - - group.add_argument('-d', '--downloadables', action='store_true', required=False, - 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.') - - register_show_subparser.add_argument('-v', '--verbose', action='count', required=False, - default=0, - help='How verbose do you want the output to be.') - - register_show_subparser.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.') - - register_show_subparser.set_defaults(func=_run_register_show) + from o3de import print_registration + print_registration.add_args(parser, subparsers) # get-registered - get_registered_subparser = subparsers.add_parser('get-registered') - group = get_registered_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-en', '--engine-name', type=str, required=False, - help='Engine name.') - group.add_argument('-pn', '--project-name', type=str, required=False, - help='Project name.') - group.add_argument('-gn', '--gem-name', type=str, required=False, - help='Gem name.') - group.add_argument('-tn', '--template-name', type=str, required=False, - help='Template name.') - group.add_argument('-df', '--default-folder', type=str, required=False, - choices=['engines', 'projects', 'gems', 'templates', 'restricted'], - help='The default folders for o3de.') - group.add_argument('-rn', '--repo-name', type=str, required=False, - help='Repo name.') - group.add_argument('-rsn', '--restricted-name', type=str, required=False, - help='Restricted name.') - - get_registered_subparser.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.') - - get_registered_subparser.set_defaults(func=_run_get_registered) + from o3de import get_registration + get_registration.add_args(parser, subparsers) # download - download_subparser = subparsers.add_parser('download') - group = download_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-e', '--engine-name', type=str, required=False, - help='Downloadable engine name.') - group.add_argument('-p', '--project-name', type=str, required=False, - help='Downloadable project name.') - group.add_argument('-g', '--gem-name', type=str, required=False, - help='Downloadable gem name.') - group.add_argument('-t', '--template-name', type=str, required=False, - help='Downloadable template name.') - download_subparser.add_argument('-dp', '--dest-path', type=str, required=False, - default=None, - help='Optional destination folder to download into.' - ' i.e. download --project-name "StarterGame" --dest-path "C:/projects"' - ' will result in C:/projects/StarterGame' - ' If blank will download to default object type folder') - - download_subparser.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.') - - download_subparser.set_defaults(func=_run_download) + from o3de import download + download.add_args(parser, subparsers) # add external subdirectories - add_external_subdirectory_subparser = subparsers.add_parser('add-external-subdirectory') - add_external_subdirectory_subparser.add_argument('external_subdirectory', metavar='external_subdirectory', type=str, - help='add an external subdirectory to cmake') - - add_external_subdirectory_subparser.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.') - - add_external_subdirectory_subparser.set_defaults(func=_run_add_external_subdirectory) + from o3de import add_external_subdirectory + add_external_subdirectory.add_args(parser, subparsers) # remove external subdirectories - remove_external_subdirectory_subparser = subparsers.add_parser('remove-external-subdirectory') - remove_external_subdirectory_subparser.add_argument('external_subdirectory', metavar='external_subdirectory', - type=str, - help='remove external subdirectory from cmake') - - remove_external_subdirectory_subparser.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.') - - remove_external_subdirectory_subparser.set_defaults(func=_run_remove_external_subdirectory) + from o3de import remove_external_subdirectory + remove_external_subdirectory.add_args(parser, subparsers) # add gems to cmake - # convenience functions to disambiguate the gem name -> gem_path and call add-external-subdirectory on gem_path - add_gem_to_cmake_subparser = subparsers.add_parser('add-gem-to-cmake') - group = add_gem_to_cmake_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-gp', '--gem-path', type=str, required=False, - help='The path to the gem.') - group.add_argument('-gn', '--gem-name', type=str, required=False, - help='The name of the gem.') - - add_gem_to_cmake_subparser.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.') - - add_gem_to_cmake_subparser.set_defaults(func=_run_add_gem_to_cmake) + from o3de import add_gem_cmake + add_gem_cmake.add_args(parser, subparsers) # remove gems from cmake - # convenience functions to disambiguate the gem name -> gem_path and call remove-external-subdirectory on gem_path - remove_gem_from_cmake_subparser = subparsers.add_parser('remove-gem-from-cmake') - group = remove_gem_from_cmake_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-gp', '--gem-path', type=str, required=False, - help='The path to the gem.') - group.add_argument('-gn', '--gem-name', type=str, required=False, - help='The name of the gem.') - - remove_gem_from_cmake_subparser.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.') - - remove_gem_from_cmake_subparser.set_defaults(func=_run_remove_gem_from_cmake) + from o3de import remove_gem_cmake + remove_gem_cmake.add_args(parser, subparsers) # add a gem to a project - add_gem_subparser = subparsers.add_parser('add-gem-to-project') - group = add_gem_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-pp', '--project-path', type=str, 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 = add_gem_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-gp', '--gem-path', type=str, required=False, - help='The path to the gem.') - group.add_argument('-gn', '--gem-name', type=str, required=False, - help='The name of the gem.') - add_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, - help='The cmake target name to add. If not specified it will assume gem_name') - add_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, - help='The cmake dependencies file in which the gem dependencies are specified.' - 'If not specified it will assume ') - add_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be added as a runtime dependency') - add_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be added as a tool dependency') - add_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be added as a server dependency') - add_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, - default='Common', - help='Optional list of platforms this gem should be added to.' - ' Ex. --platforms Mac,Windows,Linux') - add_gem_subparser.add_argument('-a', '--add-to-cmake', type=bool, required=False, - default=True, - help='Automatically call add-gem-to-cmake.') - - add_gem_subparser.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.') - - add_gem_subparser.set_defaults(func=_run_add_gem_to_project) + from o3de import add_gem_project + add_gem_project.add_args(parser, subparsers) # remove a gem from a project - remove_gem_subparser = subparsers.add_parser('remove-gem-from-project') - group = remove_gem_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-pp', '--project-path', type=str, 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 = remove_gem_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-gp', '--gem-path', type=str, required=False, - help='The path to the gem.') - group.add_argument('-gn', '--gem-name', type=str, required=False, - help='The name of the gem.') - remove_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, - help='The cmake target name to add. If not specified it will assume gem_name') - remove_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, - help='The cmake dependencies file in which the gem dependencies are specified.' - 'If not specified it will assume ') - remove_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be removed as a runtime dependency') - remove_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be removed as a server dependency') - remove_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be removed as a server dependency') - remove_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, - default='Common', - help='Optional list of platforms this gem should be removed from' - ' Ex. --platforms Mac,Windows,Linux') - remove_gem_subparser.add_argument('-r', '--remove-from-cmake', type=bool, required=False, - default=False, - help='Automatically call remove-from-cmake.') - - remove_gem_subparser.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.') - - remove_gem_subparser.set_defaults(func=_run_remove_gem_from_project) + from o3de import remove_gem_project + remove_gem_project.add_args(parser, subparsers) # sha256 - sha256_subparser = subparsers.add_parser('sha256') - sha256_subparser.add_argument('-f', '--file-path', type=str, required=True, - help='The path to the file you want to sha256.') - sha256_subparser.add_argument('-j', '--json-path', type=str, required=False, - help='optional path to an o3de json file to add the "sha256" element to.') - sha256_subparser.set_defaults(func=_run_sha256) + from o3de import sha256 + sha256.add_args(parser, subparsers) if __name__ == "__main__": diff --git a/scripts/o3de/o3de/remove_external_subdirectory.py b/scripts/o3de/o3de/remove_external_subdirectory.py new file mode 100644 index 0000000000..3e022d51b9 --- /dev/null +++ b/scripts/o3de/o3de/remove_external_subdirectory.py @@ -0,0 +1,73 @@ +# +# 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. +# +""" +Contains command to add a gem to a project's cmake scripts +""" + +import argparse +import logging +import pathlib + +from o3de import manifest + +logger = logging.getLogger() +logging.basicConfig() + +def remove_external_subdirectory(external_subdir: str or pathlib.Path, + engine_path: str or pathlib.Path = None) -> int: + """ + remove external subdirectory from cmake + :param external_subdir: external subdirectory to add to cmake + :param engine_path: optional engine path, defaults to this engine + :return: 0 for success or non 0 failure code + """ + json_data = manifest.load_o3de_manifest() + engine_object = manifest.find_engine_data(json_data, engine_path) + if not engine_object: + logger.error(f'Remove External Subdirectory Failed: {engine_path} not registered.') + return 1 + + external_subdir = pathlib.Path(external_subdir).resolve() + while external_subdir.as_posix() in engine_object['external_subdirectories']: + engine_object['external_subdirectories'].remove(external_subdir.as_posix()) + + manifest.save_o3de_manifest(json_data) + + return 0 + + +def _run_remove_external_subdirectory(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + return remove_external_subdirectory(args.external_subdirectory) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + remove_external_subdirectory_subparser = subparsers.add_parser('remove-external-subdirectory') + remove_external_subdirectory_subparser.add_argument('external_subdirectory', metavar='external_subdirectory', + type=str, + help='remove external subdirectory from cmake') + + remove_external_subdirectory_subparser.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.') + + remove_external_subdirectory_subparser.set_defaults(func=_run_remove_external_subdirectory) diff --git a/scripts/o3de/o3de/remove_gem_cmake.py b/scripts/o3de/o3de/remove_gem_cmake.py new file mode 100644 index 0000000000..2def94dfbf --- /dev/null +++ b/scripts/o3de/o3de/remove_gem_cmake.py @@ -0,0 +1,89 @@ +# +# 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. +# +""" +This file contains methods for removing a gem from a project's cmake scripts +""" + +import argparse +import logging +import pathlib + +from o3de import manifest, remove_external_subdirectory + +logger = logging.getLogger() +logging.basicConfig() + +def remove_gem_from_cmake(gem_name: str = None, + gem_path: str or pathlib.Path = None, + engine_name: str = None, + engine_path: str or pathlib.Path = None) -> int: + """ + remove a gem to cmake as an external subdirectory + :param gem_name: name of the gem to remove from cmake + :param gem_path: the path of the gem to add to cmake + :param engine_name: optional name of the engine to remove from cmake + :param engine_path: the path of the engine to remove external subdirectory from, defaults to this engine + :return: 0 for success or non 0 failure code + """ + if not gem_name and not gem_path: + logger.error('Must specify either a Gem name or Gem Path.') + return 1 + + if gem_name and not gem_path: + gem_path = manifest.get_registered(gem_name=gem_name) + + if not gem_path: + logger.error(f'Gem Path {gem_path} has not been registered.') + return 1 + + if not engine_name and not engine_path: + engine_path = manifest.get_this_engine_path() + + if engine_name and not engine_path: + engine_path = manifest.get_registered(engine_name=engine_name) + + if not engine_path: + logger.error(f'Engine Path {engine_path} is not registered.') + return 1 + + return remove_external_subdirectory.remove_external_subdirectory(external_subdir=gem_path, engine_path=engine_path) + + +def _run_remove_gem_from_cmake(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + return remove_gem_from_cmake(args.gem_name, args.gem_path) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + # convenience functions to disambiguate the gem name -> gem_path and call remove-external-subdirectory on gem_path + remove_gem_from_cmake_subparser = subparsers.add_parser('remove-gem-from-cmake') + group = remove_gem_from_cmake_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-gp', '--gem-path', type=str, required=False, + help='The path to the gem.') + group.add_argument('-gn', '--gem-name', type=str, required=False, + help='The name of the gem.') + + remove_gem_from_cmake_subparser.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.') + + remove_gem_from_cmake_subparser.set_defaults(func=_run_remove_gem_from_cmake) diff --git a/scripts/o3de/o3de/remove_gem_project.py b/scripts/o3de/o3de/remove_gem_project.py new file mode 100644 index 0000000000..a3e623f488 --- /dev/null +++ b/scripts/o3de/o3de/remove_gem_project.py @@ -0,0 +1,270 @@ +# +# 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. +# +""" +This file contains methods for removing a gem from a project +""" + +import argparse +import logging +import os +import pathlib + +from o3de import cmake, remove_gem_cmake + +logger = logging.getLogger() +logging.basicConfig() + + +def remove_gem_dependency(cmake_file: str or pathlib.Path, + gem_target: str) -> int: + """ + removes a gem dependency from a cmake file + :param cmake_file: path to the cmake file + :param gem_target: cmake target name + :return: 0 for success or non 0 failure code + """ + if not os.path.isfile(cmake_file): + logger.error(f'Failed to locate cmake file {cmake_file}') + return 1 + + # on a line by basis, remove any line with Gem::{gem_name} + t_data = [] + # Remove the gem from the cmake_dependencies file by skipping the gem name entry + removed = False + with open(cmake_file, 'r') as s: + for line in s: + if f'Gem::{gem_target}' in line: + removed = True + else: + t_data.append(line) + + if not removed: + logger.error(f'Failed to remove Gem::{gem_target} from cmake file {cmake_file}') + return 1 + + # write the cmake + os.unlink(cmake_file) + with open(cmake_file, 'w') as s: + s.writelines(t_data) + + return 0 + + +def remove_gem_from_project(gem_name: str = None, + gem_path: str or pathlib.Path = None, + gem_target: str = None, + project_name: str = None, + project_path: str or pathlib.Path = None, + dependencies_file: str or pathlib.Path = None, + runtime_dependency: bool = False, + tool_dependency: bool = False, + server_dependency: bool = False, + platforms: str = 'Common', + remove_from_cmake: bool = False) -> int: + """ + remove a gem from a project + :param gem_name: name of the gem to add + :param gem_path: path to the gem to add + :param gem_target: the name of teh cmake gem module + :param project_name: name of the project to add the gem to + :param project_path: path to the project to add the gem to + :param dependencies_file: if this dependency goes/is in a specific file + :param runtime_dependency: bool to specify this is a runtime gem for the game + :param tool_dependency: bool to specify this is a tool gem for the editor + :param server_dependency: bool to specify this is a server gem for the server + :param platforms: str to specify common or which specific platforms + :param remove_from_cmake: bool to specify that this gem should be removed from cmake + :return: 0 for success or non 0 failure code + """ + + # we need either a project name or path + if not project_name and not project_path: + logger.error(f'Must either specify a Project path or Project Name.') + return 1 + + # if project name resolve it into a path + if project_name and not project_path: + project_path = manifest.get_registered(project_name=project_name) + project_path = pathlib.Path(project_path).resolve() + if not project_path.is_dir(): + logger.error(f'Project path {project_path} is not a folder.') + return 1 + + # We need either a gem name or path + if not gem_name and not gem_path: + logger.error(f'Must either specify a Gem path or Gem Name.') + return 1 + + # if gem name resolve it into a path + if gem_name and not gem_path: + gem_path = manifest.get_registered(gem_name=gem_name) + gem_path = pathlib.Path(gem_path).resolve() + # make sure this gem already exists if we're adding. We can always remove a gem. + if not gem_path.is_dir(): + logger.error(f'Gem Path {gem_path} does not exist.') + return 1 + + # find all available modules in this gem_path + modules = cmake.get_gem_targets(gem_path=gem_path) + if len(modules) == 0: + logger.error(f'No gem modules found.') + return 1 + + # if the user has not set a specific gem target remove all of them + + # if gem target not specified, see if there is only 1 module + if not gem_target: + if len(modules) == 1: + gem_target = modules[0] + else: + logger.error(f'Gem target not specified: {modules}') + return 1 + elif gem_target not in modules: + logger.error(f'Gem target not in gem modules: {modules}') + return 1 + + # if the user has not specified either we will assume they meant the most common which is runtime + if not runtime_dependency and not tool_dependency and not server_dependency and not dependencies_file: + logger.warning("Dependency type not specified: Assuming '--runtime-dependency'") + runtime_dependency = True + + # when removing we will try to do as much as possible even with failures so ret_val will be the last error code + ret_val = 0 + + # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags + if dependencies_file: + dependencies_file = pathlib.Path(dependencies_file).resolve() + # make sure this is a project has a dependencies_file + if not dependencies_file.is_file(): + logger.error(f'Dependencies file {dependencies_file} is not present.') + return 1 + # remove the dependency + error_code = remove_gem_dependency(dependencies_file, gem_target) + if error_code: + ret_val = error_code + else: + if ',' in platforms: + platforms = platforms.split(',') + else: + platforms = [platforms] + for platform in platforms: + if runtime_dependency: + # make sure this is a project has a runtime_dependencies.cmake file + project_runtime_dependencies_file = pathlib.Path( + cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', + platform=platform)).resolve() + if not project_runtime_dependencies_file.is_file(): + logger.error(f'Runtime dependencies file {project_runtime_dependencies_file} is not present.') + else: + # remove the dependency + error_code = remove_gem_dependency(project_runtime_dependencies_file, gem_target) + if error_code: + ret_val = error_code + + if tool_dependency: + # make sure this is a project has a tool_dependencies.cmake file + project_tool_dependencies_file = pathlib.Path( + cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', + platform=platform)).resolve() + if not project_tool_dependencies_file.is_file(): + logger.error(f'Tool dependencies file {project_tool_dependencies_file} is not present.') + else: + # remove the dependency + error_code = remove_gem_dependency(project_tool_dependencies_file, gem_target) + if error_code: + ret_val = error_code + + if server_dependency: + # make sure this is a project has a tool_dependencies.cmake file + project_server_dependencies_file = pathlib.Path( + cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='server', + platform=platform)).resolve() + if not project_server_dependencies_file.is_file(): + logger.error(f'Server dependencies file {project_server_dependencies_file} is not present.') + else: + # remove the dependency + error_code = remove_gem_dependency(project_server_dependencies_file, gem_target) + if error_code: + ret_val = error_code + + if remove_from_cmake: + error_code = remove_gem_cmake.remove_gem_from_cmake(gem_path=gem_path) + if error_code: + ret_val = error_code + + return ret_val + + +def _run_remove_gem_from_project(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + return remove_gem_from_project(args.gem_name, + args.gem_path, + args.gem_target, + args.project_path, + args.project_name, + args.dependencies_file, + args.runtime_dependency, + args.tool_dependency, + args.server_dependency, + args.platforms, + args.remove_from_cmake) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + remove_gem_subparser = subparsers.add_parser('remove-gem-from-project') + group = remove_gem_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-pp', '--project-path', type=str, 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 = remove_gem_subparser.add_mutually_exclusive_group(required=True) + group.add_argument('-gp', '--gem-path', type=str, required=False, + help='The path to the gem.') + group.add_argument('-gn', '--gem-name', type=str, required=False, + help='The name of the gem.') + remove_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, + help='The cmake target name to add. If not specified it will assume gem_name') + remove_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, + help='The cmake dependencies file in which the gem dependencies are specified.' + 'If not specified it will assume ') + remove_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be removed as a runtime dependency') + remove_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be removed as a server dependency') + remove_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, + default=False, + help='Optional toggle if this gem should be removed as a server dependency') + remove_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, + default='Common', + help='Optional list of platforms this gem should be removed from' + ' Ex. --platforms Mac,Windows,Linux') + remove_gem_subparser.add_argument('-r', '--remove-from-cmake', type=bool, required=False, + default=False, + help='Automatically call remove-from-cmake.') + + remove_gem_subparser.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.') + + remove_gem_subparser.set_defaults(func=_run_remove_gem_from_project) diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py new file mode 100644 index 0000000000..9cb93d53ae --- /dev/null +++ b/scripts/o3de/o3de/repo.py @@ -0,0 +1,291 @@ +# +# 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 json +import logging +import pathlib +import shutil +import urllib.parse +import urllib.request + +from o3de import manifest, validation + +logger = logging.getLogger() +logging.basicConfig() + +def process_add_o3de_repo(file_name: str or pathlib.Path, + repo_set: set) -> int: + file_name = pathlib.Path(file_name).resolve() + if not validation.valid_o3de_repo_json(file_name): + return 1 + + cache_folder = manifest.get_o3de_cache_folder() + + with file_name.open('r') as f: + try: + repo_data = json.load(f) + except Exception as e: + logger.error(f'{file_name} failed to load: {str(e)}') + return 1 + + for engine_uri in repo_data['engines']: + engine_uri = f'{engine_uri}/engine.json' + engine_sha256 = hashlib.sha256(engine_uri.encode()) + cache_file = cache_folder / str(engine_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + 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': + with urllib.request.urlopen(engine_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + engine_json = pathlib.Path(engine_uri).resolve() + if not engine_json.is_file(): + return 1 + shutil.copy(engine_json, cache_file) + + for project_uri in repo_data['projects']: + project_uri = f'{project_uri}/project.json' + project_sha256 = hashlib.sha256(project_uri.encode()) + cache_file = cache_folder / str(project_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + 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': + with urllib.request.urlopen(project_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + project_json = pathlib.Path(project_uri).resolve() + if not project_json.is_file(): + return 1 + shutil.copy(project_json, cache_file) + + for gem_uri in repo_data['gems']: + gem_uri = f'{gem_uri}/gem.json' + gem_sha256 = hashlib.sha256(gem_uri.encode()) + cache_file = cache_folder / str(gem_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + 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': + with urllib.request.urlopen(gem_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + gem_json = pathlib.Path(gem_uri).resolve() + if not gem_json.is_file(): + return 1 + shutil.copy(gem_json, cache_file) + + for template_uri in repo_data['templates']: + template_uri = f'{template_uri}/template.json' + template_sha256 = hashlib.sha256(template_uri.encode()) + cache_file = cache_folder / str(template_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + 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': + with urllib.request.urlopen(template_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + template_json = pathlib.Path(template_uri).resolve() + if not template_json.is_file(): + return 1 + shutil.copy(template_json, cache_file) + + for repo_uri in repo_data['repos']: + if repo_uri not in repo_set: + repo_set.add(repo_uri) + repo_uri = f'{repo_uri}/repo.json' + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(repo_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + repo_json = pathlib.Path(repo_uri).resolve() + if not repo_json.is_file(): + return 1 + shutil.copy(repo_json, cache_file) + return 0 + + +def refresh_repos() -> int: + json_data = manifest.load_o3de_manifest() + + # clear the cache + cache_folder = manifest.get_o3de_cache_folder() + shutil.rmtree(cache_folder) + cache_folder = manifest.get_o3de_cache_folder() # will recreate it + + result = 0 + + # set will stop circular references + repo_set = set() + + for repo_uri in json_data['repos']: + if repo_uri not in repo_set: + repo_set.add(repo_uri) + + repo_uri = f'{repo_uri}/repo.json' + repo_sha256 = hashlib.sha256(repo_uri.encode()) + cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + if not cache_file.is_file(): + parsed_uri = urllib.parse.urlparse(repo_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + with urllib.request.urlopen(repo_uri) as s: + with cache_file.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(repo_uri).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, cache_file) + + if not validation.valid_o3de_repo_json(cache_file): + logger.error(f'Repo json {repo_uri} is not valid.') + cache_file.unlink() + return 1 + + last_failure = process_add_o3de_repo(cache_file, repo_set) + if last_failure: + result = last_failure + + return result + + +def search_repo(repo_set: set, + repo_json_data: dict, + engine_name: str = None, + project_name: str = None, + gem_name: str = None, + template_name: str = None, + restricted_name: str = None) -> dict or None: + cache_folder = manifest.get_o3de_cache_folder() + + if isinstance(engine_name, str) or isinstance(engine_name, pathlib.PurePath): + for engine_uri in repo_json_data['engines']: + engine_uri = f'{engine_uri}/engine.json' + engine_sha256 = hashlib.sha256(engine_uri.encode()) + engine_cache_file = cache_folder / str(engine_sha256.hexdigest() + '.json') + if engine_cache_file.is_file(): + with engine_cache_file.open('r') as f: + try: + engine_json_data = json.load(f) + except Exception as e: + logger.warn(f'{engine_cache_file} failed to load: {str(e)}') + else: + if engine_json_data['engine_name'] == engine_name: + return engine_json_data + + elif isinstance(project_name, str) or isinstance(project_name, pathlib.PurePath): + for project_uri in repo_json_data['projects']: + project_uri = f'{project_uri}/project.json' + project_sha256 = hashlib.sha256(project_uri.encode()) + project_cache_file = cache_folder / str(project_sha256.hexdigest() + '.json') + if project_cache_file.is_file(): + with project_cache_file.open('r') as f: + try: + project_json_data = json.load(f) + except Exception as e: + logger.warn(f'{project_cache_file} failed to load: {str(e)}') + else: + if project_json_data['project_name'] == project_name: + return project_json_data + + elif isinstance(gem_name, str) or isinstance(gem_name, pathlib.PurePath): + for gem_uri in repo_json_data['gems']: + gem_uri = f'{gem_uri}/gem.json' + gem_sha256 = hashlib.sha256(gem_uri.encode()) + gem_cache_file = cache_folder / str(gem_sha256.hexdigest() + '.json') + if gem_cache_file.is_file(): + with gem_cache_file.open('r') as f: + try: + gem_json_data = json.load(f) + except Exception as e: + logger.warn(f'{gem_cache_file} failed to load: {str(e)}') + else: + if gem_json_data['gem_name'] == gem_name: + return gem_json_data + + elif isinstance(template_name, str) or isinstance(template_name, pathlib.PurePath): + for template_uri in repo_json_data['templates']: + template_uri = f'{template_uri}/template.json' + template_sha256 = hashlib.sha256(template_uri.encode()) + template_cache_file = cache_folder / str(template_sha256.hexdigest() + '.json') + if template_cache_file.is_file(): + with template_cache_file.open('r') as f: + try: + template_json_data = json.load(f) + except Exception as e: + logger.warn(f'{template_cache_file} failed to load: {str(e)}') + else: + if template_json_data['template_name'] == template_name: + return template_json_data + + elif isinstance(restricted_name, str) or isinstance(restricted_name, pathlib.PurePath): + for restricted_uri in repo_json_data['restricted']: + restricted_uri = f'{restricted_uri}/restricted.json' + restricted_sha256 = hashlib.sha256(restricted_uri.encode()) + restricted_cache_file = cache_folder / str(restricted_sha256.hexdigest() + '.json') + if restricted_cache_file.is_file(): + with restricted_cache_file.open('r') as f: + try: + restricted_json_data = json.load(f) + except Exception as e: + logger.warn(f'{restricted_cache_file} failed to load: {str(e)}') + else: + if restricted_json_data['restricted_name'] == restricted_name: + return restricted_json_data + # recurse + else: + for repo_repo_uri in repo_json_data['repos']: + if repo_repo_uri not in repo_set: + repo_set.add(repo_repo_uri) + repo_repo_uri = f'{repo_repo_uri}/repo.json' + repo_repo_sha256 = hashlib.sha256(repo_repo_uri.encode()) + repo_repo_cache_file = cache_folder / str(repo_repo_sha256.hexdigest() + '.json') + if repo_repo_cache_file.is_file(): + with repo_repo_cache_file.open('r') as f: + try: + repo_repo_json_data = json.load(f) + except Exception as e: + logger.warn(f'{repo_repo_cache_file} failed to load: {str(e)}') + else: + item = search_repo(repo_set, + repo_repo_json_data, + engine_name, + project_name, + gem_name, + template_name) + if item: + return item + return None + diff --git a/scripts/o3de/o3de/sha256.py b/scripts/o3de/o3de/sha256.py new file mode 100644 index 0000000000..bc35919c4e --- /dev/null +++ b/scripts/o3de/o3de/sha256.py @@ -0,0 +1,82 @@ +# +# 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 hashlib + +from o3de import utils + +logger = logging.getLogger() +logging.basicConfig() + + +def sha256(file_path: str or pathlib.Path, + json_path: str or pathlib.Path = None) -> int: + if not file_path: + logger.error(f'File path cannot be empty.') + return 1 + file_path = pathlib.Path(file_path).resolve() + if not file_path.is_file(): + logger.error(f'File path {file_path} does not exist.') + return 1 + + if json_path: + json_path = pathlib.Path(json_path).resolve() + if not json_path.is_file(): + logger.error(f'Json path {json_path} does not exist.') + return 1 + + sha256 = hashlib.sha256(file_path.open('rb').read()).hexdigest() + + if json_path: + with json_path.open('r') as s: + try: + json_data = json.load(s) + except Exception as e: + logger.error(f'Failed to read Json path {json_path}: {str(e)}') + return 1 + json_data.update({"sha256": sha256}) + utils.backup_file(json_path) + with json_path.open('w') as s: + try: + s.write(json.dumps(json_data, indent=4)) + except Exception as e: + logger.error(f'Failed to write Json path {json_path}: {str(e)}') + return 1 + else: + print(sha256) + return 0 + + +def _run_sha256(args: argparse) -> int: + return sha256(args.file_path, + args.json_path) + + +def add_args(parser, subparsers) -> None: + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" + OR + o3de.py can downloadable commands by importing engine_template, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + sha256_subparser = subparsers.add_parser('sha256') + sha256_subparser.add_argument('-f', '--file-path', type=str, required=True, + help='The path to the file you want to sha256.') + sha256_subparser.add_argument('-j', '--json-path', type=str, required=False, + help='optional path to an o3de json file to add the "sha256" element to.') + sha256_subparser.set_defaults(func=_run_sha256) diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 37c84ea331..50a9e5d6dd 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -45,3 +45,28 @@ def validate_uuid4(uuid_string: str) -> bool: except ValueError: return False return str(val) == uuid_string + +def backup_file(file_name: str or pathlib.Path) -> None: + index = 0 + renamed = False + while not renamed: + backup_file_name = pathlib.Path(str(file_name) + '.bak' + str(index)).resolve() + index += 1 + if not backup_file_name.is_file(): + file_name = pathlib.Path(file_name).resolve() + file_name.rename(backup_file_name) + if backup_file_name.is_file(): + renamed = True + + +def backup_folder(folder: str or pathlib.Path) -> None: + index = 0 + renamed = False + while not renamed: + backup_folder_name = pathlib.Path(str(folder) + '.bak' + str(index)).resolve() + index += 1 + if not backup_folder_name.is_dir(): + folder = pathlib.Path(folder).resolve() + folder.rename(backup_folder_name) + if backup_folder_name.is_dir(): + renamed = True \ No newline at end of file diff --git a/scripts/o3de/o3de/validation.py b/scripts/o3de/o3de/validation.py new file mode 100644 index 0000000000..56839fe056 --- /dev/null +++ b/scripts/o3de/o3de/validation.py @@ -0,0 +1,103 @@ +# +# 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. +# +""" +This file contains functions for querying paths from ~/.o3de directory +""" +import json +import pathlib + +def valid_o3de_repo_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): + return False + + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['repo_name'] + test = json_data['origin'] + except Exception as e: + return False + + return True + + +def valid_o3de_engine_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): + return False + + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['engine_name'] + # test = json_data['origin'] # will be required soon + except Exception as e: + return False + return True + + +def valid_o3de_project_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): + return False + + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['project_name'] + # test = json_data['origin'] # will be required soon + except Exception as e: + return False + return True + + +def valid_o3de_gem_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): + return False + + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['gem_name'] + # test = json_data['origin'] # will be required soon + except Exception as e: + return False + return True + + +def valid_o3de_template_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): + return False + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['template_name'] + # test = json_data['origin'] # will be required soon + except Exception as e: + return False + return True + + +def valid_o3de_restricted_json(file_name: str or pathlib.Path) -> bool: + file_name = pathlib.Path(file_name).resolve() + if not file_name.is_file(): + return False + with file_name.open('r') as f: + try: + json_data = json.load(f) + test = json_data['restricted_name'] + # test = json_data['origin'] # will be required soon + except Exception as e: + return False + return True diff --git a/scripts/o3de/tests/unit_test_add_remove_gem.py b/scripts/o3de/tests/unit_test_add_remove_gem.py index 81f0fa615e..cc793bf32b 100755 --- a/scripts/o3de/tests/unit_test_add_remove_gem.py +++ b/scripts/o3de/tests/unit_test_add_remove_gem.py @@ -12,7 +12,7 @@ import os import pytest -from . import add_remove_gem +from o3de import add_gem_project TEST_WITHOUT_NO_GEM_CONTENT = """ # {BEGIN_LICENSE} @@ -105,7 +105,7 @@ def test_add_gem_dependency(tmpdir, contents, gem, expected_result, runtime_pres with open(runtime_dependencies_cmake_file, 'a') as s: s.write(contents) - result = add_remove_gem.add_gem_dependency(runtime_dependencies_cmake_file, gem) + result = add_gem_project.add_gem_dependency(runtime_dependencies_cmake_file, gem) if expect_failure: assert result != 0 diff --git a/scripts/o3de/tests/unit_test_registration.py b/scripts/o3de/tests/unit_test_registration.py index 31a2dcb2f0..a0abb6cacd 100644 --- a/scripts/o3de/tests/unit_test_registration.py +++ b/scripts/o3de/tests/unit_test_registration.py @@ -16,7 +16,7 @@ import pytest import pathlib from unittest.mock import patch -from .. import registration +from o3de import register string_manifest_data = '{}' @@ -38,7 +38,7 @@ def test_register_engine_path(engine_path, engine_name, force, expected_result): subparser = parser.add_subparsers(help='sub-command help') # Register the registration script subparsers with the current argument parser - registration.add_args(parser, subparser) + register.add_args(parser, subparser) arg_list = ['register', '--engine-path', str(engine_path)] if force: arg_list += ['--force'] @@ -56,11 +56,11 @@ def test_register_engine_path(engine_path, engine_name, force, expected_result): string_manifest_data = json.dumps(manifest_json) engine_json_data = {'engine_name': engine_name} - with patch('o3de.registration.load_o3de_manifest', side_effect=load_manifest_from_string) as load_manifest_mock, \ - patch('o3de.registration.save_o3de_manifest', side_effect=save_manifest_to_string) as save_manifest_mock, \ - patch('o3de.registration.get_engine_data', return_value=engine_json_data) as engine_paths_mock, \ - patch('o3de.registration.valid_o3de_engine_json', return_value=True) as valid_engine_mock, \ + with patch('o3de.manifest.load_o3de_manifest', side_effect=load_manifest_from_string) as load_manifest_mock, \ + patch('o3de.manifest.save_o3de_manifest', side_effect=save_manifest_to_string) as save_manifest_mock, \ + patch('o3de.manifest.get_engine_json_data', return_value=engine_json_data) as engine_paths_mock, \ + patch('o3de.validation.valid_o3de_engine_json', return_value=True) as valid_engine_mock, \ patch('pathlib.Path.is_dir', return_value=True) as pathlib_is_dir_mock: - result = registration._run_register(args) + result = register._run_register(args) assert result == expected_result From 470fde461f3dcbb3bd3c1cfee3b84c247d73b7fb Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 May 2021 02:04:07 -0500 Subject: [PATCH 068/140] Removed engine registration from the Jenkins build scripts which builds the Engine in an engine centric manner --- .../build/Platform/Android/build_config.json | 12 ++++----- .../build/Platform/Linux/build_config.json | 22 ++++++++-------- scripts/build/Platform/Mac/build_config.json | 16 ++++++------ .../build/Platform/Windows/build_config.json | 26 +++++++++---------- .../Windows/package_build_config.json | 4 +-- scripts/build/Platform/iOS/build_config.json | 8 +++--- 6 files changed, 44 insertions(+), 44 deletions(-) diff --git a/scripts/build/Platform/Android/build_config.json b/scripts/build/Platform/Android/build_config.json index d0fce80964..699ccdf20a 100644 --- a/scripts/build/Platform/Android/build_config.json +++ b/scripts/build/Platform/Android/build_config.json @@ -35,7 +35,7 @@ "PARAMETERS": { "CONFIGURATION":"debug", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -60,7 +60,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -76,7 +76,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=FALSE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=FALSE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -93,7 +93,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\windows_vs2019", - "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"AssetProcessorBatch", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -112,7 +112,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -128,7 +128,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\mono_android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_ABI=arm64-v8a -DANDROID_ARM_MODE=arm -DANDROID_ARM_NEON=FALSE -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_3RDPARTY_PATH!\\android-ndk\\r21d\" -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" diff --git a/scripts/build/Platform/Linux/build_config.json b/scripts/build/Platform/Linux/build_config.json index bbfc3e4269..4ae4c4ec0b 100644 --- a/scripts/build/Platform/Linux/build_config.json +++ b/scripts/build/Platform/Linux/build_config.json @@ -37,7 +37,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -53,7 +53,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -66,7 +66,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -80,7 +80,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all", "CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest" @@ -92,7 +92,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all", "CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest" @@ -108,7 +108,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -122,7 +122,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -140,7 +140,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CTEST_OPTIONS": "-L \"(SUITE_periodic)\"" @@ -156,7 +156,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CTEST_OPTIONS": "-L \"(SUITE_benchmark)\"" @@ -172,7 +172,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } @@ -187,7 +187,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mono_linux", - "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "all" } diff --git a/scripts/build/Platform/Mac/build_config.json b/scripts/build/Platform/Mac/build_config.json index f312279fe6..1e6ca79d8e 100644 --- a/scripts/build/Platform/Mac/build_config.json +++ b/scripts/build/Platform/Mac/build_config.json @@ -37,7 +37,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -51,7 +51,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -66,7 +66,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=FALSE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -81,7 +81,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", @@ -99,7 +99,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CTEST_OPTIONS": "-L \"(SUITE_periodic)\"" @@ -115,7 +115,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CTEST_OPTIONS": "-L \"(SUITE_benchmark)\"" @@ -131,7 +131,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } @@ -146,7 +146,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/mono_mac", - "CMAKE_OPTIONS": "-G Xcode -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD" } diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index ee34bae3e3..d3adf69f43 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -87,7 +87,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -101,7 +101,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_BUILD_WITH_INCREMENTAL_LINKING_DEBUG=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -119,7 +119,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -135,7 +135,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=FALSE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -150,7 +150,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -171,7 +171,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -190,7 +190,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "AssetProcessorBatch", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -209,7 +209,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_periodic", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -231,7 +231,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_sandbox", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -250,7 +250,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_benchmark", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo", @@ -269,7 +269,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -285,7 +285,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build\\mono_windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_MONOLITHIC_GAME=TRUE -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -300,7 +300,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DCMAKE_INSTALL_PREFIX=install -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DCMAKE_INSTALL_PREFIX=install", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "INSTALL", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/build/Platform/Windows/package_build_config.json b/scripts/build/Platform/Windows/package_build_config.json index 40f479a098..a5ca861377 100644 --- a/scripts/build/Platform/Windows/package_build_config.json +++ b/scripts/build/Platform/Windows/package_build_config.json @@ -4,7 +4,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "windows_vs2017", - "CMAKE_OPTIONS": "-G \"Visual Studio 15 2017\" -A x64 -T host=x64 -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G \"Visual Studio 15 2017\" -A x64 -T host=x64 -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AtomTest;AtomSampleViewer", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m:4 /p:CL_MPCount=!HALF_PROCESSORS! /nologo" @@ -15,7 +15,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"windows_vs2019", - "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"!WORKSPACE!/home\" -DO3DE_REGISTER_ENGINE_PATH=\"!WORKSPACE!/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS":"-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS":"AtomTest;AtomSampleViewer", "CMAKE_TARGET":"ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" diff --git a/scripts/build/Platform/iOS/build_config.json b/scripts/build/Platform/iOS/build_config.json index bb5f2d2fe6..75b5e7b10d 100644 --- a/scripts/build/Platform/iOS/build_config.json +++ b/scripts/build/Platform/iOS/build_config.json @@ -27,7 +27,7 @@ "PARAMETERS": { "CONFIGURATION": "debug", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -44,7 +44,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -60,7 +60,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=FALSE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=FALSE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" @@ -94,7 +94,7 @@ "PARAMETERS": { "CONFIGURATION": "release", "OUTPUT_DIRECTORY": "build/ios", - "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE", + "CMAKE_OPTIONS": "-G Xcode -DCMAKE_TOOLCHAIN_FILE=cmake/Platform/iOS/Toolchain_ios.cmake -DLY_MONOLITHIC_GAME=TRUE -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=FALSE -DLY_IOS_CODE_SIGNING_IDENTITY=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS=\"\" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=FALSE -DLY_UNITY_BUILD=TRUE", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "-destination generic/platform=iOS" From e818bfe905427477816b0acf48d778bbc139f31a Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 May 2021 02:39:50 -0500 Subject: [PATCH 069/140] Updating the ProjectManager code to use the new location of the o3de python scripts --- .../ProjectManager/Source/GemCatalog/GemInfo.cpp | 2 +- Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h | 1 - Code/Tools/ProjectManager/Source/PythonBindings.cpp | 11 +++++------ 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp index 7ba4021205..d4c7220d45 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp @@ -25,7 +25,7 @@ namespace O3DE::ProjectManager bool GemInfo::IsValid() const { - return !m_path.isEmpty() && !m_uuid.IsNull(); + return !m_path.isEmpty(); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h index 098b67dbf5..e6344ce5f8 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h @@ -43,7 +43,6 @@ namespace O3DE::ProjectManager QString m_path; QString m_name; QString m_displayName; - AZ::Uuid m_uuid; QString m_creator; bool m_isAdded = false; //! Is the gem currently added and enabled in the project? QString m_summary; diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index bc154ea059..2dd6f91d23 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -112,7 +112,7 @@ namespace O3DE::ProjectManager AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed"); // import required modules - m_registration = pybind11::module::import("o3de.registration"); + m_registration = pybind11::module::import("o3de.manifest"); return result == 0 && !PyErr_Occurred(); } catch ([[maybe_unused]] const std::exception& e) @@ -227,14 +227,13 @@ namespace O3DE::ProjectManager GemInfo gemInfo; gemInfo.m_path = Py_To_String(path); - auto data = m_registration.attr("get_gem_data")(pybind11::none(), path); + auto data = m_registration.attr("get_gem_json_data")(pybind11::none(), path); if (pybind11::isinstance(data)) { try { // required - gemInfo.m_name = Py_To_String(data["Name"]); - gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"])); + gemInfo.m_name = Py_To_String(data["gem_name"]); // optional gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name); @@ -270,7 +269,7 @@ namespace O3DE::ProjectManager ProjectInfo projectInfo; projectInfo.m_path = Py_To_String(path); - auto projectData = m_registration.attr("get_project_data")(pybind11::none(), path); + auto projectData = m_registration.attr("get_project_json_data")(pybind11::none(), path); if (pybind11::isinstance(projectData)) { try @@ -327,7 +326,7 @@ namespace O3DE::ProjectManager ProjectTemplateInfo templateInfo; templateInfo.m_path = Py_To_String(path); - auto data = m_registration.attr("get_template_data")(pybind11::none(), path); + auto data = m_registration.attr("get_template_json_data")(pybind11::none(), path); if (pybind11::isinstance(data)) { try From c90d4467351d4affd235b702f2a0c2ccc5b88e45 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 May 2021 02:49:09 -0500 Subject: [PATCH 070/140] Removing the o3de_manifest.cmake file Removed the EngineFinder.cmake file from the Engine cmake directory as it is only needed in a Project Added an EngineJson.cmake which reads the "external_subdirectories" list from the engine.json file and calls add_subdirectory on it Re-ordered the population of the generated gem dependency list to prepend the dependencies before the dependent targets --- CMakeLists.txt | 30 +- cmake/EngineFinder.cmake | 52 -- cmake/EngineJson.cmake | 45 ++ cmake/PAL.cmake | 138 +++-- cmake/SettingsRegistry.cmake | 4 +- cmake/cmake_files.cmake | 5 +- cmake/o3de_manifest.cmake | 970 ----------------------------------- 7 files changed, 164 insertions(+), 1080 deletions(-) delete mode 100644 cmake/EngineFinder.cmake create mode 100644 cmake/EngineJson.cmake delete mode 100644 cmake/o3de_manifest.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 50670c0b85..d743a8ab57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,10 +25,6 @@ include(cmake/LySet.cmake) include(cmake/Version.cmake) include(cmake/OutputDirectory.cmake) -# Set the engine_path and engine_json -set(o3de_engine_path ${CMAKE_CURRENT_LIST_DIR}) -set(o3de_engine_json ${o3de_engine_path}/engine.json) - if(NOT PROJECT_NAME) project(O3DE LANGUAGES C CXX @@ -36,21 +32,6 @@ if(NOT PROJECT_NAME) ) endif() -################################################################################ -# Resolve this engines name and restricted path -################################################################################ -include(cmake/o3de_manifest.cmake) -o3de_engine_name(${o3de_engine_json} o3de_engine_name) -o3de_restricted_path(${o3de_engine_json} o3de_engine_restricted_path) -message(STATUS "O3DE Engine Name: ${o3de_engine_name}") -message(STATUS "O3DE Engine Path: ${o3de_engine_path}") -if(o3de_engine_restricted_path) - message(STATUS "O3DE Engine Restricted Path: ${o3de_engine_restricted_path}") -endif() - -# add the engines cmake folder to the CMAKE_MODULE_PATH -list(APPEND CMAKE_MODULE_PATH "${o3de_engine_path}/cmake") - ################################################################################ # Initialize ################################################################################ @@ -92,12 +73,11 @@ if(NOT INSTALLED_ENGINE) add_subdirectory(Tools/RemoteConsole/ly_remote_console/tests/) endif() - # Add any engine restricted platforms as external subdirs - o3de_add_engine_restricted_platform_external_subdirs() - - # Add external subdirectories listed in the manifest. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra + include(cmake/EngineJson.cmake) + # Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra # external subdirectories - list(APPEND LY_EXTERNAL_SUBDIRS ${o3de_engine_external_subdirectories}) + read_engine_external_subdirs(engine_external_subdirectories) + list(APPEND LY_EXTERNAL_SUBDIRS ${engine_external_subdirectories}) # Loop over the additional external subdirectories and invoke add_subdirectory on them foreach(external_directory ${LY_EXTERNAL_SUBDIRS}) @@ -111,7 +91,7 @@ if(NOT INSTALLED_ENGINE) string(SUBSTRING ${full_directory_hash} 0 8 full_directory_hash) # Use the last directory as the suffix path to use for the Binary Directory get_filename_component(directory_name ${external_directory} NAME) - add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/${directory_name}-${full_directory_hash}) + add_subdirectory(${external_directory} ${CMAKE_BINARY_DIR}/External/${directory_name}-${full_directory_hash}) endforeach() else() diff --git a/cmake/EngineFinder.cmake b/cmake/EngineFinder.cmake deleted file mode 100644 index 9ff8ce4d66..0000000000 --- a/cmake/EngineFinder.cmake +++ /dev/null @@ -1,52 +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. -# -# This file is copied during engine registration. Edits to this file will be lost next -# time a registration happens. - -include_guard() - -# Read the engine name from the project_json file -file(READ ${CMAKE_CURRENT_LIST_DIR}/project.json project_json) -string(JSON LY_ENGINE_NAME_TO_USE ERROR_VARIABLE json_error GET ${project_json} engine) -if(json_error) - message(FATAL_ERROR "Unable to read key 'engine' from 'project.json', error: ${json_error}") -endif() - -# Read the list of paths from ~.o3de/o3de_manifest.json -file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_directory) # Windows -if((NOT home_directory) OR (NOT EXISTS ${home_directory})) - file(TO_CMAKE_PATH "$ENV{HOME}" home_directory)# Unix -endif() - -if (NOT home_directory) - message(FATAL_ERROR "Cannot find user home directory, the o3de manifest cannot be found") -endif() -# Set manifest path to path in the user home directory -set(manifest_path ${home_directory}/.o3de/o3de_manifest.json) - -if(EXISTS ${manifest_path}) - file(READ ${manifest_path} manifest_json) - string(JSON engines_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines) - if(json_error) - message(FATAL_ERROR "Unable to read key 'engines' from '${manifest_path}', error: ${json_error}") - endif() - - math(EXPR engines_count "${engines_count}-1") - foreach(engine_path_index RANGE ${engines_count}) - string(JSON engine_path ERROR_VARIABLE json_error GET ${manifest_json} engines ${engine_path_index}) - if(${json_error}) - message(FATAL_ERROR "Unable to read engines[${engine_path_index}] '${manifest_path}', error: ${json_error}") - endif() - if(engine_path) - list(APPEND CMAKE_MODULE_PATH "${engine_path}/cmake") - endif() - endforeach() -endif() diff --git a/cmake/EngineJson.cmake b/cmake/EngineJson.cmake new file mode 100644 index 0000000000..9a82d4a2c5 --- /dev/null +++ b/cmake/EngineJson.cmake @@ -0,0 +1,45 @@ +# +# 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. +# +# This file is copied during engine registration. Edits to this file will be lost next +# time a registration happens. + +include_guard() + +#! read_engine_external_subdirs +# Read the external subdirectories from the engine.json file +# External subdirectories are any folders with CMakeLists.txt in them +# This could be regular subdirectories, Gems(contains an additional gem.json), +# Restricted folders(contains an additional restricted.json), etc... +# \arg:output_external_subdirs name of output variable to store external subdirectories into +function(read_engine_external_subdirs output_external_subdirs) + file(READ ${LY_ROOT_FOLDER}/engine.json engine_json_data) + string(JSON external_subdirs_count ERROR_VARIABLE engine_json_error + LENGTH ${engine_json_data} "external_subdirectories") + if(engine_json_error) + message(FATAL_ERROR "Error querying number of elements in JSON array \"external_subdirectories\": ${engine_json_error}") + endif() + + if(external_subdirs_count GREATER 0) + math(EXPR external_subdir_range "${external_subdirs_count}-1") + # Convert the paths the relative paths to absolute paths using the engine root + # as the base directory + foreach(external_subdir_index RANGE ${external_subdir_range}) + string(JSON external_subdir ERROR_VARIABLE engine_json_error + GET ${engine_json_data} "external_subdirectories" "${external_subdir_index}") + if(engine_json_error) + message(FATAL_ERROR "Error reading field at index ${external_subdir_index} in \"external_subdirectories\" JSON array: ${engine_json_error}") + endif() + file(REAL_PATH ${external_subdir} real_external_subdir BASE_DIRECTORY ${CMAKE_SOURCE_DIR}) + list(APPEND external_subdirs ${real_external_subdir}) + endforeach() + endif() + set(${output_external_subdirs} ${external_subdirs} PARENT_SCOPE) +endfunction() diff --git a/cmake/PAL.cmake b/cmake/PAL.cmake index 7802ac8c58..e10ef758da 100644 --- a/cmake/PAL.cmake +++ b/cmake/PAL.cmake @@ -22,7 +22,107 @@ file(GLOB detection_files "cmake/Platform/*/PALDetection_*.cmake") foreach(detection_file ${detection_files}) include(${detection_file}) endforeach() -file(GLOB detection_files ${o3de_engine_restricted_path}/*/cmake/PALDetection_*.cmake) + + +#! o3de_restricted_id: Reads the "restricted" key from the o3de manifest +# +# \arg:restricted returns the restricted association element from an o3de json, otherwise engine 'o3de' is assumed +# \arg:o3de_json_file name of the o3de json file +function(o3de_restricted_id o3de_json_file restricted) + file(READ ${o3de_json_file} json_data) + string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} "restricted_name") + if(json_error) + message(WARNING "Unable to read restricted from '${o3de_json_file}', error: ${json_error}") + message(WARNING "Setting restricted to engine default 'o3de'") + set(restricted_entry "o3de") + endif() + if(restricted_entry) + set(${restricted} ${restricted_entry} PARENT_SCOPE) + endif() +endfunction() + +#! o3de_find_restricted_folder: +# +# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name +# \arg:restricted_name name of the restricted +function(o3de_find_restricted_folder restricted_name restricted_path) + # Read the restricted path from engine.json if one EXISTS + file(READ ${LY_ROOT_FOLDER}/engine.json engine_json_data) + string(JSON restricted_subdirs_count ERROR_VARIABLE engine_json_error LENGTH ${engine_json_data} "restricted") + if(restricted_subdirs_count GREATER 0) + string(JSON restricted_subdir ERROR_VARIABLE engine_json_error GET ${engine_json_data} "restricted" "0") + set(${restricted_path} ${restricted_subdir} PARENT_SCOPE) + return() + endif() + + + file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_directory) # Windows + if(NOT EXISTS ${home_directory}) + file(TO_CMAKE_PATH "$ENV{HOME}" home_directory) # Unix + if (NOT EXISTS ${home_directory}) + return() + endif() + endif() + + # Examine the o3de manifest file for the list of restricted directories + set(o3de_manifest_path ${home_directory}/.o3de/o3de_manifest.json) + if(EXISTS ${o3de_manifest_path}) + file(READ ${o3de_manifest_path} o3de_manifest_json_data) + string(JSON restricted_subdirs_count ERROR_VARIABLE engine_json_error LENGTH ${o3de_manifest_json_data} "restricted") + if(restricted_subdirs_count GREATER 0) + math(EXPR restricted_subdirs_range "${restricted_subdirs_count}-1") + foreach(restricted_subdir_index RANGE ${restricted_subdirs_range}) + string(JSON restricted_subdir ERROR_VARIABLE engine_json_error GET ${o3de_manifest_json_data} "restricted" "${restricted_subdir_index}") + list(APPEND restricted_subdirs ${restricted_subdir}) + endforeach() + endif() + endif() + # Iterate over the restricted directories from the manifest file + foreach(restricted_entry ${restricted_subdirs}) + set(restricted_json_file ${restricted_entry}/restricted.json) + file(READ ${restricted_json_file} restricted_json) + string(JSON this_restricted_name ERROR_VARIABLE json_error GET ${restricted_json} "restricted_name") + if(json_error) + message(WARNING "Unable to read restricted_name from '${restricted_json_file}', error: ${json_error}") + else() + if(this_restricted_name STREQUAL restricted_name) + set(${restricted_path} ${restricted_entry} PARENT_SCOPE) + return() + endif() + endif() + endforeach() +endfunction() + + +#! o3de_restricted_path: +# +# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name +# \arg:restricted_name name of the restricted +function(o3de_restricted_path o3de_json_file restricted_path) + o3de_restricted_id(${o3de_json_file} restricted_name) + if(restricted_name) + o3de_find_restricted_folder(${restricted_name} restricted_folder) + if(restricted_folder) + set(${restricted_path} ${restricted_folder} PARENT_SCOPE) + endif() + endif() +endfunction() + +#! read_engine_restricted_path: Locates the restricted path within the engine from a json file +# +# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name +# \arg:restricted_name name of the restricted +function(read_engine_restricted_path output_restricted_path) + # Set manifest path to path in the user home directory + set(manifest_path ${LY_ROOT_FOLDER}/engine.json) + if(EXISTS ${manifest_path}) + o3de_restricted_path(${manifest_path} output_restricted_path) + endif() +endfunction() + +read_engine_restricted_path(O3DE_ENGINE_RESTRICTED_PATH) + +file(GLOB detection_files ${O3DE_ENGINE_RESTRICTED_PATH}/*/cmake/PALDetection_*.cmake) foreach(detection_file ${detection_files}) include(${detection_file}) endforeach() @@ -37,8 +137,8 @@ ly_set(PAL_HOST_PLATFORM_NAME_LOWERCASE ${PAL_HOST_PLATFORM_NAME_LOWERCASE}) set(PAL_RESTRICTED_PLATFORMS) -string(LENGTH ${o3de_engine_restricted_path} engine_restricted_length) -file(GLOB pal_restricted_files ${o3de_engine_restricted_path}/*/cmake/PAL_*.cmake) +string(LENGTH "${O3DE_ENGINE_RESTRICTED_PATH}" engine_restricted_length) +file(GLOB pal_restricted_files ${O3DE_ENGINE_RESTRICTED_PATH}/*/cmake/PAL_*.cmake) foreach(pal_restricted_file ${pal_restricted_files}) string(FIND ${pal_restricted_file} "/cmake/PAL" end) if(${end} GREATER -1) @@ -109,18 +209,18 @@ function(ly_get_absolute_pal_filename out_name in_name) else() # The user has not supplied any path so we must assume it is the o3de engine restricted and o3de engine path # if the file is not in the o3de engine path then we cannot determine a PAL file for it - file(RELATIVE_PATH relative_path ${o3de_engine_path} ${full_name}) + file(RELATIVE_PATH relative_path ${LY_ROOT_FOLDER} ${full_name}) if (NOT (IS_ABSOLUTE relative_path OR relative_path MATCHES [[^(\.\./)+(.*)]])) if (NOT EXISTS ${full_name}) - string(REGEX MATCH "${o3de_engine_path}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) + string(REGEX MATCH "${LY_ROOT_FOLDER}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) if(NOT CMAKE_MATCH_1) - string(REGEX MATCH "${o3de_engine_path}/Platform/([^/]*)/?(.*)$" match ${full_name}) - set(full_name ${o3de_engine_restricted_path}/${CMAKE_MATCH_1}) + string(REGEX MATCH "${LY_ROOT_FOLDER}/Platform/([^/]*)/?(.*)$" match ${full_name}) + set(full_name ${O3DE_ENGINE_RESTRICTED_PATH}/${CMAKE_MATCH_1}) if(CMAKE_MATCH_2) string(APPEND full_name "/" ${CMAKE_MATCH_2}) endif() elseif("${CMAKE_MATCH_2}" IN_LIST PAL_RESTRICTED_PLATFORMS) - set(full_name ${o3de_engine_restricted_path}/${CMAKE_MATCH_2}/${CMAKE_MATCH_1}) + set(full_name ${O3DE_ENGINE_RESTRICTED_PATH}/${CMAKE_MATCH_2}/${CMAKE_MATCH_1}) if(CMAKE_MATCH_3) string(APPEND full_name "/" ${CMAKE_MATCH_3}) endif() @@ -149,25 +249,3 @@ set(LY_DISABLE_TEST_MODULES FALSE CACHE BOOL "Option to forcibly disable the inc if(LY_DISABLE_TEST_MODULES) ly_set(PAL_TRAIT_BUILD_TESTS_SUPPORTED FALSE) endif() - -################################################################################ -# Add each restricted platform in the engines restricted folder -# If the enabled restricted platform does not have a folder add one. -# If the restricted platform folder does not have a CMakeLists.txt, create one -# so the add_subdirectory on the external folder does not fail. -################################################################################ -function(o3de_add_engine_restricted_platform_external_subdirs) - foreach(restricted_platform ${PAL_RESTRICTED_PLATFORMS}) - if(restricted_platform IN_LIST enabled_platforms) - set(o3de_engine_restricted_platform_folder ${o3de_engine_restricted_path}/${restricted_platform}) - if(NOT EXISTS ${o3de_engine_restricted_platform_folder}) - file(MAKE_DIRECTORY ${o3de_engine_restricted_platform_folder}) - endif() - set(o3de_engine_restricted_platform_folder_cmakelists ${o3de_engine_restricted_platform_folder}/CMakeLists.txt) - if(NOT EXISTS ${o3de_engine_restricted_platform_folder_cmakelists}) - file(TOUCH ${o3de_engine_restricted_platform_folder_cmakelists}) - endif() - list(APPEND LY_EXTERNAL_SUBDIRS ${o3de_engine_restricted_platform_folder}) - endif() - endforeach() -endfunction() diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index 31ce36c516..dda498eeb4 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -108,11 +108,11 @@ function(ly_delayed_generate_settings_registry) # Get the gem dependencies for the given project and target combination get_property(gem_dependencies GLOBAL PROPERTY LY_DELAYED_LOAD_"${prefix_target}") list(REMOVE_DUPLICATES gem_dependencies) # Strip out any duplicate gem targets - set(all_gem_dependencies ${gem_dependencies}) + unset(all_gem_dependencies) foreach(gem_target ${gem_dependencies}) ly_get_gem_load_dependencies(gem_load_gem_dependencies ${gem_target}) - list(APPEND all_gem_dependencies ${gem_load_gem_dependencies}) + list(APPEND all_gem_dependencies ${gem_load_gem_dependencies} ${gem_target}) endforeach() list(REMOVE_DUPLICATES all_gem_dependencies) diff --git a/cmake/cmake_files.cmake b/cmake/cmake_files.cmake index baa2a272fc..b42d29c9c2 100644 --- a/cmake/cmake_files.cmake +++ b/cmake/cmake_files.cmake @@ -17,16 +17,19 @@ set(FILES Configurations.cmake Dependencies.cmake Deployment.cmake - EngineFinder.cmake + EngineJson.cmake FileUtil.cmake Findo3de.cmake + GeneralSettings.cmake Install.cmake LyAutoGen.cmake + LYPackage_S3Downloader.cmake LySet.cmake LYTestWrappers.cmake LYPython.cmake LYWrappers.cmake Monolithic.cmake + OutputDirectory.cmake Packaging.cmake PAL.cmake PALTools.cmake diff --git a/cmake/o3de_manifest.cmake b/cmake/o3de_manifest.cmake deleted file mode 100644 index 632f064659..0000000000 --- a/cmake/o3de_manifest.cmake +++ /dev/null @@ -1,970 +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. -# - -# Set the user home directory -set(O3DE_HOME_PATH "" CACHE PATH "Override the user home to this path") -if(O3DE_HOME_PATH) - set(home_directory ${O3DE_HOME_PATH}) -elseif(CMAKE_HOST_WIN32) - file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_directory) -else() - file(TO_CMAKE_PATH "$ENV{HOME}" home_directory) -endif() -if (NOT home_directory) - message(FATAL_ERROR "Cannot find user home directory, without the user home directory the o3de manifest cannot be found") -endif() - -# Optionally delete the home directory -if(O3DE_DELETE_HOME_PATH) - if(EXISTS ${home_directory}/.o3de) - message(STATUS "Deleting ${home_directory}/.o3de") - file(REMOVE_RECURSE ${home_directory}/.o3de) - else() - message(STATUS "Home path ${home_directory}/.o3de doesnt exist.") - endif() -endif() - -######################################################################################################################## -# If O3DE_REGISTER_ENGINE_PATH variable is set on the commandline this will allow registration of anything using -# O3DE_REGISTER_ENGINE_PATH o3de script. This is handy for situations like build servers which download the code and -# are expected to build without the need for someone to register o3de objects like this engine by manually typing it in. -# If O3DE_REGISTER_THIS_ENGINE=TRUE is set on the commandline when O3DE_REGISTER_ENGINE_PATH is also set this will call: -# O3DE_REGISTER_ENGINE_PATH/scripts>o3de register --this-engine --override-home-folder -# Note: register --this-engine will automatically register anything it finds in known folders, so if you put your -# o3de objects like projects/gems/templates/restricted/etc... in known folders for those types they will get registered -# automatically. Known folders for types are your .o3de/Projects and .o3de/Gems etc. So if I wanted my project to be -# registered and built by this build server I could simply put them in those known folders on the build server and they -# would get registered automatically by this call. -# OR -# I could put them on the commandline as well. This would be the way if the o3de objects we need to regiater are NOT -# in known folders or you do not intend to call with O3DE_REGISTER_THIS_ENGINE=TRUE Ex. -# -DO3DE_REGISTER_ENGINE_PATH=C:\this\engine -# -DO3DE_REGISTER_PROJECT_PATHS=C:\ThisGame;C:\ThatGame -# -DO3DE_REGISTER_GEM_PATHS=C:\ThisGem;C:\ThatGem;C:\And\Some\Other\Gem -# -DO3DE_REGISTER_RESTRICTED_PATHS=C:\this\engine\Restricted;C:\ThisGame\Restricted;C:\ThisGem\Restricted -######################################################################################################################## -if(O3DE_REGISTER_ENGINE_PATH) - if(O3DE_REGISTER_THIS_ENGINE) - if(CMAKE_HOST_WIN32) - execute_process( - COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --this-engine --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_this_engine_cmd_result - ) - else() - execute_process( - COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --this-engine --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_this_engine_cmd_result - ) - endif() - if(o3de_register_this_engine_cmd_result) - message(FATAL_ERROR "An error occured trying to register --this-engine: ${o3de_register_this_engine_cmd_result}") - else() - message(STATUS "Engine ${O3DE_REGISTER_ENGINE_PATH} registration successfull.") - endif() - endif() - - if(O3DE_REGISTER_RESTRICTED_PATHS) - foreach(restricted_path ${O3DE_REGISTER_RESTRICTED_PATHS}) - if(CMAKE_HOST_WIN32) - execute_process( - COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --restricted-path ${restricted_path} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_restricted_cmd_result - ) - else() - execute_process( - COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --restricted-path ${restricted_path} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_restricted_cmd_result - ) - endif() - if(o3de_register_restricted_cmd_result) - message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --restricted-path ${restricted_path} --override-home-folder ${home_directory}: ${o3de_register_restricted_cmd_result}") - else() - message(STATUS "Restricted ${restricted_path} registration successfull.") - endif() - endforeach() - endif() - - if(O3DE_REGISTER_PROJECT_PATHS) - foreach(project_path ${O3DE_REGISTER_PROJECT_PATHS}) - if(CMAKE_HOST_WIN32) - execute_process( - COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --project-path ${project_path} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_project_cmd_result - ) - else() - execute_process( - COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --project-path ${project_path} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_project_cmd_result - ) - endif() - if(o3de_register_project_cmd_result) - message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --project-path ${project_path} --override-home-folder ${home_directory}") - else() - message(STATUS "Project ${project_path} registration successfull.") - endif() - endforeach() - endif() - - if(O3DE_REGISTER_GEM_PATHS) - foreach(gem_path ${O3DE_REGISTER_GEM_PATHS}) - if(CMAKE_HOST_WIN32) - execute_process( - COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --gem-path ${gem_path} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_gem_cmd_result - ) - else() - execute_process( - COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --gem-path ${gem_path} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_gem_cmd_result - ) - endif() - if(o3de_register_gem_cmd_result) - message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --gem-path ${gem_path} --override-home-folder ${home_directory}") - else() - message(STATUS "Gem ${gem_path} registration successfull.") - endif() - endforeach() - endif() - - if(O3DE_REGISTER_TEMPLATE_PATHS) - foreach(template_path ${O3DE_REGISTER_TEMPLATE_PATHS}) - if(CMAKE_HOST_WIN32) - execute_process( - COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --template-path ${template_path} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_template_cmd_result - ) - else() - execute_process( - COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --template-path ${template_path} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_template_cmd_result - ) - endif() - if(o3de_register_template_cmd_result) - message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --template-path ${template_path} --override-home-folder ${home_directory}") - else() - message(STATUS "Template ${template_path} registration successfull.") - endif() - endforeach() - endif() - - if(O3DE_REGISTER_REPO_URIS) - foreach(repo_uri ${O3DE_REGISTER_REPO_URIS}) - if(CMAKE_HOST_WIN32) - execute_process( - COMMAND cmd /c ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.bat register --repo-uri ${repo_uri} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_repo_cmd_result - ) - else() - execute_process( - COMMAND sh ${O3DE_REGISTER_ENGINE_PATH}/scripts/o3de.sh register --repo-uri ${repo_uri} --override-home-folder ${home_directory} - RESULT_VARIABLE o3de_register_repo_cmd_result - ) - endif() - if(o3de_register_repo_cmd_result) - message(FATAL_ERROR "An error occured trying to ${O3DE_REGISTER_ENGINE_PATH}/scripts>o3de register --repo-uri ${repo_uri} --override-home-folder ${home_directory}") - else() - message(STATUS "Repo ${repo_uri} registration successfull.") - endif() - endforeach() - endif() -endif() - -################################################################################ -# o3de manifest -################################################################################ -# Set manifest json path to the /.o3de/o3de_manifest.json -set(o3de_manifest_json_path ${home_directory}/.o3de/o3de_manifest.json) -if(NOT EXISTS ${o3de_manifest_json_path}) - message(FATAL_ERROR "${o3de_manifest_json_path} not found. You must o3de register --this-engine.") -endif() -file(READ ${o3de_manifest_json_path} manifest_json_data) - -################################################################################ -# o3de manifest name -################################################################################ -string(JSON o3de_manifest_name ERROR_VARIABLE json_error GET ${manifest_json_data} o3de_manifest_name) -if(json_error) - message(FATAL_ERROR "Unable to read repo_name from '${o3de_manifest_json_path}', error: ${json_error}") -endif() - -################################################################################ -# o3de origin -################################################################################ -string(JSON o3de_origin ERROR_VARIABLE json_error GET ${manifest_json_data} origin) -if(json_error) - message(FATAL_ERROR "Unable to read origin from '${o3de_manifest_json_path}', error: ${json_error}") -endif() - -################################################################################ -# o3de default engines folder -################################################################################ -string(JSON o3de_default_engines_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_engines_folder) -if(json_error) - message(FATAL_ERROR "Unable to read default_engines_folder from '${o3de_manifest_json_path}', error: ${json_error}") -endif() - -################################################################################ -# o3de default projects folder -################################################################################ -string(JSON o3de_default_projects_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_projects_folder) -if(json_error) - message(FATAL_ERROR "Unable to read default_projects_folder from '${o3de_manifest_json_path}', error: ${json_error}") -endif() - -################################################################################ -# o3de default gems folder -################################################################################ -string(JSON o3de_default_gems_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_gems_folder) -if(json_error) - message(FATAL_ERROR "Unable to read default_gems_folder from '${o3de_manifest_json_path}', error: ${json_error}") -endif() - -################################################################################ -# o3de default templates folder -################################################################################ -string(JSON o3de_default_templates_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_templates_folder) -if(json_error) - message(FATAL_ERROR "Unable to read default_templates_folder from '${o3de_manifest_json_path}', error: ${json_error}") -endif() - -################################################################################ -# o3de default restricted folder -################################################################################ -string(JSON o3de_default_restricted_folder ERROR_VARIABLE json_error GET ${manifest_json_data} default_restricted_folder) -if(json_error) - message(FATAL_ERROR "Unable to read default_restricted_folder from '${o3de_manifest_json_path}', error: ${json_error}") -endif() - -################################################################################ -# o3de projects -################################################################################ -string(JSON o3de_projects_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} projects) -if(json_error) - message(FATAL_ERROR "Unable to read key 'projects' from '${o3de_manifest_json_path}', error: ${json_error}") -endif() -if(${o3de_projects_count} GREATER 0) - math(EXPR o3de_projects_count "${o3de_projects_count}-1") - foreach(projects_index RANGE ${o3de_projects_count}) - string(JSON projects_path ERROR_VARIABLE json_error GET ${manifest_json_data} projects ${projects_index}) - if(json_error) - message(FATAL_ERROR "Unable to read projects[${projects_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_projects ${projects_path}) - list(APPEND o3de_global_projects ${projects_path}) - endforeach() -endif() - -################################################################################ -# o3de gems -################################################################################ -string(JSON o3de_gems_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} gems) -if(json_error) - message(FATAL_ERROR "Unable to read key 'gems' from '${o3de_manifest_json_path}', error: ${json_error}") -endif() -if(${o3de_gems_count} GREATER 0) - math(EXPR o3de_gems_count "${o3de_gems_count}-1") - foreach(gems_index RANGE ${o3de_gems_count}) - string(JSON gems_path ERROR_VARIABLE json_error GET ${manifest_json_data} gems ${gems_index}) - if(json_error) - message(FATAL_ERROR "Unable to read gems[${gems_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_gems ${gems_path}) - list(APPEND o3de_global_gems ${gems_path}) - endforeach() -endif() - -################################################################################ -# o3de templates -################################################################################ -string(JSON o3de_templates_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} templates) -if(json_error) - message(FATAL_ERROR "Unable to read key 'templates' from '${o3de_manifest_json_path}', error: ${json_error}") -endif() -if(${o3de_templates_count} GREATER 0) - math(EXPR o3de_templates_count "${o3de_templates_count}-1") - foreach(templates_index RANGE ${o3de_templates_count}) - string(JSON templates_path ERROR_VARIABLE json_error GET ${manifest_json_data} templates ${templates_index}) - if(json_error) - message(FATAL_ERROR "Unable to read templates[${templates_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_templates ${templates_path}) - list(APPEND o3de_global_templates ${templates_path}) - endforeach() -endif() - -################################################################################ -# o3de repos -################################################################################ -string(JSON o3de_repos_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} repos) -if(json_error) - message(FATAL_ERROR "Unable to read key 'repos' from '${o3de_manifest_json_path}', error: ${json_error}") -endif() -if(${o3de_repos_count} GREATER 0) - math(EXPR o3de_repos_count "${o3de_repos_count}-1") - foreach(repos_index RANGE ${o3de_repos_count}) - string(JSON repo_uri ERROR_VARIABLE json_error GET ${manifest_json_data} repos ${repos_index}) - if(json_error) - message(FATAL_ERROR "Unable to read repos[${repos_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_repos ${repo_uri}) - list(APPEND o3de_global_repos ${repo_uri}) - endforeach() -endif() - -################################################################################ -# o3de restricted -################################################################################ -string(JSON o3de_restricted_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} restricted) -if(json_error) - message(FATAL_ERROR "Unable to read key 'restricted' from '${o3de_manifest_json_path}', error: ${json_error}") -endif() -if(${o3de_restricted_count} GREATER 0) - math(EXPR o3de_restricted_count "${o3de_restricted_count}-1") - foreach(restricted_index RANGE ${o3de_restricted_count}) - string(JSON restricted_path ERROR_VARIABLE json_error GET ${manifest_json_data} restricted ${restricted_index}) - if(json_error) - message(FATAL_ERROR "Unable to read restricted[${restricted_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_restricted ${restricted_path}) - list(APPEND o3de_global_restricted ${restricted_path}) - endforeach() -endif() - -################################################################################ -# o3de engines -################################################################################ -string(JSON o3de_engines_count ERROR_VARIABLE json_error LENGTH ${manifest_json_data} engines) -if(json_error) - message(FATAL_ERROR "Unable to read key 'engines' from '${o3de_manifest_json_path}', error: ${json_error}") -endif() - -if(${o3de_engines_count} GREATER 0) - math(EXPR o3de_engines_count "${o3de_engines_count}-1") - # Either the engine_path and engine_json are set in which case the user is configuring from the engine - # or project_path and project_json are set in which case the user is configuring from the project. - # We need to know which engine_path the user is using so if the project_json is set then we need - # to read the project_json and disambiguate the engine_path. - if(NOT o3de_engine_path) - if(NOT o3de_project_json) - message(FATAL_ERROR "Neither o3de_engine_path nor o3de_project_json defined. Cannot determine engine!") - endif() - - # get the name of the engine this project uses - file(READ ${o3de_project_json} project_json_data) - string(JSON project_engine_name ERROR_VARIABLE json_error GET ${project_json_data} engine) - if(json_error) - message(FATAL_ERROR "Unable to read 'engine' from '${o3de_project_json}', error: ${json_error}") - endif() - - # search each engine in order from the manifest to find the matching engine name - foreach(engines_index RANGE ${o3de_engines_count}) - string(JSON engine_data ERROR_VARIABLE json_error GET ${manifest_json_data} engines ${engines_index}) - if(json_error) - message(FATAL_ERROR "Unable to read engines[${engines_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - - # get this engines path - string(JSON this_engine_path ERROR_VARIABLE json_error GET ${engine_data} path) - if(json_error) - message(FATAL_ERROR "Unable to read engine path from '${o3de_manifest_json_path}', error: ${json_error}") - endif() - - # add this engine to the engines list - list(APPEND o3de_engines ${this_engine_path}) - - # use path to get the engine.json - set(this_engine_json ${this_engine_path}/engine.json) - - # read the name of this engine - file(READ ${this_engine_json} this_engine_json_data) - string(JSON this_engine_name ERROR_VARIABLE json_error GET ${this_engine_json_data} engine_name) - if(json_error) - message(FATAL_ERROR "Unable to read engine_name from '${this_engine_json}', error: ${json_error}") - endif() - - # see if this engines name is the same as the one this projects should use - if(${this_engine_name} STREQUAL ${project_engine_name}) - message(STATUS "Found engine: '${project_engine_name}' at ${this_engine_path}") - set(o3de_engine_path ${this_engine_path}) - break() - endif() - endforeach() - endif() -endif() - -#we should have an engine_path at this point -if(NOT o3de_engine_path) - message(FATAL_ERROR "o3de_engine_path not defined. Cannot determine engine!") -endif() - -# now that we have an engine_path read in that engines o3de resources -if(${o3de_engines_count} GREATER -1) - foreach(engines_index RANGE ${o3de_engines_count}) - string(JSON engine_data ERROR_VARIABLE json_error GET ${manifest_json_data} engines ${engines_index}) - if(json_error) - message(FATAL_ERROR "Unable to read engines[${engines_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - - # get this engines path - string(JSON this_engine_path ERROR_VARIABLE json_error GET ${engine_data} path) - if(json_error) - message(FATAL_ERROR "Unable to read engine path from '${o3de_manifest_json_path}', error: ${json_error}") - endif() - - if(${o3de_engine_path} STREQUAL ${this_engine_path}) - ################################################################################ - # o3de engine projects - ################################################################################ - string(JSON o3de_engine_projects_count ERROR_VARIABLE json_error LENGTH ${engine_data} projects) - if(json_error) - message(FATAL_ERROR "Unable to read key 'projects' from '${engine_data}', error: ${json_error}") - endif() - if(${o3de_engine_projects_count} GREATER 0) - math(EXPR o3de_engine_projects_count "${o3de_engine_projects_count}-1") - foreach(engine_projects_index RANGE ${o3de_engine_projects_count}) - string(JSON engine_projects_path ERROR_VARIABLE json_error GET ${engine_data} projects ${engine_projects_index}) - if(json_error) - message(FATAL_ERROR "Unable to read engine projects[${projects_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_projects ${engine_projects_path}) - list(APPEND o3de_engine_projects ${engine_projects_path}) - endforeach() - endif() - - ################################################################################ - # o3de engine gems - ################################################################################ - string(JSON o3de_engine_gems_count ERROR_VARIABLE json_error LENGTH ${engine_data} gems) - if(json_error) - message(FATAL_ERROR "Unable to read key 'gems' from '${engine_data}', error: ${json_error}") - endif() - if(${o3de_engine_gems_count} GREATER 0) - math(EXPR o3de_engine_gems_count "${o3de_engine_gems_count}-1") - foreach(engine_gems_index RANGE ${o3de_engine_gems_count}) - string(JSON engine_gems_path ERROR_VARIABLE json_error GET ${engine_data} gems ${engine_gems_index}) - if(json_error) - message(FATAL_ERROR "Unable to read engine gems[${gems_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_gems ${engine_gems_path}) - list(APPEND o3de_engine_gems ${engine_gems_path}) - endforeach() - endif() - - ################################################################################ - # o3de engine templates - ################################################################################ - string(JSON o3de_engine_templates_count ERROR_VARIABLE json_error LENGTH ${engine_data} templates) - if(json_error) - message(FATAL_ERROR "Unable to read key 'templates' from '${o3de_manifest_json_path}', error: ${json_error}") - endif() - if(${o3de_engine_gems_count} GREATER 0) - math(EXPR o3de_engine_templates_count "${o3de_engine_templates_count}-1") - foreach(engine_templates_index RANGE ${o3de_engine_templates_count}) - string(JSON engine_templates_path ERROR_VARIABLE json_error GET ${engine_data} templates ${engine_templates_index}) - if(json_error) - message(FATAL_ERROR "Unable to read engine templates[${templates_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_templates ${engine_templates_path}) - list(APPEND o3de_engine_templates ${engine_templates_path}) - endforeach() - endif() - - ################################################################################ - # o3de engine restricted - ################################################################################ - string(JSON o3de_engine_restricted_count ERROR_VARIABLE json_error LENGTH ${engine_data} restricted) - if(json_error) - message(FATAL_ERROR "Unable to read key 'restricted' from '${o3de_manifest_json_path}', error: ${json_error}") - endif() - if(${o3de_engine_restricted_count} GREATER 0) - math(EXPR o3de_engine_restricted_count "${o3de_engine_restricted_count}-1") - foreach(engine_restricted_index RANGE ${o3de_engine_restricted_count}) - string(JSON engine_restricted_path ERROR_VARIABLE json_error GET ${engine_data} restricted ${engine_restricted_index}) - if(json_error) - message(FATAL_ERROR "Unable to read engine restricted[${engine_restricted_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_restricted ${engine_restricted_path}) - list(APPEND o3de_engine_restricted ${engine_restricted_path}) - endforeach() - endif() - - ################################################################################ - # o3de engine external_subdirectories - ################################################################################ - string(JSON o3de_external_subdirectories_count ERROR_VARIABLE json_error LENGTH ${engine_data} external_subdirectories) - if(json_error) - message(FATAL_ERROR "Unable to read key 'external_subdirectories' from '${o3de_manifest_json_path}', error: ${json_error}") - endif() - if(${o3de_external_subdirectories_count} GREATER 0) - math(EXPR o3de_external_subdirectories_count "${o3de_external_subdirectories_count}-1") - foreach(external_subdirectories_index RANGE ${o3de_external_subdirectories_count}) - string(JSON external_subdirectories_path ERROR_VARIABLE json_error GET ${engine_data} external_subdirectories ${external_subdirectories_index}) - if(json_error) - message(FATAL_ERROR "Unable to read engine external_subdirectories[${gems_index}] '${o3de_manifest_json_path}', error: ${json_error}") - endif() - list(APPEND o3de_engine_external_subdirectories ${external_subdirectories_path}) - endforeach() - endif() - - break() - - endif() - endforeach() -endif() - - -################################################################################ -#! o3de_engine_id: -# -# \arg:engine returns the engine association element from an o3de json -# \arg:o3de_json_file name of the o3de json file -################################################################################ -function(o3de_engine_id o3de_json_file engine) - file(READ ${o3de_json_file} json_data) - string(JSON engine_entry ERROR_VARIABLE json_error GET ${json_data} engine) - if(json_error) - message(WARNING "Unable to read engine from '${o3de_json_file}', error: ${json_error}") - message(WARNING "Setting engine to engine default 'o3de'") - set(engine_entry "o3de") - endif() - if(engine_entry) - set(${engine} ${engine_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_project_id: -# -# \arg:project returns the project association element from an o3de json -# \arg:o3de_json_file name of the o3de json file -################################################################################ -function(o3de_project_id o3de_json_file project) - file(READ ${o3de_json_file} json_data) - string(JSON project_entry ERROR_VARIABLE json_error GET ${json_data} project) - if(json_error) - message(FATAL_ERROR "Unable to read project from '${o3de_json_file}', error: ${json_error}") - endif() - if(project_entry) - set(${project} ${project_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_gem_id: -# -# \arg:gem returns the gem association element from an o3de json -# \arg:o3de_json_file name of the o3de json file -################################################################################ -function(o3de_gem_id o3de_json_file gem) - file(READ ${o3de_json_file} json_data) - string(JSON gem_entry ERROR_VARIABLE json_error GET ${json_data} gem) - if(json_error) - message(FATAL_ERROR "Unable to read gem from '${o3de_json_file}', error: ${json_error}") - endif() - if(gem_entry) - set(${gem} ${gem_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_template_id: -# -# \arg:template returns the template association element from an o3de json -# \arg:o3de_json_file name of the o3de json file -################################################################################ -function(o3de_template_id o3de_json_file template) - file(READ ${o3de_json_file} json_data) - string(JSON template_entry ERROR_VARIABLE json_error GET ${json_data} template) - if(json_error) - message(FATAL_ERROR "Unable to read template from '${o3de_json_file}', error: ${json_error}") - endif() - if(template_entry) - set(${template} ${template_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_repo_id: -# -# \arg:repo returns the repo association element from an o3de json -# \arg:o3de_json_file name of the o3de json file -################################################################################ -function(o3de_repo_id o3de_json_file repo) - file(READ ${o3de_json_file} json_data) - string(JSON repo_entry ERROR_VARIABLE json_error GET ${json_data} repo) - if(json_error) - message(FATAL_ERROR "Unable to read repo from '${o3de_json_file}', error: ${json_error}") - endif() - if(repo_entry) - set(${repo} ${repo_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_restricted_id: -# -# \arg:restricted returns the restricted association element from an o3de json, otherwise engine 'o3de' is assumed -# \arg:o3de_json_file name of the o3de json file -################################################################################ -function(o3de_restricted_id o3de_json_file restricted) - file(READ ${o3de_json_file} json_data) - string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} restricted) - if(json_error) - message(WARNING "Unable to read restricted from '${o3de_json_file}', error: ${json_error}") - message(WARNING "Setting restricted to engine default 'o3de'") - set(restricted_entry "o3de") - endif() - if(restricted_entry) - set(${restricted} ${restricted_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_find_engine_folder: -# -# \arg:engine_path returns the path of the o3de engine folder with name engine_name -# \arg:engine_name name of the engine -################################################################################ -function(o3de_find_engine_folder engine_name engine_path) - foreach(engine_entry ${o3de_engines}) - set(engine_json_file ${engine_entry}/engine.json) - file(READ ${engine_json_file} engine_json) - string(JSON this_engine_name ERROR_VARIABLE json_error GET ${engine_json} engine_name) - if(json_error) - message(WARNING "Unable to read engine_name from '${engine_json_file}', error: ${json_error}") - else() - if(this_engine_name STREQUAL engine_name) - set(${engine_path} ${engine_entry} PARENT_SCOPE) - return() - endif() - endif() - endforeach() - message(FATAL_ERROR "Unable to find repo_name: '${engine_name}'") -endfunction() - - -################################################################################ -#! o3de_find_project_folder: -# -# \arg:project_path returns the path of the o3de project folder with name project_name -# \arg:project_name name of the project -################################################################################ -function(o3de_find_project_folder project_name project_path) - foreach(project_entry ${o3de_projects}) - set(project_json_file ${project_entry}/project.json) - file(READ ${project_json_file} project_json) - string(JSON this_project_name ERROR_VARIABLE json_error GET ${project_json} project_name) - if(json_error) - message(WARNING "Unable to read project_name from '${project_json_file}', error: ${json_error}") - else() - if(this_project_name STREQUAL project_name) - set(${project_path} ${project_entry} PARENT_SCOPE) - return() - endif() - endif() - endforeach() - message(FATAL_ERROR "Unable to find project_name: '${project_name}'") -endfunction() - - -################################################################################ -#! o3de_find_gem_folder: -# -# \arg:gem_path returns the path of the o3de gem folder with name gem_name -# \arg:gem_name name of the gem -################################################################################ -function(o3de_find_gem_folder gem_name gem_path) - foreach(gem_entry ${o3de_gems}) - set(gem_json_file ${gem_entry}/gem.json) - file(READ ${gem_json_file} gem_json) - string(JSON this_gem_name ERROR_VARIABLE json_error GET ${gem_json} gem_name) - if(json_error) - message(WARNING "Unable to read gem_name from '${gem_json_file}', error: ${json_error}") - else() - if(this_gem_name STREQUAL gem_name) - set(${gem_path} ${gem_entry} PARENT_SCOPE) - return() - endif() - endif() - endforeach() - message(FATAL_ERROR "Unable to find gem_name: '${gem_name}'") -endfunction() - - -################################################################################ -#! o3de_find_template_folder: -# -# \arg:template_path returns the path of the o3de template folder with name template_name -# \arg:template_name name of the template -################################################################################ -function(o3de_find_template_folder template_name template_path) - foreach(template_entry ${o3de_templates}) - set(template_json_file ${template_entry}/template.json) - file(READ ${template_json_file} template_json) - string(JSON this_template_name ERROR_VARIABLE json_error GET ${template_json} template_name) - if(json_error) - message(WARNING "Unable to read template_name from '${template_json_file}', error: ${json_error}") - else() - if(this_template_name STREQUAL template_name) - set(${template_path} ${template_entry} PARENT_SCOPE) - return() - endif() - endif() - endforeach() - message(FATAL_ERROR "Unable to find template_name: '${template_name}'") -endfunction() - - -################################################################################ -#! o3de_find_repo_folder: -# -# \arg:repo_path returns the path of the o3de repo folder with name repo_name -# \arg:repo_name name of the repo -################################################################################ -function(o3de_find_repo_folder repo_name repo_path) - foreach(repo_entry ${o3de_repos}) - set(repo_json_file ${repo_entry}/repo.json) - file(READ ${repo_json_file} repo_json) - string(JSON this_repo_name ERROR_VARIABLE json_error GET ${repo_json} repo_name) - if(json_error) - message(WARNING "Unable to read repo_name from '${repo_json_file}', error: ${json_error}") - else() - if(this_repo_name STREQUAL repo_name) - set(${repo_path} ${repo_entry} PARENT_SCOPE) - return() - endif() - endif() - endforeach() - message(FATAL_ERROR "Unable to find repo_name: '${repo_name}'") -endfunction() - - -################################################################################ -#! o3de_find_restricted_folder: -# -# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name -# \arg:restricted_name name of the restricted -################################################################################ -function(o3de_find_restricted_folder restricted_name restricted_path) - foreach(restricted_entry ${o3de_restricted}) - set(restricted_json_file ${restricted_entry}/restricted.json) - file(READ ${restricted_json_file} restricted_json) - string(JSON this_restricted_name ERROR_VARIABLE json_error GET ${restricted_json} restricted_name) - if(json_error) - message(WARNING "Unable to read restricted_name from '${restricted_json_file}', error: ${json_error}") - else() - if(this_restricted_name STREQUAL restricted_name) - set(${restricted_path} ${restricted_entry} PARENT_SCOPE) - return() - endif() - endif() - endforeach() - message(FATAL_ERROR "Unable to find restricted_name: '${restricted_name}'") -endfunction() - - -################################################################################ -#! o3de_engine_name: -# -# \arg:engine returns the engine_name element from an engine.json -# \arg:o3de_engine_json_file name of the o3de json file -################################################################################ -function(o3de_engine_name o3de_engine_json_file engine) - file(READ ${o3de_engine_json_file} json_data) - string(JSON engine_entry ERROR_VARIABLE json_error GET ${json_data} engine_name) - if(json_error) - message(FATAL_ERROR "Unable to read engine_name from '${o3de_json_file}', error: ${json_error}") - endif() - if(engine_entry) - set(${engine} ${engine_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_project_name: -# -# \arg:project returns the project_name element from an project.json -# \arg:o3de_project_json_file name of the o3de json file -################################################################################ -function(o3de_project_name o3de_project_json_file project) - file(READ ${o3de_project_json_file} json_data) - string(JSON project_entry ERROR_VARIABLE json_error GET ${json_data} project_name) - if(json_error) - message(FATAL_ERROR "Unable to read project_name from '${o3de_json_file}', error: ${json_error}") - endif() - if(project_entry) - set(${project} ${project_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_gem_name: -# -# \arg:gem returns the gem_name element from an gem.json -# \arg:o3de_gem_json_file name of the o3de json file -################################################################################ -function(o3de_gem_name o3de_gem_json_file gem) - file(READ ${o3de_gem_json_file} json_data) - string(JSON gem_entry ERROR_VARIABLE json_error GET ${json_data} gem_name) - if(json_error) - message(FATAL_ERROR "Unable to read gem_name from '${o3de_json_file}', error: ${json_error}") - endif() - if(gem_entry) - set(${gem} ${gem_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_template_name: -# -# \arg:template returns the template_name element from an template json -# \arg:o3de_template_json_file name of the o3de json file -################################################################################ -function(o3de_template_name o3de_template_json_file template) - file(READ ${o3de_template_json_file} json_data) - string(JSON template_entry ERROR_VARIABLE json_error GET ${json_data} template_name) - if(json_error) - message(FATAL_ERROR "Unable to read template_name from '${o3de_json_file}', error: ${json_error}") - endif() - if(template_entry) - set(${template} ${template_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_repo_name: -# -# \arg:repo returns the repo_name element from an repo.json or o3de_manifest.json -# \arg:o3de_repo_json_file name of the o3de json file -################################################################################ -function(o3de_repo_name o3de_repo_json_file repo) - file(READ ${o3de_repo_json_file} json_data) - string(JSON repo_entry ERROR_VARIABLE json_error GET ${json_data} repo_name) - if(json_error) - message(FATAL_ERROR "Unable to read repo_name from '${o3de_json_file}', error: ${json_error}") - endif() - if(repo_entry) - set(${repo} ${repo_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_restricted_name: -# -# \arg:restricted returns the restricted association element from an o3de json -# \arg:o3de_json_file name of the o3de json file -################################################################################ -function(o3de_restricted_name o3de_json_file restricted) - file(READ ${o3de_json_file} json_data) - string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} restricted_name) - if(json_error) - message(WARNING "FATAL_ERROR to read restricted_name from '${o3de_json_file}', error: ${json_error}") - endif() - if(restricted_entry) - set(${restricted} ${restricted_entry} PARENT_SCOPE) - endif() -endfunction() - - -################################################################################ -#! o3de_engine_path: -# -# \arg:engine_path returns the path of the o3de engine folder with name engine_name -# \arg:engine_name name of the engine -################################################################################ -function(o3de_engine_path o3de_json_file engine_path) - o3de_engine_id(${o3de_json_file} engine_name) - if(engine_name) - o3de_find_engine_folder(${engine_name} engine_folder) - if(engine_folder) - set(${engine_path} ${engine_folder} PARENT_SCOPE) - endif() - endif() -endfunction() - - -################################################################################ -#! o3de_project_path: -# -# \arg:project_path returns the path of the o3de project folder with name project_name -# \arg:project_name name of the project -################################################################################ -function(o3de_project_path o3de_json_file project_path) - o3de_project_id(${o3de_json_file} project_name) - if(project_name) - o3de_find_project_folder(${project_name} project_folder) - if(project_folder) - set(${project_path} ${project_folder} PARENT_SCOPE) - endif() - endif() -endfunction() - - -################################################################################ -#! o3de_template_path: -# -# \arg:template_path returns the path of the o3de template folder with name template_name -# \arg:template_name name of the template -################################################################################ -function(o3de_template_path o3de_json_file template_path) - o3de_template_id(${o3de_json_file} template_name) - if(template_name) - o3de_find_template_folder(${template_name} template_folder) - if(template_folder) - set(${template_path} ${template_folder} PARENT_SCOPE) - endif() - endif() -endfunction() - - -################################################################################ -#! o3de_repo_path: -# -# \arg:repo_path returns the path of the o3de repo folder with name repo_name -# \arg:repo_name name of the repo -################################################################################ -function(o3de_repo_path o3de_json_file repo_path) - o3de_repo_id(${o3de_json_file} repo_name) - if(repo_name) - o3de_find_repo_folder(${repo_name} repo_folder) - if(repo_folder) - set(${repo_path} ${repo_folder} PARENT_SCOPE) - endif() - endif() -endfunction() - - -################################################################################ -#! o3de_restricted_path: -# -# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name -# \arg:restricted_name name of the restricted -################################################################################ -function(o3de_restricted_path o3de_json_file restricted_path) - o3de_restricted_id(${o3de_json_file} restricted_name) - if(restricted_name) - o3de_find_restricted_folder(${restricted_name} restricted_folder) - if(restricted_folder) - set(${restricted_path} ${restricted_folder} PARENT_SCOPE) - endif() - endif() -endfunction() From 7e4070e5f1edd9366562dbfb1860699e7a4db114 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 May 2021 02:50:30 -0500 Subject: [PATCH 071/140] Updating the DefaultProject and DefaultGem templates to use the "restricted_name" key for indicating the identifier of a restricted directory location instead of "restricted" --- Templates/DefaultGem/template.json | 2 +- Templates/DefaultProject/template.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Templates/DefaultGem/template.json b/Templates/DefaultGem/template.json index 22d4eb27e6..b653718095 100644 --- a/Templates/DefaultGem/template.json +++ b/Templates/DefaultGem/template.json @@ -1,6 +1,6 @@ { "template_name": "DefaultGem", - "restricted": "o3de", + "restricted_name": "o3de", "restricted_platform_relative_path": "Templates", "origin": "The primary repo for DefaultGem goes here: i.e. http://www.mydomain.com", "license": "What license DefaultGem uses goes here: i.e. https://opensource.org/licenses/MIT", diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index e823b6df19..31b448c9f6 100644 --- a/Templates/DefaultProject/template.json +++ b/Templates/DefaultProject/template.json @@ -1,6 +1,6 @@ { "template_name": "DefaultProject", - "restricted": "o3de", + "restricted_name": "o3de", "restricted_platform_relative_path": "Templates", "origin": "The primary repo for DefaultProject goes here: i.e. http://www.mydomain.com", "license": "What license DefaultProject uses goes here: i.e. https://opensource.org/licenses/MIT", From 7872360e4a6b9c2411ee7365c8ec595f49a0c960 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 May 2021 02:53:40 -0500 Subject: [PATCH 072/140] Updating the engine.json file with the list of external_subdirectories, projects and template that come with it --- engine.json | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/engine.json b/engine.json index e8dba6d965..7662d4f034 100644 --- a/engine.json +++ b/engine.json @@ -1,8 +1,98 @@ { "engine_name": "o3de", - "restricted": "o3de", + "restricted_name": "o3de", "FileVersion": 1, "O3DEVersion": "0.0.0.0", "O3DECopyrightYear": 2021, - "O3DEBuildNumber": 0 + "O3DEBuildNumber": 0, + "external_subdirectories": [ + "Gems/Achievements", + "Gems/AssetMemoryAnalyzer", + "Gems/AssetValidation", + "Gems/Atom", + "Gems/AtomContent", + "Gems/AtomLyIntegration", + "Gems/AtomTressFX", + "Gems/AudioEngineWwise", + "Gems/AudioSystem", + "Gems/AutomatedLauncherTesting", + "Gems/AWSClientAuth", + "Gems/AWSCore", + "Gems/AWSMetrics", + "Gems/Blast", + "Gems/Camera", + "Gems/CameraFramework", + "Gems/CertificateManager", + "Gems/CrashReporting", + "Gems/CustomAssetExample", + "Gems/DebugDraw", + "Gems/DevTextures", + "Gems/EditorPythonBindings", + "Gems/EMotionFX", + "Gems/ExpressionEvaluation", + "Gems/FastNoise", + "Gems/GameState", + "Gems/GameStateSamples", + "Gems/Gestures", + "Gems/GradientSignal", + "Gems/GraphCanvas", + "Gems/GraphModel", + "Gems/HttpRequestor", + "Gems/ImGui", + "Gems/InAppPurchases", + "Gems/LandscapeCanvas", + "Gems/LmbrCentral", + "Gems/LocalUser", + "Gems/LyShine", + "Gems/LyShineExamples", + "Gems/Maestro", + "Gems/MessagePopup", + "Gems/Metastream", + "Gems/Microphone", + "Gems/Multiplayer", + "Gems/MultiplayerCompression", + "Gems/NvCloth", + "Gems/PBSreferenceMaterials", + "Gems/PhysicsEntities", + "Gems/PhysX", + "Gems/PhysXDebug", + "Gems/PhysXSamples", + "Gems/Prefab", + "Gems/Presence", + "Gems/PrimitiveAssets", + "Gems/PythonAssetBuilder", + "Gems/QtForPython", + "Gems/RADTelemetry", + "Gems/SaveData", + "Gems/SceneLoggingExample", + "Gems/SceneProcessing", + "Gems/ScriptCanvas", + "Gems/ScriptCanvasDeveloper", + "Gems/ScriptCanvasPhysics", + "Gems/ScriptCanvasTesting", + "Gems/ScriptedEntityTweener", + "Gems/ScriptEvents", + "Gems/SliceFavorites", + "Gems/StartingPointCamera", + "Gems/StartingPointInput", + "Gems/StartingPointMovement", + "Gems/SurfaceData", + "Gems/TestAssetBuilder", + "Gems/TextureAtlas", + "Gems/TickBusOrderViewer", + "Gems/Twitch", + "Gems/UIBasics", + "Gems/Vegetation", + "Gems/Vegetation_Gem_Assets", + "Gems/VideoPlaybackFramework", + "Gems/VirtualGamepad", + "Gems/WhiteBox" + ], + "projects": [ + "AutomatedTesting" + ], + "templates": [ + "Templates/DefaultGem", + "Templates/DefaultProject" + ] } From a424ac63ecfa387f3da99c86e4aebefa00d9b6d3 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 May 2021 02:07:36 -0500 Subject: [PATCH 073/140] Adding empty CMakeLists.txt to Asset only gems to fit the new definition of a gem. That defintion is that a gem is a directory with a gem.json and a CMakeLists.txt in it --- Gems/AtomContent/CMakeLists.txt | 10 ++++++++++ Gems/AtomContent/gem.json | 14 ++++++++++++++ Gems/AtomTressFX/CMakeLists.txt | 10 ++++++++++ Gems/DevTextures/CMakeLists.txt | 10 ++++++++++ Gems/PBSreferenceMaterials/CMakeLists.txt | 10 ++++++++++ Gems/PhysXSamples/CMakeLists.txt | 10 ++++++++++ Gems/PhysicsEntities/CMakeLists.txt | 10 ++++++++++ Gems/PrimitiveAssets/CMakeLists.txt | 10 ++++++++++ Gems/UiBasics/CMakeLists.txt | 10 ++++++++++ Gems/Vegetation_Gem_Assets/CMakeLists.txt | 10 ++++++++++ 10 files changed, 104 insertions(+) create mode 100644 Gems/AtomContent/CMakeLists.txt create mode 100644 Gems/AtomContent/gem.json create mode 100644 Gems/AtomTressFX/CMakeLists.txt create mode 100644 Gems/DevTextures/CMakeLists.txt create mode 100644 Gems/PBSreferenceMaterials/CMakeLists.txt create mode 100644 Gems/PhysXSamples/CMakeLists.txt create mode 100644 Gems/PhysicsEntities/CMakeLists.txt create mode 100644 Gems/PrimitiveAssets/CMakeLists.txt create mode 100644 Gems/UiBasics/CMakeLists.txt create mode 100644 Gems/Vegetation_Gem_Assets/CMakeLists.txt diff --git a/Gems/AtomContent/CMakeLists.txt b/Gems/AtomContent/CMakeLists.txt new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/Gems/AtomContent/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/Gems/AtomContent/gem.json b/Gems/AtomContent/gem.json new file mode 100644 index 0000000000..941e7dea20 --- /dev/null +++ b/Gems/AtomContent/gem.json @@ -0,0 +1,14 @@ +{ + "gem_name": "AtomContent", + "origin": "The primary repo for Atom goes here: i.e. http://www.mydomain.com", + "license": "What license Atom uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "Atom Content", + "summary": "ontains multiple packages containing source Assets that can be used with Atom", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "AtomConent" + ], + "icon_path": "preview.png" +} diff --git a/Gems/AtomTressFX/CMakeLists.txt b/Gems/AtomTressFX/CMakeLists.txt new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/Gems/AtomTressFX/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/Gems/DevTextures/CMakeLists.txt b/Gems/DevTextures/CMakeLists.txt new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/Gems/DevTextures/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/Gems/PBSreferenceMaterials/CMakeLists.txt b/Gems/PBSreferenceMaterials/CMakeLists.txt new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/Gems/PBSreferenceMaterials/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/Gems/PhysXSamples/CMakeLists.txt b/Gems/PhysXSamples/CMakeLists.txt new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/Gems/PhysXSamples/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/Gems/PhysicsEntities/CMakeLists.txt b/Gems/PhysicsEntities/CMakeLists.txt new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/Gems/PhysicsEntities/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/Gems/PrimitiveAssets/CMakeLists.txt b/Gems/PrimitiveAssets/CMakeLists.txt new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/Gems/PrimitiveAssets/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/Gems/UiBasics/CMakeLists.txt b/Gems/UiBasics/CMakeLists.txt new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/Gems/UiBasics/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/Gems/Vegetation_Gem_Assets/CMakeLists.txt b/Gems/Vegetation_Gem_Assets/CMakeLists.txt new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/Gems/Vegetation_Gem_Assets/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# From 530c9a424e2d128282f735dcaabb11566b4476ea Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 May 2021 04:11:02 -0500 Subject: [PATCH 074/140] Updating the manifest get_registered command to read the engine projects, gems, external_subdirectories, restricted and templates paths from the engine.json --- scripts/o3de/o3de/add_external_subdirectory.py | 3 ++- scripts/o3de/o3de/cmake.py | 2 +- scripts/o3de/o3de/download.py | 2 +- scripts/o3de/o3de/manifest.py | 16 ++++++++-------- scripts/o3de/o3de/register.py | 1 - .../o3de/o3de/remove_external_subdirectory.py | 4 ++-- scripts/o3de/o3de/remove_gem_cmake.py | 2 +- scripts/o3de/o3de/remove_gem_project.py | 2 +- scripts/o3de/o3de/validation.py | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/scripts/o3de/o3de/add_external_subdirectory.py b/scripts/o3de/o3de/add_external_subdirectory.py index 15dc5163c5..388f0027da 100644 --- a/scripts/o3de/o3de/add_external_subdirectory.py +++ b/scripts/o3de/o3de/add_external_subdirectory.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -Contains command to add a gem to a project's cmake scripts +Contains command to add an external_subdirectory to a project's cmake scripts """ import argparse @@ -50,6 +50,7 @@ def add_external_subdirectory(external_subdir: str or pathlib.Path, logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') return 1 + engine_object.setdefault('external_subdirectories', []) while external_subdir.as_posix() in engine_object['external_subdirectories']: engine_object['external_subdirectories'].remove(external_subdir.as_posix()) diff --git a/scripts/o3de/o3de/cmake.py b/scripts/o3de/o3de/cmake.py index b5b28cbb7e..7e95a9c2fe 100644 --- a/scripts/o3de/o3de/cmake.py +++ b/scripts/o3de/o3de/cmake.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -This file contains methods for introspecting data from cmake scripts +Contains methods for query CMake gem target information """ import logging diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index 218463f98b..3db2f077cd 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -This file contains functions for querying paths from ~/.o3de directory +Implements functionality for downloading o3de objecs either locally or from a URI """ import argparse diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index b3aac6d1f3..44d6ff1b61 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -This file contains functions for querying paths from ~/.o3de directory +Contains functions for data from json files such as the o3de_manifests.json, engine.json, project.json, etc... """ import json @@ -496,7 +496,7 @@ def get_registered(engine_name: str = None, return engine_path elif isinstance(project_name, str): - engine_object = find_engine_data(json_data) + enging_projects = get_engine_projects() projects = json_data['projects'].copy() projects.extend(engine_object['projects']) for project_path in projects: @@ -513,9 +513,9 @@ def get_registered(engine_name: str = None, return project_path elif isinstance(gem_name, str): - engine_object = find_engine_data(json_data) + engine_gems = get_engine_gems() gems = json_data['gems'].copy() - gems.extend(engine_object['gems']) + gems.extend(engine_gems) for gem_path in gems: gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' @@ -530,9 +530,9 @@ def get_registered(engine_name: str = None, return gem_path elif isinstance(template_name, str): - engine_object = find_engine_data(json_data) + engine_templates = get_engine_templates() templates = json_data['templates'].copy() - templates.extend(engine_object['templates']) + templates.extend(engine_templates) for template_path in templates: template_path = pathlib.Path(template_path).resolve() template_json = template_path / 'template.json' @@ -547,9 +547,9 @@ def get_registered(engine_name: str = None, return template_path elif isinstance(restricted_name, str): - engine_object = find_engine_data(json_data) + engine_restricted = get_engine_restricted() restricted = json_data['restricted'].copy() - restricted.extend(engine_object['restricted']) + restricted.extend(engine_restricted) for restricted_path in restricted: restricted_path = pathlib.Path(restricted_path).resolve() restricted_json = restricted_path / 'restricted.json' diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index e96d057e9c..d6a734e1fd 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -374,7 +374,6 @@ def register_engine_path(json_data: dict, engine_object = {} engine_object.update({'path': engine_path.as_posix()}) - engine_object.update({'restricted': []}) json_data.setdefault('engines', []).insert(0, engine_object) diff --git a/scripts/o3de/o3de/remove_external_subdirectory.py b/scripts/o3de/o3de/remove_external_subdirectory.py index 3e022d51b9..a636474fba 100644 --- a/scripts/o3de/o3de/remove_external_subdirectory.py +++ b/scripts/o3de/o3de/remove_external_subdirectory.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -Contains command to add a gem to a project's cmake scripts +Implemens functinality to remove external_subdirectories from the o3de_manifests.json """ import argparse @@ -31,7 +31,7 @@ def remove_external_subdirectory(external_subdir: str or pathlib.Path, """ json_data = manifest.load_o3de_manifest() engine_object = manifest.find_engine_data(json_data, engine_path) - if not engine_object: + if not engine_object or not 'external_subdirectories' in engine_object: logger.error(f'Remove External Subdirectory Failed: {engine_path} not registered.') return 1 diff --git a/scripts/o3de/o3de/remove_gem_cmake.py b/scripts/o3de/o3de/remove_gem_cmake.py index 2def94dfbf..8f73caaad1 100644 --- a/scripts/o3de/o3de/remove_gem_cmake.py +++ b/scripts/o3de/o3de/remove_gem_cmake.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -This file contains methods for removing a gem from a project's cmake scripts +Contains methods for removing a gem from a project's cmake scripts """ import argparse diff --git a/scripts/o3de/o3de/remove_gem_project.py b/scripts/o3de/o3de/remove_gem_project.py index a3e623f488..7644357042 100644 --- a/scripts/o3de/o3de/remove_gem_project.py +++ b/scripts/o3de/o3de/remove_gem_project.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -This file contains methods for removing a gem from a project +Contains methods for removing a gem target from a project """ import argparse diff --git a/scripts/o3de/o3de/validation.py b/scripts/o3de/o3de/validation.py index 56839fe056..f3a5f5e376 100644 --- a/scripts/o3de/o3de/validation.py +++ b/scripts/o3de/o3de/validation.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -This file contains functions for querying paths from ~/.o3de directory +This file validating o3de object json files """ import json import pathlib From b42cc19f28280ad4b87c0bc1c4c225aee8f7a816 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Sun, 23 May 2021 21:54:56 -0500 Subject: [PATCH 075/140] Moved the preview.png from the that the o3de engine template script from cmake/Tools directory to the o3de/resources directory --- {cmake/Tools => scripts/o3de/o3de/resources}/preview.png | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {cmake/Tools => scripts/o3de/o3de/resources}/preview.png (100%) diff --git a/cmake/Tools/preview.png b/scripts/o3de/o3de/resources/preview.png similarity index 100% rename from cmake/Tools/preview.png rename to scripts/o3de/o3de/resources/preview.png From e59b154139ab530e99cda544fcea60eadcdb1302 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Sun, 23 May 2021 22:10:09 -0500 Subject: [PATCH 076/140] Updated the refactored o3de command scripts to be able to run standalone by adding a main section Removed the ability to suppress errors in the add-gem-to-cmake and add-external-subdirectory command Reduced duplicate logic in the download.py, register.py and repo.py scripts Removed the registration.py script and moved the registration of those comamnds directly to the o3de.py script Reduced the exception scope in the o3de command scripts to be as constrained as possible. For example instead of having a block of Exception for catching a dictionary KeyError, the block has been updated to just catch KeyError Added a python test for validating the "register.py --this-engine" functionality --- scripts/o3de.py | 81 ++- .../o3de/o3de/add_external_subdirectory.py | 77 ++- scripts/o3de/o3de/add_gem_cmake.py | 86 ++- scripts/o3de/o3de/add_gem_project.py | 78 ++- scripts/o3de/o3de/download.py | 641 ++++-------------- scripts/o3de/o3de/engine_template.py | 89 ++- scripts/o3de/o3de/get_registration.py | 60 +- scripts/o3de/o3de/global_project.py | 15 +- scripts/o3de/o3de/manifest.py | 26 +- scripts/o3de/o3de/print_registration.py | 72 +- scripts/o3de/o3de/register.py | 398 ++++------- scripts/o3de/o3de/registration.py | 92 --- .../o3de/o3de/remove_external_subdirectory.py | 55 +- scripts/o3de/o3de/remove_gem_cmake.py | 59 +- scripts/o3de/o3de/remove_gem_project.py | 74 +- scripts/o3de/o3de/repo.py | 275 ++------ scripts/o3de/o3de/sha256.py | 63 +- scripts/o3de/o3de/utils.py | 44 +- scripts/o3de/o3de/validation.py | 21 +- scripts/o3de/tests/unit_test_registration.py | 57 +- 20 files changed, 1031 insertions(+), 1332 deletions(-) delete mode 100755 scripts/o3de/o3de/registration.py diff --git a/scripts/o3de.py b/scripts/o3de.py index d3b877620f..dabb83b068 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -13,27 +13,70 @@ import argparse import pathlib import sys -# As o3de.py shares the same name as the o3de package attempting to use a regular -# from o3de import line tries to import from the current o3de.py script and not the package -# So the current script directory is removed from the sys.path temporary -SCRIPT_DIR_REMOVED = False -SCRIPT_DIR = pathlib.Path(__file__).parent.resolve() -while str(SCRIPT_DIR) in sys.path: - SCRIPT_DIR_REMOVED = True - sys.path.remove(str(SCRIPT_DIR)) - -from o3de import engine_template -from o3de import global_project -from o3de import registration - -if SCRIPT_DIR_REMOVED: - sys.path.insert(0, str(SCRIPT_DIR)) - def add_args(parser, subparsers) -> None: - global_project.add_args(parser, subparsers) - engine_template.add_args(parser, subparsers) - registration.add_args(parser, subparsers) + """ + add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + invoked by o3de.py + Ex o3de.py can invoke the register downloadable commands by importing register, + call add_args and execute: python o3de.py register --gem-path "C:/TestGem" + :param parser: the caller instantiates a parser and passes it in here + :param subparsers: the caller instantiates subparsers and passes it in here + """ + + # As o3de.py shares the same name as the o3de package attempting to use a regular + # from o3de import line tries to import from the current o3de.py script and not the package + # So the current script directory is removed from the sys.path temporary + SCRIPT_DIR_REMOVED = False + SCRIPT_DIR = pathlib.Path(__file__).parent.resolve() + while str(SCRIPT_DIR) in sys.path: + SCRIPT_DIR_REMOVED = True + sys.path.remove(str(SCRIPT_DIR)) + + from o3de import engine_template, global_project, register, print_registration, get_registration, download, \ + add_external_subdirectory, remove_external_subdirectory, add_gem_cmake, remove_gem_cmake, add_gem_project, \ + remove_gem_project, sha256 + + if SCRIPT_DIR_REMOVED: + sys.path.insert(0, str(SCRIPT_DIR)) + + # global_project + global_project.add_args(subparsers) + # engine templaate + engine_template.add_args(subparsers) + + # register + register.add_args(subparsers) + + # show + print_registration.add_args(subparsers) + + # get-registered + get_registration.add_args(subparsers) + + # download + download.add_args(subparsers) + + # add external subdirectories + add_external_subdirectory.add_args(subparsers) + + # remove external subdirectories + remove_external_subdirectory.add_args(subparsers) + + # add gems to cmake + add_gem_cmake.add_args(subparsers) + + # remove gems from cmake + remove_gem_cmake.add_args(subparsers) + + # add a gem to a project + add_gem_project.add_args(subparsers) + + # remove a gem from a project + remove_gem_project.add_args(subparsers) + + # sha256 + sha256.add_args(subparsers) if __name__ == "__main__": diff --git a/scripts/o3de/o3de/add_external_subdirectory.py b/scripts/o3de/o3de/add_external_subdirectory.py index 388f0027da..29013d30c8 100644 --- a/scripts/o3de/o3de/add_external_subdirectory.py +++ b/scripts/o3de/o3de/add_external_subdirectory.py @@ -15,6 +15,7 @@ Contains command to add an external_subdirectory to a project's cmake scripts import argparse import logging import pathlib +import sys from o3de import manifest @@ -22,32 +23,27 @@ logger = logging.getLogger() logging.basicConfig() def add_external_subdirectory(external_subdir: str or pathlib.Path, - engine_path: str or pathlib.Path = None, - suppress_errors: bool = False) -> int: + engine_path: str or pathlib.Path = None) -> int: """ add external subdirectory to a cmake :param external_subdir: external subdirectory to add to cmake :param engine_path: optional engine path, defaults to this engine - :param suppress_errors: optional silence errors :return: 0 for success or non 0 failure code """ external_subdir = pathlib.Path(external_subdir).resolve() if not external_subdir.is_dir(): - if not suppress_errors: - logger.error(f'Add External Subdirectory Failed: {external_subdir} does not exist.') + logger.error(f'Add External Subdirectory Failed: {external_subdir} does not exist.') return 1 external_subdir_cmake = external_subdir / 'CMakeLists.txt' if not external_subdir_cmake.is_file(): - if not suppress_errors: - logger.error(f'Add External Subdirectory Failed: {external_subdir} does not contain a CMakeLists.txt.') + logger.error(f'Add External Subdirectory Failed: {external_subdir} does not contain a CMakeLists.txt.') return 1 json_data = manifest.load_o3de_manifest() engine_object = manifest.find_engine_data(json_data, engine_path) if not engine_object: - if not suppress_errors: - logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') + logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') return 1 engine_object.setdefault('external_subdirectories', []) @@ -76,7 +72,7 @@ def add_external_subdirectory(external_subdir: str or pathlib.Path, if end > start + len('include('): try: include_cmake_file = pathlib.Path(engine_path / line[start + len('include('): end]).resolve() - except Exception as e: + except FileNotFoundError as e: pass else: parse_cmake_file(include_cmake_file, files) @@ -88,7 +84,7 @@ def add_external_subdirectory(external_subdir: str or pathlib.Path, try: include_cmake_file = pathlib.Path( cmake_path / line[start + len('add_subdirectory('): end]).resolve() - except Exception as e: + except FileNotFoundError as e: pass else: parse_cmake_file(include_cmake_file, files) @@ -100,8 +96,7 @@ def add_external_subdirectory(external_subdir: str or pathlib.Path, if external_subdir in cmake_files: manifest.save_o3de_manifest(json_data) - if not suppress_errors: - logger.error(f'External subdirectory {external_subdir.as_posix()} already included by add_subdirectory().') + logger.warning(f'External subdirectory {external_subdir.as_posix()} already included by add_subdirectory().') return 1 engine_object['external_subdirectories'].insert(0, external_subdir.as_posix()) @@ -119,23 +114,55 @@ def _run_add_external_subdirectory(args: argparse) -> int: return add_external_subdirectory(args.external_subdirectory) -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here + Ex. Directly run from this file alone with: python add-external-subdirectory.py "/home/foo/external-subdir" + :param parser: the caller passes an argparse parser like instance to this method + """ + parser.add_argument('external_subdirectory', metavar='external_subdirectory', type=str, + help='add an external subdirectory to cmake') + + 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.') + + parser.set_defaults(func=_run_add_external_subdirectory) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py add_external_subdirectory "/home/foo/external-subdir" :param subparsers: the caller instantiates subparsers and passes it in here """ add_external_subdirectory_subparser = subparsers.add_parser('add-external-subdirectory') - add_external_subdirectory_subparser.add_argument('external_subdirectory', metavar='external_subdirectory', type=str, - help='add an external subdirectory to cmake') + add_parser_args(add_external_subdirectory_subparser) - add_external_subdirectory_subparser.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.') - add_external_subdirectory_subparser.set_defaults(func=_run_add_external_subdirectory) +def main(): + """ + Runs add_external_subdirectory.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/add_gem_cmake.py b/scripts/o3de/o3de/add_gem_cmake.py index fa2d2f4bb3..523fb8dce8 100644 --- a/scripts/o3de/o3de/add_gem_cmake.py +++ b/scripts/o3de/o3de/add_gem_cmake.py @@ -15,6 +15,7 @@ Contains command to add a gem to a project's cmake scripts import argparse import logging import pathlib +import sys from o3de import add_external_subdirectory, manifest, validation @@ -24,39 +25,33 @@ logging.basicConfig() def add_gem_to_cmake(gem_name: str = None, gem_path: str or pathlib.Path = None, engine_name: str = None, - engine_path: str or pathlib.Path = None, - suppress_errors: bool = False) -> int: + engine_path: str or pathlib.Path = None) -> int: """ add a gem to a cmake as an external subdirectory for an engine :param gem_name: name of the gem to add to cmake :param gem_path: the path of the gem to add to cmake :param engine_name: name of the engine to add to cmake :param engine_path: the path of the engine to add external subdirectory to, default to this engine - :param suppress_errors: optional silence errors :return: 0 for success or non 0 failure code """ if not gem_name and not gem_path: - if not suppress_errors: - logger.error('Must specify either a Gem name or Gem Path.') + logger.error('Must specify either a Gem name or Gem Path.') return 1 if gem_name and not gem_path: gem_path = manifest.get_registered(gem_name=gem_name) if not gem_path: - if not suppress_errors: - logger.error(f'Gem Path {gem_path} has not been registered.') + logger.error(f'Gem Path {gem_path} has not been registered.') return 1 gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' if not gem_json.is_file(): - if not suppress_errors: - logger.error(f'Gem json {gem_json} is not present.') + logger.error(f'Gem json {gem_json} is not present.') return 1 if not validation.valid_o3de_gem_json(gem_json): - if not suppress_errors: - logger.error(f'Gem json {gem_json} is not valid.') + logger.error(f'Gem json {gem_json} is not valid.') return 1 if not engine_name and not engine_path: @@ -66,22 +61,18 @@ def add_gem_to_cmake(gem_name: str = None, engine_path = manifest.get_registered(engine_name=engine_name) if not engine_path: - if not suppress_errors: - logger.error(f'Engine Path {engine_path} has not been registered.') + logger.error(f'Engine Path {engine_path} has not been registered.') return 1 engine_json = engine_path / 'engine.json' if not engine_json.is_file(): - if not suppress_errors: - logger.error(f'Engine json {engine_json} is not present.') + logger.error(f'Engine json {engine_json} is not present.') return 1 if not validation.valid_o3de_engine_json(engine_json): - if not suppress_errors: - logger.error(f'Engine json {engine_json} is not valid.') + logger.error(f'Engine json {engine_json} is not valid.') return 1 - return add_external_subdirectory.add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path, suppress_errors=suppress_errors) - + return add_external_subdirectory.add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path) def _run_add_gem_to_cmake(args: argparse) -> int: if args.override_home_folder: @@ -90,25 +81,58 @@ def _run_add_gem_to_cmake(args: argparse) -> int: return add_gem_to_cmake(gem_name=args.gem_name, gem_path=args.gem_path) -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here + Ex. Directly run from this file alone with: python add_gem_cmake.py --gem-path "/path/to/gem" + :param parser: the caller passes an argparse parser like instance to this method """ - add_gem_to_cmake_subparser = subparsers.add_parser('add-gem-to-cmake') - group = add_gem_to_cmake_subparser.add_mutually_exclusive_group(required=True) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-gp', '--gem-path', type=str, required=False, help='The path to the gem.') group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') - add_gem_to_cmake_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + 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.') - add_gem_to_cmake_subparser.set_defaults(func=_run_add_gem_to_cmake) + parser.set_defaults(func=_run_add_gem_to_cmake) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py add-gem-to-cmake --gem-path "/path/to/gem" + :param subparsers: the caller instantiates subparsers and passes it in here + """ + add_gem_cmake_subparser = subparsers.add_parser('add-gem-to-cmake') + add_parser_args(add_gem_cmake_subparser) + + +def main(): + """ + Runs add_gem_cmake.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/add_gem_project.py b/scripts/o3de/o3de/add_gem_project.py index 933fd019bb..78dffc4477 100644 --- a/scripts/o3de/o3de/add_gem_project.py +++ b/scripts/o3de/o3de/add_gem_project.py @@ -17,6 +17,7 @@ import json import logging import os import pathlib +import sys from o3de import add_gem_cmake, cmake, manifest, validation @@ -126,13 +127,13 @@ def add_gem_to_project(gem_name: str = None, with project_json.open('r') as s: try: project_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Error loading Project json {project_json}: {str(e)}') return 1 else: try: engine_name = project_json_data['engine'] - except Exception as e: + except KeyError as e: logger.error(f'Project json {project_json} "engine" not found: {str(e)}') return 1 else: @@ -261,51 +262,84 @@ def _run_add_gem_to_project(args: argparse) -> int: args.add_to_cmake) -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here + Ex. Directly run from this file alone with: python add_gem_project.py --project-path "D:/TestProject" --gem-path "D:/TestGem" + :param parser: the caller passes an argparse parser like instance to this method """ - add_gem_subparser = subparsers.add_parser('add-gem-to-project') - group = add_gem_subparser.add_mutually_exclusive_group(required=True) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-pp', '--project-path', type=str, 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 = add_gem_subparser.add_mutually_exclusive_group(required=True) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-gp', '--gem-path', type=str, required=False, help='The path to the gem.') group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') - add_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, + parser.add_argument('-gt', '--gem-target', type=str, required=False, help='The cmake target name to add. If not specified it will assume gem_name') - add_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, + parser.add_argument('-df', '--dependencies-file', type=str, required=False, help='The cmake dependencies file in which the gem dependencies are specified.' 'If not specified it will assume ') - add_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, + parser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, default=False, help='Optional toggle if this gem should be added as a runtime dependency') - add_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, + parser.add_argument('-td', '--tool-dependency', action='store_true', required=False, default=False, help='Optional toggle if this gem should be added as a tool dependency') - add_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, + parser.add_argument('-sd', '--server-dependency', action='store_true', required=False, default=False, help='Optional toggle if this gem should be added as a server dependency') - add_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, + parser.add_argument('-pl', '--platforms', type=str, required=False, default='Common', help='Optional list of platforms this gem should be added to.' ' Ex. --platforms Mac,Windows,Linux') - add_gem_subparser.add_argument('-a', '--add-to-cmake', type=bool, required=False, + parser.add_argument('-a', '--add-to-cmake', type=bool, required=False, default=True, help='Automatically call add-gem-to-cmake.') - add_gem_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + 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.') - add_gem_subparser.set_defaults(func=_run_add_gem_to_project) + parser.set_defaults(func=_run_add_gem_to_project) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py add-gem-to-project --project-path "D:/TestProject" --gem-path "D:/TestGem" + :param subparsers: the caller instantiates subparsers and passes it in here + """ + add_gem_project_subparser = subparsers.add_parser('add-gem-to-project') + add_parser_args(add_gem_project_subparser) + + +def main(): + """ + Runs add_gem_project.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index 3db2f077cd..1dbb584c92 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -18,18 +18,90 @@ import json import logging import pathlib import shutil +import sys import urllib.parse import urllib.request -from o3de import manifest, utils, validation +from o3de import manifest, repo, utils, validation logger = logging.getLogger() logging.basicConfig() -def download_engine(engine_name: str, - dest_path: str) -> int: +def unzip_manifest_json_data(download_zip_path: pathlib.Path, zip_file_name: str) -> dict: + json_data = {} + with zipfile.ZipFile(download_zip_path, 'r') as zip_data: + with zip_data.open(zip_file_name) as manifest_json_file: + try: + json_data = json.load(manifest_json_file) + except json.JSONDecodeError as e: + logger.error(f'UnZip exception:{str(e)}') + + return json_data + +def validate_downloaded_zip_sha256(download_uri_json_data: dict, download_zip_path: pathlib.Path, + manifest_json_name) -> int: + # if the engine.json has a sha256 check it against a sha256 of the zip + try: + sha256A = download_uri_json_data['sha256'] + except KeyError as e: + logger.warn(f'SECURITY WARNING: The advertised o3de object you downloaded has no "sha256"!!! Be VERY careful!!!' + f' We cannot verify this is the actually the advertised object!!!') + else: + sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the f{manifest_json_name}. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + manifest_json_data = unzip_manifest_json_data(download_zip_path, manifest_json_name) + + # remove the sha256 if present in the advertised downloadable manifest json + # then compare it to the json in the zip, they should now be identical + try: + del download_uri_json_data['sha256'] + except KeyError as e: + pass + + sha256A = hashlib.sha256(json.dumps(download_uri_json_data, indent=4).encode('utf8')).hexdigest() + with unzipped_manifest_json.open('r') as s: + try: + unzipped_manifest_json_data = json.load(s) + except json.JSONDecodeError as e: + logger.error(f'Failed to read manifest json {unzipped_manifest_json}. Unable to confirm this' + f' is the same template that was advertised.') + return 1 + sha256B = hashlib.sha256(json.dumps(unzipped_manifest_json_data, indent=4).encode('utf8')).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded manifest json does not match' + f' the advertised manifest json. Deleting unzipped files!!!') + shutil.rmtree(dest_path) + return 1 + + return 0 + + +def get_downloadable(engine_name: str = None, + project_name: str = None, + gem_name: str = None, + template_name: str = None, + restricted_name: str = None) -> dict or None: + json_data = manifest.load_o3de_manifest() + try: + o3de_object_uris = json_data['repos'] + except KeyError as key_err: + logger.error(f'Unable to load repos from o3de manifest: {str(key_err)}') + return None + + manifest_json = 'repo.json' + search_func = lambda: repo.search_repo(manifest_json, engine_name, project_name, gem_name, template_name) + return repo.search_o3de_object(manifest_json, o3de_object_uris, search_func) + + +def download_o3de_object(object_name: str, default_folder_name: str, dest_path: str or pathlib.Path, + object_type: str, downloadable_kwarg_key) -> int: if not dest_path: - dest_path = manifest.get_registered(default_folder='engines') + dest_path = manifest.get_registered(default_folder=default_folder_name) if not dest_path: logger.error(f'Destination path not cannot be empty.') return 1 @@ -37,512 +109,50 @@ def download_engine(engine_name: str, dest_path = pathlib.Path(dest_path).resolve() dest_path.mkdir(exist_ok=True) - download_path = manifest.get_o3de_download_folder() / 'engines' / engine_name + download_path = manifest.get_o3de_download_folder() / default_folder_name / object_name download_path.mkdir(exist_ok=True) - download_zip_path = download_path / 'engine.zip' + download_zip_path = download_path / f'{object_type}.zip' - downloadable_engine_data = get_downloadable(engine_name=engine_name) - if not downloadable_engine_data: - logger.error(f'Downloadable engine {engine_name} not found.') + downloadable_object_data = get_downloadable(**{downloadable_kwarg_key : object_name}) + if not downloadable_object_data: + logger.error(f'Downloadable o3de object {object_name} not found.') return 1 - origin = downloadable_engine_data['origin'] - url = f'{origin}/project.zip' + origin = downloadable_json_data['origin'] + url = f'{origin}/object_type.zip' parsed_uri = urllib.parse.urlparse(url) - if download_zip_path.is_file(): - logger.warn(f'Project already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) + download_zip_result = utils.download_zip_file(parsed_uri, download_zip_path) + if download_zip_result != 0: + return download_zip_result - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Engine zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 + return validate_downloaded_zip_sha256(downloadable_object_data, download_zip_path) - # if the engine.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_engine_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised engine you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised engine!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded engine.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the engine.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - dest_engine_folder = dest_path / engine_name - if dest_engine_folder.is_dir(): - utils.backup_folder(dest_engine_folder) - with zipfile.ZipFile(download_zip_path, 'r') as project_zip: - try: - project_zip.extractall(dest_path) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_engine_json = dest_engine_folder / 'engine.json' - if not unzipped_engine_json.is_file(): - logger.error(f'Engine json {unzipped_engine_json} is missing.') - return 1 - - if not validation.valid_o3de_engine_json(unzipped_engine_json): - logger.error(f'Engine json {unzipped_engine_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable engine.json - # then compare it to the engine.json in the zip, they should now be identical - try: - del downloadable_engine_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_engine_data, indent=4).encode('utf8')).hexdigest() - with unzipped_engine_json.open('r') as s: - try: - unzipped_engine_json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to read engine json {unzipped_engine_json}. Unable to confirm this' - f' is the same template that was advertised.') - return 1 - sha256B = hashlib.sha256(json.dumps(unzipped_engine_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded engine.json does not match' - f' the advertised engine.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 +def download_engine(engine_name: str, + dest_path: str or pathlib.Path) -> int: + return download_o3de_object(engine_name, 'engines', dest_path, 'engine', 'engine_name') def download_project(project_name: str, dest_path: str or pathlib.Path) -> int: - if not dest_path: - dest_path = manifest.get_registered(default_folder='projects') - if not dest_path: - logger.error(f'Destination path not specified and not default projects path.') - return 1 - - dest_path = pathlib.Path(dest_path).resolve() - dest_path.mkdir(exist_ok=True, parents=True) - - download_path = manifest.get_o3de_download_folder() / 'projects' / project_name - download_path.mkdir(exist_ok=True, parents=True) - download_zip_path = download_path / 'project.zip' - - downloadable_project_data = get_downloadable(project_name=project_name) - if not downloadable_project_data: - logger.error(f'Downloadable project {project_name} not found.') - return 1 - - origin = downloadable_project_data['origin'] - url = f'{origin}/project.zip' - parsed_uri = urllib.parse.urlparse(url) - - if download_zip_path.is_file(): - logger.warn(f'Project already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) - - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Project zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 - - # if the project.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_project_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised project you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised project!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded project.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the project.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - dest_project_folder = dest_path / project_name - if dest_project_folder.is_dir(): - utils.backup_folder(dest_project_folder) - with zipfile.ZipFile(download_zip_path, 'r') as project_zip: - try: - project_zip.extractall(dest_project_folder) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_project_json = dest_project_folder / 'project.json' - if not unzipped_project_json.is_file(): - logger.error(f'Project json {unzipped_project_json} is missing.') - return 1 - - if not validation.valid_o3de_project_json(unzipped_project_json): - logger.error(f'Project json {unzipped_project_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable project.json - # then compare it to the project.json in the zip, they should now be identical - try: - del downloadable_project_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_project_data, indent=4).encode('utf8')).hexdigest() - with unzipped_project_json.open('r') as s: - try: - unzipped_project_json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to read Project json {unzipped_project_json}. Unable to confirm this' - f' is the same project that was advertised.') - return 1 - sha256B = hashlib.sha256(json.dumps(unzipped_project_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded project.json does not match' - f' the advertised project.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 + return download_o3de_object(project_name, 'projects', dest_path, 'project', 'project_name') def download_gem(gem_name: str, dest_path: str or pathlib.Path) -> int: - if not dest_path: - dest_path = manifest.get_registered(default_folder='gems') - if not dest_path: - logger.error(f'Destination path not cannot be empty.') - return 1 - - dest_path = pathlib.Path(dest_path).resolve() - dest_path.mkdir(exist_ok=True, parents=True) - - download_path = manifest.get_o3de_download_folder() / 'gems' / gem_name - download_path.mkdir(exist_ok=True, parents=True) - download_zip_path = download_path / 'gem.zip' - - downloadable_gem_data = get_downloadable(gem_name=gem_name) - if not downloadable_gem_data: - logger.error(f'Downloadable gem {gem_name} not found.') - return 1 - - origin = downloadable_gem_data['origin'] - url = f'{origin}/gem.zip' - parsed_uri = urllib.parse.urlparse(url) - - if download_zip_path.is_file(): - logger.warn(f'Project already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) - - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Gem zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 - - # if the gem.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_gem_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised gem you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised gem!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded gem.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the gem.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - dest_gem_folder = dest_path / gem_name - if dest_gem_folder.is_dir(): - utils.backup_folder(dest_gem_folder) - with zipfile.ZipFile(download_zip_path, 'r') as gem_zip: - try: - gem_zip.extractall(dest_path) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_gem_json = dest_gem_folder / 'gem.json' - if not unzipped_gem_json.is_file(): - logger.error(f'Engine json {unzipped_gem_json} is missing.') - return 1 - - if not validation.valid_o3de_engine_json(unzipped_gem_json): - logger.error(f'Engine json {unzipped_gem_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable gem.json - # then compare it to the gem.json in the zip, they should now be identical - try: - del downloadable_gem_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_gem_data, indent=4).encode('utf8')).hexdigest() - with unzipped_gem_json.open('r') as s: - try: - unzipped_gem_json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to read gem json {unzipped_gem_json}. Unable to confirm this' - f' is the same gem that was advertised.') - return 1 - sha256B = hashlib.sha256(json.dumps(unzipped_gem_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded gem.json does not match' - f' the advertised gem.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 + return download_o3de_object(gem_name, 'gems', dest_path, 'gem', 'gem_name') def download_template(template_name: str, dest_path: str or pathlib.Path) -> int: - if not dest_path: - dest_path = manifest.get_registered(default_folder='templates') - if not dest_path: - logger.error(f'Destination path not cannot be empty.') - return 1 + return download_o3de_object(template_name, 'templates', dest_path, 'template', 'template_name') - dest_path = pathlib.Path(dest_path).resolve() - dest_path.mkdir(exist_ok=True, parents=True) - - download_path = manifest.get_o3de_download_folder() / 'templates' / template_name - download_path.mkdir(exist_ok=True, parents=True) - download_zip_path = download_path / 'template.zip' - - downloadable_template_data = get_downloadable(template_name=template_name) - if not downloadable_template_data: - logger.error(f'Downloadable template {template_name} not found.') - return 1 - - origin = downloadable_template_data['origin'] - url = f'{origin}/project.zip' - parsed_uri = urllib.parse.urlparse(url) - - result = 0 - - if download_zip_path.is_file(): - logger.warn(f'Project already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) - - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Template zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 - - # if the template.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_template_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised template you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised template!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded template.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the template.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - dest_template_folder = dest_path / template_name - if dest_template_folder.is_dir(): - utils.backup_folder(dest_template_folder) - with zipfile.ZipFile(download_zip_path, 'r') as project_zip: - try: - project_zip.extractall(dest_path) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_template_json = dest_template_folder / 'template.json' - if not unzipped_template_json.is_file(): - logger.error(f'Template json {unzipped_template_json} is missing.') - return 1 - - if not validation.valid_o3de_engine_json(unzipped_template_json): - logger.error(f'Template json {unzipped_template_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable template.json - # then compare it to the template.json in the zip, they should now be identical - try: - del downloadable_template_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_template_data, indent=4).encode('utf8')).hexdigest() - with unzipped_template_json.open('r') as s: - try: - unzipped_template_json_data = json.load(s) - except Exception as e: - logger.error(f'Failed to read Template json {unzipped_template_json}. Unable to confirm this' - f' is the same template that was advertised.') - return 1 - sha256B = hashlib.sha256(json.dumps(unzipped_template_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded template.json does not match' - f' the advertised template.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 def download_restricted(restricted_name: str, dest_path: str or pathlib.Path) -> int: - if not dest_path: - dest_path = manifest.get_registered(default_folder='restricted') - if not dest_path: - logger.error(f'Destination path not cannot be empty.') - return 1 - - dest_path = pathlib.Path(dest_path).resolve() - dest_path.mkdir(exist_ok=True, parents=True) - - download_path = manifest.get_o3de_download_folder() / 'restricted' / restricted_name - download_path.mkdir(exist_ok=True, parents=True) - download_zip_path = download_path / 'restricted.zip' - - downloadable_restricted_data = get_downloadable(restricted_name=restricted_name) - if not downloadable_restricted_data: - logger.error(f'Downloadable Restricted {restricted_name} not found.') - return 1 - - origin = downloadable_restricted_data['origin'] - url = f'{origin}/restricted.zip' - parsed_uri = urllib.parse.urlparse(url) - - if download_zip_path.is_file(): - logger.warn(f'Restricted already downloaded to {download_zip_path}.') - elif parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(url) as s: - with download_zip_path.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, download_zip_path) - - if not zipfile.is_zipfile(download_zip_path): - logger.error(f"Restricted zip {download_zip_path} is invalid.") - download_zip_path.unlink() - return 1 - - # if the restricted.json has a sha256 check it against a sha256 of the zip - try: - sha256A = downloadable_restricted_data['sha256'] - except Exception as e: - logger.warn(f'SECURITY WARNING: The advertised restricted you downloaded has no "sha256"!!! Be VERY careful!!!' - f' We cannot verify this is the actually the advertised restricted!!!') - else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded restricted.zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the restricted.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - dest_restricted_folder = dest_path / restricted_name - if dest_restricted_folder.is_dir(): - utils.backup_folder(dest_restricted_folder) - with zipfile.ZipFile(download_zip_path, 'r') as project_zip: - try: - project_zip.extractall(dest_path) - except Exception as e: - logger.error(f'UnZip exception:{str(e)}') - shutil.rmtree(dest_path) - return 1 - - unzipped_restricted_json = dest_restricted_folder / 'restricted.json' - if not unzipped_restricted_json.is_file(): - logger.error(f'Restricted json {unzipped_restricted_json} is missing.') - return 1 - - if not validation.valid_o3de_engine_json(unzipped_restricted_json): - logger.error(f'Restricted json {unzipped_restricted_json} is invalid.') - return 1 - - # remove the sha256 if present in the advertised downloadable restricted.json - # then compare it to the restricted.json in the zip, they should now be identical - try: - del downloadable_restricted_data['sha256'] - except Exception as e: - pass - - sha256A = hashlib.sha256(json.dumps(downloadable_restricted_data, indent=4).encode('utf8')).hexdigest() - with unzipped_restricted_json.open('r') as s: - try: - unzipped_restricted_json_data = json.load(s) - except Exception as e: - logger.error( - f'Failed to read Restricted json {unzipped_restricted_json}. Unable to confirm this' - f' is the same restricted that was advertised.') - return 1 - sha256B = hashlib.sha256( - json.dumps(unzipped_restricted_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded restricted.json does not match' - f' the advertised restricted.json. Deleting unzipped files!!!') - shutil.rmtree(dest_path) - return 1 - - return 0 + return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name') def _run_download(args: argparse) -> int: @@ -562,20 +172,16 @@ def _run_download(args: argparse) -> int: return download_template(args.template_name, args.dest_path) + return 1 -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here + Ex. Directly run from this file alone with: python download.py --engine-name "o3de" + :param parser: the caller passes an argparse parser like instance to this method """ - download_subparser = subparsers.add_parser('download') - group = download_subparser.add_mutually_exclusive_group(required=True) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-e', '--engine-name', type=str, required=False, help='Downloadable engine name.') group.add_argument('-p', '--project-name', type=str, required=False, @@ -584,15 +190,52 @@ def add_args(parser, subparsers) -> None: help='Downloadable gem name.') group.add_argument('-t', '--template-name', type=str, required=False, help='Downloadable template name.') - download_subparser.add_argument('-dp', '--dest-path', type=str, required=False, + parser.add_argument('-dp', '--dest-path', type=str, required=False, default=None, help='Optional destination folder to download into.' - ' i.e. download --project-name "StarterGame" --dest-path "C:/projects"' - ' will result in C:/projects/StarterGame' + ' i.e. download --project-name "AstomSamplerViewer" --dest-path "C:/projects"' + ' will result in C:/projects/AtomSampleViewer' ' If blank will download to default object type folder') - download_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + 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.') - download_subparser.set_defaults(func=_run_download) + parser.set_defaults(func=_run_download) + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py download --engine-name "o3de" + :param subparsers: the caller instantiates subparsers and passes it in here + """ + download_subparser = subparsers.add_parser('download') + add_parser_args(download_subparser) + + +def main(): + """ + Runs download.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index 324c204a43..0c63d4e42e 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -79,7 +79,7 @@ restricted_platforms = { } template_file_name = 'template.json' - +this_script_parent = os.path.dirname(os.path.realpath(__file__)) def _transform(s_data: str, replacements: list, @@ -329,7 +329,7 @@ def _instantiate_template(template_json_data: dict, with open(platform_json, 'r') as s: try: json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Failed to load {platform_json}: ' + str(e)) return 1 else: @@ -407,7 +407,7 @@ def create_template(source_path: str, template_path = f'{default_templates_folder}/{template_path}' logger.info(f'Template path not a full path. Using default templates folder {template_path}') if os.path.isdir(template_path): - logger.error(f'Template path {template_path} is already exists.') + logger.error(f'Template path {template_path} already exists.') return 1 # template name is now the last component of the template_path @@ -432,12 +432,12 @@ def create_template(source_path: str, with open(engine_json) as s: try: engine_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f"Failed to read engine json {engine_json}: {str(e)}") return 1 try: engine_restricted = engine_json_data['restricted_name'] - except Exception as e: + except KeyError as e: logger.error(f"Engine json {engine_json} restricted not found.") return 1 engine_restricted_folder = manifest.get_registered(restricted_name=engine_restricted) @@ -475,12 +475,12 @@ def create_template(source_path: str, with open(restricted_json, 'r') as s: try: restricted_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Failed to load {restricted_json}: ' + str(e)) return 1 try: template_restricted_name = restricted_json_data['restricted_name'] - except Exception as e: + except KeyError as e: logger.error(f'Failed to read restricted_name from {restricted_json}') return 1 else: @@ -943,8 +943,7 @@ def create_template(source_path: str, s.write(json.dumps(json_data, indent=4)) # copy the default preview.png - this_script_parent = os.path.dirname(os.path.realpath(__file__)) - preview_png_src = f'{this_script_parent}/preview.png' + preview_png_src = f'{this_script_parent}/resources/preview.png' preview_png_dst = f'{template_path}/Template/preview.png' if not os.path.isfile(preview_png_dst): shutil.copy(preview_png_src, preview_png_dst) @@ -1067,14 +1066,14 @@ def create_from_template(destination_path: str, with open(template_json) as s: try: template_json_data = json.load(s) - except Exception as e: + except KeyError as e: logger.error(f'Could read template json {template_json}: {str(e)}.') return 1 # read template name from the json try: template_name = template_json_data['template_name'] - except Exception as e: + except KeyError as e: logger.error(f'Could not read "template_name" from template json {template_json}: {str(e)}.') return 1 @@ -1083,7 +1082,7 @@ def create_from_template(destination_path: str, if not template_restricted_name and not template_restricted_path: try: template_json_restricted_name = template_json_data['restricted_name'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".') else: @@ -1100,7 +1099,7 @@ def create_from_template(destination_path: str, # The user specified a --template-restricted-name try: template_json_restricted_name = template_json_data['restricted_name'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_name}') @@ -1120,7 +1119,7 @@ def create_from_template(destination_path: str, template_restricted_path = template_restricted_path.replace('\\', '/') try: template_json_restricted_name = template_json_data['restricted_name'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_path}') @@ -1154,7 +1153,7 @@ def create_from_template(destination_path: str, try: template_json_restricted_platform_relative_path = template_json_data[ 'restricted_platform_relative_path'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_platform_relative_path' element warn and use it logger.info(f'The template does not specify a "restricted_platform_relative_path".' f' Using {template_restricted_platform_relative_path}') @@ -1175,7 +1174,7 @@ def create_from_template(destination_path: str, try: template_restricted_platform_relative_path = template_json_data[ 'restricted_platform_relative_path'] - except Exception as e: + except KeyError as e: # The template json doesn't have a 'restricted_platform_relative_path' element, set empty string. template_restricted_platform_relative_path = '' @@ -1356,14 +1355,14 @@ def create_project(project_path: str, with open(template_json) as s: try: template_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Could read template json {template_json}: {str(e)}.') return 1 # read template name from the json try: template_name = template_json_data['template_name'] - except Exception as e: + except KeyError as e: logger.error(f'Could not read "template_name" from template json {template_json}: {str(e)}.') return 1 @@ -1372,7 +1371,7 @@ def create_project(project_path: str, if not template_restricted_name and not template_restricted_path: try: template_json_restricted_name = template_json_data['restricted_name'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".') else: @@ -1389,7 +1388,7 @@ def create_project(project_path: str, # The user specified a --template-restricted-name try: template_json_restricted_name = template_json_data['restricted_name'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_name}') @@ -1409,7 +1408,7 @@ def create_project(project_path: str, template_restricted_path = template_restricted_path.replace('\\', '/') try: template_json_restricted_name = template_json_data['restricted_name'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_path}') @@ -1442,7 +1441,7 @@ def create_project(project_path: str, try: template_json_restricted_platform_relative_path = template_json_data[ 'restricted_platform_relative_path'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_platform_relative_path' element warn and use it logger.info(f'The template does not specify a "restricted_platform_relative_path".' f' Using {template_restricted_platform_relative_path}') @@ -1463,7 +1462,7 @@ def create_project(project_path: str, try: template_restricted_platform_relative_path = template_json_data[ 'restricted_platform_relative_path'] - except Exception as e: + except KeyError as e: # The template json doesn't have a 'restricted_platform_relative_path' element, set empty string. template_restricted_platform_relative_path = '' if not template_restricted_platform_relative_path: @@ -1597,13 +1596,13 @@ def create_project(project_path: str, with open(restricted_json, 'r') as s: try: restricted_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Failed to load restricted json {restricted_json}.') return 1 try: restricted_name = restricted_json_data["restricted_name"] - except Exception as e: + except KeyError as e: logger.error(f'Failed to read "restricted_name" from restricted json {restricted_json}.') return 1 @@ -1616,7 +1615,7 @@ def create_project(project_path: str, with open(project_json, 'r') as s: try: project_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Failed to load project json {project_json}.') return 1 @@ -1625,7 +1624,7 @@ def create_project(project_path: str, with open(project_json, 'w') as s: try: s.write(json.dumps(project_json_data, indent=4)) - except Exception as e: + except OSError as e: logger.error(f'Failed to write project json {project_json}.') return 1 @@ -1656,7 +1655,7 @@ def create_project(project_path: str, engine_json_data = manifest.get_engine_json_data(engine_path=manifest.get_this_engine_path()) try: engine_name = engine_json_data['engine_name'] - except Exception as e: + except KeyError as e: logger.error(f"engine_name for this engine not found in engine.json.") return 1 @@ -1665,7 +1664,7 @@ def create_project(project_path: str, with open(project_json, 'w') as s: try: s.write(json.dumps(project_json_data, indent=4)) - except Exception as e: + except OSError as e: logger.error(f'Failed to write project json at {project_path}.') return 1 @@ -1749,14 +1748,14 @@ def create_gem(gem_path: str, with open(template_json) as s: try: template_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Could read template json {template_json}: {str(e)}.') return 1 # read template name from the json try: template_name = template_json_data['template_name'] - except Exception as e: + except KeyError as e: logger.error(f'Could not read "template_name" from template json {template_json}: {str(e)}.') return 1 @@ -1765,7 +1764,7 @@ def create_gem(gem_path: str, if not template_restricted_name and not template_restricted_path: try: template_json_restricted_name = template_json_data['restricted_name'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".') else: @@ -1781,7 +1780,7 @@ def create_gem(gem_path: str, # The user specified a --template-restricted-name try: template_json_restricted_name = template_json_data['restricted_name'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_name}') @@ -1801,7 +1800,7 @@ def create_gem(gem_path: str, template_restricted_path = template_restricted_path.replace('\\', '/') try: template_json_restricted_name = template_json_data['restricted_name'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_name' element warn and use it logger.info(f'The template does not specify a "restricted_name".' f' Using supplied {template_restricted_path}') @@ -1833,7 +1832,7 @@ def create_gem(gem_path: str, try: template_json_restricted_platform_relative_path = template_json_data[ 'restricted_platform_relative_path'] - except Exception as e: + except KeyError as e: # the template json doesn't have a 'restricted_platform_relative_path' element warn and use it logger.info(f'The template does not specify a "restricted_platform_relative_path".' f' Using {template_restricted_platform_relative_path}') @@ -1854,7 +1853,7 @@ def create_gem(gem_path: str, try: template_restricted_platform_relative_path = template_json_data[ 'restricted_platform_relative_path'] - except Exception as e: + except KeyError as e: # The template json doesn't have a 'restricted_platform_relative_path' element, set empty string. template_restricted_platform_relative_path = '' if not template_restricted_platform_relative_path: @@ -1988,13 +1987,13 @@ def create_gem(gem_path: str, with open(restricted_json, 'r') as s: try: restricted_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Failed to load restricted json {restricted_json}.') return 1 try: restricted_name = restricted_json_data["restricted_name"] - except Exception as e: + except KeyError as e: logger.error(f'Failed to read "restricted_name" from restricted json {restricted_json}.') return 1 @@ -2007,7 +2006,7 @@ def create_gem(gem_path: str, with open(gem_json, 'r') as s: try: gem_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Failed to load gem json {gem_json}.') return 1 @@ -2016,7 +2015,7 @@ def create_gem(gem_path: str, with open(gem_json, 'w') as s: try: s.write(json.dumps(gem_json_data, indent=4)) - except Exception as e: + except OSError as e: logger.error(f'Failed to write project json {gem_json}.') return 1 @@ -2110,15 +2109,14 @@ def _run_create_gem(args: argparse) -> int: args.module_id) -def add_args(parser, subparsers) -> None: +def add_args(subparsers) -> None: """ add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be invoked locally or aggregated by a central python file. - Ex. Directly run from this file alone with: python engine_template.py create_gem --gem-path TestGem + Ex. Directly run from this file alone with: python engine_template.py create-gem --gem-path TestGem OR o3de.py can aggregate commands by importing engine_template, - call add_args and execute: python o3de.py create_gem --gem-path TestGem - :param parser: the caller instantiates a parser and passes it in here + call add_args and execute: python o3de.py create-gem --gem-path TestGem :param subparsers: the caller instantiates subparsers and passes it in here """ # turn a directory into a template @@ -2438,13 +2436,12 @@ if __name__ == "__main__": the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) # add args to the parser - add_args(the_parser, the_subparsers) + add_args(the_subparsers) # parse args the_args = the_parser.parse_args() # run - ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 # return diff --git a/scripts/o3de/o3de/get_registration.py b/scripts/o3de/o3de/get_registration.py index c38d4d1cfb..d51600826c 100644 --- a/scripts/o3de/o3de/get_registration.py +++ b/scripts/o3de/o3de/get_registration.py @@ -11,6 +11,7 @@ import argparse import pathlib +import sys from o3de import manifest @@ -27,19 +28,14 @@ def _run_get_registered(args: argparse) -> str or pathlib.Path: args.restricted_name) -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here + Ex. Directly run from this file alone with: python get_registration.py --engine-name "o3de" + :param parser: the caller passes an argparse parser like instance to this method """ - get_registered_subparser = subparsers.add_parser('get-registered') - group = get_registered_subparser.add_mutually_exclusive_group(required=True) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-en', '--engine-name', type=str, required=False, help='Engine name.') group.add_argument('-pn', '--project-name', type=str, required=False, @@ -56,7 +52,45 @@ def add_args(parser, subparsers) -> None: group.add_argument('-rsn', '--restricted-name', type=str, required=False, help='Restricted name.') - get_registered_subparser.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.') + 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.') - get_registered_subparser.set_defaults(func=_run_get_registered) + parser.set_defaults(func=_run_get_registered) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py get-registered --engine-name "o3de" + :param subparsers: the caller instantiates subparsers and passes it in here + """ + get_registered_subparser = subparsers.add_parser('get-registered') + add_parser_args(get_registered_subparser) + + +def main(): + """ + Runs get_registration.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/global_project.py b/scripts/o3de/o3de/global_project.py index 1a17e3b79e..787e676a7e 100644 --- a/scripts/o3de/o3de/global_project.py +++ b/scripts/o3de/o3de/global_project.py @@ -52,17 +52,17 @@ def set_global_project(project_name: str or None, with bootstrap_setreg_file.open('r') as f: try: json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Bootstrap.setreg failed to load: {str(e)}') else: try: json_data["Amazon"]["AzCore"]["Bootstrap"]["project_path"] = project_path - except Exception as e: + except KeyError as e: logger.error(f'Bootstrap.setreg failed to load: {str(e)}') else: try: os.unlink(bootstrap_setreg_file) - except Exception as e: + except OSError as e: logger.error(f'Failed to unlink bootstrap file {bootstrap_setreg_file}: {str(e)}') return 1 else: @@ -88,12 +88,12 @@ def get_global_project() -> pathlib.Path or None: with bootstrap_setreg_file.open('r') as f: try: json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Bootstrap.setreg failed to load: {str(e)}') else: try: project_path = json_data["Amazon"]["AzCore"]["Bootstrap"]["project_path"] - except Exception as e: + except KeyError as e: logger.error(f'Bootstrap.setreg cannot find Amazon:AzCore:Bootstrap:project_path: {str(e)}') else: return pathlib.Path(project_path).resolve() @@ -118,7 +118,7 @@ def _run_set_global_project(args: argparse) -> int: args.project_path) -def add_args(parser, subparsers) -> None: +def add_args(subparsers) -> None: """ add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be invoked locally or aggregated by a central python file. @@ -126,7 +126,6 @@ def add_args(parser, subparsers) -> None: OR o3de.py can aggregate commands by importing global_project, call add_args and execute: python o3de.py set_global_project --project-path C:/TestProject - :param parser: the caller instantiates a parser and passes it in here :param subparsers: the caller instantiates subparsers and passes it in here """ get_global_project_subparser = subparsers.add_parser('get-global-project') @@ -156,7 +155,7 @@ if __name__ == "__main__": the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) # add args to the parser - add_args(the_parser, the_subparsers) + add_args(the_subparsers) # parse args the_args = the_parser.parse_args() diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 44d6ff1b61..6c14c2533f 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -176,7 +176,7 @@ def load_o3de_manifest() -> dict: with get_o3de_manifest().open('r') as f: try: json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Manifest json failed to load: {str(e)}') return {} else: @@ -187,7 +187,7 @@ def save_o3de_manifest(json_data: dict) -> None: with get_o3de_manifest().open('w') as s: try: s.write(json.dumps(json_data, indent=4)) - except Exception as e: + except OSError as e: logger.error(f'Manifest json failed to save: {str(e)}') @@ -331,7 +331,7 @@ def get_engine_json_data(engine_name: str = None, with engine_json.open('r') as f: try: engine_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{engine_json} failed to load: {str(e)}') else: return engine_json_data @@ -364,7 +364,7 @@ def get_project_json_data(project_name: str = None, with project_json.open('r') as f: try: project_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{project_json} failed to load: {str(e)}') else: return project_json_data @@ -397,7 +397,7 @@ def get_gem_json_data(gem_name: str = None, with gem_json.open('r') as f: try: gem_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{gem_json} failed to load: {str(e)}') else: return gem_json_data @@ -430,7 +430,7 @@ def get_template_json_data(template_name: str = None, with template_json.open('r') as f: try: template_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{template_json} failed to load: {str(e)}') else: return template_json_data @@ -463,7 +463,7 @@ def get_restricted_data(restricted_name: str = None, with restricted_json.open('r') as f: try: restricted_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{restricted_json} failed to load: {str(e)}') else: return restricted_json_data @@ -488,7 +488,7 @@ def get_registered(engine_name: str = None, with engine_json.open('r') as f: try: engine_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{engine_json} failed to load: {str(e)}') else: this_engines_name = engine_json_data['engine_name'] @@ -505,7 +505,7 @@ def get_registered(engine_name: str = None, with project_json.open('r') as f: try: project_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{project_json} failed to load: {str(e)}') else: this_projects_name = project_json_data['project_name'] @@ -522,7 +522,7 @@ def get_registered(engine_name: str = None, with gem_json.open('r') as f: try: gem_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{gem_json} failed to load: {str(e)}') else: this_gems_name = gem_json_data['gem_name'] @@ -539,7 +539,7 @@ def get_registered(engine_name: str = None, with template_json.open('r') as f: try: template_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{template_path} failed to load: {str(e)}') else: this_templates_name = template_json_data['template_name'] @@ -556,7 +556,7 @@ def get_registered(engine_name: str = None, with restricted_json.open('r') as f: try: restricted_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{restricted_json} failed to load: {str(e)}') else: this_restricted_name = restricted_json_data['restricted_name'] @@ -591,7 +591,7 @@ def get_registered(engine_name: str = None, with repo.open('r') as f: try: repo_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{cache_file} failed to load: {str(e)}') else: this_repos_name = repo_json_data['repo_name'] diff --git a/scripts/o3de/o3de/print_registration.py b/scripts/o3de/o3de/print_registration.py index 7900fad7e4..292f2224bc 100644 --- a/scripts/o3de/o3de/print_registration.py +++ b/scripts/o3de/o3de/print_registration.py @@ -13,6 +13,7 @@ import argparse import json import hashlib import logging +import sys import urllib.parse from o3de import manifest, validation @@ -143,7 +144,7 @@ def print_engines_data(engines_data: dict) -> None: with engine_json.open('r') as f: try: engine_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{engine_json} failed to load: {str(e)}') else: print(engine_json) @@ -170,7 +171,7 @@ def print_projects_data(projects_data: dict) -> None: with project_json.open('r') as f: try: project_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{project_json} failed to load: {str(e)}') else: print(project_json) @@ -197,7 +198,7 @@ def print_gems_data(gems_data: dict) -> None: with gem_json.open('r') as f: try: gem_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{gem_json} failed to load: {str(e)}') else: print(gem_json) @@ -224,7 +225,7 @@ def print_templates_data(templates_data: dict) -> None: with template_json.open('r') as f: try: template_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{template_json} failed to load: {str(e)}') else: print(template_json) @@ -243,7 +244,7 @@ def print_repos_data(repos_data: dict) -> None: with cache_file.open('r') as s: try: repo_json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{cache_file} failed to load: {str(e)}') else: print(f'{repo_uri}/repo.json cached as:') @@ -260,7 +261,7 @@ def print_restricted_data(restricted_data: dict) -> None: with restricted_json.open('r') as f: try: restricted_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.warn(f'{restricted_json} failed to load: {str(e)}') else: print(restricted_json) @@ -365,19 +366,14 @@ def _run_register_show(args: argparse) -> int: return 0 -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here + Ex. Directly run from this file alone with: python print_registration.py --engine-projects + :param parser: the caller passes an argparse parser like instance to this method """ - register_show_subparser = subparsers.add_parser('register-show') - group = register_show_subparser.add_mutually_exclusive_group(required=False) + 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.') @@ -446,11 +442,49 @@ def add_args(parser, subparsers) -> None: default=False, help='Combine all repos templates into a single list of resources.') - register_show_subparser.add_argument('-v', '--verbose', action='count', required=False, + parser.add_argument('-v', '--verbose', action='count', required=False, default=0, help='How verbose do you want the output to be.') - register_show_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + 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.') - register_show_subparser.set_defaults(func=_run_register_show) \ No newline at end of file + parser.set_defaults(func=_run_register_show) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py register-show --engine-projects + :param subparsers: the caller instantiates subparsers and passes it in here + """ + register_show_subparser = subparsers.add_parser('register-show') + add_parser_args(register_show_subparser) + + +def main(): + """ + Runs print_registration.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index d6a734e1fd..c44af03b30 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -19,6 +19,7 @@ import json import os import pathlib import shutil +import sys import urllib.parse import urllib.request @@ -134,172 +135,74 @@ def register_all_in_folder(folder_path: str or pathlib.Path, return ret_val -def register_all_engines_in_folder(engines_path: str or pathlib.Path, - remove: bool = False, - force: bool = False) -> int: - if not engines_path: +def register_all_o3de_objects_of_type_in_folder(o3de_object_path: str or pathlib.Path, + o3de_object_type: str, + remove: bool, + force: bool, + **register_kwargs) -> int: + if not o3de_object_path: logger.error(f'Engines path cannot be empty.') return 1 - engines_path = pathlib.Path(engines_path).resolve() - if not engines_path.is_dir(): + o3de_object_path = pathlib.Path(o3de_object_path).resolve() + if not o3de_object_path.is_dir(): logger.error(f'Engines path is not dir.') return 1 - engines_set = set() + o3de_object_type_set = set() + register_path_kwarg = f'{o3de_object_type}_path' if o3de_object_type != 'repo' else f'{o3de_object_type}_uri' ret_val = 0 - for root, dirs, files in os.walk(engines_path): - for name in files: - if name == 'engine.json': - engines_set.add(root) + for root, dirs, files in os.walk(o3de_object_path): + if f'{o3de_object_type}.json' in files: + o3de_object_type_set.add(root) + # Stop iteration of any subdirectories + # Nested o3de objects of the same type aren't supported(i.e an engine cannot be inside of a engine). + dirs[:] = [] - for engine in sorted(engines_set, reverse=True): - error_code = register(engine_path=engine, remove=remove, force=force) + for o3de_object_type_root in sorted(o3de_object_type_set, reverse=True): + error_code = register(**{register_path_kwarg: o3de_object_type_root}, + remove=remove, force=force, **register_kwargs) if error_code: ret_val = error_code return ret_val +def register_all_engines_in_folder(engines_path: str or pathlib.Path, + remove: bool = False, + force: bool = False) -> int: + return register_all_o3de_objects_of_type_in_folder(engines_path, 'engine', remove, force) + + def register_all_projects_in_folder(projects_path: str or pathlib.Path, remove: bool = False, engine_path: str or pathlib.Path = None) -> int: - if not projects_path: - logger.error(f'Projects path cannot be empty.') - return 1 - - projects_path = pathlib.Path(projects_path).resolve() - if not projects_path.is_dir(): - logger.error(f'Projects path is not dir.') - return 1 - - projects_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(projects_path): - for name in files: - if name == 'project.json': - projects_set.add(root) - - for project in sorted(projects_set, reverse=True): - error_code = register(engine_path=engine_path, project_path=project, remove=remove) - if error_code: - ret_val = error_code - - return ret_val + return register_all_o3de_objects_of_type_in_folder(projects_path, 'project', remove, False, engine_path=engine_path) def register_all_gems_in_folder(gems_path: str or pathlib.Path, remove: bool = False, engine_path: str or pathlib.Path = None) -> int: - if not gems_path: - logger.error(f'Gems path cannot be empty.') - return 1 - - gems_path = pathlib.Path(gems_path).resolve() - if not gems_path.is_dir(): - logger.error(f'Gems path is not dir.') - return 1 - - gems_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(gems_path): - for name in files: - if name == 'gem.json': - gems_set.add(root) - - for gem in sorted(gems_set, reverse=True): - error_code = register(engine_path=engine_path, gem_path=gem, remove=remove) - if error_code: - ret_val = error_code - - return ret_val + return register_all_o3de_objects_of_type_in_folder(gems_path, 'gem', remove, False, engine_path=engine_path) def register_all_templates_in_folder(templates_path: str or pathlib.Path, remove: bool = False, engine_path: str or pathlib.Path = None) -> int: - if not templates_path: - logger.error(f'Templates path cannot be empty.') - return 1 - - templates_path = pathlib.Path(templates_path).resolve() - if not templates_path.is_dir(): - logger.error(f'Templates path is not dir.') - return 1 - - templates_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(templates_path): - for name in files: - if name == 'template.json': - templates_set.add(root) - - for template in sorted(templates_set, reverse=True): - error_code = register(engine_path=engine_path, template_path=template, remove=remove) - if error_code: - ret_val = error_code - - return ret_val + return register_all_o3de_objects_of_type_in_folder(templates_path, 'template', remove, False, engine_path=engine_path) def register_all_restricted_in_folder(restricted_path: str or pathlib.Path, remove: bool = False, engine_path: str or pathlib.Path = None) -> int: - if not restricted_path: - logger.error(f'Restricted path cannot be empty.') - return 1 - - restricted_path = pathlib.Path(restricted_path).resolve() - if not restricted_path.is_dir(): - logger.error(f'Restricted path is not dir.') - return 1 - - restricted_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(restricted_path): - for name in files: - if name == 'restricted.json': - restricted_set.add(root) - - for restricted in sorted(restricted_set, reverse=True): - error_code = register(engine_path=engine_path, restricted_path=restricted, remove=remove) - if error_code: - ret_val = error_code - - return ret_val + return register_all_o3de_objects_of_type_in_folder(restricted_path, 'restricted', remove, False, engine_path=engine_path) def register_all_repos_in_folder(repos_path: str or pathlib.Path, remove: bool = False, engine_path: str or pathlib.Path = None) -> int: - if not repos_path: - logger.error(f'Repos path cannot be empty.') - return 1 - - repos_path = pathlib.Path(repos_path).resolve() - if not repos_path.is_dir(): - logger.error(f'Repos path is not dir.') - return 1 - - repo_set = set() - - ret_val = 0 - for root, dirs, files in os.walk(repos_path): - for name in files: - if name == 'repo.json': - repo_set.add(root) - - for repo in sorted(repo_set, reverse=True): - error_code = register(engine_path=engine_path, repo_uri=repo, remove=remove) - if error_code: - ret_val = error_code - - return ret_val + return register_all_o3de_objects_of_type_in_folder(repos_path, 'repo', remove, force, engine_path=engine_path) def remove_engine_name_to_path(json_data: dict, @@ -395,21 +298,13 @@ def register_gem_path(json_data: dict, logger.error(f'Engine path {engine_path} is not registered.') return 1 - while gem_path in engine_data['gems']: - engine_data['gems'].remove(gem_path) - - while gem_path.as_posix() in engine_data['gems']: - engine_data['gems'].remove(gem_path.as_posix()) + engine_data['gems'] = list(filter(lambda p: gem_path != pathlib.Path(p), engine_data['gems'])) if remove: logger.warn(f'Removing Gem path {gem_path}.') return 0 else: - while gem_path in json_data['gems']: - json_data['gems'].remove(gem_path) - - while gem_path.as_posix() in json_data['gems']: - json_data['gems'].remove(gem_path.as_posix()) + json_data['gems'] = list(filter(lambda p: gem_path != pathlib.Path(p), json_data['gems'])) if remove: logger.warn(f'Removing Gem path {gem_path}.') @@ -447,21 +342,13 @@ def register_project_path(json_data: dict, logger.error(f'Engine path {engine_path} is not registered.') return 1 - while project_path in engine_data['projects']: - engine_data['projects'].remove(project_path) - - while project_path.as_posix() in engine_data['projects']: - engine_data['projects'].remove(project_path.as_posix()) + engine_data['projects'] = list(filter(lambda p: project_path != pathlib.Path(p), engine_data['projects'])) if remove: logger.warn(f'Engine {engine_path} removing Project path {project_path}.') return 0 else: - while project_path in json_data['projects']: - json_data['projects'].remove(project_path) - - while project_path.as_posix() in json_data['projects']: - json_data['projects'].remove(project_path.as_posix()) + json_data['projects'] = list(filter(lambda p: project_path != pathlib.Path(p), json_data['projects'])) if remove: logger.warn(f'Removing Project path {project_path}.') @@ -486,20 +373,20 @@ def register_project_path(json_data: dict, with this_engine_json.open('r') as f: try: this_engine_json = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Engine json failed to load: {str(e)}') return 1 with project_json.open('r') as f: try: project_json_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Project json failed to load: {str(e)}') return 1 update_project_json = False try: update_project_json = project_json_data['engine'] != this_engine_json['engine_name'] - except Exception as e: + except KeyError as e: update_project_json = True if update_project_json: @@ -508,7 +395,7 @@ def register_project_path(json_data: dict, with project_json.open('w') as s: try: s.write(json.dumps(project_json_data, indent=4)) - except Exception as e: + except OSError as e: logger.error(f'Project json failed to save: {str(e)}') return 1 @@ -530,21 +417,13 @@ def register_template_path(json_data: dict, logger.error(f'Engine path {engine_path} is not registered.') return 1 - while template_path in engine_data['templates']: - engine_data['templates'].remove(template_path) - - while template_path.as_posix() in engine_data['templates']: - engine_data['templates'].remove(template_path.as_posix()) + engine_data['templates'] = list(filter(lambda p: template_path != pathlib.Path(p), engine_data['templates'])) if remove: logger.warn(f'Engine {engine_path} removing Template path {template_path}.') return 0 else: - while template_path in json_data['templates']: - json_data['templates'].remove(template_path) - - while template_path.as_posix() in json_data['templates']: - json_data['templates'].remove(template_path.as_posix()) + json_data['templates'] = list(filter(lambda p: template_path != pathlib.Path(p), json_data['templates'])) if remove: logger.warn(f'Removing Template path {template_path}.') @@ -582,21 +461,13 @@ def register_restricted_path(json_data: dict, logger.error(f'Engine path {engine_path} is not registered.') return 1 - while restricted_path in engine_data['restricted']: - engine_data['restricted'].remove(restricted_path) - - while restricted_path.as_posix() in engine_data['restricted']: - engine_data['restricted'].remove(restricted_path.as_posix()) + engine_data['restricted'] = list(filter(lambda p: restricted_path != pathlib.Path(p), engine_data['restricted'])) if remove: logger.warn(f'Engine {engine_path} removing Restricted path {restricted_path}.') return 0 else: - while restricted_path in json_data['restricted']: - json_data['restricted'].remove(restricted_path) - - while restricted_path.as_posix() in json_data['restricted']: - json_data['restricted'].remove(restricted_path.as_posix()) + json_data['restricted'] = list(filter(lambda p: restricted_path != pathlib.Path(p), json_data['restricted'])) if remove: logger.warn(f'Removing Restricted path {restricted_path}.') @@ -629,10 +500,7 @@ def register_repo(json_data: dict, url = f'{repo_uri}/repo.json' parsed_uri = urllib.parse.urlparse(url) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': + if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: while repo_uri in json_data['repos']: json_data['repos'].remove(repo_uri) else: @@ -647,118 +515,67 @@ def register_repo(json_data: dict, repo_sha256 = hashlib.sha256(url.encode()) cache_file = manifest.get_o3de_cache_folder() / str(repo_sha256.hexdigest() + '.json') - result = 0 - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - if not cache_file.is_file(): - with urllib.request.urlopen(url) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - json_data['repos'].insert(0, repo_uri) - else: - if not cache_file.is_file(): - origin_file = pathlib.Path(url).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, origin_file) + result = utils.download_file(url, cache_file) + if result == 0: json_data['repos'].insert(0, repo_uri.as_posix()) - repo_set = set() result = repo.process_add_o3de_repo(cache_file, repo_set) return result +def register_default_o3de_object_folder(json_data: dict, + default_o3de_object_folder: str or pathlib.Path, + o3de_object_key: str) -> int: + # make sure the path exists + default_o3de_object_folder = pathlib.Path(default_o3de_object_folder).resolve() + if not default_o3de_object_folder.is_dir(): + logger.error(f'Default o3de object folder {default_o3de_object_folder} does not exist.') + return 1 + + json_data[o3de_object_key] = default_o3de_object_folder.as_posix() + + return 0 + + def register_default_engines_folder(json_data: dict, default_engines_folder: str or pathlib.Path, remove: bool = False) -> int: - if remove: - default_engines_folder = manifest.get_o3de_engines_folder() - - # make sure the path exists - default_engines_folder = pathlib.Path(default_engines_folder).resolve() - if not default_engines_folder.is_dir(): - logger.error(f'Default engines folder {default_engines_folder} does not exist.') - return 1 - - default_engines_folder = default_engines_folder.as_posix() - json_data['default_engines_folder'] = default_engines_folder - - return 0 + return register_default_o3de_object_folder(json_data, + manifest.get_o3de_engines_folder() if remove else default_engines_folder, + 'default_engines_folder', remove) def register_default_projects_folder(json_data: dict, default_projects_folder: str or pathlib.Path, remove: bool = False) -> int: - if remove: - default_projects_folder = manifest.get_o3de_projects_folder() - - # make sure the path exists - default_projects_folder = pathlib.Path(default_projects_folder).resolve() - if not default_projects_folder.is_dir(): - logger.error(f'Default projects folder {default_projects_folder} does not exist.') - return 1 - - default_projects_folder = default_projects_folder.as_posix() - json_data['default_projects_folder'] = default_projects_folder - - return 0 + return register_default_o3de_object_folder(json_data, + manifest.get_o3de_projects_folder() if remove else default_projects_folder, + 'default_projects_folder', remove) def register_default_gems_folder(json_data: dict, default_gems_folder: str or pathlib.Path, remove: bool = False) -> int: - if remove: - default_gems_folder = manifest.get_o3de_gems_folder() - - # make sure the path exists - default_gems_folder = pathlib.Path(default_gems_folder).resolve() - if not default_gems_folder.is_dir(): - logger.error(f'Default gems folder {default_gems_folder} does not exist.') - return 1 - - default_gems_folder = default_gems_folder.as_posix() - json_data['default_gems_folder'] = default_gems_folder - - return 0 + return register_default_o3de_object_folder(json_data, + manifest.get_o3de_gems_folder() if remove else default_gems_folder, + 'default_gems_folder', remove) def register_default_templates_folder(json_data: dict, default_templates_folder: str or pathlib.Path, remove: bool = False) -> int: - if remove: - default_templates_folder = manifest.get_o3de_templates_folder() - - # make sure the path exists - default_templates_folder = pathlib.Path(default_templates_folder).resolve() - if not default_templates_folder.is_dir(): - logger.error(f'Default templates folder {default_templates_folder} does not exist.') - return 1 - - default_templates_folder = default_templates_folder.as_posix() - json_data['default_templates_folder'] = default_templates_folder - - return 0 + return register_default_o3de_object_folder(json_data, + manifest.get_o3de_templates_folder() if remove else default_templates_folder, + 'default_templates_folder', remove) def register_default_restricted_folder(json_data: dict, default_restricted_folder: str or pathlib.Path, - remove: bool = False) -> int: - if remove: - default_restricted_folder = manifest.get_o3de_restricted_folder() - - # make sure the path exists - default_restricted_folder = pathlib.Path(default_restricted_folder).resolve() - if not default_restricted_folder.is_dir(): - logger.error(f'Default restricted folder {default_restricted_folder} does not exist.') - return 1 - - default_restricted_folder = default_restricted_folder.as_posix() - json_data['default_restricted_folder'] = default_restricted_folder - - return 0 + reset_to_default: 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) def register(engine_path: str or pathlib.Path = None, @@ -999,20 +816,14 @@ def _run_register(args: argparse) -> int: force=args.force) -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here + Ex. Directly run from this file alone with: python register.py --engine-path "C:/o3de" + :param parser: the caller passes an argparse parser like instance to this method """ - # register - register_subparser = subparsers.add_parser('register') - group = register_subparser.add_mutually_exclusive_group(required=True) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--this-engine', action='store_true', required=False, default=False, help='Registers the engine this script is running from.') @@ -1054,12 +865,49 @@ def add_args(parser, subparsers) -> None: default=False, help='Refresh the repo cache.') - register_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + 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.') - - register_subparser.add_argument('-r', '--remove', action='store_true', required=False, + parser.add_argument('-r', '--remove', action='store_true', required=False, default=False, help='Remove entry.') - register_subparser.add_argument('-f', '--force', action='store_true', default=False, + parser.add_argument('-f', '--force', action='store_true', default=False, help='For the update of the registration field being modified.') - register_subparser.set_defaults(func=_run_register) + parser.set_defaults(func=_run_register) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py register --engine-path "C:/o3de" + :param subparsers: the caller instantiates subparsers and passes it in here + """ + register_subparser = subparsers.add_parser('register') + add_parser_args(register_subparser) + + +def main(): + """ + Runs register.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/registration.py b/scripts/o3de/o3de/registration.py deleted file mode 100755 index 801c698ca4..0000000000 --- a/scripts/o3de/o3de/registration.py +++ /dev/null @@ -1,92 +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. -# -""" -This file contains all the code that has to do with registering engines, projects, gems and templates -""" - -import argparse -import sys - - -def add_args(parser, subparsers) -> None: - """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be - invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here - """ - # register - from o3de import register - register.add_args(parser, subparsers) - - # show - from o3de import print_registration - print_registration.add_args(parser, subparsers) - - # get-registered - from o3de import get_registration - get_registration.add_args(parser, subparsers) - - # download - from o3de import download - download.add_args(parser, subparsers) - - # add external subdirectories - from o3de import add_external_subdirectory - add_external_subdirectory.add_args(parser, subparsers) - - # remove external subdirectories - from o3de import remove_external_subdirectory - remove_external_subdirectory.add_args(parser, subparsers) - - # add gems to cmake - from o3de import add_gem_cmake - add_gem_cmake.add_args(parser, subparsers) - - # remove gems from cmake - from o3de import remove_gem_cmake - remove_gem_cmake.add_args(parser, subparsers) - - # add a gem to a project - from o3de import add_gem_project - add_gem_project.add_args(parser, subparsers) - - # remove a gem from a project - from o3de import remove_gem_project - remove_gem_project.add_args(parser, subparsers) - - # sha256 - from o3de import sha256 - sha256.add_args(parser, subparsers) - - -if __name__ == "__main__": - # parse the command line args - the_parser = argparse.ArgumentParser() - - # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) - - # add args to the parser - add_args(the_parser, the_subparsers) - - # parse args - the_args = the_parser.parse_args() - - # run - ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 - - # return - sys.exit(ret) diff --git a/scripts/o3de/o3de/remove_external_subdirectory.py b/scripts/o3de/o3de/remove_external_subdirectory.py index a636474fba..b433e9c398 100644 --- a/scripts/o3de/o3de/remove_external_subdirectory.py +++ b/scripts/o3de/o3de/remove_external_subdirectory.py @@ -15,6 +15,7 @@ Implemens functinality to remove external_subdirectories from the o3de_manifests import argparse import logging import pathlib +import sys from o3de import manifest @@ -62,12 +63,58 @@ def add_args(parser, subparsers) -> None: :param parser: the caller instantiates a parser and passes it in here :param subparsers: the caller instantiates subparsers and passes it in here """ - remove_external_subdirectory_subparser = subparsers.add_parser('remove-external-subdirectory') - remove_external_subdirectory_subparser.add_argument('external_subdirectory', metavar='external_subdirectory', + + +def add_parser_args(parser): + """ + add_parser_args is called to add arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python remove_external_subdirectory.py "D:/subdir" + :param parser: the caller passes an argparse parser like instance to this method + """ + parser.add_argument('external_subdirectory', metavar='external_subdirectory', type=str, help='remove external subdirectory from cmake') - remove_external_subdirectory_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + 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.') - remove_external_subdirectory_subparser.set_defaults(func=_run_remove_external_subdirectory) + parser.set_defaults(func=_run_remove_external_subdirectory) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py remove-external-subdirectory "D:/subdir" + :param subparsers: the caller instantiates subparsers and passes it in here + """ + remove_external_subdirectory_subparser = subparsers.add_parser('remove-external-subdirectory') + add_parser_args(remove_external_subdirectory_subparser) + + +def main(): + """ + Runs remove_external_subdirectory.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/remove_gem_cmake.py b/scripts/o3de/o3de/remove_gem_cmake.py index 8f73caaad1..3d988a579a 100644 --- a/scripts/o3de/o3de/remove_gem_cmake.py +++ b/scripts/o3de/o3de/remove_gem_cmake.py @@ -15,6 +15,7 @@ Contains methods for removing a gem from a project's cmake scripts import argparse import logging import pathlib +import sys from o3de import manifest, remove_external_subdirectory @@ -64,26 +65,58 @@ def _run_remove_gem_from_cmake(args: argparse) -> int: return remove_gem_from_cmake(args.gem_name, args.gem_path) -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here + Ex. Directly run from this file alone with: python remove_gem_cmake.py --gem-name Atom + :param parser: the caller passes an argparse parser like instance to this method """ - # convenience functions to disambiguate the gem name -> gem_path and call remove-external-subdirectory on gem_path - remove_gem_from_cmake_subparser = subparsers.add_parser('remove-gem-from-cmake') - group = remove_gem_from_cmake_subparser.add_mutually_exclusive_group(required=True) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-gp', '--gem-path', type=str, required=False, help='The path to the gem.') group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') - remove_gem_from_cmake_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + 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.') - remove_gem_from_cmake_subparser.set_defaults(func=_run_remove_gem_from_cmake) + parser.set_defaults(func=_run_remove_gem_from_cmake) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py remove-gem-from-cmake --gem-name Atom + :param subparsers: the caller instantiates subparsers and passes it in here + """ + remove_gem_from_cmake_subparser = subparsers.add_parser('remove-gem-from-cmake') + add_parser_args(remove_gem_from_cmake_subparser) + + +def main(): + """ + Runs remove_gem_cmake.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/remove_gem_project.py b/scripts/o3de/o3de/remove_gem_project.py index 7644357042..671427db14 100644 --- a/scripts/o3de/o3de/remove_gem_project.py +++ b/scripts/o3de/o3de/remove_gem_project.py @@ -16,6 +16,7 @@ import argparse import logging import os import pathlib +import sys from o3de import cmake, remove_gem_cmake @@ -220,51 +221,84 @@ def _run_remove_gem_from_project(args: argparse) -> int: args.remove_from_cmake) -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here + Ex. Directly run from this file alone with: python remove_gem_project.py --project-path D:/Test --gem-name Atom + :param parser: the caller passes an argparse parser like instance to this method """ - remove_gem_subparser = subparsers.add_parser('remove-gem-from-project') - group = remove_gem_subparser.add_mutually_exclusive_group(required=True) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-pp', '--project-path', type=str, 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 = remove_gem_subparser.add_mutually_exclusive_group(required=True) + group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-gp', '--gem-path', type=str, required=False, help='The path to the gem.') group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') - remove_gem_subparser.add_argument('-gt', '--gem-target', type=str, required=False, + parser.add_argument('-gt', '--gem-target', type=str, required=False, help='The cmake target name to add. If not specified it will assume gem_name') - remove_gem_subparser.add_argument('-df', '--dependencies-file', type=str, required=False, + parser.add_argument('-df', '--dependencies-file', type=str, required=False, help='The cmake dependencies file in which the gem dependencies are specified.' 'If not specified it will assume ') - remove_gem_subparser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, + parser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, default=False, help='Optional toggle if this gem should be removed as a runtime dependency') - remove_gem_subparser.add_argument('-td', '--tool-dependency', action='store_true', required=False, + parser.add_argument('-td', '--tool-dependency', action='store_true', required=False, default=False, help='Optional toggle if this gem should be removed as a server dependency') - remove_gem_subparser.add_argument('-sd', '--server-dependency', action='store_true', required=False, + parser.add_argument('-sd', '--server-dependency', action='store_true', required=False, default=False, help='Optional toggle if this gem should be removed as a server dependency') - remove_gem_subparser.add_argument('-pl', '--platforms', type=str, required=False, + parser.add_argument('-pl', '--platforms', type=str, required=False, default='Common', help='Optional list of platforms this gem should be removed from' ' Ex. --platforms Mac,Windows,Linux') - remove_gem_subparser.add_argument('-r', '--remove-from-cmake', type=bool, required=False, + parser.add_argument('-r', '--remove-from-cmake', type=bool, required=False, default=False, help='Automatically call remove-from-cmake.') - remove_gem_subparser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + 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.') - remove_gem_subparser.set_defaults(func=_run_remove_gem_from_project) + parser.set_defaults(func=_run_remove_gem_from_project) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py remove-gem-from-project --project-path D:/Test --gem-name Atom + :param subparsers: the caller instantiates subparsers and passes it in here + """ + remove_gem_project_subparser = subparsers.add_parser('remove-gem-from-project') + add_parser_args(remove_gem_project_subparser) + + +def main(): + """ + Runs remove_gem_project.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py index 9cb93d53ae..c6b4874b6a 100644 --- a/scripts/o3de/o3de/repo.py +++ b/scripts/o3de/o3de/repo.py @@ -16,11 +16,12 @@ import shutil import urllib.parse import urllib.request -from o3de import manifest, validation +from o3de import manifest, utils, validation logger = logging.getLogger() logging.basicConfig() + def process_add_o3de_repo(file_name: str or pathlib.Path, repo_set: set) -> int: file_name = pathlib.Path(file_name).resolve() @@ -32,105 +33,26 @@ def process_add_o3de_repo(file_name: str or pathlib.Path, with file_name.open('r') as f: try: repo_data = json.load(f) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'{file_name} failed to load: {str(e)}') return 1 - for engine_uri in repo_data['engines']: - engine_uri = f'{engine_uri}/engine.json' - engine_sha256 = hashlib.sha256(engine_uri.encode()) - cache_file = cache_folder / str(engine_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - 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': - with urllib.request.urlopen(engine_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - engine_json = pathlib.Path(engine_uri).resolve() - if not engine_json.is_file(): - return 1 - shutil.copy(engine_json, cache_file) - - for project_uri in repo_data['projects']: - project_uri = f'{project_uri}/project.json' - project_sha256 = hashlib.sha256(project_uri.encode()) - cache_file = cache_folder / str(project_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - 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': - with urllib.request.urlopen(project_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - project_json = pathlib.Path(project_uri).resolve() - if not project_json.is_file(): - return 1 - shutil.copy(project_json, cache_file) - - for gem_uri in repo_data['gems']: - gem_uri = f'{gem_uri}/gem.json' - gem_sha256 = hashlib.sha256(gem_uri.encode()) - cache_file = cache_folder / str(gem_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - 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': - with urllib.request.urlopen(gem_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - gem_json = pathlib.Path(gem_uri).resolve() - if not gem_json.is_file(): - return 1 - shutil.copy(gem_json, cache_file) - - for template_uri in repo_data['templates']: - template_uri = f'{template_uri}/template.json' - template_sha256 = hashlib.sha256(template_uri.encode()) - cache_file = cache_folder / str(template_sha256.hexdigest() + '.json') - if not cache_file.is_file(): - 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': - with urllib.request.urlopen(template_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - template_json = pathlib.Path(template_uri).resolve() - if not template_json.is_file(): - return 1 - shutil.copy(template_json, cache_file) - - for repo_uri in repo_data['repos']: - if repo_uri not in repo_set: - repo_set.add(repo_uri) - repo_uri = f'{repo_uri}/repo.json' - repo_sha256 = hashlib.sha256(repo_uri.encode()) - cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') + for o3de_object_uris, manifest_json in [(repo_data['engines'], 'engine.json'), + (repo_data['projects'], 'project.json'), + (repo_data['gems'], 'gem.json'), + (repo_data['template'], 'template.json'), + (repo_data['restricted'], 'restricted.json')]: + for o3de_object_uri in o3de_object_uris: + manifest_json_uri = f'{o3de_object_uri}/{manifest_json}' + manifest_json_sha256 = hashlib.sha256(manifest_json_uri.encode()) + cache_file = cache_folder / str(manifest_json_sha256.hexdigest() + '.json') if not cache_file.is_file(): - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(repo_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - repo_json = pathlib.Path(repo_uri).resolve() - if not repo_json.is_file(): - return 1 - shutil.copy(repo_json, cache_file) + parsed_uri = urllib.parse.urlparse(manifest_json_uri) + download_file_result = utils.download_file(parsed_uri, cache_file) + if download_file_result != 0: + return download_file_result + + repo_set |= repo_data['repos'] return 0 @@ -156,18 +78,9 @@ def refresh_repos() -> int: cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json') if not cache_file.is_file(): parsed_uri = urllib.parse.urlparse(repo_uri) - if parsed_uri.scheme == 'http' or \ - parsed_uri.scheme == 'https' or \ - parsed_uri.scheme == 'ftp' or \ - parsed_uri.scheme == 'ftps': - with urllib.request.urlopen(repo_uri) as s: - with cache_file.open('wb') as f: - shutil.copyfileobj(s, f) - else: - origin_file = pathlib.Path(repo_uri).resolve() - if not origin_file.is_file(): - return 1 - shutil.copy(origin_file, cache_file) + download_file_result = utils.download_file(parsed_uri, cache_file) + if download_file_result != 0: + return download_file_result if not validation.valid_o3de_repo_json(cache_file): logger.error(f'Repo json {repo_uri} is not valid.') @@ -181,111 +94,67 @@ def refresh_repos() -> int: return result -def search_repo(repo_set: set, - repo_json_data: dict, +def search_repo(repo_json_data: dict, engine_name: str = None, project_name: str = None, gem_name: str = None, template_name: str = None, restricted_name: str = None) -> dict or None: - cache_folder = manifest.get_o3de_cache_folder() if isinstance(engine_name, str) or isinstance(engine_name, pathlib.PurePath): - for engine_uri in repo_json_data['engines']: - engine_uri = f'{engine_uri}/engine.json' - engine_sha256 = hashlib.sha256(engine_uri.encode()) - engine_cache_file = cache_folder / str(engine_sha256.hexdigest() + '.json') - if engine_cache_file.is_file(): - with engine_cache_file.open('r') as f: - try: - engine_json_data = json.load(f) - except Exception as e: - logger.warn(f'{engine_cache_file} failed to load: {str(e)}') - else: - if engine_json_data['engine_name'] == engine_name: - return engine_json_data - + o3de_object_uris = repo_json_data['engines'] + manifest_json = 'engine.json' + json_key = 'engine_name' + search_func = lambda: None if manifest_json_data.get(json_key, '') == engine_name else manifest_json_data elif isinstance(project_name, str) or isinstance(project_name, pathlib.PurePath): - for project_uri in repo_json_data['projects']: - project_uri = f'{project_uri}/project.json' - project_sha256 = hashlib.sha256(project_uri.encode()) - project_cache_file = cache_folder / str(project_sha256.hexdigest() + '.json') - if project_cache_file.is_file(): - with project_cache_file.open('r') as f: - try: - project_json_data = json.load(f) - except Exception as e: - logger.warn(f'{project_cache_file} failed to load: {str(e)}') - else: - if project_json_data['project_name'] == project_name: - return project_json_data - + o3de_object_uris = repo_json_data['projects'] + manifest_json = 'project.json' + json_key = 'project_name' + search_func = lambda: None if manifest_json_data.get(json_key, '') == project_name else manifest_json_data elif isinstance(gem_name, str) or isinstance(gem_name, pathlib.PurePath): - for gem_uri in repo_json_data['gems']: - gem_uri = f'{gem_uri}/gem.json' - gem_sha256 = hashlib.sha256(gem_uri.encode()) - gem_cache_file = cache_folder / str(gem_sha256.hexdigest() + '.json') - if gem_cache_file.is_file(): - with gem_cache_file.open('r') as f: - try: - gem_json_data = json.load(f) - except Exception as e: - logger.warn(f'{gem_cache_file} failed to load: {str(e)}') - else: - if gem_json_data['gem_name'] == gem_name: - return gem_json_data - + o3de_object_uris = repo_json_data['gems'] + manifest_json = 'gem.json' + json_key = 'gem_name' + search_func = lambda: None if manifest_json_data.get(json_key, '') == gem_name else manifest_json_data elif isinstance(template_name, str) or isinstance(template_name, pathlib.PurePath): - for template_uri in repo_json_data['templates']: - template_uri = f'{template_uri}/template.json' - template_sha256 = hashlib.sha256(template_uri.encode()) - template_cache_file = cache_folder / str(template_sha256.hexdigest() + '.json') - if template_cache_file.is_file(): - with template_cache_file.open('r') as f: - try: - template_json_data = json.load(f) - except Exception as e: - logger.warn(f'{template_cache_file} failed to load: {str(e)}') - else: - if template_json_data['template_name'] == template_name: - return template_json_data - + o3de_object_uris = repo_json_data['template'] + manifest_json = 'template.json' + json_key = 'template_name' + search_func = lambda: None if manifest_json_data.get(json_key, '') == template_name_name else manifest_json_data elif isinstance(restricted_name, str) or isinstance(restricted_name, pathlib.PurePath): - for restricted_uri in repo_json_data['restricted']: - restricted_uri = f'{restricted_uri}/restricted.json' - restricted_sha256 = hashlib.sha256(restricted_uri.encode()) - restricted_cache_file = cache_folder / str(restricted_sha256.hexdigest() + '.json') - if restricted_cache_file.is_file(): - with restricted_cache_file.open('r') as f: - try: - restricted_json_data = json.load(f) - except Exception as e: - logger.warn(f'{restricted_cache_file} failed to load: {str(e)}') - else: - if restricted_json_data['restricted_name'] == restricted_name: - return restricted_json_data - # recurse + o3de_object_uris = repo_json_data['restricted'] + manifest_json = 'restricted.json' + json_key = 'restricted_name' + search_func = lambda: None if manifest_json_data.get(json_key, '') == restricted_name else manifest_json_data else: - for repo_repo_uri in repo_json_data['repos']: - if repo_repo_uri not in repo_set: - repo_set.add(repo_repo_uri) - repo_repo_uri = f'{repo_repo_uri}/repo.json' - repo_repo_sha256 = hashlib.sha256(repo_repo_uri.encode()) - repo_repo_cache_file = cache_folder / str(repo_repo_sha256.hexdigest() + '.json') - if repo_repo_cache_file.is_file(): - with repo_repo_cache_file.open('r') as f: - try: - repo_repo_json_data = json.load(f) - except Exception as e: - logger.warn(f'{repo_repo_cache_file} failed to load: {str(e)}') - else: - item = search_repo(repo_set, - repo_repo_json_data, - engine_name, - project_name, - gem_name, - template_name) - if item: - return item - return None + return None + o3de_object = search_o3de_object(manifest_json, o3de_object_uris, search_func) + if o3de_object: + return o3de_object + + # recurse into the repos object to search for the o3de object + o3de_object_uris = repo_json_data['repos'] + manifest_json = 'repo.json' + search_func = lambda: search_repo(manifest_json, engine_name, project_name, gem_name, template_name) + return search_o3de_object(manifest_json, o3de_object_uris, search_func) + + +def search_o3de_object(manifest_json, o3de_object_uris, search_func): + # Search for the o3de object based on the supplied object name in the current repo + cache_folder = manifest.get_o3de_cache_folder() + for o3de_object_uri in o3de_object_uris: + manifest_json_uri = f'{o3de_object_uri}/{manifest_json}' + manifest_json_sha256 = hashlib.sha256(manifest_json_uri.encode()) + cache_file = cache_folder / str(manifest_json_sha256.hexdigest() + '.json') + if cache_file.is_file(): + with cache_file.open('r') as f: + try: + manifest_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warn(f'{cache_file} failed to load: {str(e)}') + else: + result_json_data = search_func() + if result_json_data: + return result_json_data + return None diff --git a/scripts/o3de/o3de/sha256.py b/scripts/o3de/o3de/sha256.py index bc35919c4e..bbec7696d6 100644 --- a/scripts/o3de/o3de/sha256.py +++ b/scripts/o3de/o3de/sha256.py @@ -13,6 +13,8 @@ import argparse import json import logging import hashlib +import pathlib +import sys from o3de import utils @@ -42,7 +44,7 @@ def sha256(file_path: str or pathlib.Path, with json_path.open('r') as s: try: json_data = json.load(s) - except Exception as e: + except json.JSONDecodeError as e: logger.error(f'Failed to read Json path {json_path}: {str(e)}') return 1 json_data.update({"sha256": sha256}) @@ -50,7 +52,7 @@ def sha256(file_path: str or pathlib.Path, with json_path.open('w') as s: try: s.write(json.dumps(json_data, indent=4)) - except Exception as e: + except OSError as e: logger.error(f'Failed to write Json path {json_path}: {str(e)}') return 1 else: @@ -63,20 +65,53 @@ def _run_sha256(args: argparse) -> int: args.json_path) -def add_args(parser, subparsers) -> None: +def add_parser_args(parser): """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be + add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here + Ex. Directly run from this file alone with: python sha256.py --file-path "C:/TestGem" + :param parser: the caller passes an argparse parser like instance to this method + """ + parser.add_argument('-f', '--file-path', type=str, required=True, + help='The path to the file you want to sha256.') + parser.add_argument('-j', '--json-path', type=str, required=False, + help='optional path to an o3de json file to add the "sha256" element to.') + parser.set_defaults(func=_run_sha256) + + +def add_args(subparsers) -> None: + """ + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py sha256 --file-path "C:/TestGem" :param subparsers: the caller instantiates subparsers and passes it in here """ sha256_subparser = subparsers.add_parser('sha256') - sha256_subparser.add_argument('-f', '--file-path', type=str, required=True, - help='The path to the file you want to sha256.') - sha256_subparser.add_argument('-j', '--json-path', type=str, required=False, - help='optional path to an o3de json file to add the "sha256" element to.') - sha256_subparser.set_defaults(func=_run_sha256) + add_parser_args(sha256_subparser) + + +def main(): + """ + Runs sha256.py script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + + # add args to the parser + add_parser_args(the_parser) + + # parse args + the_args = the_parser.parse_args() + + # run + ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 + + # return + sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/utils.py b/scripts/o3de/o3de/utils.py index 50a9e5d6dd..4330de25b8 100755 --- a/scripts/o3de/o3de/utils.py +++ b/scripts/o3de/o3de/utils.py @@ -13,7 +13,9 @@ This file contains utility functions """ import uuid - +import pathlib +import shutil +import urllib.request def validate_identifier(identifier: str) -> bool: """ @@ -46,6 +48,7 @@ def validate_uuid4(uuid_string: str) -> bool: return False return str(val) == uuid_string + def backup_file(file_name: str or pathlib.Path) -> None: index = 0 renamed = False @@ -69,4 +72,41 @@ def backup_folder(folder: str or pathlib.Path) -> None: folder = pathlib.Path(folder).resolve() folder.rename(backup_folder_name) if backup_folder_name.is_dir(): - renamed = True \ No newline at end of file + renamed = True + + +def download_file(parsed_uri, download_path: pathlib.Path) -> int: + """ + :param parsed_uri: uniform resource identifier to zip file to download + :param download_path: location path on disk to download file + """ + if download_path.is_file(): + logger.warn(f'File already downloaded to {download_path}.') + elif parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: + with urllib.request.urlopen(url) as s: + with download_path.open('wb') as f: + shutil.copyfileobj(s, f) + else: + origin_file = pathlib.Path(url).resolve() + if not origin_file.is_file(): + return 1 + shutil.copy(origin_file, download_path) + + return 0 + + +def download_zip_file(parsed_uri, download_zip_path: pathlib.Path) -> int: + """ + :param parsed_uri: uniform resource identifier to zip file to download + :param download_zip_path: path to output zip file + """ + download_file_result = download_file(parsed_uri, download_zip_path) + if download_file_result != 0: + return download_file_result + + if not zipfile.is_zipfile(download_zip_path): + logger.error(f"File zip {download_zip_path} is invalid.") + download_zip_path.unlink() + return 1 + + return 0 \ No newline at end of file diff --git a/scripts/o3de/o3de/validation.py b/scripts/o3de/o3de/validation.py index f3a5f5e376..721b7eae09 100644 --- a/scripts/o3de/o3de/validation.py +++ b/scripts/o3de/o3de/validation.py @@ -14,6 +14,10 @@ This file validating o3de object json files import json import pathlib +def valid_o3de_json_dict(json_data: dict, key: str) -> bool: + return key in json_data + + def valid_o3de_repo_json(file_name: str or pathlib.Path) -> bool: file_name = pathlib.Path(file_name).resolve() if not file_name.is_file(): @@ -24,7 +28,7 @@ def valid_o3de_repo_json(file_name: str or pathlib.Path) -> bool: json_data = json.load(f) test = json_data['repo_name'] test = json_data['origin'] - except Exception as e: + except (json.JSONDecodeError, KeyError) as e: return False return True @@ -39,8 +43,7 @@ def valid_o3de_engine_json(file_name: str or pathlib.Path) -> bool: try: json_data = json.load(f) test = json_data['engine_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: + except (json.JSONDecodeError, KeyError) as e: return False return True @@ -54,8 +57,7 @@ def valid_o3de_project_json(file_name: str or pathlib.Path) -> bool: try: json_data = json.load(f) test = json_data['project_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: + except (json.JSONDecodeError, KeyError) as e: return False return True @@ -69,8 +71,7 @@ def valid_o3de_gem_json(file_name: str or pathlib.Path) -> bool: try: json_data = json.load(f) test = json_data['gem_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: + except (json.JSONDecodeError, KeyError) as e: return False return True @@ -83,8 +84,7 @@ def valid_o3de_template_json(file_name: str or pathlib.Path) -> bool: try: json_data = json.load(f) test = json_data['template_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: + except (json.JSONDecodeError, KeyError) as e: return False return True @@ -97,7 +97,6 @@ def valid_o3de_restricted_json(file_name: str or pathlib.Path) -> bool: try: json_data = json.load(f) test = json_data['restricted_name'] - # test = json_data['origin'] # will be required soon - except Exception as e: + except (json.JSONDecodeError, KeyError) as e: return False return True diff --git a/scripts/o3de/tests/unit_test_registration.py b/scripts/o3de/tests/unit_test_registration.py index a0abb6cacd..eb866e76d4 100644 --- a/scripts/o3de/tests/unit_test_registration.py +++ b/scripts/o3de/tests/unit_test_registration.py @@ -35,11 +35,10 @@ string_manifest_data = '{}' ) def test_register_engine_path(engine_path, engine_name, force, expected_result): parser = argparse.ArgumentParser() - subparser = parser.add_subparsers(help='sub-command help') # Register the registration script subparsers with the current argument parser - register.add_args(parser, subparser) - arg_list = ['register', '--engine-path', str(engine_path)] + register.add_parser_args(parser) + arg_list = ['--engine-path', str(engine_path)] if force: arg_list += ['--force'] args = parser.parse_args(arg_list) @@ -64,3 +63,55 @@ def test_register_engine_path(engine_path, engine_name, force, expected_result): result = register._run_register(args) assert result == expected_result + +@pytest.fixture(scope='class') +def init_manifest_data(request): + class ManifestData: + def __init__(self): + self.json_string = json.dumps({'default_engines_folder': '', + 'default_projects_folder': '', 'default_gems_folder': '', + 'default_templates_folder': '', 'default_restricted_folder': ''}) + + request.cls.manifest_data = ManifestData() + + +@pytest.mark.usefixtures('init_manifest_data') +class TestRegisterThisEngine: + @pytest.mark.parametrize( + "engine_path, engine_name, force, expected_result", [ + pytest.param(pathlib.PurePath('D:/o3de/o3de'), "o3de", False, 0), + pytest.param(pathlib.PurePath('F:/Open3DEngine'), "o3de", False, 1), + pytest.param(pathlib.PurePath('F:/Open3DEngine'), "o3de", True, 0) + ] + ) + def test_register_this_engine(self, engine_path, engine_name, force, expected_result): + parser = argparse.ArgumentParser() + + # Register the registration script subparsers with the current argument parser + register.add_parser_args(parser) + arg_list = ['--this-engine'] + if force: + arg_list += ['--force'] + args = parser.parse_args(arg_list) + + def load_manifest_from_string() -> dict: + try: + manifest_json = json.loads(self.manifest_data.json_string) + except json.JSONDecodeError as err: + logging.error("Error decoding Json from Manifest file") + else: + return manifest_json + def save_manifest_to_string(manifest_json: dict) -> None: + self.manifest_data.json_string = json.dumps(manifest_json) + + engine_json_data = {'engine_name': engine_name} + + with patch('o3de.manifest.load_o3de_manifest', side_effect=load_manifest_from_string) as load_manifest_mock, \ + patch('o3de.manifest.save_o3de_manifest', side_effect=save_manifest_to_string) as save_manifest_mock, \ + patch('o3de.manifest.get_engine_json_data', return_value=engine_json_data) as engine_paths_mock, \ + patch('o3de.manifest.get_this_engine_path', return_value=engine_path) as engine_paths_mock, \ + patch('o3de.validation.valid_o3de_engine_json', return_value=True) as valid_engine_mock, \ + patch('pathlib.Path.is_dir', return_value=True) as pathlib_is_dir_mock: + result = register._run_register(args) + assert result == expected_result + From 98c3660bd92424094a501d06710c9396d627de4b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Sun, 23 May 2021 22:15:48 -0500 Subject: [PATCH 077/140] Correcting the comments in the PAL.cmake file --- cmake/PAL.cmake | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmake/PAL.cmake b/cmake/PAL.cmake index e10ef758da..dca54e4731 100644 --- a/cmake/PAL.cmake +++ b/cmake/PAL.cmake @@ -26,6 +26,7 @@ endforeach() #! o3de_restricted_id: Reads the "restricted" key from the o3de manifest # +# \arg:o3de_json_file name of the o3de json file to read the "restricted_name" key from # \arg:restricted returns the restricted association element from an o3de json, otherwise engine 'o3de' is assumed # \arg:o3de_json_file name of the o3de json file function(o3de_restricted_id o3de_json_file restricted) @@ -33,8 +34,6 @@ function(o3de_restricted_id o3de_json_file restricted) string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} "restricted_name") if(json_error) message(WARNING "Unable to read restricted from '${o3de_json_file}', error: ${json_error}") - message(WARNING "Setting restricted to engine default 'o3de'") - set(restricted_entry "o3de") endif() if(restricted_entry) set(${restricted} ${restricted_entry} PARENT_SCOPE) @@ -96,8 +95,8 @@ endfunction() #! o3de_restricted_path: # -# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name -# \arg:restricted_name name of the restricted +# \arg:o3de_json_file json file to read restricted id from +# \arg:restricted_name name of the restricted object function(o3de_restricted_path o3de_json_file restricted_path) o3de_restricted_id(${o3de_json_file} restricted_name) if(restricted_name) @@ -110,8 +109,7 @@ endfunction() #! read_engine_restricted_path: Locates the restricted path within the engine from a json file # -# \arg:restricted_path returns the path of the o3de restricted folder with name restricted_name -# \arg:restricted_name name of the restricted +# \arg:output_restricted_path returns the path of the o3de restricted folder with name restricted_name function(read_engine_restricted_path output_restricted_path) # Set manifest path to path in the user home directory set(manifest_path ${LY_ROOT_FOLDER}/engine.json) From 574efd711cae5326c87d39ff58a17853f32019bf Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Sun, 23 May 2021 22:48:52 -0500 Subject: [PATCH 078/140] Adding a "gem_module_roots" array to the gem.json for the Atom and AtomLyIntegration gems to allow additional module roots to be checked when determining the root directory of a GEM_MODULE target With this change the AtomViewportDisplayInfo gem.json as it is no longer needed. --- Gems/Atom/gem.json | 16 +++++++++++++++- .../AtomViewportDisplayInfo/gem.json | 12 ------------ Gems/AtomLyIntegration/gem.json | 12 +++++++++++- 3 files changed, 26 insertions(+), 14 deletions(-) delete mode 100644 Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json diff --git a/Gems/Atom/gem.json b/Gems/Atom/gem.json index c74a9013f3..99a715281e 100644 --- a/Gems/Atom/gem.json +++ b/Gems/Atom/gem.json @@ -1,3 +1,17 @@ { - "gem_name": "Atom" + "gem_name": "Atom", + "gem_module_roots": [ + "Asset/ImageProcessingAtom", + "Asset/Shader", + "Bootstrap", + "Component/DebugCamera", + "Feature/Common", + "RHI", + "RHI/DX12", + "RHI/Metal", + "RHI/Null", + "RHI/Vulkan", + "RPI", + "Tools/AtomToolsFramework" + ] } diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json deleted file mode 100644 index dd92a99ea9..0000000000 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "gem_name": "AtomLyIntegration_AtomViewportDisplayInfo", - "display_name": "Atom Viewport Display Info Overlay", - "summary": "Provides a diagnostic viewport overlay for the default O3DE Atom viewport.", - "canonical_tags": [ - "Gem" - ], - "user_tags": [ - "AtomLyIntegration", - "AtomViewportDisplayInfo" - ] -} \ No newline at end of file diff --git a/Gems/AtomLyIntegration/gem.json b/Gems/AtomLyIntegration/gem.json index 0971ad53c2..c350281ad1 100644 --- a/Gems/AtomLyIntegration/gem.json +++ b/Gems/AtomLyIntegration/gem.json @@ -1,3 +1,13 @@ { - "gem_name": "AtomLyIntegration" + "gem_name": "AtomLyIntegration", + "gem_module_roots": [ + "AtomBridge", + "AtomFont", + "AtomImGuiTools", + "AtomViewportDisplayInfo", + "CommonFeatures", + "EMotionFXAtom", + "ImguiAtom", + "TechnicalArt/DccScriptingInterface" + ] } From d004365e278551ef275ef3876f1242b3f2cdfaa7 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Sun, 23 May 2021 22:52:10 -0500 Subject: [PATCH 079/140] Updating the generation for the cmake_dependencies...setreg files to detect the nearest gem module root for a cmake target that has been marked with the GEM_MODULE property. The list of gem module roots are made up of the gem.json location + list of paths in the gem.json "gem_module_roots" JSON array if it exist --- cmake/SettingsRegistry.cmake | 115 ++++++++++++++++++++++++++++++----- 1 file changed, 100 insertions(+), 15 deletions(-) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index b0d9624728..d1f4041cce 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -31,7 +31,7 @@ set(gem_module_template [[ "@stripped_gem_target@": { "Modules":["$"], - "SourcePaths":["@gem_relative_source_dir@"] + "SourcePaths":["@gem_module_root_relative_to_engine_root@"] }]] ) @@ -85,6 +85,101 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) set(${ly_GEM_LOAD_DEPENDENCIES} ${all_gem_load_dependencies} PARENT_SCOPE) endfunction() +#!ly_get_gem_module_roots: Uses the supplied gem_target to lookup the nearest gem.json file above the SOURCE_DIR +# If a gem.json file is found it is added as gem module root and then queried for additional gem module root +# by looking up the "gem_module_root" key +# +# \arg:gem_target(TARGET) - Target to look upwards from using its SOURCE_DIR property +function(ly_get_gem_module_roots output_gem_module_roots gem_target) + unset(gem_module_roots) + get_property(gem_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) + + if(gem_source_dir) + set(candidate_gem_dir ${gem_source_dir}) + # Locate the root of the gem by finding the gem.json location + while(NOT EXISTS ${candidate_gem_dir}/gem.json) + get_filename_component(parent_dir ${candidate_gem_dir} DIRECTORY) + if (${parent_dir} STREQUAL ${candidate_gem_dir}) + message(WARNING "Did not find a gem.json while processing GEM_MODULE target ${gem_target}!") + break() + endif() + set(candidate_gem_dir ${parent_dir}) + endwhile() + endif() + + if (EXISTS ${candidate_gem_dir}/gem.json) + set(gem_source_dir ${candidate_gem_dir}) + file(READ ${gem_source_dir}/gem.json gem_json_data) + string(JSON module_root_count ERROR_VARIABLE gem_json_error LENGTH ${gem_json_data} gem_module_roots) + if(module_root_count GREATER 0) + math(EXPR module_root_range "${module_root_count}-1") + # Convert the paths the relative paths to absolute paths using the engine root + # as the base directory + foreach(module_root_index RANGE ${module_root_range}) + string(JSON module_root ERROR_VARIABLE gem_json_error GET ${gem_json_data} gem_module_roots ${module_root_index}) + file(REAL_PATH ${module_root} gem_absolute_module_root BASE_DIRECTORY ${gem_source_dir}) + list(APPEND gem_module_roots ${gem_absolute_module_root}) + endforeach() + endif() + endif() + + # Prepend the relative path from the Engine Root to the gem_module_roots list + list(PREPEND gem_module_roots ${gem_source_dir}) + set(${output_gem_module_roots} ${gem_module_roots} PARENT_SCOPE) +endfunction() + +#!ly_find_best_gem_module_roots: Attempts to find the gem module root which is the closest ancestor directory +# to the gem_target using the supplied gem_module_roots +# If a gem.json file is found it is added as gem module root and then queried for additional gem module root +# by looking up the "gem_module_root" key + +# \arg:gem_target(TARGET) - Target to whose SOURCE_DIR property is compared against the module roots +# \arg:gem_module_roots(list:PATH) - list of absolute gem module roots to search for nearest ancestor +function(ly_find_best_gem_module_root output_module_root gem_target gem_module_roots) + + get_property(module_root_cached DIRECTORY PROPERTY gem_module_root_${gem_target} SET) + if(module_root_cached) + get_property(module_root_prop DIRECTORY PROPERTY gem_module_root_${gem_target} ) + set(${output_module_root} ${module_root_prop} PARENT_SCOPE) + return() + endif() + + # An optimization for the case where there is only one gem_module_roots. The output_module_root is set to that + list(LENGTH gem_module_roots gem_module_roots_count) + if(gem_module_roots_count EQUAL 1) + list(GET gem_module_roots 0 best_module_root) + set_property(DIRECTORY PROPERTY gem_module_root_${gem_target} ${best_module_root}) + set(${output_module_root} ${best_module_root} PARENT_SCOPE) + return() + endif() + + get_property(gem_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) + # shortest_prefix is used to store the shortest prefix from a gem module root to the gem source dir + # Initialized to 10000 to make sure it is larger than any file path length + set(shortest_prefix "10000") + unset(best_module_root) + foreach(gem_module_root ${gem_module_roots}) + file(RELATIVE_PATH relative_to_module_root ${gem_module_root} ${gem_source_dir}) + # if the gem SOURCE_DIR is not relative to the module root then continue + if(relative_to_module_root MATCHES [[^\.\./]] OR IS_ABSOLUTE ${relative_to_module_root}) + continue() + endif() + # Update the shortest prefix + string(LENGTH "${relative_to_module_root}" module_to_source_dir_length) + if(module_to_source_dir_length LESS shortest_prefix) + set(best_module_root ${gem_module_root}) + set(shortest_prefix "${module_to_source_dir_length}") + endif() + endforeach() + + # Assign the best_module_root path to the output variable and stored it in a DIRECTORY property for caching + if(best_module_root) + set_property(DIRECTORY PROPERTY gem_module_root_${gem_target} ${best_module_root}) + set(${output_module_root} ${best_module_root} PARENT_SCOPE) + endif() + +endfunction() + #! ly_delayed_generate_settings_registry: Generates a .setreg file for each target with dependencies # added to it via ly_add_target_dependencies # The generated file contains the file to the each dependent targets @@ -102,7 +197,7 @@ function(ly_delayed_generate_settings_registry) # Retrieve the target name from the back of the list list(POP_BACK prefix_target_list target) - # Retreives the prefix if available from the remaining element of the list + # Retrieves the prefix if available from the remaining element of the list list(POP_BACK prefix_target_list prefix) # Get the gem dependencies for the given project and target combination @@ -123,20 +218,10 @@ function(ly_delayed_generate_settings_registry) if (NOT TARGET ${gem_target}) message(FATAL_ERROR "Dependency ${gem_target} from ${target} does not exist") endif() - get_property(gem_relative_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) - if(gem_relative_source_dir) - # Most gems SOURCE dir is nested in the path, we need to find the path where an 'Assets' or 'Code' folder resides - while(NOT EXISTS ${gem_relative_source_dir}/Assets AND NOT EXISTS ${gem_relative_source_dir}/Code) - get_filename_component(parent_dir ${gem_relative_source_dir} DIRECTORY) - if (${parent_dir} STREQUAL ${gem_relative_source_dir}) - message(FATAL_ERROR "Did not find a Gem source dir while processing target ${gem_target}!") - endif() - set(gem_relative_source_dir ${parent_dir}) - endwhile() - file(TO_CMAKE_PATH ${LY_ROOT_FOLDER} ly_root_folder_cmake) - file(RELATIVE_PATH gem_relative_source_dir ${ly_root_folder_cmake} ${gem_relative_source_dir}) - endif() + ly_get_gem_module_roots(gem_module_roots ${gem_target}) + ly_find_best_gem_module_root(best_gem_module_root "${gem_target}" "${gem_module_roots}") + file(RELATIVE_PATH gem_module_root_relative_to_engine_root ${LY_ROOT_FOLDER} ${best_gem_module_root}) # Strip target namespace from gem targets before configuring them into the json template ly_strip_target_namespace(TARGET ${gem_target} OUTPUT_VARIABLE stripped_gem_target) From 911ad84e53b616e9337ce819f25120630cbf6955 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Sun, 23 May 2021 23:26:31 -0500 Subject: [PATCH 080/140] Updating the exclusion rule for the install folder to only include an install folder at the root of the repo --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c396847560..8a63faa2f1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ __pycache__ AssetProcessorTemp/** [Bb]uild/** [Cc]ache/ -install/ +/install/ Editor/EditorEventLog.xml Editor/EditorLayout.xml **/*egg-info/** From b99bcea24a1932c7dde20007636dd99048d5b763 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Sun, 23 May 2021 23:29:05 -0500 Subject: [PATCH 081/140] Updating the engine.json.in template for the cmake INSTALL target to add the list of external subdirectories to allow the installed layout to access the subdirectories via it's engine.json file --- cmake/EngineJson.cmake | 2 ++ cmake/Platform/Common/Install_common.cmake | 10 ++++++++++ cmake/install/engine.json.in | 7 +++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cmake/EngineJson.cmake b/cmake/EngineJson.cmake index 9a82d4a2c5..c3ab29d09e 100644 --- a/cmake/EngineJson.cmake +++ b/cmake/EngineJson.cmake @@ -13,6 +13,8 @@ include_guard() +set(LY_EXTERNAL_SUBDIRS "" CACHE STRING "List of subdirectories to recurse into when running cmake against the engine's CMakeLists.txt") + #! read_engine_external_subdirs # Read the external subdirectories from the engine.json file # External subdirectories are any folders with CMakeLists.txt in them diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index ebe31a4cfa..b8202a1314 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -224,6 +224,16 @@ function(ly_setup_cmake_install) REGEX "Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE ) + # Transform the LY_EXTERNAL_SUBDIRS list into a json array + set(LY_INSTALL_EXTERNAL_SUBDIRS "[]") + set(external_subdir_index "0") + foreach(external_subdir ${LY_EXTERNAL_SUBDIRS}) + math(EXPR external_subdir_index "${external_subdir_index} + 1") + file(RELATIVE_PATH engine_rel_external_subdir ${LY_ROOT_FOLDER} ${external_subdir}) + string(JSON LY_INSTALL_EXTERNAL_SUBDIRS ERROR_VARIABLE external_subdir_error SET ${LY_INSTALL_EXTERNAL_SUBDIRS} + ${external_subdir_index} "\"${engine_rel_external_subdir}\"") + endforeach() + configure_file(${LY_ROOT_FOLDER}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY) install( diff --git a/cmake/install/engine.json.in b/cmake/install/engine.json.in index 4a8579d864..1cfb1826ce 100644 --- a/cmake/install/engine.json.in +++ b/cmake/install/engine.json.in @@ -1,8 +1,11 @@ { "engine_name": "@LY_VERSION_ENGINE_NAME@", - "restricted": "o3de", + "restricted_name": "o3de", "FileVersion": 1, "O3DEVersion": "@LY_VERSION_STRING@", "O3DECopyrightYear": @LY_VERSION_COPYRIGHT_YEAR@, - "O3DEBuildNumber": @LY_VERSION_BUILD_NUMBER@ + "O3DEBuildNumber": @LY_VERSION_BUILD_NUMBER@, + "external_subdirectories": @LY_INSTALL_EXTERNAL_SUBDIRS@, + "projects": [@LY_INSTALL_PROJECTS@], + "templates": [@LY_INSTALL_TEMPLATES@] } From 57bdc58c68995642c13045d81a9e45dbacb1f1bf Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 24 May 2021 00:49:00 -0500 Subject: [PATCH 082/140] Renamed the unit_test_registration.py script to be unit_test_register.py to be inline with the register.py script --- scripts/o3de/tests/CMakeLists.txt | 2 +- .../tests/{unit_test_registration.py => unit_test_register.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename scripts/o3de/tests/{unit_test_registration.py => unit_test_register.py} (100%) diff --git a/scripts/o3de/tests/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt index 29410e3523..7abc22a030 100644 --- a/scripts/o3de/tests/CMakeLists.txt +++ b/scripts/o3de/tests/CMakeLists.txt @@ -16,7 +16,7 @@ endif() # Add a test to test out the o3de package `o3de.py register` command ly_add_pytest( NAME o3de_register - PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_registration.py + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_register.py TEST_SUITE smoke EXCLUDE_TEST_RUN_TARGET_FROM_IDE ) diff --git a/scripts/o3de/tests/unit_test_registration.py b/scripts/o3de/tests/unit_test_register.py similarity index 100% rename from scripts/o3de/tests/unit_test_registration.py rename to scripts/o3de/tests/unit_test_register.py From 21285809bf0dfb8a30fd00061d5e81bb80cb3f10 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 24 May 2021 11:39:07 -0500 Subject: [PATCH 083/140] Adding back gem.json files to the Atom and AtomLyIntegration folders which are to be seen as sub gem roots as a workaround for detecting the location of the "gem" root for the Atom/AtomLyIntegration GEM_MODULE targets Removed the logic in the SettingsRegistry.cmake for reading a "gem_module_roots" key from the gem.json file in order to determine the root of the Atom and Atom LyIntegration sub gem modules --- Gems/Atom/Asset/ImageProcessingAtom/gem.json | 10 +++ Gems/Atom/Asset/Shader/gem.json | 10 +++ Gems/Atom/Bootstrap/gem.json | 10 +++ Gems/Atom/Component/DebugCamera/gem.json | 10 +++ Gems/Atom/Feature/Common/gem.json | 10 +++ Gems/Atom/RHI/DX12/gem.json | 10 +++ Gems/Atom/RHI/Metal/gem.json | 10 +++ Gems/Atom/RHI/Null/gem.json | 10 +++ Gems/Atom/RHI/Vulkan/gem.json | 10 +++ Gems/Atom/RHI/gem.json | 10 +++ Gems/Atom/RPI/gem.json | 10 +++ Gems/Atom/Tools/AtomToolsFramework/gem.json | 10 +++ Gems/Atom/gem.json | 16 +--- Gems/AtomLyIntegration/AtomBridge/gem.json | 10 +++ Gems/AtomLyIntegration/AtomFont/gem.json | 10 +++ .../AtomLyIntegration/AtomImGuiTools/gem.json | 10 +++ .../AtomViewportDisplayInfo/gem.json | 12 +++ .../AtomLyIntegration/CommonFeatures/gem.json | 10 +++ Gems/AtomLyIntegration/EMotionFXAtom/gem.json | 10 +++ Gems/AtomLyIntegration/ImguiAtom/gem.json | 10 +++ .../DccScriptingInterface/gem.json | 10 +++ Gems/AtomLyIntegration/gem.json | 12 +-- cmake/SettingsRegistry.cmake | 80 ++----------------- 23 files changed, 213 insertions(+), 97 deletions(-) create mode 100644 Gems/Atom/Asset/ImageProcessingAtom/gem.json create mode 100644 Gems/Atom/Asset/Shader/gem.json create mode 100644 Gems/Atom/Bootstrap/gem.json create mode 100644 Gems/Atom/Component/DebugCamera/gem.json create mode 100644 Gems/Atom/Feature/Common/gem.json create mode 100644 Gems/Atom/RHI/DX12/gem.json create mode 100644 Gems/Atom/RHI/Metal/gem.json create mode 100644 Gems/Atom/RHI/Null/gem.json create mode 100644 Gems/Atom/RHI/Vulkan/gem.json create mode 100644 Gems/Atom/RHI/gem.json create mode 100644 Gems/Atom/RPI/gem.json create mode 100644 Gems/Atom/Tools/AtomToolsFramework/gem.json create mode 100644 Gems/AtomLyIntegration/AtomBridge/gem.json create mode 100644 Gems/AtomLyIntegration/AtomFont/gem.json create mode 100644 Gems/AtomLyIntegration/AtomImGuiTools/gem.json create mode 100644 Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json create mode 100644 Gems/AtomLyIntegration/CommonFeatures/gem.json create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/gem.json create mode 100644 Gems/AtomLyIntegration/ImguiAtom/gem.json create mode 100644 Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json diff --git a/Gems/Atom/Asset/ImageProcessingAtom/gem.json b/Gems/Atom/Asset/ImageProcessingAtom/gem.json new file mode 100644 index 0000000000..86256bff9d --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "ImageProcessingAtom", + "display_name": "Atom Image Processing", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/Asset/Shader/gem.json b/Gems/Atom/Asset/Shader/gem.json new file mode 100644 index 0000000000..71c741f436 --- /dev/null +++ b/Gems/Atom/Asset/Shader/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "AtomShader", + "display_name": "Atom Shader Builder", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/Bootstrap/gem.json b/Gems/Atom/Bootstrap/gem.json new file mode 100644 index 0000000000..8aa5cade6e --- /dev/null +++ b/Gems/Atom/Bootstrap/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_Bootstrap", + "display_name": "Atom Bootstrap", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/Component/DebugCamera/gem.json b/Gems/Atom/Component/DebugCamera/gem.json new file mode 100644 index 0000000000..06d39d1fc0 --- /dev/null +++ b/Gems/Atom/Component/DebugCamera/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_Component_DebugCamera", + "display_name": "Atom Debug Camera Component", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/Feature/Common/gem.json b/Gems/Atom/Feature/Common/gem.json new file mode 100644 index 0000000000..6980863b4c --- /dev/null +++ b/Gems/Atom/Feature/Common/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_Feature_Common", + "display_name": "Atom Feature Common", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/RHI/DX12/gem.json b/Gems/Atom/RHI/DX12/gem.json new file mode 100644 index 0000000000..683ccfb43a --- /dev/null +++ b/Gems/Atom/RHI/DX12/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_RHI_DX12", + "display_name": "Atom RHI DX12", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/RHI/Metal/gem.json b/Gems/Atom/RHI/Metal/gem.json new file mode 100644 index 0000000000..3e1726e8fa --- /dev/null +++ b/Gems/Atom/RHI/Metal/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_RHI_Metal", + "display_name": "Atom RHI Metal", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/RHI/Null/gem.json b/Gems/Atom/RHI/Null/gem.json new file mode 100644 index 0000000000..4fa5f1e480 --- /dev/null +++ b/Gems/Atom/RHI/Null/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_RHI_Null", + "display_name": "Atom RHI Null", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/RHI/Vulkan/gem.json b/Gems/Atom/RHI/Vulkan/gem.json new file mode 100644 index 0000000000..1f2fcd7f30 --- /dev/null +++ b/Gems/Atom/RHI/Vulkan/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_RHI_Vulkan", + "display_name": "Atom RHI Vulkan", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/RHI/gem.json b/Gems/Atom/RHI/gem.json new file mode 100644 index 0000000000..eb67e40a4a --- /dev/null +++ b/Gems/Atom/RHI/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_RHI", + "display_name": "Atom RHI", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/RPI/gem.json b/Gems/Atom/RPI/gem.json new file mode 100644 index 0000000000..7e822611a9 --- /dev/null +++ b/Gems/Atom/RPI/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_RPI", + "display_name": "Atom API", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/Tools/AtomToolsFramework/gem.json b/Gems/Atom/Tools/AtomToolsFramework/gem.json new file mode 100644 index 0000000000..3060d3f51a --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "AtomToolsFramework", + "display_name": "Atom Tools Framework", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/Atom/gem.json b/Gems/Atom/gem.json index 99a715281e..91bc9bcf53 100644 --- a/Gems/Atom/gem.json +++ b/Gems/Atom/gem.json @@ -1,17 +1,5 @@ { "gem_name": "Atom", - "gem_module_roots": [ - "Asset/ImageProcessingAtom", - "Asset/Shader", - "Bootstrap", - "Component/DebugCamera", - "Feature/Common", - "RHI", - "RHI/DX12", - "RHI/Metal", - "RHI/Null", - "RHI/Vulkan", - "RPI", - "Tools/AtomToolsFramework" - ] + "display_name": "Atom", + "summary": "Next-Gen Rendering Package for the O3DE engine" } diff --git a/Gems/AtomLyIntegration/AtomBridge/gem.json b/Gems/AtomLyIntegration/AtomBridge/gem.json new file mode 100644 index 0000000000..329741bb8e --- /dev/null +++ b/Gems/AtomLyIntegration/AtomBridge/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "Atom_AtomBridge", + "display_name": "Atom Bridge", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/AtomLyIntegration/AtomFont/gem.json b/Gems/AtomLyIntegration/AtomFont/gem.json new file mode 100644 index 0000000000..a609061ea3 --- /dev/null +++ b/Gems/AtomLyIntegration/AtomFont/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "AtomFont", + "display_name": "Atom Font", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/AtomLyIntegration/AtomImGuiTools/gem.json b/Gems/AtomLyIntegration/AtomImGuiTools/gem.json new file mode 100644 index 0000000000..5cee62f7bb --- /dev/null +++ b/Gems/AtomLyIntegration/AtomImGuiTools/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "AtomImGuiTools", + "display_name": "Atom ImGui", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json new file mode 100644 index 0000000000..3a83607924 --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json @@ -0,0 +1,12 @@ +{ + "gem_name": "AtomLyIntegration_AtomViewportDisplayInfo", + "display_name": "Atom Viewport Display Info Overlay", + "summary": "Provides a diagnostic viewport overlay for the default O3DE Atom viewport.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "AtomLyIntegration", + "AtomViewportDisplayInfo" + ] +} diff --git a/Gems/AtomLyIntegration/CommonFeatures/gem.json b/Gems/AtomLyIntegration/CommonFeatures/gem.json new file mode 100644 index 0000000000..306c61e6d7 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "CommonFeaturesAtom", + "display_name": "Common Features Atom", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/gem.json b/Gems/AtomLyIntegration/EMotionFXAtom/gem.json new file mode 100644 index 0000000000..e2a81d0a5e --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "EMotionFX_Atom", + "display_name": "EMotionFX Atom", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/AtomLyIntegration/ImguiAtom/gem.json b/Gems/AtomLyIntegration/ImguiAtom/gem.json new file mode 100644 index 0000000000..6d6551b5fa --- /dev/null +++ b/Gems/AtomLyIntegration/ImguiAtom/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "ImguiAtom", + "display_name": "Imgui Atom", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json new file mode 100644 index 0000000000..94f5bb6d43 --- /dev/null +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "DccScriptingInterface", + "display_name": "Atom Dcc Scripting Interface", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/AtomLyIntegration/gem.json b/Gems/AtomLyIntegration/gem.json index c350281ad1..4f587a8806 100644 --- a/Gems/AtomLyIntegration/gem.json +++ b/Gems/AtomLyIntegration/gem.json @@ -1,13 +1,5 @@ { "gem_name": "AtomLyIntegration", - "gem_module_roots": [ - "AtomBridge", - "AtomFont", - "AtomImGuiTools", - "AtomViewportDisplayInfo", - "CommonFeatures", - "EMotionFXAtom", - "ImguiAtom", - "TechnicalArt/DccScriptingInterface" - ] + "display_name": "Atom O3DE Integration", + "summary": "Collection of module targets for integrating Atom with the O3DE engine" } diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index d1f4041cce..825440e100 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -85,12 +85,10 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) set(${ly_GEM_LOAD_DEPENDENCIES} ${all_gem_load_dependencies} PARENT_SCOPE) endfunction() -#!ly_get_gem_module_roots: Uses the supplied gem_target to lookup the nearest gem.json file above the SOURCE_DIR -# If a gem.json file is found it is added as gem module root and then queried for additional gem module root -# by looking up the "gem_module_root" key +#!ly_get_gem_module_root: Uses the supplied gem_target to lookup the nearest gem.json file above the SOURCE_DIR # # \arg:gem_target(TARGET) - Target to look upwards from using its SOURCE_DIR property -function(ly_get_gem_module_roots output_gem_module_roots gem_target) +function(ly_get_gem_module_root output_gem_module_root gem_target) unset(gem_module_roots) get_property(gem_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) @@ -109,76 +107,13 @@ function(ly_get_gem_module_roots output_gem_module_roots gem_target) if (EXISTS ${candidate_gem_dir}/gem.json) set(gem_source_dir ${candidate_gem_dir}) - file(READ ${gem_source_dir}/gem.json gem_json_data) - string(JSON module_root_count ERROR_VARIABLE gem_json_error LENGTH ${gem_json_data} gem_module_roots) - if(module_root_count GREATER 0) - math(EXPR module_root_range "${module_root_count}-1") - # Convert the paths the relative paths to absolute paths using the engine root - # as the base directory - foreach(module_root_index RANGE ${module_root_range}) - string(JSON module_root ERROR_VARIABLE gem_json_error GET ${gem_json_data} gem_module_roots ${module_root_index}) - file(REAL_PATH ${module_root} gem_absolute_module_root BASE_DIRECTORY ${gem_source_dir}) - list(APPEND gem_module_roots ${gem_absolute_module_root}) - endforeach() - endif() endif() - # Prepend the relative path from the Engine Root to the gem_module_roots list - list(PREPEND gem_module_roots ${gem_source_dir}) - set(${output_gem_module_roots} ${gem_module_roots} PARENT_SCOPE) + # Set the gem module root output directory to the location with the gem.json file within it or + # the supplied gem_target SOURCE_DIR location if no gem.json file was found + set(${output_gem_module_root} ${gem_source_dir} PARENT_SCOPE) endfunction() -#!ly_find_best_gem_module_roots: Attempts to find the gem module root which is the closest ancestor directory -# to the gem_target using the supplied gem_module_roots -# If a gem.json file is found it is added as gem module root and then queried for additional gem module root -# by looking up the "gem_module_root" key - -# \arg:gem_target(TARGET) - Target to whose SOURCE_DIR property is compared against the module roots -# \arg:gem_module_roots(list:PATH) - list of absolute gem module roots to search for nearest ancestor -function(ly_find_best_gem_module_root output_module_root gem_target gem_module_roots) - - get_property(module_root_cached DIRECTORY PROPERTY gem_module_root_${gem_target} SET) - if(module_root_cached) - get_property(module_root_prop DIRECTORY PROPERTY gem_module_root_${gem_target} ) - set(${output_module_root} ${module_root_prop} PARENT_SCOPE) - return() - endif() - - # An optimization for the case where there is only one gem_module_roots. The output_module_root is set to that - list(LENGTH gem_module_roots gem_module_roots_count) - if(gem_module_roots_count EQUAL 1) - list(GET gem_module_roots 0 best_module_root) - set_property(DIRECTORY PROPERTY gem_module_root_${gem_target} ${best_module_root}) - set(${output_module_root} ${best_module_root} PARENT_SCOPE) - return() - endif() - - get_property(gem_source_dir TARGET ${gem_target} PROPERTY SOURCE_DIR) - # shortest_prefix is used to store the shortest prefix from a gem module root to the gem source dir - # Initialized to 10000 to make sure it is larger than any file path length - set(shortest_prefix "10000") - unset(best_module_root) - foreach(gem_module_root ${gem_module_roots}) - file(RELATIVE_PATH relative_to_module_root ${gem_module_root} ${gem_source_dir}) - # if the gem SOURCE_DIR is not relative to the module root then continue - if(relative_to_module_root MATCHES [[^\.\./]] OR IS_ABSOLUTE ${relative_to_module_root}) - continue() - endif() - # Update the shortest prefix - string(LENGTH "${relative_to_module_root}" module_to_source_dir_length) - if(module_to_source_dir_length LESS shortest_prefix) - set(best_module_root ${gem_module_root}) - set(shortest_prefix "${module_to_source_dir_length}") - endif() - endforeach() - - # Assign the best_module_root path to the output variable and stored it in a DIRECTORY property for caching - if(best_module_root) - set_property(DIRECTORY PROPERTY gem_module_root_${gem_target} ${best_module_root}) - set(${output_module_root} ${best_module_root} PARENT_SCOPE) - endif() - -endfunction() #! ly_delayed_generate_settings_registry: Generates a .setreg file for each target with dependencies # added to it via ly_add_target_dependencies @@ -219,9 +154,8 @@ function(ly_delayed_generate_settings_registry) message(FATAL_ERROR "Dependency ${gem_target} from ${target} does not exist") endif() - ly_get_gem_module_roots(gem_module_roots ${gem_target}) - ly_find_best_gem_module_root(best_gem_module_root "${gem_target}" "${gem_module_roots}") - file(RELATIVE_PATH gem_module_root_relative_to_engine_root ${LY_ROOT_FOLDER} ${best_gem_module_root}) + ly_get_gem_module_root(gem_module_root ${gem_target}) + file(RELATIVE_PATH gem_module_root_relative_to_engine_root ${LY_ROOT_FOLDER} ${gem_module_root}) # Strip target namespace from gem targets before configuring them into the json template ly_strip_target_namespace(TARGET ${gem_target} OUTPUT_VARIABLE stripped_gem_target) From 1a95b96985993b31eedff012670f12dcc15e54cf Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 24 May 2021 13:06:43 -0500 Subject: [PATCH 084/140] Fixed importing of o3de package modules within the o3de.py script when a relative path is used to invoke it --- scripts/o3de.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/scripts/o3de.py b/scripts/o3de.py index dabb83b068..cc3a14a8c3 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -27,18 +27,26 @@ def add_args(parser, subparsers) -> None: # As o3de.py shares the same name as the o3de package attempting to use a regular # from o3de import line tries to import from the current o3de.py script and not the package # So the current script directory is removed from the sys.path temporary - SCRIPT_DIR_REMOVED = False - SCRIPT_DIR = pathlib.Path(__file__).parent.resolve() - while str(SCRIPT_DIR) in sys.path: - SCRIPT_DIR_REMOVED = True - sys.path.remove(str(SCRIPT_DIR)) + script_dir_removed = False + script_abs_dir_removed = False + script_dir = pathlib.Path(__file__).parent + script_abs_dir = pathlib.Path(__file__).parent.resolve() + while str(script_dir) in sys.path: + script_dir_removed = True + sys.path.remove(str(script_dir)) + while str(script_abs_dir) in sys.path: + script_abs_dir_removed = True + # Remove the absolute path to the script_dir as well + sys.path.remove(str(script_abs_dir.resolve())) from o3de import engine_template, global_project, register, print_registration, get_registration, download, \ add_external_subdirectory, remove_external_subdirectory, add_gem_cmake, remove_gem_cmake, add_gem_project, \ remove_gem_project, sha256 - if SCRIPT_DIR_REMOVED: - sys.path.insert(0, str(SCRIPT_DIR)) + if script_abs_dir_removed: + sys.path.insert(0, str(script_abs_dir)) + if script_dir_removed: + sys.path.insert(0, str(script_dir)) # global_project global_project.add_args(subparsers) From 76985602ce0ab1f41a263a92458a0032f0c017c8 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 24 May 2021 15:57:01 -0500 Subject: [PATCH 085/140] Remove commented out logic from the DefaultProject CMakeLists.txt --- .../DefaultProject/Template/CMakeLists.txt | 95 ------------------- 1 file changed, 95 deletions(-) diff --git a/Templates/DefaultProject/Template/CMakeLists.txt b/Templates/DefaultProject/Template/CMakeLists.txt index c92607a789..b5b8692059 100644 --- a/Templates/DefaultProject/Template/CMakeLists.txt +++ b/Templates/DefaultProject/Template/CMakeLists.txt @@ -46,98 +46,3 @@ else() add_subdirectory(Code) endif() - - - -# #! Adds the --project-path argument to the VS IDE debugger command arguments -# function(add_vs_debugger_arguments) -# # Inject the project root into the --project-path argument into the Visual Studio Debugger arguments by defaults -# list(APPEND app_targets ${Name}.GameLauncher ${Name}.ServerLauncher) -# list(APPEND app_targets AssetBuilder AssetProcessor AssetProcessorBatch Editor) -# foreach(app_target IN LISTS app_targets) -# if (TARGET ${app_target}) -# set_property(TARGET ${app_target} APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${CMAKE_CURRENT_LIST_DIR}\"") -# endif() -# endforeach() -# endfunction() - -# set(o3de_project_path ${CMAKE_CURRENT_LIST_DIR}) -# set(o3de_project_json ${o3de_project_path}/project.json) - -# if(NOT PROJECT_NAME) -# cmake_minimum_required(VERSION 3.19) -# project(${Name} -# LANGUAGES C CXX -# VERSION 1.0.0.0 -# ) - -# # set this project as the only project -# set(LY_PROJECTS ${CMAKE_CURRENT_LIST_DIR}) - -# # o3de manifest -# include(o3de_manifest.cmake) - -# ################################################################################ -# # Set the engine_path and resolve this engines restricted path if it has one -# ################################################################################ -# o3de_engine_path(${o3de_project_json} o3de_engine_path) -# o3de_project_name(${o3de_project_json} o3de_project_name) -# o3de_restricted_path(${o3de_project_json} o3de_project_restricted_path) -# message(STATUS "O3DE Project Name: ${o3de_project_name}") -# message(STATUS "O3DE Project Path: ${o3de_project_path}") -# if(o3de_project_restricted_path) -# message(STATUS "O3DE Project Restricted Path: ${o3de_project_restricted_path}") -# endif() - -# # add the engines cmake folder to the CMAKE_MODULE_PATH -# list(APPEND CMAKE_MODULE_PATH "${o3de_engine_path}/cmake") - -# # add subdirectory on the engine path for this project -# #add_subdirectory(${o3de_engine_path} o3de) -# find_package(o3de REQUIRED) -# o3de_initialize() - -# # add this --project-path arguments to visual studio debugger -# add_vs_debugger_arguments() - -# else() -# ###################################################### -# # the engine is calling add sub_directory() on us -# ###################################################### -# o3de_project_name(${o3de_project_json} o3de_project_name) -# o3de_restricted_path(${o3de_project_json} o3de_project_restricted_path) - -# # Currently we are in the folder: ${CMAKE_CURRENT_LIST_DIR} -# # Get the platform specific folder ${pal_dir} for the folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} -# # Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform -# # in which case it will see if that platform is present here or in the restricted folder. -# # i.e. It could here: TestDP/Platform/ or -# # //TestDP -# ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_project_restricted_path} ${o3de_project_path} ${o3de_project_name}) - -# # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the -# # project cmake for this platform. -# include(${pal_dir}/${PAL_PLATFORM_NAME_LOWERCASE}_project.cmake) - -# # Add the project_name to global LY_PROJECTS_TARGET_NAME property -# set_property(GLOBAL APPEND PROPERTY LY_PROJECTS_TARGET_NAME ${o3de_project_name}) - -# add_subdirectory(Code) -# endif() - - - - - - - - - - - - - - - - - From bff7d39f68d2e7fed3afa11dd22e95ed0d1c8c54 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 24 May 2021 16:21:29 -0700 Subject: [PATCH 086/140] passing imported for executables --- cmake/LYWrappers.cmake | 23 +++++++++++++++-------- cmake/SettingsRegistry.cmake | 7 ++++++- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index bddd1a6c66..0e4ba5e214 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -100,22 +100,27 @@ function(ly_add_target) ly_include_cmake_file_list(${file_cmake}) endforeach() - set(linking_options) - set(linking_count) + unset(linking_options) + unset(linking_count) + unset(target_type_options) if(ly_add_target_STATIC) set(linking_options STATIC) + set(target_type_options STATIC) set(linking_count "${linking_count}1") endif() if(ly_add_target_SHARED) set(linking_options SHARED) + set(target_type_options SHARED) set(linking_count "${linking_count}1") endif() if(ly_add_target_MODULE) set(linking_options ${PAL_LINKOPTION_MODULE}) + set(target_type_options ${PAL_LINKOPTION_MODULE}) set(linking_count "${linking_count}1") endif() if(ly_add_target_HEADERONLY) set(linking_options INTERFACE) + set(target_type_options INTERFACE) set(linking_count "${linking_count}1") endif() if(ly_add_target_EXECUTABLE) @@ -130,7 +135,7 @@ function(ly_add_target) message(FATAL_ERROR "More than one of the following options [STATIC | SHARED | MODULE | HEADERONLY | EXECUTABLE | APPLICATION ] was specified and they are mutually exclusive") endif() if(ly_add_target_IMPORTED) - list(APPEND linking_options IMPORTED GLOBAL) + list(APPEND target_type_options IMPORTED GLOBAL) endif() if(ly_add_target_NAMESPACE) @@ -141,7 +146,8 @@ function(ly_add_target) set(project_NAME ${ly_add_target_NAME}) if(ly_add_target_EXECUTABLE) - add_executable(${ly_add_target_NAME} + add_executable(${ly_add_target_NAME} + ${target_type_options} ${ALLFILES} ${ly_add_target_GENERATED_FILES} ) ly_apply_platform_properties(${ly_add_target_NAME}) @@ -149,7 +155,8 @@ function(ly_add_target) set_target_properties(${ly_add_target_NAME} PROPERTIES LINKER_LANGUAGE CXX) endif() elseif(ly_add_target_APPLICATION) - add_executable(${ly_add_target_NAME} + add_executable(${ly_add_target_NAME} + ${target_type_options} ${PAL_EXECUTABLE_APPLICATION_FLAG} ${ALLFILES} ${ly_add_target_GENERATED_FILES} ) @@ -159,12 +166,12 @@ function(ly_add_target) endif() elseif(ly_add_target_HEADERONLY) add_library(${ly_add_target_NAME} - ${linking_options} + ${target_type_options} ${ALLFILES} ${ly_add_target_GENERATED_FILES} ) else() add_library(${ly_add_target_NAME} - ${linking_options} + ${target_type_options} ${ALLFILES} ${ly_add_target_GENERATED_FILES} ) ly_apply_platform_properties(${ly_add_target_NAME}) @@ -302,7 +309,7 @@ function(ly_add_target) set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGETS ${interface_name}) set(runtime_dependencies_list SHARED MODULE EXECUTABLE APPLICATION) - if(linking_options IN_LIST runtime_dependencies_list) + if(NOT ly_add_target_IMPORTED AND linking_options IN_LIST runtime_dependencies_list) add_custom_command(TARGET ${ly_add_target_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/runtime_dependencies/$/${ly_add_target_NAME}.cmake diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index 31ce36c516..b40650d900 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -150,7 +150,12 @@ function(ly_delayed_generate_settings_registry) list(JOIN target_gem_dependencies_names ",\n" target_gem_dependencies_names) string(CONFIGURE ${gems_json_template} gem_json @ONLY) - set(dependencies_setreg $/Registry/cmake_dependencies.${specialization_name}.setreg) + if(prefix) + set(target_dir $) + else() + set(target_dir $) + endif() + set(dependencies_setreg ${target_dir}/Registry/cmake_dependencies.${specialization_name}.setreg) file(GENERATE OUTPUT ${dependencies_setreg} CONTENT ${gem_json}) set_property(TARGET ${target} APPEND PROPERTY INTERFACE_LY_TARGET_FILES "${dependencies_setreg}\nRegistry") From db0db5c1c0c95f73ec7847b86bd1e989b00533f2 Mon Sep 17 00:00:00 2001 From: pappeste Date: Mon, 24 May 2021 18:57:48 -0700 Subject: [PATCH 087/140] Proper dependencies to LmbrCentral/LmbrCentral.Editor, mixing those two can cause Editor modules to load non-Editor modules --- .../ComponentEntityEditorPlugin/CMakeLists.txt | 4 ++-- Gems/AutomatedLauncherTesting/Code/CMakeLists.txt | 2 +- Gems/EMotionFX/Code/CMakeLists.txt | 2 +- Gems/FastNoise/Code/CMakeLists.txt | 2 +- Gems/GradientSignal/Code/CMakeLists.txt | 4 ++-- Gems/ImGui/Code/CMakeLists.txt | 2 +- Gems/LandscapeCanvas/Code/CMakeLists.txt | 2 +- Gems/LyShine/Code/CMakeLists.txt | 12 +++++------- Gems/LyShineExamples/Code/CMakeLists.txt | 4 +++- Gems/Maestro/Code/CMakeLists.txt | 3 --- Gems/PhysX/Code/CMakeLists.txt | 4 ++-- Gems/StartingPointCamera/Code/CMakeLists.txt | 2 +- Gems/SurfaceData/Code/CMakeLists.txt | 2 +- Gems/Vegetation/Code/CMakeLists.txt | 2 +- 14 files changed, 22 insertions(+), 25 deletions(-) diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt index 275bb0ba9f..66c96eb4c6 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt @@ -35,7 +35,7 @@ ly_add_target( AZ::AzToolsFramework Legacy::CryCommon Legacy::EditorLib - Gem::LmbrCentral + Gem::LmbrCentral.Editor ) ly_add_dependencies(Editor ComponentEntityEditorPlugin) @@ -65,7 +65,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzToolsFrameworkTestCommon Legacy::CryCommon Legacy::EditorLib - Gem::LmbrCentral + Gem::LmbrCentral.Editor ) ly_add_googletest( NAME Legacy::ComponentEntityEditorPlugin.Tests diff --git a/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt b/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt index 551f76da02..57b6824060 100644 --- a/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt +++ b/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt @@ -23,7 +23,7 @@ ly_add_target( PUBLIC AZ::AzCore Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Static ) ly_add_target( diff --git a/Gems/EMotionFX/Code/CMakeLists.txt b/Gems/EMotionFX/Code/CMakeLists.txt index b90902a948..8f0957a280 100644 --- a/Gems/EMotionFX/Code/CMakeLists.txt +++ b/Gems/EMotionFX/Code/CMakeLists.txt @@ -36,7 +36,7 @@ ly_add_target( AZ::AzCore AZ::AzFramework Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Static PUBLIC AZ::AtomCore Gem::Atom_RPI.Public diff --git a/Gems/FastNoise/Code/CMakeLists.txt b/Gems/FastNoise/Code/CMakeLists.txt index a49126303a..0f7a92e8d9 100644 --- a/Gems/FastNoise/Code/CMakeLists.txt +++ b/Gems/FastNoise/Code/CMakeLists.txt @@ -23,7 +23,7 @@ ly_add_target( PUBLIC Legacy::CryCommon Gem::GradientSignal - Gem::LmbrCentral + Gem::LmbrCentral.Static ) ly_add_target( diff --git a/Gems/GradientSignal/Code/CMakeLists.txt b/Gems/GradientSignal/Code/CMakeLists.txt index 7b8c9813e6..f7f8571beb 100644 --- a/Gems/GradientSignal/Code/CMakeLists.txt +++ b/Gems/GradientSignal/Code/CMakeLists.txt @@ -22,7 +22,7 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Static Gem::SurfaceData Gem::ImageProcessingAtom.Headers ) @@ -67,7 +67,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) 3rdParty::Qt::Widgets Legacy::CryCommon AZ::AzToolsFramework - Gem::LmbrCentral + Gem::LmbrCentral.Editor Gem::SurfaceData AZ::AssetBuilderSDK Gem::GradientSignal.Static diff --git a/Gems/ImGui/Code/CMakeLists.txt b/Gems/ImGui/Code/CMakeLists.txt index 2f7d6c6ce7..0751c5825b 100644 --- a/Gems/ImGui/Code/CMakeLists.txt +++ b/Gems/ImGui/Code/CMakeLists.txt @@ -70,7 +70,7 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC Gem::ImGui.ImGuiLYUtils - Gem::LmbrCentral + Gem::LmbrCentral.Static ) ly_add_target( diff --git a/Gems/LandscapeCanvas/Code/CMakeLists.txt b/Gems/LandscapeCanvas/Code/CMakeLists.txt index e8e2fce689..497c83845f 100644 --- a/Gems/LandscapeCanvas/Code/CMakeLists.txt +++ b/Gems/LandscapeCanvas/Code/CMakeLists.txt @@ -35,7 +35,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryCommon Legacy::Editor.Headers Legacy::EditorCommon - Gem::LmbrCentral + Gem::LmbrCentral.Editor Gem::GraphCanvasWidgets Gem::GraphModel.Editor.Static Gem::GradientSignal.Editor diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index 732bd1cfd4..d9f011750e 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -26,13 +26,13 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Legacy::CryCommon - Gem::LmbrCentral - Gem::TextureAtlas PUBLIC Gem::Atom_RPI.Public Gem::Atom_Utils.Static Gem::Atom_Bootstrap.Headers Gem::AtomFont + Gem::LmbrCentral.Static + Gem::TextureAtlas ) ly_add_target( @@ -49,8 +49,6 @@ ly_add_target( PRIVATE Gem::LyShine.Static Legacy::CryCommon - Gem::LmbrCentral - Gem::TextureAtlas RUNTIME_DEPENDENCIES Gem::LmbrCentral Gem::TextureAtlas @@ -85,7 +83,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::EditorCore Gem::LyShine.Static Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Editor.Static Gem::TextureAtlas Gem::AtomToolsFramework.Static Gem::AtomToolsFramework.Editor @@ -117,7 +115,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryCommon AZ::AssetBuilderSDK Gem::LyShine.Editor.Static - Gem::LmbrCentral + Gem::LmbrCentral.Editor Gem::TextureAtlas RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor @@ -175,7 +173,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest Legacy::CryCommon AZ::AssetBuilderSDK - Gem::LmbrCentral + Gem::LmbrCentral.Editor Gem::TextureAtlas Gem::LyShine.Editor.Static ) diff --git a/Gems/LyShineExamples/Code/CMakeLists.txt b/Gems/LyShineExamples/Code/CMakeLists.txt index 372bfa948b..1b8393a806 100644 --- a/Gems/LyShineExamples/Code/CMakeLists.txt +++ b/Gems/LyShineExamples/Code/CMakeLists.txt @@ -22,7 +22,7 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Static Gem::LyShine.Static ) @@ -39,4 +39,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::LyShineExamples.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) diff --git a/Gems/Maestro/Code/CMakeLists.txt b/Gems/Maestro/Code/CMakeLists.txt index fe58ba03a6..f21badab80 100644 --- a/Gems/Maestro/Code/CMakeLists.txt +++ b/Gems/Maestro/Code/CMakeLists.txt @@ -22,7 +22,6 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Legacy::CryCommon - Gem::LmbrCentral ) ly_add_target( @@ -39,7 +38,6 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::Maestro.Static - Gem::LmbrCentral RUNTIME_DEPENDENCIES Gem::LmbrCentral ) @@ -69,7 +67,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzToolsFramework AZ::AssetBuilderSDK Gem::Maestro.Static - Gem::LmbrCentral RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index b4c7b580a6..4ebb32b977 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -46,7 +46,7 @@ ly_add_target( AZ::AzCore AZ::AzFramework Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Static ) ly_add_target( @@ -107,7 +107,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::SceneCore AZ::SceneData Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Editor.Static Gem::PhysX.NumericalMethods Gem::PhysX.Static Gem::AtomLyIntegration_CommonFeatures.Static diff --git a/Gems/StartingPointCamera/Code/CMakeLists.txt b/Gems/StartingPointCamera/Code/CMakeLists.txt index d6dd1a7038..b32e713d4a 100644 --- a/Gems/StartingPointCamera/Code/CMakeLists.txt +++ b/Gems/StartingPointCamera/Code/CMakeLists.txt @@ -23,7 +23,7 @@ ly_add_target( PRIVATE AZ::AzCore Gem::CameraFramework.Static - Gem::LmbrCentral + Gem::LmbrCentral.Static Legacy::CryCommon ) diff --git a/Gems/SurfaceData/Code/CMakeLists.txt b/Gems/SurfaceData/Code/CMakeLists.txt index de1aa51938..c45c7aa09b 100644 --- a/Gems/SurfaceData/Code/CMakeLists.txt +++ b/Gems/SurfaceData/Code/CMakeLists.txt @@ -25,7 +25,7 @@ ly_add_target( PUBLIC Gem::Atom_RPI.Public Gem::Atom_Feature_Common.Static - Gem::LmbrCentral + Gem::LmbrCentral.Static ) ly_add_target( diff --git a/Gems/Vegetation/Code/CMakeLists.txt b/Gems/Vegetation/Code/CMakeLists.txt index c4a003bb4a..2dfbd96d60 100644 --- a/Gems/Vegetation/Code/CMakeLists.txt +++ b/Gems/Vegetation/Code/CMakeLists.txt @@ -26,7 +26,7 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Static Gem::GradientSignal Gem::SurfaceData.Static Gem::AtomLyIntegration_CommonFeatures.Static From d3fb2dd68c2907779c8b8832fee8b058e3082873 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 24 May 2021 22:49:37 -0500 Subject: [PATCH 088/140] Removed the add_external_subdirectory and add_gem_cmake python scripts as well as their remove counterparts. Updated teh register.py script to be able to register subdirectories to the o3de_manifest.json Also added the ability to register external subdirectories to the project.json if the --external-subdirectory-project-path is supplied Added the ability to register external subdirectories to the engine.json if the --external-subdirector-engine-path is supplied --- scripts/o3de.py | 15 +- .../o3de/o3de/add_external_subdirectory.py | 168 --------- scripts/o3de/o3de/add_gem_cmake.py | 138 ------- scripts/o3de/o3de/add_gem_project.py | 5 +- scripts/o3de/o3de/manifest.py | 66 +++- scripts/o3de/o3de/register.py | 341 ++++++++---------- .../o3de/o3de/remove_external_subdirectory.py | 120 ------ scripts/o3de/o3de/remove_gem_cmake.py | 122 ------- scripts/o3de/o3de/remove_gem_project.py | 10 +- 9 files changed, 203 insertions(+), 782 deletions(-) delete mode 100644 scripts/o3de/o3de/add_external_subdirectory.py delete mode 100644 scripts/o3de/o3de/add_gem_cmake.py delete mode 100644 scripts/o3de/o3de/remove_external_subdirectory.py delete mode 100644 scripts/o3de/o3de/remove_gem_cmake.py diff --git a/scripts/o3de.py b/scripts/o3de.py index cc3a14a8c3..050d860790 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -40,8 +40,7 @@ def add_args(parser, subparsers) -> None: sys.path.remove(str(script_abs_dir.resolve())) from o3de import engine_template, global_project, register, print_registration, get_registration, download, \ - add_external_subdirectory, remove_external_subdirectory, add_gem_cmake, remove_gem_cmake, add_gem_project, \ - remove_gem_project, sha256 + add_gem_project, remove_gem_project, sha256 if script_abs_dir_removed: sys.path.insert(0, str(script_abs_dir)) @@ -65,18 +64,6 @@ def add_args(parser, subparsers) -> None: # download download.add_args(subparsers) - # add external subdirectories - add_external_subdirectory.add_args(subparsers) - - # remove external subdirectories - remove_external_subdirectory.add_args(subparsers) - - # add gems to cmake - add_gem_cmake.add_args(subparsers) - - # remove gems from cmake - remove_gem_cmake.add_args(subparsers) - # add a gem to a project add_gem_project.add_args(subparsers) diff --git a/scripts/o3de/o3de/add_external_subdirectory.py b/scripts/o3de/o3de/add_external_subdirectory.py deleted file mode 100644 index 29013d30c8..0000000000 --- a/scripts/o3de/o3de/add_external_subdirectory.py +++ /dev/null @@ -1,168 +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. -# -""" -Contains command to add an external_subdirectory to a project's cmake scripts -""" - -import argparse -import logging -import pathlib -import sys - -from o3de import manifest - -logger = logging.getLogger() -logging.basicConfig() - -def add_external_subdirectory(external_subdir: str or pathlib.Path, - engine_path: str or pathlib.Path = None) -> int: - """ - add external subdirectory to a cmake - :param external_subdir: external subdirectory to add to cmake - :param engine_path: optional engine path, defaults to this engine - :return: 0 for success or non 0 failure code - """ - external_subdir = pathlib.Path(external_subdir).resolve() - if not external_subdir.is_dir(): - logger.error(f'Add External Subdirectory Failed: {external_subdir} does not exist.') - return 1 - - external_subdir_cmake = external_subdir / 'CMakeLists.txt' - if not external_subdir_cmake.is_file(): - logger.error(f'Add External Subdirectory Failed: {external_subdir} does not contain a CMakeLists.txt.') - return 1 - - json_data = manifest.load_o3de_manifest() - engine_object = manifest.find_engine_data(json_data, engine_path) - if not engine_object: - logger.error(f'Add External Subdirectory Failed: {engine_path} not registered.') - return 1 - - engine_object.setdefault('external_subdirectories', []) - while external_subdir.as_posix() in engine_object['external_subdirectories']: - engine_object['external_subdirectories'].remove(external_subdir.as_posix()) - - def parse_cmake_file(cmake: str or pathlib.Path, - files: set): - cmake_path = pathlib.Path(cmake).resolve() - cmake_file = cmake_path - if cmake_path.is_dir(): - files.add(cmake_path) - cmake_file = cmake_path / 'CMakeLists.txt' - elif cmake_path.is_file(): - cmake_path = cmake_path.parent - else: - return - - with cmake_file.open('r') as s: - lines = s.readlines() - for line in lines: - line = line.strip() - start = line.find('include(') - if start == 0: - end = line.find(')', start) - if end > start + len('include('): - try: - include_cmake_file = pathlib.Path(engine_path / line[start + len('include('): end]).resolve() - except FileNotFoundError as e: - pass - else: - parse_cmake_file(include_cmake_file, files) - else: - start = line.find('add_subdirectory(') - if start == 0: - end = line.find(')', start) - if end > start + len('add_subdirectory('): - try: - include_cmake_file = pathlib.Path( - cmake_path / line[start + len('add_subdirectory('): end]).resolve() - except FileNotFoundError as e: - pass - else: - parse_cmake_file(include_cmake_file, files) - - cmake_files = set() - parse_cmake_file(engine_path, cmake_files) - for external in engine_object["external_subdirectories"]: - parse_cmake_file(external, cmake_files) - - if external_subdir in cmake_files: - manifest.save_o3de_manifest(json_data) - logger.warning(f'External subdirectory {external_subdir.as_posix()} already included by add_subdirectory().') - return 1 - - engine_object['external_subdirectories'].insert(0, external_subdir.as_posix()) - engine_object['external_subdirectories'] = sorted(engine_object['external_subdirectories']) - - manifest.save_o3de_manifest(json_data) - - return 0 - - -def _run_add_external_subdirectory(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - - return add_external_subdirectory(args.external_subdirectory) - - -def add_parser_args(parser): - """ - add_parser_args is called to add arguments to each command such that it can be - invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python add-external-subdirectory.py "/home/foo/external-subdir" - :param parser: the caller passes an argparse parser like instance to this method - """ - parser.add_argument('external_subdirectory', metavar='external_subdirectory', type=str, - help='add an external subdirectory to cmake') - - 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.') - - parser.set_defaults(func=_run_add_external_subdirectory) - - -def add_args(subparsers) -> None: - """ - add_args is called to add subparsers arguments to each command such that it can be - a central python file such as o3de.py. - It can be run from the o3de.py script as follows - call add_args and execute: python o3de.py add_external_subdirectory "/home/foo/external-subdir" - :param subparsers: the caller instantiates subparsers and passes it in here - """ - add_external_subdirectory_subparser = subparsers.add_parser('add-external-subdirectory') - add_parser_args(add_external_subdirectory_subparser) - - -def main(): - """ - Runs add_external_subdirectory.py script as standalone script - """ - # parse the command line args - the_parser = argparse.ArgumentParser() - - # add subparsers - - # add args to the parser - add_parser_args(the_parser) - - # parse args - the_args = the_parser.parse_args() - - # run - ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 - - # return - sys.exit(ret) - - -if __name__ == "__main__": - main() diff --git a/scripts/o3de/o3de/add_gem_cmake.py b/scripts/o3de/o3de/add_gem_cmake.py deleted file mode 100644 index 523fb8dce8..0000000000 --- a/scripts/o3de/o3de/add_gem_cmake.py +++ /dev/null @@ -1,138 +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. -# -""" -Contains command to add a gem to a project's cmake scripts -""" - -import argparse -import logging -import pathlib -import sys - -from o3de import add_external_subdirectory, manifest, validation - -logger = logging.getLogger() -logging.basicConfig() - -def add_gem_to_cmake(gem_name: str = None, - gem_path: str or pathlib.Path = None, - engine_name: str = None, - engine_path: str or pathlib.Path = None) -> int: - """ - add a gem to a cmake as an external subdirectory for an engine - :param gem_name: name of the gem to add to cmake - :param gem_path: the path of the gem to add to cmake - :param engine_name: name of the engine to add to cmake - :param engine_path: the path of the engine to add external subdirectory to, default to this engine - :return: 0 for success or non 0 failure code - """ - if not gem_name and not gem_path: - logger.error('Must specify either a Gem name or Gem Path.') - return 1 - - if gem_name and not gem_path: - gem_path = manifest.get_registered(gem_name=gem_name) - - if not gem_path: - logger.error(f'Gem Path {gem_path} has not been registered.') - return 1 - - gem_path = pathlib.Path(gem_path).resolve() - gem_json = gem_path / 'gem.json' - if not gem_json.is_file(): - logger.error(f'Gem json {gem_json} is not present.') - return 1 - if not validation.valid_o3de_gem_json(gem_json): - logger.error(f'Gem json {gem_json} is not valid.') - return 1 - - if not engine_name and not engine_path: - engine_path = manifest.get_this_engine_path() - - if engine_name and not engine_path: - engine_path = manifest.get_registered(engine_name=engine_name) - - if not engine_path: - logger.error(f'Engine Path {engine_path} has not been registered.') - return 1 - - engine_json = engine_path / 'engine.json' - if not engine_json.is_file(): - logger.error(f'Engine json {engine_json} is not present.') - return 1 - if not validation.valid_o3de_engine_json(engine_json): - logger.error(f'Engine json {engine_json} is not valid.') - return 1 - - return add_external_subdirectory.add_external_subdirectory(external_subdir=gem_path, engine_path=engine_path) - -def _run_add_gem_to_cmake(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - - return add_gem_to_cmake(gem_name=args.gem_name, gem_path=args.gem_path) - - -def add_parser_args(parser): - """ - add_parser_args is called to add arguments to each command such that it can be - invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python add_gem_cmake.py --gem-path "/path/to/gem" - :param parser: the caller passes an argparse parser like instance to this method - """ - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-gp', '--gem-path', type=str, required=False, - help='The path to the gem.') - group.add_argument('-gn', '--gem-name', type=str, required=False, - help='The name of the gem.') - - 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.') - - parser.set_defaults(func=_run_add_gem_to_cmake) - - -def add_args(subparsers) -> None: - """ - add_args is called to add subparsers arguments to each command such that it can be - a central python file such as o3de.py. - It can be run from the o3de.py script as follows - call add_args and execute: python o3de.py add-gem-to-cmake --gem-path "/path/to/gem" - :param subparsers: the caller instantiates subparsers and passes it in here - """ - add_gem_cmake_subparser = subparsers.add_parser('add-gem-to-cmake') - add_parser_args(add_gem_cmake_subparser) - - -def main(): - """ - Runs add_gem_cmake.py script as standalone script - """ - # parse the command line args - the_parser = argparse.ArgumentParser() - - # add subparsers - - # add args to the parser - add_parser_args(the_parser) - - # parse args - the_args = the_parser.parse_args() - - # run - ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 - - # return - sys.exit(ret) - - -if __name__ == "__main__": - main() diff --git a/scripts/o3de/o3de/add_gem_project.py b/scripts/o3de/o3de/add_gem_project.py index 78dffc4477..8eb1468485 100644 --- a/scripts/o3de/o3de/add_gem_project.py +++ b/scripts/o3de/o3de/add_gem_project.py @@ -19,7 +19,7 @@ import os import pathlib import sys -from o3de import add_gem_cmake, cmake, manifest, validation +from o3de import cmake, manifest, validation logger = logging.getLogger() logging.basicConfig() @@ -239,9 +239,6 @@ def add_gem_to_project(gem_name: str = None, # add the dependency ret_val = add_gem_dependency(project_server_dependencies_file, gem_target) - if not ret_val and add_to_cmake: - ret_val = add_gem_cmake.add_gem_to_cmake(gem_path=gem_path, engine_path=engine_path) - return ret_val diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 6c14c2533f..bc27d9116c 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -131,7 +131,7 @@ def get_o3de_manifest() -> pathlib.Path: json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) json_data.update({'projects': []}) - json_data.update({'gems': []}) + json_data.update({'external_subdirectories': []}) json_data.update({'templates': []}) json_data.update({'restricted': []}) json_data.update({'repos': []}) @@ -172,8 +172,15 @@ def get_o3de_manifest() -> pathlib.Path: return manifest_path -def load_o3de_manifest() -> dict: - with get_o3de_manifest().open('r') as f: +def load_o3de_manifest(manifest_path: pathlib.Path = None) -> dict: + """ + Loads supplied manifest file or ~/.o3de/o3de_manifest.json if None + + :param manifest_path: optional path to manifest file to load + """ + if not manifest_path: + manifest_path = get_o3de_manifest() + with manifest_path.open('r') as f: try: json_data = json.load(f) except json.JSONDecodeError as e: @@ -183,8 +190,16 @@ def load_o3de_manifest() -> dict: return json_data -def save_o3de_manifest(json_data: dict) -> None: - with get_o3de_manifest().open('w') as s: +def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> None: + """ + Save the json dictionary to the supplied manifest file or ~/.o3de/o3de_manifest.json if None + + :param json_data: dictionary to save in json format at the file path + :param manifest_path: optional path to manifest file to save + """ + if not manifest_path: + manifest_path = get_o3de_manifest() + with manifest_path.open('w') as s: try: s.write(json.dumps(json_data, indent=4)) except OSError as e: @@ -198,36 +213,44 @@ def get_this_engine() -> dict: return engine_data -def get_engines() -> dict: +def get_engines() -> list: json_data = load_o3de_manifest() return json_data['engines'] -def get_projects() -> dict: +def get_projects() -> list: json_data = load_o3de_manifest() return json_data['projects'] -def get_gems() -> dict: - json_data = load_o3de_manifest() - return json_data['gems'] +def get_gems() -> list: + def is_gem_subdirectory(subdir): + return (pathlib.Path(subdir) / 'gem.json').exists() + + external_subdirs = get_external_subdirectories() + return list(filter(is_gem_subdirectory, external_subdirs)) if external_subdirs else [] -def get_templates() -> dict: +def get_templates() -> list: json_data = load_o3de_manifest() return json_data['templates'] -def get_restricted() -> dict: +def get_restricted() -> list: json_data = load_o3de_manifest() return json_data['restricted'] -def get_repos() -> dict: +def get_external_subdirectories() -> list: + json_data = load_o3de_manifest() + return json_data['external_subdirectories'] + + +def get_repos() -> list: json_data = load_o3de_manifest() return json_data['repos'] - +# engine.json queries def get_engine_projects() -> list: engine_path = get_this_engine_path() engine_object = get_engine_json_data(engine_path=engine_path) @@ -264,6 +287,21 @@ def get_engine_external_subdirectories() -> list: engine_object['external_subdirectories'])) if 'external_subdirectories' in engine_object else [] +# project.json queries +def get_project_gems(project_path: pathlib.Path) -> list: + def is_gem_subdirectory(subdir): + return (pathlib.Path(subdir) / 'gem.json').exists() + + external_subdirs = get_project_external_subdirectories() + return list(filter(is_gem_subdirectory, external_subdirs)) if external_subdirs else [] + + +def get_project_external_subdirectories(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['external_subdirectories'])) if 'external_subdirectories' in project_object else [] + + def get_all_projects() -> list: engine_projects = get_engine_projects() projects_data = get_projects() diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index c44af03b30..1b30448db9 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -1,3 +1,4 @@ + # # All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or # its licensors. @@ -23,7 +24,7 @@ import sys import urllib.parse import urllib.request -from o3de import add_gem_cmake, get_registration, manifest, remove_external_subdirectory, repo, utils, validation +from o3de import get_registration, manifest, repo, utils, validation logger = logging.getLogger() logging.basicConfig() @@ -183,7 +184,8 @@ def register_all_projects_in_folder(projects_path: str or pathlib.Path, def register_all_gems_in_folder(gems_path: str or pathlib.Path, remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: + engine_path: pathlib.Path = None, + project_path: pathlib.Path = None) -> int: return register_all_o3de_objects_of_type_in_folder(gems_path, 'gem', remove, False, engine_path=engine_path) @@ -283,105 +285,121 @@ def register_engine_path(json_data: dict, return add_engine_name_to_path(json_data, engine_path, force) +def register_o3de_object_path(json_data: dict, + o3de_object_path: str or pathlib.Path, + o3de_object_key: str, + o3de_json_filename: str, + validation_func: callable, + remove: bool = False, + engine_path: pathlib.Path = None, + project_path: pathlib.Path = None) -> int: + # save_path variable is used to save the changes to the store the path to the file to save + # if the registration is for the project or engine + save_path = None + + if not o3de_object_path: + logger.error(f'o3de object path cannot be empty.') + return 1 + + o3de_object_path = pathlib.Path(o3de_object_path).resolve() + + if engine_path and project_path: + logger.error(f'Both a project path: {project_path} and engine path: {engine_path} has been supplied.' + 'A subdirectory can only be registered to either the engine path or project in one command') + + manifest_data = None + if engine_path: + manifest_data = manifest.get_engine_json_data(json_data, engine_path) + if not manifest_data: + logger.error(f'Cannot load engine.json data at path {engine_path}') + return 1 + + save_path = engine_path / 'engine.json' + elif project_path: + manifest_data = manifest.get_project_json_data(json_data, project_path) + if not manifest_data: + logger.error(f'Cannot load project.json data at path {project_path}') + return 1 + + save_path = project_path / 'project.json' + else: + manifest_data = json_data + + paths_to_remove = [o3de_object_path] + if save_path: + try: + paths_to_remove.append(o3de_object_path.relative_to(save_path.parent)) + except ValueError: + pass # It is OK relative path cannot be formed + manifest_data[o3de_object_key] = list(filter(lambda p: pathlib.Path(p) not in paths_to_remove, + manifest_data.setdefault(o3de_object_key, []))) + + if remove: + if save_path: + manifest.save_o3de_manifest(manifest_data, save_path) + return 0 + + if not o3de_object_path.is_dir(): + logger.error(f'o3de object path {o3de_object_path} does not exist.') + return 1 + + manifest_json_path = o3de_object_path / o3de_json_filename + if validation_func and not validation_func(manifest_json_path): + logger.error(f'o3de json {manifest_json_path} is not valid.') + return 1 + + # if there is a save path make it relative the directory containing o3de object json file + if save_path: + try: + o3de_object_path = o3de_object_path.relative_to(save_path.parent) + except ValueError: + pass # It is OK relative path cannot be formed + manifest_data[o3de_object_key].insert(0, o3de_object_path.as_posix()) + if save_path: + manifest.save_o3de_manifest(manifest_data, save_path) + + return 0 + + +def register_external_subdirectory(json_data: dict, + external_subdir_path: str or pathlib.Path, + remove: bool = False, + engine_path: pathlib.Path = None, + project_path: pathlib.Path = None) -> int: + """ + :return An integer return code indicating whether registration or removal of the external subdirectory + completed successfully + """ + return register_o3de_object_path(json_data, external_subdir_path, 'external_subdirectories', '', None, remove, + engine_path, project_path) + + def register_gem_path(json_data: dict, gem_path: str or pathlib.Path, remove: bool = False, - engine_path: str or pathlib.Path = None) -> int: - if not gem_path: - logger.error(f'Gem path cannot be empty.') - return 1 - gem_path = pathlib.Path(gem_path).resolve() - - if engine_path: - engine_data = manifest.find_engine_data(json_data, engine_path) - if not engine_data: - logger.error(f'Engine path {engine_path} is not registered.') - return 1 - - engine_data['gems'] = list(filter(lambda p: gem_path != pathlib.Path(p), engine_data['gems'])) - - if remove: - logger.warn(f'Removing Gem path {gem_path}.') - return 0 - else: - json_data['gems'] = list(filter(lambda p: gem_path != pathlib.Path(p), json_data['gems'])) - - if remove: - logger.warn(f'Removing Gem path {gem_path}.') - return 0 - - if not gem_path.is_dir(): - logger.error(f'Gem path {gem_path} does not exist.') - return 1 - - gem_json = gem_path / 'gem.json' - if not validation.valid_o3de_gem_json(gem_json): - logger.error(f'Gem json {gem_json} is not valid.') - return 1 - - if engine_path: - engine_data['gems'].insert(0, gem_path.as_posix()) - else: - json_data['gems'].insert(0, gem_path.as_posix()) - - return 0 + engine_path: pathlib.Path = None, + project_path: pathlib.Path = None) -> int: + return register_o3de_object_path(json_data, gem_path, 'external_subdirectories', 'gem.json', + validation.valid_o3de_gem_json, remove, engine_path, project_path) def register_project_path(json_data: dict, project_path: str or pathlib.Path, remove: bool = False, engine_path: str or pathlib.Path = None) -> int: - if not project_path: - logger.error(f'Project path cannot be empty.') - return 1 - project_path = pathlib.Path(project_path).resolve() + result = register_o3de_object_path(json_data, project_path, 'projects', 'project.json', + validation.valid_o3de_project_json, remove, engine_path, None) - if engine_path: - engine_data = manifest.find_engine_data(json_data, engine_path) - if not engine_data: - logger.error(f'Engine path {engine_path} is not registered.') - return 1 - - engine_data['projects'] = list(filter(lambda p: project_path != pathlib.Path(p), engine_data['projects'])) - - if remove: - logger.warn(f'Engine {engine_path} removing Project path {project_path}.') - return 0 - else: - json_data['projects'] = list(filter(lambda p: project_path != pathlib.Path(p), json_data['projects'])) - - if remove: - logger.warn(f'Removing Project path {project_path}.') - return 0 - - if not project_path.is_dir(): - logger.error(f'Project path {project_path} does not exist.') - return 1 - - project_json = project_path / 'project.json' - if not validation.valid_o3de_project_json(project_json): - logger.error(f'Project json {project_json} is not valid.') - return 1 - - if engine_path: - engine_data['projects'].insert(0, project_path.as_posix()) - else: - json_data['projects'].insert(0, project_path.as_posix()) + if result != 0: + return result # registering a project has the additional step of setting the project.json 'engine' field - this_engine_json = manifest.get_this_engine_path() / 'engine.json' - with this_engine_json.open('r') as f: - try: - this_engine_json = json.load(f) - except json.JSONDecodeError as e: - logger.error(f'Engine json failed to load: {str(e)}') - return 1 - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.error(f'Project json failed to load: {str(e)}') - return 1 + this_engine_json = manifest.get_engine_json_data(engine_path=manifest.get_this_engine_path()) + if not this_engine_json: + return 1 + project_json_data = manifest.get_project_json_data(project_path=project_path) + if not project_json_data: + return 1 update_project_json = False try: @@ -399,6 +417,7 @@ def register_project_path(json_data: dict, logger.error(f'Project json failed to save: {str(e)}') return 1 + return 0 @@ -406,88 +425,16 @@ def register_template_path(json_data: dict, template_path: str or pathlib.Path, remove: bool = False, engine_path: str or pathlib.Path = None) -> int: - if not template_path: - logger.error(f'Template path cannot be empty.') - return 1 - template_path = pathlib.Path(template_path).resolve() - - if engine_path: - engine_data = manifest.find_engine_data(json_data, engine_path) - if not engine_data: - logger.error(f'Engine path {engine_path} is not registered.') - return 1 - - engine_data['templates'] = list(filter(lambda p: template_path != pathlib.Path(p), engine_data['templates'])) - - if remove: - logger.warn(f'Engine {engine_path} removing Template path {template_path}.') - return 0 - else: - json_data['templates'] = list(filter(lambda p: template_path != pathlib.Path(p), json_data['templates'])) - - if remove: - logger.warn(f'Removing Template path {template_path}.') - return 0 - - if not template_path.is_dir(): - logger.error(f'Template path {template_path} does not exist.') - return 1 - - template_json = template_path / 'template.json' - if not validation.valid_o3de_template_json(template_json): - logger.error(f'Template json {template_json} is not valid.') - return 1 - - if engine_path: - engine_data['templates'].insert(0, template_path.as_posix()) - else: - json_data['templates'].insert(0, template_path.as_posix()) - - return 0 + return register_o3de_object_path(json_data, template_path, 'templates', 'template.json', + validation.valid_o3de_template_json, remove, engine_path, None) def register_restricted_path(json_data: dict, restricted_path: str or pathlib.Path, remove: bool = False, engine_path: str or pathlib.Path = None) -> int: - if not restricted_path: - logger.error(f'Restricted path cannot be empty.') - return 1 - restricted_path = pathlib.Path(restricted_path).resolve() - - if engine_path: - engine_data = manifest.find_engine_data(json_data, engine_path) - if not engine_data: - logger.error(f'Engine path {engine_path} is not registered.') - return 1 - - engine_data['restricted'] = list(filter(lambda p: restricted_path != pathlib.Path(p), engine_data['restricted'])) - - if remove: - logger.warn(f'Engine {engine_path} removing Restricted path {restricted_path}.') - return 0 - else: - json_data['restricted'] = list(filter(lambda p: restricted_path != pathlib.Path(p), json_data['restricted'])) - - if remove: - logger.warn(f'Removing Restricted path {restricted_path}.') - return 0 - - if not restricted_path.is_dir(): - logger.error(f'Restricted path {restricted_path} does not exist.') - return 1 - - restricted_json = restricted_path / 'restricted.json' - if not validation.valid_o3de_restricted_json(restricted_json): - logger.error(f'Restricted json {restricted_json} is not valid.') - return 1 - - if engine_path: - engine_data['restricted'].insert(0, restricted_path.as_posix()) - else: - json_data['restricted'].insert(0, restricted_path.as_posix()) - - return 0 + return register_o3de_object_path(json_data, restricted_path, 'restricted', 'restricted.json', + validation.valid_o3de_restricted_json, remove, engine_path, None) def register_repo(json_data: dict, @@ -581,6 +528,7 @@ def register_default_restricted_folder(json_data: dict, def register(engine_path: str or pathlib.Path = None, project_path: str or pathlib.Path = None, gem_path: str or pathlib.Path = None, + external_subdir_path: str or pathlib.Path = None, template_path: str or pathlib.Path = None, restricted_path: str or pathlib.Path = None, repo_uri: str or pathlib.Path = None, @@ -589,15 +537,18 @@ 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, + external_subdir_engine_path: pathlib.Path = None, + external_subdir_project_path: pathlib.Path = None, remove: bool = False, force: bool = False ) -> int: """ - Adds/Updates entries to the .o3de/o3de_manifest.json + Adds/Updates entries to the ~/.o3de/o3de_manifest.json :param engine_path: if engine folder is supplied the path will be added to the engine if it can, if not global :param project_path: project folder :param gem_path: gem folder + :param external_subdir_path: external subdirectory :param template_path: template folder :param restricted_path: restricted folder :param repo_uri: repo uri @@ -606,6 +557,10 @@ 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 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. + The registrations occurs in the project.json in this case :param remove: add/remove the entries :param force: force update of the engine_path for specified "engine_name" from the engine.json file @@ -627,7 +582,14 @@ def register(engine_path: str or pathlib.Path = None, if not gem_path: logger.error(f'Gem path cannot be empty.') return 1 - result = register_gem_path(json_data, gem_path, remove, engine_path) + result = register_gem_path(json_data, gem_path, remove, + external_subdir_engine_path, external_subdir_project_path) + elif isinstance(external_subdir_path, str) or isinstance(external_subdir_path, pathlib.PurePath): + if not external_subdir_path: + logger.error(f'External Subdirectory path is None.') + return 1 + result = register_external_subdirectory(json_data, external_subdir_path, remove, + external_subdir_engine_path, external_subdir_project_path) elif isinstance(template_path, str) or isinstance(template_path, pathlib.PurePath): if not template_path: @@ -685,32 +647,6 @@ def remove_invalid_o3de_objects() -> None: if not validation.valid_o3de_engine_json(pathlib.Path(engine_path).resolve() / 'engine.json'): logger.warn(f"Engine path {engine_path} is invalid.") register(engine_path=engine_path, remove=True) - else: - for project in engine_object['projects']: - if not validation.valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): - logger.warn(f"Project path {project} is invalid.") - register(engine_path=engine_path, project_path=project, remove=True) - - for gem_path in engine_object['gems']: - if not validation.valid_o3de_gem_json(pathlib.Path(gem_path).resolve() / 'gem.json'): - logger.warn(f"Gem path {gem_path} is invalid.") - register(engine_path=engine_path, gem_path=gem_path, remove=True) - - for template_path in engine_object['templates']: - if not validation.valid_o3de_template_json(pathlib.Path(template_path).resolve() / 'template.json'): - logger.warn(f"Template path {template_path} is invalid.") - register(engine_path=engine_path, template_path=template_path, remove=True) - - for restricted in engine_object['restricted']: - if not validation.valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'): - logger.warn(f"Restricted path {restricted} is invalid.") - register(engine_path=engine_path, restricted_path=restricted, remove=True) - - for external in engine_object['external_subdirectories']: - external = pathlib.Path(external).resolve() - if not external.is_dir(): - logger.warn(f"External subdirectory {external} is invalid.") - remove_external_subdirectory.remove_external_subdirectory(external) for project in json_data['projects']: if not validation.valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): @@ -722,6 +658,12 @@ def remove_invalid_o3de_objects() -> None: logger.warn(f"Gem path {gem} is invalid.") register(gem_path=gem, remove=True) + for external in json_data['external_subdirectories']: + external = pathlib.Path(external).resolve() + if not external.is_dir(): + logger.warn(f"External subdirectory {external} is invalid.") + register(engine_path=engine_path, external_subdir_path=external, remove=True) + for template in json_data['templates']: if not validation.valid_o3de_template_json(pathlib.Path(template).resolve() / 'template.json'): logger.warn(f"Template path {template} is invalid.") @@ -804,6 +746,7 @@ def _run_register(args: argparse) -> int: return register(engine_path=args.engine_path, project_path=args.project_path, gem_path=args.gem_path, + external_subdir_path=args.external_subdirectory, template_path=args.template_path, restricted_path=args.restricted_path, repo_uri=args.repo_uri, @@ -812,6 +755,8 @@ def _run_register(args: argparse) -> int: default_gems_folder=args.default_gems_folder, default_templates_folder=args.default_templates_folder, default_restricted_folder=args.default_restricted_folder, + external_subdir_engine_path=args.external_subdirectory_engine_path, + external_subdir_project_path=args.external_subdirectory_project_path, remove=args.remove, force=args.force) @@ -833,6 +778,8 @@ def add_parser_args(parser): help='Project path to register/remove.') group.add_argument('-gp', '--gem-path', type=str, required=False, help='Gem path to register/remove.') + group.add_argument('-es', '--external-subdirectory', type=str, required=False, + help='External subdirectory path to register/remove.') group.add_argument('-tp', '--template-path', type=str, required=False, help='Template path to register/remove.') group.add_argument('-rp', '--restricted-path', type=str, required=False, @@ -872,6 +819,14 @@ def add_parser_args(parser): help='Remove entry.') parser.add_argument('-f', '--force', action='store_true', default=False, help='For the update of the registration field being modified.') + + external_subdir_group = parser.add_argument_group(title='external-subdirectory', + description='path arguments to use with the --external-subdirectory option') + external_subdir_path_group = external_subdir_group.add_mutually_exclusive_group() + external_subdir_path_group.add_argument('-esep', '--external-subdirectory-engine-path', type=pathlib.Path, + help='If supplied, registers the external subdirectory with the engine.json at' \ + ' the engine-path location') + external_subdir_path_group.add_argument('-espp', '--external-subdirectory-project-path', type=pathlib.Path) parser.set_defaults(func=_run_register) diff --git a/scripts/o3de/o3de/remove_external_subdirectory.py b/scripts/o3de/o3de/remove_external_subdirectory.py deleted file mode 100644 index b433e9c398..0000000000 --- a/scripts/o3de/o3de/remove_external_subdirectory.py +++ /dev/null @@ -1,120 +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. -# -""" -Implemens functinality to remove external_subdirectories from the o3de_manifests.json -""" - -import argparse -import logging -import pathlib -import sys - -from o3de import manifest - -logger = logging.getLogger() -logging.basicConfig() - -def remove_external_subdirectory(external_subdir: str or pathlib.Path, - engine_path: str or pathlib.Path = None) -> int: - """ - remove external subdirectory from cmake - :param external_subdir: external subdirectory to add to cmake - :param engine_path: optional engine path, defaults to this engine - :return: 0 for success or non 0 failure code - """ - json_data = manifest.load_o3de_manifest() - engine_object = manifest.find_engine_data(json_data, engine_path) - if not engine_object or not 'external_subdirectories' in engine_object: - logger.error(f'Remove External Subdirectory Failed: {engine_path} not registered.') - return 1 - - external_subdir = pathlib.Path(external_subdir).resolve() - while external_subdir.as_posix() in engine_object['external_subdirectories']: - engine_object['external_subdirectories'].remove(external_subdir.as_posix()) - - manifest.save_o3de_manifest(json_data) - - return 0 - - -def _run_remove_external_subdirectory(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - - return remove_external_subdirectory(args.external_subdirectory) - - -def add_args(parser, subparsers) -> None: - """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be - invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python register.py register --gem-path "C:/TestGem" - OR - o3de.py can downloadable commands by importing engine_template, - call add_args and execute: python o3de.py register --gem-path "C:/TestGem" - :param parser: the caller instantiates a parser and passes it in here - :param subparsers: the caller instantiates subparsers and passes it in here - """ - - -def add_parser_args(parser): - """ - add_parser_args is called to add arguments to each command such that it can be - invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python remove_external_subdirectory.py "D:/subdir" - :param parser: the caller passes an argparse parser like instance to this method - """ - parser.add_argument('external_subdirectory', metavar='external_subdirectory', - type=str, - help='remove external subdirectory from cmake') - - 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.') - - parser.set_defaults(func=_run_remove_external_subdirectory) - - -def add_args(subparsers) -> None: - """ - add_args is called to add subparsers arguments to each command such that it can be - a central python file such as o3de.py. - It can be run from the o3de.py script as follows - call add_args and execute: python o3de.py remove-external-subdirectory "D:/subdir" - :param subparsers: the caller instantiates subparsers and passes it in here - """ - remove_external_subdirectory_subparser = subparsers.add_parser('remove-external-subdirectory') - add_parser_args(remove_external_subdirectory_subparser) - - -def main(): - """ - Runs remove_external_subdirectory.py script as standalone script - """ - # parse the command line args - the_parser = argparse.ArgumentParser() - - # add subparsers - - # add args to the parser - add_parser_args(the_parser) - - # parse args - the_args = the_parser.parse_args() - - # run - ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 - - # return - sys.exit(ret) - - -if __name__ == "__main__": - main() diff --git a/scripts/o3de/o3de/remove_gem_cmake.py b/scripts/o3de/o3de/remove_gem_cmake.py deleted file mode 100644 index 3d988a579a..0000000000 --- a/scripts/o3de/o3de/remove_gem_cmake.py +++ /dev/null @@ -1,122 +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. -# -""" -Contains methods for removing a gem from a project's cmake scripts -""" - -import argparse -import logging -import pathlib -import sys - -from o3de import manifest, remove_external_subdirectory - -logger = logging.getLogger() -logging.basicConfig() - -def remove_gem_from_cmake(gem_name: str = None, - gem_path: str or pathlib.Path = None, - engine_name: str = None, - engine_path: str or pathlib.Path = None) -> int: - """ - remove a gem to cmake as an external subdirectory - :param gem_name: name of the gem to remove from cmake - :param gem_path: the path of the gem to add to cmake - :param engine_name: optional name of the engine to remove from cmake - :param engine_path: the path of the engine to remove external subdirectory from, defaults to this engine - :return: 0 for success or non 0 failure code - """ - if not gem_name and not gem_path: - logger.error('Must specify either a Gem name or Gem Path.') - return 1 - - if gem_name and not gem_path: - gem_path = manifest.get_registered(gem_name=gem_name) - - if not gem_path: - logger.error(f'Gem Path {gem_path} has not been registered.') - return 1 - - if not engine_name and not engine_path: - engine_path = manifest.get_this_engine_path() - - if engine_name and not engine_path: - engine_path = manifest.get_registered(engine_name=engine_name) - - if not engine_path: - logger.error(f'Engine Path {engine_path} is not registered.') - return 1 - - return remove_external_subdirectory.remove_external_subdirectory(external_subdir=gem_path, engine_path=engine_path) - - -def _run_remove_gem_from_cmake(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - - return remove_gem_from_cmake(args.gem_name, args.gem_path) - - -def add_parser_args(parser): - """ - add_parser_args is called to add arguments to each command such that it can be - invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python remove_gem_cmake.py --gem-name Atom - :param parser: the caller passes an argparse parser like instance to this method - """ - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-gp', '--gem-path', type=str, required=False, - help='The path to the gem.') - group.add_argument('-gn', '--gem-name', type=str, required=False, - help='The name of the gem.') - - 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.') - - parser.set_defaults(func=_run_remove_gem_from_cmake) - - -def add_args(subparsers) -> None: - """ - add_args is called to add subparsers arguments to each command such that it can be - a central python file such as o3de.py. - It can be run from the o3de.py script as follows - call add_args and execute: python o3de.py remove-gem-from-cmake --gem-name Atom - :param subparsers: the caller instantiates subparsers and passes it in here - """ - remove_gem_from_cmake_subparser = subparsers.add_parser('remove-gem-from-cmake') - add_parser_args(remove_gem_from_cmake_subparser) - - -def main(): - """ - Runs remove_gem_cmake.py script as standalone script - """ - # parse the command line args - the_parser = argparse.ArgumentParser() - - # add subparsers - - # add args to the parser - add_parser_args(the_parser) - - # parse args - the_args = the_parser.parse_args() - - # run - ret = the_args.func(the_args) if hasattr(the_args, 'func') else 1 - - # return - sys.exit(ret) - - -if __name__ == "__main__": - main() diff --git a/scripts/o3de/o3de/remove_gem_project.py b/scripts/o3de/o3de/remove_gem_project.py index 671427db14..463cc69961 100644 --- a/scripts/o3de/o3de/remove_gem_project.py +++ b/scripts/o3de/o3de/remove_gem_project.py @@ -18,7 +18,7 @@ import os import pathlib import sys -from o3de import cmake, remove_gem_cmake +from o3de import cmake logger = logging.getLogger() logging.basicConfig() @@ -196,11 +196,6 @@ def remove_gem_from_project(gem_name: str = None, if error_code: ret_val = error_code - if remove_from_cmake: - error_code = remove_gem_cmake.remove_gem_from_cmake(gem_path=gem_path) - if error_code: - ret_val = error_code - return ret_val @@ -256,9 +251,6 @@ def add_parser_args(parser): default='Common', help='Optional list of platforms this gem should be removed from' ' Ex. --platforms Mac,Windows,Linux') - parser.add_argument('-r', '--remove-from-cmake', type=bool, required=False, - default=False, - help='Automatically call remove-from-cmake.') 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.') From 84a3a3d40a7fa74059cda929888626cca8e21292 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 24 May 2021 22:53:57 -0500 Subject: [PATCH 089/140] Updating the DefaultProject template to copy over a gem.json file to the Code folder of the created project, since the Code itself is a GEM_MODULE that loads using the Module loading system --- Templates/DefaultProject/Template/Code/gem.json | 14 ++++++++++++++ Templates/DefaultProject/template.json | 6 ++++++ 2 files changed, 20 insertions(+) create mode 100644 Templates/DefaultProject/Template/Code/gem.json diff --git a/Templates/DefaultProject/Template/Code/gem.json b/Templates/DefaultProject/Template/Code/gem.json new file mode 100644 index 0000000000..5b8fb3fde0 --- /dev/null +++ b/Templates/DefaultProject/Template/Code/gem.json @@ -0,0 +1,14 @@ +{ + "gem_name": "${Name}", + "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "${Name}", + "summary": "A short description of ${Name}.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "${Name}" + ], + "icon_path": "preview.png" +} diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index 31b448c9f6..d654c3a969 100644 --- a/Templates/DefaultProject/template.json +++ b/Templates/DefaultProject/template.json @@ -48,6 +48,12 @@ "isTemplated": true, "isOptional": false }, + { + "file": "Code/gem.json", + "origin": "Code/gem.json", + "isTemplated": true, + "isOptional": true + }, { "file": "Code/Include/${Name}/${Name}Bus.h", "origin": "Code/Include/${Name}/${Name}Bus.h", From d2a15de66835255d08dfd9e142cc5c951b10bd67 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 24 May 2021 22:56:35 -0500 Subject: [PATCH 090/140] Adding support to read an "external_subdirectories" key from the project.json when building a project. This allows the project to build additional gems via adding the external subdirectory in the project.json file manually or using the `o3de.py register --external-subdirectory-path= --external_subdirectory-project-path-` command --- CMakeLists.txt | 17 ++++-- Templates/DefaultGem/Template/CMakeLists.txt | 2 +- cmake/O3DEJson.cmake | 55 ++++++++++++++++++++ cmake/Projects.cmake | 39 +++++++++----- 4 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 cmake/O3DEJson.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d743a8ab57..83c9d7d14f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,11 +53,22 @@ include(cmake/Monolithic.cmake) include(cmake/SettingsRegistry.cmake) include(cmake/TestImpactFramework/LYTestImpactFramework.cmake) include(cmake/CMakeFiles.cmake) +include(cmake/O3DEJson.cmake) ################################################################################ # Subdirectory processing ################################################################################ +function(add_engine_json_external_subdirectories) + read_json_external_subdirs(external_subdis ${LY_ROOT_FOLDER}/engine.json) + foreach(external_subdir ${external_subdis}) + file(REAL_PATH ${external_subdir} real_external_subdir BASE_DIRECTORY ${LY_ROOT_FOLDER}) + list(APPEND engine_external_subdirs ${real_external_subdir}) + endforeach() + + set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${engine_external_subdirs}) +endfunction() + # Add the projects first so the Launcher can find them include(cmake/Projects.cmake) @@ -73,11 +84,11 @@ if(NOT INSTALLED_ENGINE) add_subdirectory(Tools/RemoteConsole/ly_remote_console/tests/) endif() - include(cmake/EngineJson.cmake) # Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra # external subdirectories - read_engine_external_subdirs(engine_external_subdirectories) - list(APPEND LY_EXTERNAL_SUBDIRS ${engine_external_subdirectories}) + add_engine_json_external_subdirectories() + get_property(external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS) + list(APPEND LY_EXTERNAL_SUBDIRS ${external_subdirs}) # Loop over the additional external subdirectories and invoke add_subdirectory on them foreach(external_directory ${LY_EXTERNAL_SUBDIRS}) diff --git a/Templates/DefaultGem/Template/CMakeLists.txt b/Templates/DefaultGem/Template/CMakeLists.txt index fb63008782..1a24bd488f 100644 --- a/Templates/DefaultGem/Template/CMakeLists.txt +++ b/Templates/DefaultGem/Template/CMakeLists.txt @@ -11,7 +11,7 @@ set(o3de_gem_path ${CMAKE_CURRENT_LIST_DIR}) set(o3de_gem_json ${o3de_gem_path}/gem.json) -o3de_gem_name(${o3de_gem_json} o3de_gem_name) +o3de_read_json_key(o3de_gem_name ${o3de_gem_json} "gem_name") o3de_restricted_path(${o3de_gem_json} o3de_gem_restricted_path) # Currently we are in the DefaultProjectSource folder: ${CMAKE_CURRENT_LIST_DIR} diff --git a/cmake/O3DEJson.cmake b/cmake/O3DEJson.cmake new file mode 100644 index 0000000000..5d748e9681 --- /dev/null +++ b/cmake/O3DEJson.cmake @@ -0,0 +1,55 @@ +# +# 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. +# + +include_guard() + +set(LY_EXTERNAL_SUBDIRS "" CACHE STRING "List of subdirectories to recurse into when running cmake against the engine's CMakeLists.txt") + +#! read_json_external_subdirs +# Read the "external_subdirectories" array from a *.json file +# External subdirectories are any folders with CMakeLists.txt in them +# This could be regular subdirectories, Gems(contains an additional gem.json), +# Restricted folders(contains an additional restricted.json), etc... +# +# \arg:output_external_subdirs name of output variable to store external subdirectories into +# \arg:input_json_path path to the *.json file to load and read the external subdirectories from +# \return: external subdirectories as is from the json file. +function(read_json_external_subdirs output_external_subdirs input_json_path) + file(READ ${input_json_path} manifest_json_data) + string(JSON external_subdirs_count ERROR_VARIABLE manifest_json_error + LENGTH ${manifest_json_data} "external_subdirectories") + if(manifest_json_error) + # There is "external_subdirectories" key, so theire are no subdirectories to read + return() + endif() + + if(external_subdirs_count GREATER 0) + math(EXPR external_subdir_range "${external_subdirs_count}-1") + foreach(external_subdir_index RANGE ${external_subdir_range}) + string(JSON external_subdir ERROR_VARIABLE manifest_json_error + GET ${manifest_json_data} "external_subdirectories" "${external_subdir_index}") + if(manifest_json_error) + message(FATAL_ERROR "Error reading field at index ${external_subdir_index} in \"external_subdirectories\" JSON array: ${manifest_json_error}") + endif() + list(APPEND external_subdirs ${external_subdir}) + endforeach() + endif() + set(${output_external_subdirs} ${external_subdirs} PARENT_SCOPE) +endfunction() + +function(o3de_read_json_key output_value input_json_path key) + file(READ ${input_json_path} manifest_json_data) + string(JSON value ERROR_VARIABLE manifest_json_error GET ${manifest_json_data} ${key}) + if(manifest_json_error) + message(FATAL_ERROR "Error reading field at key ${key} in file \"${input_json_path}\" : ${manifest_json_error}") + endif() + set(${output_value} ${value} PARENT_SCOPE) +endfunction() diff --git a/cmake/Projects.cmake b/cmake/Projects.cmake index 781fee3711..297dad4ddf 100644 --- a/cmake/Projects.cmake +++ b/cmake/Projects.cmake @@ -105,6 +105,7 @@ function(ly_add_project_dependencies) ) endfunction() + #template for generating the project build_path setreg set(project_build_path_template [[ { @@ -120,7 +121,6 @@ set(project_build_path_template [[ }]] ) - #! ly_generate_project_build_path_setreg: Generates a .setreg file that contains an absolute path to the ${CMAKE_BINARY_DIR} # This allows locate the directory where the project it's binaries are built to be located within the engine. # Which are the shared libraries and launcher executables @@ -136,18 +136,32 @@ set(project_build_path_template [[ # can only run on the host platform # \arg:project_real_path Full path to the o3de project directory function(ly_generate_project_build_path_setreg project_real_path) - # The build path isn't needed on non-monolithic platforms - # Nor on any non-host platforms - if (LY_MONOLITHIC_GAME OR NOT PAL_TRAIT_BUILD_HOST_TOOLS) - return() - endif() + # The build path isn't needed on non-monolithic platforms + # Nor on any non-host platforms + if (LY_MONOLITHIC_GAME OR NOT PAL_TRAIT_BUILD_HOST_TOOLS) + return() + endif() - # Set the project_bin_path to the ${CMAKE_BINARY_DIR} to provide the configure template - # with the project build directory - set(project_bin_path ${CMAKE_BINARY_DIR}) - string(CONFIGURE ${project_build_path_template} project_build_path_setreg_content @ONLY) - set(project_user_build_path_setreg_file ${project_real_path}/user/Registry/Platform/${PAL_PLATFORM_NAME}/build_path.setreg) - file(GENERATE OUTPUT ${project_user_build_path_setreg_file} CONTENT ${project_build_path_setreg_content}) + # Set the project_bin_path to the ${CMAKE_BINARY_DIR} to provide the configure template + # with the project build directory + set(project_bin_path ${CMAKE_BINARY_DIR}) + string(CONFIGURE ${project_build_path_template} project_build_path_setreg_content @ONLY) + set(project_user_build_path_setreg_file ${project_real_path}/user/Registry/Platform/${PAL_PLATFORM_NAME}/build_path.setreg) + file(GENERATE OUTPUT ${project_user_build_path_setreg_file} CONTENT ${project_build_path_setreg_content}) +endfunction() + + +function(add_project_json_external_subdirectories project_path) + set(project_json_path ${project_path}/project.json) + if(EXISTS ${project_json_path}) + read_json_external_subdirs(external_subdirs ${project_path}/project.json) + foreach(external_subdir ${external_subdirs}) + file(REAL_PATH ${external_subdir} real_external_subdir BASE_DIRECTORY ${project_path}) + list(APPEND project_external_subdirs ${real_external_subdir}) + endforeach() + + set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${project_external_subdirs}) + endif() endfunction() # Add the projects here so the above function is found @@ -163,5 +177,6 @@ foreach(project ${LY_PROJECTS}) list(APPEND LY_PROJECTS_FOLDER_NAME ${project_folder_name}) add_subdirectory(${project} "${project_folder_name}-${full_directory_hash}") ly_generate_project_build_path_setreg(${full_directory_path}) + add_project_json_external_subdirectories(${full_directory_path}) endforeach() ly_set(LY_PROJECTS_FOLDER_NAME ${LY_PROJECTS_FOLDER_NAME}) From 79ba6c0ecff130ea498a5ebb61cb09caccc3f764 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 25 May 2021 17:00:26 -0500 Subject: [PATCH 091/140] Updating the EngineFinder.cmake for the AutomatedTesting project to use the engines_path key --- AutomatedTesting/EngineFinder.cmake | 51 ++++++++++++++++++----------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/AutomatedTesting/EngineFinder.cmake b/AutomatedTesting/EngineFinder.cmake index 9ff8ce4d66..a7dbf671fd 100644 --- a/AutomatedTesting/EngineFinder.cmake +++ b/AutomatedTesting/EngineFinder.cmake @@ -20,33 +20,46 @@ if(json_error) message(FATAL_ERROR "Unable to read key 'engine' from 'project.json', error: ${json_error}") endif() -# Read the list of paths from ~.o3de/o3de_manifest.json -file(TO_CMAKE_PATH "$ENV{USERPROFILE}" home_directory) # Windows -if((NOT home_directory) OR (NOT EXISTS ${home_directory})) - file(TO_CMAKE_PATH "$ENV{HOME}" home_directory)# Unix +if(DEFINED ENV{USERPROFILE} AND EXISTS $ENV{USERPROFILE}) + set(manifest_path $ENV{USERPROFILE}/.o3de/o3de_manifest.json) # Windows +else() + set(manifest_path $ENV{HOME}/.o3de/o3de_manifest.json) # Unix endif() -if (NOT home_directory) - message(FATAL_ERROR "Cannot find user home directory, the o3de manifest cannot be found") -endif() -# Set manifest path to path in the user home directory -set(manifest_path ${home_directory}/.o3de/o3de_manifest.json) - +# Read the ~/.o3de/o3de_manifest.json file and look through the 'engines_path' object. +# Find a key that matches LY_ENGINE_NAME_TO_USE and use that as the engine path. if(EXISTS ${manifest_path}) file(READ ${manifest_path} manifest_json) - string(JSON engines_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines) + + string(JSON engines_path_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines_path) if(json_error) - message(FATAL_ERROR "Unable to read key 'engines' from '${manifest_path}', error: ${json_error}") + message(FATAL_ERROR "Unable to read key 'engines_path' from '${manifest_path}', error: ${json_error}") endif() - math(EXPR engines_count "${engines_count}-1") - foreach(engine_path_index RANGE ${engines_count}) - string(JSON engine_path ERROR_VARIABLE json_error GET ${manifest_json} engines ${engine_path_index}) - if(${json_error}) - message(FATAL_ERROR "Unable to read engines[${engine_path_index}] '${manifest_path}', error: ${json_error}") + string(JSON engines_path_type ERROR_VARIABLE json_error TYPE ${manifest_json} engines_path) + if(json_error OR NOT ${engines_path_type} STREQUAL "OBJECT") + message(FATAL_ERROR "Type of 'engines_path' in '${manifest_path}' is not a JSON Object, error: ${json_error}") + endif() + + math(EXPR engines_path_count "${engines_path_count}-1") + foreach(engine_path_index RANGE ${engines_path_count}) + string(JSON engine_name ERROR_VARIABLE json_error MEMBER ${manifest_json} engines_path ${engine_path_index}) + if(json_error) + message(FATAL_ERROR "Unable to read 'engines_path/${engine_path_index}' from '${manifest_path}', error: ${json_error}") endif() - if(engine_path) - list(APPEND CMAKE_MODULE_PATH "${engine_path}/cmake") + + if(LY_ENGINE_NAME_TO_USE STREQUAL engine_name) + string(JSON engine_path ERROR_VARIABLE json_error GET ${manifest_json} engines_path ${engine_name}) + if(json_error) + message(FATAL_ERROR "Unable to read value from 'engines_path/${engine_name}', error: ${json_error}") + endif() + + if(engine_path) + list(APPEND CMAKE_MODULE_PATH "${engine_path}/cmake") + break() + endif() endif() endforeach() +else() + message(FATAL_ERROR "Engine registration is required before configuring a project. Please register an engine by running 'scripts/o3de register --this-engine'") endif() From 19adbf2f4145ced221d7a2af7c864fac2d5f710b Mon Sep 17 00:00:00 2001 From: pappeste Date: Tue, 25 May 2021 15:12:17 -0700 Subject: [PATCH 092/140] Removing adding runtime dependencies for gems that are in the BUILD_DEPENDENCIES --- Code/Sandbox/Editor/CMakeLists.txt | 5 ++++- .../ComponentEntityEditorPlugin/CMakeLists.txt | 5 ++++- Gems/AWSClientAuth/Code/CMakeLists.txt | 14 ++++++++++---- Gems/AWSMetrics/Code/CMakeLists.txt | 7 +++++-- Gems/AudioEngineWwise/Code/CMakeLists.txt | 3 ++- Gems/AudioSystem/Code/CMakeLists.txt | 3 ++- Gems/GameStateSamples/Code/CMakeLists.txt | 4 ++++ Gems/GradientSignal/Code/CMakeLists.txt | 7 +++---- Gems/GraphCanvas/Code/CMakeLists.txt | 1 - Gems/ImGui/Code/CMakeLists.txt | 2 ++ Gems/LandscapeCanvas/Code/CMakeLists.txt | 15 ++++++++++----- Gems/LyShine/Code/CMakeLists.txt | 12 ++++++++---- Gems/PhysXDebug/Code/CMakeLists.txt | 4 ++-- Gems/SceneProcessing/Code/CMakeLists.txt | 3 ++- Gems/ScriptCanvas/Code/CMakeLists.txt | 7 ++++++- Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt | 1 + Gems/ScriptCanvasPhysics/Code/CMakeLists.txt | 2 ++ Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 5 +++++ Gems/Twitch/Code/CMakeLists.txt | 2 ++ Gems/Vegetation/Code/CMakeLists.txt | 3 ++- cmake/LYWrappers.cmake | 2 -- 21 files changed, 76 insertions(+), 31 deletions(-) diff --git a/Code/Sandbox/Editor/CMakeLists.txt b/Code/Sandbox/Editor/CMakeLists.txt index c62e05f012..843f7cf04d 100644 --- a/Code/Sandbox/Editor/CMakeLists.txt +++ b/Code/Sandbox/Editor/CMakeLists.txt @@ -129,6 +129,8 @@ ly_add_target( 3rdParty::AWSNativeSDK::Core 3rdParty::Qt::Network Legacy::EditorCore + RUNTIME_DEPENDENCIES + Gem::AtomViewportDisplayInfo ) ly_add_source_properties( SOURCES CryEdit.cpp @@ -243,7 +245,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) Legacy::CryCommon AZ::AzToolsFramework Legacy::EditorLib - Gem::LmbrCentral + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) ly_add_googletest( NAME Legacy::EditorLib.Tests diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt index 66c96eb4c6..80da6e6b2c 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt @@ -36,6 +36,8 @@ ly_add_target( Legacy::CryCommon Legacy::EditorLib Gem::LmbrCentral.Editor + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) ly_add_dependencies(Editor ComponentEntityEditorPlugin) @@ -65,7 +67,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzToolsFrameworkTestCommon Legacy::CryCommon Legacy::EditorLib - Gem::LmbrCentral.Editor + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) ly_add_googletest( NAME Legacy::ComponentEntityEditorPlugin.Tests diff --git a/Gems/AWSClientAuth/Code/CMakeLists.txt b/Gems/AWSClientAuth/Code/CMakeLists.txt index e9f2a4ed84..a80fb6d532 100644 --- a/Gems/AWSClientAuth/Code/CMakeLists.txt +++ b/Gems/AWSClientAuth/Code/CMakeLists.txt @@ -29,6 +29,9 @@ ly_add_target( Gem::HttpRequestor 3rdParty::AWSNativeSDK::AWSClientAuth 3rdParty::AWSNativeSDK::Core + RUNTIME_DEPENDENCIES + Gem::AWSCore + Gem::HttpRequestor ) ly_add_target( @@ -44,11 +47,13 @@ ly_add_target( AZ::AzCore AZ::AzFramework Gem::AWSCore - Gem::HttpRequestor 3rdParty::AWSNativeSDK::AWSClientAuth 3rdParty::AWSNativeSDK::Core PUBLIC Gem::AWSClientAuth.Static + RUNTIME_DEPENDENCIES + Gem::AWSCore + Gem::HttpRequestor ) ################################################################################ @@ -71,10 +76,11 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) 3rdParty::AWSNativeSDK::AWSClientAuth AZ::AzCore AZ::AzFramework - Gem::AWSCore Gem::AWSClientAuth.Static - AZ::AWSNativeSDKInit - Gem::HttpRequestor + RUNTIUME_DEPENDENCIES + Gem::AWSCore + AZ::AWSNativeSDKInit + Gem::HttpRequestor ) ly_add_googletest( NAME Gem::AWSClientAuth.Tests diff --git a/Gems/AWSMetrics/Code/CMakeLists.txt b/Gems/AWSMetrics/Code/CMakeLists.txt index ffa9ac0408..a67583208e 100644 --- a/Gems/AWSMetrics/Code/CMakeLists.txt +++ b/Gems/AWSMetrics/Code/CMakeLists.txt @@ -23,6 +23,7 @@ ly_add_target( PRIVATE AZ::AzCore AZ::AzFramework + PUBLIC Gem::AWSCore ) @@ -40,8 +41,9 @@ ly_add_target( PRIVATE AZ::AzCore AZ::AzFramework - Gem::AWSCore Gem::AWSMetrics.Static + RUNTIME_DEPENDENCIES + Gem::AWSCore ) ################################################################################ @@ -63,8 +65,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest AZ::AzCore AZ::AzFramework - Gem::AWSCore Gem::AWSMetrics.Static + RUNTIME_DEPENDENCIES + Gem::AWSCore ) ly_add_googletest( NAME Gem::AWSMetrics.Tests diff --git a/Gems/AudioEngineWwise/Code/CMakeLists.txt b/Gems/AudioEngineWwise/Code/CMakeLists.txt index 5ea6a6d461..08e3ef53d0 100644 --- a/Gems/AudioEngineWwise/Code/CMakeLists.txt +++ b/Gems/AudioEngineWwise/Code/CMakeLists.txt @@ -205,7 +205,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC AZ::AssetBuilderSDK Gem::AudioEngineWwise.Static - Gem::AudioSystem.Editor + RUNTIME_DEPENDENCIES + Gem::AudioSystem.Editor ) ly_add_target( diff --git a/Gems/AudioSystem/Code/CMakeLists.txt b/Gems/AudioSystem/Code/CMakeLists.txt index 8a6f2c417e..83b3393a03 100644 --- a/Gems/AudioSystem/Code/CMakeLists.txt +++ b/Gems/AudioSystem/Code/CMakeLists.txt @@ -101,7 +101,8 @@ if (PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzFramework Legacy::CryCommon Gem::AudioSystem.Static - Gem::LmbrCentral + RUNTIME_DEPENDENCIES + Gem::LmbrCentral ) ly_add_googletest( NAME Gem::AudioSystem.Tests diff --git a/Gems/GameStateSamples/Code/CMakeLists.txt b/Gems/GameStateSamples/Code/CMakeLists.txt index e3ebc25016..2a7a2cd3ba 100644 --- a/Gems/GameStateSamples/Code/CMakeLists.txt +++ b/Gems/GameStateSamples/Code/CMakeLists.txt @@ -44,4 +44,8 @@ ly_add_target( AZ::AzFramework Gem::LmbrCentral Gem::GameStateSamples.Headers + RUNTIME_DEPENDENCIES + Gem::GameState + Gem::LocalUser + Gem::LmbrCentral ) diff --git a/Gems/GradientSignal/Code/CMakeLists.txt b/Gems/GradientSignal/Code/CMakeLists.txt index f7f8571beb..bb90f6a9af 100644 --- a/Gems/GradientSignal/Code/CMakeLists.txt +++ b/Gems/GradientSignal/Code/CMakeLists.txt @@ -44,7 +44,6 @@ ly_add_target( Gem::ImageProcessingAtom.Headers # Atom/ImageProcessing/PixelFormats.h is part of a header in Includes RUNTIME_DEPENDENCIES Gem::LmbrCentral - Gem::SurfaceData ) if(PAL_TRAIT_BUILD_HOST_TOOLS) @@ -67,10 +66,11 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) 3rdParty::Qt::Widgets Legacy::CryCommon AZ::AzToolsFramework - Gem::LmbrCentral.Editor - Gem::SurfaceData AZ::AssetBuilderSDK Gem::GradientSignal.Static + Gem::SurfaceData + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) ly_add_target( @@ -89,7 +89,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::GradientSignal.Editor.Static RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor - Gem::SurfaceData.Editor ) endif() diff --git a/Gems/GraphCanvas/Code/CMakeLists.txt b/Gems/GraphCanvas/Code/CMakeLists.txt index 683b0e4bdf..869d981730 100644 --- a/Gems/GraphCanvas/Code/CMakeLists.txt +++ b/Gems/GraphCanvas/Code/CMakeLists.txt @@ -51,7 +51,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME GraphCanvas.Editor GEM_MODULE - NAMESPACE Gem AUTOMOC AUTORCC diff --git a/Gems/ImGui/Code/CMakeLists.txt b/Gems/ImGui/Code/CMakeLists.txt index 0751c5825b..16dad0bfd3 100644 --- a/Gems/ImGui/Code/CMakeLists.txt +++ b/Gems/ImGui/Code/CMakeLists.txt @@ -53,6 +53,8 @@ ly_add_target( PUBLIC Gem::ImGui.imguilib Legacy::CryCommon + RUNTIME_DEPENDENCIES + Gem::ImGui.imguilib ) ly_add_target( diff --git a/Gems/LandscapeCanvas/Code/CMakeLists.txt b/Gems/LandscapeCanvas/Code/CMakeLists.txt index 497c83845f..c82225560e 100644 --- a/Gems/LandscapeCanvas/Code/CMakeLists.txt +++ b/Gems/LandscapeCanvas/Code/CMakeLists.txt @@ -35,16 +35,21 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryCommon Legacy::Editor.Headers Legacy::EditorCommon - Gem::LmbrCentral.Editor - Gem::GraphCanvasWidgets Gem::GraphModel.Editor.Static Gem::GradientSignal.Editor Gem::SurfaceData.Editor Gem::Vegetation.Editor + Gem::LmbrCentral.Editor + PUBLIC + Gem::GraphCanvasWidgets + RUNTIME_DEPENDENCIES + Gem::GradientSignal.Editor + Gem::SurfaceData.Editor + Gem::Vegetation.Editor + Gem::LmbrCentral.Editor ) ly_add_target( NAME LandscapeCanvas.Editor GEM_MODULE - NAMESPACE Gem FILES_CMAKE landscapecanvas_editor_files.cmake @@ -61,7 +66,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzCore AZ::AzToolsFramework Legacy::Editor.Headers - Gem::GraphCanvasWidgets Gem::GraphModel.Editor.Static Gem::LandscapeCanvas.Editor.Static RUNTIME_DEPENDENCIES @@ -97,9 +101,10 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest AZ::AzFramework AZ::AzToolsFramework - Gem::GraphCanvasWidgets Gem::GraphModel.Editor.Static Gem::LandscapeCanvas.Editor.Static + RUNTIME_DEPENDENCIES + Gem::GraphCanvasWidgets ) ly_add_googletest( NAME Gem::LandscapeCanvas.Editor.Tests diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index d9f011750e..4237434abd 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -92,6 +92,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Atom_RPI.Public Gem::Atom_Utils.Static Gem::Atom_Bootstrap.Headers + RUNTIME_DEPENDENCIES + Gem::TextureAtlas ) ly_add_target( @@ -143,8 +145,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest Gem::LyShine.Static Legacy::CryCommon - Gem::LmbrCentral - Gem::TextureAtlas + RUNTIME_DEPENDENCIES + Gem::LmbrCentral + Gem::TextureAtlas ) ly_add_googletest( NAME Gem::LyShine.Tests @@ -173,9 +176,10 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest Legacy::CryCommon AZ::AssetBuilderSDK - Gem::LmbrCentral.Editor - Gem::TextureAtlas Gem::LyShine.Editor.Static + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor + Gem::TextureAtlas ) ly_add_googletest( NAME Gem::LyShine.Editor.Tests diff --git a/Gems/PhysXDebug/Code/CMakeLists.txt b/Gems/PhysXDebug/Code/CMakeLists.txt index f198f6f26e..e7d624fe99 100644 --- a/Gems/PhysXDebug/Code/CMakeLists.txt +++ b/Gems/PhysXDebug/Code/CMakeLists.txt @@ -66,9 +66,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryCommon Legacy::Editor.Headers AZ::AzToolsFramework - Gem::PhysX + Gem::PhysX.Editor Gem::ImGui.imguilib - Gem::ImGui + Gem::ImGui.Editor RUNTIME_DEPENDENCIES Gem::PhysX.Editor Gem::ImGui.Editor diff --git a/Gems/SceneProcessing/Code/CMakeLists.txt b/Gems/SceneProcessing/Code/CMakeLists.txt index 67124a74d5..9af46aaa20 100644 --- a/Gems/SceneProcessing/Code/CMakeLists.txt +++ b/Gems/SceneProcessing/Code/CMakeLists.txt @@ -84,7 +84,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) BUILD_DEPENDENCIES PRIVATE AZ::AzTest - Gem::SceneProcessing + RUNTIME_DEPENDENCIES + Gem::SceneProcessing ) ly_add_googletest( NAME Gem::SceneProcessing.Tests diff --git a/Gems/ScriptCanvas/Code/CMakeLists.txt b/Gems/ScriptCanvas/Code/CMakeLists.txt index 32efa74520..75f1194aa8 100644 --- a/Gems/ScriptCanvas/Code/CMakeLists.txt +++ b/Gems/ScriptCanvas/Code/CMakeLists.txt @@ -81,6 +81,8 @@ ly_add_target( *.ScriptCanvasGrammar.xml,ScriptCanvasGrammar_Source.jinja,$path/$fileprefix.generated.cpp *.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Header.jinja,$path/$fileprefix.generated.h *.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Source.jinja,$path/$fileprefix.generated.cpp + RUNTIME_DEPENDENCIES + Gem::ScriptCanvasDebugger ) ly_add_target( @@ -170,6 +172,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::ExpressionEvaluation.Static PRIVATE Legacy::EditorCore + RUNTIME_DEPENDENCIES + Gem::ScriptCanvas ) ly_add_target( @@ -228,7 +232,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) PRIVATE AZ::AzTest AZ::AzFramework - Gem::ScriptCanvas + RUNTIME_DEPENDENCIES + Gem::ScriptCanvas ) ly_add_googletest( NAME Gem::ScriptCanvas.Tests diff --git a/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt b/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt index d9ce9004d3..5f8c01b70d 100644 --- a/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt @@ -81,5 +81,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::GraphCanvasWidgets RUNTIME_DEPENDENCIES Gem::ScriptCanvas.Editor + Gem::GraphCanvasWidgets ) endif() diff --git a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt index 23ee6937c7..c75cf1a0db 100644 --- a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt @@ -36,6 +36,8 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::ScriptCanvasPhysics.Static + RUNTIME_DEPENDENCIES + Gem::ScriptCanvas ) ################################################################################ diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index 639ef114fc..3969a90e8c 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -45,6 +45,11 @@ ly_add_target( *.ScriptCanvasGrammar.xml,ScriptCanvasGrammar_Source.jinja,$path/$fileprefix.generated.cpp *.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Header.jinja,$path/$fileprefix.generated.h *.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Source.jinja,$path/$fileprefix.generated.cpp + RUNTIME_DEPENDENCIES + Gem::ScriptCanvas + Gem::ScriptCanvasEditor + Gem::GraphCanvasWidgets + Gem::ScriptEvents ) ly_add_target( diff --git a/Gems/Twitch/Code/CMakeLists.txt b/Gems/Twitch/Code/CMakeLists.txt index 14d7a41532..20bccf4f52 100644 --- a/Gems/Twitch/Code/CMakeLists.txt +++ b/Gems/Twitch/Code/CMakeLists.txt @@ -29,6 +29,8 @@ ly_add_target( AZ::AzCore Gem::HttpRequestor 3rdParty::AWSNativeSDK::Core + RUNTIME_DEPENDENCIES + Gem::HttpRequestor ) ly_add_target( diff --git a/Gems/Vegetation/Code/CMakeLists.txt b/Gems/Vegetation/Code/CMakeLists.txt index 2dfbd96d60..d7332f5b2e 100644 --- a/Gems/Vegetation/Code/CMakeLists.txt +++ b/Gems/Vegetation/Code/CMakeLists.txt @@ -27,9 +27,10 @@ ly_add_target( PUBLIC Legacy::CryCommon Gem::LmbrCentral.Static - Gem::GradientSignal Gem::SurfaceData.Static Gem::AtomLyIntegration_CommonFeatures.Static + RUNTIME_DEPENDENCIES + Gem::GradientSignal ) ly_add_target( diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 0e4ba5e214..34eb67c2eb 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -400,8 +400,6 @@ function(ly_delayed_target_link_libraries) target_link_libraries(${target} ${visibility} $) target_compile_definitions(${target} ${visibility} $) target_compile_options(${target} ${visibility} $) - # Add it also as a manual dependency so runtime_dependencies walks it through - ly_add_dependencies(${target} ${item}) else() ly_parse_third_party_dependencies(${item}) target_link_libraries(${target} ${visibility} ${item}) From d536a9438d79a32aa030f3e2ab3b27cb2177d0c7 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 25 May 2021 17:30:47 -0500 Subject: [PATCH 093/140] Revert "Fixes an issue with RUNTIME_DEPENDENCIES including too many targets during install" This reverts commit f972edee010845160615370f66391cbe3c552448. --- cmake/LYWrappers.cmake | 7 ------- cmake/Platform/Common/Install_common.cmake | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 1edd288285..34eb67c2eb 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -379,16 +379,9 @@ function(ly_delayed_target_link_libraries) list(APPEND CMAKE_MODULE_PATH ${additional_module_paths}) get_property(delayed_targets GLOBAL PROPERTY LY_DELAYED_LINK_TARGETS) - foreach(target ${delayed_targets}) get_property(delayed_link GLOBAL PROPERTY LY_DELAYED_LINK_${target}) - - # Cache off the original MANUALLY_ADDED_DEPENDENCIES that were associated with the target - # via previous ly_add_dependencies() calls either explicitly or through RUNTIME_DEPENDENCIES - get_target_property(target_orig_manually_added_dependencies ${target} MANUALLY_ADDED_DEPENDENCIES) - set_property(TARGET ${target} PROPERTY LY_ORIGINAL_MANUALLY_ADDED_DEPENDENCIES ${target_orig_manually_added_dependencies}) - if(delayed_link) cmake_parse_arguments(ly_delayed_target_link_libraries "" "" "${visibilities}" ${delayed_link}) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index b8202a1314..7bf71d7e01 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -125,7 +125,7 @@ function(ly_setup_target ALIAS_TARGET_NAME) endforeach() endif() - get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} LY_ORIGINAL_MANUALLY_ADDED_DEPENDENCIES) + get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") else() From f12162a1cfb45a694981ba61776889e68fd6513b Mon Sep 17 00:00:00 2001 From: phistere Date: Tue, 25 May 2021 17:40:09 -0500 Subject: [PATCH 094/140] Update Launcher to find the autoexec.cfg in assets Was looking in the engine root for the autoexec.cfg, changed it to use the project assets path. --- Code/LauncherUnified/Launcher.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index d0e950c1ad..922397c325 100644 --- a/Code/LauncherUnified/Launcher.cpp +++ b/Code/LauncherUnified/Launcher.cpp @@ -643,7 +643,8 @@ namespace O3DELauncher if (gEnv && gEnv->pConsole) { // Execute autoexec.cfg to load the initial level - AZ::Interface::Get()->ExecuteConfigFile("autoexec.cfg"); + auto autoExecFile = AZ::IO::FixedMaxPath{pathToAssets} / "autoexec.cfg"; + AZ::Interface::Get()->ExecuteConfigFile(autoExecFile.Native()); // Find out if console command file was passed // via --console-command-file=%filename% and execute it From 59254cc9e795d2936fa336e8c9d3585d56d45ffd Mon Sep 17 00:00:00 2001 From: phistere Date: Tue, 25 May 2021 17:40:09 -0500 Subject: [PATCH 095/140] Update Launcher to find the autoexec.cfg in assets Was looking in the engine root for the autoexec.cfg, changed it to use the project assets path. --- Code/LauncherUnified/Launcher.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index d0e950c1ad..922397c325 100644 --- a/Code/LauncherUnified/Launcher.cpp +++ b/Code/LauncherUnified/Launcher.cpp @@ -643,7 +643,8 @@ namespace O3DELauncher if (gEnv && gEnv->pConsole) { // Execute autoexec.cfg to load the initial level - AZ::Interface::Get()->ExecuteConfigFile("autoexec.cfg"); + auto autoExecFile = AZ::IO::FixedMaxPath{pathToAssets} / "autoexec.cfg"; + AZ::Interface::Get()->ExecuteConfigFile(autoExecFile.Native()); // Find out if console command file was passed // via --console-command-file=%filename% and execute it From 3bc5ecd9d9d6a87b60771c0a406e9cbd25e67fd7 Mon Sep 17 00:00:00 2001 From: phistere Date: Tue, 25 May 2021 18:24:43 -0500 Subject: [PATCH 096/140] Fixes a divide by zero in Atom FPS Display --- .../Code/Source/AtomViewportDisplayInfoSystemComponent.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp index 672c26a9ab..30841648ae 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp @@ -301,7 +301,10 @@ namespace AZ::Render lastTime = time; } - const double averageFPS = aznumeric_cast(m_fpsHistory.size()) / actualInterval.count(); + const double averageFPS = (actualInterval.count() != 0.0) + ? aznumeric_cast(m_fpsHistory.size()) / actualInterval.count() + : 0.0; + const double frameIntervalSeconds = m_fpsInterval.count(); DrawLine( From 9f46e34cc4daf661f91d8d625200672c2639f1f9 Mon Sep 17 00:00:00 2001 From: phistere Date: Tue, 25 May 2021 18:27:45 -0500 Subject: [PATCH 097/140] Updates to the DefaultProject template Removes raytracingschenesrg.srgi Updates to the root scenesrg.srgi (to match AtomSampleViewer) Adds a SceneSrg.azsli and a README to the template --- .../Template/ShaderLib/README.md | 5 ++++ .../ShaderLib/raytracingscenesrg.srgi | 30 ------------------- .../Template/ShaderLib/scenesrg.srgi | 3 +- .../ShaderResourceGroups/SceneSrg.azsli | 24 +++++++++++++++ Templates/DefaultProject/template.json | 12 ++++++-- 5 files changed, 40 insertions(+), 34 deletions(-) create mode 100644 Templates/DefaultProject/Template/ShaderLib/README.md delete mode 100644 Templates/DefaultProject/Template/ShaderLib/raytracingscenesrg.srgi create mode 100644 Templates/DefaultProject/Template/Shaders/ShaderResourceGroups/SceneSrg.azsli diff --git a/Templates/DefaultProject/Template/ShaderLib/README.md b/Templates/DefaultProject/Template/ShaderLib/README.md new file mode 100644 index 0000000000..034550163d --- /dev/null +++ b/Templates/DefaultProject/Template/ShaderLib/README.md @@ -0,0 +1,5 @@ +# Customizing Shader Resource Groups + +Please read: +*\/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/README.md* +for details on how to customize scenesrg.srgi and viewsrg.srgi. diff --git a/Templates/DefaultProject/Template/ShaderLib/raytracingscenesrg.srgi b/Templates/DefaultProject/Template/ShaderLib/raytracingscenesrg.srgi deleted file mode 100644 index ac27571828..0000000000 --- a/Templates/DefaultProject/Template/ShaderLib/raytracingscenesrg.srgi +++ /dev/null @@ -1,30 +0,0 @@ -// {BEGIN_LICENSE} -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ -// {END_LICENSE} - -#pragma once - -// Please read README.md for an explanation on why scenesrg.srgi and viewsrg.srgi are -// located in this folder (And how you can optionally customize your own scenesrg.srgi -// and viewsrg.srgi in your game project). - -#include - -partial ShaderResourceGroup RayTracingSceneSrg : SRG_RayTracingScene -{ -/* Intentionally Empty. Helps define the SrgSemantic for RayTracingSceneSrg once.*/ -}; - -#define AZ_COLLECTING_PARTIAL_SRGS -#include -#undef AZ_COLLECTING_PARTIAL_SRGS diff --git a/Templates/DefaultProject/Template/ShaderLib/scenesrg.srgi b/Templates/DefaultProject/Template/ShaderLib/scenesrg.srgi index 9b4803b7dc..0a8cec5963 100644 --- a/Templates/DefaultProject/Template/ShaderLib/scenesrg.srgi +++ b/Templates/DefaultProject/Template/ShaderLib/scenesrg.srgi @@ -26,5 +26,6 @@ partial ShaderResourceGroup SceneSrg : SRG_PerScene }; #define AZ_COLLECTING_PARTIAL_SRGS -#include +#include +#include #undef AZ_COLLECTING_PARTIAL_SRGS diff --git a/Templates/DefaultProject/Template/Shaders/ShaderResourceGroups/SceneSrg.azsli b/Templates/DefaultProject/Template/Shaders/ShaderResourceGroups/SceneSrg.azsli new file mode 100644 index 0000000000..4c962fbbcd --- /dev/null +++ b/Templates/DefaultProject/Template/Shaders/ShaderResourceGroups/SceneSrg.azsli @@ -0,0 +1,24 @@ +// {BEGIN_LICENSE} +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +// {END_LICENSE} + +#ifndef AZ_COLLECTING_PARTIAL_SRGS +#error Do not include this file directly. Include the main .srgi file instead. +#endif + +partial ShaderResourceGroup SceneSrg +{ + float m_time; + float m_deltaTime; +} + diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index d654c3a969..b79cb67e7d 100644 --- a/Templates/DefaultProject/template.json +++ b/Templates/DefaultProject/template.json @@ -577,10 +577,10 @@ "isOptional": false }, { - "file": "ShaderLib/raytracingscenesrg.srgi", - "origin": "ShaderLib/raytracingscenesrg.srgi", + "file": "ShaderLib/README.md", + "origin": "ShaderLib/README.md", "isTemplated": true, - "isOptional": false + "isOptional": true }, { "file": "ShaderLib/scenesrg.srgi", @@ -600,6 +600,12 @@ "isTemplated": true, "isOptional": false }, + { + "file": "Shaders/ShaderResourceGroups/SceneSrg.azsli", + "origin": "Shaders/ShaderResourceGroups/SceneSrg.azsli", + "isTemplated": true, + "isOptional": false + }, { "file": "autoexec.cfg", "origin": "autoexec.cfg", From df44f782f2539d37607546a9c13c35eb53bc9ba9 Mon Sep 17 00:00:00 2001 From: pappeste Date: Tue, 25 May 2021 18:11:48 -0700 Subject: [PATCH 098/140] More dependencies fixes --- .../Plugins/ComponentEntityEditorPlugin/CMakeLists.txt | 1 + Gems/AWSClientAuth/Code/CMakeLists.txt | 5 ++++- Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt | 2 ++ Gems/LyShine/Code/CMakeLists.txt | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt index 80da6e6b2c..5e640e3934 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt @@ -67,6 +67,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzToolsFrameworkTestCommon Legacy::CryCommon Legacy::EditorLib + Gem::LmbrCentral.Editor RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) diff --git a/Gems/AWSClientAuth/Code/CMakeLists.txt b/Gems/AWSClientAuth/Code/CMakeLists.txt index a80fb6d532..ea6e765f2b 100644 --- a/Gems/AWSClientAuth/Code/CMakeLists.txt +++ b/Gems/AWSClientAuth/Code/CMakeLists.txt @@ -76,8 +76,11 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) 3rdParty::AWSNativeSDK::AWSClientAuth AZ::AzCore AZ::AzFramework + AZ::AWSNativeSDKInit Gem::AWSClientAuth.Static - RUNTIUME_DEPENDENCIES + Gem::AWSCore + Gem::HttpRequestor + RUNTIME_DEPENDENCIES Gem::AWSCore AZ::AWSNativeSDKInit Gem::HttpRequestor diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt index 6492f4f13a..9a9b389227 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/CMakeLists.txt @@ -43,6 +43,8 @@ ly_add_target( PRIVATE AZ::AzCore Gem::EMotionFX_Atom.Static + RUNTIME_DEPENDENCIES + Gem::EMotionFX ) if(PAL_TRAIT_BUILD_HOST_TOOLS) diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index 4237434abd..a8419aa00a 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -177,6 +177,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) Legacy::CryCommon AZ::AssetBuilderSDK Gem::LyShine.Editor.Static + Gem::LmbrCentral.Editor + Gem::TextureAtlas RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor Gem::TextureAtlas From 80f9da800ad7bdea8936622a97ccb78d69673849 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 25 May 2021 22:27:28 -0500 Subject: [PATCH 099/140] insert the scripts/o3de folder to the front of the sys.path for the o3de.py script to allow the o3de package scripts to be imported --- scripts/o3de.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/scripts/o3de.py b/scripts/o3de.py index 050d860790..abe1a2990e 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -26,26 +26,19 @@ def add_args(parser, subparsers) -> None: # As o3de.py shares the same name as the o3de package attempting to use a regular # from o3de import line tries to import from the current o3de.py script and not the package - # So the current script directory is removed from the sys.path temporary - script_dir_removed = False - script_abs_dir_removed = False + # So the {current script directory} / 'o3de' is added to the front of the sys.path + script_dir = pathlib.Path(__file__).parent - script_abs_dir = pathlib.Path(__file__).parent.resolve() - while str(script_dir) in sys.path: - script_dir_removed = True - sys.path.remove(str(script_dir)) - while str(script_abs_dir) in sys.path: - script_abs_dir_removed = True - # Remove the absolute path to the script_dir as well - sys.path.remove(str(script_abs_dir.resolve())) + o3de_package_dir = (script_dir / 'o3de').resolve() + + # add the scripts/o3de directory to the front of the sys.path + sys.path.insert(0, str(o3de_package_dir)) from o3de import engine_template, global_project, register, print_registration, get_registration, download, \ add_gem_project, remove_gem_project, sha256 - if script_abs_dir_removed: - sys.path.insert(0, str(script_abs_dir)) - if script_dir_removed: - sys.path.insert(0, str(script_dir)) + # Remove the temporarily added path + sys.path = sys.path[1:] # global_project global_project.add_args(subparsers) From 59934e6be1f168710dc14781f72708f30b4485bd Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 26 May 2021 00:20:41 -0500 Subject: [PATCH 100/140] Updating the ProjectManager code and scripts with new layout of the o3de package scripts --- .gitignore | 1 + .../Source/GemCatalog/GemModel.cpp | 23 ++-- .../Source/GemCatalog/GemModel.h | 8 +- .../ProjectManager/Source/PythonBindings.cpp | 86 ++++++------- .../ProjectManager/Source/PythonBindings.h | 9 +- scripts/o3de/o3de/manifest.py | 23 ++++ scripts/project_manager/projects.py | 120 +++++++++--------- 7 files changed, 141 insertions(+), 129 deletions(-) diff --git a/.gitignore b/.gitignore index 8a63faa2f1..664680c5bf 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ _savebackup/ TestResults/** *.swatches /imgui.ini +/scripts/project_manager/logs/ diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 724a8fa630..df11c4c7a6 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -33,8 +33,6 @@ namespace O3DE::ProjectManager item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); item->setData(gemInfo.m_name, RoleName); - const QString uuidString = gemInfo.m_uuid.ToString().c_str(); - item->setData(uuidString, RoleUuid); item->setData(gemInfo.m_creator, RoleCreator); item->setData(gemInfo.m_gemOrigin, RoleGemOrigin); item->setData(aznumeric_cast(gemInfo.m_platforms), RolePlatforms); @@ -53,7 +51,7 @@ namespace O3DE::ProjectManager appendRow(item); const QModelIndex modelIndex = index(rowCount()-1, 0); - m_uuidToIndexMap[uuidString] = modelIndex; + m_nameToIndexMap[gemInfo.m_name] = modelIndex; } void GemModel::Clear() @@ -76,11 +74,6 @@ namespace O3DE::ProjectManager return static_cast(modelIndex.data(RoleGemOrigin).toInt()); } - QString GemModel::GetUuidString(const QModelIndex& modelIndex) - { - return modelIndex.data(RoleUuid).toString(); - } - GemInfo::Platforms GemModel::GetPlatforms(const QModelIndex& modelIndex) { return static_cast(modelIndex.data(RolePlatforms).toInt()); @@ -111,10 +104,10 @@ namespace O3DE::ProjectManager return modelIndex.data(RoleDocLink).toString(); } - QModelIndex GemModel::FindIndexByUuidString(const QString& uuidString) const + QModelIndex GemModel::FindIndexByNameString(const QString& nameString) const { - const auto iterator = m_uuidToIndexMap.find(uuidString); - if (iterator != m_uuidToIndexMap.end()) + const auto iterator = m_nameToIndexMap.find(nameString); + if (iterator != m_nameToIndexMap.end()) { return iterator.value(); } @@ -122,11 +115,11 @@ namespace O3DE::ProjectManager return {}; } - void GemModel::FindGemNamesByUuidStrings(QStringList& inOutGemNames) + void GemModel::FindGemNamesByNameStrings(QStringList& inOutGemNames) { for (QString& dependingGemString : inOutGemNames) { - QModelIndex modelIndex = FindIndexByUuidString(dependingGemString); + QModelIndex modelIndex = FindIndexByNameString(dependingGemString); if (modelIndex.isValid()) { dependingGemString = GetName(modelIndex); @@ -147,7 +140,7 @@ namespace O3DE::ProjectManager return {}; } - FindGemNamesByUuidStrings(result); + FindGemNamesByNameStrings(result); return result; } @@ -164,7 +157,7 @@ namespace O3DE::ProjectManager return {}; } - FindGemNamesByUuidStrings(result); + FindGemNamesByNameStrings(result); return result; } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 480f4c74d3..0caa399b58 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -33,8 +33,8 @@ namespace O3DE::ProjectManager void AddGem(const GemInfo& gemInfo); void Clear(); - QModelIndex FindIndexByUuidString(const QString& uuidString) const; - void FindGemNamesByUuidStrings(QStringList& inOutGemNames); + QModelIndex FindIndexByNameString(const QString& nameString) const; + void FindGemNamesByNameStrings(QStringList& inOutGemNames); QStringList GetDependingGemUuids(const QModelIndex& modelIndex); QStringList GetDependingGemNames(const QModelIndex& modelIndex); QStringList GetConflictingGemUuids(const QModelIndex& modelIndex); @@ -43,7 +43,6 @@ namespace O3DE::ProjectManager static QString GetName(const QModelIndex& modelIndex); static QString GetCreator(const QModelIndex& modelIndex); static GemInfo::GemOrigin GetGemOrigin(const QModelIndex& modelIndex); - static QString GetUuidString(const QModelIndex& modelIndex); static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex); static GemInfo::Types GetTypes(const QModelIndex& modelIndex); static QString GetSummary(const QModelIndex& modelIndex); @@ -59,7 +58,6 @@ namespace O3DE::ProjectManager enum UserRole { RoleName = Qt::UserRole, - RoleUuid, RoleCreator, RoleGemOrigin, RolePlatforms, @@ -76,7 +74,7 @@ namespace O3DE::ProjectManager RoleTypes }; - QHash m_uuidToIndexMap; + QHash m_nameToIndexMap; QItemSelectionModel* m_selectionModel = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 5b24c8b6e7..efec83bc39 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -283,9 +283,11 @@ namespace O3DE::ProjectManager AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed"); // import required modules - m_register= pybind11::module::import("o3de.register"); + m_register = pybind11::module::import("o3de.register"); m_manifest = pybind11::module::import("o3de.manifest"); m_engineTemplate = pybind11::module::import("o3de.engine_template"); + m_addGemProject = pybind11::module::import("o3de.add_gem_project"); + m_removeGemProject = pybind11::module::import("o3de.remove_gem_project"); return result == 0 && !PyErr_Occurred(); } catch ([[maybe_unused]] const std::exception& e) @@ -331,26 +333,26 @@ namespace O3DE::ProjectManager { EngineInfo engineInfo; bool result = ExecuteWithLock([&] { - pybind11::str enginePath = m_registration.attr("get_this_engine_path")(); + pybind11::str enginePath = m_manifest.attr("get_this_engine_path")(); - auto o3deData = m_registration.attr("load_o3de_manifest")(); + auto o3deData = m_manifest.attr("load_o3de_manifest")(); if (pybind11::isinstance(o3deData)) { - engineInfo.m_path = Py_To_String(enginePath); - engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]); - engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); - engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]); - engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); - engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"third_party_path",""); + engineInfo.m_path = Py_To_String(enginePath); + engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]); + engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); + engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]); + engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); + engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"third_party_path",""); } - auto engineData = m_registration.attr("get_engine_json_data")(pybind11::none(), enginePath); + auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); if (pybind11::isinstance(engineData)) { try { - engineInfo.m_version = Py_To_String_Optional(engineData,"O3DEVersion","0.0.0.0"); - engineInfo.m_name = Py_To_String_Optional(engineData,"engine_name","O3DE"); + engineInfo.m_version = Py_To_String_Optional(engineData,"O3DEVersion","0.0.0.0"); + engineInfo.m_name = Py_To_String_Optional(engineData,"engine_name","O3DE"); } catch ([[maybe_unused]] const std::exception& e) { @@ -365,13 +367,13 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(engineInfo)); + return AZ::Success(AZStd::move(engineInfo)); } return AZ::Failure(); } - bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo) + bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo) { bool result = ExecuteWithLock([&] { pybind11::str enginePath = engineInfo.m_path.toStdString(); @@ -379,17 +381,17 @@ namespace O3DE::ProjectManager pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString(); pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString(); - auto registrationResult = m_registration.attr("register")( - enginePath, // engine_path - pybind11::none(), // project_path - pybind11::none(), // gem_path - pybind11::none(), // template_path - pybind11::none(), // restricted_path - pybind11::none(), // repo_uri + auto registrationResult = m_register.attr("register")( + enginePath, // engine_path + pybind11::none(), // project_path + pybind11::none(), // gem_path + pybind11::none(), // template_path + pybind11::none(), // restricted_path + pybind11::none(), // repo_uri pybind11::none(), // default_engines_folder defaultProjectsFolder, - defaultGemsFolder, - defaultTemplatesFolder + defaultGemsFolder, + defaultTemplatesFolder ); if (registrationResult.cast() != 0) @@ -397,13 +399,13 @@ namespace O3DE::ProjectManager result = false; } - auto manifest = m_registration.attr("load_o3de_manifest")(); + auto manifest = m_manifest.attr("load_o3de_manifest")(); if (pybind11::isinstance(manifest)) { try { manifest["third_party_path"] = engineInfo.m_thirdPartyPath.toStdString(); - m_registration.attr("save_o3de_manifest")(manifest); + m_manifest.attr("save_o3de_manifest")(manifest); } catch ([[maybe_unused]] const std::exception& e) { @@ -435,13 +437,13 @@ namespace O3DE::ProjectManager bool result = ExecuteWithLock([&] { // external gems - for (auto path : m_registration.attr("get_gems")()) + for (auto path : m_manifest.attr("get_gems")()) { gems.push_back(GemInfoFromPath(path)); } // gems from the engine - for (auto path : m_registration.attr("get_engine_gems")()) + for (auto path : m_manifest.attr("get_engine_gems")()) { gems.push_back(GemInfoFromPath(path)); } @@ -457,7 +459,7 @@ namespace O3DE::ProjectManager } } - AZ::Outcome PythonBindings::CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) + AZ::Outcome PythonBindings::CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) { ProjectInfo createdProjectInfo; bool result = ExecuteWithLock([&] { @@ -477,7 +479,7 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(createdProjectInfo)); + return AZ::Success(AZStd::move(createdProjectInfo)); } } @@ -499,7 +501,7 @@ namespace O3DE::ProjectManager GemInfo gemInfo; gemInfo.m_path = Py_To_String(path); - auto data = m_registration.attr("get_gem_json_data")(pybind11::none(), path); + auto data = m_manifest.attr("get_gem_json_data")(pybind11::none(), path); if (pybind11::isinstance(data)) { try @@ -512,14 +514,6 @@ namespace O3DE::ProjectManager gemInfo.m_summary = Py_To_String_Optional(data, "Summary", ""); gemInfo.m_version = Py_To_String_Optional(data, "Version", ""); - if (data.contains("Dependencies")) - { - for (auto dependency : data["Dependencies"]) - { - const AZ::Uuid uuid = Py_To_String(dependency["Uuid"]); - gemInfo.m_dependingGemUuids.push_back(uuid.ToString().c_str()); - } - } if (data.contains("Tags")) { for (auto tag : data["Tags"]) @@ -543,13 +537,13 @@ namespace O3DE::ProjectManager projectInfo.m_path = Py_To_String(path); projectInfo.m_isNew = false; - auto projectData = m_registration.attr("get_project_json_data")(pybind11::none(), path); + auto projectData = m_manifest.attr("get_project_json_data")(pybind11::none(), path); if (pybind11::isinstance(projectData)) { try { projectInfo.m_projectName = Py_To_String(projectData["project_name"]); - projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName); + projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName); } catch ([[maybe_unused]] const std::exception& e) { @@ -566,13 +560,13 @@ namespace O3DE::ProjectManager bool result = ExecuteWithLock([&] { // external projects - for (auto path : m_registration.attr("get_projects")()) + for (auto path : m_manifest.attr("get_projects")()) { projects.push_back(ProjectInfoFromPath(path)); } // projects from the engine - for (auto path : m_registration.attr("get_engine_projects")()) + for (auto path : m_manifest.attr("get_engine_projects")()) { projects.push_back(ProjectInfoFromPath(path)); } @@ -594,7 +588,7 @@ namespace O3DE::ProjectManager pybind11::str pyGemPath = gemPath.toStdString(); pybind11::str pyProjectPath = projectPath.toStdString(); - m_registration.attr("add_gem_to_project")( + m_addGemProject.attr("add_gem_to_project")( pybind11::none(), // gem_name pyGemPath, pybind11::none(), // gem_target @@ -612,7 +606,7 @@ namespace O3DE::ProjectManager pybind11::str pyGemPath = gemPath.toStdString(); pybind11::str pyProjectPath = projectPath.toStdString(); - m_registration.attr("remove_gem_to_project")( + m_removeGemProject.attr("remove_gem_from_project")( pybind11::none(), // gem_name pyGemPath, pybind11::none(), // gem_target @@ -634,7 +628,7 @@ namespace O3DE::ProjectManager ProjectTemplateInfo templateInfo; templateInfo.m_path = Py_To_String(path); - auto data = m_registration.attr("get_template_json_data")(pybind11::none(), path); + auto data = m_manifest.attr("get_template_json_data")(pybind11::none(), path); if (pybind11::isinstance(data)) { try @@ -674,7 +668,7 @@ namespace O3DE::ProjectManager QVector templates; bool result = ExecuteWithLock([&] { - for (auto path : m_registration.attr("get_project_templates")()) + for (auto path : m_manifest.attr("get_project_templates")()) { templates.push_back(ProjectTemplateInfoFromPath(path)); } diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 892e13a65b..2dc15bd574 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -12,7 +12,7 @@ #pragma once #include -#include +#include #include // Qt defines slots, which interferes with the use here. @@ -25,7 +25,7 @@ namespace O3DE::ProjectManager { - class PythonBindings + class PythonBindings : public PythonBindingsInterface::Registrar { public: @@ -66,6 +66,9 @@ namespace O3DE::ProjectManager AZ::IO::FixedMaxPath m_enginePath; pybind11::handle m_engineTemplate; AZStd::recursive_mutex m_lock; - pybind11::handle m_registration; + pybind11::handle m_register; + pybind11::handle m_manifest; + pybind11::handle m_addGemProject; + pybind11::handle m_removeGemProject; }; } diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index bc27d9116c..241f6ecbee 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -322,6 +322,29 @@ def get_all_templates() -> list: templates_data.extend(engine_templates) return templates_data +def get_project_templates(): # temporary until we have a better way to do this... maybe template_type element + project_templates = [] + for template in get_all_templates(): + if 'Project' in template: + project_templates.append(template) + return project_templates + + +def get_gem_templates(): # temporary until we have a better way to do this... maybe template_type element + gem_templates = [] + for template in get_all_templates(): + if 'Gem' in template: + gem_templates.append(template) + 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_all_restricted() -> list: engine_restricted = get_engine_restricted() diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index e50c8d8a2d..704b7c5f9a 100755 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -29,10 +29,10 @@ executable_path = '' logger = logging.getLogger() logger.setLevel(logging.INFO) -from o3de import engine_template, registration +from o3de import add_gem_project, cmake, engine_template, manifest, register, remove_gem_project -o3de_folder = registration.get_o3de_folder() -o3de_logs_folder = registration.get_o3de_logs_folder() +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') @@ -123,7 +123,7 @@ class ProjectManagerDialog(QObject): super(ProjectManagerDialog, self).__init__(parent) self.ui_path = (pathlib.Path(__file__).parent / 'ui').resolve() - self.home_folder = registration.get_home_folder() + self.home_folder = manifest.get_home_folder() self.log_display = None self.dialog_logger = DialogLogger(self) @@ -201,7 +201,7 @@ class ProjectManagerDialog(QObject): self.dialog.show() def refresh_project_list(self) -> None: - projects = registration.get_all_projects() + 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]})' @@ -255,7 +255,7 @@ class ProjectManagerDialog(QObject): return self.project_list_box.itemData(self.project_list_box.currentIndex(), Qt.ToolTipRole) def get_selected_project_name(self) -> str: - project_data = registration.get_project_data(project_path=self.get_selected_project_path()) + project_data = manifest.get_project_json_data(project_path=self.get_selected_project_path()) return project_data['project_name'] def create_project_handler(self): @@ -297,7 +297,7 @@ class ProjectManagerDialog(QObject): return folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Project Name", - registration.get_o3de_projects_folder().as_posix()) + manifest.get_o3de_projects_folder().as_posix()) folder_dialog.setFileMode(QFileDialog.AnyFile) folder_dialog.setOptions(QFileDialog.ShowDirsOnly) project_count = 0 @@ -313,7 +313,7 @@ class ProjectManagerDialog(QObject): if engine_template.create_project(project_path=project_folder[0], template_path=project_template_path) == 0: # Success - registration.register(project_path=project_folder[0]) + register.register(project_path=project_folder[0]) self.refresh_project_list() msg_box = QMessageBox(parent=self.dialog) msg_box.setWindowTitle("O3DE") @@ -359,7 +359,7 @@ class ProjectManagerDialog(QObject): return folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name", - registration.get_o3de_gems_folder().as_posix()) + manifest.get_o3de_gems_folder().as_posix()) folder_dialog.setFileMode(QFileDialog.AnyFile) folder_dialog.setOptions(QFileDialog.ShowDirsOnly) gem_count = 0 @@ -375,7 +375,7 @@ class ProjectManagerDialog(QObject): if engine_template.create_gem(gem_path=gem_folder[0], template_path=gem_template_path) == 0: # Success - registration.register(gem_path=gem_folder[0]) + 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.") @@ -391,13 +391,13 @@ class ProjectManagerDialog(QObject): source_folder = QFileDialog.getExistingDirectory(self.dialog, "Select a Folder to make a template out of.", - registration.get_o3de_folder().as_posix()) + 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.", - registration.get_o3de_templates_folder().as_posix()) + manifest.get_o3de_templates_folder().as_posix()) destination_template_folder_dialog.setFileMode(QFileDialog.AnyFile) destination_template_folder_dialog.setOptions(QFileDialog.ShowDirsOnly) destination_folder = None @@ -409,7 +409,7 @@ class ProjectManagerDialog(QObject): if engine_template.create_template(source_path=source_folder, template_path=destination_folder[0]) == 0: # Success - registration.register(template_path=destination_folder[0]) + 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.") @@ -453,7 +453,7 @@ class ProjectManagerDialog(QObject): return folder_dialog = QFileDialog(self.dialog, "Select a Folder and Enter a New Gem Name", - registration.get_o3de_gems_folder().as_posix()) + manifest.get_o3de_gems_folder().as_posix()) folder_dialog.setFileMode(QFileDialog.AnyFile) folder_dialog.setOptions(QFileDialog.ShowDirsOnly) gem_count = 0 @@ -482,9 +482,9 @@ class ProjectManagerDialog(QObject): :return: None """ project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder", - registration.get_o3de_projects_folder().as_posix()) + manifest.get_o3de_projects_folder().as_posix()) if project_folder: - if registration.register(project_path=project_folder) == 0: + if register.register(project_path=project_folder) == 0: # Success self.refresh_project_list() @@ -501,9 +501,9 @@ class ProjectManagerDialog(QObject): :return: None """ gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder", - registration.get_o3de_gems_folder().as_posix()) + manifest.get_o3de_gems_folder().as_posix()) if gem_folder: - if registration.register(gem_path=gem_folder) == 0: + if register.register(gem_path=gem_folder) == 0: # Success msg_box = QMessageBox(parent=self.dialog) msg_box.setWindowTitle("O3DE") @@ -518,9 +518,9 @@ class ProjectManagerDialog(QObject): :return: None """ template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder", - registration.get_o3de_templates_folder().as_posix()) + manifest.get_o3de_templates_folder().as_posix()) if template_folder: - if registration.register(template_path=template_folder) == 0: + if register.register(template_path=template_folder) == 0: # Success msg_box = QMessageBox(parent=self.dialog) msg_box.setWindowTitle("O3DE") @@ -535,9 +535,9 @@ class ProjectManagerDialog(QObject): :return: None """ restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder", - registration.get_o3de_restricted_folder().as_posix()) + manifest.get_o3de_restricted_folder().as_posix()) if restricted_folder: - if registration.register(restricted_path=restricted_folder) == 0: + if register.register(restricted_path=restricted_folder) == 0: # Success msg_box = QMessageBox(parent=self.dialog) msg_box.setWindowTitle("O3DE") @@ -552,9 +552,9 @@ class ProjectManagerDialog(QObject): :return: None """ project_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Project Folder", - registration.get_o3de_projects_folder().as_posix()) + manifest.get_o3de_projects_folder().as_posix()) if project_folder: - if registration.register(project_path=project_folder, remove=True) == 0: + if register.register(project_path=project_folder, remove=True) == 0: # Success self.refresh_project_list() @@ -571,9 +571,9 @@ class ProjectManagerDialog(QObject): :return: None """ gem_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Gem Folder", - registration.get_o3de_gems_folder().as_posix()) + manifest.get_o3de_gems_folder().as_posix()) if gem_folder: - if registration.register(gem_path=gem_folder, remove=True) == 0: + if register.register(gem_path=gem_folder, remove=True) == 0: # Success msg_box = QMessageBox(parent=self.dialog) msg_box.setWindowTitle("O3DE") @@ -588,9 +588,9 @@ class ProjectManagerDialog(QObject): :return: None """ template_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Template Folder", - registration.get_o3de_templates_folder().as_posix()) + manifest.get_o3de_templates_folder().as_posix()) if template_folder: - if registration.register(template_path=template_folder, remove=True) == 0: + if register.register(template_path=template_folder, remove=True) == 0: # Success msg_box = QMessageBox(parent=self.dialog) msg_box.setWindowTitle("O3DE") @@ -605,9 +605,9 @@ class ProjectManagerDialog(QObject): :return: None """ restricted_folder = QFileDialog.getExistingDirectory(self.dialog, "Select Restricted Folder", - registration.get_o3de_restricted_folder().as_posix()) + manifest.get_o3de_restricted_folder().as_posix()) if restricted_folder: - if registration.register(restricted_path=restricted_folder, remove=True) == 0: + if register.register(restricted_path=restricted_folder, remove=True) == 0: # Success msg_box = QMessageBox(parent=self.dialog) msg_box.setWindowTitle("O3DE") @@ -767,13 +767,13 @@ class ProjectManagerDialog(QObject): return [(self.enabled_gem_targets_list.model().data(item)) for item in selected_items] def add_runtime_project_gem_targets_handler(self) -> None: - gem_paths = registration.get_all_gems() + 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: - this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) for this_gem_target in this_gems_targets: if gem_target == this_gem_target: - registration.add_gem_to_project(gem_path=gem_path, + add_gem_project.add_gem_to_project(gem_path=gem_path, gem_target=gem_target, project_path=self.get_selected_project_path(), runtime_dependency=True) @@ -784,13 +784,13 @@ class ProjectManagerDialog(QObject): self.refresh_runtime_project_gem_targets_enabled_list() def remove_runtime_project_gem_targets_handler(self): - gem_paths = registration.get_all_gems() + 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: - this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) for this_gem_target in this_gems_targets: if gem_target == this_gem_target: - registration.remove_gem_from_project(gem_path=gem_path, + remove_gem_project.remove_gem_from_project(gem_path=gem_path, gem_target=gem_target, project_path=self.get_selected_project_path(), runtime_dependency=True) @@ -801,13 +801,13 @@ class ProjectManagerDialog(QObject): self.refresh_runtime_project_gem_targets_enabled_list() def add_tool_project_gem_targets_handler(self) -> None: - gem_paths = registration.get_all_gems() + 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: - this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) for this_gem_target in this_gems_targets: if gem_target == this_gem_target: - registration.add_gem_to_project(gem_path=gem_path, + add_gem_project.add_gem_to_project(gem_path=gem_path, gem_target=gem_target, project_path=self.get_selected_project_path(), tool_dependency=True) @@ -818,13 +818,13 @@ class ProjectManagerDialog(QObject): self.refresh_tool_project_gem_targets_enabled_list() def remove_tool_project_gem_targets_handler(self): - gem_paths = registration.get_all_gems() + 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: - this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) for this_gem_target in this_gems_targets: if gem_target == this_gem_target: - registration.remove_gem_from_project(gem_path=gem_path, + remove_gem_project.remove_gem_from_project(gem_path=gem_path, gem_target=gem_target, project_path=self.get_selected_project_path(), tool_dependency=True) @@ -835,13 +835,13 @@ class ProjectManagerDialog(QObject): self.refresh_tool_project_gem_targets_enabled_list() def add_server_project_gem_targets_handler(self) -> None: - gem_paths = registration.get_all_gems() + 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: - this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) for this_gem_target in this_gems_targets: if gem_target == this_gem_target: - registration.add_gem_to_project(gem_path=gem_path, + add_gem_project.add_gem_to_project(gem_path=gem_path, gem_target=gem_target, project_path=self.get_selected_project_path(), server_dependency=True) @@ -852,13 +852,13 @@ class ProjectManagerDialog(QObject): self.refresh_server_project_gem_targets_enabled_list() def remove_server_project_gem_targets_handler(self): - gem_paths = registration.get_all_gems() + 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: - this_gems_targets = registration.get_gem_targets(gem_path=gem_path) + this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) for this_gem_target in this_gems_targets: if gem_target == this_gem_target: - registration.remove_gem_from_project(gem_path=gem_path, + remove_gem_project.remove_gem_from_project(gem_path=gem_path, gem_target=gem_target, project_path=self.get_selected_project_path(), server_dependency=True) @@ -870,7 +870,7 @@ class ProjectManagerDialog(QObject): def refresh_runtime_project_gem_targets_enabled_list(self) -> None: enabled_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = registration.get_project_runtime_gem_targets( + enabled_project_gem_targets = cmake.get_project_runtime_gem_targets( project_path=self.get_selected_project_path()) for gem_target in sorted(enabled_project_gem_targets): model_item = QStandardItem(gem_target) @@ -879,9 +879,9 @@ class ProjectManagerDialog(QObject): def refresh_runtime_project_gem_targets_available_list(self) -> None: available_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = registration.get_project_runtime_gem_targets( + enabled_project_gem_targets = cmake.get_project_runtime_gem_targets( project_path=self.get_selected_project_path()) - all_gem_targets = registration.get_all_gem_targets() + all_gem_targets = cmake.get_all_gem_targets() for gem_target in sorted(all_gem_targets): if gem_target not in enabled_project_gem_targets: model_item = QStandardItem(gem_target) @@ -890,7 +890,7 @@ class ProjectManagerDialog(QObject): def refresh_tool_project_gem_targets_enabled_list(self) -> None: enabled_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = registration.get_project_tool_gem_targets( + enabled_project_gem_targets = cmake.get_project_tool_gem_targets( project_path=self.get_selected_project_path()) for gem_target in sorted(enabled_project_gem_targets): model_item = QStandardItem(gem_target) @@ -899,9 +899,9 @@ class ProjectManagerDialog(QObject): def refresh_tool_project_gem_targets_available_list(self) -> None: available_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = registration.get_project_tool_gem_targets( + enabled_project_gem_targets = cmake.get_project_tool_gem_targets( project_path=self.get_selected_project_path()) - all_gem_targets = registration.get_all_gem_targets() + all_gem_targets = cmake.get_all_gem_targets() for gem_target in sorted(all_gem_targets): if gem_target not in enabled_project_gem_targets: model_item = QStandardItem(gem_target) @@ -910,7 +910,7 @@ class ProjectManagerDialog(QObject): def refresh_server_project_gem_targets_enabled_list(self) -> None: enabled_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = registration.get_project_server_gem_targets( + enabled_project_gem_targets = cmake.get_project_server_gem_targets( project_path=self.get_selected_project_path()) for gem_target in sorted(enabled_project_gem_targets): model_item = QStandardItem(gem_target) @@ -919,9 +919,9 @@ class ProjectManagerDialog(QObject): def refresh_server_project_gem_targets_available_list(self) -> None: available_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = registration.get_project_server_gem_targets( + enabled_project_gem_targets = cmake.get_project_server_gem_targets( project_path=self.get_selected_project_path()) - all_gem_targets = registration.get_all_gem_targets() + all_gem_targets = cmake.get_all_gem_targets() for gem_target in sorted(all_gem_targets): if gem_target not in enabled_project_gem_targets: model_item = QStandardItem(gem_target) @@ -930,21 +930,21 @@ class ProjectManagerDialog(QObject): def refresh_create_project_template_list(self) -> None: self.create_project_template_model = QStandardItemModel() - for project_template_path in registration.get_project_templates(): + 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 registration.get_gem_templates(): + 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 registration.get_generic_templates(): + 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) From 922099050b319c387e6fc5097a99f2bc31c9681c Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 26 May 2021 04:46:16 -0500 Subject: [PATCH 101/140] Simplified the o3de package gem enable/disable logic The add_gem_project and remove_gem project scripts, now just enables on a gem name basis instead of a CMake target basis Updated the ProjectManager code and scripts to account for the add_gem_project and rmeove_gem_project script changes. --- .../ProjectManager/Source/PythonBindings.cpp | 2 - Gems/TextureAtlas/Code/CMakeLists.txt | 4 +- scripts/o3de/o3de/add_gem_project.py | 245 ++++++------------ scripts/o3de/o3de/cmake.py | 186 ++----------- scripts/o3de/o3de/manifest.py | 4 +- scripts/o3de/o3de/remove_gem_project.py | 167 ++++-------- scripts/project_manager/projects.py | 152 ++--------- 7 files changed, 165 insertions(+), 595 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index efec83bc39..c1e62f9c04 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -591,7 +591,6 @@ namespace O3DE::ProjectManager m_addGemProject.attr("add_gem_to_project")( pybind11::none(), // gem_name pyGemPath, - pybind11::none(), // gem_target pybind11::none(), // project_name pyProjectPath ); @@ -609,7 +608,6 @@ namespace O3DE::ProjectManager m_removeGemProject.attr("remove_gem_from_project")( pybind11::none(), // gem_name pyGemPath, - pybind11::none(), // gem_target pybind11::none(), // project_name pyProjectPath ); diff --git a/Gems/TextureAtlas/Code/CMakeLists.txt b/Gems/TextureAtlas/Code/CMakeLists.txt index 45b9549d10..d67601235d 100644 --- a/Gems/TextureAtlas/Code/CMakeLists.txt +++ b/Gems/TextureAtlas/Code/CMakeLists.txt @@ -62,10 +62,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::TextureAtlas.Static Gem::ImageProcessingAtom.Headers ) + ly_create_alias(NAME TextureAtlas.Builders NAMESPACE Gem TARGETS Gem::TextureAtlas.Editor) + ly_create_alias(NAME TextureAtlas.Tools NAMESPACE Gem TARGETS Gem::TextureAtlas.Editor) endif() ly_create_alias(NAME TextureAtlas.Servers NAMESPACE Gem TARGETS Gem::TextureAtlas) ly_create_alias(NAME TextureAtlas.Clients NAMESPACE Gem TARGETS Gem::TextureAtlas) -ly_create_alias(NAME TextureAtlas.Builders NAMESPACE Gem TARGETS Gem::TextureAtlas.Editor) -ly_create_alias(NAME TextureAtlas.Tools NAMESPACE Gem TARGETS Gem::TextureAtlas.Editor) diff --git a/scripts/o3de/o3de/add_gem_project.py b/scripts/o3de/o3de/add_gem_project.py index 8eb1468485..42db0a97bd 100644 --- a/scripts/o3de/o3de/add_gem_project.py +++ b/scripts/o3de/o3de/add_gem_project.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -Contains command to add a gem to a project's cmake scripts +Contains command to add a gem to a project's enabled_gem.cmake file """ import argparse @@ -24,55 +24,51 @@ from o3de import cmake, manifest, validation logger = logging.getLogger() logging.basicConfig() -def add_gem_dependency(cmake_file: str or pathlib.Path, - gem_target: str) -> int: +def add_gem_dependency(cmake_file: pathlib.Path, + gem_name: str) -> int: """ adds a gem dependency to a cmake file :param cmake_file: path to the cmake file - :param gem_target: name of the cmake target + :param gem_name: name of the gem :return: 0 for success or non 0 failure code """ - if not os.path.isfile(cmake_file): - logger.error(f'Failed to locate cmake file {cmake_file}') + if not cmake_file.is_file(): + logger.error(f'Failed to locate cmake file {str(cmake_file)}') return 1 - # on a line by basis, see if there already is Gem::{gem_name} + # on a line by basis, see if there already is {gem_name} # find the first occurrence of a gem, copy its formatting and replace # the gem name with the new one and append it # if the gem is already present fail t_data = [] added = False + line_index_to_append = None with open(cmake_file, 'r') as s: + line_index = 0 for line in s: - if f'Gem::{gem_target}' in line: - logger.warning(f'{gem_target} is already a gem dependency.') + if 'ENABLED_GEMS' in line: + line_index_to_append = line_index + if f'{gem_name}' == line.strip(): + logger.warning(f'{gem_name} is already enabled in file {str(cmake_file)}.') return 0 - if not added and r'Gem::' in line: - new_gem = ' ' * line.find(r'Gem::') + f'Gem::{gem_target}\n' - t_data.append(new_gem) - added = True t_data.append(line) + line_index += 1 - # if we didn't add it the set gem dependencies could be empty so + + indent = 4 + if line_index_to_append: + t_data[line_index_to_append] = f'{" " * indent}{gem_name}\n' + added = True + + # if we didn't add, then create a new set(ENABLED_GEMS) variable # add a new gem, if empty the correct format is 1 tab=4spaces - if not added: - index = 0 - for line in t_data: - index = index + 1 - if r'set(GEM_DEPENDENCIES' in line: - t_data.insert(index, f' Gem::{gem_target}\n') - added = True - break - - # if we didn't add it then it's not here, add a whole new one if not added: t_data.append('\n') - t_data.append('set(GEM_DEPENDENCIES\n') - t_data.append(f' Gem::{gem_target}\n') + t_data.append('set(ENABLED_GEMS\n') + t_data.append(f'{" " * indent}{gem_name}\n') t_data.append(')\n') # write the cmake - os.unlink(cmake_file) with open(cmake_file, 'w') as s: s.writelines(t_data) @@ -80,29 +76,19 @@ def add_gem_dependency(cmake_file: str or pathlib.Path, def add_gem_to_project(gem_name: str = None, - gem_path: str or pathlib.Path = None, - gem_target: str = None, + gem_path: pathlib.Path = None, project_name: str = None, - project_path: str or pathlib.Path = None, - dependencies_file: str or pathlib.Path = None, - runtime_dependency: bool = False, - tool_dependency: bool = False, - server_dependency: bool = False, - platforms: str = 'Common', - add_to_cmake: bool = True) -> int: + project_path: pathlib.Path = None, + enabled_gem_file: pathlib.Path = None, + platforms: str = 'Common') -> int: """ add a gem to a project :param gem_name: name of the gem to add :param gem_path: path to the gem to add - :param gem_target: the name of the cmake gem module :param project_name: name of to the project to add the gem to :param project_path: path to the project to add the gem to - :param dependencies_file: if this dependency goes/is in a specific file - :param runtime_dependency: bool to specify this is a runtime gem for the game - :param tool_dependency: bool to specify this is a tool gem for the editor - :param server_dependency: bool to specify this is a server gem for the server + :param enabled_gem_file_file: if this dependency goes/is in a specific file :param platforms: str to specify common or which specific platforms - :param add_to_cmake: bool to specify that this gem should be added to cmake :return: 0 for success or non 0 failure code """ # we need either a project name or path @@ -113,35 +99,16 @@ def add_gem_to_project(gem_name: str = None, # if project name resolve it into a path if project_name and 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.home() / ".o3de/manifest.json")}, engine.json') + return 1 + project_path = pathlib.Path(project_path).resolve() if not project_path.is_dir(): logger.error(f'Project path {project_path} is not a folder.') return 1 - # get the engine name this project is associated with - # and resolve that engines path - project_json = project_path / 'project.json' - if not validation.valid_o3de_project_json(project_json): - logger.error(f'Project json {project_json} is not valid.') - return 1 - with project_json.open('r') as s: - try: - project_json_data = json.load(s) - except json.JSONDecodeError as e: - logger.error(f'Error loading Project json {project_json}: {str(e)}') - return 1 - else: - try: - engine_name = project_json_data['engine'] - except KeyError as e: - logger.error(f'Project json {project_json} "engine" not found: {str(e)}') - return 1 - else: - engine_path = manifest.get_registered(engine_name=engine_name) - if not engine_path: - logger.error(f'Engine {engine_name} is not registered.') - return 1 - # we need either a gem name or path if not gem_name and not gem_path: logger.error(f'Must either specify a Gem path or Gem Name.') @@ -150,94 +117,47 @@ def add_gem_to_project(gem_name: str = None, # if gem name resolve it into a path if gem_name and not gem_path: gem_path = manifest.get_registered(gem_name=gem_name) + if not gem_path: + logger.error(f'Unable to locate gem path from the registered manifest.json files:' + f' {str(pathlib.Path.home() / ".o3de/manifest.json")},' + f' {project_path / "project.json"}, engine.json') + return 1 + gem_path = pathlib.Path(gem_path).resolve() # make sure this gem already exists if we're adding. We can always remove a gem. if not gem_path.is_dir(): logger.error(f'Gem Path {gem_path} does not exist.') return 1 - # if add to cmake, make sure the gem.json exists and valid before we proceed - if add_to_cmake: - gem_json = gem_path / 'gem.json' - if not gem_json.is_file(): - logger.error(f'Gem json {gem_json} is not present.') - return 1 - if not validation.valid_o3de_gem_json(gem_json): - logger.error(f'Gem json {gem_json} is not valid.') + # Read gem.json from the gem path + gem_json_data = manifest.get_gem_json_data(gem_path=gem_path) + if not gem_json_data: + logger.error(f'Could not read gem.json content under {gem_path}.') + return 1 + + + ret_val = 0 + if enabled_gem_file: + # make sure this is a project has a dependencies_file + if not enabled_gem_file.is_file(): + logger.error(f'Enabled gem file {enabled_gem_file} is not present.') return 1 + # add the dependency + ret_val = add_gem_dependency(enabled_gem_file, gem_json_data['gem_name']) - # find all available modules in this gem_path - modules = cmake.get_gem_targets(gem_path=gem_path) - if len(modules) == 0: - logger.error(f'No gem modules found under {gem_path}.') - return 1 - - # if the gem has no modules and the user has specified a target fail - if gem_target and not modules: - logger.error(f'Gem has no targets, but gem target {gem_target} was specified.') - return 1 - - # if the gem target is not in the modules - if gem_target not in modules: - logger.error(f'Gem target not in gem modules: {modules}') - return 1 - - if gem_target: - # if the user has not specified either we will assume they meant the most common which is runtime - if not runtime_dependency and not tool_dependency and not server_dependency and not dependencies_file: - logger.warning("Dependency type not specified: Assuming '--runtime-dependency'") - runtime_dependency = True - - ret_val = 0 - - # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags - if dependencies_file: - dependencies_file = pathlib.Path(dependencies_file).resolve() - # make sure this is a project has a dependencies_file - if not dependencies_file.is_file(): - logger.error(f'Dependencies file {dependencies_file} is not present.') - return 1 - # add the dependency - ret_val = add_gem_dependency(dependencies_file, gem_target) - + else: + if ',' in platforms: + platforms = platforms.split(',') else: - if ',' in platforms: - platforms = platforms.split(',') - else: - platforms = [platforms] - for platform in platforms: - if runtime_dependency: - # make sure this is a project has a runtime_dependencies.cmake file - project_runtime_dependencies_file = pathlib.Path( - cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', - platform=platform)).resolve() - if not project_runtime_dependencies_file.is_file(): - logger.error(f'Runtime dependencies file {project_runtime_dependencies_file} is not present.') - return 1 - # add the dependency - ret_val = add_gem_dependency(project_runtime_dependencies_file, gem_target) - - if (ret_val == 0) and tool_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_tool_dependencies_file = pathlib.Path( - cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', - platform=platform)).resolve() - if not project_tool_dependencies_file.is_file(): - logger.error(f'Tool dependencies file {project_tool_dependencies_file} is not present.') - return 1 - # add the dependency - ret_val = add_gem_dependency(project_tool_dependencies_file, gem_target) - - if (ret_val == 0) and server_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_server_dependencies_file = pathlib.Path( - cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='server', - platform=platform)).resolve() - if not project_server_dependencies_file.is_file(): - logger.error(f'Server dependencies file {project_server_dependencies_file} is not present.') - return 1 - # add the dependency - ret_val = add_gem_dependency(project_server_dependencies_file, gem_target) + platforms = [platforms] + for platform in platforms: + # Find the path to enabled gem file. + # It will be created by add_gem_dependency if it doesn't exist + project_enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path, platform=platform) + if not project_enabled_gem_file.is_file(): + project_enabled_gem_file.touch() + # add the dependency + ret_val = add_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) return ret_val @@ -248,15 +168,10 @@ def _run_add_gem_to_project(args: argparse) -> int: return add_gem_to_project(args.gem_name, args.gem_path, - args.gem_target, args.project_name, args.project_path, - args.dependencies_file, - args.runtime_dependency, - args.tool_dependency, - args.server_dependency, - args.platforms, - args.add_to_cmake) + args.enabled_gem_file, + args.platforms) def add_parser_args(parser): @@ -267,38 +182,24 @@ def add_parser_args(parser): :param parser: the caller passes an argparse parser like instance to this method """ group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-pp', '--project-path', type=str, required=False, + 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_mutually_exclusive_group(required=True) - group.add_argument('-gp', '--gem-path', type=str, required=False, + group.add_argument('-gp', '--gem-path', type=pathlib.Path, required=False, help='The path to the gem.') group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') - parser.add_argument('-gt', '--gem-target', type=str, required=False, - help='The cmake target name to add. If not specified it will assume gem_name') - parser.add_argument('-df', '--dependencies-file', type=str, required=False, - help='The cmake dependencies file in which the gem dependencies are specified.' - 'If not specified it will assume ') - parser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be added as a runtime dependency') - parser.add_argument('-td', '--tool-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be added as a tool dependency') - parser.add_argument('-sd', '--server-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be added as a server dependency') + parser.add_argument('-egf', '--enabled-gem-file', type=pathlib.Path, required=False, + help='The cmake enabled_gem file in which the gem dependencies are specified.' + 'If not specified it will assume enabled_gems.cmake') parser.add_argument('-pl', '--platforms', type=str, required=False, default='Common', help='Optional list of platforms this gem should be added to.' ' Ex. --platforms Mac,Windows,Linux') - parser.add_argument('-a', '--add-to-cmake', type=bool, required=False, - default=True, - help='Automatically call add-gem-to-cmake.') - parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, help='By default the home folder is the user folder, override it to this folder.') parser.set_defaults(func=_run_add_gem_to_project) diff --git a/scripts/o3de/o3de/cmake.py b/scripts/o3de/o3de/cmake.py index 7e95a9c2fe..eb8e3957ad 100644 --- a/scripts/o3de/o3de/cmake.py +++ b/scripts/o3de/o3de/cmake.py @@ -21,30 +21,12 @@ from o3de import manifest logger = logging.getLogger() logging.basicConfig() -def get_project_runtime_gem_targets(project_path: str or pathlib.Path, +def get_project_gems(project_path: pathlib.Path, platform: str = 'Common') -> set: - return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) + return get_gems_from_cmake_file(get_enabled_gem_cmake_file(project_path=project_path, platform=platform)) -def get_project_tool_gem_targets(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) - - -def get_project_server_gem_targets(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) - - -def get_project_gem_targets(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - runtime_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) - tool_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) - server_gems = get_gem_targets_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) - return runtime_gems.union(tool_gems.union(server_gems)) - - -def get_gem_targets_from_cmake_file(cmake_file: str or pathlib.Path) -> set: +def get_gem_from_cmake_file(cmake_file: pathlib.Path) -> set: """ Gets a list of declared gem targets dependencies of a cmake file :param cmake_file: path to the cmake file @@ -59,102 +41,23 @@ def get_gem_targets_from_cmake_file(cmake_file: str or pathlib.Path) -> set: gem_target_set = set() with cmake_file.open('r') as s: for line in s: - gem_name = line.split('Gem::') - if len(gem_name) > 1: - # Only take the name as everything leading up to the first '.' if found - # Gem naming conventions will have GemName.Editor, GemName.Server, and GemName - # as different targets of the GemName Gem - gem_target_set.add(gem_name[1].replace('\n', '')) + gem_name = line.strip() + gem_target_set.add(gem_name) return gem_target_set -def get_project_runtime_gem_names(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) - - -def get_project_tool_gem_names(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) - - -def get_project_server_gem_names(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - return get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) - - -def get_project_gem_names(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - runtime_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', platform=platform)) - tool_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', platform=platform)) - server_gem_names = get_gem_names_from_cmake_file(get_dependencies_cmake_file(project_path=project_path, dependency_type='server', platform=platform)) - return runtime_gem_names.union(tool_gem_names.union(server_gem_names)) - - -def get_gem_names_from_cmake_file(cmake_file: str or pathlib.Path) -> set: - """ - Gets a list of declared gem dependencies of a cmake file - :param cmake_file: path to the cmake file - :return: set of gems found - """ - cmake_file = pathlib.Path(cmake_file).resolve() - - if not cmake_file.is_file(): - logger.error(f'Failed to locate cmake file {cmake_file}') - return set() - - gem_set = set() - with cmake_file.open('r') as s: - for line in s: - gem_name = line.split('Gem::') - if len(gem_name) > 1: - # Only take the name as everything leading up to the first '.' if found - # Gem naming conventions will have GemName.Editor, GemName.Server, and GemName - # as different targets of the GemName Gem - gem_set.add(gem_name[1].split('.')[0].replace('\n', '')) - return gem_set - - -def get_project_runtime_gem_paths(project_path: str or pathlib.Path, +def get_project_gem_paths(project_path: pathlib.Path, platform: str = 'Common') -> set: - gem_names = get_project_runtime_gem_names(project_path, platform) + gem_names = get_project_gems(project_path, platform) gem_paths = set() for gem_name in gem_names: gem_paths.add(manifest.get_registered(gem_name=gem_name)) return gem_paths -def get_project_tool_gem_paths(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - gem_names = get_project_tool_gem_names(project_path, platform) - gem_paths = set() - for gem_name in gem_names: - gem_paths.add(manifest.get_registered(gem_name=gem_name)) - return gem_paths - - -def get_project_server_gem_paths(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - gem_names = get_project_server_gem_names(project_path, platform) - gem_paths = set() - for gem_name in gem_names: - gem_paths.add(manifest.get_registered(gem_name=gem_name)) - return gem_paths - - -def get_project_gem_paths(project_path: str or pathlib.Path, - platform: str = 'Common') -> set: - gem_names = get_project_gem_names(project_path, platform) - gem_paths = set() - for gem_name in gem_names: - gem_paths.add(manifest.get_registered(gem_name=gem_name)) - return gem_paths - - -def get_dependencies_cmake_file(project_name: str = None, +def get_enabled_gem_cmake_file(project_name: str = None, project_path: str or pathlib.Path = None, - dependency_type: str = 'runtime', - platform: str = 'Common') -> str or None: + platform: str = 'Common') -> pathlib.Path or None: """ get the standard cmake file name for a particular type of dependency :param gem_name: name of the gem, resolves gem_path @@ -169,66 +72,17 @@ def get_dependencies_cmake_file(project_name: str = None, project_path = manifest.get_registered(project_name=project_name) project_path = pathlib.Path(project_path).resolve() + enable_gem_filename = "enabled_gem.cmake" if platform == 'Common': - dependencies_file = f'{dependency_type}_dependencies.cmake' - dependencies_file_path = project_path / 'Gem/Code' / dependencies_file - if dependencies_file_path.is_file(): - return dependencies_file_path - return project_path / 'Code' / dependencies_file + project_code_dir = project_path / 'Gem/Code' + if project_code_dir.is_dir(): + dependencies_file_path = project_code_dir / enable_gem_filename + return dependencies_file_path.resolve() + return (project_path / 'Code' / enable_gem_filename).resolve() else: - dependencies_file = f'{platform.lower()}_{dependency_type}_dependencies.cmake' - dependencies_file_path = project_path / 'Gem/Code/Platform' / platform / dependencies_file - if dependencies_file_path.is_file(): - return dependencies_file_path - return project_path / 'Code/Platform' / platform / dependencies_file - - -def get_all_gem_targets() -> list: - modules = [] - for gem_path in manifest.get_all_gems(): - this_gems_targets = get_gem_targets(gem_path=gem_path) - modules.extend(this_gems_targets) - return modules - - -def get_gem_targets(gem_name: str = None, - gem_path: str or pathlib.Path = None) -> list: - """ - Finds gem targets in a gem - :param gem_name: name of the gem, resolves gem_path - :param gem_path: path of the gem - :return: list of gem targets - """ - if not gem_name and not gem_path: - return [] - - if gem_name and not gem_path: - gem_path = manifest.get_registered(gem_name=gem_name) - - if not gem_path: - return [] - - gem_path = pathlib.Path(gem_path).resolve() - gem_json = gem_path / 'gem.json' - if not validation.valid_o3de_gem_json(gem_json): - return [] - - module_identifiers = [ - 'MODULE', - 'GEM_MODULE', - '${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}' - ] - modules = [] - for root, dirs, files in os.walk(gem_path): - for file in files: - if file == 'CMakeLists.txt': - with open(os.path.join(root, file), 'r') as s: - for line in s: - trimmed = line.lstrip() - if trimmed.startswith('NAME '): - trimmed = trimmed.rstrip(' \n') - split_trimmed = trimmed.split(' ') - if len(split_trimmed) == 3 and split_trimmed[2] in module_identifiers: - modules.append(split_trimmed[1]) - return modules + project_code_dir = project_path / 'Gem/Code/Platform' / platform + if project_code_dir.is_dir(): + dependencies_file_path = project_code_dir / enable_gem_filename + return dependencies_file_path.resolve() + return (project_path / 'Code/Platform' / platform / enable_gem_filename).resolve() diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 241f6ecbee..c3b327641c 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -574,9 +574,7 @@ def get_registered(engine_name: str = None, return project_path elif isinstance(gem_name, str): - engine_gems = get_engine_gems() - gems = json_data['gems'].copy() - gems.extend(engine_gems) + gems = get_all_gems() for gem_path in gems: gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' diff --git a/scripts/o3de/o3de/remove_gem_project.py b/scripts/o3de/o3de/remove_gem_project.py index 463cc69961..72c51f0e2c 100644 --- a/scripts/o3de/o3de/remove_gem_project.py +++ b/scripts/o3de/o3de/remove_gem_project.py @@ -9,7 +9,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # """ -Contains methods for removing a gem target from a project +Contains methods for removing a gem from a project """ import argparse @@ -18,41 +18,40 @@ import os import pathlib import sys -from o3de import cmake +from o3de import cmake, manifest logger = logging.getLogger() logging.basicConfig() -def remove_gem_dependency(cmake_file: str or pathlib.Path, - gem_target: str) -> int: +def remove_gem_dependency(cmake_file: pathlib.Path, + gem_name: str) -> int: """ removes a gem dependency from a cmake file :param cmake_file: path to the cmake file - :param gem_target: cmake target name + :param gem_name: name of the gem :return: 0 for success or non 0 failure code """ - if not os.path.isfile(cmake_file): + if not cmake_file.is_file(): logger.error(f'Failed to locate cmake file {cmake_file}') return 1 - # on a line by basis, remove any line with Gem::{gem_name} + # on a line by basis, remove any line with {gem_name} t_data = [] - # Remove the gem from the cmake_dependencies file by skipping the gem name entry + # Remove the gem from the enabled_gem file by skipping the gem name entry removed = False with open(cmake_file, 'r') as s: for line in s: - if f'Gem::{gem_target}' in line: + if gem_name == line.strip(): removed = True else: t_data.append(line) if not removed: - logger.error(f'Failed to remove Gem::{gem_target} from cmake file {cmake_file}') + logger.error(f'Failed to remove {gem_name} from cmake file {cmake_file}') return 1 # write the cmake - os.unlink(cmake_file) with open(cmake_file, 'w') as s: s.writelines(t_data) @@ -60,29 +59,19 @@ def remove_gem_dependency(cmake_file: str or pathlib.Path, def remove_gem_from_project(gem_name: str = None, - gem_path: str or pathlib.Path = None, - gem_target: str = None, + gem_path: pathlib.Path = None, project_name: str = None, - project_path: str or pathlib.Path = None, - dependencies_file: str or pathlib.Path = None, - runtime_dependency: bool = False, - tool_dependency: bool = False, - server_dependency: bool = False, - platforms: str = 'Common', - remove_from_cmake: bool = False) -> int: + project_path: pathlib.Path = None, + enabled_gem_file: pathlib.Path = None, + platforms: str = 'Common') -> int: """ remove a gem from a project :param gem_name: name of the gem to add :param gem_path: path to the gem to add - :param gem_target: the name of teh cmake gem module :param project_name: name of the project to add the gem to :param project_path: path to the project to add the gem to - :param dependencies_file: if this dependency goes/is in a specific file - :param runtime_dependency: bool to specify this is a runtime gem for the game - :param tool_dependency: bool to specify this is a tool gem for the editor - :param server_dependency: bool to specify this is a server gem for the server + :param enabled_gem_file: File to remove enabled gem from :param platforms: str to specify common or which specific platforms - :param remove_from_cmake: bool to specify that this gem should be removed from cmake :return: 0 for success or non 0 failure code """ @@ -94,6 +83,11 @@ def remove_gem_from_project(gem_name: str = None, # if project name resolve it into a path if project_name and 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.home() / ".o3de/manifest.json")}, engine.json') + return 1 + project_path = pathlib.Path(project_path).resolve() if not project_path.is_dir(): logger.error(f'Project path {project_path} is not a folder.') @@ -107,48 +101,35 @@ def remove_gem_from_project(gem_name: str = None, # if gem name resolve it into a path if gem_name and not gem_path: gem_path = manifest.get_registered(gem_name=gem_name) + if not gem_path: + logger.error(f'Unable to locate gem path from the registered manifest.json files:' + f' {str(pathlib.Path.home() / ".o3de/manifest.json")},' + f' {project_path / "project.json"}, engine.json') + return 1 gem_path = pathlib.Path(gem_path).resolve() # make sure this gem already exists if we're adding. We can always remove a gem. if not gem_path.is_dir(): logger.error(f'Gem Path {gem_path} does not exist.') return 1 - # find all available modules in this gem_path - modules = cmake.get_gem_targets(gem_path=gem_path) - if len(modules) == 0: - logger.error(f'No gem modules found.') + + # Read gem.json from the gem path + gem_json_data = manifest.get_gem_json_data(gem_path=gem_path) + if not gem_json_data: + logger.error(f'Could not read gem.json content under {gem_path}.') return 1 - # if the user has not set a specific gem target remove all of them - - # if gem target not specified, see if there is only 1 module - if not gem_target: - if len(modules) == 1: - gem_target = modules[0] - else: - logger.error(f'Gem target not specified: {modules}') - return 1 - elif gem_target not in modules: - logger.error(f'Gem target not in gem modules: {modules}') - return 1 - - # if the user has not specified either we will assume they meant the most common which is runtime - if not runtime_dependency and not tool_dependency and not server_dependency and not dependencies_file: - logger.warning("Dependency type not specified: Assuming '--runtime-dependency'") - runtime_dependency = True - # when removing we will try to do as much as possible even with failures so ret_val will be the last error code ret_val = 0 # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags - if dependencies_file: - dependencies_file = pathlib.Path(dependencies_file).resolve() - # make sure this is a project has a dependencies_file - if not dependencies_file.is_file(): - logger.error(f'Dependencies file {dependencies_file} is not present.') + if enabled_gem_file: + # make sure this is a project has an enabled_gem file + if not enabled_gem_file.is_file(): + logger.error(f'Enabled gem file {enabled_gem_file} is not present.') return 1 # remove the dependency - error_code = remove_gem_dependency(dependencies_file, gem_target) + error_code = remove_gem_dependency(dependencies_file, gem_json_data['gem_name']) if error_code: ret_val = error_code else: @@ -157,44 +138,16 @@ def remove_gem_from_project(gem_name: str = None, else: platforms = [platforms] for platform in platforms: - if runtime_dependency: - # make sure this is a project has a runtime_dependencies.cmake file - project_runtime_dependencies_file = pathlib.Path( - cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='runtime', - platform=platform)).resolve() - if not project_runtime_dependencies_file.is_file(): - logger.error(f'Runtime dependencies file {project_runtime_dependencies_file} is not present.') - else: - # remove the dependency - error_code = remove_gem_dependency(project_runtime_dependencies_file, gem_target) - if error_code: - ret_val = error_code + # make sure this is a project has a enabled_gem.cmake file + project_enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path, platform=platform) + if not project_enabled_gem_file.is_file(): + logger.error(f'Enabled gem file {project_enabled_gem_file} is not present.') + else: + # remove the dependency + error_code = remove_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) + if error_code: + ret_val = error_code - if tool_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_tool_dependencies_file = pathlib.Path( - cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='tool', - platform=platform)).resolve() - if not project_tool_dependencies_file.is_file(): - logger.error(f'Tool dependencies file {project_tool_dependencies_file} is not present.') - else: - # remove the dependency - error_code = remove_gem_dependency(project_tool_dependencies_file, gem_target) - if error_code: - ret_val = error_code - - if server_dependency: - # make sure this is a project has a tool_dependencies.cmake file - project_server_dependencies_file = pathlib.Path( - cmake.get_dependencies_cmake_file(project_path=project_path, dependency_type='server', - platform=platform)).resolve() - if not project_server_dependencies_file.is_file(): - logger.error(f'Server dependencies file {project_server_dependencies_file} is not present.') - else: - # remove the dependency - error_code = remove_gem_dependency(project_server_dependencies_file, gem_target) - if error_code: - ret_val = error_code return ret_val @@ -205,15 +158,10 @@ def _run_remove_gem_from_project(args: argparse) -> int: return remove_gem_from_project(args.gem_name, args.gem_path, - args.gem_target, - args.project_path, args.project_name, - args.dependencies_file, - args.runtime_dependency, - args.tool_dependency, - args.server_dependency, - args.platforms, - args.remove_from_cmake) + args.project_path, + args.enabled_gem_file, + args.platforms) def add_parser_args(parser): @@ -224,35 +172,24 @@ def add_parser_args(parser): :param parser: the caller passes an argparse parser like instance to this method """ group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-pp', '--project-path', type=str, required=False, + 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_mutually_exclusive_group(required=True) - group.add_argument('-gp', '--gem-path', type=str, required=False, + group.add_argument('-gp', '--gem-path', type=pathlib.Path, required=False, help='The path to the gem.') group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') - parser.add_argument('-gt', '--gem-target', type=str, required=False, - help='The cmake target name to add. If not specified it will assume gem_name') - parser.add_argument('-df', '--dependencies-file', type=str, required=False, - help='The cmake dependencies file in which the gem dependencies are specified.' + parser.add_argument('-egf', '--enabled-gem-file', type=pathlib.Path, required=False, + help='The cmake enabled gem file in which gem dependencies are to be removed from.' 'If not specified it will assume ') - parser.add_argument('-rd', '--runtime-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be removed as a runtime dependency') - parser.add_argument('-td', '--tool-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be removed as a server dependency') - parser.add_argument('-sd', '--server-dependency', action='store_true', required=False, - default=False, - help='Optional toggle if this gem should be removed as a server dependency') parser.add_argument('-pl', '--platforms', type=str, required=False, default='Common', help='Optional list of platforms this gem should be removed from' ' Ex. --platforms Mac,Windows,Linux') - parser.add_argument('-ohf', '--override-home-folder', type=str, required=False, + parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, help='By default the home folder is the user folder, override it to this folder.') parser.set_defaults(func=_run_remove_gem_from_project) diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index 704b7c5f9a..71d0d11b2c 100755 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -766,167 +766,49 @@ class ProjectManagerDialog(QObject): 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_runtime_project_gem_targets_handler(self) -> None: + 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: - this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - add_gem_project.add_gem_to_project(gem_path=gem_path, - gem_target=gem_target, - project_path=self.get_selected_project_path(), - runtime_dependency=True) - self.refresh_runtime_project_gem_targets_available_list() - self.refresh_runtime_project_gem_targets_enabled_list() - return + add_gem_project.add_gem_to_project(gem_path=gem_path, + project_path=self.get_selected_project_path()) + self.refresh_runtime_project_gem_targets_available_list() + self.refresh_runtime_project_gem_targets_enabled_list() + return self.refresh_runtime_project_gem_targets_available_list() self.refresh_runtime_project_gem_targets_enabled_list() - def remove_runtime_project_gem_targets_handler(self): + 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: - this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - remove_gem_project.remove_gem_from_project(gem_path=gem_path, - gem_target=gem_target, - project_path=self.get_selected_project_path(), - runtime_dependency=True) - self.refresh_runtime_project_gem_targets_available_list() - self.refresh_runtime_project_gem_targets_enabled_list() - return + remove_gem_project.remove_gem_from_project(gem_path=gem_path, + project_path=self.get_selected_project_path()) + self.refresh_runtime_project_gem_targets_available_list() + self.refresh_runtime_project_gem_targets_enabled_list() + return self.refresh_runtime_project_gem_targets_available_list() self.refresh_runtime_project_gem_targets_enabled_list() - def add_tool_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: - this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - add_gem_project.add_gem_to_project(gem_path=gem_path, - gem_target=gem_target, - project_path=self.get_selected_project_path(), - tool_dependency=True) - self.refresh_tool_project_gem_targets_available_list() - self.refresh_tool_project_gem_targets_enabled_list() - return - self.refresh_tool_project_gem_targets_available_list() - self.refresh_tool_project_gem_targets_enabled_list() - - def remove_tool_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: - this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - remove_gem_project.remove_gem_from_project(gem_path=gem_path, - gem_target=gem_target, - project_path=self.get_selected_project_path(), - tool_dependency=True) - self.refresh_tool_project_gem_targets_available_list() - self.refresh_tool_project_gem_targets_enabled_list() - return - self.refresh_tool_project_gem_targets_available_list() - self.refresh_tool_project_gem_targets_enabled_list() - - def add_server_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: - this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - add_gem_project.add_gem_to_project(gem_path=gem_path, - gem_target=gem_target, - project_path=self.get_selected_project_path(), - server_dependency=True) - self.refresh_server_project_gem_targets_available_list() - self.refresh_server_project_gem_targets_enabled_list() - return - self.refresh_server_project_gem_targets_available_list() - self.refresh_server_project_gem_targets_enabled_list() - - def remove_server_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: - this_gems_targets = cmake.get_gem_targets(gem_path=gem_path) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - remove_gem_project.remove_gem_from_project(gem_path=gem_path, - gem_target=gem_target, - project_path=self.get_selected_project_path(), - server_dependency=True) - self.refresh_server_project_gem_targets_available_list() - self.refresh_server_project_gem_targets_enabled_list() - return - self.refresh_server_project_gem_targets_available_list() - self.refresh_server_project_gem_targets_enabled_list() - def refresh_runtime_project_gem_targets_enabled_list(self) -> None: enabled_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = cmake.get_project_runtime_gem_targets( - project_path=self.get_selected_project_path()) - for gem_target in sorted(enabled_project_gem_targets): + 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_runtime_project_gem_targets_available_list(self) -> None: available_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = cmake.get_project_runtime_gem_targets( - project_path=self.get_selected_project_path()) - all_gem_targets = cmake.get_all_gem_targets() + 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_tool_project_gem_targets_enabled_list(self) -> None: - enabled_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = cmake.get_project_tool_gem_targets( - project_path=self.get_selected_project_path()) - for gem_target in sorted(enabled_project_gem_targets): - 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_tool_project_gem_targets_available_list(self) -> None: - available_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = cmake.get_project_tool_gem_targets( - project_path=self.get_selected_project_path()) - all_gem_targets = cmake.get_all_gem_targets() - 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_server_project_gem_targets_enabled_list(self) -> None: - enabled_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = cmake.get_project_server_gem_targets( - project_path=self.get_selected_project_path()) - for gem_target in sorted(enabled_project_gem_targets): - 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_server_project_gem_targets_available_list(self) -> None: - available_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = cmake.get_project_server_gem_targets( - project_path=self.get_selected_project_path()) - all_gem_targets = cmake.get_all_gem_targets() - 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() From 62d196da301fd5e7483ee8c77143e9cc110d71af Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 26 May 2021 04:57:43 -0500 Subject: [PATCH 102/140] Removed tool and server gem query functions from the ProjectManager projects.py script Updated the mentions of the runtime gem targets to just be general project gem targets --- scripts/project_manager/projects.py | 135 ++++------------------------ 1 file changed, 18 insertions(+), 117 deletions(-) diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index 71d0d11b2c..d062343662 100755 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -186,12 +186,8 @@ class ProjectManagerDialog(QObject): self.remove_restricted_button = self.dialog.findChild(QPushButton, 'removeRestrictedButton') self.remove_restricted_button.clicked.connect(self.remove_restricted_handler) - self.manage_runtime_project_gem_targets_button = self.dialog.findChild(QPushButton, 'manageRuntimeGemTargetsButton') - self.manage_runtime_project_gem_targets_button.clicked.connect(self.manage_runtime_project_gem_targets_handler) - self.manage_tool_project_gem_targets_button = self.dialog.findChild(QPushButton, 'manageToolGemTargetsButton') - self.manage_tool_project_gem_targets_button.clicked.connect(self.manage_tool_project_gem_targets_handler) - self.manage_server_project_gem_targets_button = self.dialog.findChild(QPushButton, 'manageServerGemTargetsButton') - self.manage_server_project_gem_targets_button.clicked.connect(self.manage_server_project_gem_targets_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') @@ -615,7 +611,7 @@ class ProjectManagerDialog(QObject): msg_box.exec() return - def manage_runtime_project_gem_targets_handler(self): + 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. @@ -642,121 +638,26 @@ class ProjectManagerDialog(QObject): 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 Runtime Gem Targets for Project:" + 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_runtime_project_gem_targets_handler) + 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_runtime_project_gem_targets_available_list() + 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_runtime_project_gem_targets_handler) + 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_runtime_project_gem_targets_enabled_list() + self.refresh_project_gem_targets_enabled_list() self.manage_project_gem_targets_dialog.exec() - def manage_tool_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 Tool Gem Targets 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_tool_project_gem_targets_handler) - - self.available_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, - 'availableGemTargetsList') - self.refresh_tool_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_tool_project_gem_targets_handler) - - self.enabled_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, - 'enabledGemTargetsList') - self.refresh_tool_project_gem_targets_enabled_list() - - self.manage_project_gem_targets_dialog.exec() - - def manage_server_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 Server Gem Targets 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_server_project_gem_targets_handler) - - self.available_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, - 'availableGemTargetsList') - self.refresh_server_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_server_project_gem_targets_handler) - - self.enabled_gem_targets_list = self.manage_project_gem_targets_dialog.findChild(QListView, - 'enabledGemTargetsList') - self.refresh_server_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() @@ -772,11 +673,11 @@ class ProjectManagerDialog(QObject): for gem_path in gem_paths: add_gem_project.add_gem_to_project(gem_path=gem_path, project_path=self.get_selected_project_path()) - self.refresh_runtime_project_gem_targets_available_list() - self.refresh_runtime_project_gem_targets_enabled_list() + self.refresh_project_gem_targets_available_list() + self.refresh_project_gem_targets_enabled_list() return - self.refresh_runtime_project_gem_targets_available_list() - self.refresh_runtime_project_gem_targets_enabled_list() + 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() @@ -784,13 +685,13 @@ class ProjectManagerDialog(QObject): for gem_path in gem_paths: remove_gem_project.remove_gem_from_project(gem_path=gem_path, project_path=self.get_selected_project_path()) - self.refresh_runtime_project_gem_targets_available_list() - self.refresh_runtime_project_gem_targets_enabled_list() + self.refresh_project_gem_targets_available_list() + self.refresh_project_gem_targets_enabled_list() return - self.refresh_runtime_project_gem_targets_available_list() - self.refresh_runtime_project_gem_targets_enabled_list() + self.refresh_project_gem_targets_available_list() + self.refresh_project_gem_targets_enabled_list() - def refresh_runtime_project_gem_targets_enabled_list(self) -> None: + 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): @@ -799,7 +700,7 @@ class ProjectManagerDialog(QObject): self.enabled_gem_targets_list.setModel(enabled_project_gem_targets_model) - def refresh_runtime_project_gem_targets_available_list(self) -> None: + 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() From e8428b42beb80a0b9c71ed9112df83543822a2a1 Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 26 May 2021 08:17:09 -0700 Subject: [PATCH 103/140] Adjusting o3de path to run from install (authored by @lumberyard-employee-dm) --- scripts/o3de.py | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/scripts/o3de.py b/scripts/o3de.py index 050d860790..f91d5a25a0 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -26,26 +26,15 @@ def add_args(parser, subparsers) -> None: # As o3de.py shares the same name as the o3de package attempting to use a regular # from o3de import line tries to import from the current o3de.py script and not the package - # So the current script directory is removed from the sys.path temporary - script_dir_removed = False - script_abs_dir_removed = False + # So the {current script directory} / 'o3de' is added to the front of the sys.path script_dir = pathlib.Path(__file__).parent - script_abs_dir = pathlib.Path(__file__).parent.resolve() - while str(script_dir) in sys.path: - script_dir_removed = True - sys.path.remove(str(script_dir)) - while str(script_abs_dir) in sys.path: - script_abs_dir_removed = True - # Remove the absolute path to the script_dir as well - sys.path.remove(str(script_abs_dir.resolve())) - + o3de_package_dir = (script_dir / 'o3de').resolve() + # add the scripts/o3de directory to the front of the sys.path + sys.path.insert(0, str(o3de_package_dir)) from o3de import engine_template, global_project, register, print_registration, get_registration, download, \ add_gem_project, remove_gem_project, sha256 - - if script_abs_dir_removed: - sys.path.insert(0, str(script_abs_dir)) - if script_dir_removed: - sys.path.insert(0, str(script_dir)) + # Remove the temporarily added path + sys.path = sys.path[1:] # global_project global_project.add_args(subparsers) From 607dbc47b3915a6ab504dd01f5f1c70fea97bce5 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 26 May 2021 10:40:47 -0500 Subject: [PATCH 104/140] Surrouding the setting of the BASE_PATH within double quotes in the o3de.bat script. This allows to allow paths with spaces in it leading to the engine root directory to work properly when running the script --- scripts/o3de.bat | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/o3de.bat b/scripts/o3de.bat index 0a65b722d7..9031933e61 100644 --- a/scripts/o3de.bat +++ b/scripts/o3de.bat @@ -12,15 +12,15 @@ REM pushd %~dp0% CD %~dp0.. -SET BASE_PATH=%CD% +SET "BASE_PATH=%CD%" CD %~dp0 -SET PYTHON_DIRECTORY=%BASE_PATH%\python +SET "PYTHON_DIRECTORY=%BASE_PATH%\python" IF EXIST "%PYTHON_DIRECTORY%" GOTO pythonPathAvailable GOTO pythonDirNotFound :pythonPathAvailable SET PYTHON_EXECUTABLE=%PYTHON_DIRECTORY%\python.cmd IF NOT EXIST "%PYTHON_EXECUTABLE%" GOTO pythonExeNotFound -CALL "%PYTHON_EXECUTABLE%" %BASE_PATH%\scripts\o3de.py %* +CALL "%PYTHON_EXECUTABLE%" "%BASE_PATH%\scripts\o3de.py" %* GOTO end :pythonDirNotFound ECHO Python directory not found: %PYTHON_DIRECTORY% From c3e605e6c2d4354d42dc586ea41171f95f019430 Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 26 May 2021 09:12:08 -0700 Subject: [PATCH 105/140] Fixing call to ly_de_alias_target --- cmake/SettingsRegistry.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index e819b5c28e..07ed89c218 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -147,7 +147,7 @@ function(ly_delayed_generate_settings_registry) # de-namespace them foreach(gem_target ${all_gem_dependencies}) - ly_de_alias_target(TARGET ${gem_target} OUTPUT_VARIABLE stripped_gem_target) + ly_de_alias_target(${gem_target} stripped_gem_target) list(APPEND new_gem_dependencies ${stripped_gem_target}) endforeach() set(all_gem_dependencies ${new_gem_dependencies}) @@ -173,7 +173,7 @@ function(ly_delayed_generate_settings_registry) file(RELATIVE_PATH gem_module_root_relative_to_engine_root ${LY_ROOT_FOLDER} ${gem_module_root}) # De-alias namespace from gem targets before configuring them into the json template - ly_de_alias_target(TARGET ${gem_target} OUTPUT_VARIABLE stripped_gem_target) + ly_de_alias_target(${gem_target} stripped_gem_target) string(CONFIGURE ${gem_module_template} gem_module_json @ONLY) list(APPEND target_gem_dependencies_names ${gem_module_json}) endforeach() From c8a84d94356fbec1e502cb6e0651d1cf6e1cb214 Mon Sep 17 00:00:00 2001 From: phistere Date: Wed, 26 May 2021 13:10:55 -0500 Subject: [PATCH 106/140] Fixes an include path error with AudioEngineWwise Was missing a build dependency on the AudioSystem.Editor.Static target. --- Gems/AudioEngineWwise/Code/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/AudioEngineWwise/Code/CMakeLists.txt b/Gems/AudioEngineWwise/Code/CMakeLists.txt index 985bb4cf61..75006a1673 100644 --- a/Gems/AudioEngineWwise/Code/CMakeLists.txt +++ b/Gems/AudioEngineWwise/Code/CMakeLists.txt @@ -207,6 +207,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::EditorCore PUBLIC AZ::AssetBuilderSDK + Gem::AudioSystem.Editor.Static Gem::AudioEngineWwise.Static RUNTIME_DEPENDENCIES Gem::AudioSystem.Editor From 2c4ab59ee5b9cebedaabb68a4df64e4f10ce7131 Mon Sep 17 00:00:00 2001 From: pappeste Date: Wed, 26 May 2021 14:38:26 -0700 Subject: [PATCH 107/140] clearing variable --- cmake/SettingsRegistry.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index 07ed89c218..63d67f7b2b 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -146,6 +146,7 @@ function(ly_delayed_generate_settings_registry) list(REMOVE_DUPLICATES all_gem_dependencies) # de-namespace them + unset(new_gem_dependencies) foreach(gem_target ${all_gem_dependencies}) ly_de_alias_target(${gem_target} stripped_gem_target) list(APPEND new_gem_dependencies ${stripped_gem_target}) From 32919b1e7bd5514e75801eb7d889f8ffa0f07966 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 26 May 2021 18:34:25 -0500 Subject: [PATCH 108/140] Updating the AZ_DECLARE_MODULE_CLASS call in the Project's template code module to use the Gem_ prefix instead of Project_ since that is what the StaticModules.inl file geneates in it CreateStaticModules function when generating a monolithic solution --- Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp b/Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp index 003a984dd6..4f11828366 100644 --- a/Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp +++ b/Templates/DefaultProject/Template/Code/Source/${Name}Module.cpp @@ -47,4 +47,4 @@ namespace ${Name} }; }// namespace ${Name} -AZ_DECLARE_MODULE_CLASS(Project_${Name}, ${Name}::${Name}Module) +AZ_DECLARE_MODULE_CLASS(Gem_${Name}, ${Name}::${Name}Module) From 44c8a19bcee970dee0052f328e9a7f6722ffb9b9 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 26 May 2021 19:05:33 -0500 Subject: [PATCH 109/140] Fix Python TypeError in the engine_template.py create-project command --- scripts/o3de/o3de/engine_template.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/o3de/o3de/engine_template.py b/scripts/o3de/o3de/engine_template.py index f4d2b63cff..63dec3e765 100755 --- a/scripts/o3de/o3de/engine_template.py +++ b/scripts/o3de/o3de/engine_template.py @@ -1338,6 +1338,10 @@ def create_project(project_path: str, if template_name and not template_path: template_path = manifest.get_registered(template_name=template_name) + if not template_path: + logger.error(f'Could not find the template path using name {template_name}.\n' + f'Has the engine been registered yet. It can be registered via the "o3de.py register --this-engine" command') + return 1 if not os.path.isdir(template_path): logger.error(f'Could not find the template {template_name}=>{template_path}') return 1 From 84cf3bffde3ba8202923bcbb2c82f56aed777a13 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 26 May 2021 20:49:52 -0500 Subject: [PATCH 110/140] Updating the Install_common.cmake script to copy over the source engine.json templates array to the generated installed engine.json --- cmake/O3DEJson.cmake | 45 +++++++++++++--------- cmake/Platform/Common/Install_common.cmake | 15 +++++--- cmake/install/engine.json.in | 2 +- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/cmake/O3DEJson.cmake b/cmake/O3DEJson.cmake index 5d748e9681..ab5f95bc8c 100644 --- a/cmake/O3DEJson.cmake +++ b/cmake/O3DEJson.cmake @@ -14,35 +14,42 @@ include_guard() set(LY_EXTERNAL_SUBDIRS "" CACHE STRING "List of subdirectories to recurse into when running cmake against the engine's CMakeLists.txt") #! read_json_external_subdirs -# Read the "external_subdirectories" array from a *.json file -# External subdirectories are any folders with CMakeLists.txt in them -# This could be regular subdirectories, Gems(contains an additional gem.json), -# Restricted folders(contains an additional restricted.json), etc... -# -# \arg:output_external_subdirs name of output variable to store external subdirectories into -# \arg:input_json_path path to the *.json file to load and read the external subdirectories from -# \return: external subdirectories as is from the json file. +# Read the "external_subdirectories" array from a *.json file +# External subdirectories are any folders with CMakeLists.txt in them +# This could be regular subdirectories, Gems(contains an additional gem.json), +# Restricted folders(contains an additional restricted.json), etc... +# +# \arg:output_external_subdirs name of output variable to store external subdirectories into +# \arg:input_json_path path to the *.json file to load and read the external subdirectories from +# \return: external subdirectories as is from the json file. function(read_json_external_subdirs output_external_subdirs input_json_path) + o3de_read_json_array(json_array ${input_json_path} "external_subdirectories") + set(${output_external_subdirs} ${json_array} PARENT_SCOPE) +endfunction() + +#! read_json_array +# Reads the a json array field into a cmake list variable +function(o3de_read_json_array read_output_array input_json_path array_key) file(READ ${input_json_path} manifest_json_data) - string(JSON external_subdirs_count ERROR_VARIABLE manifest_json_error - LENGTH ${manifest_json_data} "external_subdirectories") + string(JSON array_count ERROR_VARIABLE manifest_json_error + LENGTH ${manifest_json_data} ${array_key}) if(manifest_json_error) - # There is "external_subdirectories" key, so theire are no subdirectories to read + # There is no key, return return() endif() - if(external_subdirs_count GREATER 0) - math(EXPR external_subdir_range "${external_subdirs_count}-1") - foreach(external_subdir_index RANGE ${external_subdir_range}) - string(JSON external_subdir ERROR_VARIABLE manifest_json_error - GET ${manifest_json_data} "external_subdirectories" "${external_subdir_index}") + if(array_count GREATER 0) + math(EXPR array_range "${array_count}-1") + foreach(array_index RANGE ${array_range}) + string(JSON array_element ERROR_VARIABLE manifest_json_error + GET ${manifest_json_data} ${array_key} "${array_index}") if(manifest_json_error) - message(FATAL_ERROR "Error reading field at index ${external_subdir_index} in \"external_subdirectories\" JSON array: ${manifest_json_error}") + message(FATAL_ERROR "Error reading field at index ${array_index} in \"${array_key}\" JSON array: ${manifest_json_error}") endif() - list(APPEND external_subdirs ${external_subdir}) + list(APPEND array_elements ${array_element}) endforeach() endif() - set(${output_external_subdirs} ${external_subdirs} PARENT_SCOPE) + set(${read_output_array} ${array_elements} PARENT_SCOPE) endfunction() function(o3de_read_json_key output_value input_json_path key) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 7bf71d7e01..04f0a0ff23 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -225,14 +225,19 @@ function(ly_setup_cmake_install) ) # Transform the LY_EXTERNAL_SUBDIRS list into a json array - set(LY_INSTALL_EXTERNAL_SUBDIRS "[]") - set(external_subdir_index "0") + set(indent " ") foreach(external_subdir ${LY_EXTERNAL_SUBDIRS}) - math(EXPR external_subdir_index "${external_subdir_index} + 1") file(RELATIVE_PATH engine_rel_external_subdir ${LY_ROOT_FOLDER} ${external_subdir}) - string(JSON LY_INSTALL_EXTERNAL_SUBDIRS ERROR_VARIABLE external_subdir_error SET ${LY_INSTALL_EXTERNAL_SUBDIRS} - ${external_subdir_index} "\"${engine_rel_external_subdir}\"") + list(APPEND relative_external_subdirs "\"${engine_rel_external_subdir}\"") endforeach() + list(JOIN relative_external_subdirs ",\n${indent}" LY_INSTALL_EXTERNAL_SUBDIRS) + + # Read the "templates" key from the source engine.json + o3de_read_json_array(engine_templates ${LY_ROOT_FOLDER}/engine.json "templates") + foreach(template_path ${engine_templates}) + list(APPEND relative_templates "\"${template_path}\"") + endforeach() + list(JOIN relative_templates ",\n${indent}" LY_INSTALL_TEMPLATES) configure_file(${LY_ROOT_FOLDER}/cmake/install/engine.json.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json @ONLY) diff --git a/cmake/install/engine.json.in b/cmake/install/engine.json.in index 1cfb1826ce..ce2e1be25c 100644 --- a/cmake/install/engine.json.in +++ b/cmake/install/engine.json.in @@ -5,7 +5,7 @@ "O3DEVersion": "@LY_VERSION_STRING@", "O3DECopyrightYear": @LY_VERSION_COPYRIGHT_YEAR@, "O3DEBuildNumber": @LY_VERSION_BUILD_NUMBER@, - "external_subdirectories": @LY_INSTALL_EXTERNAL_SUBDIRS@, + "external_subdirectories": [@LY_INSTALL_EXTERNAL_SUBDIRS@], "projects": [@LY_INSTALL_PROJECTS@], "templates": [@LY_INSTALL_TEMPLATES@] } From 5b8e759c2d29e2d75e343d79d8134f6d8c3e8c4b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Wed, 26 May 2021 23:59:49 -0500 Subject: [PATCH 111/140] Implemented changes in the ly_setup_target() command to forward the ly_create_alias() command calls to the configured CMakeLists.txt per installed target --- cmake/Gems.cmake | 15 +++++++++++++-- cmake/Platform/Common/Install_common.cmake | 19 +++++++++++++++++++ cmake/cmake_files.cmake | 1 + cmake/install/TargetCMakeLists.txt.in | 1 + 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/cmake/Gems.cmake b/cmake/Gems.cmake index caa5b74c93..a90cf09639 100644 --- a/cmake/Gems.cmake +++ b/cmake/Gems.cmake @@ -47,6 +47,10 @@ function(ly_create_alias) if (NOT TARGET ${ly_create_alias_NAME}) add_library(${ly_create_alias_NAME} ALIAS ${de_aliased_target_name}) endif() + # Store off the arguments needed used ly_create_alias into a DIRECTORY property + # This will be used to re-create the calls in the generated CMakeLists.txt in the INSTALL step + string(REPLACE ";" " " create_alias_args "${ly_create_alias_NAME},${ly_create_alias_NAMESPACE},${ly_create_alias_TARGETS}") + set_property(DIRECTORY APPEND PROPERTY LY_CREATE_ALIAS_ARGUMENTS "${ly_create_alias_NAME},${ly_create_alias_NAMESPACE},${ly_create_alias_TARGETS}") return() endif() @@ -75,6 +79,13 @@ function(ly_create_alias) # now add the final alias: add_library(${ly_create_alias_NAMESPACE}::${ly_create_alias_NAME} ALIAS ${ly_create_alias_NAME}) + + # Store off the arguments needed used ly_create_alias into a DIRECTORY property + # This will be used to re-create the calls in the generated CMakeLists.txt in the INSTALL step + + # Replace the CMake list separator with a space to replicate the space separated TARGETS arguments + string(REPLACE ";" " " create_alias_args "${ly_create_alias_NAME},${ly_create_alias_NAMESPACE},${ly_create_alias_TARGETS}") + set_property(DIRECTORY APPEND PROPERTY LY_CREATE_ALIAS_ARGUMENTS "${create_alias_args}") endfunction() # ly_enable_gems @@ -143,7 +154,7 @@ endfunction() function(ly_enable_gems_delayed) get_property(ly_delayed_enable_gems GLOBAL PROPERTY LY_DELAYED_ENABLE_GEMS) foreach(project_target_variant ${ly_delayed_enable_gems}) - # we expect a colon seperated list of + # we expect a colon separated list of # PROJECT_NAME,target_name,variant_name string(REPLACE "," ";" project_target_variant_list "${project_target_variant}") list(LENGTH project_target_variant_list project_target_variant_length) @@ -152,7 +163,7 @@ function(ly_enable_gems_delayed) endif() if(NOT project_target_variant_length EQUAL 3) - message(FATAL_ERROR "Invalid specificaiton of gems, expected 'project','target','variant' and got ${project_target_variant}") + message(FATAL_ERROR "Invalid specification of gems, expected 'project','target','variant' and got ${project_target_variant}") endif() list(POP_BACK project_target_variant_list variant) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 04f0a0ff23..27b8d83a9c 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -155,6 +155,25 @@ function(ly_setup_target ALIAS_TARGET_NAME) list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + # Replicate the ly_create_alias() calls based on the SOURCE_DIR for each target that generates an installed CMakeLists.txt + string(JOIN "\n" create_alias_template + "if(NOT TARGET @ALIAS_NAME@)" + " ly_create_alias(NAME @ALIAS_NAME@ NAMESPACE @ALIAS_NAMESPACE@ TARGETS @ALIAS_TARGETS@)" + "endif()" + "" + ) + get_property(create_alias_commands_arg_list DIRECTORY ${absolute_target_source_dir} PROPERTY LY_CREATE_ALIAS_ARGUMENTS) + foreach(create_alias_single_command_arg_list ${create_alias_commands_arg_list}) + # Split the ly_create_alias arguments back out based on commas + string(REPLACE "," ";" create_alias_single_command_arg_list "${create_alias_single_command_arg_list}") + list(POP_FRONT create_alias_single_command_arg_list ALIAS_NAME) + list(POP_FRONT create_alias_single_command_arg_list ALIAS_NAMESPACE) + # The rest of the list are the target dependencies + set(ALIAS_TARGETS ${create_alias_single_command_arg_list}) + string(CONFIGURE "${create_alias_template}" create_alias_command @ONLY) + string(APPEND CREATE_ALIASES_PLACEHOLDER ${create_alias_command}) + endforeach() + # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target configure_file(${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in ${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/CMakeLists.txt @ONLY) diff --git a/cmake/cmake_files.cmake b/cmake/cmake_files.cmake index b42d29c9c2..a1fd66a06d 100644 --- a/cmake/cmake_files.cmake +++ b/cmake/cmake_files.cmake @@ -20,6 +20,7 @@ set(FILES EngineJson.cmake FileUtil.cmake Findo3de.cmake + Gems.cmake GeneralSettings.cmake Install.cmake LyAutoGen.cmake diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/TargetCMakeLists.txt.in index b2c8b9b6f6..06cd022898 100644 --- a/cmake/install/TargetCMakeLists.txt.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -27,6 +27,7 @@ ly_add_target( @RUNTIME_DEPENDENCIES_PLACEHOLDER@ ) +@CREATE_ALIASES_PLACEHOLDER@ set(configs @CMAKE_CONFIGURATION_TYPES@) foreach(config ${configs}) include("@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) From cb2772a7484822f9126962df0900ea40cea46a04 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 01:51:09 -0500 Subject: [PATCH 112/140] Updating the Install_common.cmake ly_setup_o3de_install() function to be able forward all the ly_add_targets calls within a single source Engine CMakeLists.txt to a single installed Engine CMakeLists.txt --- cmake/LYWrappers.cmake | 9 + cmake/Platform/Common/Install_common.cmake | 367 +++++++++++---------- cmake/install/Copyright.in | 10 + cmake/install/TargetCMakeLists.txt.in | 11 - 4 files changed, 210 insertions(+), 187 deletions(-) create mode 100644 cmake/install/Copyright.in diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index af6aefdac0..a75a121ccd 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -308,6 +308,15 @@ function(ly_add_target) # Store the target so we can walk through all of them in LocationDependencies.cmake set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGETS ${interface_name}) + # Store the aliased target into a DIRECTORY property + set_property(DIRECTORY APPEND PROPERTY LY_DIRECTORY_TARGETS ${interface_name}) + # Store the directory path in a GLOBAL property so that it can be accessed + # in the layout install logic. Skip if the directory has already been added + get_property(ly_all_target_directories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) + if(NOT CMAKE_CURRENT_SOURCE_DIR IN_LIST ly_all_target_directories) + set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGET_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + set(runtime_dependencies_list SHARED MODULE EXECUTABLE APPLICATION) if(NOT ly_add_target_IMPORTED AND linking_options IN_LIST runtime_dependencies_list) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 27b8d83a9c..aa9e710a0e 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -17,143 +17,190 @@ file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_ file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) set(install_output_folder "${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$") -#! ly_setup_targets: setups all targets -function(ly_setup_targets) - get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) - foreach(target IN LISTS all_targets) - ly_setup_target(${target}) + +#! ly_setup_subdirectories: setups all targets on a per directory basis +function(ly_setup_subdirectories) + get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) + foreach(target IN LISTS all_subdirectories) + ly_setup_subdirectory(${target}) endforeach() endfunction() -#! ly_setup_target: setups the target to be installed by cmake install. -function(ly_setup_target ALIAS_TARGET_NAME) - unset(TARGET_NAME) - ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) - - get_target_property(absolute_target_source_dir ${TARGET_NAME} SOURCE_DIR) +#! ly_setup_subdirectory: setup all targets in the subdirectory +function(ly_setup_subdirectory absolute_target_source_dir) + + file(READ ${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in target_cmakelists_template) + # The builtin BUILDSYSTEM_TARGETS property isn't being used here as that returns the de-alised + # TARGET and we need the alias namespace for recreating the CMakeLists.txt in the install layout + get_property(ALIAS_TARGETS_NAME DIRECTORY ${absolute_target_source_dir} PROPERTY LY_DIRECTORY_TARGETS) file(RELATIVE_PATH target_source_dir ${LY_ROOT_FOLDER} ${absolute_target_source_dir}) + foreach(ALIAS_TARGET_NAME IN LISTS ALIAS_TARGETS_NAME) + unset(TARGET_NAME) + ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) - # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that - # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the - # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. - # Instead, we install them with install(DIRECTORY) - set(include_location "include") - get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) - if (include_directories) - unset(public_headers) - foreach(include_directory ${include_directories}) - string(GENEX_STRIP ${include_directory} include_genex_expr) - if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions - unset(current_public_headers) - install(DIRECTORY ${include_directory} - DESTINATION ${include_location}/${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} - FILES_MATCHING - PATTERN *.h - PATTERN *.hpp - PATTERN *.inl - ) - endif() - endforeach() - endif() - - # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target - file(RELATIVE_PATH archive_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) - - get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) - if(target_runtime_output_directory) - file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) - endif() - - get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY) - if(target_library_output_directory) - file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) - endif() - - install( - TARGETS ${TARGET_NAME} - ARCHIVE - DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${ly_install_target_COMPONENT} - LIBRARY - DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} - RUNTIME - DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} - ) - - # CMakeLists.txt file - string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME}) - if(match) - set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}") - set(NAME_PLACEHOLDER ${CMAKE_MATCH_2}) - else() - set(NAMESPACE_PLACEHOLDER "") - set(NAME_PLACEHOLDER ${TARGET_NAME}) - endif() - - set(TARGET_TYPE_PLACEHOLDER "") - get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) - # Remove the _LIBRARY since we dont need to pass that to ly_add_targets - string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) - # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead - string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) - if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") - get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) - if(gem_module) - set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") + # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that + # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the + # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. + # Instead, we install them with install(DIRECTORY) + set(include_location "include") + get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) + if (include_directories) + unset(public_headers) + foreach(include_directory ${include_directories}) + string(GENEX_STRIP ${include_directory} include_genex_expr) + if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions + unset(current_public_headers) + install(DIRECTORY ${include_directory} + DESTINATION ${include_location}/${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + FILES_MATCHING + PATTERN *.h + PATTERN *.hpp + PATTERN *.inl + ) + endif() + endforeach() endif() - endif() - get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) - if(COMPILE_DEFINITIONS_PLACEHOLDER) - string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") - else() - unset(COMPILE_DEFINITIONS_PLACEHOLDER) - endif() + # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target + file(RELATIVE_PATH archive_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) - # Includes need additional processing to add the install root - if(include_directories) - foreach(include ${include_directories}) - string(GENEX_STRIP ${include} include_genex_expr) - if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions - file(RELATIVE_PATH relative_include ${absolute_target_source_dir} ${include}) - string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}/${relative_include}\n") + get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) + if(target_runtime_output_directory) + file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) + endif() + + get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY) + if(target_library_output_directory) + file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) + endif() + + install( + TARGETS ${TARGET_NAME} + ARCHIVE + DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ + COMPONENT ${ly_install_target_COMPONENT} + LIBRARY + DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} + COMPONENT ${ly_install_target_COMPONENT} + RUNTIME + DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} + COMPONENT ${ly_install_target_COMPONENT} + ) + + # CMakeLists.txt file + string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME}) + if(match) + set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}") + set(NAME_PLACEHOLDER ${CMAKE_MATCH_2}) + else() + set(NAMESPACE_PLACEHOLDER "") + set(NAME_PLACEHOLDER ${TARGET_NAME}) + endif() + + set(TARGET_TYPE_PLACEHOLDER "") + get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) + # Remove the _LIBRARY since we dont need to pass that to ly_add_targets + string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) + # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead + string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) + if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") + get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) + if(gem_module) + set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") endif() - endforeach() - endif() + endif() - get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) - if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found - string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") - else() - unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) - endif() + get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) + if(COMPILE_DEFINITIONS_PLACEHOLDER) + string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") + else() + unset(COMPILE_DEFINITIONS_PLACEHOLDER) + endif() - get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) - unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) - if(inteface_build_dependencies_props) - foreach(build_dependency ${inteface_build_dependencies_props}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + # Includes need additional processing to add the install root + if(include_directories) + foreach(include ${include_directories}) + string(GENEX_STRIP ${include} include_genex_expr) + if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions + file(RELATIVE_PATH relative_include ${absolute_target_source_dir} ${include}) + string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}/${relative_include}\n") + endif() + endforeach() + endif() + + get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) + if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found + string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") + else() + unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) + endif() + + get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) + unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + if(inteface_build_dependencies_props) + foreach(build_dependency ${inteface_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + endif() + endforeach() + endif() + # We also need to pass the private link libraries since we will use that to generate the runtime dependencies + get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) + if(private_build_dependencies_props) + foreach(build_dependency ${private_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + endif() + endforeach() + endif() + list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + + # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target + string(CONFIGURE ${target_cmakelists_template} configured_target @ONLY) + string(APPEND all_configured_targets "${configured_target}") + + # Config file + set(target_file_contents "# Generated by O3DE install\n\n") + if(NOT target_type STREQUAL INTERFACE_LIBRARY) + + unset(target_location) + set(runtime_types EXECUTABLE APPLICATION) + if(target_type IN_LIST runtime_types) + set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$") + elseif(target_type STREQUAL MODULE_LIBRARY) + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") + elseif(target_type STREQUAL SHARED_LIBRARY) + string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$ \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\")\n") + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") + else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY + set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$") endif() - endforeach() - endif() - # We also need to pass the private link libraries since we will use that to generate the runtime dependencies - get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) - if(private_build_dependencies_props) - foreach(build_dependency ${private_build_dependencies_props}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + + if(target_location) + string(APPEND target_file_contents + "set_property(TARGET ${TARGET_NAME} + APPEND_STRING PROPERTY IMPORTED_LOCATION + $<$$:${target_location}$ + ) + set_property(TARGET ${TARGET_NAME} + PROPERTY IMPORTED_LOCATION_$> + ${target_location} + ) + ") endif() - endforeach() - endif() - list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) - string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + endif() + + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" + DESTINATION ${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + ) + endforeach() # Replicate the ly_create_alias() calls based on the SOURCE_DIR for each target that generates an installed CMakeLists.txt string(JOIN "\n" create_alias_template @@ -174,48 +221,16 @@ function(ly_setup_target ALIAS_TARGET_NAME) string(APPEND CREATE_ALIASES_PLACEHOLDER ${create_alias_command}) endforeach() - # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target - configure_file(${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in ${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/CMakeLists.txt @ONLY) - - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/CMakeLists.txt" - DESTINATION ${target_source_dir}/${NAME_PLACEHOLDER} - COMPONENT ${ly_install_target_COMPONENT} + file(READ ${LY_ROOT_FOLDER}/cmake/install/Copyright.in cmake_copyright_comment) + # Write out all the agreegated ly_add_target function calls and the final ly_create_alias() calls to the target CMakeList.txt + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt + "${cmake_copyright_comment}" + "${all_configured_targets}" + "\n" + "${CREATE_ALIASES_PLACEHOLDER}" ) - - # Config file - set(target_file_contents "# Generated by O3DE install\n\n") - if(NOT target_type STREQUAL INTERFACE_LIBRARY) - - unset(target_location) - set(runtime_types EXECUTABLE APPLICATION) - if(target_type IN_LIST runtime_types) - set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$") - elseif(target_type STREQUAL MODULE_LIBRARY) - set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") - elseif(target_type STREQUAL SHARED_LIBRARY) - string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$ \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\")\n") - set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") - else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY - set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$") - endif() - - if(target_location) - string(APPEND target_file_contents -"set_property(TARGET ${TARGET_NAME} - APPEND_STRING PROPERTY IMPORTED_LOCATION - $<$$:${target_location}$ -) -set_property(TARGET ${TARGET_NAME} - PROPERTY IMPORTED_LOCATION_$> - ${target_location} -) -") - endif() - endif() - - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/${NAME_PLACEHOLDER}_$.cmake" - DESTINATION ${target_source_dir}/${NAME_PLACEHOLDER} + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt" + DESTINATION ${target_source_dir} COMPONENT ${ly_install_target_COMPONENT} ) @@ -224,7 +239,7 @@ endfunction() #! ly_setup_o3de_install: orchestrates the installation of the different parts. This is the entry point from the root CMakeLists.txt function(ly_setup_o3de_install) - ly_setup_targets() + ly_setup_subdirectories() ly_setup_cmake_install() ly_setup_target_generator() ly_setup_runtime_dependencies() @@ -283,12 +298,12 @@ function(ly_setup_cmake_install) # Findo3de.cmake file: we generate a different Findo3de.camke file than the one we have in cmake. This one is going to expose all # targets that are pre-built - get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) unset(FIND_PACKAGES_PLACEHOLDER) - foreach(alias_target IN LISTS all_targets) - ly_de_alias_target(${alias_target} target) - get_target_property(target_source_dir ${target} SOURCE_DIR) - file(RELATIVE_PATH target_source_dir_relative ${LY_ROOT_FOLDER} ${target_source_dir}) + + # Add to the FIND_PACKAGES_PLACEHOLDER all directories in which ly_add_target were called in + get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) + foreach(target_subdirectory IN LISTS all_subdirectories) + file(RELATIVE_PATH target_source_dir_relative ${LY_ROOT_FOLDER} ${target_subdirectory}) string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${target_source_dir_relative}/${target})\n") endforeach() @@ -339,7 +354,7 @@ function(ly_copy source_file target_directory) endfunction()" COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) - + unset(runtime_commands) get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) foreach(alias_target IN LISTS all_targets) @@ -350,12 +365,12 @@ endfunction()" if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS) continue() endif() - + get_target_property(target_runtime_output_directory ${target} RUNTIME_OUTPUT_DIRECTORY) if(target_runtime_output_directory) file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) endif() - + # Qt get_property(has_qt_dependency GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${target}) if(has_qt_dependency) @@ -374,7 +389,7 @@ endfunction()" foreach(runtime_dependency ${runtime_dependencies}) unset(runtime_command) ly_get_runtime_dependency_command(runtime_command ${runtime_dependency}) - string(CONFIGURE "${runtime_command}" runtime_command @ONLY) + string(CONFIGURE "${runtime_command}" runtime_command @ONLY) list(APPEND runtime_commands ${runtime_command}) endforeach() @@ -382,10 +397,10 @@ endfunction()" list(REMOVE_DUPLICATES runtime_commands) list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file - install(CODE "${runtime_commands_str}" + install(CODE "${runtime_commands_str}" COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) - + endfunction() #! ly_setup_others: install directories required by the engine diff --git a/cmake/install/Copyright.in b/cmake/install/Copyright.in new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/cmake/install/Copyright.in @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/TargetCMakeLists.txt.in index 06cd022898..0503fd5f2b 100644 --- a/cmake/install/TargetCMakeLists.txt.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -1,13 +1,3 @@ -# -# 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. -# # Generated by O3DE @@ -27,7 +17,6 @@ ly_add_target( @RUNTIME_DEPENDENCIES_PLACEHOLDER@ ) -@CREATE_ALIASES_PLACEHOLDER@ set(configs @CMAKE_CONFIGURATION_TYPES@) foreach(config ${configs}) include("@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) From 0dd8fce2b0073c0ccc5ce3d3cd170def9b6e9fda Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 10:30:11 -0700 Subject: [PATCH 113/140] Pass on fixing LmbrCentral.Static dependencies --- Gems/AudioEngineWwise/Code/CMakeLists.txt | 2 +- Gems/AutomatedLauncherTesting/Code/CMakeLists.txt | 2 +- Gems/EMotionFX/Code/CMakeLists.txt | 2 +- Gems/FastNoise/Code/CMakeLists.txt | 10 +++++++--- Gems/GradientSignal/Code/CMakeLists.txt | 10 ++++++++-- Gems/ImGui/Code/CMakeLists.txt | 3 ++- Gems/LyShine/Code/CMakeLists.txt | 8 +++++--- Gems/LyShineExamples/Code/CMakeLists.txt | 2 +- Gems/PhysX/Code/CMakeLists.txt | 7 +++++-- Gems/StartingPointCamera/Code/CMakeLists.txt | 2 +- Gems/SurfaceData/Code/CMakeLists.txt | 5 ++++- Gems/Vegetation/Code/CMakeLists.txt | 5 +++-- 12 files changed, 39 insertions(+), 19 deletions(-) diff --git a/Gems/AudioEngineWwise/Code/CMakeLists.txt b/Gems/AudioEngineWwise/Code/CMakeLists.txt index 75006a1673..f90064908a 100644 --- a/Gems/AudioEngineWwise/Code/CMakeLists.txt +++ b/Gems/AudioEngineWwise/Code/CMakeLists.txt @@ -207,8 +207,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::EditorCore PUBLIC AZ::AssetBuilderSDK - Gem::AudioSystem.Editor.Static Gem::AudioEngineWwise.Static + Gem::AudioSystem.Editor RUNTIME_DEPENDENCIES Gem::AudioSystem.Editor ) diff --git a/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt b/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt index 264491500f..6215ae7697 100644 --- a/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt +++ b/Gems/AutomatedLauncherTesting/Code/CMakeLists.txt @@ -23,7 +23,7 @@ ly_add_target( PUBLIC AZ::AzCore Legacy::CryCommon - Gem::LmbrCentral.Static + Gem::LmbrCentral ) ly_add_target( diff --git a/Gems/EMotionFX/Code/CMakeLists.txt b/Gems/EMotionFX/Code/CMakeLists.txt index a78e8487f0..bc0268cd60 100644 --- a/Gems/EMotionFX/Code/CMakeLists.txt +++ b/Gems/EMotionFX/Code/CMakeLists.txt @@ -36,10 +36,10 @@ ly_add_target( AZ::AzCore AZ::AzFramework Legacy::CryCommon - Gem::LmbrCentral.Static PUBLIC AZ::AtomCore Gem::Atom_RPI.Public + Gem::LmbrCentral COMPILE_DEFINITIONS PUBLIC EMFX_DEVELOPMENT_BUILD diff --git a/Gems/FastNoise/Code/CMakeLists.txt b/Gems/FastNoise/Code/CMakeLists.txt index 0fb98c0237..8c12dcf5be 100644 --- a/Gems/FastNoise/Code/CMakeLists.txt +++ b/Gems/FastNoise/Code/CMakeLists.txt @@ -23,7 +23,8 @@ ly_add_target( PUBLIC Legacy::CryCommon Gem::GradientSignal - Gem::LmbrCentral.Static + PRIVATE + Gem::LmbrCentral ) ly_add_target( @@ -61,6 +62,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC Include BUILD_DEPENDENCIES + PRIVATE + Gem::LmbrCentral.Editor PUBLIC Gem::FastNoise.Static AZ::AzToolsFramework @@ -69,7 +72,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME FastNoise.Editor GEM_MODULE - NAMESPACE Gem FILES_CMAKE fastnoise_editor_shared_files.cmake @@ -80,7 +82,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Include BUILD_DEPENDENCIES PRIVATE - FastNoise.Editor.Static + Gem::FastNoise.Editor.Static + Gem::LmbrCentral.Editor RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor Gem::SurfaceData.Editor @@ -113,6 +116,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) PRIVATE AZ::AzTest FastNoise.Editor.Static + Gem::LmbrCentral.Editor ) ly_add_googletest( NAME Gem::FastNoise.Editor.Tests diff --git a/Gems/GradientSignal/Code/CMakeLists.txt b/Gems/GradientSignal/Code/CMakeLists.txt index 7fe3897568..244f7360ea 100644 --- a/Gems/GradientSignal/Code/CMakeLists.txt +++ b/Gems/GradientSignal/Code/CMakeLists.txt @@ -22,9 +22,10 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC Legacy::CryCommon - Gem::LmbrCentral.Static Gem::SurfaceData Gem::ImageProcessingAtom.Headers + PRIVATE + Gem::LmbrCentral ) ly_add_target( @@ -40,6 +41,7 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::GradientSignal.Static + Gem::LmbrCentral PUBLIC Gem::ImageProcessingAtom.Headers # Atom/ImageProcessing/PixelFormats.h is part of a header in Includes RUNTIME_DEPENDENCIES @@ -66,6 +68,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC GRADIENTSIGNAL_EDITOR BUILD_DEPENDENCIES + PRIVATE + Gem::LmbrCentral.Editor PUBLIC 3rdParty::Qt::Widgets Legacy::CryCommon @@ -79,7 +83,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME GradientSignal.Editor GEM_MODULE - NAMESPACE Gem FILES_CMAKE gradientsignal_editor_shared_files.cmake @@ -91,6 +94,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE Gem::GradientSignal.Editor.Static + Gem::LmbrCentral.Editor RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) @@ -120,6 +124,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) PRIVATE AZ::AzTest Gem::GradientSignal.Static + Gem::LmbrCentral ) ly_add_googletest( NAME Gem::GradientSignal.Tests @@ -140,6 +145,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest Gem::GradientSignal.Static Gem::GradientSignal.Editor.Static + Gem::LmbrCentral.Editor ) ly_add_googletest( NAME Gem::GradientSignal.Editor.Tests diff --git a/Gems/ImGui/Code/CMakeLists.txt b/Gems/ImGui/Code/CMakeLists.txt index e1286419ce..fccdb6fc08 100644 --- a/Gems/ImGui/Code/CMakeLists.txt +++ b/Gems/ImGui/Code/CMakeLists.txt @@ -72,7 +72,8 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC Gem::ImGui.ImGuiLYUtils - Gem::LmbrCentral.Static + PRIVATE + Gem::LmbrCentral ) ly_add_target( diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index 9f38120088..4dede1c6ac 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -26,13 +26,13 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Legacy::CryCommon + Gem::LmbrCentral PUBLIC Gem::Atom_RPI.Public Gem::Atom_Utils.Static Gem::Atom_Bootstrap.Headers Gem::AtomFont - Gem::LmbrCentral.Static - Gem::TextureAtlas + Gem::TextureAtlas ) ly_add_target( @@ -49,6 +49,7 @@ ly_add_target( PRIVATE Gem::LyShine.Static Legacy::CryCommon + Gem::LmbrCentral RUNTIME_DEPENDENCIES Gem::LmbrCentral Gem::TextureAtlas @@ -86,7 +87,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::EditorCore Gem::LyShine.Static Legacy::CryCommon - Gem::LmbrCentral.Editor.Static + Gem::LmbrCentral.Editor Gem::TextureAtlas.Editor Gem::AtomToolsFramework.Static Gem::AtomToolsFramework.Editor @@ -152,6 +153,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest Gem::LyShine.Static Legacy::CryCommon + Gem::LmbrCentral RUNTIME_DEPENDENCIES Gem::LmbrCentral Gem::TextureAtlas diff --git a/Gems/LyShineExamples/Code/CMakeLists.txt b/Gems/LyShineExamples/Code/CMakeLists.txt index a80b05d6c2..ce420cbd30 100644 --- a/Gems/LyShineExamples/Code/CMakeLists.txt +++ b/Gems/LyShineExamples/Code/CMakeLists.txt @@ -22,7 +22,7 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC Legacy::CryCommon - Gem::LmbrCentral.Static + Gem::LmbrCentral Gem::LyShine.Static ) diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index 64b8efb98a..b0318af9f2 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -46,7 +46,8 @@ ly_add_target( AZ::AzCore AZ::AzFramework Legacy::CryCommon - Gem::LmbrCentral.Static + PRIVATE + Gem::LmbrCentral ) ly_add_target( @@ -66,6 +67,7 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::PhysX.Static + Gem::LmbrCentral RUNTIME_DEPENDENCIES Gem::LmbrCentral ) @@ -111,7 +113,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::SceneCore AZ::SceneData Legacy::CryCommon - Gem::LmbrCentral.Editor.Static + Gem::LmbrCentral.Editor Gem::PhysX.NumericalMethods Gem::PhysX.Static Gem::AtomLyIntegration_CommonFeatures.Static @@ -165,6 +167,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTestShared AZ::AzTest Gem::PhysX.Static + Gem::LmbrCentral RUNTIME_DEPENDENCIES Gem::LmbrCentral ) diff --git a/Gems/StartingPointCamera/Code/CMakeLists.txt b/Gems/StartingPointCamera/Code/CMakeLists.txt index cf8efc0cd6..7bc57476a5 100644 --- a/Gems/StartingPointCamera/Code/CMakeLists.txt +++ b/Gems/StartingPointCamera/Code/CMakeLists.txt @@ -23,7 +23,7 @@ ly_add_target( PRIVATE AZ::AzCore Gem::CameraFramework.Static - Gem::LmbrCentral.Static + Gem::LmbrCentral Legacy::CryCommon ) diff --git a/Gems/SurfaceData/Code/CMakeLists.txt b/Gems/SurfaceData/Code/CMakeLists.txt index 7a9cb47039..642849675c 100644 --- a/Gems/SurfaceData/Code/CMakeLists.txt +++ b/Gems/SurfaceData/Code/CMakeLists.txt @@ -22,10 +22,10 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Legacy::CryCommon + Gem::LmbrCentral PUBLIC Gem::Atom_RPI.Public Gem::Atom_Feature_Common.Static - Gem::LmbrCentral.Static ) ly_add_target( @@ -42,6 +42,7 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::SurfaceData.Static + Gem::LmbrCentral RUNTIME_DEPENDENCIES Gem::LmbrCentral ) @@ -71,6 +72,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryCommon AZ::AzToolsFramework Gem::SurfaceData.Static + Gem::LmbrCentral.Editor RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor ) @@ -100,6 +102,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest Legacy::CryCommon Gem::SurfaceData.Static + Gem::LmbrCentral ) ly_add_googletest( NAME Gem::SurfaceData.Tests diff --git a/Gems/Vegetation/Code/CMakeLists.txt b/Gems/Vegetation/Code/CMakeLists.txt index 12439878af..7283f53c97 100644 --- a/Gems/Vegetation/Code/CMakeLists.txt +++ b/Gems/Vegetation/Code/CMakeLists.txt @@ -24,10 +24,11 @@ ly_add_target( PUBLIC Include BUILD_DEPENDENCIES + PRIVATE + Gem::LmbrCentral + Gem::SurfaceData PUBLIC Legacy::CryCommon - Gem::LmbrCentral.Static - Gem::SurfaceData.Static Gem::AtomLyIntegration_CommonFeatures.Static RUNTIME_DEPENDENCIES Gem::GradientSignal From 4e80ce1b1d9131354fbee4571b7ca847a9033d0b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 12:36:33 -0500 Subject: [PATCH 114/140] Re-added back an ly_setup_target function which configures the CMakeLists.txt template for a single target --- cmake/Platform/Common/Install_common.cmake | 336 +++++++++++---------- 1 file changed, 171 insertions(+), 165 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index aa9e710a0e..939f523d75 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -18,6 +18,175 @@ file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_ set(install_output_folder "${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$") +#! ly_setup_target: Setup the data needed to re-create the cmake target commands for a single target +function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) + # De-alias target name + ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) + + # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that + # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the + # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. + # Instead, we install them with install(DIRECTORY) + set(include_location "include") + get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) + if (include_directories) + unset(public_headers) + foreach(include_directory ${include_directories}) + string(GENEX_STRIP ${include_directory} include_genex_expr) + if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions + unset(current_public_headers) + install(DIRECTORY ${include_directory} + DESTINATION ${include_location}/${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + FILES_MATCHING + PATTERN *.h + PATTERN *.hpp + PATTERN *.inl + ) + endif() + endforeach() + endif() + + # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target + file(RELATIVE_PATH archive_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) + + get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) + if(target_runtime_output_directory) + file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) + endif() + + get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY) + if(target_library_output_directory) + file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) + endif() + + install( + TARGETS ${TARGET_NAME} + ARCHIVE + DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ + COMPONENT ${ly_install_target_COMPONENT} + LIBRARY + DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} + COMPONENT ${ly_install_target_COMPONENT} + RUNTIME + DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} + COMPONENT ${ly_install_target_COMPONENT} + ) + + # CMakeLists.txt file + string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME}) + if(match) + set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}") + set(NAME_PLACEHOLDER ${CMAKE_MATCH_2}) + else() + set(NAMESPACE_PLACEHOLDER "") + set(NAME_PLACEHOLDER ${TARGET_NAME}) + endif() + + set(TARGET_TYPE_PLACEHOLDER "") + get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) + # Remove the _LIBRARY since we dont need to pass that to ly_add_targets + string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) + # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead + string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) + if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") + get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) + if(gem_module) + set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") + endif() + endif() + + get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) + if(COMPILE_DEFINITIONS_PLACEHOLDER) + string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") + else() + unset(COMPILE_DEFINITIONS_PLACEHOLDER) + endif() + + # Includes need additional processing to add the install root + if(include_directories) + foreach(include ${include_directories}) + string(GENEX_STRIP ${include} include_genex_expr) + if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions + file(RELATIVE_PATH relative_include ${absolute_target_source_dir} ${include}) + string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}/${relative_include}\n") + endif() + endforeach() + endif() + + get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) + if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found + string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") + else() + unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) + endif() + + get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) + unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + if(inteface_build_dependencies_props) + foreach(build_dependency ${inteface_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + endif() + endforeach() + endif() + # We also need to pass the private link libraries since we will use that to generate the runtime dependencies + get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) + if(private_build_dependencies_props) + foreach(build_dependency ${private_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + endif() + endforeach() + endif() + list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + + # Config file + set(target_file_contents "# Generated by O3DE install\n\n") + if(NOT target_type STREQUAL INTERFACE_LIBRARY) + + unset(target_location) + set(runtime_types EXECUTABLE APPLICATION) + if(target_type IN_LIST runtime_types) + set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$") + elseif(target_type STREQUAL MODULE_LIBRARY) + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") + elseif(target_type STREQUAL SHARED_LIBRARY) + string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$ \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\")\n") + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") + else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY + set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$") + endif() + + if(target_location) + string(APPEND target_file_contents +"set_property(TARGET ${TARGET_NAME} + APPEND_STRING PROPERTY IMPORTED_LOCATION + $<$$:${target_location}$ +) +set_property(TARGET ${TARGET_NAME} + PROPERTY IMPORTED_LOCATION_$> + ${target_location} +) +") + endif() + endif() + + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" + DESTINATION ${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + ) + + # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target + file(READ ${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in target_cmakelists_template) + string(CONFIGURE ${target_cmakelists_template} output_cmakelists_data @ONLY) + set(${OUTPUT_CONFIGURED_TARGET} ${output_cmakelists_data} PARENT_SCOPE) +endfunction() + #! ly_setup_subdirectories: setups all targets on a per directory basis function(ly_setup_subdirectories) get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) @@ -30,176 +199,13 @@ endfunction() #! ly_setup_subdirectory: setup all targets in the subdirectory function(ly_setup_subdirectory absolute_target_source_dir) - file(READ ${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in target_cmakelists_template) # The builtin BUILDSYSTEM_TARGETS property isn't being used here as that returns the de-alised # TARGET and we need the alias namespace for recreating the CMakeLists.txt in the install layout get_property(ALIAS_TARGETS_NAME DIRECTORY ${absolute_target_source_dir} PROPERTY LY_DIRECTORY_TARGETS) file(RELATIVE_PATH target_source_dir ${LY_ROOT_FOLDER} ${absolute_target_source_dir}) foreach(ALIAS_TARGET_NAME IN LISTS ALIAS_TARGETS_NAME) - unset(TARGET_NAME) - ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) - - # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that - # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the - # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. - # Instead, we install them with install(DIRECTORY) - set(include_location "include") - get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) - if (include_directories) - unset(public_headers) - foreach(include_directory ${include_directories}) - string(GENEX_STRIP ${include_directory} include_genex_expr) - if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions - unset(current_public_headers) - install(DIRECTORY ${include_directory} - DESTINATION ${include_location}/${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} - FILES_MATCHING - PATTERN *.h - PATTERN *.hpp - PATTERN *.inl - ) - endif() - endforeach() - endif() - - # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target - file(RELATIVE_PATH archive_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) - - get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) - if(target_runtime_output_directory) - file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) - endif() - - get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY) - if(target_library_output_directory) - file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) - endif() - - install( - TARGETS ${TARGET_NAME} - ARCHIVE - DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${ly_install_target_COMPONENT} - LIBRARY - DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} - RUNTIME - DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} - ) - - # CMakeLists.txt file - string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME}) - if(match) - set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}") - set(NAME_PLACEHOLDER ${CMAKE_MATCH_2}) - else() - set(NAMESPACE_PLACEHOLDER "") - set(NAME_PLACEHOLDER ${TARGET_NAME}) - endif() - - set(TARGET_TYPE_PLACEHOLDER "") - get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) - # Remove the _LIBRARY since we dont need to pass that to ly_add_targets - string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) - # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead - string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) - if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") - get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) - if(gem_module) - set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") - endif() - endif() - - get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) - if(COMPILE_DEFINITIONS_PLACEHOLDER) - string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") - else() - unset(COMPILE_DEFINITIONS_PLACEHOLDER) - endif() - - # Includes need additional processing to add the install root - if(include_directories) - foreach(include ${include_directories}) - string(GENEX_STRIP ${include} include_genex_expr) - if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions - file(RELATIVE_PATH relative_include ${absolute_target_source_dir} ${include}) - string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}/${relative_include}\n") - endif() - endforeach() - endif() - - get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) - if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found - string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") - else() - unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) - endif() - - get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) - unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) - if(inteface_build_dependencies_props) - foreach(build_dependency ${inteface_build_dependencies_props}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") - endif() - endforeach() - endif() - # We also need to pass the private link libraries since we will use that to generate the runtime dependencies - get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) - if(private_build_dependencies_props) - foreach(build_dependency ${private_build_dependencies_props}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") - endif() - endforeach() - endif() - list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) - string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") - - # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target - string(CONFIGURE ${target_cmakelists_template} configured_target @ONLY) + ly_setup_target(configured_target ${ALIAS_TARGET_NAME}) string(APPEND all_configured_targets "${configured_target}") - - # Config file - set(target_file_contents "# Generated by O3DE install\n\n") - if(NOT target_type STREQUAL INTERFACE_LIBRARY) - - unset(target_location) - set(runtime_types EXECUTABLE APPLICATION) - if(target_type IN_LIST runtime_types) - set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$") - elseif(target_type STREQUAL MODULE_LIBRARY) - set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") - elseif(target_type STREQUAL SHARED_LIBRARY) - string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$ \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\")\n") - set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") - else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY - set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$") - endif() - - if(target_location) - string(APPEND target_file_contents - "set_property(TARGET ${TARGET_NAME} - APPEND_STRING PROPERTY IMPORTED_LOCATION - $<$$:${target_location}$ - ) - set_property(TARGET ${TARGET_NAME} - PROPERTY IMPORTED_LOCATION_$> - ${target_location} - ) - ") - endif() - endif() - - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" - DESTINATION ${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} - ) endforeach() # Replicate the ly_create_alias() calls based on the SOURCE_DIR for each target that generates an installed CMakeLists.txt @@ -304,7 +310,7 @@ function(ly_setup_cmake_install) get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) foreach(target_subdirectory IN LISTS all_subdirectories) file(RELATIVE_PATH target_source_dir_relative ${LY_ROOT_FOLDER} ${target_subdirectory}) - string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${target_source_dir_relative}/${target})\n") + string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${target_source_dir_relative})\n") endforeach() configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) From 18e479589d672a146ac6e8c1362ca481825c3723 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 01:51:09 -0500 Subject: [PATCH 115/140] Updating the Install_common.cmake ly_setup_o3de_install() function to be able forward all the ly_add_targets calls within a single source Engine CMakeLists.txt to a single installed Engine CMakeLists.txt --- cmake/LYWrappers.cmake | 9 + cmake/Platform/Common/Install_common.cmake | 367 +++++++++++---------- cmake/install/Copyright.in | 10 + cmake/install/TargetCMakeLists.txt.in | 11 - 4 files changed, 210 insertions(+), 187 deletions(-) create mode 100644 cmake/install/Copyright.in diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index ee0d66553a..bef3b25328 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -313,6 +313,15 @@ function(ly_add_target) # Store the target so we can walk through all of them in LocationDependencies.cmake set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGETS ${interface_name}) + # Store the aliased target into a DIRECTORY property + set_property(DIRECTORY APPEND PROPERTY LY_DIRECTORY_TARGETS ${interface_name}) + # Store the directory path in a GLOBAL property so that it can be accessed + # in the layout install logic. Skip if the directory has already been added + get_property(ly_all_target_directories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) + if(NOT CMAKE_CURRENT_SOURCE_DIR IN_LIST ly_all_target_directories) + set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGET_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}) + endif() + set(runtime_dependencies_list SHARED MODULE EXECUTABLE APPLICATION) if(NOT ly_add_target_IMPORTED AND linking_options IN_LIST runtime_dependencies_list) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 27b8d83a9c..aa9e710a0e 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -17,143 +17,190 @@ file(RELATIVE_PATH runtime_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_RUNTIME_ file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) set(install_output_folder "${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$") -#! ly_setup_targets: setups all targets -function(ly_setup_targets) - get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) - foreach(target IN LISTS all_targets) - ly_setup_target(${target}) + +#! ly_setup_subdirectories: setups all targets on a per directory basis +function(ly_setup_subdirectories) + get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) + foreach(target IN LISTS all_subdirectories) + ly_setup_subdirectory(${target}) endforeach() endfunction() -#! ly_setup_target: setups the target to be installed by cmake install. -function(ly_setup_target ALIAS_TARGET_NAME) - unset(TARGET_NAME) - ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) - - get_target_property(absolute_target_source_dir ${TARGET_NAME} SOURCE_DIR) +#! ly_setup_subdirectory: setup all targets in the subdirectory +function(ly_setup_subdirectory absolute_target_source_dir) + + file(READ ${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in target_cmakelists_template) + # The builtin BUILDSYSTEM_TARGETS property isn't being used here as that returns the de-alised + # TARGET and we need the alias namespace for recreating the CMakeLists.txt in the install layout + get_property(ALIAS_TARGETS_NAME DIRECTORY ${absolute_target_source_dir} PROPERTY LY_DIRECTORY_TARGETS) file(RELATIVE_PATH target_source_dir ${LY_ROOT_FOLDER} ${absolute_target_source_dir}) + foreach(ALIAS_TARGET_NAME IN LISTS ALIAS_TARGETS_NAME) + unset(TARGET_NAME) + ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) - # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that - # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the - # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. - # Instead, we install them with install(DIRECTORY) - set(include_location "include") - get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) - if (include_directories) - unset(public_headers) - foreach(include_directory ${include_directories}) - string(GENEX_STRIP ${include_directory} include_genex_expr) - if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions - unset(current_public_headers) - install(DIRECTORY ${include_directory} - DESTINATION ${include_location}/${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} - FILES_MATCHING - PATTERN *.h - PATTERN *.hpp - PATTERN *.inl - ) - endif() - endforeach() - endif() - - # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target - file(RELATIVE_PATH archive_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) - - get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) - if(target_runtime_output_directory) - file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) - endif() - - get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY) - if(target_library_output_directory) - file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) - endif() - - install( - TARGETS ${TARGET_NAME} - ARCHIVE - DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${ly_install_target_COMPONENT} - LIBRARY - DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} - RUNTIME - DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} - ) - - # CMakeLists.txt file - string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME}) - if(match) - set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}") - set(NAME_PLACEHOLDER ${CMAKE_MATCH_2}) - else() - set(NAMESPACE_PLACEHOLDER "") - set(NAME_PLACEHOLDER ${TARGET_NAME}) - endif() - - set(TARGET_TYPE_PLACEHOLDER "") - get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) - # Remove the _LIBRARY since we dont need to pass that to ly_add_targets - string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) - # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead - string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) - if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") - get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) - if(gem_module) - set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") + # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that + # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the + # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. + # Instead, we install them with install(DIRECTORY) + set(include_location "include") + get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) + if (include_directories) + unset(public_headers) + foreach(include_directory ${include_directories}) + string(GENEX_STRIP ${include_directory} include_genex_expr) + if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions + unset(current_public_headers) + install(DIRECTORY ${include_directory} + DESTINATION ${include_location}/${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + FILES_MATCHING + PATTERN *.h + PATTERN *.hpp + PATTERN *.inl + ) + endif() + endforeach() endif() - endif() - get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) - if(COMPILE_DEFINITIONS_PLACEHOLDER) - string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") - else() - unset(COMPILE_DEFINITIONS_PLACEHOLDER) - endif() + # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target + file(RELATIVE_PATH archive_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) - # Includes need additional processing to add the install root - if(include_directories) - foreach(include ${include_directories}) - string(GENEX_STRIP ${include} include_genex_expr) - if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions - file(RELATIVE_PATH relative_include ${absolute_target_source_dir} ${include}) - string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}/${relative_include}\n") + get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) + if(target_runtime_output_directory) + file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) + endif() + + get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY) + if(target_library_output_directory) + file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) + endif() + + install( + TARGETS ${TARGET_NAME} + ARCHIVE + DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ + COMPONENT ${ly_install_target_COMPONENT} + LIBRARY + DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} + COMPONENT ${ly_install_target_COMPONENT} + RUNTIME + DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} + COMPONENT ${ly_install_target_COMPONENT} + ) + + # CMakeLists.txt file + string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME}) + if(match) + set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}") + set(NAME_PLACEHOLDER ${CMAKE_MATCH_2}) + else() + set(NAMESPACE_PLACEHOLDER "") + set(NAME_PLACEHOLDER ${TARGET_NAME}) + endif() + + set(TARGET_TYPE_PLACEHOLDER "") + get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) + # Remove the _LIBRARY since we dont need to pass that to ly_add_targets + string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) + # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead + string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) + if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") + get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) + if(gem_module) + set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") endif() - endforeach() - endif() + endif() - get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) - if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found - string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") - else() - unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) - endif() + get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) + if(COMPILE_DEFINITIONS_PLACEHOLDER) + string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") + else() + unset(COMPILE_DEFINITIONS_PLACEHOLDER) + endif() - get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) - unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) - if(inteface_build_dependencies_props) - foreach(build_dependency ${inteface_build_dependencies_props}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + # Includes need additional processing to add the install root + if(include_directories) + foreach(include ${include_directories}) + string(GENEX_STRIP ${include} include_genex_expr) + if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions + file(RELATIVE_PATH relative_include ${absolute_target_source_dir} ${include}) + string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}/${relative_include}\n") + endif() + endforeach() + endif() + + get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) + if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found + string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") + else() + unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) + endif() + + get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) + unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + if(inteface_build_dependencies_props) + foreach(build_dependency ${inteface_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + endif() + endforeach() + endif() + # We also need to pass the private link libraries since we will use that to generate the runtime dependencies + get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) + if(private_build_dependencies_props) + foreach(build_dependency ${private_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + endif() + endforeach() + endif() + list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + + # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target + string(CONFIGURE ${target_cmakelists_template} configured_target @ONLY) + string(APPEND all_configured_targets "${configured_target}") + + # Config file + set(target_file_contents "# Generated by O3DE install\n\n") + if(NOT target_type STREQUAL INTERFACE_LIBRARY) + + unset(target_location) + set(runtime_types EXECUTABLE APPLICATION) + if(target_type IN_LIST runtime_types) + set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$") + elseif(target_type STREQUAL MODULE_LIBRARY) + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") + elseif(target_type STREQUAL SHARED_LIBRARY) + string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$ \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\")\n") + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") + else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY + set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$") endif() - endforeach() - endif() - # We also need to pass the private link libraries since we will use that to generate the runtime dependencies - get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) - if(private_build_dependencies_props) - foreach(build_dependency ${private_build_dependencies_props}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + + if(target_location) + string(APPEND target_file_contents + "set_property(TARGET ${TARGET_NAME} + APPEND_STRING PROPERTY IMPORTED_LOCATION + $<$$:${target_location}$ + ) + set_property(TARGET ${TARGET_NAME} + PROPERTY IMPORTED_LOCATION_$> + ${target_location} + ) + ") endif() - endforeach() - endif() - list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) - string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + endif() + + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" + DESTINATION ${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + ) + endforeach() # Replicate the ly_create_alias() calls based on the SOURCE_DIR for each target that generates an installed CMakeLists.txt string(JOIN "\n" create_alias_template @@ -174,48 +221,16 @@ function(ly_setup_target ALIAS_TARGET_NAME) string(APPEND CREATE_ALIASES_PLACEHOLDER ${create_alias_command}) endforeach() - # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target - configure_file(${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in ${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/CMakeLists.txt @ONLY) - - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/CMakeLists.txt" - DESTINATION ${target_source_dir}/${NAME_PLACEHOLDER} - COMPONENT ${ly_install_target_COMPONENT} + file(READ ${LY_ROOT_FOLDER}/cmake/install/Copyright.in cmake_copyright_comment) + # Write out all the agreegated ly_add_target function calls and the final ly_create_alias() calls to the target CMakeList.txt + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt + "${cmake_copyright_comment}" + "${all_configured_targets}" + "\n" + "${CREATE_ALIASES_PLACEHOLDER}" ) - - # Config file - set(target_file_contents "# Generated by O3DE install\n\n") - if(NOT target_type STREQUAL INTERFACE_LIBRARY) - - unset(target_location) - set(runtime_types EXECUTABLE APPLICATION) - if(target_type IN_LIST runtime_types) - set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$") - elseif(target_type STREQUAL MODULE_LIBRARY) - set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") - elseif(target_type STREQUAL SHARED_LIBRARY) - string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$ \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\")\n") - set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") - else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY - set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$") - endif() - - if(target_location) - string(APPEND target_file_contents -"set_property(TARGET ${TARGET_NAME} - APPEND_STRING PROPERTY IMPORTED_LOCATION - $<$$:${target_location}$ -) -set_property(TARGET ${TARGET_NAME} - PROPERTY IMPORTED_LOCATION_$> - ${target_location} -) -") - endif() - endif() - - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${NAME_PLACEHOLDER}/${NAME_PLACEHOLDER}_$.cmake" - DESTINATION ${target_source_dir}/${NAME_PLACEHOLDER} + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt" + DESTINATION ${target_source_dir} COMPONENT ${ly_install_target_COMPONENT} ) @@ -224,7 +239,7 @@ endfunction() #! ly_setup_o3de_install: orchestrates the installation of the different parts. This is the entry point from the root CMakeLists.txt function(ly_setup_o3de_install) - ly_setup_targets() + ly_setup_subdirectories() ly_setup_cmake_install() ly_setup_target_generator() ly_setup_runtime_dependencies() @@ -283,12 +298,12 @@ function(ly_setup_cmake_install) # Findo3de.cmake file: we generate a different Findo3de.camke file than the one we have in cmake. This one is going to expose all # targets that are pre-built - get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) unset(FIND_PACKAGES_PLACEHOLDER) - foreach(alias_target IN LISTS all_targets) - ly_de_alias_target(${alias_target} target) - get_target_property(target_source_dir ${target} SOURCE_DIR) - file(RELATIVE_PATH target_source_dir_relative ${LY_ROOT_FOLDER} ${target_source_dir}) + + # Add to the FIND_PACKAGES_PLACEHOLDER all directories in which ly_add_target were called in + get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) + foreach(target_subdirectory IN LISTS all_subdirectories) + file(RELATIVE_PATH target_source_dir_relative ${LY_ROOT_FOLDER} ${target_subdirectory}) string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${target_source_dir_relative}/${target})\n") endforeach() @@ -339,7 +354,7 @@ function(ly_copy source_file target_directory) endfunction()" COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) - + unset(runtime_commands) get_property(all_targets GLOBAL PROPERTY LY_ALL_TARGETS) foreach(alias_target IN LISTS all_targets) @@ -350,12 +365,12 @@ endfunction()" if(NOT target_type IN_LIST LY_TARGET_TYPES_WITH_RUNTIME_OUTPUTS) continue() endif() - + get_target_property(target_runtime_output_directory ${target} RUNTIME_OUTPUT_DIRECTORY) if(target_runtime_output_directory) file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) endif() - + # Qt get_property(has_qt_dependency GLOBAL PROPERTY LY_DETECT_QT_DEPENDENCY_${target}) if(has_qt_dependency) @@ -374,7 +389,7 @@ endfunction()" foreach(runtime_dependency ${runtime_dependencies}) unset(runtime_command) ly_get_runtime_dependency_command(runtime_command ${runtime_dependency}) - string(CONFIGURE "${runtime_command}" runtime_command @ONLY) + string(CONFIGURE "${runtime_command}" runtime_command @ONLY) list(APPEND runtime_commands ${runtime_command}) endforeach() @@ -382,10 +397,10 @@ endfunction()" list(REMOVE_DUPLICATES runtime_commands) list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file - install(CODE "${runtime_commands_str}" + install(CODE "${runtime_commands_str}" COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) - + endfunction() #! ly_setup_others: install directories required by the engine diff --git a/cmake/install/Copyright.in b/cmake/install/Copyright.in new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/cmake/install/Copyright.in @@ -0,0 +1,10 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/TargetCMakeLists.txt.in index 06cd022898..0503fd5f2b 100644 --- a/cmake/install/TargetCMakeLists.txt.in +++ b/cmake/install/TargetCMakeLists.txt.in @@ -1,13 +1,3 @@ -# -# 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. -# # Generated by O3DE @@ -27,7 +17,6 @@ ly_add_target( @RUNTIME_DEPENDENCIES_PLACEHOLDER@ ) -@CREATE_ALIASES_PLACEHOLDER@ set(configs @CMAKE_CONFIGURATION_TYPES@) foreach(config ${configs}) include("@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) From f6568f5c639849a890d9cef803d7b6fd4ba5b66b Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 12:36:33 -0500 Subject: [PATCH 116/140] Re-added back an ly_setup_target function which configures the CMakeLists.txt template for a single target --- cmake/Platform/Common/Install_common.cmake | 336 +++++++++++---------- 1 file changed, 171 insertions(+), 165 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index aa9e710a0e..939f523d75 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -18,6 +18,175 @@ file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_ set(install_output_folder "${CMAKE_INSTALL_PREFIX}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$") +#! ly_setup_target: Setup the data needed to re-create the cmake target commands for a single target +function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME) + # De-alias target name + ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) + + # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that + # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the + # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. + # Instead, we install them with install(DIRECTORY) + set(include_location "include") + get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) + if (include_directories) + unset(public_headers) + foreach(include_directory ${include_directories}) + string(GENEX_STRIP ${include_directory} include_genex_expr) + if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions + unset(current_public_headers) + install(DIRECTORY ${include_directory} + DESTINATION ${include_location}/${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + FILES_MATCHING + PATTERN *.h + PATTERN *.hpp + PATTERN *.inl + ) + endif() + endforeach() + endif() + + # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target + file(RELATIVE_PATH archive_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) + + get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) + if(target_runtime_output_directory) + file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) + endif() + + get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY) + if(target_library_output_directory) + file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) + endif() + + install( + TARGETS ${TARGET_NAME} + ARCHIVE + DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ + COMPONENT ${ly_install_target_COMPONENT} + LIBRARY + DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} + COMPONENT ${ly_install_target_COMPONENT} + RUNTIME + DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} + COMPONENT ${ly_install_target_COMPONENT} + ) + + # CMakeLists.txt file + string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME}) + if(match) + set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}") + set(NAME_PLACEHOLDER ${CMAKE_MATCH_2}) + else() + set(NAMESPACE_PLACEHOLDER "") + set(NAME_PLACEHOLDER ${TARGET_NAME}) + endif() + + set(TARGET_TYPE_PLACEHOLDER "") + get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) + # Remove the _LIBRARY since we dont need to pass that to ly_add_targets + string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) + # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead + string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) + if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") + get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) + if(gem_module) + set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") + endif() + endif() + + get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) + if(COMPILE_DEFINITIONS_PLACEHOLDER) + string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") + else() + unset(COMPILE_DEFINITIONS_PLACEHOLDER) + endif() + + # Includes need additional processing to add the install root + if(include_directories) + foreach(include ${include_directories}) + string(GENEX_STRIP ${include} include_genex_expr) + if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions + file(RELATIVE_PATH relative_include ${absolute_target_source_dir} ${include}) + string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}/${relative_include}\n") + endif() + endforeach() + endif() + + get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) + if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found + string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") + else() + unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) + endif() + + get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) + unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + if(inteface_build_dependencies_props) + foreach(build_dependency ${inteface_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + endif() + endforeach() + endif() + # We also need to pass the private link libraries since we will use that to generate the runtime dependencies + get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) + if(private_build_dependencies_props) + foreach(build_dependency ${private_build_dependencies_props}) + # Skip wrapping produced when targets are not created in the same directory + if(NOT ${build_dependency} MATCHES "^::@") + list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") + endif() + endforeach() + endif() + list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) + string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") + + # Config file + set(target_file_contents "# Generated by O3DE install\n\n") + if(NOT target_type STREQUAL INTERFACE_LIBRARY) + + unset(target_location) + set(runtime_types EXECUTABLE APPLICATION) + if(target_type IN_LIST runtime_types) + set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$") + elseif(target_type STREQUAL MODULE_LIBRARY) + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") + elseif(target_type STREQUAL SHARED_LIBRARY) + string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$ \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\")\n") + set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") + else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY + set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$") + endif() + + if(target_location) + string(APPEND target_file_contents +"set_property(TARGET ${TARGET_NAME} + APPEND_STRING PROPERTY IMPORTED_LOCATION + $<$$:${target_location}$ +) +set_property(TARGET ${TARGET_NAME} + PROPERTY IMPORTED_LOCATION_$> + ${target_location} +) +") + endif() + endif() + + file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" + DESTINATION ${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + ) + + # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target + file(READ ${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in target_cmakelists_template) + string(CONFIGURE ${target_cmakelists_template} output_cmakelists_data @ONLY) + set(${OUTPUT_CONFIGURED_TARGET} ${output_cmakelists_data} PARENT_SCOPE) +endfunction() + #! ly_setup_subdirectories: setups all targets on a per directory basis function(ly_setup_subdirectories) get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) @@ -30,176 +199,13 @@ endfunction() #! ly_setup_subdirectory: setup all targets in the subdirectory function(ly_setup_subdirectory absolute_target_source_dir) - file(READ ${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in target_cmakelists_template) # The builtin BUILDSYSTEM_TARGETS property isn't being used here as that returns the de-alised # TARGET and we need the alias namespace for recreating the CMakeLists.txt in the install layout get_property(ALIAS_TARGETS_NAME DIRECTORY ${absolute_target_source_dir} PROPERTY LY_DIRECTORY_TARGETS) file(RELATIVE_PATH target_source_dir ${LY_ROOT_FOLDER} ${absolute_target_source_dir}) foreach(ALIAS_TARGET_NAME IN LISTS ALIAS_TARGETS_NAME) - unset(TARGET_NAME) - ly_de_alias_target(${ALIAS_TARGET_NAME} TARGET_NAME) - - # All include directories marked PUBLIC or INTERFACE will be installed. We dont use PUBLIC_HEADER because in order to do that - # we need to set the PUBLIC_HEADER property of the target for all the headers we are exporting. After doing that, installing the - # headers end up in one folder instead of duplicating the folder structure of the public/interface include directory. - # Instead, we install them with install(DIRECTORY) - set(include_location "include") - get_target_property(include_directories ${TARGET_NAME} INTERFACE_INCLUDE_DIRECTORIES) - if (include_directories) - unset(public_headers) - foreach(include_directory ${include_directories}) - string(GENEX_STRIP ${include_directory} include_genex_expr) - if(include_genex_expr STREQUAL include_directory) # only for cases where there are no generation expressions - unset(current_public_headers) - install(DIRECTORY ${include_directory} - DESTINATION ${include_location}/${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} - FILES_MATCHING - PATTERN *.h - PATTERN *.hpp - PATTERN *.inl - ) - endif() - endforeach() - endif() - - # Get the output folders, archive is always the same, but runtime/library can be in subfolders defined per target - file(RELATIVE_PATH archive_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) - - get_target_property(target_runtime_output_directory ${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY) - if(target_runtime_output_directory) - file(RELATIVE_PATH target_runtime_output_subdirectory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${target_runtime_output_directory}) - endif() - - get_target_property(target_library_output_directory ${TARGET_NAME} LIBRARY_OUTPUT_DIRECTORY) - if(target_library_output_directory) - file(RELATIVE_PATH target_library_output_subdirectory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${target_library_output_directory}) - endif() - - install( - TARGETS ${TARGET_NAME} - ARCHIVE - DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ - COMPONENT ${ly_install_target_COMPONENT} - LIBRARY - DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} - RUNTIME - DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} - COMPONENT ${ly_install_target_COMPONENT} - ) - - # CMakeLists.txt file - string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME}) - if(match) - set(NAMESPACE_PLACEHOLDER "NAMESPACE ${CMAKE_MATCH_1}") - set(NAME_PLACEHOLDER ${CMAKE_MATCH_2}) - else() - set(NAMESPACE_PLACEHOLDER "") - set(NAME_PLACEHOLDER ${TARGET_NAME}) - endif() - - set(TARGET_TYPE_PLACEHOLDER "") - get_target_property(target_type ${NAME_PLACEHOLDER} TYPE) - # Remove the _LIBRARY since we dont need to pass that to ly_add_targets - string(REPLACE "_LIBRARY" "" TARGET_TYPE_PLACEHOLDER ${target_type}) - # For HEADER_ONLY libs we end up generating "INTERFACE" libraries, need to specify HEADERONLY instead - string(REPLACE "INTERFACE" "HEADERONLY" TARGET_TYPE_PLACEHOLDER ${TARGET_TYPE_PLACEHOLDER}) - if(TARGET_TYPE_PLACEHOLDER STREQUAL "MODULE") - get_target_property(gem_module ${NAME_PLACEHOLDER} GEM_MODULE) - if(gem_module) - set(TARGET_TYPE_PLACEHOLDER "GEM_MODULE") - endif() - endif() - - get_target_property(COMPILE_DEFINITIONS_PLACEHOLDER ${TARGET_NAME} INTERFACE_COMPILE_DEFINITIONS) - if(COMPILE_DEFINITIONS_PLACEHOLDER) - string(REPLACE ";" "\n" COMPILE_DEFINITIONS_PLACEHOLDER "${COMPILE_DEFINITIONS_PLACEHOLDER}") - else() - unset(COMPILE_DEFINITIONS_PLACEHOLDER) - endif() - - # Includes need additional processing to add the install root - if(include_directories) - foreach(include ${include_directories}) - string(GENEX_STRIP ${include} include_genex_expr) - if(include_genex_expr STREQUAL include) # only for cases where there are no generation expressions - file(RELATIVE_PATH relative_include ${absolute_target_source_dir} ${include}) - string(APPEND INCLUDE_DIRECTORIES_PLACEHOLDER "\${LY_ROOT_FOLDER}/include/${target_source_dir}/${relative_include}\n") - endif() - endforeach() - endif() - - get_target_property(RUNTIME_DEPENDENCIES_PLACEHOLDER ${TARGET_NAME} MANUALLY_ADDED_DEPENDENCIES) - if(RUNTIME_DEPENDENCIES_PLACEHOLDER) # not found properties return the name of the variable with a "-NOTFOUND" at the end, here we set it to empty if not found - string(REPLACE ";" "\n" RUNTIME_DEPENDENCIES_PLACEHOLDER "${RUNTIME_DEPENDENCIES_PLACEHOLDER}") - else() - unset(RUNTIME_DEPENDENCIES_PLACEHOLDER) - endif() - - get_target_property(inteface_build_dependencies_props ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) - unset(INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) - if(inteface_build_dependencies_props) - foreach(build_dependency ${inteface_build_dependencies_props}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") - endif() - endforeach() - endif() - # We also need to pass the private link libraries since we will use that to generate the runtime dependencies - get_target_property(private_build_dependencies_props ${TARGET_NAME} LINK_LIBRARIES) - if(private_build_dependencies_props) - foreach(build_dependency ${private_build_dependencies_props}) - # Skip wrapping produced when targets are not created in the same directory - if(NOT ${build_dependency} MATCHES "^::@") - list(APPEND INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${build_dependency}") - endif() - endforeach() - endif() - list(REMOVE_DUPLICATES INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER) - string(REPLACE ";" "\n" INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER "${INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER}") - - # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target - string(CONFIGURE ${target_cmakelists_template} configured_target @ONLY) + ly_setup_target(configured_target ${ALIAS_TARGET_NAME}) string(APPEND all_configured_targets "${configured_target}") - - # Config file - set(target_file_contents "# Generated by O3DE install\n\n") - if(NOT target_type STREQUAL INTERFACE_LIBRARY) - - unset(target_location) - set(runtime_types EXECUTABLE APPLICATION) - if(target_type IN_LIST runtime_types) - set(target_location "\${LY_ROOT_FOLDER}/${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory}/$") - elseif(target_type STREQUAL MODULE_LIBRARY) - set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") - elseif(target_type STREQUAL SHARED_LIBRARY) - string(APPEND target_file_contents "set_property(TARGET ${TARGET_NAME} PROPERTY IMPORTED_IMPLIB_$ \"\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$\")\n") - set(target_location "\${LY_ROOT_FOLDER}/${library_output_directory}/${PAL_PLATFORM_NAME}/$/${target_library_output_subdirectory}/$") - else() # STATIC_LIBRARY, OBJECT_LIBRARY, INTERFACE_LIBRARY - set(target_location "\${LY_ROOT_FOLDER}/${archive_output_directory}/${PAL_PLATFORM_NAME}/$/$") - endif() - - if(target_location) - string(APPEND target_file_contents - "set_property(TARGET ${TARGET_NAME} - APPEND_STRING PROPERTY IMPORTED_LOCATION - $<$$:${target_location}$ - ) - set_property(TARGET ${TARGET_NAME} - PROPERTY IMPORTED_LOCATION_$> - ${target_location} - ) - ") - endif() - endif() - - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" CONTENT "${target_file_contents}") - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/${NAME_PLACEHOLDER}_$.cmake" - DESTINATION ${target_source_dir} - COMPONENT ${ly_install_target_COMPONENT} - ) endforeach() # Replicate the ly_create_alias() calls based on the SOURCE_DIR for each target that generates an installed CMakeLists.txt @@ -304,7 +310,7 @@ function(ly_setup_cmake_install) get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) foreach(target_subdirectory IN LISTS all_subdirectories) file(RELATIVE_PATH target_source_dir_relative ${LY_ROOT_FOLDER} ${target_subdirectory}) - string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${target_source_dir_relative}/${target})\n") + string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${target_source_dir_relative})\n") endforeach() configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) From 1fa7adb185a7ed066116e17711b3b1bd45ed53c8 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 14:42:50 -0700 Subject: [PATCH 117/140] Adding missing gem.json files --- .../AtomViewportDisplayIcons/gem.json | 10 ++++++++++ .../AtomLyIntegration/AtomViewportDisplayInfo/gem.json | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json create mode 100644 Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json new file mode 100644 index 0000000000..41f69e33a0 --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "AtomViewportDisplayIcons", + "display_name": "Atom Viewport Display Icons", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json new file mode 100644 index 0000000000..04e2464a26 --- /dev/null +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/gem.json @@ -0,0 +1,10 @@ +{ + "gem_name": "AtomViewportDisplayInfo", + "display_name": "Atom Viewport Display Info", + "summary": "", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + ] +} From 394ac7ab6a1255bd34099dbcba214544801fa952 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 16:44:50 -0500 Subject: [PATCH 118/140] Updated the enable gem and disable gem API (#54) * Updated the enable gem and disable gem API Renamed remove_gem_project.py -> disable_gem.py Renamed add_gem_project.py -> enable_gem.py Renamed the "add-gem-to-project" command -> "enable-gem" Renamed the "remove-gem-from-project" command -> "disable-gem" Fixed the parsing of the enabled gems from the enabled_gems.cmake file * Adding newline to the end of the CMakeLists.txt --- .../ProjectManager/Source/PythonBindings.cpp | 8 +- .../ProjectManager/Source/PythonBindings.h | 4 +- scripts/o3de.py | 6 +- scripts/o3de/o3de/cmake.py | 28 +- .../{remove_gem_project.py => disable_gem.py} | 74 ++--- .../{add_gem_project.py => enable_gem.py} | 66 ++--- scripts/o3de/o3de/manifest.py | 68 +++-- scripts/o3de/tests/CMakeLists.txt | 7 + .../o3de/tests/unit_test_add_remove_gem.py | 259 ------------------ scripts/o3de/tests/unit_test_cmake.py | 69 +++++ scripts/project_manager/projects.py | 10 +- 11 files changed, 208 insertions(+), 391 deletions(-) rename scripts/o3de/o3de/{remove_gem_project.py => disable_gem.py} (69%) rename scripts/o3de/o3de/{add_gem_project.py => enable_gem.py} (76%) delete mode 100755 scripts/o3de/tests/unit_test_add_remove_gem.py create mode 100644 scripts/o3de/tests/unit_test_cmake.py diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index c1e62f9c04..71d3c6de63 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -286,8 +286,8 @@ namespace O3DE::ProjectManager m_register = pybind11::module::import("o3de.register"); m_manifest = pybind11::module::import("o3de.manifest"); m_engineTemplate = pybind11::module::import("o3de.engine_template"); - m_addGemProject = pybind11::module::import("o3de.add_gem_project"); - m_removeGemProject = pybind11::module::import("o3de.remove_gem_project"); + m_enableGemProject = pybind11::module::import("o3de.enable_gem"); + m_disableGemProject = pybind11::module::import("o3de.disable_gem"); return result == 0 && !PyErr_Occurred(); } catch ([[maybe_unused]] const std::exception& e) @@ -588,7 +588,7 @@ namespace O3DE::ProjectManager pybind11::str pyGemPath = gemPath.toStdString(); pybind11::str pyProjectPath = projectPath.toStdString(); - m_addGemProject.attr("add_gem_to_project")( + m_enableGemProject.attr("enable_gem_in_project")( pybind11::none(), // gem_name pyGemPath, pybind11::none(), // project_name @@ -605,7 +605,7 @@ namespace O3DE::ProjectManager pybind11::str pyGemPath = gemPath.toStdString(); pybind11::str pyProjectPath = projectPath.toStdString(); - m_removeGemProject.attr("remove_gem_from_project")( + m_disableGemProject.attr("disable_gem_in_project")( pybind11::none(), // gem_name pyGemPath, pybind11::none(), // project_name diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 2dc15bd574..88bd0c1911 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -68,7 +68,7 @@ namespace O3DE::ProjectManager AZStd::recursive_mutex m_lock; pybind11::handle m_register; pybind11::handle m_manifest; - pybind11::handle m_addGemProject; - pybind11::handle m_removeGemProject; + pybind11::handle m_enableGemProject; + pybind11::handle m_disableGemProject; }; } diff --git a/scripts/o3de.py b/scripts/o3de.py index f91d5a25a0..24ba862529 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -32,7 +32,7 @@ def add_args(parser, subparsers) -> None: # add the scripts/o3de directory to the front of the sys.path sys.path.insert(0, str(o3de_package_dir)) from o3de import engine_template, global_project, register, print_registration, get_registration, download, \ - add_gem_project, remove_gem_project, sha256 + enable_gem, disable_gem, sha256 # Remove the temporarily added path sys.path = sys.path[1:] @@ -54,10 +54,10 @@ def add_args(parser, subparsers) -> None: download.add_args(subparsers) # add a gem to a project - add_gem_project.add_args(subparsers) + enable_gem.add_args(subparsers) # remove a gem from a project - remove_gem_project.add_args(subparsers) + disable_gem.add_args(subparsers) # sha256 sha256.add_args(subparsers) diff --git a/scripts/o3de/o3de/cmake.py b/scripts/o3de/o3de/cmake.py index eb8e3957ad..dfcce708eb 100644 --- a/scripts/o3de/o3de/cmake.py +++ b/scripts/o3de/o3de/cmake.py @@ -26,9 +26,9 @@ def get_project_gems(project_path: pathlib.Path, return get_gems_from_cmake_file(get_enabled_gem_cmake_file(project_path=project_path, platform=platform)) -def get_gem_from_cmake_file(cmake_file: pathlib.Path) -> set: +def get_enabled_gems(cmake_file: pathlib.Path) -> set: """ - Gets a list of declared gem targets dependencies of a cmake file + Gets a list of enabled gems from the cmake file :param cmake_file: path to the cmake file :return: set of gem targets found """ @@ -38,11 +38,29 @@ def get_gem_from_cmake_file(cmake_file: pathlib.Path) -> set: logger.error(f'Failed to locate cmake file {cmake_file}') return set() + enable_gem_start_marker = 'set(ENABLED_GEMS' + enable_gem_end_marker = ')' gem_target_set = set() with cmake_file.open('r') as s: + in_gem_list = False for line in s: - gem_name = line.strip() - gem_target_set.add(gem_name) + line = line.strip() + if line.startswith(enable_gem_start_marker): + # Set the flag to indicate that we are in the ENABLED_GEMS variable + in_gem_list = True + # Skip pass the 'set(ENABLED_GEMS' marker just in case their are gems declared on the same line + line = line[len(enable_gem_start_marker):] + if in_gem_list: + # Since we are inside the ENABLED_GEMS variable determine if the line has the end_marker of ')' + if line.endswith(enable_gem_end_marker): + # Strip away the line end marker + line = line[:-len(enable_gem_end_marker)] + # Set the flag to indicate that we are no longer in the ENABLED_GEMS variable after this line + in_gem_list = False + # Split the rest of the line on whitespace just in case there are multiple gems in a line + gem_name_list = line.split() + gem_target_set.update(gem_name_list) + return gem_target_set @@ -72,7 +90,7 @@ def get_enabled_gem_cmake_file(project_name: str = None, project_path = manifest.get_registered(project_name=project_name) project_path = pathlib.Path(project_path).resolve() - enable_gem_filename = "enabled_gem.cmake" + enable_gem_filename = "enabled_gems.cmake" if platform == 'Common': project_code_dir = project_path / 'Gem/Code' diff --git a/scripts/o3de/o3de/remove_gem_project.py b/scripts/o3de/o3de/disable_gem.py similarity index 69% rename from scripts/o3de/o3de/remove_gem_project.py rename to scripts/o3de/o3de/disable_gem.py index 72c51f0e2c..6c466c3631 100644 --- a/scripts/o3de/o3de/remove_gem_project.py +++ b/scripts/o3de/o3de/disable_gem.py @@ -58,20 +58,18 @@ def remove_gem_dependency(cmake_file: pathlib.Path, return 0 -def remove_gem_from_project(gem_name: str = None, - gem_path: pathlib.Path = None, - project_name: str = None, - project_path: pathlib.Path = None, - enabled_gem_file: pathlib.Path = None, - platforms: str = 'Common') -> int: +def disable_gem_in_project(gem_name: str = None, + gem_path: pathlib.Path = None, + project_name: str = None, + project_path: pathlib.Path = None, + enabled_gem_file: pathlib.Path = None) -> int: """ - remove a gem from a project + disable a gem in a projects enabled_gems.cmake file :param gem_name: name of the gem to add :param gem_path: path to the gem to add :param project_name: name of the project to add the gem to :param project_path: path to the project to add the gem to :param enabled_gem_file: File to remove enabled gem from - :param platforms: str to specify common or which specific platforms :return: 0 for success or non 0 failure code """ @@ -122,53 +120,37 @@ def remove_gem_from_project(gem_name: str = None, # when removing we will try to do as much as possible even with failures so ret_val will be the last error code ret_val = 0 - # if the user has specified the dependencies file then ignore the runtime_dependency and tool_dependency flags - if enabled_gem_file: - # make sure this is a project has an enabled_gem file - if not enabled_gem_file.is_file(): - logger.error(f'Enabled gem file {enabled_gem_file} is not present.') - return 1 - # remove the dependency - error_code = remove_gem_dependency(dependencies_file, gem_json_data['gem_name']) - if error_code: - ret_val = error_code - else: - if ',' in platforms: - platforms = platforms.split(',') - else: - platforms = [platforms] - for platform in platforms: - # make sure this is a project has a enabled_gem.cmake file - project_enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path, platform=platform) - if not project_enabled_gem_file.is_file(): - logger.error(f'Enabled gem file {project_enabled_gem_file} is not present.') - else: - # remove the dependency - error_code = remove_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) - if error_code: - ret_val = error_code + if not enabled_gem_file: + enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path) + # make sure this is a project has an enabled gems file + if not enabled_gem_file.is_file(): + logger.error(f'Enabled gem file {enabled_gem_file} is not present.') + return 1 + # remove the gem + error_code = remove_gem_dependency(enabled_gem_file, gem_json_data['gem_name']) + if error_code: + ret_val = error_code return ret_val -def _run_remove_gem_from_project(args: argparse) -> int: +def _run_disable_gem_in_project(args: argparse) -> int: if args.override_home_folder: manifest.override_home_folder = args.override_home_folder - return remove_gem_from_project(args.gem_name, + return disable_gem_in_project(args.gem_name, args.gem_path, args.project_name, args.project_path, - args.enabled_gem_file, - args.platforms) + args.enabled_gem_file) def add_parser_args(parser): """ add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python remove_gem_project.py --project-path D:/Test --gem-name Atom + Ex. Directly run from this file alone with: python disable_gem.py --project-path D:/Test --gem-name Atom :param parser: the caller passes an argparse parser like instance to this method """ group = parser.add_mutually_exclusive_group(required=True) @@ -182,17 +164,13 @@ def add_parser_args(parser): group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') parser.add_argument('-egf', '--enabled-gem-file', type=pathlib.Path, required=False, - help='The cmake enabled gem file in which gem dependencies are to be removed from.' + help='The cmake enabled gem file in which gem names are to be removed from.' 'If not specified it will assume ') - parser.add_argument('-pl', '--platforms', type=str, required=False, - default='Common', - help='Optional list of platforms this gem should be removed from' - ' Ex. --platforms Mac,Windows,Linux') parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, help='By default the home folder is the user folder, override it to this folder.') - parser.set_defaults(func=_run_remove_gem_from_project) + parser.set_defaults(func=_run_disable_gem_in_project) def add_args(subparsers) -> None: @@ -200,16 +178,16 @@ def add_args(subparsers) -> None: add_args is called to add subparsers arguments to each command such that it can be a central python file such as o3de.py. It can be run from the o3de.py script as follows - call add_args and execute: python o3de.py remove-gem-from-project --project-path D:/Test --gem-name Atom + call add_args and execute: python o3de.py disable-gem-from-cmake --project-path D:/Test --gem-name Atom :param subparsers: the caller instantiates subparsers and passes it in here """ - remove_gem_project_subparser = subparsers.add_parser('remove-gem-from-project') - add_parser_args(remove_gem_project_subparser) + disable_gem_project_subparser = subparsers.add_parser('disable-gem') + add_parser_args(disable_gem_project_subparser) def main(): """ - Runs remove_gem_project.py script as standalone script + Runs disable_gem_project.py script as standalone script """ # parse the command line args the_parser = argparse.ArgumentParser() diff --git a/scripts/o3de/o3de/add_gem_project.py b/scripts/o3de/o3de/enable_gem.py similarity index 76% rename from scripts/o3de/o3de/add_gem_project.py rename to scripts/o3de/o3de/enable_gem.py index 42db0a97bd..73fc2ea3cf 100644 --- a/scripts/o3de/o3de/add_gem_project.py +++ b/scripts/o3de/o3de/enable_gem.py @@ -75,20 +75,18 @@ def add_gem_dependency(cmake_file: pathlib.Path, return 0 -def add_gem_to_project(gem_name: str = None, - gem_path: pathlib.Path = None, - project_name: str = None, - project_path: pathlib.Path = None, - enabled_gem_file: pathlib.Path = None, - platforms: str = 'Common') -> int: +def enable_gem_in_project(gem_name: str = None, + gem_path: pathlib.Path = None, + project_name: str = None, + project_path: pathlib.Path = None, + enabled_gem_file: pathlib.Path = None) -> int: """ - add a gem to a project + enable a gem in a projects enabled_gems.cmake file :param gem_name: name of the gem to add :param gem_path: path to the gem to add :param project_name: name of to the project to add the gem to :param project_path: path to the project to add the gem to :param enabled_gem_file_file: if this dependency goes/is in a specific file - :param platforms: str to specify common or which specific platforms :return: 0 for success or non 0 failure code """ # we need either a project name or path @@ -138,47 +136,41 @@ def add_gem_to_project(gem_name: str = None, ret_val = 0 if enabled_gem_file: - # make sure this is a project has a dependencies_file + # make sure this is a project has an enabled gems file if not enabled_gem_file.is_file(): logger.error(f'Enabled gem file {enabled_gem_file} is not present.') return 1 - # add the dependency + # add the gem ret_val = add_gem_dependency(enabled_gem_file, gem_json_data['gem_name']) else: - if ',' in platforms: - platforms = platforms.split(',') - else: - platforms = [platforms] - for platform in platforms: - # Find the path to enabled gem file. - # It will be created by add_gem_dependency if it doesn't exist - project_enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path, platform=platform) - if not project_enabled_gem_file.is_file(): - project_enabled_gem_file.touch() - # add the dependency - ret_val = add_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) + # Find the path to enabled gem file. + # It will be created if it doesn't exist + project_enabled_gem_file = cmake.get_enabled_gem_cmake_file(project_path=project_path) + if not project_enabled_gem_file.is_file(): + project_enabled_gem_file.touch() + # add the gem + ret_val = add_gem_dependency(project_enabled_gem_file, gem_json_data['gem_name']) return ret_val -def _run_add_gem_to_project(args: argparse) -> int: +def _run_enable_gem_in_project(args: argparse) -> int: if args.override_home_folder: manifest.override_home_folder = args.override_home_folder - return add_gem_to_project(args.gem_name, - args.gem_path, - args.project_name, - args.project_path, - args.enabled_gem_file, - args.platforms) + return enable_gem_in_project(args.gem_name, + args.gem_path, + args.project_name, + args.project_path, + args.enabled_gem_file) def add_parser_args(parser): """ add_parser_args is called to add arguments to each command such that it can be invoked locally or added by a central python file. - Ex. Directly run from this file alone with: python add_gem_project.py --project-path "D:/TestProject" --gem-path "D:/TestGem" + Ex. Directly run from this file alone with: python enable_gem.py --project-path "D:/TestProject" --gem-path "D:/TestGem" :param parser: the caller passes an argparse parser like instance to this method """ group = parser.add_mutually_exclusive_group(required=True) @@ -192,17 +184,13 @@ def add_parser_args(parser): group.add_argument('-gn', '--gem-name', type=str, required=False, help='The name of the gem.') parser.add_argument('-egf', '--enabled-gem-file', type=pathlib.Path, required=False, - help='The cmake enabled_gem file in which the gem dependencies are specified.' + help='The cmake enabled_gem file in which the gem names are specified.' 'If not specified it will assume enabled_gems.cmake') - parser.add_argument('-pl', '--platforms', type=str, required=False, - default='Common', - help='Optional list of platforms this gem should be added to.' - ' Ex. --platforms Mac,Windows,Linux') parser.add_argument('-ohf', '--override-home-folder', type=pathlib.Path, required=False, help='By default the home folder is the user folder, override it to this folder.') - parser.set_defaults(func=_run_add_gem_to_project) + parser.set_defaults(func=_run_enable_gem_in_project) def add_args(subparsers) -> None: @@ -213,13 +201,13 @@ def add_args(subparsers) -> None: call add_args and execute: python o3de.py add-gem-to-project --project-path "D:/TestProject" --gem-path "D:/TestGem" :param subparsers: the caller instantiates subparsers and passes it in here """ - add_gem_project_subparser = subparsers.add_parser('add-gem-to-project') - add_parser_args(add_gem_project_subparser) + enable_gem_project_subparser = subparsers.add_parser('enable-gem') + add_parser_args(enable_gem_project_subparser) def main(): """ - Runs add_gem_project.py script as standalone script + Runs enable_gem.py script as standalone script """ # parse the command line args the_parser = argparse.ArgumentParser() diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index c3b327641c..092430500f 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -231,6 +231,11 @@ def get_gems() -> list: return list(filter(is_gem_subdirectory, external_subdirs)) if external_subdirs else [] +def get_external_subdirectories() -> list: + json_data = load_o3de_manifest() + return json_data['external_subdirectories'] + + def get_templates() -> list: json_data = load_o3de_manifest() return json_data['templates'] @@ -241,11 +246,6 @@ def get_restricted() -> list: return json_data['restricted'] -def get_external_subdirectories() -> list: - json_data = load_o3de_manifest() - return json_data['external_subdirectories'] - - def get_repos() -> list: json_data = load_o3de_manifest() return json_data['repos'] @@ -266,6 +266,13 @@ def get_engine_gems() -> list: return list(filter(is_gem_subdirectory, external_subdirs)) if external_subdirs else [] +def get_engine_external_subdirectories() -> list: + engine_path = get_this_engine_path() + engine_object = get_engine_json_data(engine_path=engine_path) + return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), + engine_object['external_subdirectories'])) if 'external_subdirectories' in engine_object else [] + + def get_engine_templates() -> list: engine_path = get_this_engine_path() engine_object = get_engine_json_data(engine_path=engine_path) @@ -280,19 +287,12 @@ def get_engine_restricted() -> list: engine_object['restricted'])) if 'restricted' in engine_object else [] -def get_engine_external_subdirectories() -> list: - engine_path = get_this_engine_path() - engine_object = get_engine_json_data(engine_path=engine_path) - return list(map(lambda rel_path: (pathlib.Path(engine_path) / rel_path).as_posix(), - engine_object['external_subdirectories'])) if 'external_subdirectories' in engine_object else [] - - # project.json queries def get_project_gems(project_path: pathlib.Path) -> list: def is_gem_subdirectory(subdir): return (pathlib.Path(subdir) / 'gem.json').exists() - external_subdirs = get_project_external_subdirectories() + external_subdirs = get_project_external_subdirectories(project_path) return list(filter(is_gem_subdirectory, external_subdirs)) if external_subdirs else [] @@ -302,26 +302,42 @@ def get_project_external_subdirectories(project_path: pathlib.Path) -> list: project_object['external_subdirectories'])) if 'external_subdirectories' in project_object else [] +# Combined manifest queries def get_all_projects() -> list: - engine_projects = get_engine_projects() - projects_data = get_projects() - projects_data.extend(engine_projects) - return projects_data + projects_data = set(get_projects()) + projects_data.update(get_engine_projects()) + return list(projects_data) -def get_all_gems() -> list: - engine_gems = get_engine_gems() - gems_data = get_gems() - gems_data.extend(engine_gems) - return gems_data +def get_all_gems(project_path: pathlib.Path = None) -> list: + gems_data = set(get_gems()) + gems_data.update(get_engine_gems()) + if project_path: + gems_data.update(get_project_gems(project_path)) + return list(gems_data) + + +def get_all_external_subdirectories(project_path: pathlib.Path = None) -> list: + external_subdirectories_data = set(get_external_subdirectories()) + external_subdirectories_data.update(get_engine_external_subdirectories()) + if project_path: + external_subdirectories_data.update(get_project_external_subdirectories(project_path)) + return list(templates_data) def get_all_templates() -> list: - engine_templates = get_engine_templates() - templates_data = get_templates() - templates_data.extend(engine_templates) - return templates_data + templates_data = set(get_templates()) + templates_data.update(get_engine_templates()) + return list(templates_data) + +def get_all_restricted() -> list: + restricted_data = set(get_restricted()) + restricted_data.update(get_engine_restricted()) + return list(gems_data) + + +# Template functions def get_project_templates(): # temporary until we have a better way to do this... maybe template_type element project_templates = [] for template in get_all_templates(): diff --git a/scripts/o3de/tests/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt index 7abc22a030..5c83f4112b 100644 --- a/scripts/o3de/tests/CMakeLists.txt +++ b/scripts/o3de/tests/CMakeLists.txt @@ -20,3 +20,10 @@ ly_add_pytest( TEST_SUITE smoke EXCLUDE_TEST_RUN_TARGET_FROM_IDE ) + +ly_add_pytest( + NAME o3de_cmake + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_cmake.py + TEST_SUITE smoke + EXCLUDE_TEST_RUN_TARGET_FROM_IDE +) diff --git a/scripts/o3de/tests/unit_test_add_remove_gem.py b/scripts/o3de/tests/unit_test_add_remove_gem.py deleted file mode 100755 index cc793bf32b..0000000000 --- a/scripts/o3de/tests/unit_test_add_remove_gem.py +++ /dev/null @@ -1,259 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -import os -import pytest - -from o3de import add_gem_project - -TEST_WITHOUT_NO_GEM_CONTENT = """ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES -) -""" - -TEST_WITHOUT_ONLY_GEM_CONTENT = """ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::TestGem -) -""" - -TEST_WITHOUT_ADDED_GEM_CONTENT = """ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::ExistingGem -) -""" - -TEST_WITH_ADDED_GEM_CONTENT = """ -# {BEGIN_LICENSE} -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# {END_LICENSE} - -set(GEM_DEPENDENCIES - Gem::TestGem - Gem::ExistingGem -) -""" - - -@pytest.mark.parametrize( - "contents, gem, expected_result, runtime_present, expect_failure", [ - pytest.param(TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", TEST_WITH_ADDED_GEM_CONTENT, True, False), - pytest.param(TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", TEST_WITH_ADDED_GEM_CONTENT, False, True), - pytest.param(TEST_WITHOUT_ADDED_GEM_CONTENT, "/TestGem", TEST_WITH_ADDED_GEM_CONTENT, True, True), - pytest.param(TEST_WITHOUT_NO_GEM_CONTENT, "TestGem", TEST_WITHOUT_ONLY_GEM_CONTENT, True, False), - ] -) -def test_add_gem_dependency(tmpdir, contents, gem, expected_result, runtime_present, expect_failure): - dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/') - os.makedirs(dev_root, exist_ok=True) - - dev_project_gem_code = f'{dev_root}/TestProject/Gem/Code' - os.makedirs(dev_project_gem_code, exist_ok=True) - - runtime_dependencies_cmake_file = f'{dev_project_gem_code}/runtime_dependencies.cmake' - if runtime_present: - if os.path.isfile(runtime_dependencies_cmake_file): - os.unlink(runtime_dependencies_cmake_file) - with open(runtime_dependencies_cmake_file, 'a') as s: - s.write(contents) - - result = add_gem_project.add_gem_dependency(runtime_dependencies_cmake_file, gem) - - if expect_failure: - assert result != 0 - else: - assert result == 0 - with open(runtime_dependencies_cmake_file, 'r') as s: - s_data = s.read() - assert s_data == expected_result - - -@pytest.mark.parametrize( - "contents, gem, expected_result, runtime_present, expect_failure", [ - pytest.param(TEST_WITH_ADDED_GEM_CONTENT, "TestGem", TEST_WITHOUT_ADDED_GEM_CONTENT, True, False), - pytest.param(TEST_WITH_ADDED_GEM_CONTENT, "TestGem", TEST_WITHOUT_ADDED_GEM_CONTENT, False, True), - pytest.param(TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", TEST_WITHOUT_ADDED_GEM_CONTENT, True, True) - ] -) -def test_remove_gem_dependency(tmpdir, contents, gem, expected_result, runtime_present, expect_failure): - dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/') - os.makedirs(dev_root, exist_ok=True) - - dev_project_gem_code = f'{dev_root}/TestProject/Gem/Code' - os.makedirs(dev_project_gem_code, exist_ok=True) - - runtime_dependencies_cmake_file = f'{dev_project_gem_code}/runtime_dependencies.cmake' - if runtime_present: - if os.path.isfile(runtime_dependencies_cmake_file): - os.unlink(runtime_dependencies_cmake_file) - with open(runtime_dependencies_cmake_file, 'a') as s: - s.write(contents) - - result = add_remove_gem.remove_gem_dependency(runtime_dependencies_cmake_file, gem) - - if expect_failure: - assert result != 0 - else: - assert result == 0 - with open(runtime_dependencies_cmake_file, 'r') as s: - s_data = s.read() - assert s_data == expected_result - - -@pytest.mark.parametrize("add," - " contents, gem, project, expected_result," - " runtime_present, tool_present," - " ask_for_runtime, ask_for_tool," - " expect_failure", [ - pytest.param(True, - TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITH_ADDED_GEM_CONTENT, - True, True, - True, True, - False), - pytest.param(True, - TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITH_ADDED_GEM_CONTENT, - True, False, - True, True, - True), - pytest.param(True, - TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITH_ADDED_GEM_CONTENT, - False, True, - True, True, - True), - pytest.param(True, - TEST_WITHOUT_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITH_ADDED_GEM_CONTENT, - False, False, - True, True, - True), - - pytest.param(False, - TEST_WITH_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITHOUT_ADDED_GEM_CONTENT, - True, True, - True, True, - False), - pytest.param(False, - TEST_WITH_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITHOUT_ADDED_GEM_CONTENT, - True, False, - True, True, - True), - pytest.param(False, - TEST_WITH_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITHOUT_ADDED_GEM_CONTENT, - False, True, - True, True, - True), - pytest.param(False, - TEST_WITH_ADDED_GEM_CONTENT, "TestGem", "TestProject", - TEST_WITHOUT_ADDED_GEM_CONTENT, - False, False, - True, True, - True) - ] - ) -def test_add_remove_gem(tmpdir, - add, - contents, gem, project, - expected_result, - runtime_present, tool_present, - ask_for_runtime, ask_for_tool, - expect_failure): - dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/') - os.makedirs(dev_root, exist_ok=True) - - dev_project_gem_code = f'{dev_root}/TestProject/Gem/Code' - os.makedirs(dev_project_gem_code, exist_ok=True) - - runtime_dependencies_cmake_file = f'{dev_project_gem_code}/runtime_dependencies.cmake' - if runtime_present: - if os.path.isfile(runtime_dependencies_cmake_file): - os.unlink(runtime_dependencies_cmake_file) - with open(runtime_dependencies_cmake_file, 'a') as s: - s.write(contents) - - tool_dependencies_cmake_file = f'{dev_project_gem_code}/tool_dependencies.cmake' - os.makedirs(dev_project_gem_code, exist_ok=True) - - if tool_present: - if os.path.isfile(tool_dependencies_cmake_file): - os.unlink(tool_dependencies_cmake_file) - with open(tool_dependencies_cmake_file, 'w') as s: - s.write(contents) - - project_folder = f'{dev_root}/TestProject' - os.makedirs(project_folder, exist_ok=True) - - gems_folder = f'{dev_root}/Gems' - os.makedirs(gems_folder, exist_ok=True) - - gem_folder = f'{gems_folder}/{gem}' - os.makedirs(gem_folder, exist_ok=True) - - result = add_remove_gem.add_remove_gem(add, dev_root, gem, project, ask_for_runtime, ask_for_tool) - - if expect_failure: - assert result != 0 - else: - assert result == 0 - if runtime_present: - with open(runtime_dependencies_cmake_file, 'r') as s: - s_data = s.read() - assert s_data == expected_result - if tool_present: - with open(tool_dependencies_cmake_file, 'r') as s: - s_data = s.read() - assert s_data == expected_result - diff --git a/scripts/o3de/tests/unit_test_cmake.py b/scripts/o3de/tests/unit_test_cmake.py new file mode 100644 index 0000000000..e5ce17dc03 --- /dev/null +++ b/scripts/o3de/tests/unit_test_cmake.py @@ -0,0 +1,69 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +import io +import json +import logging +import pytest +import pathlib +from unittest.mock import patch + +from o3de import cmake + + +class TestGetEnabledGems: + @pytest.mark.parametrize( + "enable_gems_cmake_data, expected_set", [ + pytest.param(""" + # Comment + set(ENABLED_GEMS foo bar baz) + """, set(['foo', 'bar', 'baz'])), + pytest.param(""" + # Comment + set(ENABLED_GEMS + foo + bar + baz + ) + """, set(['foo', 'bar', 'baz'])), + pytest.param(""" + # Comment + set(ENABLED_GEMS + foo + bar + baz) + """, set(['foo', 'bar', 'baz'])), + pytest.param(""" + # Comment + set(ENABLED_GEMS + foo bar + baz) + """, set(['foo', 'bar', 'baz'])), + pytest.param(""" + # Comment + set(RANDOM_VARIABLE TestGame, TestProject Test Engine) + set(ENABLED_GEMS HelloWorld IceCream + foo + baz bar + baz baz baz baz baz morebaz lessbaz + ) + Random Text + """, set(['HelloWorld', 'IceCream', 'foo', 'bar', 'baz', 'morebaz', 'lessbaz'])), + ] + ) + def test_get_enabled_gems(self, enable_gems_cmake_data, expected_set): + enabled_gems_set = set() + with patch('pathlib.Path.resolve', return_value=pathlib.Path('enabled_gems.cmake')) as pathlib_is_resolve_mock,\ + patch('pathlib.Path.is_file', return_value=True) as pathlib_is_file_mock,\ + patch('pathlib.Path.open', return_value=io.StringIO(enable_gems_cmake_data)) as pathlib_open_mock: + enabled_gems_set = cmake.get_enabled_gems(pathlib.Path('enabled_gems.cmake')) + + assert enabled_gems_set == expected_set diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index d062343662..f9f40aa4bf 100755 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -29,7 +29,7 @@ executable_path = '' logger = logging.getLogger() logger.setLevel(logging.INFO) -from o3de import add_gem_project, cmake, engine_template, manifest, register, remove_gem_project +from o3de import disable_gem, enable_gem, cmake, engine_template, manifest, register o3de_folder = manifest.get_o3de_folder() o3de_logs_folder = manifest.get_o3de_logs_folder() @@ -671,8 +671,8 @@ class ProjectManagerDialog(QObject): gem_paths = manifest.get_all_gems() for gem_target in self.manage_project_gem_targets_get_selected_available_gems(): for gem_path in gem_paths: - add_gem_project.add_gem_to_project(gem_path=gem_path, - project_path=self.get_selected_project_path()) + enable_gem.enable_gem_in_project(gem_path=gem_path, + project_path=self.get_selected_project_path()) self.refresh_project_gem_targets_available_list() self.refresh_project_gem_targets_enabled_list() return @@ -683,8 +683,8 @@ class ProjectManagerDialog(QObject): gem_paths = manifest.get_all_gems() for gem_target in self.manage_project_gem_targets_get_selected_enabled_gems(): for gem_path in gem_paths: - remove_gem_project.remove_gem_from_project(gem_path=gem_path, - project_path=self.get_selected_project_path()) + disable_gem.disable_gem_in_project(gem_path=gem_path, + project_path=self.get_selected_project_path()) self.refresh_project_gem_targets_available_list() self.refresh_project_gem_targets_enabled_list() return From d6cfa6833375b76a24f8f53b3b6805aec41ba739 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 15:04:17 -0700 Subject: [PATCH 119/140] Reverting error check and comment --- cmake/LYWrappers.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index bef3b25328..48423f3575 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -692,7 +692,9 @@ endfunction() # given a target name, returns the "real" name of the target if its an alias. # this function recursively de-aliases function(ly_de_alias_target target_name output_variable_name) + # its not okay to call get_target_property on a non-existent target if (NOT TARGET ${target_name}) + message(FATAL_ERROR "ly_de_alias_target called on non-existent target: ${target_name}") endif() while(target_name) From 1c52147c3ad05fb3845868e335beb5da2ddfeda1 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 17:12:28 -0500 Subject: [PATCH 120/140] Fixed path case issue in the declaration of the path to the UiBasics gem --- engine.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine.json b/engine.json index 7662d4f034..09bb3f5ff6 100644 --- a/engine.json +++ b/engine.json @@ -81,7 +81,7 @@ "Gems/TextureAtlas", "Gems/TickBusOrderViewer", "Gems/Twitch", - "Gems/UIBasics", + "Gems/UiBasics", "Gems/Vegetation", "Gems/Vegetation_Gem_Assets", "Gems/VideoPlaybackFramework", From c67cd2dc4e25fa3f3890d4937d57327f537b68a0 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 17:35:08 -0500 Subject: [PATCH 121/140] Renaming the TargetCMakeLists.txt.in to InstalledTarget.in to get avoid it being picked up by the CopyrightValidator --- cmake/Platform/Common/Install_common.cmake | 2 +- cmake/install/{TargetCMakeLists.txt.in => InstalledTarget.in} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename cmake/install/{TargetCMakeLists.txt.in => InstalledTarget.in} (100%) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 939f523d75..b18aed6fb4 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -182,7 +182,7 @@ set_property(TARGET ${TARGET_NAME} ) # Since a CMakeLists.txt could contain multiple targets, we generate it in a folder per target - file(READ ${LY_ROOT_FOLDER}/cmake/install/TargetCMakeLists.txt.in target_cmakelists_template) + file(READ ${LY_ROOT_FOLDER}/cmake/install/InstalledTarget.in target_cmakelists_template) string(CONFIGURE ${target_cmakelists_template} output_cmakelists_data @ONLY) set(${OUTPUT_CONFIGURED_TARGET} ${output_cmakelists_data} PARENT_SCOPE) endfunction() diff --git a/cmake/install/TargetCMakeLists.txt.in b/cmake/install/InstalledTarget.in similarity index 100% rename from cmake/install/TargetCMakeLists.txt.in rename to cmake/install/InstalledTarget.in From 166db0b0c60dd80e833c4d7e80b75f0e4f8a7532 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 16:09:12 -0700 Subject: [PATCH 122/140] Android fix for FastNoise --- Gems/FastNoise/Code/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/FastNoise/Code/CMakeLists.txt b/Gems/FastNoise/Code/CMakeLists.txt index 8c12dcf5be..ae42af771a 100644 --- a/Gems/FastNoise/Code/CMakeLists.txt +++ b/Gems/FastNoise/Code/CMakeLists.txt @@ -134,6 +134,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) PRIVATE AZ::AzTest Gem::FastNoise.Static + Gem::LmbrCentral ) ly_add_googletest( NAME Gem::FastNoise.Tests From da147f273dcbef1b84e8d94c28e7656e385cd631 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 18:41:28 -0500 Subject: [PATCH 123/140] Adding VERBOSE messages to the SettingsRegistry.cmake 'ly_get_gem_load_dependencies()' function which logs the gem target to it's load dependencies --- cmake/SettingsRegistry.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index c6ddbf810b..6f929d06e1 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -74,6 +74,7 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) ly_get_gem_load_dependencies(dependencies ${dealias_load_dependency}) list(APPEND all_gem_load_dependencies ${dependencies}) list(APPEND all_gem_load_dependencies ${dealias_load_dependency}) + message(VERBOSE "Load Dependency \"${dealias_load_dependency}\" has load dependencies of: ${dependencies}") endif() endforeach() endif() @@ -81,6 +82,7 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) list(REMOVE_DUPLICATES all_gem_load_dependencies) set_property(GLOBAL PROPERTY LY_GEM_LOAD_DEPENDENCIES_${ly_TARGET} "${all_gem_load_dependencies}") set(${ly_GEM_LOAD_DEPENDENCIES} ${all_gem_load_dependencies} PARENT_SCOPE) + message(VERBOSE "Gem Target \"${ly_TARGET}\" has load dependencies of: ${all_gem_load_dependencies}") endfunction() #!ly_get_gem_module_root: Uses the supplied gem_target to lookup the nearest gem.json file above the SOURCE_DIR From 62b6cfac421fe9c1f1dac60c5a1a8ae97b0f3741 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 16:58:06 -0700 Subject: [PATCH 124/140] letting users pass CMAKE_MODULE_PATH to find the engine --- Templates/DefaultProject/Template/EngineFinder.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Templates/DefaultProject/Template/EngineFinder.cmake b/Templates/DefaultProject/Template/EngineFinder.cmake index a7dbf671fd..fbbe3d8cfe 100644 --- a/Templates/DefaultProject/Template/EngineFinder.cmake +++ b/Templates/DefaultProject/Template/EngineFinder.cmake @@ -61,5 +61,8 @@ if(EXISTS ${manifest_path}) endif() endforeach() else() - message(FATAL_ERROR "Engine registration is required before configuring a project. Please register an engine by running 'scripts/o3de register --this-engine'") + # If the user is passing CMAKE_MODULE_PATH we assume thats where we will find the engine + if(NOT CMAKE_MODULE_PATH) + message(FATAL_ERROR "Engine registration is required before configuring a project. Please register an engine by running 'scripts/o3de register --this-engine'") + endif() endif() From d1a2eed40c37df587ee80bde6ddcd2b5ee7c3ed0 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 17:26:25 -0700 Subject: [PATCH 125/140] Fix identiation issues --- cmake/LYWrappers.cmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 48423f3575..d7f88f12ec 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -88,8 +88,8 @@ function(ly_add_target) endif() if(NOT ly_add_target_IMPORTED AND NOT ly_add_target_HEADERONLY) if(NOT ly_add_target_FILES_CMAKE) - message(FATAL_ERROR "You must provide a list of _files.cmake files for the target") - endif() + message(FATAL_ERROR "You must provide a list of _files.cmake files for the target") + endif() endif() # If the GEM_MODULE tag is passed set the normal MODULE argument @@ -127,7 +127,7 @@ function(ly_add_target) set(linking_options INTERFACE) set(target_type_options INTERFACE) set(linking_count "${linking_count}1") - endif() + endif() if(ly_add_target_EXECUTABLE) set(linking_options EXECUTABLE) set(linking_count "${linking_count}1") From 4a15f55f789a8c3e9cae506e43b4482c20b303c7 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 17:37:59 -0700 Subject: [PATCH 126/140] Updating AutomatedTesting/EngineFinder.cmake --- AutomatedTesting/EngineFinder.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AutomatedTesting/EngineFinder.cmake b/AutomatedTesting/EngineFinder.cmake index a7dbf671fd..fbbe3d8cfe 100644 --- a/AutomatedTesting/EngineFinder.cmake +++ b/AutomatedTesting/EngineFinder.cmake @@ -61,5 +61,8 @@ if(EXISTS ${manifest_path}) endif() endforeach() else() - message(FATAL_ERROR "Engine registration is required before configuring a project. Please register an engine by running 'scripts/o3de register --this-engine'") + # If the user is passing CMAKE_MODULE_PATH we assume thats where we will find the engine + if(NOT CMAKE_MODULE_PATH) + message(FATAL_ERROR "Engine registration is required before configuring a project. Please register an engine by running 'scripts/o3de register --this-engine'") + endif() endif() From 32b620501dfb3cb2c1d875cb3fac6281ae511843 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 18:33:28 -0700 Subject: [PATCH 127/140] Fix some cross dependencies between client and non-client gems --- Gems/LyShineExamples/Code/CMakeLists.txt | 16 ++++++++-------- Gems/ScriptCanvasPhysics/Code/CMakeLists.txt | 16 +++++++--------- Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 4 ++-- cmake/SettingsRegistry.cmake | 2 +- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Gems/LyShineExamples/Code/CMakeLists.txt b/Gems/LyShineExamples/Code/CMakeLists.txt index ce420cbd30..04812ec722 100644 --- a/Gems/LyShineExamples/Code/CMakeLists.txt +++ b/Gems/LyShineExamples/Code/CMakeLists.txt @@ -20,9 +20,10 @@ ly_add_target( PUBLIC Include BUILD_DEPENDENCIES + PRIVATE + Gem::LmbrCentral PUBLIC Legacy::CryCommon - Gem::LmbrCentral Gem::LyShine.Static ) @@ -39,13 +40,12 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::LyShineExamples.Static - RUNTIME_DEPENDENCIES - Gem::LmbrCentral ) -# if enabled, LyShineExamples is used by all kinds of applications -ly_create_alias(NAME LyShineExamples.Builders NAMESPACE Gem TARGETS Gem::LyShineExamples) -ly_create_alias(NAME LyShineExamples.Tools NAMESPACE Gem TARGETS Gem::LyShineExamples) -ly_create_alias(NAME LyShineExamples.Clients NAMESPACE Gem TARGETS Gem::LyShineExamples) -ly_create_alias(NAME LyShineExamples.Servers NAMESPACE Gem TARGETS Gem::LyShineExamples) +# if enabled, LyShineExamples is used by all kinds of applications, however, the dependency to LmbrCentral is different +# per application type +ly_create_alias(NAME LyShineExamples.Builders NAMESPACE Gem TARGETS Gem::LyShineExamples Gem::LmbrCentral.Editor) +ly_create_alias(NAME LyShineExamples.Tools NAMESPACE Gem TARGETS Gem::LyShineExamples Gem::LmbrCentral.Editor) +ly_create_alias(NAME LyShineExamples.Clients NAMESPACE Gem TARGETS Gem::LyShineExamples Gem::LmbrCentral) +ly_create_alias(NAME LyShineExamples.Servers NAMESPACE Gem TARGETS Gem::LyShineExamples Gem::LmbrCentral) diff --git a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt index 73ec851b70..c97dba180a 100644 --- a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt @@ -18,10 +18,9 @@ ly_add_target( PRIVATE Source BUILD_DEPENDENCIES - PUBLIC - Gem::ScriptCanvas PRIVATE Legacy::CryCommon + Gem::ScriptCanvas ) ly_add_target( @@ -36,15 +35,14 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::ScriptCanvasPhysics.Static - RUNTIME_DEPENDENCIES - Gem::ScriptCanvas ) -# By default, the above module is used by all application types -ly_create_alias(NAME ScriptCanvasPhysics.Clients NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics) -ly_create_alias(NAME ScriptCanvasPhysics.Servers NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics) -ly_create_alias(NAME ScriptCanvasPhysics.Tools NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics) -ly_create_alias(NAME ScriptCanvasPhysics.Builders NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics) +# By default, the above module is used by all application types, however, the module depends at runtime to ScriptCanvas +# and the dependency needs to be different per application type +ly_create_alias(NAME ScriptCanvasPhysics.Clients NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics Gem::ScriptCanvas) +ly_create_alias(NAME ScriptCanvasPhysics.Servers NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics Gem::ScriptCanvas) +ly_create_alias(NAME ScriptCanvasPhysics.Tools NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics Gem::ScriptCanvas.Editor) +ly_create_alias(NAME ScriptCanvasPhysics.Builders NAMESPACE Gem TARGETS Gem::ScriptCanvasPhysics Gem::ScriptCanvas.Editor) ################################################################################ # Tests diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index 5641813a43..c6264e2fef 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -34,7 +34,7 @@ ly_add_target( Gem::ScriptCanvas Gem::ScriptCanvasEditor Gem::GraphCanvasWidgets - Gem::ScriptEvents + Gem::ScriptEvents.Editor PRIVATE AZ::AzCore AZ::AzFramework @@ -46,7 +46,7 @@ ly_add_target( *.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Header.jinja,$path/$fileprefix.generated.h *.ScriptCanvasNodeable.xml,ScriptCanvasNodeable_Source.jinja,$path/$fileprefix.generated.cpp RUNTIME_DEPENDENCIES - Gem::ScriptCanvas + Gem::ScriptCanvas.Editor Gem::ScriptCanvasEditor Gem::GraphCanvasWidgets Gem::ScriptEvents diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index 6f929d06e1..4d932601b4 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -74,7 +74,6 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) ly_get_gem_load_dependencies(dependencies ${dealias_load_dependency}) list(APPEND all_gem_load_dependencies ${dependencies}) list(APPEND all_gem_load_dependencies ${dealias_load_dependency}) - message(VERBOSE "Load Dependency \"${dealias_load_dependency}\" has load dependencies of: ${dependencies}") endif() endforeach() endif() @@ -83,6 +82,7 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) set_property(GLOBAL PROPERTY LY_GEM_LOAD_DEPENDENCIES_${ly_TARGET} "${all_gem_load_dependencies}") set(${ly_GEM_LOAD_DEPENDENCIES} ${all_gem_load_dependencies} PARENT_SCOPE) message(VERBOSE "Gem Target \"${ly_TARGET}\" has load dependencies of: ${all_gem_load_dependencies}") + endfunction() #!ly_get_gem_module_root: Uses the supplied gem_target to lookup the nearest gem.json file above the SOURCE_DIR From 639240576f9d696cba04547831473c7bb1f181d5 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 18:37:34 -0700 Subject: [PATCH 128/140] Adding alias for the project gem so it gets loaded --- AutomatedTesting/Gem/Code/CMakeLists.txt | 6 ++++++ .../DefaultProject/Template/Code/CMakeLists.txt | 12 +++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/AutomatedTesting/Gem/Code/CMakeLists.txt b/AutomatedTesting/Gem/Code/CMakeLists.txt index 9315bf8397..548aa51ad1 100644 --- a/AutomatedTesting/Gem/Code/CMakeLists.txt +++ b/AutomatedTesting/Gem/Code/CMakeLists.txt @@ -28,6 +28,12 @@ ly_add_target( Gem::Atom_AtomBridge.Static ) +# if enabled, AutomatedTesting is used by all kinds of applications +ly_create_alias(NAME AutomatedTesting.Builders NAMESPACE Gem TARGETS Gem::AutomatedTesting) +ly_create_alias(NAME AutomatedTesting.Tools NAMESPACE Gem TARGETS Gem::AutomatedTesting) +ly_create_alias(NAME AutomatedTesting.Clients NAMESPACE Gem TARGETS Gem::AutomatedTesting) +ly_create_alias(NAME AutomatedTesting.Servers NAMESPACE Gem TARGETS Gem::AutomatedTesting) + ################################################################################ # Gem dependencies ################################################################################ diff --git a/Templates/DefaultProject/Template/Code/CMakeLists.txt b/Templates/DefaultProject/Template/Code/CMakeLists.txt index b116fb2044..43459b1606 100644 --- a/Templates/DefaultProject/Template/Code/CMakeLists.txt +++ b/Templates/DefaultProject/Template/Code/CMakeLists.txt @@ -33,7 +33,7 @@ endif() # in ${pal_dir}/${NameLower}_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake ly_add_target( NAME ${Name}.Static STATIC - NAMESPACE Project + NAMESPACE Gem FILES_CMAKE ${NameLower}_files.cmake ${pal_dir}/${NameLower}_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake @@ -48,7 +48,7 @@ ly_add_target( ly_add_target( NAME ${Name} ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} - NAMESPACE Project + NAMESPACE Gem FILES_CMAKE ${NameLower}_shared_files.cmake ${pal_dir}/${NameLower}_shared_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake @@ -57,10 +57,16 @@ ly_add_target( Include BUILD_DEPENDENCIES PRIVATE - Project::${Name}.Static + Gem::${Name}.Static AZ::AzCore ) +# if enabled, ${Name} is used by all kinds of applications +ly_create_alias(NAME ${Name}.Builders NAMESPACE Gem TARGETS Gem::${Name}) +ly_create_alias(NAME ${Name}.Tools NAMESPACE Gem TARGETS Gem::${Name}) +ly_create_alias(NAME ${Name}.Clients NAMESPACE Gem TARGETS Gem::${Name}) +ly_create_alias(NAME ${Name}.Servers NAMESPACE Gem TARGETS Gem::${Name}) + ################################################################################ # Gem dependencies ################################################################################ From 68e2fb83dd8101923b3c85c352808ece9c3db32b Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 18:54:22 -0700 Subject: [PATCH 129/140] More dependency fixes for linux builds --- Gems/LyShineExamples/Code/CMakeLists.txt | 1 + Gems/ScriptCanvasPhysics/Code/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Gems/LyShineExamples/Code/CMakeLists.txt b/Gems/LyShineExamples/Code/CMakeLists.txt index 04812ec722..96c41bbb64 100644 --- a/Gems/LyShineExamples/Code/CMakeLists.txt +++ b/Gems/LyShineExamples/Code/CMakeLists.txt @@ -40,6 +40,7 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::LyShineExamples.Static + Gem::LmbrCentral ) # if enabled, LyShineExamples is used by all kinds of applications, however, the dependency to LmbrCentral is different diff --git a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt index c97dba180a..107db38f5e 100644 --- a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt @@ -35,6 +35,7 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::ScriptCanvasPhysics.Static + Gem::ScriptCanvas ) # By default, the above module is used by all application types, however, the module depends at runtime to ScriptCanvas @@ -63,6 +64,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest Legacy::CryCommon Gem::ScriptCanvasPhysics.Static + Gem::ScriptCanvas ) ly_add_googletest( NAME Gem::ScriptCanvasPhysics.Tests From 87721cae55fd167724ddace87b62b9fc6a853bed Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 20:56:03 -0500 Subject: [PATCH 130/140] Removed the ability to run download command from the o3de python package without user intervention --- scripts/o3de.py | 5 +---- scripts/o3de/o3de/download.py | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/o3de.py b/scripts/o3de.py index 24ba862529..8d7532878c 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -31,7 +31,7 @@ def add_args(parser, subparsers) -> None: o3de_package_dir = (script_dir / 'o3de').resolve() # add the scripts/o3de directory to the front of the sys.path sys.path.insert(0, str(o3de_package_dir)) - from o3de import engine_template, global_project, register, print_registration, get_registration, download, \ + from o3de import engine_template, global_project, register, print_registration, get_registration, \ enable_gem, disable_gem, sha256 # Remove the temporarily added path sys.path = sys.path[1:] @@ -50,9 +50,6 @@ def add_args(parser, subparsers) -> None: # get-registered get_registration.add_args(subparsers) - # download - download.add_args(subparsers) - # add a gem to a project enable_gem.add_args(subparsers) diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index 1dbb584c92..6f1b82e754 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -237,5 +237,4 @@ def main(): sys.exit(ret) -if __name__ == "__main__": - main() +# Do not allow running the download.py script as a standalone script until it is reviewed by app-sec From 425cb3e2fa4065c24661c4bfccf598c177e61f73 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 19:18:42 -0700 Subject: [PATCH 131/140] Aaaaannnddd another dependency fix --- Gems/ScriptCanvasTesting/Code/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index c6264e2fef..76a549d6b9 100644 --- a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt @@ -109,6 +109,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzFramework AZ::AzToolsFramework Gem::ScriptCanvasTesting.Editor.Static + Gem::ScriptCanvas.Editor RUNTIME_DEPENDENCIES Gem::GraphCanvas.Editor Gem::ScriptCanvas.Editor From 74464afbf3a31ea0e82c766444fb34e5bd4c451a Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 21:20:19 -0500 Subject: [PATCH 132/140] Updated the global_project.py script to be able to specify and output path when setting the global project path Also updated that script to support an input path when reading the global project path. Added a unit test for the global_projecy.py "set-global-project" command --- scripts/o3de/o3de/disable_gem.py | 2 +- scripts/o3de/o3de/enable_gem.py | 2 +- scripts/o3de/o3de/global_project.py | 221 +++++++++++------- scripts/o3de/o3de/manifest.py | 12 +- scripts/o3de/o3de/register.py | 8 +- scripts/o3de/o3de/sha256.py | 2 +- scripts/o3de/tests/CMakeLists.txt | 7 + scripts/o3de/tests/unit_global_project.py | 40 ++++ .../o3de/tests/unit_test_current_project.py | 102 -------- 9 files changed, 192 insertions(+), 204 deletions(-) create mode 100644 scripts/o3de/tests/unit_global_project.py delete mode 100755 scripts/o3de/tests/unit_test_current_project.py diff --git a/scripts/o3de/o3de/disable_gem.py b/scripts/o3de/o3de/disable_gem.py index 6c466c3631..61d71445f0 100644 --- a/scripts/o3de/o3de/disable_gem.py +++ b/scripts/o3de/o3de/disable_gem.py @@ -83,7 +83,7 @@ def disable_gem_in_project(gem_name: str = None, 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.home() / ".o3de/manifest.json")}, engine.json') + f' {str(pathlib.Path("~/.o3de/o3de_manifest.json").expanduser())}, engine.json') return 1 project_path = pathlib.Path(project_path).resolve() diff --git a/scripts/o3de/o3de/enable_gem.py b/scripts/o3de/o3de/enable_gem.py index 73fc2ea3cf..0dee01e05e 100644 --- a/scripts/o3de/o3de/enable_gem.py +++ b/scripts/o3de/o3de/enable_gem.py @@ -117,7 +117,7 @@ def enable_gem_in_project(gem_name: str = None, gem_path = manifest.get_registered(gem_name=gem_name) if not gem_path: logger.error(f'Unable to locate gem path from the registered manifest.json files:' - f' {str(pathlib.Path.home() / ".o3de/manifest.json")},' + f' {str(pathlib.Path( "~/.o3de/o3de_manifest.json").expanduser())},' f' {project_path / "project.json"}, engine.json') return 1 diff --git a/scripts/o3de/o3de/global_project.py b/scripts/o3de/o3de/global_project.py index 787e676a7e..d165510250 100644 --- a/scripts/o3de/o3de/global_project.py +++ b/scripts/o3de/o3de/global_project.py @@ -16,94 +16,122 @@ import sys import re import pathlib import json -from o3de import manifest + +from o3de import manifest, validation logger = logging.getLogger() logging.basicConfig() +DEFAULT_BOOTSTRAP_SETREG = pathlib.Path('~/.o3de/Registry/bootstrap.setreg').expanduser() +PROJECT_PATH_KEY = ('Amazon', 'AzCore', 'Bootstrap', 'project_path') -def set_global_project(project_name: str or None, - project_path: str or pathlib.Path or None) -> int: +def get_json_data(input_path: pathlib.Path): + setreg_json_data = {} + # If the output_path exist validate that it is a valid json file + if input_path.is_file(): + with input_path.open('r') as f: + try: + setreg_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.error(f'The file: {input_path} is not a valid json file: {str(e)}') + + return setreg_json_data + +def set_global_project(output_path: pathlib.Path, + project_name: str = None, + project_path: pathlib.Path = None, + force: bool = False) -> int: """ - set what the current project is - :param project_name: the name of the project you want to set, resolves project_path - :param project_path: the path of the project you want to set + Adds a project path the a settings registry file in the users ~/.o3de/Registry directory + :param output_path: path to .setreg file to store project_path value into + :param project_name: name of the project to lookup path for + :param project_path: path to the project to add to .setreg file + :param force: if set, the project path will be set within the .setreg file regardless of if the path doesn't exist :return: 0 for success or non 0 failure code """ - if project_path and project_name: - logger.error(f'Project Name and Project Path provided, these are mutually exclusive.') - return 1 - + # we need either a project name or path if not project_name and not project_path: - logger.error('Must specify either a Project name or Project Path.') + logger.error(f'Must either specify a Project path or Project Name.') return 1 + # if project name resolve it into a path if project_name and not project_path: project_path = manifest.get_registered(project_name=project_name) if not project_path: - logger.error(f'Project Path {project_path} has not been registered.') + logger.error( + f'The project name has been supplied. Unable to locate project path from the registered manifest.json files:' + f' {str(pathlib.Path("~/.o3de/o3de_manifest.json").expanduser())}, engine.json\n' + 'A The --project-path parameter can be used directly to skip checking the manifest') return 1 - project_path = pathlib.Path(project_path).resolve() + # Only perform project path validations when force=False + if not force: + if not project_path.is_dir(): + logger.error(f'Project path {project_path} is not a folder.') + return 1 - bootstrap_setreg_file = manifest.get_o3de_registry_folder() / 'bootstrap.setreg' - if bootstrap_setreg_file.is_file(): - with bootstrap_setreg_file.open('r') as f: + # Validate that the supplied path points contains a valid project.json + if not validation.valid_o3de_project_json(project_path / 'project.json'): + logger.error(f'The supplied project path does not contain a valid project.json.\n' + f'The Path will not be set') + return 1 + + # If the output_path exist validate that it is a valid json file and read it's json data + setreg_json_data = get_json_data(output_path) + if output_path.is_file(): + with output_path.open('r') as f: try: - json_data = json.load(f) - except json.JSONDecodeError as e: - logger.error(f'Bootstrap.setreg failed to load: {str(e)}') - else: - try: - json_data["Amazon"]["AzCore"]["Bootstrap"]["project_path"] = project_path - except KeyError as e: - logger.error(f'Bootstrap.setreg failed to load: {str(e)}') - else: - try: - os.unlink(bootstrap_setreg_file) - except OSError as e: - logger.error(f'Failed to unlink bootstrap file {bootstrap_setreg_file}: {str(e)}') - return 1 - else: - json_data = {} - json_data.update({"Amazon":{"AzCore":{"Bootstrap":{"project_path":project_path.as_posix()}}}}) + setreg_json_data = json.load(f) + except (json.JSONDecodeError) as e: + logger.error(f'The output file: {output_path} is not a valid json file: {str(e)}') + return 1 - with bootstrap_setreg_file.open('w') as s: - s.write(json.dumps(json_data, indent=4)) + # Add a json dictionary that will be merged with any existing json data from the .setreg file + merge_json_data = {} + json_object_iter = merge_json_data + for json_key in PROJECT_PATH_KEY[:-1]: + # Add the parent json object for the key to update + json_object_iter = json_object_iter.setdefault(json_key, {}) + + # Set the project path value here + json_object_iter[PROJECT_PATH_KEY[-1]] = project_path.as_posix() + setreg_json_data.update(merge_json_data) + + # Create the parent directories + if output_path.parent: + output_path.parent.mkdir(parents=True, exist_ok=True) + try: + with output_path.open('w') as s: + s.write(json.dumps(setreg_json_data, indent=4) + '\n') + except OSError as e: + logger.error(f'Failed to write project path {project_path} to file {output_path}: {str(e)}') + return 1 return 0 -def get_global_project() -> pathlib.Path or None: +def get_global_project(input_path: pathlib.Path) -> pathlib.Path or None: """ - get what the current project set is + Retrieves the /Amazon/AzCore/Bootstrap/project_path key from the supplied file path :return: project_path or None on failure """ - bootstrap_setreg_file = manifest.get_o3de_registry_folder() / 'bootstrap.setreg' - if not bootstrap_setreg_file.is_file(): - logger.error(f'Bootstrap.setreg file {bootstrap_setreg_file} does not exist.') - return None + setreg_json_data = get_json_data(input_path) - with bootstrap_setreg_file.open('r') as f: - try: - json_data = json.load(f) - except json.JSONDecodeError as e: - logger.error(f'Bootstrap.setreg failed to load: {str(e)}') - else: - try: - project_path = json_data["Amazon"]["AzCore"]["Bootstrap"]["project_path"] - except KeyError as e: - logger.error(f'Bootstrap.setreg cannot find Amazon:AzCore:Bootstrap:project_path: {str(e)}') - else: - return pathlib.Path(project_path).resolve() + try: + # Iterate over each element of the tuple and read the json key from each successive json object + json_object_iter = setreg_json_data + for json_key in PROJECT_PATH_KEY: + json_object_iter = json_object_iter[json_key] + except KeyError as e: + logger.error(f'Cannot read key /{"/".join(PROJECT_PATH_KEY)} from file {input_path.as_posix()}: {str(e)}') + else: + project_path = json_object_iter + return pathlib.Path(project_path).resolve() return None def _run_get_global_project(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder - - project_path = get_global_project() + project_path = get_global_project(args.input_path) if project_path: print(project_path.as_posix()) return 0 @@ -111,51 +139,66 @@ def _run_get_global_project(args: argparse) -> int: def _run_set_global_project(args: argparse) -> int: - if args.override_home_folder: - manifest.override_home_folder = args.override_home_folder + return set_global_project(args.output_path, + args.project_name, + args.project_path, + args.force) - return set_global_project(args.project_name, - args.project_path) +def add_parser_args(get_project_parser, set_project_parser): + """ + add_parser_args is called to add arguments to each command such that it can be + invoked locally or added by a central python file. + Ex. Directly run from this file alone with: python global_project.py --project-path "D:/TestProject" + :param parser: the caller passes an argparse parser like instance to this method + """ + + # get-current-project + get_project_parser.add_argument('-i', '--input-path', type=pathlib.Path, required=False, default=DEFAULT_BOOTSTRAP_SETREG, + help=f'Optional path to file to read /{"/".join(PROJECT_PATH_KEY)} key from.' + f' If not supplied, then {DEFAULT_BOOTSTRAP_SETREG} is used instead') + get_project_parser.set_defaults(func=_run_get_global_project) + + # set-current-project + group = set_project_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.') + set_project_parser.add_argument('-o', '--output-path', type=pathlib.Path, required=False, + default=DEFAULT_BOOTSTRAP_SETREG, + help=f'Optional path to output file to write project_path key to. ' + f'If not supplied, then {DEFAULT_BOOTSTRAP_SETREG} is used instead') + set_project_parser.add_argument('-f', '--force', action='store_true', default=False, + help=f'Force the setting of the project path in the supplied setreg file') + set_project_parser.set_defaults(func=_run_set_global_project) def add_args(subparsers) -> None: """ - add_args is called to add expected parser arguments and subparsers arguments to each command such that it can be - invoked locally or aggregated by a central python file. - Ex. Directly run from this file alone with: python global_project.py set_global_project --project-name TestProject - OR - o3de.py can aggregate commands by importing global_project, call add_args and - execute: python o3de.py set_global_project --project-path C:/TestProject + add_args is called to add subparsers arguments to each command such that it can be + a central python file such as o3de.py. + It can be run from the o3de.py script as follows + call add_args and execute: python o3de.py set-global-project --project-path "D:/TestProject" :param subparsers: the caller instantiates subparsers and passes it in here """ - get_global_project_subparser = subparsers.add_parser('get-global-project') - get_global_project_subparser.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.') - - get_global_project_subparser.set_defaults(func=_run_get_global_project) - - set_global_project_subparser = subparsers.add_parser('set-global-project') - group = set_global_project_subparser.add_mutually_exclusive_group(required=True) - group.add_argument('-pn', '--project-name', required=False, - help='The name of the project. If supplied this will resolve the --project-path.') - group.add_argument('-pp', '--project-path', required=False, - help='The path to the project') - - set_global_project_subparser.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.') - - set_global_project_subparser.set_defaults(func=_run_set_global_project) + get_project_subparser = subparsers.add_parser('get-global-project') + set_project_subparser = subparsers.add_parser('set-global-project') + add_parser_args(get_project_subparser, set_project_subparser) -if __name__ == "__main__": +def main(): + """ + Runs this script as standalone script + """ # parse the command line args the_parser = argparse.ArgumentParser() # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help', dest='command', required=True) + project_subparsers = the_parser.add_subparsers(help="Commands for modifying the project path in the user's home" + " setreg files") # add args to the parser - add_args(the_subparsers) + add_args(project_subparsers) # parse args the_args = the_parser.parse_args() @@ -165,3 +208,7 @@ if __name__ == "__main__": # return sys.exit(ret) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index 092430500f..9436e1dd29 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -142,7 +142,7 @@ def get_o3de_manifest() -> pathlib.Path: with default_restricted_folder_json.open('w') as s: restricted_json_data = {} restricted_json_data.update({'restricted_name': 'o3de'}) - s.write(json.dumps(restricted_json_data, indent=4)) + s.write(json.dumps(restricted_json_data, indent=4) + '\n') json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()}) default_projects_restricted_folder_json = default_projects_restricted_folder / 'restricted.json' @@ -150,24 +150,24 @@ def get_o3de_manifest() -> pathlib.Path: with default_projects_restricted_folder_json.open('w') as s: restricted_json_data = {} restricted_json_data.update({'restricted_name': 'projects'}) - s.write(json.dumps(restricted_json_data, indent=4)) + s.write(json.dumps(restricted_json_data, indent=4) + '\n') default_gems_restricted_folder_json = default_gems_restricted_folder / 'restricted.json' if not default_gems_restricted_folder_json.is_file(): with default_gems_restricted_folder_json.open('w') as s: restricted_json_data = {} restricted_json_data.update({'restricted_name': 'gems'}) - s.write(json.dumps(restricted_json_data, indent=4)) + s.write(json.dumps(restricted_json_data, indent=4) + '\n') default_templates_restricted_folder_json = default_templates_restricted_folder / 'restricted.json' if not default_templates_restricted_folder_json.is_file(): with default_templates_restricted_folder_json.open('w') as s: restricted_json_data = {} restricted_json_data.update({'restricted_name': 'templates'}) - s.write(json.dumps(restricted_json_data, indent=4)) + s.write(json.dumps(restricted_json_data, indent=4) + '\n') with manifest_path.open('w') as s: - s.write(json.dumps(json_data, indent=4)) + s.write(json.dumps(json_data, indent=4) + '\n') return manifest_path @@ -201,7 +201,7 @@ def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> N manifest_path = get_o3de_manifest() with manifest_path.open('w') as s: try: - s.write(json.dumps(json_data, indent=4)) + s.write(json.dumps(json_data, indent=4) + '\n') except OSError as e: logger.error(f'Manifest json failed to save: {str(e)}') diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 1b30448db9..68575488dc 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -410,12 +410,8 @@ def register_project_path(json_data: dict, if update_project_json: project_json_data['engine'] = this_engine_json['engine_name'] utils.backup_file(project_json) - with project_json.open('w') as s: - try: - s.write(json.dumps(project_json_data, indent=4)) - except OSError as e: - logger.error(f'Project json failed to save: {str(e)}') - return 1 + if not manifest.save_o3de_manifest(project_json_data, project_path): + return 1 return 0 diff --git a/scripts/o3de/o3de/sha256.py b/scripts/o3de/o3de/sha256.py index bbec7696d6..db0a1fe834 100644 --- a/scripts/o3de/o3de/sha256.py +++ b/scripts/o3de/o3de/sha256.py @@ -51,7 +51,7 @@ def sha256(file_path: str or pathlib.Path, utils.backup_file(json_path) with json_path.open('w') as s: try: - s.write(json.dumps(json_data, indent=4)) + s.write(json.dumps(json_data, indent=4) + '\n') except OSError as e: logger.error(f'Failed to write Json path {json_path}: {str(e)}') return 1 diff --git a/scripts/o3de/tests/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt index 5c83f4112b..0526c7740d 100644 --- a/scripts/o3de/tests/CMakeLists.txt +++ b/scripts/o3de/tests/CMakeLists.txt @@ -27,3 +27,10 @@ ly_add_pytest( TEST_SUITE smoke EXCLUDE_TEST_RUN_TARGET_FROM_IDE ) + +ly_add_pytest( + NAME o3de_global_project + PATH ${CMAKE_CURRENT_LIST_DIR}/unit_test_global_project.py + TEST_SUITE smoke + EXCLUDE_TEST_RUN_TARGET_FROM_IDE +) diff --git a/scripts/o3de/tests/unit_global_project.py b/scripts/o3de/tests/unit_global_project.py new file mode 100644 index 0000000000..1d3a4dd4f4 --- /dev/null +++ b/scripts/o3de/tests/unit_global_project.py @@ -0,0 +1,40 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +import io +import json +import logging +import pytest +import pathlib +from unittest.mock import patch + +from o3de import global_project + + +logger = logging.getLogger() +logging.basicConfig() + +DEFAULT_BOOTSTRAP_SETREG = pathlib.Path('~/.o3de/Registry/bootstrap.setreg').expanduser() +PROJECT_PATH_KEY = ('Amazon', 'AzCore', 'Bootstrap', 'project_path') + +class TestSetGlobalProject: + @pytest.mark.parametrize( + "output_path, project_path, force, expected_result", [ + pytest.param(pathlib.Path('~/.o3de/Registry/bootstrap.setreg'), pathlib.Path('A:/'), False, False), + pytest.param(pathlib.Path('~/.o3de/Registry/bootstrap.setreg'), pathlib.Path('A:/'), True, True) + ] + ) + def test_set_global_project_non_existent_project_path(self, output_path, project_path, force, expected_result): + with patch('pathlib.Path.open', return_value=io.StringIO()) as pathlib_open_mock: + result = global_project.set_global_project(output_path, project_path=project_path, force=force) == 0 + + + assert result == expected_result diff --git a/scripts/o3de/tests/unit_test_current_project.py b/scripts/o3de/tests/unit_test_current_project.py deleted file mode 100755 index 7db48b62aa..0000000000 --- a/scripts/o3de/tests/unit_test_current_project.py +++ /dev/null @@ -1,102 +0,0 @@ -# -# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -# its licensors. -# -# For complete copyright and license terms please see the LICENSE at the root of this -# distribution (the "License"). All use of this software is governed by the License, -# or, if provided, by the license below or the license accompanying this file. Do not -# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# - -import os -import pytest - -from . import current_project - -TEST_BOOTSTRAP_CONTENT_1 = """ -project_path = Game1 -foo = bar -key1 = value1 -key2 = value2 -assets = pc -""" -TEST_BOOTSTRAP_CONTENT_2 = """ -project_path=Game1 -foo = bar -key1 = value1 -key2 = value2 -assets = pc -""" -TEST_BOOTSTRAP_CONTENT_3 = """ -project_path= Game1 -foo = bar -key1 = value1 -key2 = value2 -assets = pc -""" -TEST_BOOTSTRAP_CONTENT_4 = """ -project_path =Game1 -foo = bar -key1 = value1 -key2 = value2 -assets = pc -""" -TEST_BOOTSTRAP_CONTENT_5 = """ -project_path = Game1 -foo = bar -key1 = value1 -key2 = value2 -assets = pc -""" - -@pytest.mark.parametrize( - "contents, expected_result", [ - pytest.param(TEST_BOOTSTRAP_CONTENT_1, 'Game1'), - pytest.param(TEST_BOOTSTRAP_CONTENT_2, 'Game1'), - pytest.param(TEST_BOOTSTRAP_CONTENT_3, 'Game1'), - pytest.param(TEST_BOOTSTRAP_CONTENT_4, 'Game1'), - pytest.param(TEST_BOOTSTRAP_CONTENT_5, 'Game1'), - ] -) -def test_get_current_project(tmpdir, contents, expected_result): - dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/') - os.makedirs(dev_root, exist_ok=True) - - bootstrap_file = f'{dev_root}/bootstrap.cfg' - if os.path.isfile(bootstrap_file): - os.unlink(bootstrap_file) - with open(bootstrap_file, 'a') as s: - s.write(contents) - - result = current_project.get_current_project(dev_root) - assert expected_result == result - - -@pytest.mark.parametrize( - "contents, project_to_set, expected_result", [ - pytest.param(TEST_BOOTSTRAP_CONTENT_1, 'Test1', 0), - pytest.param(TEST_BOOTSTRAP_CONTENT_1, ' Test2', 0), - pytest.param(TEST_BOOTSTRAP_CONTENT_1, 'Test3 ', 0), - pytest.param(TEST_BOOTSTRAP_CONTENT_1, '/Test4', 1), - pytest.param(TEST_BOOTSTRAP_CONTENT_1, '=Test5', 1), - ] -) -def test_set_current_project(tmpdir, contents, project_to_set, expected_result): - dev_root = str(tmpdir.join('dev').realpath()).replace('\\', '/') - os.makedirs(dev_root, exist_ok=True) - - bootstrap_file = f'{dev_root}/bootstrap.cfg' - if os.path.isfile(bootstrap_file): - os.unlink(bootstrap_file) - with open(bootstrap_file, 'a') as s: - s.write(contents) - - result = current_project.set_current_project(dev_root, project_to_set) - assert expected_result == result - - if result == 0: - project_that_is_set = current_project.get_current_project(dev_root) - print(project_that_is_set) - print(project_to_set) - assert project_to_set.strip() == project_that_is_set \ No newline at end of file From 69e79867be5f87132c43c89f8ca081d543498242 Mon Sep 17 00:00:00 2001 From: pappeste Date: Thu, 27 May 2021 20:12:48 -0700 Subject: [PATCH 133/140] Making imported targets global, fixing identiation of the enabled_gems.cmake file --- AutomatedTesting/Gem/Code/enabled_gems.cmake | 2 +- cmake/Gems.cmake | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake index 32fdd11415..2ea800bae6 100644 --- a/AutomatedTesting/Gem/Code/enabled_gems.cmake +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -54,4 +54,4 @@ set(ENABLED_GEMS AWSCore AWSClientAuth AWSMetrics - ) +) diff --git a/cmake/Gems.cmake b/cmake/Gems.cmake index a90cf09639..d418d5dcd1 100644 --- a/cmake/Gems.cmake +++ b/cmake/Gems.cmake @@ -63,13 +63,17 @@ function(ly_create_alias) "This could be a copy-paste error, where some part of the ly_create_alias call was changed but the other") endif() - add_library(${ly_create_alias_NAME} INTERFACE IMPORTED) + add_library(${ly_create_alias_NAME} INTERFACE IMPORTED GLOBAL) set_target_properties(${ly_create_alias_NAME} PROPERTIES GEM_MODULE TRUE) foreach(target_name ${ly_create_alias_TARGETS}) - ly_de_alias_target(${target_name} de_aliased_target_name) - if(NOT de_aliased_target_name) - message(FATAL_ERROR "Target not found in ly_create_alias call: ${target_name} - check your spelling of the target name") + if(TARGET ${target_name}) + ly_de_alias_target(${target_name} de_aliased_target_name) + if(NOT de_aliased_target_name) + message(FATAL_ERROR "Target not found in ly_create_alias call: ${target_name} - check your spelling of the target name") + endif() + else() + set(de_aliased_target_name ${target_name}) endif() list(APPEND final_targets ${de_aliased_target_name}) endforeach() From 23a5afeefb72854df46f7b861c12f07fcfba5d1d Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Thu, 27 May 2021 23:47:51 -0500 Subject: [PATCH 134/140] Renaming the unit_global_project.py to unit_test_global_project.py. This fixes the unit test not being found --- .../tests/{unit_global_project.py => unit_test_global_project.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/o3de/tests/{unit_global_project.py => unit_test_global_project.py} (100%) diff --git a/scripts/o3de/tests/unit_global_project.py b/scripts/o3de/tests/unit_test_global_project.py similarity index 100% rename from scripts/o3de/tests/unit_global_project.py rename to scripts/o3de/tests/unit_test_global_project.py From 3b349e72a05e10d13e0a35b7d5912b8cc6d0c500 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 28 May 2021 01:17:57 -0500 Subject: [PATCH 135/140] Adding QtForPython gem to the AutomatedTesting project --- .../Platform/Android/runtime_dependencies.cmake | 10 ---------- .../Code/Platform/Android/tool_dependencies.cmake | 10 ---------- .../Code/Platform/Linux/runtime_dependencies.cmake | 10 ---------- .../Code/Platform/Linux/tool_dependencies.cmake | 10 ---------- .../Platform/Windows/runtime_dependencies.cmake | 13 ------------- .../Code/Platform/Windows/tool_dependencies.cmake | 14 -------------- .../Code/Platform/iOS/runtime_dependencies.cmake | 10 ---------- .../Gem/Code/Platform/iOS/tool_dependencies.cmake | 10 ---------- AutomatedTesting/Gem/Code/enabled_gems.cmake | 1 + 9 files changed, 1 insertion(+), 87 deletions(-) delete mode 100644 AutomatedTesting/Gem/Code/Platform/Android/runtime_dependencies.cmake delete mode 100644 AutomatedTesting/Gem/Code/Platform/Android/tool_dependencies.cmake delete mode 100644 AutomatedTesting/Gem/Code/Platform/Linux/runtime_dependencies.cmake delete mode 100644 AutomatedTesting/Gem/Code/Platform/Linux/tool_dependencies.cmake delete mode 100644 AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake delete mode 100644 AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake delete mode 100644 AutomatedTesting/Gem/Code/Platform/iOS/runtime_dependencies.cmake delete mode 100644 AutomatedTesting/Gem/Code/Platform/iOS/tool_dependencies.cmake diff --git a/AutomatedTesting/Gem/Code/Platform/Android/runtime_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/Android/runtime_dependencies.cmake deleted file mode 100644 index 4d5680a30d..0000000000 --- a/AutomatedTesting/Gem/Code/Platform/Android/runtime_dependencies.cmake +++ /dev/null @@ -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. -# diff --git a/AutomatedTesting/Gem/Code/Platform/Android/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/Android/tool_dependencies.cmake deleted file mode 100644 index 4d5680a30d..0000000000 --- a/AutomatedTesting/Gem/Code/Platform/Android/tool_dependencies.cmake +++ /dev/null @@ -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. -# diff --git a/AutomatedTesting/Gem/Code/Platform/Linux/runtime_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/Linux/runtime_dependencies.cmake deleted file mode 100644 index 4d5680a30d..0000000000 --- a/AutomatedTesting/Gem/Code/Platform/Linux/runtime_dependencies.cmake +++ /dev/null @@ -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. -# diff --git a/AutomatedTesting/Gem/Code/Platform/Linux/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/Linux/tool_dependencies.cmake deleted file mode 100644 index 4d5680a30d..0000000000 --- a/AutomatedTesting/Gem/Code/Platform/Linux/tool_dependencies.cmake +++ /dev/null @@ -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. -# diff --git a/AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake deleted file mode 100644 index ffcaf7293a..0000000000 --- a/AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake +++ /dev/null @@ -1,13 +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. -# - -set(GEM_DEPENDENCIES -) \ No newline at end of file diff --git a/AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake deleted file mode 100644 index 933dd7927b..0000000000 --- a/AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake +++ /dev/null @@ -1,14 +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. -# - -set(GEM_DEPENDENCIES - Gem::QtForPython.Editor -) \ No newline at end of file diff --git a/AutomatedTesting/Gem/Code/Platform/iOS/runtime_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/iOS/runtime_dependencies.cmake deleted file mode 100644 index 4d5680a30d..0000000000 --- a/AutomatedTesting/Gem/Code/Platform/iOS/runtime_dependencies.cmake +++ /dev/null @@ -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. -# diff --git a/AutomatedTesting/Gem/Code/Platform/iOS/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/iOS/tool_dependencies.cmake deleted file mode 100644 index 4d5680a30d..0000000000 --- a/AutomatedTesting/Gem/Code/Platform/iOS/tool_dependencies.cmake +++ /dev/null @@ -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. -# diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake index 2ea800bae6..d99d17b55e 100644 --- a/AutomatedTesting/Gem/Code/enabled_gems.cmake +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -21,6 +21,7 @@ set(ENABLED_GEMS InAppPurchases AutomatedTesting EditorPythonBindings + QtForPython PythonAssetBuilder Metastream AudioSystem From b73bc09ce709cfb2efe58f69592a77fee2192822 Mon Sep 17 00:00:00 2001 From: phistere Date: Fri, 28 May 2021 01:20:24 -0500 Subject: [PATCH 136/140] Fixes a name comparison issue during module load A name like Camera.dll was matching against Atom_Component_DebugCamera.dll so it thought the module was already seen and wouldn't add it to the list of dynamic modules to load. --- Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index d1cab75564..1010ae3473 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -1330,7 +1330,7 @@ namespace AZ { auto CompareDynamicModuleDescriptor = [&dynamicLibraryPath](const DynamicModuleDescriptor& entry) { - return entry.m_dynamicLibraryPath.contains(dynamicLibraryPath); + return AZ::IO::PathView(entry.m_dynamicLibraryPath).Stem() == AZ::IO::PathView(dynamicLibraryPath).Stem(); }; if (auto moduleIter = AZStd::find_if(gemModules.begin(), gemModules.end(), CompareDynamicModuleDescriptor); moduleIter == gemModules.end()) From 58bad80ffa590a760ace9f2ca311bf2b57a6f545 Mon Sep 17 00:00:00 2001 From: pappeste Date: Fri, 28 May 2021 00:17:20 -0700 Subject: [PATCH 137/140] changing paths for the install location in Jenkins --- scripts/build/Platform/Windows/build_config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Windows/build_config.json b/scripts/build/Platform/Windows/build_config.json index d3adf69f43..38cd7d6ad8 100644 --- a/scripts/build/Platform/Windows/build_config.json +++ b/scripts/build/Platform/Windows/build_config.json @@ -300,7 +300,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE -DCMAKE_INSTALL_PREFIX=install", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DLY_DISABLE_TEST_MODULES=TRUE", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "INSTALL", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" @@ -332,7 +332,7 @@ "PARAMETERS": { "CONFIGURATION": "profile", "OUTPUT_DIRECTORY": "build\\windows_vs2019", - "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/build/windows_vs2019/install/cmake", + "CMAKE_OPTIONS": "-G \"Visual Studio 16 2019\" -DCMAKE_SYSTEM_VERSION=10.0 -DLY_UNITY_BUILD=TRUE -DCMAKE_MODULE_PATH=!WORKSPACE!/o3de/install/cmake", "CMAKE_LY_PROJECTS": "", "CMAKE_TARGET": "ALL_BUILD", "CMAKE_NATIVE_BUILD_ARGS": "/m /nologo" From 3c0c066f8807b5a8bcf8ca1385e689a0a0153800 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 28 May 2021 02:54:54 -0500 Subject: [PATCH 138/140] Updating the ProjectManager Gem validation check to make sure the name isn't empty either --- Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp index 16e52c7073..bc44928868 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp @@ -25,7 +25,7 @@ namespace O3DE::ProjectManager bool GemInfo::IsValid() const { - return !m_path.isEmpty(); + return !m_name.isEmpty() && !m_path.isEmpty(); } QString GemInfo::GetPlatformString(Platform platform) From 9ad70608e8156017d066bb405424497446f61e7d Mon Sep 17 00:00:00 2001 From: pappeste Date: Fri, 28 May 2021 09:46:27 -0700 Subject: [PATCH 139/140] Fixing compilation failure --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 9e6e50caf8..d1c1879609 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -466,7 +466,7 @@ namespace O3DE::ProjectManager [&] { pybind11::str projectPath = path.toStdString(); - auto pythonRegistrationResult = m_registration.attr("register")(pybind11::none(), projectPath); + auto pythonRegistrationResult = m_register.attr("register")(pybind11::none(), projectPath); // Returns an exit code so boolify it then invert result registrationResult = !pythonRegistrationResult.cast(); @@ -482,7 +482,7 @@ namespace O3DE::ProjectManager [&] { pybind11::str projectPath = path.toStdString(); - auto pythonRegistrationResult = m_registration.attr("register")( + auto pythonRegistrationResult = m_register.attr("register")( pybind11::none(), // engine_path projectPath, // project_path pybind11::none(), // gem_path From ddab4cf53a4ef1f6e7f710530ded564775a3f733 Mon Sep 17 00:00:00 2001 From: pappeste Date: Fri, 28 May 2021 10:06:21 -0700 Subject: [PATCH 140/140] Fix for register python bindings --- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index d1c1879609..8db8492cae 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -384,11 +384,12 @@ namespace O3DE::ProjectManager auto registrationResult = m_register.attr("register")( enginePath, // engine_path pybind11::none(), // project_path - pybind11::none(), // gem_path + pybind11::none(), // gem_path + pybind11::none(), // external_subdir_path pybind11::none(), // template_path pybind11::none(), // restricted_path pybind11::none(), // repo_uri - pybind11::none(), // default_engines_folder + pybind11::none(), // default_engines_folder defaultProjectsFolder, defaultGemsFolder, defaultTemplatesFolder @@ -486,15 +487,19 @@ namespace O3DE::ProjectManager pybind11::none(), // engine_path projectPath, // project_path pybind11::none(), // gem_path + pybind11::none(), // external_subdir_path pybind11::none(), // template_path pybind11::none(), // restricted_path pybind11::none(), // repo_uri pybind11::none(), // default_engines_folder + pybind11::none(), // default_projects_folder pybind11::none(), // default_gems_folder pybind11::none(), // default_templates_folder pybind11::none(), // default_restricted_folder - pybind11::none(), // default_restricted_folder - true // remove + pybind11::none(), // external_subdir_engine_path + pybind11::none(), // external_subdir_project_path + true, // remove + false // force ); // Returns an exit code so boolify it then invert result