44# Ian Ashworth, May 2025
55#
66import http .client
7+ import signal
78from sys import api_version
89import sys
910import csv
1819
1920http .client ._MAXHEADERS = 1000
2021
22+ job_status = 0
23+
2124logging .basicConfig (
2225 level = logging .INFO ,
2326 format = "[%(asctime)s] {%(module)s:%(lineno)d} %(levelname)s - %(message)s"
2427)
2528
29+ # initialise
30+ all_my_comp_data = []
31+ my_statistics = {}
32+
33+
2634def RepDebug (level , msg ):
2735 if hasattr (args , 'debug' ) and level <= args .debug :
2836 print ("dbg{" + str (level ) + "} " + msg )
@@ -33,6 +41,59 @@ def RepWarning(msg):
3341 print ("WARNING: " + msg )
3442 return True
3543
44+ def CompleteTask (job_status ):
45+ now = datetime .datetime .now ()
46+ my_statistics ['_jobStatus' ] = job_status
47+
48+ print ('Finished: %s' % now .strftime ("%Y-%m-%d %H:%M:%S" ))
49+ print ('Summary:' )
50+ pprint (my_statistics )
51+
52+ # if dumping data
53+ if args .dump_data :
54+ # if outputting to a CSV file
55+ if args .csv_file :
56+ '''Note: See the BD API doc and in particular .../api-doc/public.html#_bom_vulnerability_endpoints
57+ for a complete list of the fields available. The below code shows a subset of them just to
58+ illustrate how to write out the data into a CSV format.
59+ '''
60+ logging .info (f"Exporting { len (all_my_comp_data )} records to CSV file { args .csv_file } " )
61+
62+ with open (args .csv_file , 'w' ) as csv_f :
63+ field_names = [
64+ 'Component' ,
65+ 'Component Version' ,
66+ 'Status' ,
67+ 'Url'
68+ ]
69+
70+ writer = csv .DictWriter (csv_f , fieldnames = field_names )
71+ writer .writeheader ()
72+
73+ for my_comp_data in all_my_comp_data :
74+ row_data = {
75+ 'Component' : my_comp_data ['componentName' ],
76+ 'Component Version' : my_comp_data ['componentVersion' ],
77+ 'Status' : my_comp_data ['status' ],
78+ 'Url' : my_comp_data ['url' ]
79+ }
80+ writer .writerow (row_data )
81+ else :
82+ # print to screen
83+ pprint (all_my_comp_data )
84+
85+ def SignalHandler (sig , frame ):
86+ # Complete the work
87+ print ("Ctrl+C detected!" )
88+
89+ # tidy up and complete the job
90+ CompleteTask (1 )
91+ sys .exit (job_status )
92+
93+ # ------------------------------------------------------------------------------
94+ # register the signal handler
95+ signal .signal (signal .SIGINT , SignalHandler )
96+
3697
3798# Parse command line arguments
3899parser = argparse .ArgumentParser ("Refresh copyrights for project/version components" )
@@ -74,9 +135,8 @@ def RepWarning(msg):
74135 retries = args .retries ,
75136)
76137
77- # initialise
78- all_my_comp_data = []
79- my_statistics = {}
138+
139+ str_unknown = "n/a"
80140
81141str_unknown = "n/a"
82142
@@ -121,10 +181,13 @@ def RepWarning(msg):
121181my_statistics ['_cntProjects' ] = 0
122182my_statistics ['_cntVersions' ] = 0
123183my_statistics ['_cntComponents' ] = 0
184+ my_statistics ['_cntOrigins' ] = 0
185+
124186my_statistics ['_cntRefresh' ] = 0
125187my_statistics ['_cntNoOrigins' ] = 0
126188my_statistics ['_cntNoIDs' ] = 0
127189my_statistics ['_cntSkippedProjects' ] = 0
190+ my_statistics ['_jobStatus' ] = 0
128191
129192# record any control values
130193if args .project_name :
@@ -156,17 +219,18 @@ def RepWarning(msg):
156219 projects = bd .get_resource ('projects' )
157220
158221
159- cnt_projects = 0
222+ cnt_project = 0
223+ cnt_call = 0
160224
161225# loop through projects list
162226for this_project in projects :
163227
164- cnt_projects += 1
228+ cnt_project += 1
165229
166230 # check if we are skipping over this project
167- if args .skip_projects and cnt_projects <= args .skip_projects :
231+ if args .skip_projects and cnt_project <= args .skip_projects :
168232 my_statistics ['_cntSkippedProjects' ] += 1
169- RepDebug (1 , 'Skipping project [%d] [%s]' % (cnt_projects , this_project ['name' ]))
233+ RepDebug (1 , 'Skipping project [%d] [%s]' % (cnt_project , this_project ['name' ]))
170234 continue
171235
172236 # check if we have hit any limit
@@ -180,7 +244,7 @@ def RepWarning(msg):
180244
181245 # process this project
182246 my_statistics ['_cntProjects' ] += 1
183- RepDebug (1 , '## Project: [%d] [%s]' % (cnt_projects , this_project ['name' ]))
247+ RepDebug (1 , '## Project: [%d] [%s]' % (cnt_project , this_project ['name' ]))
184248
185249 if args .version_name :
186250 # note the specific project version of interest
@@ -220,7 +284,6 @@ def RepWarning(msg):
220284 for this_comp_data in bd .get_resource ('components' , this_version , ** comp_kwargs ):
221285
222286 if args .max_components and my_statistics ['_cntComponents' ] >= args .max_components :
223- RepDebug (1 , 'Reached component limit [%d]' % args .max_components )
224287 break
225288
226289 my_statistics ['_cntComponents' ] += 1
@@ -255,6 +318,8 @@ def RepWarning(msg):
255318 for this_origin in this_comp_data ['origins' ]:
256319
257320 n_origin += 1
321+ my_statistics ['_cntOrigins' ] += 1
322+
258323 if this_origin .get ('externalId' ):
259324 origin_id = this_origin ['externalId' ]
260325 else :
@@ -266,10 +331,14 @@ def RepWarning(msg):
266331 url += "/copyrights-refresh"
267332
268333 status = - 1
334+ cnt_call += 1
335+ call_id = "{}.{}" .format (cnt_project , cnt_call )
269336
270337 if args .dry_run != 0 :
271- RepDebug (2 , " DryRun: origin - no [%d] id [%s] url [%s]" % (n_origin , origin_id , url ))
338+ RepDebug (2 , ' DryRun: %s - origin - no [%d] id [%s] url [%s]' % (call_id , n_origin , origin_id , url ))
272339 else :
340+ RepDebug (3 ,
341+ ' Origin: %s - origin - no [%d] id [%s] url [%s]' % (call_id , n_origin , origin_id , url ))
273342 try :
274343 response = bd .session .put (url , data = None , ** refresh_kwargs )
275344 RepDebug (5 ,'Refresh response: origin [%s] [%s]' % (this_origin , response ))
@@ -319,42 +388,5 @@ def RepWarning(msg):
319388
320389# end of processing loop
321390
322- now = datetime .datetime .now ()
323- print ('Finished: %s' % now .strftime ("%Y-%m-%d %H:%M:%S" ))
324- print ('Summary:' )
325- pprint (my_statistics )
326-
327- # if dumping data
328- if args .dump_data :
329- # if outputting to a CSV file
330- if args .csv_file :
331- '''Note: See the BD API doc and in particular .../api-doc/public.html#_bom_vulnerability_endpoints
332- for a complete list of the fields available. The below code shows a subset of them just to
333- illustrate how to write out the data into a CSV format.
334- '''
335- logging .info (f"Exporting { len (all_my_comp_data )} records to CSV file { args .csv_file } " )
336-
337- with open (args .csv_file , 'w' ) as csv_f :
338- field_names = [
339- 'Component' ,
340- 'Component Version' ,
341- 'Status' ,
342- 'Url'
343- ]
344-
345- writer = csv .DictWriter (csv_f , fieldnames = field_names )
346- writer .writeheader ()
347-
348- for my_comp_data in all_my_comp_data :
349- row_data = {
350- 'Component' : my_comp_data ['componentName' ],
351- 'Component Version' : my_comp_data ['componentVersion' ],
352- 'Status' : my_comp_data ['status' ],
353- 'Url' : my_comp_data ['url' ]
354- }
355- writer .writerow (row_data )
356- else :
357- # print to screen
358- pprint (all_my_comp_data )
359-
391+ CompleteTask (0 )
360392#end
0 commit comments