4
4
# Ian Ashworth, May 2025
5
5
#
6
6
import http .client
7
+ import signal
7
8
from sys import api_version
8
9
import sys
9
10
import csv
18
19
19
20
http .client ._MAXHEADERS = 1000
20
21
22
+ job_status = 0
23
+
21
24
logging .basicConfig (
22
25
level = logging .INFO ,
23
26
format = "[%(asctime)s] {%(module)s:%(lineno)d} %(levelname)s - %(message)s"
24
27
)
25
28
29
+ # initialise
30
+ all_my_comp_data = []
31
+ my_statistics = {}
32
+
33
+
26
34
def RepDebug (level , msg ):
27
35
if hasattr (args , 'debug' ) and level <= args .debug :
28
36
print ("dbg{" + str (level ) + "} " + msg )
@@ -33,6 +41,59 @@ def RepWarning(msg):
33
41
print ("WARNING: " + msg )
34
42
return True
35
43
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
+
36
97
37
98
# Parse command line arguments
38
99
parser = argparse .ArgumentParser ("Refresh copyrights for project/version components" )
@@ -74,9 +135,8 @@ def RepWarning(msg):
74
135
retries = args .retries ,
75
136
)
76
137
77
- # initialise
78
- all_my_comp_data = []
79
- my_statistics = {}
138
+
139
+ str_unknown = "n/a"
80
140
81
141
str_unknown = "n/a"
82
142
@@ -121,10 +181,13 @@ def RepWarning(msg):
121
181
my_statistics ['_cntProjects' ] = 0
122
182
my_statistics ['_cntVersions' ] = 0
123
183
my_statistics ['_cntComponents' ] = 0
184
+ my_statistics ['_cntOrigins' ] = 0
185
+
124
186
my_statistics ['_cntRefresh' ] = 0
125
187
my_statistics ['_cntNoOrigins' ] = 0
126
188
my_statistics ['_cntNoIDs' ] = 0
127
189
my_statistics ['_cntSkippedProjects' ] = 0
190
+ my_statistics ['_jobStatus' ] = 0
128
191
129
192
# record any control values
130
193
if args .project_name :
@@ -156,17 +219,18 @@ def RepWarning(msg):
156
219
projects = bd .get_resource ('projects' )
157
220
158
221
159
- cnt_projects = 0
222
+ cnt_project = 0
223
+ cnt_call = 0
160
224
161
225
# loop through projects list
162
226
for this_project in projects :
163
227
164
- cnt_projects += 1
228
+ cnt_project += 1
165
229
166
230
# 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 :
168
232
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' ]))
170
234
continue
171
235
172
236
# check if we have hit any limit
@@ -180,7 +244,7 @@ def RepWarning(msg):
180
244
181
245
# process this project
182
246
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' ]))
184
248
185
249
if args .version_name :
186
250
# note the specific project version of interest
@@ -220,7 +284,6 @@ def RepWarning(msg):
220
284
for this_comp_data in bd .get_resource ('components' , this_version , ** comp_kwargs ):
221
285
222
286
if args .max_components and my_statistics ['_cntComponents' ] >= args .max_components :
223
- RepDebug (1 , 'Reached component limit [%d]' % args .max_components )
224
287
break
225
288
226
289
my_statistics ['_cntComponents' ] += 1
@@ -255,6 +318,8 @@ def RepWarning(msg):
255
318
for this_origin in this_comp_data ['origins' ]:
256
319
257
320
n_origin += 1
321
+ my_statistics ['_cntOrigins' ] += 1
322
+
258
323
if this_origin .get ('externalId' ):
259
324
origin_id = this_origin ['externalId' ]
260
325
else :
@@ -266,10 +331,14 @@ def RepWarning(msg):
266
331
url += "/copyrights-refresh"
267
332
268
333
status = - 1
334
+ cnt_call += 1
335
+ call_id = "{}.{}" .format (cnt_project , cnt_call )
269
336
270
337
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 ))
272
339
else :
340
+ RepDebug (3 ,
341
+ ' Origin: %s - origin - no [%d] id [%s] url [%s]' % (call_id , n_origin , origin_id , url ))
273
342
try :
274
343
response = bd .session .put (url , data = None , ** refresh_kwargs )
275
344
RepDebug (5 ,'Refresh response: origin [%s] [%s]' % (this_origin , response ))
@@ -319,42 +388,5 @@ def RepWarning(msg):
319
388
320
389
# end of processing loop
321
390
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 )
360
392
#end
0 commit comments