xref: /aosp_15_r20/external/mesa3d/bin/ci/custom_logger.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Workerimport argparse
2*61046927SAndroid Build Coastguard Workerimport logging
3*61046927SAndroid Build Coastguard Workerfrom datetime import datetime
4*61046927SAndroid Build Coastguard Workerfrom pathlib import Path
5*61046927SAndroid Build Coastguard Worker
6*61046927SAndroid Build Coastguard Workerfrom structured_logger import StructuredLogger
7*61046927SAndroid Build Coastguard Worker
8*61046927SAndroid Build Coastguard Worker
9*61046927SAndroid Build Coastguard Workerclass CustomLogger:
10*61046927SAndroid Build Coastguard Worker    def __init__(self, log_file):
11*61046927SAndroid Build Coastguard Worker        self.log_file = log_file
12*61046927SAndroid Build Coastguard Worker        self.logger = StructuredLogger(file_name=self.log_file)
13*61046927SAndroid Build Coastguard Worker
14*61046927SAndroid Build Coastguard Worker    def get_last_dut_job(self):
15*61046927SAndroid Build Coastguard Worker        """
16*61046927SAndroid Build Coastguard Worker        Gets the details of the most recent DUT job.
17*61046927SAndroid Build Coastguard Worker
18*61046927SAndroid Build Coastguard Worker        Returns:
19*61046927SAndroid Build Coastguard Worker            dict: Details of the most recent DUT job.
20*61046927SAndroid Build Coastguard Worker
21*61046927SAndroid Build Coastguard Worker        Raises:
22*61046927SAndroid Build Coastguard Worker            ValueError: If no DUT jobs are found in the logger's data.
23*61046927SAndroid Build Coastguard Worker        """
24*61046927SAndroid Build Coastguard Worker        try:
25*61046927SAndroid Build Coastguard Worker            job = self.logger.data["dut_jobs"][-1]
26*61046927SAndroid Build Coastguard Worker        except KeyError:
27*61046927SAndroid Build Coastguard Worker            raise ValueError(
28*61046927SAndroid Build Coastguard Worker                "No DUT jobs found. Please create a job via create_dut_job call."
29*61046927SAndroid Build Coastguard Worker            )
30*61046927SAndroid Build Coastguard Worker
31*61046927SAndroid Build Coastguard Worker        return job
32*61046927SAndroid Build Coastguard Worker
33*61046927SAndroid Build Coastguard Worker    def update(self, **kwargs):
34*61046927SAndroid Build Coastguard Worker        """
35*61046927SAndroid Build Coastguard Worker        Updates the log file with provided key-value pairs.
36*61046927SAndroid Build Coastguard Worker
37*61046927SAndroid Build Coastguard Worker        Args:
38*61046927SAndroid Build Coastguard Worker            **kwargs: Key-value pairs to be updated.
39*61046927SAndroid Build Coastguard Worker
40*61046927SAndroid Build Coastguard Worker        """
41*61046927SAndroid Build Coastguard Worker        with self.logger.edit_context():
42*61046927SAndroid Build Coastguard Worker            for key, value in kwargs.items():
43*61046927SAndroid Build Coastguard Worker                self.logger.data[key] = value
44*61046927SAndroid Build Coastguard Worker
45*61046927SAndroid Build Coastguard Worker    def create_dut_job(self, **kwargs):
46*61046927SAndroid Build Coastguard Worker        """
47*61046927SAndroid Build Coastguard Worker        Creates a new DUT job with provided key-value pairs.
48*61046927SAndroid Build Coastguard Worker
49*61046927SAndroid Build Coastguard Worker        Args:
50*61046927SAndroid Build Coastguard Worker            **kwargs: Key-value pairs for the new DUT job.
51*61046927SAndroid Build Coastguard Worker
52*61046927SAndroid Build Coastguard Worker        """
53*61046927SAndroid Build Coastguard Worker        with self.logger.edit_context():
54*61046927SAndroid Build Coastguard Worker            if "dut_jobs" not in self.logger.data:
55*61046927SAndroid Build Coastguard Worker                self.logger.data["dut_jobs"] = []
56*61046927SAndroid Build Coastguard Worker            new_job = {
57*61046927SAndroid Build Coastguard Worker                "status": "",
58*61046927SAndroid Build Coastguard Worker                "submitter_start_time": datetime.now().isoformat(),
59*61046927SAndroid Build Coastguard Worker                "dut_submit_time": "",
60*61046927SAndroid Build Coastguard Worker                "dut_start_time": "",
61*61046927SAndroid Build Coastguard Worker                "dut_end_time": "",
62*61046927SAndroid Build Coastguard Worker                "dut_name": "",
63*61046927SAndroid Build Coastguard Worker                "dut_state": "pending",
64*61046927SAndroid Build Coastguard Worker                "dut_job_phases": [],
65*61046927SAndroid Build Coastguard Worker                **kwargs,
66*61046927SAndroid Build Coastguard Worker            }
67*61046927SAndroid Build Coastguard Worker            self.logger.data["dut_jobs"].append(new_job)
68*61046927SAndroid Build Coastguard Worker
69*61046927SAndroid Build Coastguard Worker    def update_dut_job(self, key, value):
70*61046927SAndroid Build Coastguard Worker        """
71*61046927SAndroid Build Coastguard Worker        Updates the last DUT job with a key-value pair.
72*61046927SAndroid Build Coastguard Worker
73*61046927SAndroid Build Coastguard Worker        Args:
74*61046927SAndroid Build Coastguard Worker            key : The key to be updated.
75*61046927SAndroid Build Coastguard Worker            value: The value to be assigned.
76*61046927SAndroid Build Coastguard Worker
77*61046927SAndroid Build Coastguard Worker        """
78*61046927SAndroid Build Coastguard Worker        with self.logger.edit_context():
79*61046927SAndroid Build Coastguard Worker            job = self.get_last_dut_job()
80*61046927SAndroid Build Coastguard Worker            job[key] = value
81*61046927SAndroid Build Coastguard Worker
82*61046927SAndroid Build Coastguard Worker    def update_status_fail(self, reason=""):
83*61046927SAndroid Build Coastguard Worker        """
84*61046927SAndroid Build Coastguard Worker        Sets the status of the last DUT job to 'fail' and logs the failure reason.
85*61046927SAndroid Build Coastguard Worker
86*61046927SAndroid Build Coastguard Worker        Args:
87*61046927SAndroid Build Coastguard Worker            reason (str, optional): The reason for the failure. Defaults to "".
88*61046927SAndroid Build Coastguard Worker
89*61046927SAndroid Build Coastguard Worker        """
90*61046927SAndroid Build Coastguard Worker        with self.logger.edit_context():
91*61046927SAndroid Build Coastguard Worker            job = self.get_last_dut_job()
92*61046927SAndroid Build Coastguard Worker            job["status"] = "fail"
93*61046927SAndroid Build Coastguard Worker            job["dut_job_fail_reason"] = reason
94*61046927SAndroid Build Coastguard Worker
95*61046927SAndroid Build Coastguard Worker    def create_job_phase(self, phase_name):
96*61046927SAndroid Build Coastguard Worker        """
97*61046927SAndroid Build Coastguard Worker        Creates a new job phase for the last DUT job.
98*61046927SAndroid Build Coastguard Worker
99*61046927SAndroid Build Coastguard Worker        Args:
100*61046927SAndroid Build Coastguard Worker            phase_name : The name of the new job phase.
101*61046927SAndroid Build Coastguard Worker
102*61046927SAndroid Build Coastguard Worker        """
103*61046927SAndroid Build Coastguard Worker        with self.logger.edit_context():
104*61046927SAndroid Build Coastguard Worker            job = self.get_last_dut_job()
105*61046927SAndroid Build Coastguard Worker            if job["dut_job_phases"] and job["dut_job_phases"][-1]["end_time"] == "":
106*61046927SAndroid Build Coastguard Worker                # If the last phase exists and its end time is empty, set the end time
107*61046927SAndroid Build Coastguard Worker                job["dut_job_phases"][-1]["end_time"] = datetime.now().isoformat()
108*61046927SAndroid Build Coastguard Worker
109*61046927SAndroid Build Coastguard Worker            # Create a new phase
110*61046927SAndroid Build Coastguard Worker            phase_data = {
111*61046927SAndroid Build Coastguard Worker                "name": phase_name,
112*61046927SAndroid Build Coastguard Worker                "start_time": datetime.now().isoformat(),
113*61046927SAndroid Build Coastguard Worker                "end_time": "",
114*61046927SAndroid Build Coastguard Worker            }
115*61046927SAndroid Build Coastguard Worker            job["dut_job_phases"].append(phase_data)
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker    def check_dut_timings(self, job):
118*61046927SAndroid Build Coastguard Worker        """
119*61046927SAndroid Build Coastguard Worker        Check the timing sequence of a job to ensure logical consistency.
120*61046927SAndroid Build Coastguard Worker
121*61046927SAndroid Build Coastguard Worker        The function verifies that the job's submission time is not earlier than its start time and that
122*61046927SAndroid Build Coastguard Worker        the job's end time is not earlier than its start time. If either of these conditions is found to be true,
123*61046927SAndroid Build Coastguard Worker        an error is logged for each instance of inconsistency.
124*61046927SAndroid Build Coastguard Worker
125*61046927SAndroid Build Coastguard Worker        Args:
126*61046927SAndroid Build Coastguard Worker        job (dict): A dictionary containing timing information of a job. Expected keys are 'dut_start_time',
127*61046927SAndroid Build Coastguard Worker                    'dut_submit_time', and 'dut_end_time'.
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker        Returns:
130*61046927SAndroid Build Coastguard Worker        None: This function does not return a value; it logs errors if timing inconsistencies are detected.
131*61046927SAndroid Build Coastguard Worker
132*61046927SAndroid Build Coastguard Worker        The function checks the following:
133*61046927SAndroid Build Coastguard Worker        - If 'dut_start_time' and 'dut_submit_time' are both present and correctly sequenced.
134*61046927SAndroid Build Coastguard Worker        - If 'dut_start_time' and 'dut_end_time' are both present and correctly sequenced.
135*61046927SAndroid Build Coastguard Worker        """
136*61046927SAndroid Build Coastguard Worker
137*61046927SAndroid Build Coastguard Worker        # Check if the start time and submit time exist
138*61046927SAndroid Build Coastguard Worker        if job.get("dut_start_time") and job.get("dut_submit_time"):
139*61046927SAndroid Build Coastguard Worker            # If they exist, check if the submission time is before the start time
140*61046927SAndroid Build Coastguard Worker            if job["dut_start_time"] < job["dut_submit_time"]:
141*61046927SAndroid Build Coastguard Worker                logging.error("Job submission is happening before job start.")
142*61046927SAndroid Build Coastguard Worker
143*61046927SAndroid Build Coastguard Worker        # Check if the start time and end time exist
144*61046927SAndroid Build Coastguard Worker        if job.get("dut_start_time") and job.get("dut_end_time"):
145*61046927SAndroid Build Coastguard Worker            # If they exist, check if the end time is after the start time
146*61046927SAndroid Build Coastguard Worker            if job["dut_end_time"] < job["dut_start_time"]:
147*61046927SAndroid Build Coastguard Worker                logging.error("Job ended before it started.")
148*61046927SAndroid Build Coastguard Worker
149*61046927SAndroid Build Coastguard Worker    # Method to update DUT start, submit and end time
150*61046927SAndroid Build Coastguard Worker    def update_dut_time(self, value, custom_time):
151*61046927SAndroid Build Coastguard Worker        """
152*61046927SAndroid Build Coastguard Worker        Updates DUT start, submit, and end times.
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker        Args:
155*61046927SAndroid Build Coastguard Worker            value : Specifies which DUT time to update. Options: 'start', 'submit', 'end'.
156*61046927SAndroid Build Coastguard Worker            custom_time : Custom time to set. If None, use current time.
157*61046927SAndroid Build Coastguard Worker
158*61046927SAndroid Build Coastguard Worker        Raises:
159*61046927SAndroid Build Coastguard Worker            ValueError: If an invalid argument is provided for value.
160*61046927SAndroid Build Coastguard Worker
161*61046927SAndroid Build Coastguard Worker        """
162*61046927SAndroid Build Coastguard Worker        with self.logger.edit_context():
163*61046927SAndroid Build Coastguard Worker            job = self.get_last_dut_job()
164*61046927SAndroid Build Coastguard Worker            timestamp = custom_time if custom_time else datetime.now().isoformat()
165*61046927SAndroid Build Coastguard Worker            if value == "start":
166*61046927SAndroid Build Coastguard Worker                job["dut_start_time"] = timestamp
167*61046927SAndroid Build Coastguard Worker                job["dut_state"] = "running"
168*61046927SAndroid Build Coastguard Worker            elif value == "submit":
169*61046927SAndroid Build Coastguard Worker                job["dut_submit_time"] = timestamp
170*61046927SAndroid Build Coastguard Worker                job["dut_state"] = "submitted"
171*61046927SAndroid Build Coastguard Worker            elif value == "end":
172*61046927SAndroid Build Coastguard Worker                job["dut_end_time"] = timestamp
173*61046927SAndroid Build Coastguard Worker                job["dut_state"] = "finished"
174*61046927SAndroid Build Coastguard Worker            else:
175*61046927SAndroid Build Coastguard Worker                raise ValueError(
176*61046927SAndroid Build Coastguard Worker                    "Error: Invalid argument provided for --update-dut-time. Use 'start', 'submit', 'end'."
177*61046927SAndroid Build Coastguard Worker                )
178*61046927SAndroid Build Coastguard Worker            # check the sanity of the partial structured log
179*61046927SAndroid Build Coastguard Worker            self.check_dut_timings(job)
180*61046927SAndroid Build Coastguard Worker
181*61046927SAndroid Build Coastguard Worker    def close_dut_job(self):
182*61046927SAndroid Build Coastguard Worker        """
183*61046927SAndroid Build Coastguard Worker        Closes the most recent DUT (Device Under Test) job in the logger's data.
184*61046927SAndroid Build Coastguard Worker
185*61046927SAndroid Build Coastguard Worker        The method performs the following operations:
186*61046927SAndroid Build Coastguard Worker        1. Validates if there are any DUT jobs in the logger's data.
187*61046927SAndroid Build Coastguard Worker        2. If the last phase of the most recent DUT job has an empty end time, it sets the end time to the current time.
188*61046927SAndroid Build Coastguard Worker
189*61046927SAndroid Build Coastguard Worker        Raises:
190*61046927SAndroid Build Coastguard Worker            ValueError: If no DUT jobs are found in the logger's data.
191*61046927SAndroid Build Coastguard Worker        """
192*61046927SAndroid Build Coastguard Worker        with self.logger.edit_context():
193*61046927SAndroid Build Coastguard Worker            job = self.get_last_dut_job()
194*61046927SAndroid Build Coastguard Worker            # Check if the last phase exists and its end time is empty, then set the end time
195*61046927SAndroid Build Coastguard Worker            if job["dut_job_phases"] and job["dut_job_phases"][-1]["end_time"] == "":
196*61046927SAndroid Build Coastguard Worker                job["dut_job_phases"][-1]["end_time"] = datetime.now().isoformat()
197*61046927SAndroid Build Coastguard Worker
198*61046927SAndroid Build Coastguard Worker    def close(self):
199*61046927SAndroid Build Coastguard Worker        """
200*61046927SAndroid Build Coastguard Worker        Closes the most recent DUT (Device Under Test) job in the logger's data.
201*61046927SAndroid Build Coastguard Worker
202*61046927SAndroid Build Coastguard Worker        The method performs the following operations:
203*61046927SAndroid Build Coastguard Worker        1. Determines the combined status of all DUT jobs.
204*61046927SAndroid Build Coastguard Worker        2. Sets the submitter's end time to the current time.
205*61046927SAndroid Build Coastguard Worker        3. Updates the DUT attempt counter to reflect the total number of DUT jobs.
206*61046927SAndroid Build Coastguard Worker
207*61046927SAndroid Build Coastguard Worker        """
208*61046927SAndroid Build Coastguard Worker        with self.logger.edit_context():
209*61046927SAndroid Build Coastguard Worker            job_status = []
210*61046927SAndroid Build Coastguard Worker            for job in self.logger.data["dut_jobs"]:
211*61046927SAndroid Build Coastguard Worker                if "status" in job:
212*61046927SAndroid Build Coastguard Worker                    job_status.append(job["status"])
213*61046927SAndroid Build Coastguard Worker
214*61046927SAndroid Build Coastguard Worker            if not job_status:
215*61046927SAndroid Build Coastguard Worker                job_combined_status = "null"
216*61046927SAndroid Build Coastguard Worker            else:
217*61046927SAndroid Build Coastguard Worker                # Get job_combined_status
218*61046927SAndroid Build Coastguard Worker                if "pass" in job_status:
219*61046927SAndroid Build Coastguard Worker                    job_combined_status = "pass"
220*61046927SAndroid Build Coastguard Worker                else:
221*61046927SAndroid Build Coastguard Worker                    job_combined_status = "fail"
222*61046927SAndroid Build Coastguard Worker
223*61046927SAndroid Build Coastguard Worker            self.logger.data["job_combined_status"] = job_combined_status
224*61046927SAndroid Build Coastguard Worker            self.logger.data["dut_attempt_counter"] = len(self.logger.data["dut_jobs"])
225*61046927SAndroid Build Coastguard Worker            job["submitter_end_time"] = datetime.now().isoformat()
226*61046927SAndroid Build Coastguard Worker
227*61046927SAndroid Build Coastguard Worker
228*61046927SAndroid Build Coastguard Workerdef process_args(args):
229*61046927SAndroid Build Coastguard Worker    # Function to process key-value pairs and call corresponding logger methods
230*61046927SAndroid Build Coastguard Worker    def process_key_value_pairs(args_list, action_func):
231*61046927SAndroid Build Coastguard Worker        if not args_list:
232*61046927SAndroid Build Coastguard Worker            raise ValueError(
233*61046927SAndroid Build Coastguard Worker                f"No key-value pairs provided for {action_func.__name__.replace('_', '-')}"
234*61046927SAndroid Build Coastguard Worker            )
235*61046927SAndroid Build Coastguard Worker        if len(args_list) % 2 != 0:
236*61046927SAndroid Build Coastguard Worker            raise ValueError(
237*61046927SAndroid Build Coastguard Worker                f"Incomplete key-value pairs for {action_func.__name__.replace('_', '-')}"
238*61046927SAndroid Build Coastguard Worker            )
239*61046927SAndroid Build Coastguard Worker        kwargs = dict(zip(args_list[::2], args_list[1::2]))
240*61046927SAndroid Build Coastguard Worker        action_func(**kwargs)
241*61046927SAndroid Build Coastguard Worker
242*61046927SAndroid Build Coastguard Worker    # Create a CustomLogger object with the specified log file path
243*61046927SAndroid Build Coastguard Worker    custom_logger = CustomLogger(Path(args.log_file))
244*61046927SAndroid Build Coastguard Worker
245*61046927SAndroid Build Coastguard Worker    if args.update:
246*61046927SAndroid Build Coastguard Worker        process_key_value_pairs(args.update, custom_logger.update)
247*61046927SAndroid Build Coastguard Worker
248*61046927SAndroid Build Coastguard Worker    if args.create_dut_job:
249*61046927SAndroid Build Coastguard Worker        process_key_value_pairs(args.create_dut_job, custom_logger.create_dut_job)
250*61046927SAndroid Build Coastguard Worker
251*61046927SAndroid Build Coastguard Worker    if args.update_dut_job:
252*61046927SAndroid Build Coastguard Worker        key, value = args.update_dut_job
253*61046927SAndroid Build Coastguard Worker        custom_logger.update_dut_job(key, value)
254*61046927SAndroid Build Coastguard Worker
255*61046927SAndroid Build Coastguard Worker    if args.create_job_phase:
256*61046927SAndroid Build Coastguard Worker        custom_logger.create_job_phase(args.create_job_phase)
257*61046927SAndroid Build Coastguard Worker
258*61046927SAndroid Build Coastguard Worker    if args.update_status_fail:
259*61046927SAndroid Build Coastguard Worker        custom_logger.update_status_fail(args.update_status_fail)
260*61046927SAndroid Build Coastguard Worker
261*61046927SAndroid Build Coastguard Worker    if args.update_dut_time:
262*61046927SAndroid Build Coastguard Worker        if len(args.update_dut_time) == 2:
263*61046927SAndroid Build Coastguard Worker            action, custom_time = args.update_dut_time
264*61046927SAndroid Build Coastguard Worker        elif len(args.update_dut_time) == 1:
265*61046927SAndroid Build Coastguard Worker            action, custom_time = args.update_dut_time[0], None
266*61046927SAndroid Build Coastguard Worker        else:
267*61046927SAndroid Build Coastguard Worker            raise ValueError("Invalid number of values for --update-dut-time")
268*61046927SAndroid Build Coastguard Worker
269*61046927SAndroid Build Coastguard Worker        if action in ["start", "end", "submit"]:
270*61046927SAndroid Build Coastguard Worker            custom_logger.update_dut_time(action, custom_time)
271*61046927SAndroid Build Coastguard Worker        else:
272*61046927SAndroid Build Coastguard Worker            raise ValueError(
273*61046927SAndroid Build Coastguard Worker                "Error: Invalid argument provided for --update-dut-time. Use 'start', 'submit', 'end'."
274*61046927SAndroid Build Coastguard Worker            )
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Worker    if args.close_dut_job:
277*61046927SAndroid Build Coastguard Worker        custom_logger.close_dut_job()
278*61046927SAndroid Build Coastguard Worker
279*61046927SAndroid Build Coastguard Worker    if args.close:
280*61046927SAndroid Build Coastguard Worker        custom_logger.close()
281*61046927SAndroid Build Coastguard Worker
282*61046927SAndroid Build Coastguard Worker
283*61046927SAndroid Build Coastguard Workerdef main():
284*61046927SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(description="Custom Logger Command Line Tool")
285*61046927SAndroid Build Coastguard Worker    parser.add_argument("log_file", help="Path to the log file")
286*61046927SAndroid Build Coastguard Worker    parser.add_argument(
287*61046927SAndroid Build Coastguard Worker        "--update",
288*61046927SAndroid Build Coastguard Worker        nargs=argparse.ZERO_OR_MORE,
289*61046927SAndroid Build Coastguard Worker        metavar=("key", "value"),
290*61046927SAndroid Build Coastguard Worker        help="Update a key-value pair e.g., --update key1 value1 key2 value2)",
291*61046927SAndroid Build Coastguard Worker    )
292*61046927SAndroid Build Coastguard Worker    parser.add_argument(
293*61046927SAndroid Build Coastguard Worker        "--create-dut-job",
294*61046927SAndroid Build Coastguard Worker        nargs=argparse.ZERO_OR_MORE,
295*61046927SAndroid Build Coastguard Worker        metavar=("key", "value"),
296*61046927SAndroid Build Coastguard Worker        help="Create a new DUT job with key-value pairs (e.g., --create-dut-job key1 value1 key2 value2)",
297*61046927SAndroid Build Coastguard Worker    )
298*61046927SAndroid Build Coastguard Worker    parser.add_argument(
299*61046927SAndroid Build Coastguard Worker        "--update-dut-job",
300*61046927SAndroid Build Coastguard Worker        nargs=argparse.ZERO_OR_MORE,
301*61046927SAndroid Build Coastguard Worker        metavar=("key", "value"),
302*61046927SAndroid Build Coastguard Worker        help="Update a key-value pair in DUT job",
303*61046927SAndroid Build Coastguard Worker    )
304*61046927SAndroid Build Coastguard Worker    parser.add_argument(
305*61046927SAndroid Build Coastguard Worker        "--create-job-phase",
306*61046927SAndroid Build Coastguard Worker        help="Create a new job phase (e.g., --create-job-phase name)",
307*61046927SAndroid Build Coastguard Worker    )
308*61046927SAndroid Build Coastguard Worker    parser.add_argument(
309*61046927SAndroid Build Coastguard Worker        "--update-status-fail",
310*61046927SAndroid Build Coastguard Worker        help="Update fail as the status and log the failure reason (e.g., --update-status-fail reason)",
311*61046927SAndroid Build Coastguard Worker    )
312*61046927SAndroid Build Coastguard Worker    parser.add_argument(
313*61046927SAndroid Build Coastguard Worker        "--update-dut-time",
314*61046927SAndroid Build Coastguard Worker        nargs=argparse.ZERO_OR_MORE,
315*61046927SAndroid Build Coastguard Worker        metavar=("action", "custom_time"),
316*61046927SAndroid Build Coastguard Worker        help="Update DUT start and end time. Provide action ('start', 'submit', 'end') and custom_time (e.g., '2023-01-01T12:00:00')",
317*61046927SAndroid Build Coastguard Worker    )
318*61046927SAndroid Build Coastguard Worker    parser.add_argument(
319*61046927SAndroid Build Coastguard Worker        "--close-dut-job",
320*61046927SAndroid Build Coastguard Worker        action="store_true",
321*61046927SAndroid Build Coastguard Worker        help="Close the dut job by updating end time of last dut job)",
322*61046927SAndroid Build Coastguard Worker    )
323*61046927SAndroid Build Coastguard Worker    parser.add_argument(
324*61046927SAndroid Build Coastguard Worker        "--close",
325*61046927SAndroid Build Coastguard Worker        action="store_true",
326*61046927SAndroid Build Coastguard Worker        help="Updates combined status, submitter's end time and DUT attempt counter",
327*61046927SAndroid Build Coastguard Worker    )
328*61046927SAndroid Build Coastguard Worker    args = parser.parse_args()
329*61046927SAndroid Build Coastguard Worker
330*61046927SAndroid Build Coastguard Worker    process_args(args)
331*61046927SAndroid Build Coastguard Worker
332*61046927SAndroid Build Coastguard Worker
333*61046927SAndroid Build Coastguard Workerif __name__ == "__main__":
334*61046927SAndroid Build Coastguard Worker    main()
335