Coverage for pyEDAA/Launcher/__init__.py: 41%

80 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-20 22:15 +0000

1# ==================================================================================================================== # 

2# _____ ____ _ _ _ _ # 

3# _ __ _ _| ____| _ \ / \ / \ | | __ _ _ _ _ __ ___| |__ ___ _ __ # 

4# | '_ \| | | | _| | | | |/ _ \ / _ \ | | / _` | | | | '_ \ / __| '_ \ / _ \ '__| # 

5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| |__| (_| | |_| | | | | (__| | | | __/ | # 

6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_____\__,_|\__,_|_| |_|\___|_| |_|\___|_| # 

7# |_| |___/ # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Stefan Unrein # 

11# Patrick Lehmann # 

12# # 

13# License: # 

14# ==================================================================================================================== # 

15# Copyright 2021-2024 Stefan Unrein - Endingen, Germany # 

16# # 

17# Licensed under the Apache License, Version 2.0 (the "License"); # 

18# you may not use this file except in compliance with the License. # 

19# You may obtain a copy of the License at # 

20# # 

21# http://www.apache.org/licenses/LICENSE-2.0 # 

22# # 

23# Unless required by applicable law or agreed to in writing, software # 

24# distributed under the License is distributed on an "AS IS" BASIS, # 

25# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

26# See the License for the specific language governing permissions and # 

27# limitations under the License. # 

28# # 

29# SPDX-License-Identifier: Apache-2.0 # 

30# ==================================================================================================================== # 

31# 

32"""Start the correct Vivado Version based on version in `*.xpr`file.""" 

33__author__ = "Stefan Unrein" 

34__email__ = "stefan.unrein@gmx.net" 

35__copyright__ = "2021-2024, Stefan Unrein" 

36__license__ = "Apache License, Version 2.0" 

37__version__ = "0.1.0" 

38__keywords__ = ["launcher", "version selector", "xilinx", "vivado"] 

39 

40from re import compile as re_compile 

41 

42from sys import exit, argv 

43import subprocess 

44from pathlib import Path 

45from textwrap import dedent 

46from time import sleep 

47from typing import NoReturn, Generator 

48 

49from pyTooling.Decorators import export 

50 

51 

52@export 

53class Program: 

54 """Program instance of pyEDAA.Launcher.""" 

55 

56 vivadoBatchfile = Path("bin/vivado.bat") 

57 vvglWrapperFile = Path("bin/unwrapped/win64.o/vvgl.exe") 

58 

59 versionLineRegExp = re_compile(r"^<!--\s*Product\sVersion:\s+Vivado\s+v(?P<major>\d+).(?P<minor>\d+)(?:.(?P<patch>\d+))?\s+\(64-bit\)\s+-->") 

60 

61 _projectFilePath: Path 

62 

63 

64 def __init__(self, projectFilePath: Path) -> None: 

65 """Initializer. 

66 

67 :param projectFilePath: Path to the ``*.xpr`` file. 

68 :raises Exception: When the given ``*.xpr`` file doesn't exist. 

69 """ 

70 if not projectFilePath.exists(): 70 ↛ 71line 70 didn't jump to line 71 because the condition on line 70 was never true

71 raise Exception(f"Vivado project file '{projectFilePath}' not found.") \ 

72 from FileNotFoundError(f"File '{projectFilePath}' not found.") 

73 

74 self._projectFilePath = projectFilePath 

75 

76 def GetVersion(self) -> str: 

77 """Opens an ``*.xpr`` file and returns the Vivado version used to save this file. 

78 

79 :returns: Used Vivado version to save the given ``*.xpr`` file. 

80 :raises Exception: When the version information isn't found in the file. 

81 """ 

82 with self._projectFilePath.open("r", encoding="utf-8") as file: 

83 for line in file: 83 ↛ 88line 83 didn't jump to line 88 because the loop on line 83 didn't complete

84 match = self.versionLineRegExp.match(line) 

85 if match is not None: 

86 return f"{match['major']}.{match['minor']}" 

87 else: 

88 raise Exception(f"Pattern not found in '{self._projectFilePath}'.") 

89 

90 @classmethod 

91 def GetVivadoVersions(self, installPath: Path) -> Generator[str, None, None]: 

92 """Scan a given directory for installed Vivado versions. 

93 

94 :param installPath: Xilinx installation directory. 

95 :returns: A generator for a sequence of installed Vivado versions. 

96 """ 

97 for item in installPath.iterdir(): 

98 if item.is_dir(): 

99 yield item.name 

100 

101 def StartVivado(self, xilinxInstallationPath: Path, version: str) -> NoReturn: 

102 """Start the given Vivado version with an ``*.xpr`` file as parameter. 

103 

104 :param xilinxInstallationPath: Path to the Xilinx toolchain installations. 

105 :param version: The Vivado version to start. 

106 """ 

107 vivadoInstallationPath = xilinxInstallationPath / version 

108 

109 vvglWrapperPath = vivadoInstallationPath / self.vvglWrapperFile 

110 vivadoBatchfilePath = vivadoInstallationPath / self.vivadoBatchfile 

111 

112 cmd = [str(vvglWrapperPath), str(vivadoBatchfilePath), str(self._projectFilePath)] 

113 subprocess.Popen(cmd, cwd=self._projectFilePath.parent) # , creationflags=subprocess.DETACHED_PROCESS) 

114 

115 print("") 

116 print(f"Opening project with Vivado {version}.") 

117 

118 sleep(2) 

119 exit(0) 

120 

121 @classmethod 

122 def PrintHelp(cls, scriptPath: Path) -> None: 

123 """Print a help page. 

124 

125 :param scriptPath: Path to this script. 

126 """ 

127 print(dedent(f"""\ 

128 Run-Path '{scriptPath}' 

129 

130 For using this Launcher, please bind the *.xpr file extension to this executable with: 

131 * Put this executable into the Vivado installation folder. E.g: C:\\Xilinx\\Vivado\\ 

132 * Change *.xpr association: right-click -> open with -> VivadoManager.exe 

133 """)) 

134 

135 

136@export 

137def main() -> NoReturn: 

138 """Entry point function. 

139 

140 It creates an instance of :class:`Program` and hands over the execution to the OOP world. 

141 """ 

142 xilinxInstallationPath = Path.cwd() 

143 scriptPath = Path(argv[0]) 

144 

145 if (argc := len(argv)) == 0: 

146 Program.PrintHelp(scriptPath) 

147 

148 print(f"Current path '{xilinxInstallationPath}' contains the following folders:") 

149 for version in Program.GetVivadoVersions(xilinxInstallationPath): 

150 print(f"* {version}") 

151 

152 print("") 

153 print("Press any key to exit.") 

154 

155 # wait on user interaction 

156 input() 

157 exit(0) 

158 

159 elif argc == 1: 

160 projectFileArgument = argv[1] 

161 projectFilePath = Path(projectFileArgument) 

162 

163 program = Program(projectFilePath) 

164 

165 try: 

166 versionFromXPRFile = program.GetVersion() 

167 except Exception as ex: 

168 print(f"[ERROR] {ex}") 

169 exit(1) 

170 

171 for version in program.GetVivadoVersions(xilinxInstallationPath): 

172 if version == versionFromXPRFile: 

173 program.StartVivado(xilinxInstallationPath, versionFromXPRFile) 

174 else: 

175 vivadoPath = xilinxInstallationPath / versionFromXPRFile 

176 print(dedent(f"""\ 

177 ERROR: Vivado version {versionFromXPRFile} not available at path '{vivadoPath}'. Please start manually! 

178 

179 Press any key to exit. 

180 """)) 

181 

182 # wait on user interaction 

183 input() 

184 exit(1) 

185 

186 

187# Entry point 

188if __name__ == "__main__": 188 ↛ 189line 188 didn't jump to line 189 because the condition on line 188 was never true

189 main()