Coverage for apio/utils/apio_platforms.py: 85%

39 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-23 03:53 +0000

1# -*- coding: utf-8 -*- 

2# -- This file is part of the Apio project 

3# -- (C) 2016-2018 FPGAwars 

4# -- Author Jesús Arroyo 

5# -- License GPLv2 

6# -- Derived from: 

7# ---- Platformio project 

8# ---- (C) 2014-2016 Ivan Kravets <me@ikravets.com> 

9# ---- License Apache v2 

10"""Definition of underlying platforms supported by Apio.""" 

11 

12import re 

13import platform 

14from dataclasses import dataclass 

15from apio.utils import env_options 

16from apio.common.apio_console import fatal_error 

17 

18# # -- The list of supported platforms and their attribute. The fields match 

19# # -- the dataclass ApioPlatform below. 

20# _SUPPORTED_PLATFORMS = { 

21# "darwin-arm64": { 

22# "type": "Mac OSX", 

23# "variant": "ARM 64 bit (Apple Silicon)", 

24# "is_darwin": True, 

25# }, 

26# "linux-x86-64": { 

27# "type": "Linux", 

28# "variant": "X86 64 bit", 

29# "is_linux": True, 

30# }, 

31# "windows-amd64": { 

32# "type": "Windows", 

33# "variant": "x86 64 bit", 

34# "is_windows": True, 

35# }, 

36# } 

37 

38 

39@dataclass(frozen=True) 

40class ApioPlatform: 

41 """A class with Apio supported platforms and their attributes.""" 

42 

43 # -- Platform id. 

44 id: str 

45 

46 # -- Human readable general platform type. 

47 type: str 

48 

49 # -- Human readable variant of the platform type. 

50 variant: str 

51 

52 # -- Set to True exactly one of these 

53 is_darwin: bool = False 

54 is_linux: bool = False 

55 is_windows: bool = False 

56 

57 def __post_init__(self): 

58 """Post init validation""" 

59 

60 # -- Constraint chars in platform id. 

61 assert re.fullmatch(r"[a-z0-9-]+", self.id), self.id 

62 

63 # -- Exactly one of the platform types should be true. 

64 assert ( 

65 sum([self.is_linux, self.is_windows, self.is_darwin]) == 1 

66 ), self.id 

67 

68 # -- Sanity check the matching between names and types. 

69 assert ("darwin" in self.id) == self.is_darwin, self.id 

70 assert ("linux" in self.id) == self.is_linux, self.id 

71 assert ("windows" in self.id) == self.is_windows, self.id 

72 

73 

74# -- The supported platforms as a dict with platform id as keys and 

75# -- ApioPlatform as values. It is constructed from the values in 

76# -- _SUPPORTED_PLATFORMS. 

77# _APIO_PLATFORMS: dict[str, ApioPlatform] = { 

78# id: ApioPlatform(id=id, **fields) 

79# for id, fields in _SUPPORTED_PLATFORMS.items() 

80# } 

81 

82# -- The list of supported platforms and their attribute. 

83_APIO_PLATFORMS_DICT = { 

84 "darwin-arm64": ApioPlatform( 

85 id="darwin-arm64", 

86 type="Mac OSX", 

87 variant="ARM 64 bit (Apple Silicon)", 

88 is_darwin=True, 

89 ), 

90 "linux-x86-64": ApioPlatform( 

91 id="linux-x86-64", 

92 type="Linux", 

93 variant="X86 64 bit", 

94 is_linux=True, 

95 ), 

96 "windows-amd64": ApioPlatform( 

97 id="windows-amd64", 

98 type="Windows", 

99 variant="x86 64 bit", 

100 is_windows=True, 

101 ), 

102} 

103 

104# -- Same set of platforms, but keyed by platform id. 

105# _APIO_PLATFORMS_DICT: dict[str, ApioPlatform] = { 

106# p.id: p for p in _APIO_PLATFORMS_LIST 

107# } 

108 

109# assert len(_APIO_PLATFORMS_LIST) == len(_APIO_PLATFORMS_DICT) 

110 

111 

112def _determine_system_platform_id() -> str: 

113 """Return a String with the current platform: 

114 ex. linux-x86-64 

115 ex. windows-amd64""" 

116 

117 # -- Get the platform: linux, windows, darwin 

118 type_ = platform.system().lower() 

119 platform_str = f"{type_}" 

120 

121 # -- Get the architecture 

122 arch = platform.machine().lower() 

123 

124 # -- Special case for windows 

125 if type_ == "windows": 125 ↛ 127line 125 didn't jump to line 127 because the condition on line 125 was never true

126 # -- Assume all the windows to be 64-bits 

127 arch = "amd64" 

128 

129 # -- Add the architecture, if it exists 

130 if arch: 130 ↛ 134line 130 didn't jump to line 134 because the condition on line 130 was always true

131 platform_str += f"_{arch}" 

132 

133 # -- Return the full platform 

134 return platform_str 

135 

136 

137def get_apio_platform() -> ApioPlatform: 

138 """Determines and returns the platform id based on system info and 

139 optional override.""" 

140 # -- Use override and get from the underlying system. 

141 platform_id_override = env_options.get(env_options.APIO_PLATFORM) 

142 if platform_id_override: 142 ↛ 143line 142 didn't jump to line 143 because the condition on line 142 was never true

143 platform_id = platform_id_override 

144 else: 

145 platform_id = _determine_system_platform_id() 

146 

147 # Stick to the naming conventions we use for boards, fpgas, etc. 

148 platform_id = platform_id.replace("_", "-") 

149 

150 # -- Verify it's valid. This can be a user error if the override 

151 # -- is invalid. 

152 if platform_id not in _APIO_PLATFORMS_DICT: 152 ↛ 153line 152 didn't jump to line 153 because the condition on line 152 was never true

153 fatal_error( 

154 f"Unknown platform id: [{platform_id}]", 

155 info="See Apio's documentation for supported platforms.", 

156 ) 

157 

158 # -- All done ok. 

159 return _APIO_PLATFORMS_DICT[platform_id] 

160 

161 

162def get_all_apio_platforms() -> dict[str, ApioPlatform]: 

163 """Return a dict with all supported platforms.""" 

164 return _APIO_PLATFORMS_DICT.copy() 

165 

166 

167def get_system_info() -> str: 

168 """Return a short string with additional platform info such as version.""" 

169 return platform.platform()