Coverage for src/km3dq_grl/defect-add.py: 0%

194 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-18 16:16 +0000

1#! /usr/bin/env python 

2############################################################################### 

3import os 

4import re 

5import time 

6import sys 

7import getpass 

8import readline # Mandatory for proper backspace handling. Do not remove 

9 

10from km3dq_grl import defect_path 

11 

12from km3dq_common.common_library import get_site 

13from km3dq_common.common_library import get_run_properties_from_qaqc 

14 

15from km3dq_common.config_library import configure_dataquality_tag 

16from km3dq_common.config_library import configure_defect 

17 

18############################################################################### 

19def get_current_git_branch(): 

20 """ Return the current git branch""" 

21 g_branch = os.popen("git branch") 

22 for i_branch in g_branch: 

23 if "*" in i_branch: 

24 rsb = re.compile(r"\*|\s|\n") 

25 return rsb.sub("", i_branch) 

26 

27 return "Unknown" 

28 

29 

30############################################################################### 

31def return_affected_runs(input_run, dataset): 

32 

33 # Single run 

34 r_test_single = re.compile(r"\s*([0-9]+)\s*") 

35 r_t = r_test_single.fullmatch(input_run) 

36 if r_t: 

37 run_list = [] 

38 run_list.append(int(r_t.group(1))) 

39 return run_list 

40 

41 # Run list 

42 r_test_list = re.compile(r"[0-9]+\s*[, \s 0-9]*") 

43 r_t = r_test_list.fullmatch(input_run) 

44 if r_t: 

45 r_test_list2 = re.compile(r"[0-9]+") 

46 run_list = r_test_list2.findall(input_run) 

47 return run_list 

48 

49 # Run range 

50 r_test_range = re.compile(r"\s*([0-9]+)\s*-\s*([0-9]+)\s*") 

51 r_t = r_test_range.fullmatch(input_run) 

52 if r_t: 

53 run1 = int(r_t.group(1)) 

54 run2 = int(r_t.group(2)) 

55 dq_tag_0 = configure_dataquality_tag('default') 

56 (run_qaqc, _) = get_run_properties_from_qaqc(dataset, 

57 dq_tag_0, 

58 "qaqc_sftp", 

59 run1, run2) 

60 run_list = run_qaqc['runNumber'] 

61 if len(run_list) > 0: 

62 print("I have found in the JQAQC file the following runs in the " 

63 f"run range {run1} - {run2}:") 

64 print(run_list) 

65 print("Some runs may be missing if not yet processed.") 

66 

67 answer0 = False 

68 while answer0 is False: 

69 confirm0 = input("Please confirm by typing YES or NO:") 

70 if confirm0 not in ("YES", "NO"): 

71 print("Type YES or NO") 

72 else: 

73 answer0 = True 

74 

75 if confirm0 == "YES": 

76 return run_list 

77 sys.exit() 

78 else: 

79 print("I have not found any run in the JQAQC file in the" 

80 f"run range {run1} - {run2}. Either there is no much PHYS" 

81 "in this range, either they are not yet processed.") 

82 

83 # No pattern found ! 

84 return [] 

85 

86 

87############################################################################### 

88# User inputs 

89 

90# Detector affected 

91answer = False 

92while answer is False: 

93 det = input("Detector ([A] / [O] for the current ARCA/ORCA detector): ") 

94 if det == "A": 

95 det = "D0ARCA028" 

96 elif det == "O": 

97 det = "D1ORCA019" 

98 site = get_site(det) 

99 

100 dq_tag = configure_dataquality_tag('default') 

101 

102 if det not in dq_tag['det'][site]: 

103 print("Unknown detector!") 

104 else: 

105 answer = True 

106 

107# Defect type 

108answer = False 

109print("Defect type: ") 

110avail_answer = [] 

111defects = configure_defect() 

112 

113for i_def in defects['bit'].keys(): 

114 avail_answer.append(i_def) 

115 

116for i_def, def_type in enumerate(avail_answer): 

117 print(f"{i_def}. {def_type}") 

118 

119while answer is False: 

120 def_type = input("") 

121 try: 

122 def_type_int = int(def_type) 

123 def_type = avail_answer[def_type_int] 

124 answer = True 

125 except ValueError: 

126 print("Please enter an integer") 

127 except IndexError: 

128 print(f"Please enter an integer between 0 and {len(avail_answer)-1}") 

129 

130# Defect description 

131answer = False 

132print("Defect description: ") 

133avail_answer = [] 

134for i_def in defects['bit'][def_type].keys(): 

135 avail_answer.append(i_def) 

136 

137for i_def, def_descr in enumerate(avail_answer): 

138 print(f"{i_def}. {def_descr}") 

139 

140while answer is False: 

141 def_descr = input("") 

142 try: 

143 def_descr_int = int(def_descr) 

144 def_descr = avail_answer[def_descr_int] 

145 answer = True 

146 except ValueError: 

147 print("Please enter an integer") 

148 except IndexError: 

149 print(f"Please enter an integer between 0 and {len(avail_answer)-1}") 

150 

151# Defect tag 

152def_tag = input("Defect tag (by default: def-HEAD): ") 

153if def_tag == "": 

154 def_tag = "def-HEAD" 

155 

156# Run affected 

157answer = False 

158while answer is False: 

159 run = input("Run, run list (separated by a coma)" 

160 " or run range (separated by a dash): ") 

161 processed_runs = return_affected_runs(run, det) 

