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
« 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
10from km3dq_grl import defect_path
12from km3dq_common.common_library import get_site
13from km3dq_common.common_library import get_run_properties_from_qaqc
15from km3dq_common.config_library import configure_dataquality_tag
16from km3dq_common.config_library import configure_defect
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)
27 return "Unknown"
30###############################################################################
31def return_affected_runs(input_run, dataset):
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
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
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.")
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
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.")
83 # No pattern found !
84 return []
87###############################################################################
88# User inputs
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)
100 dq_tag = configure_dataquality_tag('default')
102 if det not in dq_tag['det'][site]:
103 print("Unknown detector!")
104 else:
105 answer = True
107# Defect type
108answer = False
109print("Defect type: ")
110avail_answer = []
111defects = configure_defect()
113for i_def in defects['bit'].keys():
114 avail_answer.append(i_def)
116for i_def, def_type in enumerate(avail_answer):
117 print(f"{i_def}. {def_type}")
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}")
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)
137for i_def, def_descr in enumerate(avail_answer):
138 print(f"{i_def}. {def_descr}")
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}")
151# Defect tag
152def_tag = input("Defect tag (by default: def-HEAD): ")
153if def_tag == "":
154 def_tag = "def-HEAD"
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)
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
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
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...): ")
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
200# Author
201answer = False
202whoami = getpass.getuser()
203while answer is False:
204 author = input(f"Author (default: {whoami}): ")
205 if author == "":
206 author = whoami
208 date = time.strftime("%d/%m/%y", time.localtime())
209 author += f" ({date})"
210 answer = True
212###############################################################################
213# Treatment if user inputs
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)
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")
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")
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
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)
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}")
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
275if confirm == "NO":
276 sys.exit()
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)
285 print(f"You are now working in {git_branch} branch.")
286else:
287 git_branch = cur_git_branch
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
300cmd = f"mv {def_file}_tmp {def_file}"
301os.popen(cmd)
303cmd = f"git commit {def_file} -m '{det} defect added by {author}'"
304os.popen(cmd)
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")