project_generator.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. import os
  8. from config_data import ConfigData
  9. from threaded_lambda import ThreadedLambda
  10. from subprocess_runner import SubprocessRunner
  11. class ProjectGenerator(ThreadedLambda):
  12. """
  13. This class knows how to create an Android project.
  14. It first runs the configuration commands supported by o3de.bat/o3de.sh,
  15. validates the configuration and generates the project.
  16. """
  17. def __init__(self, config: ConfigData):
  18. def _job_func():
  19. self._run_commands()
  20. super().__init__("Android Project Generator", _job_func)
  21. self._config = config
  22. o3de_cmd = config.get_o3de_cmd()
  23. self._sdk_root_configure_cmd = SubprocessRunner(
  24. [
  25. o3de_cmd,
  26. "android-configure",
  27. "--set-value",
  28. f"sdk.root={config.android_sdk_path}",
  29. "--project",
  30. config.project_path,
  31. ],
  32. timeOutSeconds=10,
  33. )
  34. self._api_level_configure_cmd = SubprocessRunner(
  35. [
  36. o3de_cmd,
  37. "android-configure",
  38. "--set-value",
  39. f"platform.sdk.api={config.android_sdk_api_level}",
  40. "--project",
  41. config.project_path,
  42. ],
  43. timeOutSeconds=10,
  44. )
  45. self._ndk_configure_cmd = SubprocessRunner(
  46. [
  47. o3de_cmd,
  48. "android-configure",
  49. "--set-value",
  50. f"ndk.version={config.android_ndk_version}",
  51. "--project",
  52. config.project_path,
  53. ],
  54. timeOutSeconds=10,
  55. )
  56. # agp is Android Gradle Plugin. FIXME: Make it a variable.
  57. self._agp_configure_cmd = SubprocessRunner(
  58. [
  59. o3de_cmd,
  60. "android-configure",
  61. "--set-value",
  62. "android.gradle.plugin=8.1.0",
  63. "--project",
  64. config.project_path,
  65. ],
  66. timeOutSeconds=10,
  67. )
  68. self._validate_configuration_cmd = SubprocessRunner(
  69. [
  70. o3de_cmd,
  71. "android-configure",
  72. "--validate",
  73. "--project",
  74. config.project_path,
  75. ],
  76. timeOutSeconds=60
  77. )
  78. arg_list = [
  79. o3de_cmd,
  80. "android-generate",
  81. "-p",
  82. config.get_project_name(),
  83. "-B",
  84. config.get_android_build_dir(),
  85. "--asset-mode",
  86. config.asset_mode,
  87. ]
  88. if config.is_meta_quest_project:
  89. arg_list.extend(["--oculus-project"])
  90. if config.extra_cmake_args:
  91. # It is imperative to wrap the extra cmake arguments in double quotes "-DFOO=ON -DBAR=OFF"
  92. # because the cmake arguments/variables are separated by spaces.
  93. arg_list.extend(["--extra-cmake-args", f'"{config.extra_cmake_args}"'])
  94. self._generate_project_cmd = SubprocessRunner(
  95. arg_list,
  96. timeOutSeconds=60,
  97. # The "android-generate" subcommand requires to be run from the project root directory,
  98. # otherwise it won't find the settings we previously defined with the multiple calls
  99. # to "android-configure" subcommand.
  100. cwd=config.project_path
  101. )
  102. def _run_commands(self):
  103. """
  104. This is a "protected" function. It is invoked when super().start() is called.
  105. """
  106. if self._is_cancelled:
  107. self._is_finished = True
  108. self._is_success = False
  109. return
  110. commands = [
  111. self._sdk_root_configure_cmd,
  112. self._api_level_configure_cmd,
  113. self._ndk_configure_cmd,
  114. self._agp_configure_cmd,
  115. self._validate_configuration_cmd,
  116. self._generate_project_cmd,
  117. ]
  118. for command in commands:
  119. if self._is_cancelled:
  120. self._is_finished = True
  121. self._is_success = False
  122. return
  123. if not command.run():
  124. self._record_command_error(command)
  125. return
  126. else:
  127. self._record_command_results(command)
  128. self._is_finished = True
  129. self._is_success = True
  130. self._report_msg += f"Next Steps:\nYou can compile, deploy and execute the android application with Android Studio by opening the project:\n{self._config.get_android_build_dir()}.\n"
  131. self._report_msg += "Alternatively, you can compile the project from the command line with the following commands:\n"
  132. self._report_msg += f"$ cd {self._config.get_android_build_dir()}\n$ .\\gradlew assembleProfile\nOr if interested in compiling for debugging:\n$ .\\gradlew assembleDebug\n"
  133. def _record_command_error(self, command: SubprocessRunner):
  134. self._is_finished = True
  135. self._is_success = False
  136. self._record_command_results(command)
  137. def _record_command_results(self, command: SubprocessRunner):
  138. self._report_msg += f"Command:\n{command.get_command_str()}\nCompleted with status code {command.get_error_code()}.\n"
  139. self._report_msg += command.get_stdall()
  140. # class ProjectGenerator END
  141. ######################################################