Coverage for src/debputy/build_support/build_context.py: 48%

46 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-10-12 15:06 +0000

1from typing import Optional, TYPE_CHECKING 

2from collections.abc import Mapping 

3 

4from debputy.architecture_support import DpkgArchitectureBuildProcessValuesTable 

5from debputy.manifest_conditions import _run_build_time_tests 

6 

7if TYPE_CHECKING: 

8 from debputy.commands.debputy_cmd.context import CommandContext 

9 

10 

11class BuildContext: 

12 @staticmethod 

13 def from_command_context( 

14 cmd_context: "CommandContext", 

15 ) -> "BuildContext": 

16 return BuildContextImpl(cmd_context) 

17 

18 @property 

19 def deb_build_options(self) -> Mapping[str, str | None]: 

20 raise NotImplementedError 

21 

22 def parallelization_limit(self, *, support_zero_as_unlimited: bool = False) -> int: 

23 """Parallelization limit of the build 

24 

25 This is accessor that reads the `parallel` option from `DEB_BUILD_OPTIONS` with relevant 

26 fallback behavior. 

27 

28 :param support_zero_as_unlimited: The debhelper framework allowed `0` to mean unlimited 

29 in some build systems. If the build system supports this, it should set this option 

30 to True, which will allow `0` as a possible return value. WHen this option is False 

31 (which is the default), `0` will be remapped to a high number to preserve the effect 

32 in spirit (said fallback number is also from `debhelper`). 

33 """ 

34 limit = self.deb_build_options.get("parallel") 

35 if limit is None: 

36 return 1 

37 try: 

38 v = int(limit) 

39 except ValueError: 

40 return 1 

41 if v == 0 and not support_zero_as_unlimited: 

42 # debhelper allowed "0" to be used as unlimited in some cases. Preserve that feature 

43 # for callers that are prepared for it. For everyone else, remap 0 to an obscene number 

44 # that de facto has the same behavior 

45 # 

46 # The number is taken out of `cmake.pm` from `debhelper` to be "Bug compatible" with 

47 # debhelper on the fallback as well. 

48 return 999 

49 return v 

50 

51 @property 

52 def is_terse_build(self) -> bool: 

53 """Whether the build is terse 

54 

55 This is a shorthand for testing for `terse` in DEB_BUILD_OPTIONS 

56 """ 

57 return "terse" in self.deb_build_options 

58 

59 @property 

60 def is_cross_compiling(self) -> bool: 

61 """Whether the build is considered a cross build 

62 

63 Note: Do **not** use this as indicator for whether tests should run. Use `should_run_tests` instead. 

64 To the naive eye, they seem like they overlap in functionality, but they do not. There are cross 

65 builds where tests can be run. Additionally, there are non-cross-builds where tests should be 

66 skipped. 

67 """ 

68 return self.dpkg_architecture_variables.is_cross_compiling 

69 

70 def cross_tool(self, command: str) -> str: 

71 if not self.is_cross_compiling: 

72 return command 

73 cross_prefix = self.dpkg_architecture_variables["DEB_HOST_GNU_TYPE"] 

74 return f"{cross_prefix}-{command}" 

75 

76 @property 

77 def dpkg_architecture_variables(self) -> DpkgArchitectureBuildProcessValuesTable: 

78 raise NotImplementedError 

79 

80 @property 

81 def should_run_tests(self) -> bool: 

82 return _run_build_time_tests(self.deb_build_options) 

83 

84 

85class BuildContextImpl(BuildContext): 

86 def __init__( 

87 self, 

88 cmd_context: "CommandContext", 

89 ) -> None: 

90 self._cmd_context = cmd_context 

91 

92 @property 

93 def deb_build_options(self) -> Mapping[str, str | None]: 

94 return self._cmd_context.deb_build_options 

95 

96 @property 

97 def dpkg_architecture_variables(self) -> DpkgArchitectureBuildProcessValuesTable: 

98 return self._cmd_context.dpkg_architecture_variables()