craft-application 2.6.2__tar.gz → 2.6.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. {craft_application-2.6.2 → craft_application-2.6.3}/PKG-INFO +1 -1
  2. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/_version.py +2 -2
  3. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/application.py +34 -27
  4. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/services/lifecycle.py +1 -1
  5. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application.egg-info/PKG-INFO +1 -1
  6. craft_application-2.6.3/tests/integration/data/valid_projects/environment/testcraft.yaml +18 -0
  7. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/test_application.py +37 -2
  8. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/services/test_lifecycle.py +5 -5
  9. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/test_application.py +31 -9
  10. craft_application-2.6.2/tests/integration/data/valid_projects/environment/testcraft.yaml +0 -14
  11. {craft_application-2.6.2 → craft_application-2.6.3}/.editorconfig +0 -0
  12. {craft_application-2.6.2 → craft_application-2.6.3}/.github/.jira_sync_config.yaml +0 -0
  13. {craft_application-2.6.2 → craft_application-2.6.3}/.github/ISSUE_TEMPLATE/bug.yaml +0 -0
  14. {craft_application-2.6.2 → craft_application-2.6.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  15. {craft_application-2.6.2 → craft_application-2.6.3}/.github/ISSUE_TEMPLATE/task.yaml +0 -0
  16. {craft_application-2.6.2 → craft_application-2.6.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  17. {craft_application-2.6.2 → craft_application-2.6.3}/.github/release-drafter.yaml +0 -0
  18. {craft_application-2.6.2 → craft_application-2.6.3}/.github/release-drafter.yml +0 -0
  19. {craft_application-2.6.2 → craft_application-2.6.3}/.github/renovate.json5 +0 -0
  20. {craft_application-2.6.2 → craft_application-2.6.3}/.github/workflows/cla-check.yaml +0 -0
  21. {craft_application-2.6.2 → craft_application-2.6.3}/.github/workflows/docs.yaml +0 -0
  22. {craft_application-2.6.2 → craft_application-2.6.3}/.github/workflows/release-drafter.yaml +0 -0
  23. {craft_application-2.6.2 → craft_application-2.6.3}/.github/workflows/tests.yaml +0 -0
  24. {craft_application-2.6.2 → craft_application-2.6.3}/.gitignore +0 -0
  25. {craft_application-2.6.2 → craft_application-2.6.3}/.pre-commit-config.yaml +0 -0
  26. {craft_application-2.6.2 → craft_application-2.6.3}/.readthedocs.yaml +0 -0
  27. {craft_application-2.6.2 → craft_application-2.6.3}/.yamllint.yaml +0 -0
  28. {craft_application-2.6.2 → craft_application-2.6.3}/HACKING.rst +0 -0
  29. {craft_application-2.6.2 → craft_application-2.6.3}/LICENSE +0 -0
  30. {craft_application-2.6.2 → craft_application-2.6.3}/README.rst +0 -0
  31. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/__init__.py +0 -0
  32. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/commands/__init__.py +0 -0
  33. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/commands/base.py +0 -0
  34. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/commands/lifecycle.py +0 -0
  35. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/commands/other.py +0 -0
  36. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/errors.py +0 -0
  37. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/grammar.py +0 -0
  38. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/__init__.py +0 -0
  39. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/errors.py +0 -0
  40. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/launchpad.py +0 -0
  41. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/models/__init__.py +0 -0
  42. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/models/base.py +0 -0
  43. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/models/build.py +0 -0
  44. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/models/code.py +0 -0
  45. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/models/distro.py +0 -0
  46. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/models/project.py +0 -0
  47. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/models/recipe.py +0 -0
  48. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/launchpad/util.py +0 -0
  49. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/misc/instance_bashrc +0 -0
  50. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/models/__init__.py +0 -0
  51. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/models/base.py +0 -0
  52. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/models/constraints.py +0 -0
  53. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/models/grammar.py +0 -0
  54. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/models/metadata.py +0 -0
  55. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/models/project.py +0 -0
  56. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/py.typed +0 -0
  57. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/remote/__init__.py +0 -0
  58. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/remote/errors.py +0 -0
  59. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/remote/git.py +0 -0
  60. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/remote/utils.py +0 -0
  61. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/remote/worktree.py +0 -0
  62. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/secrets.py +0 -0
  63. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/services/__init__.py +0 -0
  64. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/services/base.py +0 -0
  65. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/services/package.py +0 -0
  66. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/services/provider.py +0 -0
  67. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/services/remotebuild.py +0 -0
  68. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/services/request.py +0 -0
  69. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/services/service_factory.py +0 -0
  70. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/__init__.py +0 -0
  71. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/callbacks.py +0 -0
  72. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/error_formatting.py +0 -0
  73. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/logging.py +0 -0
  74. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/paths.py +0 -0
  75. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/platforms.py +0 -0
  76. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/repositories.py +0 -0
  77. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/snap_config.py +0 -0
  78. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/string.py +0 -0
  79. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application/util/yaml.py +0 -0
  80. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application.egg-info/SOURCES.txt +0 -0
  81. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application.egg-info/dependency_links.txt +0 -0
  82. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application.egg-info/requires.txt +0 -0
  83. {craft_application-2.6.2 → craft_application-2.6.3}/craft_application.egg-info/top_level.txt +0 -0
  84. {craft_application-2.6.2 → craft_application-2.6.3}/docs/_static/css/custom.css +0 -0
  85. {craft_application-2.6.2 → craft_application-2.6.3}/docs/conf.py +0 -0
  86. {craft_application-2.6.2 → craft_application-2.6.3}/docs/explanation/index.rst +0 -0
  87. {craft_application-2.6.2 → craft_application-2.6.3}/docs/howto/index.rst +0 -0
  88. {craft_application-2.6.2 → craft_application-2.6.3}/docs/index.rst +0 -0
  89. {craft_application-2.6.2 → craft_application-2.6.3}/docs/reference/index.rst +0 -0
  90. {craft_application-2.6.2 → craft_application-2.6.3}/docs/tutorials/index.rst +0 -0
  91. {craft_application-2.6.2 → craft_application-2.6.3}/pyproject.toml +0 -0
  92. {craft_application-2.6.2 → craft_application-2.6.3}/setup.cfg +0 -0
  93. {craft_application-2.6.2 → craft_application-2.6.3}/tests/__init__.py +0 -0
  94. {craft_application-2.6.2 → craft_application-2.6.3}/tests/conftest.py +0 -0
  95. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/__init__.py +0 -0
  96. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/conftest.py +0 -0
  97. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/build-secrets/secret-source-folder/source-file.txt +0 -0
  98. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/build-secrets/testcraft.yaml +0 -0
  99. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/invalid_projects/build-error/testcraft.yaml +0 -0
  100. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/valid_projects/adoption/stderr +0 -0
  101. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/valid_projects/adoption/testcraft.yaml +0 -0
  102. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/valid_projects/basic/stderr +0 -0
  103. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/valid_projects/basic/testcraft.yaml +0 -0
  104. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/valid_projects/environment/stderr +0 -0
  105. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/valid_projects/grammar/src/on-amd64-to-amd64/hello.txt +0 -0
  106. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/valid_projects/grammar/src/on-amd64-to-arm64/hello.txt +0 -0
  107. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/valid_projects/grammar/stderr +0 -0
  108. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/data/valid_projects/grammar/testcraft.yaml +0 -0
  109. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/launchpad/__init__.py +0 -0
  110. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/launchpad/conftest.py +0 -0
  111. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/launchpad/test_anonymous_access.py +0 -0
  112. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/services/__init__.py +0 -0
  113. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/services/test_lifecycle.py +0 -0
  114. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/services/test_provider.py +0 -0
  115. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/services/test_remotebuild.py +0 -0
  116. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/services/test_request.py +0 -0
  117. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/services/test_service_factory.py +0 -0
  118. {craft_application-2.6.2 → craft_application-2.6.3}/tests/integration/test_version.py +0 -0
  119. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/__init__.py +0 -0
  120. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/commands/__init__.py +0 -0
  121. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/commands/test_base.py +0 -0
  122. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/commands/test_lifecycle.py +0 -0
  123. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/commands/test_other.py +0 -0
  124. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/conftest.py +0 -0
  125. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/launchpad/__init__.py +0 -0
  126. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/launchpad/conftest.py +0 -0
  127. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/launchpad/models/__init__.py +0 -0
  128. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/launchpad/models/test_base.py +0 -0
  129. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/launchpad/models/test_code.py +0 -0
  130. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/launchpad/test_launchpad.py +0 -0
  131. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/launchpad/test_util.py +0 -0
  132. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/models/__init__.py +0 -0
  133. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/models/project_models/basic_project.yaml +0 -0
  134. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/models/project_models/full_project.yaml +0 -0
  135. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/models/project_models/invalid_project.yaml +0 -0
  136. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/models/test_constraints.py +0 -0
  137. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/models/test_grammar.py +0 -0
  138. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/models/test_project.py +0 -0
  139. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/remote/__init__.py +0 -0
  140. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/remote/conftest.py +0 -0
  141. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/remote/test_errors.py +0 -0
  142. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/remote/test_git.py +0 -0
  143. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/remote/test_utils.py +0 -0
  144. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/remote/test_worktree.py +0 -0
  145. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/services/__init__.py +0 -0
  146. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/services/conftest.py +0 -0
  147. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/services/test_package.py +0 -0
  148. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/services/test_provider.py +0 -0
  149. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/services/test_remotebuild.py +0 -0
  150. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/services/test_repositories.py +0 -0
  151. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/services/test_request.py +0 -0
  152. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/services/test_service_factory.py +0 -0
  153. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/test_errors.py +0 -0
  154. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/test_grammar.py +0 -0
  155. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/test_nothing.py +0 -0
  156. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/test_secrets.py +0 -0
  157. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/__init__.py +0 -0
  158. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/invalid_yaml/_README +0 -0
  159. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/invalid_yaml/duplicate_second_level.yaml-invalid +0 -0
  160. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/invalid_yaml/duplicate_top_level.yaml-invalid +0 -0
  161. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/invalid_yaml/unhashable.yaml-invalid +0 -0
  162. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/test_error_formatting.py +0 -0
  163. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/test_logging.py +0 -0
  164. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/test_paths.py +0 -0
  165. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/test_snap_config.py +0 -0
  166. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/test_string.py +0 -0
  167. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/test_yaml.py +0 -0
  168. {craft_application-2.6.2 → craft_application-2.6.3}/tests/unit/util/valid_yaml/empty.yaml +0 -0
  169. {craft_application-2.6.2 → craft_application-2.6.3}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: craft-application
3
- Version: 2.6.2
3
+ Version: 2.6.3
4
4
  Summary: A framework for *craft applications.
5
5
  Classifier: Development Status :: 5 - Production/Stable
6
6
  Classifier: Environment :: Console
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '2.6.2'
16
- __version_tuple__ = version_tuple = (2, 6, 2)
15
+ __version__ = version = '2.6.3'
16
+ __version_tuple__ = version_tuple = (2, 6, 3)
@@ -280,11 +280,18 @@ class Application:
280
280
  self._full_build_plan, platform, build_for, host_arch
281
281
  )
282
282
 
283
- if platform and not build_for:
284
- all_platforms = {b.platform: b for b in self._full_build_plan}
285
- if platform not in all_platforms:
286
- raise errors.InvalidPlatformError(platform, list(all_platforms.keys()))
287
- build_for = all_platforms[platform].build_for
283
+ if not build_for:
284
+ # get the build-for arch from the platform
285
+ if platform:
286
+ all_platforms = {b.platform: b for b in self._full_build_plan}
287
+ if platform not in all_platforms:
288
+ raise errors.InvalidPlatformError(
289
+ platform, list(all_platforms.keys())
290
+ )
291
+ build_for = all_platforms[platform].build_for
292
+ # otherwise get the build-for arch from the build plan
293
+ elif self._build_plan:
294
+ build_for = self._build_plan[0].build_for
288
295
 
289
296
  # validate project grammar
290
297
  GrammarAwareProject.validate_grammar(yaml_data)
@@ -576,34 +583,29 @@ class Application:
576
583
  Performs task such as environment expansion. Note that this transforms
577
584
  ``yaml_data`` in-place.
578
585
  """
586
+ # apply application-specific transformations first because an application may
587
+ # add advanced grammar, project variables, or secrets to the yaml
588
+ yaml_data = self._extra_yaml_transform(
589
+ yaml_data, build_on=build_on, build_for=build_for
590
+ )
591
+
592
+ # At the moment there is no perfect solution for what do to do
593
+ # expand project variables or to resolve the grammar if there's
594
+ # no explicitly-provided target arch. However, we must resolve
595
+ # it with *something* otherwise we might have an invalid parts
596
+ # definition full of grammar declarations and incorrect build_for
597
+ # architectures.
598
+ build_for = build_for or build_on
599
+
579
600
  # Perform variable expansion.
580
- self._expand_environment(yaml_data)
601
+ self._expand_environment(yaml_data=yaml_data, build_for=build_for)
581
602
 
582
603
  # Handle build secrets.
583
604
  if self.app.features.build_secrets:
584
605
  self._render_secrets(yaml_data)
585
606
 
586
- # apply application-specific transformations before expanding grammar
587
- # because an application may add advanced grammar to the yaml
588
- yaml_data = self._extra_yaml_transform(
589
- yaml_data, build_on=build_on, build_for=build_for
590
- )
591
-
592
607
  # Expand grammar.
593
608
  if "parts" in yaml_data:
594
- if not build_for:
595
- # At the moment there is no perfect solution for what do to do
596
- # resolve the grammar if there's no explicitly-provided target
597
- # arch. However, we must resolve it with *something* otherwise
598
- # we might have an invalid parts definition full of grammar
599
- # declarations.
600
- if self._build_plan:
601
- # If we have a build plan use one of its items, because
602
- # it's likely contemplated on the grammar.
603
- build_for = self._build_plan[0].build_for
604
- else:
605
- # As a last resort, default to the same arch as the host.
606
- build_for = build_on
607
609
  craft_cli.emit.debug(f"Processing grammar (on {build_on} for {build_for})")
608
610
  yaml_data["parts"] = grammar.process_parts(
609
611
  parts_yaml_data=yaml_data["parts"],
@@ -613,8 +615,12 @@ class Application:
613
615
 
614
616
  return yaml_data
615
617
 
616
- def _expand_environment(self, yaml_data: dict[str, Any]) -> None:
617
- """Perform expansion of project environment variables."""
618
+ def _expand_environment(self, yaml_data: dict[str, Any], build_for: str) -> None:
619
+ """Perform expansion of project environment variables.
620
+
621
+ :param yaml_data: The project's yaml data.
622
+ :param build_for: The architecture to build for.
623
+ """
618
624
  environment_vars = self._get_project_vars(yaml_data)
619
625
  project_dirs = craft_parts.ProjectDirs(
620
626
  work_dir=self._work_dir, partitions=self._partitions
@@ -623,6 +629,7 @@ class Application:
623
629
  info = craft_parts.ProjectInfo(
624
630
  application_name=self.app.name, # not used in environment expansion
625
631
  cache_dir=pathlib.Path(), # not used in environment expansion
632
+ arch=util.convert_architecture_deb_to_platform(build_for),
626
633
  project_name=yaml_data.get("name", ""),
627
634
  project_dirs=project_dirs,
628
635
  project_vars=environment_vars,
@@ -263,7 +263,7 @@ class LifecycleService(base.ProjectService):
263
263
  raise RuntimeError(f"Parts processing internal error: {err}") from err
264
264
  except OSError as err:
265
265
  raise errors.PartsLifecycleError.from_os_error(err) from err
266
- except Exception as err: # noqa: BLE001 - Converting general error.
266
+ except Exception as err:
267
267
  raise errors.PartsLifecycleError(f"Unknown error: {str(err)}") from err
268
268
 
269
269
  def post_prime(self, step_info: StepInfo) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: craft-application
3
- Version: 2.6.2
3
+ Version: 2.6.3
4
4
  Summary: A framework for *craft applications.
5
5
  Classifier: Development Status :: 5 - Production/Stable
6
6
  Classifier: Environment :: Console
@@ -0,0 +1,18 @@
1
+ name: environment-project
2
+ summary: A project with environment variables
3
+ version: 1.0
4
+ base: ["ubuntu", "22.04"]
5
+
6
+ parts:
7
+ my-part:
8
+ plugin: nil
9
+ override-build: |
10
+ target_file=${CRAFT_PART_INSTALL}/variables.yaml
11
+ touch $target_file
12
+ echo "project_name: \"${CRAFT_PROJECT_NAME}\"" >> $target_file
13
+ echo "project_dir: \"${CRAFT_PROJECT_DIR}\"" >> $target_file
14
+ echo "project_version: \"${CRAFT_PROJECT_VERSION}\"" >> $target_file
15
+ echo "arch_build_for: \"${CRAFT_ARCH_BUILD_FOR}\"" >> $target_file
16
+ echo "arch_triplet_build_for: \"${CRAFT_ARCH_TRIPLET_BUILD_FOR}\"" >> $target_file
17
+ echo "arch_build_on: \"${CRAFT_ARCH_BUILD_ON}\"" >> $target_file
18
+ echo "arch_triplet_build_on: \"${CRAFT_ARCH_TRIPLET_BUILD_ON}\"" >> $target_file
@@ -21,10 +21,12 @@ import craft_application
21
21
  import craft_cli
22
22
  import pytest
23
23
  import pytest_check
24
- from craft_application import secrets, util
24
+ from craft_application import models, secrets, util
25
25
  from craft_application.util import yaml
26
26
  from typing_extensions import override
27
27
 
28
+ from tests.conftest import MyBuildPlanner
29
+
28
30
 
29
31
  class TestableApplication(craft_application.Application):
30
32
  """An application modified for integration tests.
@@ -267,8 +269,18 @@ def test_invalid_command_argument(monkeypatch, capsys, app):
267
269
  assert stderr == expected_stderr
268
270
 
269
271
 
272
+ @pytest.mark.parametrize(
273
+ "arguments",
274
+ [
275
+ [],
276
+ ["--build-for", "s390x"],
277
+ ["--platform", "my-platform"],
278
+ ],
279
+ )
270
280
  def test_global_environment(
281
+ arguments,
271
282
  create_app,
283
+ mocker,
272
284
  monkeypatch,
273
285
  tmp_path,
274
286
  ):
@@ -276,8 +288,24 @@ def test_global_environment(
276
288
  monkeypatch.chdir(tmp_path)
277
289
  shutil.copytree(VALID_PROJECTS_DIR / "environment", tmp_path, dirs_exist_ok=True)
278
290
 
291
+ # a build plan that builds for s390x (a cross-compiling scenario unless on s390x)
292
+ mocker.patch.object(
293
+ MyBuildPlanner,
294
+ "get_build_plan",
295
+ return_value=[
296
+ models.BuildInfo(
297
+ platform="my-platform",
298
+ build_on=util.get_host_architecture(),
299
+ build_for="s390x",
300
+ base=util.get_host_base(),
301
+ ),
302
+ ],
303
+ )
304
+
279
305
  # Run in destructive mode
280
- monkeypatch.setattr("sys.argv", ["testcraft", "prime", "--destructive-mode"])
306
+ monkeypatch.setattr(
307
+ "sys.argv", ["testcraft", "prime", "--destructive-mode", *arguments]
308
+ )
281
309
  app = create_app()
282
310
  app.run()
283
311
 
@@ -291,6 +319,13 @@ def test_global_environment(
291
319
  assert variables["project_name"] == "environment-project"
292
320
  assert variables["project_dir"] == str(tmp_path)
293
321
  assert variables["project_version"] == "1.0"
322
+ assert variables["arch_build_for"] == "s390x"
323
+ assert variables["arch_triplet_build_for"] == "s390x-linux-gnu"
324
+ assert variables["arch_build_on"] == "amd64"
325
+ # craft-application doesn't have utility for getting arch triplets
326
+ assert variables["arch_triplet_build_on"].startswith(
327
+ util.convert_architecture_deb_to_platform(util.get_host_architecture())
328
+ )
294
329
 
295
330
 
296
331
  @pytest.fixture()
@@ -96,7 +96,7 @@ def test_get_parts_action_message_run(step: Step, message: str):
96
96
 
97
97
  actual = lifecycle._get_parts_action_message(action)
98
98
 
99
- assert actual == message, "Unexpected %r" % actual
99
+ assert actual == message, f"Unexpected {actual!r}"
100
100
 
101
101
 
102
102
  @pytest.mark.parametrize(
@@ -118,7 +118,7 @@ def test_get_parts_re_action_message_run(step: Step, message: str):
118
118
 
119
119
  actual = lifecycle._get_parts_action_message(action)
120
120
 
121
- assert actual == message, "Unexpected %r" % actual
121
+ assert actual == message, f"Unexpected {actual!r}"
122
122
 
123
123
 
124
124
  @pytest.mark.parametrize(
@@ -140,7 +140,7 @@ def test_get_parts_skip_action_message_run(step: Step, message: str):
140
140
 
141
141
  actual = lifecycle._get_parts_action_message(action)
142
142
 
143
- assert actual == message, "Unexpected %r" % actual
143
+ assert actual == message, f"Unexpected {actual!r}"
144
144
 
145
145
 
146
146
  @pytest.mark.parametrize(
@@ -160,7 +160,7 @@ def test_get_parts_update_action_message_run(step: Step, message: str):
160
160
 
161
161
  actual = lifecycle._get_parts_action_message(action)
162
162
 
163
- assert actual == message, "Unexpected %r" % actual
163
+ assert actual == message, f"Unexpected {actual!r}"
164
164
 
165
165
 
166
166
  @pytest.mark.parametrize(
@@ -178,7 +178,7 @@ def get_parts_action_message_with_reason(step: Step, message: str):
178
178
 
179
179
  actual = lifecycle._get_parts_action_message(action)
180
180
 
181
- assert actual == message, "Unexpected %r" % actual
181
+ assert actual == message, f"Unexpected {actual!r}"
182
182
 
183
183
 
184
184
  def test_progress_messages(fake_parts_lifecycle, emitter):
@@ -1306,10 +1306,10 @@ def test_extra_yaml_transform(tmp_path, app_metadata, fake_services):
1306
1306
 
1307
1307
  app = FakeApplication(app_metadata, fake_services)
1308
1308
  app.project_dir = tmp_path
1309
- _ = app.get_project(build_for="fake-build-for")
1309
+ _ = app.get_project(build_for="s390x")
1310
1310
 
1311
1311
  assert app.build_on == util.get_host_architecture()
1312
- assert app.build_for == "fake-build-for"
1312
+ assert app.build_for == "s390x"
1313
1313
 
1314
1314
 
1315
1315
  def test_mandatory_adoptable_fields(tmp_path, app_metadata, fake_services):
@@ -1505,7 +1505,7 @@ def test_process_grammar_no_match(grammar_app_mini, mocker):
1505
1505
 
1506
1506
 
1507
1507
  class FakeApplicationWithYamlTransform(FakeApplication):
1508
- """Application class that adds advanced grammar in `_extra_yaml_transform`."""
1508
+ """Application class that adds data in `_extra_yaml_transform`."""
1509
1509
 
1510
1510
  @override
1511
1511
  def _extra_yaml_transform(
@@ -1520,9 +1520,17 @@ class FakeApplicationWithYamlTransform(FakeApplication):
1520
1520
  new_yaml_data["parts"] = {
1521
1521
  "mypart": {
1522
1522
  "plugin": "nil",
1523
- "source": [
1524
- {"to riscv64": "to-riscv64"},
1525
- {"to s390x": "to-s390x"},
1523
+ # advanced grammar
1524
+ "build-packages": [
1525
+ "test-package",
1526
+ {"to riscv64": "riscv64-package"},
1527
+ {"to s390x": "s390x-package"},
1528
+ ],
1529
+ "build-environment": [
1530
+ # project variables
1531
+ {"hello": "$CRAFT_ARCH_BUILD_ON"},
1532
+ # build secrets
1533
+ {"MY_VAR": "$(HOST_SECRET:echo ${SECRET_VAR})"},
1526
1534
  ],
1527
1535
  }
1528
1536
  }
@@ -1530,16 +1538,30 @@ class FakeApplicationWithYamlTransform(FakeApplication):
1530
1538
  return new_yaml_data
1531
1539
 
1532
1540
 
1533
- def test_process_grammar_from_extra_transform(app_metadata, fake_services, tmp_path):
1541
+ @pytest.mark.enable_features("build_secrets")
1542
+ def test_process_yaml_from_extra_transform(
1543
+ app_metadata, fake_services, tmp_path, monkeypatch
1544
+ ):
1534
1545
  """Test that grammar is applied on data from `_extra_yaml_transform`."""
1546
+ monkeypatch.setenv("SECRET_VAR", "secret-value")
1535
1547
  project_file = tmp_path / "testcraft.yaml"
1536
1548
  project_file.write_text(BASIC_PROJECT_YAML)
1537
1549
 
1538
1550
  app = FakeApplicationWithYamlTransform(app_metadata, fake_services)
1539
1551
  app.project_dir = tmp_path
1540
-
1541
1552
  project = app.get_project(build_for="riscv64")
1542
- assert project.parts["mypart"]["source"] == "to-riscv64"
1553
+
1554
+ # process grammar
1555
+ assert project.parts["mypart"]["build-packages"] == [
1556
+ "test-package",
1557
+ "riscv64-package",
1558
+ ]
1559
+ assert project.parts["mypart"]["build-environment"] == [
1560
+ # evaluate project variables
1561
+ {"hello": get_host_architecture()},
1562
+ # render secrets
1563
+ {"MY_VAR": "secret-value"},
1564
+ ]
1543
1565
 
1544
1566
 
1545
1567
  class FakePartitionsApplication(FakeApplication):
@@ -1,14 +0,0 @@
1
- name: environment-project
2
- summary: A project with environment variables
3
- version: 1.0
4
- base: ["ubuntu", "22.04"]
5
-
6
- parts:
7
- my-part:
8
- plugin: nil
9
- override-build: |
10
- target_file=${CRAFT_PART_INSTALL}/variables.yaml
11
- touch $target_file
12
- echo "project_name: \"${CRAFT_PROJECT_NAME}\"" >> $target_file
13
- echo "project_dir: \"${CRAFT_PROJECT_DIR}\"" >> $target_file
14
- echo "project_version: \"${CRAFT_PROJECT_VERSION}\"" >> $target_file