diff --git a/.gitignore b/.gitignore index c3af907e97..664680c5bf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ __pycache__ AssetProcessorTemp/** [Bb]uild/** [Cc]ache/ +/install/ Editor/EditorEventLog.xml Editor/EditorLayout.xml **/*egg-info/** @@ -19,3 +20,4 @@ _savebackup/ TestResults/** *.swatches /imgui.ini +/scripts/project_manager/logs/ diff --git a/AutomatedTesting/EngineFinder.cmake b/AutomatedTesting/EngineFinder.cmake index 1fdcef2b56..fbbe3d8cfe 100644 --- a/AutomatedTesting/EngineFinder.cmake +++ b/AutomatedTesting/EngineFinder.cmake @@ -20,31 +20,49 @@ 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(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() - list(APPEND CMAKE_MODULE_PATH "${engine_path}/cmake") endforeach() +else() + # 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() diff --git a/AutomatedTesting/Gem/Code/CMakeLists.txt b/AutomatedTesting/Gem/Code/CMakeLists.txt index 2bcc304bde..548aa51ad1 100644 --- a/AutomatedTesting/Gem/Code/CMakeLists.txt +++ b/AutomatedTesting/Gem/Code/CMakeLists.txt @@ -28,30 +28,41 @@ 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 ################################################################################ -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 - ) +# The GameLauncher uses "Clients" gem variants: +ly_enable_gems(PROJECT_NAME AutomatedTesting GEM_FILE enabled_gems.cmake + TARGETS AutomatedTesting.GameLauncher + VARIANTS Clients) + +# 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/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake new file mode 100644 index 0000000000..d99d17b55e --- /dev/null +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -0,0 +1,58 @@ +# +# 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 + QtForPython + 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 280c25bcf7..0000000000 --- a/AutomatedTesting/Gem/Code/runtime_dependencies.cmake +++ /dev/null @@ -1,48 +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 -) diff --git a/AutomatedTesting/Gem/Code/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/tool_dependencies.cmake deleted file mode 100644 index 1d70c02b1c..0000000000 --- a/AutomatedTesting/Gem/Code/tool_dependencies.cmake +++ /dev/null @@ -1,60 +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.Editor - 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 -) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7e42613cb..387f536966 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,34 +25,13 @@ 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 VERSION ${LY_VERSION_STRING} ) - - # o3de manifest - include(cmake/o3de_manifest.cmake) endif() -################################################################################ -# Resolve this engines name and restricted path -################################################################################ -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 ################################################################################ @@ -60,6 +39,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) @@ -67,92 +47,106 @@ 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) 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) if(NOT INSTALLED_ENGINE) + # Add the rest of the targets add_subdirectory(Code) + add_subdirectory(scripts) + + # 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() + + # Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra + # 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}) + # 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}/External/${directory_name}-${full_directory_hash}) + endforeach() + else() ly_find_o3de_packages() endif() -# Add external subdirectories listed in the manifest -list(APPEND LY_EXTERNAL_SUBDIRS ${o3de_engine_external_subdirectories}) - -set(enabled_platforms - ${PAL_PLATFORM_NAME} - ${LY_PAL_TOOLS_ENABLED}) - -# Add any engine restricted platforms as external subdirs -o3de_add_engine_restricted_platform_external_subdirs() - -if(NOT INSTALLED_ENGINE) - add_subdirectory(scripts) -endif() - -# 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() - ################################################################################ # 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}/External/${directory_name}-${full_directory_hash}) -endforeach() - # The following steps have to be done after all targets are registered: # Defer generation of the StaticModules.inl file which is needed to create the AZ::Module derived class in monolithic # builds until after all the targets are known ly_delayed_generate_static_modules_inl() -# 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 -# the dependencies -include(cmake/RuntimeDependencies.cmake) -# 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 -if(NOT INSTALLED_ENGINE) - ly_setup_o3de_install() - # IMPORTANT: must be included last +# 5. inject runtime dependencies to the targets. We need to do this after (1) since we are going to walk through +# the dependencies +ly_delayed_generate_runtime_dependencies() + +# 6. Perform test impact framework post steps once all of the targets have been enumerated +ly_test_impact_post_step() + +# 7. Generate the O3DE find file and setup install locations for scripts, tools, assets etc., required by the engine +if(NOT INSTALLED_ENGINE) + # 8. Generate the O3DE find file and setup install locations for scripts, tools, assets etc., required by the engine + ly_setup_o3de_install() + # 9. CPack information (to be included after install) include(cmake/Packaging.cmake) endif() diff --git a/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp b/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp index ff6ebc0d17..31d1540d77 100644 --- a/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp +++ b/Code/CryEngine/CrySystem/LevelSystem/SpawnableLevelSystem.cpp @@ -36,8 +36,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()) { diff --git a/Code/CryEngine/CrySystem/SystemInit.cpp b/Code/CryEngine/CrySystem/SystemInit.cpp index 25d6b9c601..79041fa233 100644 --- a/Code/CryEngine/CrySystem/SystemInit.cpp +++ b/Code/CryEngine/CrySystem/SystemInit.cpp @@ -864,11 +864,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 *_dependencies.cmake."); - return false; - } return true; } diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index f03b1aac76..1010ae3473 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -1260,7 +1260,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) { @@ -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()) 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/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/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 5870c66633..2abef3f808 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{}; }; 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())) { diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index 1f29478399..922397c325 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, @@ -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 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/Code/Sandbox/Editor/CMakeLists.txt b/Code/Sandbox/Editor/CMakeLists.txt index 4706a61d08..7be9947e99 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 @@ -244,7 +246,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/Editor/RenderViewport.cpp b/Code/Sandbox/Editor/RenderViewport.cpp index f199590e4f..8cef9e802c 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()) { @@ -1313,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; diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt index d02c656b8f..53e04e1dee 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt @@ -35,10 +35,12 @@ ly_add_target( AZ::AzToolsFramework Legacy::CryCommon Legacy::EditorLib - Gem::LmbrCentral AZ::AtomCore Gem::Atom_RPI.Public Gem::AtomToolsFramework.Static + Gem::LmbrCentral.Editor + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) ly_add_dependencies(Editor ComponentEntityEditorPlugin) @@ -68,7 +70,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzToolsFrameworkTestCommon Legacy::CryCommon Legacy::EditorLib - Gem::LmbrCentral + Gem::LmbrCentral.Editor + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) ly_add_googletest( NAME Legacy::ComponentEntityEditorPlugin.Tests 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) { diff --git a/Code/Tools/ProjectManager/CMakeLists.txt b/Code/Tools/ProjectManager/CMakeLists.txt index e2b5aaf696..a655600325 100644 --- a/Code/Tools/ProjectManager/CMakeLists.txt +++ b/Code/Tools/ProjectManager/CMakeLists.txt @@ -37,11 +37,8 @@ ly_add_target( PRIVATE PY_PACKAGE="${python_package_name}" INCLUDE_DIRECTORIES - PUBLIC - . PRIVATE Source - BUILD_DEPENDENCIES PRIVATE 3rdParty::Qt::Core diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp index 791085f47a..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() && !m_uuid.IsNull(); + return !m_name.isEmpty() && !m_path.isEmpty(); } QString GemInfo::GetPlatformString(Platform platform) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h index 06b0adad32..1032ca5eaf 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h @@ -64,7 +64,6 @@ namespace O3DE::ProjectManager QString m_path; QString m_name = "Unknown Gem Name"; QString m_displayName = "Unknown Gem Name"; - AZ::Uuid m_uuid; QString m_creator = "Unknown Creator"; GemOrigin m_gemOrigin = Local; bool m_isAdded = false; //! Is the gem currently added and enabled in the project? 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 9279ad1291..8db8492cae 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -220,7 +220,7 @@ namespace RedirectOutput } } // namespace RedirectOutput -namespace O3DE::ProjectManager +namespace O3DE::ProjectManager { PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath) : m_enginePath(enginePath) @@ -283,8 +283,11 @@ 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_engineTemplate = pybind11::module::import("cmake.Tools.engine_template"); + m_register = pybind11::module::import("o3de.register"); + m_manifest = pybind11::module::import("o3de.manifest"); + m_engineTemplate = pybind11::module::import("o3de.engine_template"); + 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) @@ -326,30 +329,30 @@ namespace O3DE::ProjectManager } } - AZ::Outcome PythonBindings::GetEngineInfo() + AZ::Outcome PythonBindings::GetEngineInfo() { 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_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) { @@ -364,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(); @@ -378,17 +381,18 @@ 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 - pybind11::none(), // default_engines_folder + auto registrationResult = m_register.attr("register")( + enginePath, // engine_path + pybind11::none(), // 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 defaultProjectsFolder, - defaultGemsFolder, - defaultTemplatesFolder + defaultGemsFolder, + defaultTemplatesFolder ); if (registrationResult.cast() != 0) @@ -396,13 +400,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) { @@ -415,12 +419,12 @@ namespace O3DE::ProjectManager return result; } - 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 { @@ -428,19 +432,19 @@ namespace O3DE::ProjectManager } } - AZ::Outcome> PythonBindings::GetGems() + AZ::Outcome> PythonBindings::GetGems() { QVector gems; bool result = ExecuteWithLock([&] { - // external gems - for (auto path : m_registration.attr("get_gems")()) + // external 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")()) + // gems from the engine + for (auto path : m_manifest.attr("get_engine_gems")()) { gems.push_back(GemInfoFromPath(path)); } @@ -452,7 +456,7 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(gems)); + return AZ::Success(AZStd::move(gems)); } } @@ -463,7 +467,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(); @@ -479,19 +483,23 @@ 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 + 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 @@ -501,7 +509,7 @@ namespace O3DE::ProjectManager return result && registrationResult; } - 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([&] { @@ -521,16 +529,16 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(createdProjectInfo)); + return AZ::Success(AZStd::move(createdProjectInfo)); } } - 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 { @@ -541,30 +549,21 @@ 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); + auto data = m_manifest.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); - 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")) - { - 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"]) @@ -588,13 +587,13 @@ namespace O3DE::ProjectManager projectInfo.m_path = Py_To_String(path); projectInfo.m_isNew = false; - auto projectData = m_registration.attr("get_project_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_projectName = Py_To_String(projectData["project_name"]); + projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName); } catch ([[maybe_unused]] const std::exception& e) { @@ -605,19 +604,19 @@ namespace O3DE::ProjectManager return projectInfo; } - AZ::Outcome> PythonBindings::GetProjects() + AZ::Outcome> PythonBindings::GetProjects() { QVector projects; bool result = ExecuteWithLock([&] { - // external projects - for (auto path : m_registration.attr("get_projects")()) + // external 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")()) + // projects from the engine + for (auto path : m_manifest.attr("get_engine_projects")()) { projects.push_back(ProjectInfoFromPath(path)); } @@ -629,7 +628,7 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(projects)); + return AZ::Success(AZStd::move(projects)); } } @@ -639,10 +638,9 @@ namespace O3DE::ProjectManager pybind11::str pyGemPath = gemPath.toStdString(); pybind11::str pyProjectPath = projectPath.toStdString(); - m_registration.attr("add_gem_to_project")( + m_enableGemProject.attr("enable_gem_in_project")( pybind11::none(), // gem_name pyGemPath, - pybind11::none(), // gem_target pybind11::none(), // project_name pyProjectPath ); @@ -657,10 +655,9 @@ namespace O3DE::ProjectManager pybind11::str pyGemPath = gemPath.toStdString(); pybind11::str pyProjectPath = projectPath.toStdString(); - m_registration.attr("remove_gem_to_project")( + m_disableGemProject.attr("disable_gem_in_project")( pybind11::none(), // gem_name pyGemPath, - pybind11::none(), // gem_target pybind11::none(), // project_name pyProjectPath ); @@ -669,7 +666,7 @@ namespace O3DE::ProjectManager return result; } - bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) + bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo) { return false; } @@ -677,18 +674,18 @@ 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); + auto data = m_manifest.attr("get_template_json_data")(pybind11::none(), path); if (pybind11::isinstance(data)) { 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")) { @@ -714,12 +711,12 @@ namespace O3DE::ProjectManager return templateInfo; } - AZ::Outcome> PythonBindings::GetProjectTemplates() + AZ::Outcome> PythonBindings::GetProjectTemplates() { 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)); } @@ -731,7 +728,7 @@ namespace O3DE::ProjectManager } else { - return AZ::Success(AZStd::move(templates)); + return AZ::Success(AZStd::move(templates)); } } } diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index fb2303c495..18122f484b 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: @@ -68,6 +68,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_enableGemProject; + pybind11::handle m_disableGemProject; }; } diff --git a/Gems/AWSClientAuth/Code/CMakeLists.txt b/Gems/AWSClientAuth/Code/CMakeLists.txt index e9f2a4ed84..40f6e0fe36 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,13 +47,19 @@ 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 ) +# 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 ################################################################################ @@ -71,10 +80,14 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) 3rdParty::AWSNativeSDK::AWSClientAuth AZ::AzCore AZ::AzFramework - Gem::AWSCore - Gem::AWSClientAuth.Static AZ::AWSNativeSDKInit + Gem::AWSClientAuth.Static + Gem::AWSCore Gem::HttpRequestor + RUNTIME_DEPENDENCIES + Gem::AWSCore + AZ::AWSNativeSDKInit + Gem::HttpRequestor ) ly_add_googletest( NAME 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..aa790371d2 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,10 +41,15 @@ ly_add_target( PRIVATE AZ::AzCore AZ::AzFramework - Gem::AWSCore Gem::AWSMetrics.Static + RUNTIME_DEPENDENCIES + Gem::AWSCore ) +# 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 ################################################################################ @@ -63,8 +69,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/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/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 c74a9013f3..91bc9bcf53 100644 --- a/Gems/Atom/gem.json +++ b/Gems/Atom/gem.json @@ -1,3 +1,5 @@ { - "gem_name": "Atom" + "gem_name": "Atom", + "display_name": "Atom", + "summary": "Next-Gen Rendering Package for the O3DE engine" } diff --git a/AutomatedTesting/Gem/Code/Platform/Android/runtime_dependencies.cmake b/Gems/AtomContent/CMakeLists.txt similarity index 100% rename from AutomatedTesting/Gem/Code/Platform/Android/runtime_dependencies.cmake rename to Gems/AtomContent/CMakeLists.txt 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/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomBridge/Code/CMakeLists.txt index 0723ca46b7..4df40e3d13 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} @@ -108,4 +112,9 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AtomViewportDisplayInfo Gem::AtomViewportDisplayIcons.Editor ) + + + # 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/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/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/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp index 7d830b4ca9..146c0c67d0 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp @@ -303,7 +303,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( 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": [ + ] +} 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/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/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 index ca80c62dd0..a867fe0f0f 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/gem.json @@ -1,17 +1,14 @@ { - "gem_name": "Atom_DccScriptingInterface", - "GemFormatVersion": 4, - "Uuid": "7bf5a77dacd8438bb4966a66b5a678d8", - "Name": "Atom_DccScriptingInterface", - "DisplayName": "Atom DccScriptingInterface (DCCsi)", - "Version": "0.1.0", - "Summary": "A python framework for working with various DCC tools and workflows.", - "Tags": ["DCC","Digital","Content","Creation"], - "IconPath": "preview.png", - "Modules": [ - { - "Name": "Editor", - "Type": "EditorModule" - } + "gem_name": "DccScriptingInterface", + "display_name": "Atom DccScriptingInterface (DCCsi)", + "summary": "A python framework for working with various DCC tools and workflows.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "DCC", + "Digital", + "Content", + "Creation" ] } diff --git a/Gems/AtomLyIntegration/gem.json b/Gems/AtomLyIntegration/gem.json index 0971ad53c2..4f587a8806 100644 --- a/Gems/AtomLyIntegration/gem.json +++ b/Gems/AtomLyIntegration/gem.json @@ -1,3 +1,5 @@ { - "gem_name": "AtomLyIntegration" + "gem_name": "AtomLyIntegration", + "display_name": "Atom O3DE Integration", + "summary": "Collection of module targets for integrating Atom with the O3DE engine" } diff --git a/AutomatedTesting/Gem/Code/Platform/Android/tool_dependencies.cmake b/Gems/AtomTressFX/CMakeLists.txt similarity index 100% rename from AutomatedTesting/Gem/Code/Platform/Android/tool_dependencies.cmake rename to Gems/AtomTressFX/CMakeLists.txt diff --git a/Gems/AudioEngineWwise/Code/CMakeLists.txt b/Gems/AudioEngineWwise/Code/CMakeLists.txt index 5ea6a6d461..f90064908a 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 ################################################################################ @@ -206,6 +209,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AssetBuilderSDK Gem::AudioEngineWwise.Static Gem::AudioSystem.Editor + RUNTIME_DEPENDENCIES + Gem::AudioSystem.Editor ) ly_add_target( @@ -230,6 +235,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..3963a71ad0 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 @@ -101,7 +87,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 @@ -230,6 +217,10 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AudioSystem.Editor.Static ) + # use the above "Editor" target in tools and builders: + 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( NAME AudioSystem.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} @@ -253,3 +244,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 0954d6366c..69488b1493 100644 --- a/Gems/DebugDraw/Code/CMakeLists.txt +++ b/Gems/DebugDraw/Code/CMakeLists.txt @@ -42,6 +42,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 @@ -62,4 +65,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/AutomatedTesting/Gem/Code/Platform/Linux/runtime_dependencies.cmake b/Gems/DevTextures/CMakeLists.txt similarity index 100% rename from AutomatedTesting/Gem/Code/Platform/Linux/runtime_dependencies.cmake rename to Gems/DevTextures/CMakeLists.txt diff --git a/Gems/EMotionFX/Code/CMakeLists.txt b/Gems/EMotionFX/Code/CMakeLists.txt index b90902a948..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 PUBLIC AZ::AtomCore Gem::Atom_RPI.Public + Gem::LmbrCentral COMPILE_DEFINITIONS PUBLIC EMFX_DEVELOPMENT_BUILD @@ -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..ae42af771a 100644 --- a/Gems/FastNoise/Code/CMakeLists.txt +++ b/Gems/FastNoise/Code/CMakeLists.txt @@ -23,6 +23,7 @@ ly_add_target( PUBLIC Legacy::CryCommon Gem::GradientSignal + PRIVATE Gem::LmbrCentral ) @@ -42,6 +43,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 @@ -57,6 +62,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC Include BUILD_DEPENDENCIES + PRIVATE + Gem::LmbrCentral.Editor PUBLIC Gem::FastNoise.Static AZ::AzToolsFramework @@ -65,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 @@ -76,11 +82,18 @@ 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 ) + + # 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() ################################################################################ @@ -103,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 @@ -120,6 +134,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) PRIVATE AZ::AzTest Gem::FastNoise.Static + Gem::LmbrCentral ) ly_add_googletest( NAME Gem::FastNoise.Tests 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..abf3ca6121 100644 --- a/Gems/GameStateSamples/Code/CMakeLists.txt +++ b/Gems/GameStateSamples/Code/CMakeLists.txt @@ -44,4 +44,12 @@ ly_add_target( AZ::AzFramework Gem::LmbrCentral Gem::GameStateSamples.Headers + RUNTIME_DEPENDENCIES + Gem::GameState + Gem::LocalUser + Gem::LmbrCentral ) + +# 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..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 Gem::SurfaceData Gem::ImageProcessingAtom.Headers + PRIVATE + Gem::LmbrCentral ) ly_add_target( @@ -40,13 +41,17 @@ 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 Gem::LmbrCentral - 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( @@ -63,19 +68,21 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PUBLIC GRADIENTSIGNAL_EDITOR BUILD_DEPENDENCIES + PRIVATE + Gem::LmbrCentral.Editor PUBLIC 3rdParty::Qt::Widgets Legacy::CryCommon AZ::AzToolsFramework - Gem::LmbrCentral - Gem::SurfaceData AZ::AssetBuilderSDK Gem::GradientSignal.Static + Gem::SurfaceData + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor ) ly_add_target( NAME GradientSignal.Editor GEM_MODULE - NAMESPACE Gem FILES_CMAKE gradientsignal_editor_shared_files.cmake @@ -87,11 +94,16 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) BUILD_DEPENDENCIES PRIVATE Gem::GradientSignal.Editor.Static + Gem::LmbrCentral.Editor RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor - 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() ################################################################################ @@ -112,6 +124,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) PRIVATE AZ::AzTest Gem::GradientSignal.Static + Gem::LmbrCentral ) ly_add_googletest( NAME Gem::GradientSignal.Tests @@ -132,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/GraphCanvas/Code/CMakeLists.txt b/Gems/GraphCanvas/Code/CMakeLists.txt index 683b0e4bdf..fe24686f95 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 @@ -75,4 +74,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..fccdb6fc08 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( @@ -70,6 +72,7 @@ ly_add_target( BUILD_DEPENDENCIES PUBLIC Gem::ImGui.ImGuiLYUtils + PRIVATE Gem::LmbrCentral ) @@ -90,6 +93,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 +120,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..5288db9cc1 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 - 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 @@ -72,6 +76,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() ################################################################################ @@ -97,9 +106,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/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 796cb22292..4dede1c6ac 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -27,12 +27,12 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::LmbrCentral - Gem::TextureAtlas PUBLIC Gem::Atom_RPI.Public Gem::Atom_Utils.Static Gem::Atom_Bootstrap.Headers Gem::AtomFont + Gem::TextureAtlas ) ly_add_target( @@ -50,12 +50,14 @@ ly_add_target( Gem::LyShine.Static Legacy::CryCommon Gem::LmbrCentral - Gem::TextureAtlas RUNTIME_DEPENDENCIES Gem::LmbrCentral 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 @@ -85,7 +87,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::EditorCore Gem::LyShine.Static Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Editor Gem::TextureAtlas.Editor Gem::AtomToolsFramework.Static Gem::AtomToolsFramework.Editor @@ -94,6 +96,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Atom_RPI.Public Gem::Atom_Utils.Static Gem::Atom_Bootstrap.Headers + RUNTIME_DEPENDENCIES + Gem::TextureAtlas.Editor ) ly_add_target( @@ -117,12 +121,16 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryCommon AZ::AssetBuilderSDK Gem::LyShine.Editor.Static - Gem::LmbrCentral + Gem::LmbrCentral.Editor Gem::TextureAtlas.Editor RUNTIME_DEPENDENCIES Gem::LmbrCentral.Editor Gem::TextureAtlas.Editor ) + + # 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() ################################################################################ @@ -146,7 +154,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) Gem::LyShine.Static Legacy::CryCommon Gem::LmbrCentral - Gem::TextureAtlas + RUNTIME_DEPENDENCIES + Gem::LmbrCentral + Gem::TextureAtlas ) ly_add_googletest( NAME Gem::LyShine.Tests @@ -175,9 +185,12 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest Legacy::CryCommon AZ::AssetBuilderSDK - Gem::LmbrCentral - Gem::TextureAtlas.Editor Gem::LyShine.Editor.Static + Gem::LmbrCentral.Editor + Gem::TextureAtlas + RUNTIME_DEPENDENCIES + Gem::LmbrCentral.Editor + Gem::TextureAtlas.Editor ) ly_add_googletest( NAME Gem::LyShine.Editor.Tests diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp index f55c8c5957..902752a03c 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp @@ -208,8 +208,6 @@ namespace LyShine //////////////////////////////////////////////////////////////////////////////////////////////////// void LyShineSystemComponent::InitializeSystem() { - m_pLyShine = new CLyShine(gEnv->pSystem); - gEnv->pLyShine = m_pLyShine; BroadcastCursorImagePathname(); } @@ -374,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/LyShineExamples/Code/CMakeLists.txt b/Gems/LyShineExamples/Code/CMakeLists.txt index 372bfa948b..96c41bbb64 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,4 +40,13 @@ 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 +# 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/Maestro/Code/CMakeLists.txt b/Gems/Maestro/Code/CMakeLists.txt index fe58ba03a6..01b22b1abf 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,11 +38,14 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::Maestro.Static - Gem::LmbrCentral RUNTIME_DEPENDENCIES 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 @@ -69,10 +71,13 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzToolsFramework AZ::AssetBuilderSDK Gem::Maestro.Static - Gem::LmbrCentral 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..430fe5ca4b 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -58,9 +58,35 @@ 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 "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 @@ -80,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 @@ -94,7 +122,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Include BUILD_DEPENDENCIES PRIVATE - Gem::Multiplayer.Tools.Static + Gem::Multiplayer.Builders.Static ) ly_add_target( @@ -121,9 +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 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) @@ -151,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 @@ -165,33 +195,11 @@ 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() 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/AutomatedTesting/Gem/Code/Platform/Linux/tool_dependencies.cmake b/Gems/PBSreferenceMaterials/CMakeLists.txt similarity index 100% rename from AutomatedTesting/Gem/Code/Platform/Linux/tool_dependencies.cmake rename to Gems/PBSreferenceMaterials/CMakeLists.txt diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index b4c7b580a6..b0318af9f2 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -46,6 +46,7 @@ ly_add_target( AZ::AzCore AZ::AzFramework Legacy::CryCommon + PRIVATE Gem::LmbrCentral ) @@ -66,10 +67,15 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::PhysX.Static + Gem::LmbrCentral RUNTIME_DEPENDENCIES 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) @@ -107,7 +113,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) AZ::SceneCore AZ::SceneData Legacy::CryCommon - Gem::LmbrCentral + Gem::LmbrCentral.Editor Gem::PhysX.NumericalMethods Gem::PhysX.Static Gem::AtomLyIntegration_CommonFeatures.Static @@ -136,6 +142,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() ################################################################################ @@ -157,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/PhysXDebug/Code/CMakeLists.txt b/Gems/PhysXDebug/Code/CMakeLists.txt index f198f6f26e..b0a05ef146 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( @@ -66,11 +69,15 @@ 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 ) + # 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/AutomatedTesting/Gem/Code/Platform/iOS/runtime_dependencies.cmake b/Gems/PhysXSamples/CMakeLists.txt similarity index 100% rename from AutomatedTesting/Gem/Code/Platform/iOS/runtime_dependencies.cmake rename to Gems/PhysXSamples/CMakeLists.txt diff --git a/AutomatedTesting/Gem/Code/Platform/iOS/tool_dependencies.cmake b/Gems/PhysicsEntities/CMakeLists.txt similarity index 100% rename from AutomatedTesting/Gem/Code/Platform/iOS/tool_dependencies.cmake rename to Gems/PhysicsEntities/CMakeLists.txt 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/AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake b/Gems/PrimitiveAssets/CMakeLists.txt similarity index 95% rename from AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake rename to Gems/PrimitiveAssets/CMakeLists.txt index ffcaf7293a..4d5680a30d 100644 --- a/AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake +++ b/Gems/PrimitiveAssets/CMakeLists.txt @@ -8,6 +8,3 @@ # 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/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..4b0dfbab27 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() ################################################################################ @@ -84,7 +88,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..f9165192f0 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 @@ -81,6 +89,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( @@ -109,6 +119,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 @@ -170,6 +184,8 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::ExpressionEvaluation.Static PRIVATE Legacy::EditorCore + RUNTIME_DEPENDENCIES + Gem::ScriptCanvas ) ly_add_target( @@ -204,6 +220,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() ################################################################################ @@ -228,7 +250,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..8f2f6d3fc0 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 @@ -81,5 +86,10 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::GraphCanvasWidgets RUNTIME_DEPENDENCIES Gem::ScriptCanvas.Editor + Gem::GraphCanvasWidgets ) + # 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/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(); diff --git a/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt b/Gems/ScriptCanvasPhysics/Code/CMakeLists.txt index 23ee6937c7..107db38f5e 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,8 +35,16 @@ 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 +# 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 ################################################################################ @@ -57,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 diff --git a/Gems/ScriptCanvasTesting/Code/CMakeLists.txt b/Gems/ScriptCanvasTesting/Code/CMakeLists.txt index 639ef114fc..76a549d6b9 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 @@ -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.Editor + Gem::ScriptCanvasEditor + Gem::GraphCanvasWidgets + Gem::ScriptEvents ) ly_add_target( @@ -73,6 +78,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 ################################################################################ @@ -101,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 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..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 ) ly_add_target( @@ -42,10 +42,15 @@ ly_add_target( PRIVATE Legacy::CryCommon Gem::SurfaceData.Static + Gem::LmbrCentral RUNTIME_DEPENDENCIES 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( @@ -67,9 +72,13 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::CryCommon AZ::AzToolsFramework Gem::SurfaceData.Static + Gem::LmbrCentral.Editor 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() @@ -93,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/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 5e29a7ea65..d67601235d 100644 --- a/Gems/TextureAtlas/Code/CMakeLists.txt +++ b/Gems/TextureAtlas/Code/CMakeLists.txt @@ -62,5 +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) + 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..b5c1751003 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( @@ -47,3 +49,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/Templates/DefaultProject/Template/Code/Platform/Android/android_server_dependencies.cmake b/Gems/UiBasics/CMakeLists.txt similarity index 89% rename from Templates/DefaultProject/Template/Code/Platform/Android/android_server_dependencies.cmake rename to Gems/UiBasics/CMakeLists.txt index fe28e294e9..4d5680a30d 100644 --- a/Templates/DefaultProject/Template/Code/Platform/Android/android_server_dependencies.cmake +++ b/Gems/UiBasics/CMakeLists.txt @@ -1,4 +1,4 @@ -# {BEGIN_LICENSE} +# # All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or # its licensors. # @@ -7,7 +7,4 @@ # 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/Gems/Vegetation/Code/CMakeLists.txt b/Gems/Vegetation/Code/CMakeLists.txt index c4a003bb4a..7283f53c97 100644 --- a/Gems/Vegetation/Code/CMakeLists.txt +++ b/Gems/Vegetation/Code/CMakeLists.txt @@ -24,12 +24,14 @@ ly_add_target( PUBLIC Include BUILD_DEPENDENCIES + PRIVATE + Gem::LmbrCentral + Gem::SurfaceData PUBLIC Legacy::CryCommon - Gem::LmbrCentral - Gem::GradientSignal - Gem::SurfaceData.Static Gem::AtomLyIntegration_CommonFeatures.Static + RUNTIME_DEPENDENCIES + Gem::GradientSignal ) ly_add_target( @@ -51,6 +53,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 +81,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/Templates/DefaultProject/Template/Code/Platform/Linux/linux_server_dependencies.cmake b/Gems/Vegetation_Gem_Assets/CMakeLists.txt similarity index 89% rename from Templates/DefaultProject/Template/Code/Platform/Linux/linux_server_dependencies.cmake rename to Gems/Vegetation_Gem_Assets/CMakeLists.txt index fe28e294e9..4d5680a30d 100644 --- a/Templates/DefaultProject/Template/Code/Platform/Linux/linux_server_dependencies.cmake +++ b/Gems/Vegetation_Gem_Assets/CMakeLists.txt @@ -1,4 +1,4 @@ -# {BEGIN_LICENSE} +# # All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or # its licensors. # @@ -7,7 +7,4 @@ # 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/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/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/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/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/CMakeLists.txt b/Templates/DefaultProject/Template/CMakeLists.txt index ad0a4c869d..b5b8692059 100644 --- a/Templates/DefaultProject/Template/CMakeLists.txt +++ b/Templates/DefaultProject/Template/CMakeLists.txt @@ -23,64 +23,26 @@ 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() 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..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,48 +57,60 @@ 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 ################################################################################ -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_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_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/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) 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/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/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/EngineFinder.cmake b/Templates/DefaultProject/Template/EngineFinder.cmake new file mode 100644 index 0000000000..fbbe3d8cfe --- /dev/null +++ b/Templates/DefaultProject/Template/EngineFinder.cmake @@ -0,0 +1,68 @@ +# +# 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() + +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) + + 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_path' from '${manifest_path}', error: ${json_error}") + endif() + + 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(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() + # 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() 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/Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.cpp b/Templates/DefaultProject/Template/Shaders/ShaderResourceGroups/SceneSrg.azsli similarity index 68% rename from Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.cpp rename to Templates/DefaultProject/Template/Shaders/ShaderResourceGroups/SceneSrg.azsli index 6fdd7bdc45..4c962fbbcd 100644 --- a/Gems/ScriptCanvasDiagnosticLibrary/Code/Source/precompiled.cpp +++ b/Templates/DefaultProject/Template/Shaders/ShaderResourceGroups/SceneSrg.azsli @@ -1,3 +1,4 @@ +// {BEGIN_LICENSE} /* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. @@ -9,5 +10,15 @@ * 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; +} -#include "precompiled.h" diff --git a/Templates/DefaultProject/template.json b/Templates/DefaultProject/template.json index 56278a6b04..26b868d315 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", @@ -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", @@ -42,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", @@ -66,24 +78,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 +96,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 +114,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 +132,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 +150,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 +169,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 }, @@ -565,10 +475,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", @@ -588,6 +498,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", 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/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 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..c3ab29d09e --- /dev/null +++ b/cmake/EngineJson.cmake @@ -0,0 +1,47 @@ +# +# 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() + +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 +# 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/FindTarget.cmake.in b/cmake/FindTarget.cmake.in deleted file mode 100644 index 8ad9822dae..0000000000 --- a/cmake/FindTarget.cmake.in +++ /dev/null @@ -1,34 +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. -# - -# Generated by O3DE - -include(FindPackageHandleStandardArgs) - -ly_add_target( - NAME @NAME_PLACEHOLDER@ UNKNOWN IMPORTED - @NAMESPACE_PLACEHOLDER@ - COMPILE_DEFINITIONS - INTERFACE -@COMPILE_DEFINITIONS_PLACEHOLDER@ - INCLUDE_DIRECTORIES - INTERFACE -@INCLUDE_DIRECTORIES_PLACEHOLDER@ - BUILD_DEPENDENCIES - INTERFACE -@BUILD_DEPENDENCIES_PLACEHOLDER@ - RUNTIME_DEPENDENCIES -@RUNTIME_DEPENDENCIES_PLACEHOLDER@ -) - -foreach(config @CMAKE_CONFIGURATION_TYPES@) - include("${LY_ROOT_FOLDER}/cmake_autogen/@NAME_PLACEHOLDER@/@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) -endforeach() diff --git a/cmake/Gems.cmake b/cmake/Gems.cmake new file mode 100644 index 0000000000..d418d5dcd1 --- /dev/null +++ b/cmake/Gems.cmake @@ -0,0 +1,217 @@ +# +# 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() + # 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() + + # 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 GLOBAL) + set_target_properties(${ly_create_alias_NAME} PROPERTIES GEM_MODULE TRUE) + + foreach(target_name ${ly_create_alias_TARGETS}) + 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() + + 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}) + + # 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 +# 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. +# 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) + 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 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) + if(project_target_variant_length EQUAL 0) + continue() + endif() + + if(NOT project_target_variant_length EQUAL 3) + 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) + 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}) + # 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 the target exists, add it. + if (TARGET ${gem_name_with_namespace}.${variant}) + ly_add_target_dependencies( + ${PREFIX_CLAUSE} + TARGETS ${target} + DEPENDENT_TARGETS ${gem_name_with_namespace}.${variant} + ) + endif() + endforeach() + endforeach() +endfunction() \ No newline at end of file diff --git a/cmake/Install.cmake b/cmake/Install.cmake index b56f5ced85..205277f0e5 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -9,5 +9,7 @@ # 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) +endif() \ No newline at end of file diff --git a/cmake/LYPython.cmake b/cmake/LYPython.cmake index ff5132097c..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 @@ -265,10 +265,13 @@ 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. + 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() - 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) + ly_pip_install_local_package_editable(${LY_ROOT_FOLDER}/scripts/o3de o3de) endif() endif() diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index 8aba6ccb99..d7f88f12ec 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -53,7 +53,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. @@ -77,7 +76,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 GEM_STATIC SHARED MODULE GEM_MODULE HEADERONLY EXECUTABLE APPLICATION UNKNOWN IMPORTED AUTOMOC AUTOUIC AUTORCC NO_UNITY) + set(options STATIC SHARED MODULE GEM_STATIC 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) @@ -87,7 +86,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() @@ -106,23 +105,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) @@ -133,12 +136,11 @@ function(ly_add_target) set(linking_options APPLICATION) set(linking_count "${linking_count}1") endif() - if(ly_add_target_UNKNOWN) - set(linking_options UNKNOWN) - 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 ] was specified and they are mutually exclusive") + endif() + if(ly_add_target_IMPORTED) + list(APPEND target_type_options IMPORTED GLOBAL) endif() if(ly_add_target_NAMESPACE) @@ -149,29 +151,32 @@ 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}) + 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} + add_executable(${ly_add_target_NAME} + ${target_type_options} ${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} + ${target_type_options} ${ALLFILES} ${ly_add_target_GENERATED_FILES} ) - elseif(ly_add_target_UNKNOWN) - add_library(${ly_add_target_NAME} - ${linking_options} - IMPORTED - ) 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}) @@ -209,7 +214,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() @@ -306,10 +311,19 @@ 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}) + + # 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(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 @@ -337,22 +351,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} - 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_add_target_INSTALL_COMPONENT} - ) - endif() - endfunction() #! ly_target_link_libraries: wraps target_link_libraries handling also MODULE linkage. @@ -412,12 +410,10 @@ 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} $) - # 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}) @@ -513,7 +509,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 @@ -539,7 +535,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) @@ -555,7 +555,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}) @@ -658,42 +658,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 # @@ -735,7 +699,6 @@ function(ly_de_alias_target target_name output_variable_name) while(target_name) set(de_aliased_target_name ${target_name}) - get_target_property(target_name ${target_name} ALIASED_TARGET) endwhile() 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/O3DEJson.cmake b/cmake/O3DEJson.cmake new file mode 100644 index 0000000000..ab5f95bc8c --- /dev/null +++ b/cmake/O3DEJson.cmake @@ -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. +# + +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) + 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 array_count ERROR_VARIABLE manifest_json_error + LENGTH ${manifest_json_data} ${array_key}) + if(manifest_json_error) + # There is no key, return + return() + endif() + + 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 ${array_index} in \"${array_key}\" JSON array: ${manifest_json_error}") + endif() + list(APPEND array_elements ${array_element}) + endforeach() + endif() + set(${read_output_array} ${array_elements} 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/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") diff --git a/cmake/PAL.cmake b/cmake/PAL.cmake index 7802ac8c58..dca54e4731 100644 --- a/cmake/PAL.cmake +++ b/cmake/PAL.cmake @@ -22,7 +22,105 @@ 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: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) + 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}") + 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: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) + 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: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) + 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 +135,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 +207,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 +247,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/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 8fe2fe2c1c..b18aed6fb4 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -11,52 +11,57 @@ 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) -#! 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) +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}/$") - 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}) +#! 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 + # 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 ${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) + 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 ${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() - 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) + 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() - file(RELATIVE_PATH library_output_directory ${CMAKE_BINARY_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) install( - TARGETS ${ly_install_target_NAME} + TARGETS ${TARGET_NAME} ARCHIVE DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$ COMPONENT ${ly_install_target_COMPONENT} @@ -66,151 +71,184 @@ function(ly_install_target ly_install_target_NAME) RUNTIME DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$/${target_runtime_output_subdirectory} COMPONENT ${ly_install_target_COMPONENT} - PUBLIC_HEADER - DESTINATION ${include_location} - 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}) - 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() - - -#! 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}") + 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 - 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}") - endforeach() - string(REPLACE ";" "\n" INCLUDE_DIRECTORIES_PLACEHOLDER "${INCLUDE_DIRECTORIES_PLACEHOLDER}") + 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() - 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() - configure_file(${LY_ROOT_FOLDER}/cmake/FindTarget.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/Find${ly_generate_target_find_file_NAME}.cmake @ONLY) - -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) + 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) - 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 "ly_add_dependencies(${NAME} \"\${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(${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}_$_FOUND TRUE) -else() - set(${NAME}_$_FOUND FALSE) -endif() ") + endif() endif() - file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${NAME}_$.cmake" CONTENT "${target_file_contents}") + 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/InstalledTarget.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) + foreach(target IN LISTS all_subdirectories) + ly_setup_subdirectory(${target}) + endforeach() 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() +#! ly_setup_subdirectory: setup all targets in the subdirectory +function(ly_setup_subdirectory absolute_target_source_dir) + + # 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) + ly_setup_target(configured_target ${ALIAS_TARGET_NAME}) + string(APPEND all_configured_targets "${configured_target}") endforeach() - set(${INTERFACE_PROPERTIES} ${stripped_props} PARENT_SCOPE) -endfunction() + # 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() + 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}" + ) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/${target_source_dir}/CMakeLists.txt" + DESTINATION ${target_source_dir} + COMPONENT ${ly_install_target_COMPONENT} + ) + +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_subdirectories() ly_setup_cmake_install() ly_setup_target_generator() + ly_setup_runtime_dependencies() ly_setup_others() endfunction() @@ -218,16 +256,35 @@ endfunction() #! ly_setup_cmake_install: install the "cmake" folder function(ly_setup_cmake_install) - install(DIRECTORY "${CMAKE_SOURCE_DIR}/cmake" + install(DIRECTORY "${LY_ROOT_FOLDER}/cmake" DESTINATION . COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + PATTERN "__pycache__" EXCLUDE REGEX "Findo3de.cmake" EXCLUDE REGEX "Platform\/.*\/BuiltInPackages_.*\.cmake" EXCLUDE ) + + # Transform the LY_EXTERNAL_SUBDIRS list into a json array + set(indent " ") + foreach(external_subdir ${LY_EXTERNAL_SUBDIRS}) + file(RELATIVE_PATH engine_rel_external_subdir ${LY_ROOT_FOLDER} ${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) + install( FILES - "${CMAKE_SOURCE_DIR}/CMakeLists.txt" - "${CMAKE_SOURCE_DIR}/engine.json" + "${LY_ROOT_FOLDER}/CMakeLists.txt" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/engine.json" DESTINATION . COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) @@ -247,14 +304,16 @@ 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(target IN LISTS all_targets) - string(APPEND FIND_PACKAGES_PLACEHOLDER " find_package(${target})\n") + + # 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})\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} @@ -282,6 +341,74 @@ 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(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) + 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) @@ -294,15 +421,16 @@ function(ly_setup_others) set(install_path .) endif() - install(DIRECTORY "${CMAKE_SOURCE_DIR}/${dir}" + install(DIRECTORY "${LY_ROOT_FOLDER}/${dir}" DESTINATION ${install_path} COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} + PATTERN "__pycache__" EXCLUDE ) endforeach() # Scripts - file(GLOB o3de_scripts "${CMAKE_SOURCE_DIR}/scripts/o3de.*") + file(GLOB o3de_scripts "${LY_ROOT_FOLDER}/scripts/o3de.*") install(FILES ${o3de_scripts} DESTINATION ./scripts @@ -310,8 +438,9 @@ function(ly_setup_others) ) install(DIRECTORY - ${CMAKE_SOURCE_DIR}/scripts/bundler - ${CMAKE_SOURCE_DIR}/scripts/project_manager + ${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 @@ -319,7 +448,7 @@ function(ly_setup_others) PATTERN "tests" EXCLUDE ) - install(DIRECTORY "${CMAKE_SOURCE_DIR}/python" + install(DIRECTORY "${LY_ROOT_FOLDER}/python" DESTINATION . COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} REGEX "downloaded_packages" EXCLUDE @@ -328,36 +457,35 @@ function(ly_setup_others) # Registry install(DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR}/bin/$/Registry - DESTINATION ./bin/${PAL_PLATFORM_NAME}/$ + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/Registry + DESTINATION ./${runtime_output_directory}/${PAL_PLATFORM_NAME}/$ COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) install(DIRECTORY - ${CMAKE_SOURCE_DIR}/Registry + ${LY_ROOT_FOLDER}/Registry DESTINATION . COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Engine Source Assets install(DIRECTORY - ${CMAKE_SOURCE_DIR}/Assets + ${LY_ROOT_FOLDER}/Assets DESTINATION . COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # 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}/" + RELATIVE "${LY_ROOT_FOLDER}/" "Gems/*" ) list(FILTER gems_assets_path INCLUDE REGEX "/(Assets|Registry)$") foreach (gem_assets_path ${gems_assets_path}) - set(gem_abs_assets_path ${CMAKE_SOURCE_DIR}/${gem_assets_path}/) + set(gem_abs_assets_path ${LY_ROOT_FOLDER}/${gem_assets_path}/) if (EXISTS ${gem_abs_assets_path}) # The trailing slash is IMPORTANT here as that is needed to prevent # the "Assets" folder from being copied underneath the /Assets folder @@ -368,50 +496,62 @@ function(ly_setup_others) endif() endforeach() - # Qt Binaries - set(QT_DIRS bearer iconengines imageformats platforms styles translations) - list(TRANSFORM QT_DIRS PREPEND "${CMAKE_CURRENT_BINARY_DIR}/bin/$/" OUTPUT_VARIABLE QT_BIN_DIRS) + # gem.json files + file(GLOB_RECURSE + gems_json_path + LIST_DIRECTORIES FALSE + RELATIVE "${LY_ROOT_FOLDER}" + "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(DIRECTORY - ${QT_BIN_DIRS} - DESTINATION ./bin/${PAL_PLATFORM_NAME}/$ + ${LY_ROOT_FOLDER}/Gems/Atom/Asset/ImageProcessingAtom/Config + DESTINATION Gems/Atom/Asset/ImageProcessingAtom COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Templates install(DIRECTORY - ${CMAKE_SOURCE_DIR}/Templates + ${LY_ROOT_FOLDER}/Templates DESTINATION . COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) # Misc install(FILES - ${CMAKE_SOURCE_DIR}/ctest_pytest.ini - ${CMAKE_SOURCE_DIR}/LICENSE.txt - ${CMAKE_SOURCE_DIR}/README.md + ${LY_ROOT_FOLDER}/ctest_pytest.ini + ${LY_ROOT_FOLDER}/LICENSE.txt + ${LY_ROOT_FOLDER}/README.md DESTINATION . COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) endfunction() - #! ly_setup_target_generator: install source files needed for project launcher generation function(ly_setup_target_generator) install(FILES - ${CMAKE_SOURCE_DIR}/Code/LauncherUnified/launcher_generator.cmake - ${CMAKE_SOURCE_DIR}/Code/LauncherUnified/launcher_project_files.cmake - ${CMAKE_SOURCE_DIR}/Code/LauncherUnified/LauncherProject.cpp - ${CMAKE_SOURCE_DIR}/Code/LauncherUnified/StaticModules.in + ${LY_ROOT_FOLDER}/Code/LauncherUnified/launcher_generator.cmake + ${LY_ROOT_FOLDER}/Code/LauncherUnified/launcher_project_files.cmake + ${LY_ROOT_FOLDER}/Code/LauncherUnified/LauncherProject.cpp + ${LY_ROOT_FOLDER}/Code/LauncherUnified/StaticModules.in DESTINATION LauncherGenerator COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) - install(DIRECTORY ${CMAKE_SOURCE_DIR}/Code/LauncherUnified/Platform + install(DIRECTORY ${LY_ROOT_FOLDER}/Code/LauncherUnified/Platform DESTINATION LauncherGenerator COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) - install(FILES ${CMAKE_SOURCE_DIR}/Code/LauncherUnified/FindLauncherGenerator.cmake + install(FILES ${LY_ROOT_FOLDER}/Code/LauncherUnified/FindLauncherGenerator.cmake DESTINATION cmake COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} ) diff --git a/cmake/Platform/Common/RuntimeDependencies_common.cmake b/cmake/Platform/Common/RuntimeDependencies_common.cmake index 6ac5215a01..d9d0fe4c7f 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. @@ -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) @@ -183,7 +187,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,20 +210,25 @@ 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(aliased_target IN LISTS all_targets) - unset(runtime_dependencies) - set(runtime_commands " + 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) + continue() + endif() + + 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}\") @@ -232,21 +241,23 @@ function(ly_copy source_file target_directory) endif() endif() endfunction() -\n") + \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}" + ) - 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 - 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/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/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}") 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 d558c6f12a..a2a6d30593 100644 --- a/cmake/Platform/iOS/RuntimeDependencies_ios.cmake +++ b/cmake/Platform/iOS/RuntimeDependencies_ios.cmake @@ -118,57 +118,65 @@ 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(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) + 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 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}) diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index e1c07f4492..4d932601b4 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@"] }]] ) @@ -81,39 +81,78 @@ 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 +# +# \arg:gem_target(TARGET) - Target to look upwards from using its SOURCE_DIR property +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) + + 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}) + endif() + + # 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_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 # 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() # 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 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) + # 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}) + 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) @@ -121,16 +160,18 @@ 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 CMakeLists.txt files reside in the /Code/ so remove "Code/" from the path - if(gem_relative_source_dir MATCHES ".*/Code$") - get_filename_component(gem_relative_source_dir ${gem_relative_source_dir} DIRECTORY) - endif() - 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}) + + 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() + + 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}) + # De-alias namespace from gem targets before configuring them into the json template ly_de_alias_target(${gem_target} stripped_gem_target) string(CONFIGURE ${gem_module_template} gem_module_json @ONLY) @@ -144,7 +185,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") 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/Tools/global_project.py b/cmake/Tools/global_project.py deleted file mode 100644 index 1d84d9dcfb..0000000000 --- a/cmake/Tools/global_project.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. -# - -import argparse -import logging -import os -import sys -import re -import pathlib -import json -import cmake.Tools.registration as registration - -logger = logging.getLogger() -logging.basicConfig() - - -def set_global_project(project_name: str or None, - project_path: str or pathlib.Path or None) -> 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 - :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 - - if not project_name and not project_path: - logger.error('Must specify either a Project name or Project Path.') - return 1 - - if project_name and not project_path: - project_path = registration.get_registered(project_name=project_name) - - if not project_path: - logger.error(f'Project Path {project_path} has not been registered.') - return 1 - - project_path = pathlib.Path(project_path).resolve() - - bootstrap_setreg_file = registration.get_o3de_registry_folder() / 'bootstrap.setreg' - if bootstrap_setreg_file.is_file(): - with bootstrap_setreg_file.open('r') as f: - try: - json_data = json.load(f) - except Exception 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: - logger.error(f'Bootstrap.setreg failed to load: {str(e)}') - else: - try: - os.unlink(bootstrap_setreg_file) - except Exception 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()}}}}) - - with bootstrap_setreg_file.open('w') as s: - s.write(json.dumps(json_data, indent=4)) - - return 0 - - -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' - if not bootstrap_setreg_file.is_file(): - logger.error(f'Bootstrap.setreg file {bootstrap_setreg_file} does not exist.') - return None - - with bootstrap_setreg_file.open('r') as f: - try: - json_data = json.load(f) - except Exception 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: - logger.error(f'Bootstrap.setreg cannot find Amazon:AzCore:Bootstrap:project_path: {str(e)}') - else: - return pathlib.Path(project_path).resolve() - return None - -def _run_get_global_project(args: argparse) -> int: - if args.override_home_folder: - registration.override_home_folder = args.override_home_folder - - project_path = get_global_project() - if project_path: - print(project_path.as_posix()) - return 0 - return 1 - - -def _run_set_global_project(args: argparse) -> int: - if args.override_home_folder: - registration.override_home_folder = args.override_home_folder - - return set_global_project(args.project_name, - args.project_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 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 - :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') - 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) - - -if __name__ == "__main__": - # parse the command line args - the_parser = argparse.ArgumentParser() - - # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') - - # 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) - - # return - sys.exit(ret) diff --git a/cmake/Tools/registration.py b/cmake/Tools/registration.py deleted file mode 100755 index b13419414b..0000000000 --- a/cmake/Tools/registration.py +++ /dev/null @@ -1,4439 +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 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[2].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: - restricted_folder = get_o3de_folder() / 'Logs' - restricted_folder.mkdir(parents=True, exist_ok=True) - return restricted_folder - - -def register_shipped_engine_o3de_objects() -> 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) - 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) - 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) - 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) - 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) - 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) - 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) - 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')) - 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, supress_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) -> 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(name) - - for engine in sorted(engines_set, reverse=True): - error_code = register(engine_path=engine, remove=remove) - 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 register_engine_path(json_data: dict, - engine_path: str or pathlib.Path, - remove: 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']: - 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 - - 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['engines'].insert(0, engine_object) - - return 0 - - -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 - ) -> 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 - - :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) - - 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 _validate_engine_name_and_path(engine_name: str = None, - engine_path: str or pathlib.Path = None) -> pathlib.Path 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 - - return engine_json - -def get_engine_data(engine_name: str = None, - engine_path: str or pathlib.Path = None ) -> dict or None: - engine_json = _validate_engine_name_and_path(engine_name, engine_path) - if not engine_json: - 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 set_engine_data(engine_name: str = None, - engine_path: str or pathlib.Path = None, - engine_data: dict = None ) -> int: - if not engine_data: - logger.error('Must provide engine data.') - return 1 - - engine_json = _validate_engine_name_and_path(engine_name, engine_path) - if not engine_json: - return 1 - - with engine_json.open('w') as f: - try: - json.dump(engine_data, f, indent=4) - except Exception as e: - logger.warn(f'Failed to load or write {engine_json}: {str(e)}') - return 1 - - return 0 - - -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 - - 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 - - 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 - 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 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 _validate_gem_name_and_path(gem_name: str = None, - gem_path: str or pathlib.Path = None) -> pathlib.Path 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 - - return gem_json - - -def get_gem_data(gem_name: str = None, - gem_path: str or pathlib.Path = None) -> dict or None: - gem_json = _validate_gem_name_and_path(gem_name, gem_path) - if not gem_json: - 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 set_gem_data(gem_name: str = None, - gem_path: str or pathlib.Path = None, - gem_data: dict = None) -> int: - if not gem_data: - logger.error('Must provide Gem data.') - return 1 - - gem_json = _validate_gem_name_and_path(gem_name, gem_path) - if not gem_json: - return 1 - - with gem_json.open('w') as f: - try: - json.dump(gem_data, f, indent=4) - except Exception as e: - logger.warn(f'Failed to load and write {gem_json}: {str(e)}') - return 1 - - return 0 - - -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 - - 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 - - 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 - if not valid_o3de_template_json(template_json): - logger.error(f'Template json {template_json} is not valid.') - return 1 - - 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 1 - - 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 - - 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 - if not valid_o3de_restricted_json(restricted_json): - logger.error(f'Restricted json {restricted_json} is not valid.') - return 1 - - 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, - supress_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 - :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: - 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: - 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: - 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 supress_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, - supress_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 - :return: 0 for success or non 0 failure code - """ - if not gem_name and not gem_path: - if not supress_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 supress_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: - logger.error(f'Gem json {gem_json} is not present.') - return 1 - if not valid_o3de_gem_json(gem_json): - if not supress_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 supress_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: - logger.error(f'Engine json {engine_json} is not present.') - return 1 - if not valid_o3de_engine_json(engine_json): - if not supress_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) - - -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()) - error_code = register_shipped_engine_o3de_objects() - 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) - 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) - - -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: - """ - 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.set_defaults(func=_run_register) - - # 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) - - # 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) - - # 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) - - # 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) - - # 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) - - # 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) - - # 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) - - # 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) - - # 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) - - # 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) - - -if __name__ == "__main__": - # parse the command line args - the_parser = argparse.ArgumentParser() - - # add subparsers - the_subparsers = the_parser.add_subparsers(help='sub-command help') - - # 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) - - # return - sys.exit(ret) diff --git a/cmake/Tools/unit_test_add_remove_gem.py b/cmake/Tools/unit_test_add_remove_gem.py deleted file mode 100755 index 81f0fa615e..0000000000 --- a/cmake/Tools/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 . import add_remove_gem - -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_remove_gem.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/cmake/Tools/utils.py b/cmake/Tools/utils.py deleted file mode 100755 index 37c84ea331..0000000000 --- a/cmake/Tools/utils.py +++ /dev/null @@ -1,47 +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 utility functions -""" - -import uuid - - -def validate_identifier(identifier: str) -> bool: - """ - Determine if the identifier supplied is valid. - :param identifier: the name which needs to to checked - :return: bool: if the identifier is valid or not - """ - if not identifier: - return False - elif len(identifier) > 64: - return False - elif not identifier[0].isalpha(): - return False - else: - for character in identifier: - if not (character.isalnum() or character == '_' or character == '-'): - return False - return True - - -def validate_uuid4(uuid_string: str) -> bool: - """ - Determine if the uuid supplied is valid. - :param uuid_string: the uuid which needs to to checked - :return: bool: if the uuid is valid or not - """ - try: - val = uuid.UUID(uuid_string, version=4) - except ValueError: - return False - return str(val) == uuid_string 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/cmake_files.cmake b/cmake/cmake_files.cmake index e423eb0dbc..a1fd66a06d 100644 --- a/cmake/cmake_files.cmake +++ b/cmake/cmake_files.cmake @@ -12,20 +12,25 @@ set(FILES 3rdParty.cmake 3rdPartyPackages.cmake + CMakeFiles.cmake CommandExecution.cmake Configurations.cmake Dependencies.cmake Deployment.cmake - EngineFinder.cmake + EngineJson.cmake FileUtil.cmake Findo3de.cmake + Gems.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/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/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/install/InstalledTarget.in b/cmake/install/InstalledTarget.in new file mode 100644 index 0000000000..0503fd5f2b --- /dev/null +++ b/cmake/install/InstalledTarget.in @@ -0,0 +1,23 @@ + +# Generated by O3DE + +ly_add_target( + NAME @NAME_PLACEHOLDER@ IMPORTED @TARGET_TYPE_PLACEHOLDER@ + @NAMESPACE_PLACEHOLDER@ + COMPILE_DEFINITIONS + INTERFACE +@COMPILE_DEFINITIONS_PLACEHOLDER@ + INCLUDE_DIRECTORIES + INTERFACE +@INCLUDE_DIRECTORIES_PLACEHOLDER@ + BUILD_DEPENDENCIES + INTERFACE +@INTERFACE_BUILD_DEPENDENCIES_PLACEHOLDER@ + RUNTIME_DEPENDENCIES +@RUNTIME_DEPENDENCIES_PLACEHOLDER@ +) + +set(configs @CMAKE_CONFIGURATION_TYPES@) +foreach(config ${configs}) + include("@NAME_PLACEHOLDER@_${config}.cmake" OPTIONAL) +endforeach() diff --git a/cmake/install/engine.json.in b/cmake/install/engine.json.in new file mode 100644 index 0000000000..ce2e1be25c --- /dev/null +++ b/cmake/install/engine.json.in @@ -0,0 +1,11 @@ +{ + "engine_name": "@LY_VERSION_ENGINE_NAME@", + "restricted_name": "o3de", + "FileVersion": 1, + "O3DEVersion": "@LY_VERSION_STRING@", + "O3DECopyrightYear": @LY_VERSION_COPYRIGHT_YEAR@, + "O3DEBuildNumber": @LY_VERSION_BUILD_NUMBER@, + "external_subdirectories": [@LY_INSTALL_EXTERNAL_SUBDIRS@], + "projects": [@LY_INSTALL_PROJECTS@], + "templates": [@LY_INSTALL_TEMPLATES@] +} diff --git a/cmake/o3de_manifest.cmake b/cmake/o3de_manifest.cmake deleted file mode 100644 index 1585ec2d2f..0000000000 --- a/cmake/o3de_manifest.cmake +++ /dev/null @@ -1,986 +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) - 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) - 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) - 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} - 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) - message(STATUS "O3DE_REGISTER_RESTRICTED_PATHS=${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) - message(STATUS "O3DE_REGISTER_PROJECT_PATHS=${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) - message(STATUS "O3DE_REGISTER_GEM_PATHS=${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) - message(STATUS "O3DE_REGISTER_TEMPLATE_PATHS=${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) - message(STATUS "O3DE_REGISTER_REPO_URIS=${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) -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() - -################################################################################ -# 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) -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() - -################################################################################ -# 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() - -################################################################################ -# 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() - -################################################################################ -# 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() - -################################################################################ -# 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() - -################################################################################ -# 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() diff --git a/engine.json b/engine.json index 22ac2512f5..09bb3f5ff6 100644 --- a/engine.json +++ b/engine.json @@ -1,7 +1,98 @@ { "engine_name": "o3de", - "restricted": "o3de", + "restricted_name": "o3de", "FileVersion": 1, "O3DEVersion": "0.0.0.0", - "O3DECopyrightYear": 2021 + "O3DECopyrightYear": 2021, + "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" + ] } 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% 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/build/Platform/Android/build_config.json b/scripts/build/Platform/Android/build_config.json index fe5e223612..adaa417380 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 610c6a6514..ee6da77b29 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) -LE SUITE_sandbox -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) -LE SUITE_sandbox -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)" @@ -175,7 +175,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)" @@ -191,7 +191,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" } @@ -206,7 +206,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 bcaffce880..971e5e47a1 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..38cd7d6ad8 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", "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" 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 d689c600a1..2d9c57f6ee 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" 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% diff --git a/scripts/o3de.py b/scripts/o3de.py index dbb9c53e4b..8d7532878c 100755 --- a/scripts/o3de.py +++ b/scripts/o3de.py @@ -10,23 +10,54 @@ # 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) - -from cmake.Tools import engine_template -from cmake.Tools import global_project -from cmake.Tools import registration 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} / 'o3de' is added to the front of the sys.path + script_dir = pathlib.Path(__file__).parent + 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, \ + enable_gem, disable_gem, sha256 + # Remove the temporarily added path + sys.path = sys.path[1:] + + # 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) + + # add a gem to a project + enable_gem.add_args(subparsers) + + # remove a gem from a project + disable_gem.add_args(subparsers) + + # sha256 + sha256.add_args(subparsers) if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake b/scripts/o3de/CMakeLists.txt similarity index 91% rename from AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake rename to scripts/o3de/CMakeLists.txt index 933dd7927b..9819c1cd6e 100644 --- a/AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake +++ b/scripts/o3de/CMakeLists.txt @@ -9,6 +9,4 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -set(GEM_DEPENDENCIES - Gem::QtForPython.Editor -) \ No newline at end of file +add_subdirectory(tests) 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/o3de/__init__.py b/scripts/o3de/o3de/__init__.py new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/scripts/o3de/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/o3de/cmake.py b/scripts/o3de/o3de/cmake.py new file mode 100644 index 0000000000..dfcce708eb --- /dev/null +++ b/scripts/o3de/o3de/cmake.py @@ -0,0 +1,106 @@ +# +# 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 query CMake gem target information +""" + +import logging +import os +import pathlib + +from o3de import manifest + +logger = logging.getLogger() +logging.basicConfig() + +def get_project_gems(project_path: pathlib.Path, + platform: str = 'Common') -> set: + return get_gems_from_cmake_file(get_enabled_gem_cmake_file(project_path=project_path, platform=platform)) + + +def get_enabled_gems(cmake_file: pathlib.Path) -> set: + """ + Gets a list of enabled gems from the 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() + + 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: + 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 + + +def get_project_gem_paths(project_path: pathlib.Path, + platform: str = 'Common') -> set: + 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_enabled_gem_cmake_file(project_name: str = None, + project_path: str or pathlib.Path = 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 + :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() + enable_gem_filename = "enabled_gems.cmake" + + if platform == 'Common': + 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: + 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/disable_gem.py b/scripts/o3de/o3de/disable_gem.py new file mode 100644 index 0000000000..61d71445f0 --- /dev/null +++ b/scripts/o3de/o3de/disable_gem.py @@ -0,0 +1,211 @@ +# +# 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 +""" + +import argparse +import logging +import os +import pathlib +import sys + +from o3de import cmake, manifest + +logger = logging.getLogger() +logging.basicConfig() + + +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_name: name of the gem + :return: 0 for success or non 0 failure code + """ + 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_name} + t_data = [] + # 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 gem_name == line.strip(): + removed = True + else: + t_data.append(line) + + if not removed: + logger.error(f'Failed to remove {gem_name} from cmake file {cmake_file}') + return 1 + + # write the cmake + with open(cmake_file, 'w') as s: + s.writelines(t_data) + + return 0 + + +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: + """ + 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 + :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) + if not project_path: + logger.error(f'Unable to locate project path from the registered manifest.json files:' + f' {str(pathlib.Path("~/.o3de/o3de_manifest.json").expanduser())}, engine.json') + return 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 + + # 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) + 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 + + + # 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 + + # 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 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_disable_gem_in_project(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + return disable_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 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) + 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=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('-egf', '--enabled-gem-file', type=pathlib.Path, required=False, + help='The cmake enabled gem file in which gem names are to be removed from.' + 'If not specified it will assume ') + + 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_disable_gem_in_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 disable-gem-from-cmake --project-path D:/Test --gem-name Atom + :param subparsers: the caller instantiates subparsers and passes it in here + """ + disable_gem_project_subparser = subparsers.add_parser('disable-gem') + add_parser_args(disable_gem_project_subparser) + + +def main(): + """ + Runs disable_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 new file mode 100644 index 0000000000..6f1b82e754 --- /dev/null +++ b/scripts/o3de/o3de/download.py @@ -0,0 +1,240 @@ +# +# 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. +# +""" +Implements functionality for downloading o3de objecs either locally or from a URI +""" + +import argparse +import hashlib +import json +import logging +import pathlib +import shutil +import sys +import urllib.parse +import urllib.request + +from o3de import manifest, repo, utils, validation + +logger = logging.getLogger() +logging.basicConfig() + +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=default_folder_name) + 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() / default_folder_name / object_name + download_path.mkdir(exist_ok=True) + download_zip_path = download_path / f'{object_type}.zip' + + 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_json_data['origin'] + url = f'{origin}/object_type.zip' + parsed_uri = urllib.parse.urlparse(url) + + download_zip_result = utils.download_zip_file(parsed_uri, download_zip_path) + if download_zip_result != 0: + return download_zip_result + + return validate_downloaded_zip_sha256(downloadable_object_data, download_zip_path) + + +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: + 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: + 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: + return download_o3de_object(template_name, 'templates', dest_path, 'template', 'template_name') + + + +def download_restricted(restricted_name: str, + dest_path: str or pathlib.Path) -> int: + return download_o3de_object(restricted_name, 'restricted', dest_path, 'restricted', 'restricted_name') + + +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) + + return 1 + +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 download.py --engine-name "o3de" + :param parser: the caller passes an argparse parser like instance to this method + """ + 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, + 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.') + parser.add_argument('-dp', '--dest-path', type=str, required=False, + default=None, + help='Optional destination folder to download into.' + ' 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') + + 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_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) + + +# Do not allow running the download.py script as a standalone script until it is reviewed by app-sec diff --git a/scripts/o3de/o3de/enable_gem.py b/scripts/o3de/o3de/enable_gem.py new file mode 100644 index 0000000000..0dee01e05e --- /dev/null +++ b/scripts/o3de/o3de/enable_gem.py @@ -0,0 +1,231 @@ +# +# 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 enabled_gem.cmake file +""" + +import argparse +import json +import logging +import os +import pathlib +import sys + +from o3de import cmake, manifest, validation + +logger = logging.getLogger() +logging.basicConfig() + +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_name: name of the gem + :return: 0 for success or non 0 failure code + """ + 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_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 '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 + t_data.append(line) + line_index += 1 + + + 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: + t_data.append('\n') + t_data.append('set(ENABLED_GEMS\n') + t_data.append(f'{" " * indent}{gem_name}\n') + t_data.append(')\n') + + # write the cmake + with open(cmake_file, 'w') as s: + s.writelines(t_data) + + return 0 + + +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: + """ + 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 + :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) + 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 + + # 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) + if not gem_path: + logger.error(f'Unable to locate gem path from the registered manifest.json files:' + f' {str(pathlib.Path( "~/.o3de/o3de_manifest.json").expanduser())},' + 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 + + # 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 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 gem + ret_val = add_gem_dependency(enabled_gem_file, gem_json_data['gem_name']) + + else: + # 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_enable_gem_in_project(args: argparse) -> int: + if args.override_home_folder: + manifest.override_home_folder = args.override_home_folder + + 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 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) + 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=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('-egf', '--enabled-gem-file', type=pathlib.Path, required=False, + 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('-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_enable_gem_in_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 + """ + enable_gem_project_subparser = subparsers.add_parser('enable-gem') + add_parser_args(enable_gem_project_subparser) + + +def main(): + """ + Runs enable_gem.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/cmake/Tools/engine_template.py b/scripts/o3de/o3de/engine_template.py similarity index 93% rename from cmake/Tools/engine_template.py rename to scripts/o3de/o3de/engine_template.py index 78de209ab4..63dec3e765 100755 --- a/cmake/Tools/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 manifest, validation, utils logger = logging.getLogger() logging.basicConfig() @@ -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, @@ -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 @@ -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: @@ -403,11 +403,11 @@ 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): - 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 @@ -419,28 +419,28 @@ 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: 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'] - except Exception as e: + engine_restricted = engine_json_data['restricted_name'] + except KeyError 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,21 +466,21 @@ 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: 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: @@ -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}) @@ -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) @@ -1048,7 +1047,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 +1058,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 @@ -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 @@ -1082,57 +1081,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'] - 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".') + template_json_restricted_name = template_json_data['restricted_name'] + 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: 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'] - 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".' + template_json_restricted_name = template_json_data['restricted_name'] + 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}') 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'] - 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".' + template_json_restricted_name = template_json_data['restricted_name'] + 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}') 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 @@ -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 = '' @@ -1203,19 +1202,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,8 +1336,12 @@ 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 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 @@ -1348,7 +1351,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 @@ -1356,14 +1359,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 @@ -1371,57 +1374,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'] - 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".') + template_json_restricted_name = template_json_data['restricted_name'] + 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: 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'] - 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".' + template_json_restricted_name = template_json_data['restricted_name'] + 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}') 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'] - 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".' + template_json_restricted_name = template_json_data['restricted_name'] + 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}') 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 @@ -1442,7 +1445,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 +1466,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: @@ -1475,7 +1478,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 +1499,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 +1588,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: @@ -1597,35 +1600,35 @@ 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 - # 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 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 - 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: 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 @@ -1652,10 +1655,22 @@ 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_data = manifest.get_engine_json_data(engine_path=manifest.get_this_engine_path()) + try: + engine_name = engine_json_data['engine_name'] + except KeyError as e: + logger.error(f"engine_name for this engine not found in engine.json.") + return 1 + + project_json_data = manifest.get_project_json_data(project_path=project_path) + project_json_data.update({"engine": engine_name}) + with open(project_json, 'w') as s: + try: + s.write(json.dumps(project_json_data, indent=4)) + except OSError as e: + logger.error(f'Failed to write project json at {project_path}.') + return 1 return 0 @@ -1718,7 +1733,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 +1744,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 @@ -1737,14 +1752,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 @@ -1752,56 +1767,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'] - 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".') + template_json_restricted_name = template_json_data['restricted_name'] + 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: 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'] - 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".' + template_json_restricted_name = template_json_data['restricted_name'] + 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}') 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'] - 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".' + template_json_restricted_name = template_json_data['restricted_name'] + 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}') 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 @@ -1821,7 +1836,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}') @@ -1842,7 +1857,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: @@ -1854,7 +1869,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 +1890,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 +1979,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: @@ -1976,35 +1991,35 @@ 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 - # 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 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 - 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: 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 @@ -2098,15 +2113,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 @@ -2116,7 +2130,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 +2139,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.') @@ -2423,16 +2437,16 @@ 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) + add_args(the_subparsers) # parse args 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/get_registration.py b/scripts/o3de/o3de/get_registration.py new file mode 100644 index 0000000000..d51600826c --- /dev/null +++ b/scripts/o3de/o3de/get_registration.py @@ -0,0 +1,96 @@ +# +# 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 +import sys + +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_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 get_registration.py --engine-name "o3de" + :param parser: the caller passes an argparse parser like instance to this method + """ + 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, + 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.') + + 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_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 new file mode 100644 index 0000000000..d165510250 --- /dev/null +++ b/scripts/o3de/o3de/global_project.py @@ -0,0 +1,214 @@ +# +# 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 logging +import os +import sys +import re +import pathlib +import json + +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 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: + """ + 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 + """ + # 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) + + if not project_path: + 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 + + # 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 + + # 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: + 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 + + # 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(input_path: pathlib.Path) -> pathlib.Path or None: + """ + Retrieves the /Amazon/AzCore/Bootstrap/project_path key from the supplied file path + :return: project_path or None on failure + """ + setreg_json_data = get_json_data(input_path) + + 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: + project_path = get_global_project(args.input_path) + if project_path: + print(project_path.as_posix()) + return 0 + return 1 + + +def _run_set_global_project(args: argparse) -> int: + return set_global_project(args.output_path, + args.project_name, + args.project_path, + args.force) + + +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 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_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) + + +def main(): + """ + Runs this script as standalone script + """ + # parse the command line args + the_parser = argparse.ArgumentParser() + + # add subparsers + 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(project_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) + + +if __name__ == "__main__": + main() diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py new file mode 100644 index 0000000000..9436e1dd29 --- /dev/null +++ b/scripts/o3de/o3de/manifest.py @@ -0,0 +1,675 @@ +# +# 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 functions for data from json files such as the o3de_manifests.json, engine.json, project.json, etc... +""" + +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({'external_subdirectories': []}) + 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) + '\n') + 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) + '\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) + '\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) + '\n') + + with manifest_path.open('w') as s: + s.write(json.dumps(json_data, indent=4) + '\n') + + return manifest_path + + +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: + logger.error(f'Manifest json failed to load: {str(e)}') + return {} + else: + return json_data + + +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) + '\n') + except OSError 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() -> list: + json_data = load_o3de_manifest() + return json_data['engines'] + + +def get_projects() -> list: + json_data = load_o3de_manifest() + return json_data['projects'] + + +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_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'] + + +def get_restricted() -> list: + json_data = load_o3de_manifest() + return json_data['restricted'] + + +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) + 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_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) + 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 [] + + +# 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(project_path) + 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 [] + + +# Combined manifest queries +def get_all_projects() -> list: + projects_data = set(get_projects()) + projects_data.update(get_engine_projects()) + return list(projects_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: + 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(): + 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() + 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 json.JSONDecodeError 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 json.JSONDecodeError 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 json.JSONDecodeError 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 json.JSONDecodeError 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 json.JSONDecodeError 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 json.JSONDecodeError 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): + enging_projects = get_engine_projects() + 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 json.JSONDecodeError 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): + gems = get_all_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 json.JSONDecodeError 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_templates = get_engine_templates() + templates = json_data['templates'].copy() + templates.extend(engine_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 json.JSONDecodeError 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_restricted = get_engine_restricted() + restricted = json_data['restricted'].copy() + restricted.extend(engine_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 json.JSONDecodeError 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 json.JSONDecodeError 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..292f2224bc --- /dev/null +++ b/scripts/o3de/o3de/print_registration.py @@ -0,0 +1,490 @@ +# +# 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 sys +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 json.JSONDecodeError as e: + logger.warn(f'{engine_json} failed to load: {str(e)}') + else: + print(engine_json) + print(json.dumps(engine_json_data, indent=4)) + print('\n') + + +def print_projects_data(projects_data: dict) -> None: + print('\n') + print("Projects================================================") + for project_uri in projects_data: + # if it's not local it should be in the cache + parsed_uri = urllib.parse.urlparse(project_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + repo_sha256 = hashlib.sha256(project_uri.encode()) + cache_folder = manifest.get_o3de_cache_folder() + project_json = cache_folder / str(repo_sha256.hexdigest() + '.json') + else: + project_json = pathlib.Path(project_uri).resolve() / 'project.json' + + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warn(f'{project_json} failed to load: {str(e)}') + else: + print(project_json) + print(json.dumps(project_json_data, indent=4)) + print('\n') + + +def print_gems_data(gems_data: dict) -> None: + print('\n') + print("Gems================================================") + for gem_uri in gems_data: + # if it's not local it should be in the cache + parsed_uri = urllib.parse.urlparse(gem_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + repo_sha256 = hashlib.sha256(gem_uri.encode()) + cache_folder = manifest.get_o3de_cache_folder() + gem_json = cache_folder / str(repo_sha256.hexdigest() + '.json') + else: + gem_json = pathlib.Path(gem_uri).resolve() / 'gem.json' + + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warn(f'{gem_json} failed to load: {str(e)}') + else: + print(gem_json) + print(json.dumps(gem_json_data, indent=4)) + print('\n') + + +def print_templates_data(templates_data: dict) -> None: + print('\n') + print("Templates================================================") + for template_uri in templates_data: + # if it's not local it should be in the cache + parsed_uri = urllib.parse.urlparse(template_uri) + if parsed_uri.scheme == 'http' or \ + parsed_uri.scheme == 'https' or \ + parsed_uri.scheme == 'ftp' or \ + parsed_uri.scheme == 'ftps': + repo_sha256 = hashlib.sha256(template_uri.encode()) + cache_folder = manifest.get_o3de_cache_folder() + template_json = cache_folder / str(repo_sha256.hexdigest() + '.json') + else: + template_json = pathlib.Path(template_uri).resolve() / 'template.json' + + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warn(f'{template_json} failed to load: {str(e)}') + else: + print(template_json) + print(json.dumps(template_json_data, indent=4)) + print('\n') + + +def print_repos_data(repos_data: dict) -> None: + 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 json.JSONDecodeError 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 json.JSONDecodeError as e: + logger.warn(f'{restricted_json} failed to load: {str(e)}') + else: + print(restricted_json) + print(json.dumps(restricted_json_data, indent=4)) + print('\n') + + +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_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 print_registration.py --engine-projects + :param parser: the caller passes an argparse parser like instance to this method + """ + 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.') + + 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.') + + parser.add_argument('-v', '--verbose', action='count', required=False, + default=0, + help='How verbose do you want the output to be.') + + 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_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 new file mode 100644 index 0000000000..68575488dc --- /dev/null +++ b/scripts/o3de/o3de/register.py @@ -0,0 +1,864 @@ + +# +# 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 sys +import urllib.parse +import urllib.request + +from o3de import get_registration, manifest, 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_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 + + 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 + + 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(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 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: + 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: 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) + + +def register_all_templates_in_folder(templates_path: str or pathlib.Path, + remove: bool = False, + engine_path: str or pathlib.Path = None) -> int: + 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: + 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: + 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, + 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()}) + + json_data.setdefault('engines', []).insert(0, engine_object) + + return add_engine_name_to_path(json_data, engine_path, force) + + +def register_o3de_object_path(json_data: dict, + o3de_object_path: str or pathlib.Path, + o3de_object_key: str, + 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: 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: + result = register_o3de_object_path(json_data, project_path, 'projects', 'project.json', + validation.valid_o3de_project_json, remove, engine_path, None) + + if result != 0: + return result + + # registering a project has the additional step of setting the project.json 'engine' field + 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: + update_project_json = project_json_data['engine'] != this_engine_json['engine_name'] + except KeyError as e: + update_project_json = True + + if update_project_json: + project_json_data['engine'] = this_engine_json['engine_name'] + utils.backup_file(project_json) + if not manifest.save_o3de_manifest(project_json_data, project_path): + 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: + 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: + 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, + 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 in ['http', 'https', 'ftp', '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 = utils.download_file(url, cache_file) + if result == 0: + json_data['repos'].insert(0, repo_uri.as_posix()) + + 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: + 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: + 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: + 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: + 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, + 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, + 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, + 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, + 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 + + :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 + :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 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 + + :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, + 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: + 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) + + 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 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.") + 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, + external_subdir_path=args.external_subdirectory, + 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, + external_subdir_engine_path=args.external_subdirectory_engine_path, + external_subdir_project_path=args.external_subdirectory_project_path, + remove=args.remove, + force=args.force) + + +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 register.py --engine-path "C:/o3de" + :param parser: the caller passes an argparse parser like instance to this method + """ + 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.') + 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('-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, + 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.') + + 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.add_argument('-r', '--remove', action='store_true', required=False, + default=False, + 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) + + +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/repo.py b/scripts/o3de/o3de/repo.py new file mode 100644 index 0000000000..c6b4874b6a --- /dev/null +++ b/scripts/o3de/o3de/repo.py @@ -0,0 +1,160 @@ +# +# 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, 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() + 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 json.JSONDecodeError as e: + logger.error(f'{file_name} failed to load: {str(e)}') + return 1 + + 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(): + 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 + + +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) + 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.') + 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_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: + + if isinstance(engine_name, str) or isinstance(engine_name, pathlib.PurePath): + 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): + 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): + 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): + 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): + 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: + 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/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 diff --git a/scripts/o3de/o3de/sha256.py b/scripts/o3de/o3de/sha256.py new file mode 100644 index 0000000000..db0a1fe834 --- /dev/null +++ b/scripts/o3de/o3de/sha256.py @@ -0,0 +1,117 @@ +# +# 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 +import pathlib +import sys + +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 json.JSONDecodeError 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) + '\n') + except OSError 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_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 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') + 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 new file mode 100755 index 0000000000..4330de25b8 --- /dev/null +++ b/scripts/o3de/o3de/utils.py @@ -0,0 +1,112 @@ +# +# 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 functions +""" + +import uuid +import pathlib +import shutil +import urllib.request + +def validate_identifier(identifier: str) -> bool: + """ + Determine if the identifier supplied is valid. + :param identifier: the name which needs to to checked + :return: bool: if the identifier is valid or not + """ + if not identifier: + return False + elif len(identifier) > 64: + return False + elif not identifier[0].isalpha(): + return False + else: + for character in identifier: + if not (character.isalnum() or character == '_' or character == '-'): + return False + return True + + +def validate_uuid4(uuid_string: str) -> bool: + """ + Determine if the uuid supplied is valid. + :param uuid_string: the uuid which needs to to checked + :return: bool: if the uuid is valid or not + """ + try: + val = uuid.UUID(uuid_string, version=4) + 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 + + +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 new file mode 100644 index 0000000000..721b7eae09 --- /dev/null +++ b/scripts/o3de/o3de/validation.py @@ -0,0 +1,102 @@ +# +# 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 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(): + 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 (json.JSONDecodeError, KeyError) 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'] + except (json.JSONDecodeError, KeyError) 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'] + except (json.JSONDecodeError, KeyError) 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'] + except (json.JSONDecodeError, KeyError) 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'] + except (json.JSONDecodeError, KeyError) 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'] + except (json.JSONDecodeError, KeyError) as e: + return False + return True 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={ + }, + ) diff --git a/scripts/o3de/tests/CMakeLists.txt b/scripts/o3de/tests/CMakeLists.txt new file mode 100644 index 0000000000..0526c7740d --- /dev/null +++ b/scripts/o3de/tests/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# 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_register.py + 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 +) + +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/__init__.py b/scripts/o3de/tests/__init__.py new file mode 100644 index 0000000000..4d5680a30d --- /dev/null +++ b/scripts/o3de/tests/__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/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/cmake/Tools/unit_test_engine_template.py b/scripts/o3de/tests/unit_test_engine_template.py similarity index 100% rename from cmake/Tools/unit_test_engine_template.py rename to scripts/o3de/tests/unit_test_engine_template.py diff --git a/scripts/o3de/tests/unit_test_global_project.py b/scripts/o3de/tests/unit_test_global_project.py new file mode 100644 index 0000000000..1d3a4dd4f4 --- /dev/null +++ b/scripts/o3de/tests/unit_test_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_register.py b/scripts/o3de/tests/unit_test_register.py new file mode 100644 index 0000000000..eb866e76d4 --- /dev/null +++ b/scripts/o3de/tests/unit_test_register.py @@ -0,0 +1,117 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +import argparse +import json +import logging +import pytest +import pathlib +from unittest.mock import patch + +from o3de import register + +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() + + # Register the registration script subparsers with the current argument parser + register.add_parser_args(parser) + arg_list = ['--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.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 = 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 + diff --git a/cmake/Tools/unit_test_utils.py b/scripts/o3de/tests/unit_test_utils.py similarity index 100% rename from cmake/Tools/unit_test_utils.py rename to scripts/o3de/tests/unit_test_utils.py diff --git a/scripts/project_manager/projects.py b/scripts/project_manager/projects.py index 51ffc2be91..f9f40aa4bf 100755 --- a/scripts/project_manager/projects.py +++ b/scripts/project_manager/projects.py @@ -29,11 +29,10 @@ executable_path = '' logger = logging.getLogger() logger.setLevel(logging.INFO) -from cmake.Tools import engine_template -from cmake.Tools import registration +from o3de import disable_gem, enable_gem, cmake, engine_template, manifest, register -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') @@ -124,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) @@ -187,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') @@ -202,7 +197,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]})' @@ -256,7 +251,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): @@ -298,7 +293,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 @@ -314,7 +309,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") @@ -360,7 +355,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 @@ -376,7 +371,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.") @@ -392,13 +387,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 @@ -410,7 +405,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.") @@ -454,7 +449,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 @@ -483,9 +478,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() @@ -502,9 +497,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") @@ -519,9 +514,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") @@ -536,9 +531,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") @@ -553,9 +548,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() @@ -572,9 +567,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") @@ -589,9 +584,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") @@ -606,9 +601,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") @@ -616,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. @@ -643,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() @@ -767,185 +667,67 @@ 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: - gem_paths = registration.get_all_gems() + 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 = registration.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, - 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 - self.refresh_runtime_project_gem_targets_available_list() - self.refresh_runtime_project_gem_targets_enabled_list() + enable_gem.enable_gem_in_project(gem_path=gem_path, + project_path=self.get_selected_project_path()) + self.refresh_project_gem_targets_available_list() + self.refresh_project_gem_targets_enabled_list() + return + self.refresh_project_gem_targets_available_list() + self.refresh_project_gem_targets_enabled_list() - def remove_runtime_project_gem_targets_handler(self): - gem_paths = registration.get_all_gems() + 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 = registration.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, - 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 - self.refresh_runtime_project_gem_targets_available_list() - self.refresh_runtime_project_gem_targets_enabled_list() + disable_gem.disable_gem_in_project(gem_path=gem_path, + project_path=self.get_selected_project_path()) + self.refresh_project_gem_targets_available_list() + self.refresh_project_gem_targets_enabled_list() + return + self.refresh_project_gem_targets_available_list() + self.refresh_project_gem_targets_enabled_list() - def add_tool_project_gem_targets_handler(self) -> None: - gem_paths = registration.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) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - registration.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 = registration.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) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - registration.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 = registration.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) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - registration.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 = registration.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) - for this_gem_target in this_gems_targets: - if gem_target == this_gem_target: - registration.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: + def refresh_project_gem_targets_enabled_list(self) -> None: enabled_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = registration.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: + + def refresh_project_gem_targets_available_list(self) -> None: available_project_gem_targets_model = QStandardItemModel() - enabled_project_gem_targets = registration.get_project_runtime_gem_targets( - project_path=self.get_selected_project_path()) - all_gem_targets = registration.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 = registration.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 = registration.get_project_tool_gem_targets( - project_path=self.get_selected_project_path()) - all_gem_targets = registration.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 = registration.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 = registration.get_project_server_gem_targets( - project_path=self.get_selected_project_path()) - all_gem_targets = registration.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() - 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)