Coverage for debputy/manifest_conditions.py: 0%
88 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-22 14:29 +0100
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-22 14:29 +0100
1import dataclasses
2from typing import List, Callable, Optional
4from debian.debian_support import DpkgArchTable
6from debputy._deb_options_profiles import DebOptionsAndProfiles
7from debputy.architecture_support import DpkgArchitectureBuildProcessValuesTable
8from debputy.packages import BinaryPackage, SourcePackage
9from debputy.substitution import Substitution
10from debputy.util import active_profiles_match
13@dataclasses.dataclass(slots=True, frozen=True)
14class ConditionContext:
15 binary_package: Optional[BinaryPackage]
16 build_env: DebOptionsAndProfiles
17 substitution: Substitution
18 dpkg_architecture_variables: DpkgArchitectureBuildProcessValuesTable
19 dpkg_arch_query_table: DpkgArchTable
22class ManifestCondition:
24 def describe(self) -> str:
25 raise NotImplementedError
27 def negated(self) -> 'ManifestCondition':
28 return NegatedManifestCondition(self)
30 def evaluate(self, context: ConditionContext) -> bool:
31 raise NotImplementedError
33 @classmethod
34 def is_cross_building(cls) -> 'ManifestCondition':
35 return _IS_CROSS_BUILDING
37 @classmethod
38 def can_execute_compiled_binaries(cls):
39 return _CAN_EXECUTE_COMPILED_BINARIES
41 @classmethod
42 def run_build_time_tests(cls):
43 return _RUN_BUILD_TIME_TESTS
46class NegatedManifestCondition(ManifestCondition):
48 __slots__ = ('_condition',)
50 def __init__(self, condition: ManifestCondition) -> None:
51 self._condition = condition
53 def negated(self) -> 'ManifestCondition':
54 return self._condition
56 def describe(self) -> str:
57 return f'not ({self._condition.describe()})'
59 def evaluate(self, *args, **kwargs) -> bool:
60 return not self._condition.evaluate(*args, **kwargs)
63class ArchMatchManifestCondition(ManifestCondition):
65 __slots__ = ('_arch_spec', '_is_negated')
67 def __init__(self, arch_spec: List[str], *, is_negated: bool = False) -> None:
68 self._arch_spec = arch_spec
69 self._is_negated = is_negated
71 def negated(self) -> 'ManifestCondition':
72 return self.__class__(self._arch_spec, is_negated=not self._is_negated)
74 def describe(self) -> str:
75 if self._is_negated:
76 return f'architecture (for binary package) matches *none* of [{", ".join(self._arch_spec)}]'
77 return f'architecture (for binary package) matches any of [{", ".join(self._arch_spec)}]'
79 def evaluate(self, context: ConditionContext) -> bool:
80 binary_package = context.binary_package
81 if binary_package is None:
82 raise RuntimeError("Condition only applies in the context of a BinaryPackage, but was evaluated"
83 " without one")
84 arch = binary_package.resolved_architecture
85 match = context.dpkg_arch_query_table.architecture_is_concerned(arch, self._arch_spec)
86 return not match if self._is_negated else match
89class BuildProfileMatch(ManifestCondition):
91 __slots__ = ('_profile_spec', '_is_negated')
93 def __init__(self, profile_spec: str, *, is_negated: bool = False) -> None:
94 self._profile_spec = profile_spec
95 self._is_negated = is_negated
97 def negated(self) -> 'ManifestCondition':
98 return self.__class__(self._profile_spec, is_negated=not self._is_negated)
100 def describe(self) -> str:
101 if self._is_negated:
102 return f'DEB_BUILD_PROFILES matches *none* of [{", ".join(self._profile_spec)}]'
103 return f'DEB_BUILD_PROFILES matches any of [{", ".join(self._profile_spec)}]'
105 def evaluate(self, context: ConditionContext) -> bool:
106 match = active_profiles_match(self._profile_spec, context.build_env.deb_build_profiles)
107 return not match if self._is_negated else match
110@dataclasses.dataclass(frozen=True, slots=True)
111class _SingletonCondition(ManifestCondition):
113 description: str
114 implementation: Callable[[ConditionContext], bool]
116 def describe(self) -> str:
117 return self.description
119 def evaluate(self, context: ConditionContext) -> bool:
121 return self.implementation(context)
124def _can_run_built_binaries(context: ConditionContext) -> bool:
125 if not context.dpkg_architecture_variables.is_cross_compiling:
126 return True
127 # User / Builder asserted that we could even though we are cross-compiling, so we have to assume it is true
128 return 'crossbuildcanrunhostbinaries' in context.build_env.deb_build_options
131_IS_CROSS_BUILDING = _SingletonCondition('Cross Compiling (i.e., DEB_HOST_GNU_TYPE != DEB_BUILD_GNU_TYPE)',
132 lambda c: c.dpkg_architecture_variables.is_cross_compiling,
133 )
135_CAN_EXECUTE_COMPILED_BINARIES = _SingletonCondition('Can run built binaries (natively or via transparent emulation)',
136 _can_run_built_binaries,
137 )
139_RUN_BUILD_TIME_TESTS = _SingletonCondition('Can run built binaries (natively or via transparent emulation)',
140 lambda c: 'nocheck' in c.build_env.deb_build_options
141 )
144del _SingletonCondition
145del _can_run_built_binaries