Coverage for src/jobs/scripts.py: 100.00%

65 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-10-18 15:02 +0000

1#!/usr/bin/env python3 

2 

3# Standard libraries 

4from pathlib import Path 

5from sys import exc_info 

6from typing import Dict, List 

7 

8# Components 

9from ..types.files import Files, TempFile 

10from ..types.paths import Paths 

11 

12# ScriptsFile class 

13class ScriptsFile: 

14 

15 # Constants 

16 __SEPARATOR: str = '\n' 

17 SHEBANG_MARKER_BASH: str = '__GITLAB_CI_LOCAL_SHEBANG_MARKER_BASH__' 

18 

19 # Members 

20 __file: TempFile # type: ignore[type-arg] 

21 __folder: str 

22 __ready: bool 

23 __target: str 

24 

25 # Constructor 

26 def __init__( 

27 self, 

28 paths: Dict[str, str], 

29 prefix: str = '.tmp.', 

30 ) -> None: 

31 

32 # Variables 

33 error = '' 

34 

35 # Initialize members 

36 self.__folder = '' 

37 self.__ready = False 

38 self.__target = '' 

39 

40 # Iterate through paths 

41 for path in paths: 

42 

43 # Prepare temporary script 

44 try: 

45 self.__file = Files.temp(path=path, prefix=prefix) 

46 self.__folder = path 

47 if paths[path]: 

48 self.__target = Paths.get( 

49 Path(paths[path]) / Path(self.__file.name).name) 

50 self.__ready = True 

51 break 

52 except PermissionError: 

53 error = str(exc_info()[1]) 

54 

55 # Failed temporary script 

56 if not self.__ready: 

57 raise PermissionError(error) 

58 

59 # Configure 

60 def configure( 

61 self, 

62 errors: bool = True, 

63 verbose: bool = True, 

64 ) -> None: 

65 

66 # Write configuration 

67 self.writelines([ 

68 ' # Configurations', 

69 f" set -{'e' if errors else ''}{'x' if verbose else ''}", 

70 '', 

71 ]) 

72 

73 # Close 

74 def close(self) -> None: 

75 

76 # Flush file 

77 self.flush() 

78 

79 # Close file 

80 self.__file.close() 

81 

82 # Flush 

83 def flush(self) -> None: 

84 

85 # Flush file 

86 if not self.__file.closed: 

87 self.__file.flush() 

88 

89 # Folder 

90 @property 

91 def folder(self) -> str: 

92 

93 # Result 

94 return self.__folder 

95 

96 # Name 

97 @property 

98 def name(self) -> str: 

99 

100 # Result 

101 return self.__file.name 

102 

103 # Print 

104 def print(self) -> None: 

105 

106 # Flush file 

107 self.flush() 

108 

109 # Print content 

110 with open(self.__file.name, encoding='utf8', mode='r') as file: 

111 print(file.read()) 

112 

113 # Shebang 

114 def shebang(self) -> None: 

115 

116 # Write shebang 

117 self.write('#!/bin/sh') 

118 self.write('') 

119 

120 # Write shebang wrapper 

121 self.writelines([ 

122 '# Bash shebang wrapper', 

123 f'if [ -z "${{{self.SHEBANG_MARKER_BASH}}}" ] && type bash >/dev/null 2>&1; then', 

124 f' {self.SHEBANG_MARKER_BASH}=true bash "${0}"', 

125 ' exit "${?}"', 

126 'fi', 

127 '', 

128 ]) 

129 

130 # Subgroup start 

131 def subgroup_start(self) -> None: 

132 

133 # Write subgroup start 

134 self.write('{') 

135 

136 # Subgroup stop 

137 def subgroup_stop(self) -> None: 

138 

139 # Write subgroup stop 

140 self.write('}') 

141 

142 # Subshell start 

143 def subshell_start( 

144 self, 

145 section: str, 

146 ) -> None: 

147 

148 # Write subshell start 

149 self.write(f'# Section {section}') 

150 self.write('(') 

151 

152 # Subshell stop 

153 def subshell_stop( 

154 self, 

155 section: str, 

156 ) -> None: 

157 

158 # Write subshell stop 

159 self.write(') 2>&1') 

160 self.write(f'# Section {section}') 

161 

162 # Target 

163 def target(self) -> str: 

164 

165 # Result 

166 return self.__target 

167 

168 # Write 

169 def write(self, line: str = '') -> None: 

170 

171 # Write line 

172 self.__file.write(line) 

173 self.__file.write(self.__SEPARATOR) 

174 

175 # Write lines 

176 def writelines( 

177 self, 

178 lines: List[str], 

179 ) -> None: 

180 

181 # Write line 

182 self.__file.write(self.__SEPARATOR.join(lines)) 

183 self.__file.write(self.__SEPARATOR)