162 

163 if len(processed_runs) == 0: 

164 print("No run found!") 

165 else: 

166 print(f"The {len(processed_runs)} following runs will be added:" 

167 f"{processed_runs}") 

168 answer = True 

169 

170# Issue / comment 

171answer = False 

172while answer is False: 

173 issue_comment = input("Issue / Comment: ") 

174 if len(issue_comment) < 10: 

175 print("Entry too short... Please add more details") 

176 else: 

177 answer = True 

178 

179# Documentation 

180print("If you do not have any elog reference, you can try searching " 

181 "with the link(s):") 

182for i_run in processed_runs: 

183 if "ARCA" in det: 

184 print(f"- https://elog.km3net.de/Operations+IT/?subtext={i_run}") 

185 else: 

186 print(f"- https://elog.km3net.de/Operations+FR/?subtext={i_run}") 

187documentation = input("Documentation (elog, gitlab issue...): ") 

188 

189# Recoverability 

190answer = False 

191while answer is False: 

192 recov = input("Recoverable? ([y]es, [n]o or [u]nknown): ") 

193 if recov not in ("y", "n", "u"): 

194 print("Type y, n or u") 

195 else: 

196 if recov == "u": 

197 recov = "?" 

198 answer = True 

199 

200# Author 

201answer = False 

202whoami = getpass.getuser() 

203while answer is False: 

204 author = input(f"Author (default: {whoami}): ") 

205 if author == "": 

206 author = whoami 

207 

208 date = time.strftime("%d/%m/%y", time.localtime()) 

209 author += f" ({date})" 

210 answer = True 

211 

212############################################################################### 

213# Treatment if user inputs 

214 

215# New entries (one per run) 

216# def_file = f"{site}/{det}/Defects/{def_type}_{def_descr}_{def_tag}.txt" 

217def_file = defect_path(def_type, def_descr, det, def_tag) 

218 

219new_entry = "" 

220for i_run in processed_runs: 

221 new_entry += (f"{i_run} | " 

222 f"{issue_comment} | " 

223 f"{documentation} | " 

224 f"{recov} | " 

225 f"{author}\n") 

226 

227# Git treatment 

228# If the current branch is main, propose to switch to new created branch 

229# Otherwise, leave the choice. 

230cur_git_branch = get_current_git_branch() 

231if cur_git_branch == "master": 

232 print("You are currently in master git branch. I will create a new one " 

233 "for your defect upload\n") 

234 git_branch = cur_git_branch 

235 new_branch = "y" 

236else: 

237 print(f"You are currently in {cur_git_branch} branch. You can either " 

238 "keep on working on this branch for a bulk upload or create a " 

239 "new one") 

240 

241 answer = False 

242 while answer is False: 

243 new_branch = input("Do you want to create a new branch?" 

244 "([y]es, [n]o):") 

245 if new_branch not in ("y", "n"): 

246 print("Type y or n") 

247 else: 

248 answer = True 

249 

250# Checks that the defect file exist and ask for a final confirmation 

251if os.path.exists(def_file) is False: 

252 print(f"Defect file {def_file} does not exists." 

253 "I am creating it and adding it to git repository.") 

254 with open(def_file, "w", encoding="utf-8") as new_file: 

255 new_file.write("Run Number | " 

256 "Issue / Comment | " 

257 "Documentation | " 

258 "Recov. | " 

259 "Author\n") 

260 cmd = f"git add {def_file}" 

261 os.popen(cmd) 

262 

263print(f"I am about to add the following defect for the {det} detector:\n" 

264 f"{new_entry}\n" 

265 f"Defect file: {def_file}") 

266 

267answer = False 

268while answer is False: 

269 confirm = input("Please confirm by typing [YES] or [NO]:") 

270 if confirm not in ("YES", "NO"): 

271 print("Type YES or NO") 

272 else: 

273 answer = True 

274 

275if confirm == "NO": 

276 sys.exit() 

277 

278# Create the new branch if requested 

279if new_branch == "y": 

280 branch_time = time.strftime("%d_%m_%y_%H_%M", time.localtime()) 

281 git_branch = f"main-defect-upload-{branch_time}" 

282 cmd = f"git checkout -b {git_branch}" 

283 os.popen(cmd) 

284 

285 print(f"You are now working in {git_branch} branch.") 

286else: 

287 git_branch = cur_git_branch 

288 

289# And finally update the file 

290with open(def_file, "r", encoding="utf-8") as orig: 

291 with open(f"{def_file}_tmp", "w", encoding="utf-8") as fin: 

292 lines = orig.readlines() 

293 first_line = True 

294 for i_line in lines: 

295 fin.write(i_line) 

296 if first_line: # New entry is at the top of the defect file 

297 fin.write(new_entry) 

298 first_line = False 

299 

300cmd = f"mv {def_file}_tmp {def_file}" 

301os.popen(cmd) 

302 

303cmd = f"git commit {def_file} -m '{det} defect added by {author}'" 

304os.popen(cmd) 

305 

306print("The defect upload has been commited in the new branch.\n" 

307 "You can add more defects in the same branch.\n\n" 

308 "When your modifications are complete, proceed with:\n" 

309 f"- git push --set-upstream origin {git_branch}\n" 

310 "- Request the merging", 

311 "Once the branch is merged, the defect page will be automatically " 

312 "updated\n") 

313print("Do not forget to git fetch / git merge when you are back in " 

314 "the main branch")