capycli 2.0.0.dev8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. License.md +27 -0
  2. capycli/__init__.py +214 -0
  3. capycli/__main__.py +13 -0
  4. capycli/bom/__init__.py +10 -0
  5. capycli/bom/bom_convert.py +163 -0
  6. capycli/bom/check_bom.py +187 -0
  7. capycli/bom/check_bom_item_status.py +197 -0
  8. capycli/bom/check_granularity.py +244 -0
  9. capycli/bom/create_components.py +644 -0
  10. capycli/bom/csv.py +69 -0
  11. capycli/bom/diff_bom.py +279 -0
  12. capycli/bom/download_sources.py +227 -0
  13. capycli/bom/filter_bom.py +323 -0
  14. capycli/bom/findsources.py +278 -0
  15. capycli/bom/handle_bom.py +134 -0
  16. capycli/bom/html.py +67 -0
  17. capycli/bom/legacy.py +312 -0
  18. capycli/bom/legacy_cx.py +151 -0
  19. capycli/bom/map_bom.py +1039 -0
  20. capycli/bom/merge_bom.py +155 -0
  21. capycli/bom/plaintext.py +69 -0
  22. capycli/bom/show_bom.py +77 -0
  23. capycli/common/__init__.py +9 -0
  24. capycli/common/capycli_bom_support.py +629 -0
  25. capycli/common/comparable_version.py +161 -0
  26. capycli/common/component_cache.py +240 -0
  27. capycli/common/dependencies_base.py +48 -0
  28. capycli/common/file_support.py +28 -0
  29. capycli/common/html_support.py +119 -0
  30. capycli/common/json_support.py +36 -0
  31. capycli/common/map_result.py +116 -0
  32. capycli/common/print.py +55 -0
  33. capycli/common/purl_service.py +169 -0
  34. capycli/common/purl_store.py +100 -0
  35. capycli/common/purl_utils.py +85 -0
  36. capycli/common/script_base.py +165 -0
  37. capycli/common/script_support.py +78 -0
  38. capycli/data/__init__.py +9 -0
  39. capycli/data/granularity_list.csv +1338 -0
  40. capycli/dependencies/__init__.py +9 -0
  41. capycli/dependencies/handle_dependencies.py +70 -0
  42. capycli/dependencies/javascript.py +261 -0
  43. capycli/dependencies/maven_list.py +333 -0
  44. capycli/dependencies/maven_pom.py +150 -0
  45. capycli/dependencies/nuget.py +184 -0
  46. capycli/dependencies/python.py +345 -0
  47. capycli/main/__init__.py +9 -0
  48. capycli/main/application.py +165 -0
  49. capycli/main/argument_parser.py +101 -0
  50. capycli/main/cli.py +28 -0
  51. capycli/main/exceptions.py +14 -0
  52. capycli/main/options.py +424 -0
  53. capycli/main/result_codes.py +41 -0
  54. capycli/mapping/handle_mapping.py +46 -0
  55. capycli/mapping/mapping_to_html.py +182 -0
  56. capycli/mapping/mapping_to_xlsx.py +197 -0
  57. capycli/moverview/handle_moverview.py +46 -0
  58. capycli/moverview/moverview_to_html.py +122 -0
  59. capycli/moverview/moverview_to_xlsx.py +170 -0
  60. capycli/project/__init__.py +9 -0
  61. capycli/project/check_prerequisites.py +304 -0
  62. capycli/project/create_bom.py +190 -0
  63. capycli/project/create_project.py +335 -0
  64. capycli/project/create_readme.py +546 -0
  65. capycli/project/find_project.py +128 -0
  66. capycli/project/get_license_info.py +246 -0
  67. capycli/project/handle_project.py +118 -0
  68. capycli/project/show_ecc.py +200 -0
  69. capycli/project/show_licenses.py +211 -0
  70. capycli/project/show_project.py +215 -0
  71. capycli/project/show_vulnerabilities.py +238 -0
  72. capycli-2.0.0.dev8.dist-info/LICENSES/CC0-1.0.txt +121 -0
  73. capycli-2.0.0.dev8.dist-info/LICENSES/MIT.txt +27 -0
  74. capycli-2.0.0.dev8.dist-info/License.md +27 -0
  75. capycli-2.0.0.dev8.dist-info/METADATA +268 -0
  76. capycli-2.0.0.dev8.dist-info/RECORD +78 -0
  77. capycli-2.0.0.dev8.dist-info/WHEEL +4 -0
  78. capycli-2.0.0.dev8.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,424 @@
1
+ # -------------------------------------------------------------------------------
2
+ # Copyright (c) 2019-23 Siemens
3
+ # All Rights Reserved.
4
+ # Author: thomas.graf@siemens.com
5
+ #
6
+ # SPDX-License-Identifier: MIT
7
+ # -------------------------------------------------------------------------------
8
+
9
+ """Contains the logic for all of the default options for CaPyCli."""
10
+
11
+ import os
12
+
13
+ import tomli
14
+
15
+ import capycli
16
+ from capycli.bom.bom_convert import BomFormat
17
+ from capycli.main.argument_parser import ArgumentParser
18
+
19
+ LOG = capycli.get_logger(__name__)
20
+
21
+
22
+ class CommandlineSupport():
23
+ CONFIG_FILE_NAME = ".capycli.cfg"
24
+
25
+ def __init__(self):
26
+ custom_prog = "CaPyCli, " + capycli.get_app_version()
27
+ custom_usage = "CaPyCli command subcommand [options]"
28
+ command_help = """Commands and Sub-Commands
29
+ getdependencies dependency detection specific commands
30
+ Nuget determine dependencies for a .Net/Nuget project
31
+ Python determine dependencies for a Python project
32
+ Javascript determine dependencies for a JavaScript project
33
+ MavenPom determine dependencies for a Java/Maven project using the pom.xml file
34
+ MavenList determine dependencies for a Java/Maven project using a Maven command
35
+
36
+ bom bill of material (BOM) specific commands
37
+ Show display contents of a SBOM
38
+ Convert convert SBOM formats
39
+ Filter apply filter file to a SBOM
40
+ Check check that all releases in the SBOM exist on target SW360 instance
41
+ CheckItemStatus show additional information about SBOM items on SW360
42
+ Map map a given SBOM to data on SW360
43
+ CreateReleases create new releases for existing components on SW360
44
+ CreateComponents create new components and releases on SW360 (use with care!)
45
+ DownloadSources download source files from the URL specified in the SBOM
46
+ Granularity check a bill of material for potential component granularity issues
47
+ Diff compare two bills of material.
48
+ Merge merge two bills of material.
49
+ Findsources determine the source code for SBOM items.
50
+
51
+ mapping
52
+ ToHtml create a HTML page showing the mapping result
53
+ ToXlsx create an Excel sheet showing the mapping result
54
+
55
+ moverview
56
+ ToHtml create a HTML page showing the mapping result overview
57
+ ToXlsx create an Excel sheet showing the mapping result overview
58
+
59
+ project
60
+ Find find a project by name
61
+ Prerequisites checks whether all prerequisites for a successfull
62
+ software clearing are fulfilled
63
+ Show show project details
64
+ Licenses show licenses of all cleared compponents
65
+ Create create or update a project on SW360
66
+ Update update an exiting project, preserving linked releases
67
+ GetLicenseInfo get license info of all project components
68
+ CreateReadme create a Readme_OSS
69
+ Vulnerabilities show security vulnerabilities of a project
70
+ ECC show export control status of a project
71
+
72
+ Note that each command has also its own help display, i.e. if you enter
73
+ `capycli project vulnerabilities -h` you will get a help that only shows the options
74
+ for this specific sub-command.
75
+ Entering `capycli project -h` shows all available sub-commands of the project command.
76
+ """
77
+ self.parser = ArgumentParser(
78
+ prog=custom_prog,
79
+ usage=custom_usage,
80
+ description="SW360 Clearing Automation Command Line Interface, version " + capycli.get_app_version())
81
+ self.parser.add_command_help(command_help)
82
+
83
+ # store all positional argument in command
84
+ self.parser.add_argument(
85
+ "command",
86
+ nargs="+",
87
+ help="command and subcommand to process")
88
+
89
+ self.parser.add_argument(
90
+ "-h",
91
+ "--help",
92
+ help="show a help message and exit",
93
+ action="store_true",
94
+ )
95
+
96
+ self.register_options()
97
+
98
+ def register_options(self):
99
+ input_formats = []
100
+ input_formats.append(BomFormat.TEXT)
101
+ input_formats.append(BomFormat.CSV)
102
+ input_formats.append(BomFormat.LEGACY)
103
+ input_formats.append(BomFormat.LEGACY_CX)
104
+ input_formats.append(BomFormat.SBOM)
105
+ input_formats.append(BomFormat.CAPYCLI)
106
+
107
+ output_formats = []
108
+ output_formats.append(BomFormat.CAPYCLI)
109
+ output_formats.append(BomFormat.SBOM)
110
+ output_formats.append(BomFormat.TEXT)
111
+ output_formats.append(BomFormat.CSV)
112
+ output_formats.append(BomFormat.LEGACY)
113
+ output_formats.append(BomFormat.HTML)
114
+
115
+ self.parser.add_argument(
116
+ "-i",
117
+ "--inputfile",
118
+ dest="inputfile",
119
+ help="input file to read from",
120
+ )
121
+
122
+ self.parser.add_argument(
123
+ "-ri",
124
+ "--raw-input",
125
+ dest="raw_input",
126
+ help="raw data input file to parse repository urls"
127
+ )
128
+
129
+ self.parser.add_argument(
130
+ "-o",
131
+ "--outputfile",
132
+ dest="outputfile",
133
+ help="output file to write to",
134
+ )
135
+
136
+ self.parser.add_argument(
137
+ "-filterfile",
138
+ dest="filterfile",
139
+ help="filter file to use",
140
+ )
141
+
142
+ self.parser.add_argument(
143
+ "-v",
144
+ help="be verbose",
145
+ dest="verbose",
146
+ action="store_true",
147
+ )
148
+
149
+ self.parser.add_argument(
150
+ "-t",
151
+ "--token",
152
+ dest="sw360_token",
153
+ help="use this token for access to SW360",
154
+ )
155
+
156
+ self.parser.add_argument(
157
+ "-oa",
158
+ "--oauth2",
159
+ help="this is an oauth2 token",
160
+ action="store_true",
161
+ )
162
+
163
+ self.parser.add_argument(
164
+ "-url",
165
+ dest="sw360_url",
166
+ help="use this URL for access to SW360"
167
+ )
168
+
169
+ self.parser.add_argument(
170
+ "--nocache",
171
+ dest="nocache",
172
+ help="do not use component cache",
173
+ action="store_true"
174
+ )
175
+
176
+ self.parser.add_argument(
177
+ "-cf",
178
+ "--cachefile",
179
+ dest="cachefile",
180
+ help="cache file name to use",
181
+ )
182
+
183
+ self.parser.add_argument(
184
+ "-rc",
185
+ "--refresh_cache",
186
+ dest="refresh_cache",
187
+ help="refresh component cache",
188
+ action="store_true",
189
+ )
190
+
191
+ self.parser.add_argument(
192
+ "-sc",
193
+ "--similar",
194
+ help="look for components with similar name",
195
+ action="store_true",
196
+ )
197
+
198
+ self.parser.add_argument(
199
+ "-ov",
200
+ "--overview",
201
+ dest="create_overview",
202
+ help="create an mapping overview JSON file",
203
+ )
204
+
205
+ self.parser.add_argument(
206
+ "-mr",
207
+ "--mapresult",
208
+ dest="write_mapresult",
209
+ help="create a JSON file with the mapping details",
210
+ )
211
+
212
+ # used by project commands
213
+ self.parser.add_argument(
214
+ "-name",
215
+ help="name of the project"
216
+ )
217
+
218
+ # used by project commands
219
+ self.parser.add_argument(
220
+ "-version",
221
+ help="version of the project"
222
+ )
223
+
224
+ # used by project commands
225
+ self.parser.add_argument(
226
+ "-id",
227
+ dest="id",
228
+ help="SW360 id of the project, supersedes name and version parameters"
229
+ )
230
+
231
+ # used by GetLicenseInfo
232
+ self.parser.add_argument(
233
+ "-ncli",
234
+ "--no-overwrite-cli",
235
+ dest="ncli",
236
+ help="do not overwrite existing CLI files",
237
+ action="store_true",
238
+ )
239
+
240
+ # used by GetLicenseInfo
241
+ self.parser.add_argument(
242
+ "-nconf",
243
+ "--no-overwrite-config",
244
+ dest="nconf",
245
+ help="do not overwrite an existing configuration file",
246
+ action="store_true",
247
+ )
248
+
249
+ # used by GetLicenseInfo
250
+ self.parser.add_argument(
251
+ "-dest",
252
+ "--destination",
253
+ dest="destination",
254
+ help="the destination folder",
255
+ )
256
+
257
+ # used by CreateProject
258
+ self.parser.add_argument(
259
+ "-source",
260
+ dest="source",
261
+ help="source folder or additional source file"
262
+ )
263
+
264
+ # special parsing flag for MapBom
265
+ self.parser.add_argument(
266
+ "--dbx",
267
+ dest="dbx",
268
+ help="relaxed handling of debian version numbers (check subcommand help!)",
269
+ action="store_true",
270
+ )
271
+
272
+ self.parser.add_argument(
273
+ "--download",
274
+ help="enable automatic download of missing sources",
275
+ action="store_true",
276
+ )
277
+
278
+ # used by getdependencies python
279
+ self.parser.add_argument(
280
+ "--search-meta-data",
281
+ dest="search_meta_data",
282
+ help="search for component meta-data",
283
+ action="store_true",
284
+ )
285
+
286
+ # used by project create
287
+ self.parser.add_argument(
288
+ "-old-version",
289
+ dest="old_version",
290
+ help="previous version "
291
+ )
292
+
293
+ self.parser.add_argument(
294
+ "-ex",
295
+ help="show exit code",
296
+ action="store_true",
297
+ )
298
+
299
+ # used by bom map
300
+ self.parser.add_argument(
301
+ "-rr",
302
+ dest="result_required",
303
+ help="there must be a clearing result available",
304
+ action="store_true"
305
+ )
306
+
307
+ # used by getdependencies python
308
+ self.parser.add_argument(
309
+ "-package-source",
310
+ dest="package_source",
311
+ help="URL of the package manager to use",
312
+ )
313
+
314
+ # used by bom CheckItemStatus
315
+ self.parser.add_argument(
316
+ "-all",
317
+ help="show/use all items",
318
+ action="store_true",
319
+ )
320
+
321
+ # used by ShowSecurityVulnerability
322
+ self.parser.add_argument(
323
+ "-format",
324
+ dest="format",
325
+ help="format to use (text, json, xml)",
326
+ )
327
+
328
+ # used by ShowSecurityVulnerability
329
+ self.parser.add_argument(
330
+ "-fe",
331
+ "--forceexit",
332
+ dest="force_exit",
333
+ help="force a specific exit code",
334
+ )
335
+
336
+ # used by MapBom
337
+ self.parser.add_argument(
338
+ "-m",
339
+ "--mode",
340
+ dest="mode",
341
+ help="specific mode for some commands",
342
+ )
343
+
344
+ # used by bom convert
345
+ self.parser.add_argument(
346
+ "-if",
347
+ choices=input_formats,
348
+ dest="inputformat",
349
+ help="Specify input file format")
350
+
351
+ # used by bom convert
352
+ self.parser.add_argument(
353
+ "-of",
354
+ choices=output_formats,
355
+ dest="outputformat",
356
+ help="Specify output file format")
357
+
358
+ self.parser.add_argument(
359
+ "-X",
360
+ dest="debug", action="store_true",
361
+ help="Enable debug output")
362
+
363
+ def read_config(self, filename: str = None, config_string: str = None) -> dict:
364
+ """
365
+ Read configuration from string or config file.
366
+ """
367
+
368
+ toml_dict = None
369
+ try:
370
+ if config_string:
371
+ toml_dict = tomli.loads(config_string)
372
+ elif filename:
373
+ with open(filename, "rb") as f:
374
+ toml_dict = tomli.load(f)
375
+ else:
376
+ if os.path.isfile(self.CONFIG_FILE_NAME):
377
+ with open(self.CONFIG_FILE_NAME, "rb") as f:
378
+ toml_dict = tomli.load(f)
379
+
380
+ if not toml_dict:
381
+ return None
382
+
383
+ if "capycli" not in toml_dict:
384
+ return None
385
+
386
+ return toml_dict["capycli"]
387
+ except tomli.TOMLDecodeError as tex:
388
+ LOG.warning("Config file has invalid format: " + repr(tex))
389
+ except Exception as ex:
390
+ LOG.warning("Error reading config file: " + repr(ex))
391
+
392
+ def process_commandline(self, argv):
393
+ """Reads the command line arguments"""
394
+ args = self.parser.parse_args(argv)
395
+ cfg = self.read_config()
396
+
397
+ if cfg:
398
+ for key in cfg:
399
+ args_key = key
400
+
401
+ # handle some common naming mistakes
402
+ if args_key == "url":
403
+ args_key = "sw360_url"
404
+ if args_key == "url":
405
+ args_key = "sw360_url"
406
+ if args_key == "raw-input":
407
+ args_key = "raw_input"
408
+ if args_key == "token":
409
+ args_key = "sw360_token"
410
+ if args_key == "oa":
411
+ args_key = "oauth2"
412
+ if args_key == "search-meta-data":
413
+ args_key = "search_meta_data"
414
+ if args_key == "old-version":
415
+ args_key = "old_version"
416
+ if args_key == "package-source":
417
+ args_key = "package_source"
418
+ if args_key == "forceexit":
419
+ args_key = "force_exit"
420
+
421
+ if hasattr(args, args_key) and not args.__getattribute__(args_key):
422
+ args.__setattr__(args_key, cfg[key])
423
+
424
+ return args
@@ -0,0 +1,41 @@
1
+ # -------------------------------------------------------------------------------
2
+ # Copyright 2023 Siemens
3
+ # All Rights Reserved.
4
+ # Author: thomas.graf@siemens.com
5
+ #
6
+ # SPDX-License-Identifier: MIT
7
+ # -------------------------------------------------------------------------------
8
+
9
+ class ResultCode(object):
10
+ # application result codes
11
+
12
+ # default
13
+ RESULT_OPERATION_SUCCEEDED = 0
14
+
15
+ # general errors as defined in https://tldp.org/LDP/abs/html/exitcodes.html
16
+ RESULT_GENERAL_ERROR = 1
17
+
18
+ # predefined errors from /usr/include/sysexits.h
19
+ RESULT_COMMAND_ERROR = 64 # command was used incorrectly
20
+ RESULT_ERROR_READING_BOM = 65 # input data was incorrect
21
+ RESULT_FILE_NOT_FOUND = 66 # input file did not exist or was not readable
22
+ RESULT_ERROR_ACCESSING_SERVICE = 69 # a service is unavailable
23
+ RESULT_ERROR_WRITING_FILE = 73 # output file cannot be created
24
+ RESULT_AUTH_ERROR = 77 # insufficient permission to perform some operation, SW360 login failed
25
+ RESULT_ERROR_WRITING_BOM = 78
26
+
27
+ # use 80-113 for our exit codes, see https://tldp.org/LDP/abs/html/exitcodes.html
28
+
29
+ # custom result codes
30
+ RESULT_NO_UNIQUE_MAPPING = 80
31
+ RESULT_INCOMPLETE_MAPPING = 81
32
+ RESULT_UNHANDLED_SECURITY_VULNERABILITY_FOUND = 82
33
+
34
+ # custom errors
35
+ RESULT_ERROR_CREATING_COMPONENT = 90
36
+ RESULT_ERROR_CREATING_RELEASE = 91
37
+ RESULT_ERROR_CREATING_ITEM = 92
38
+ RESULT_NO_CACHED_RELEASES = 93
39
+ RESULT_PROJECT_NOT_FOUND = 94
40
+ RESULT_ERROR_ACCESSING_SW360 = 95
41
+ RESULT_FILTER_ERROR = 96
@@ -0,0 +1,46 @@
1
+ # -------------------------------------------------------------------------------
2
+ # Copyright (c) 2019-23 Siemens
3
+ # All Rights Reserved.
4
+ # Author: thomas.graf@siemens.com
5
+ #
6
+ # SPDX-License-Identifier: MIT
7
+ # -------------------------------------------------------------------------------
8
+
9
+ import sys
10
+
11
+ import capycli.mapping.mapping_to_html
12
+ import capycli.mapping.mapping_to_xlsx
13
+ from capycli.common.print import print_red
14
+ from capycli.main.result_codes import ResultCode
15
+
16
+
17
+ def run_mapping_command(args):
18
+ command = args.command[0].lower()
19
+ if command != "mapping":
20
+ return
21
+
22
+ if len(args.command) < 2:
23
+ print_red("No subcommand specified!")
24
+ print()
25
+
26
+ # display `mapping` related help
27
+ print("mapping - mapping sub-commands")
28
+ print(" ToHtml create a HTML page showing the mapping result")
29
+ print(" ToXlsx create an Excel sheet showing the mapping result")
30
+ return
31
+
32
+ subcommand = args.command[1].lower()
33
+ if subcommand == "tohtml":
34
+ """Create a HTML page showing the mapping result."""
35
+ app = capycli.mapping.mapping_to_html.MappingToHtml()
36
+ app.run(args)
37
+ return
38
+
39
+ if subcommand == "toxlsx":
40
+ """Create an Excel sheet showing the mapping result."""
41
+ app = capycli.mapping.mapping_to_xlsx.MappingToExcelXlsx()
42
+ app.run(args)
43
+ return
44
+
45
+ print_red("Unknown sub-command: " + subcommand)
46
+ sys.exit(ResultCode.RESULT_COMMAND_ERROR)
@@ -0,0 +1,182 @@
1
+ # -------------------------------------------------------------------------------
2
+ # Copyright (c) 2019-23 Siemens
3
+ # All Rights Reserved.
4
+ # Author: thomas.graf@siemens.com
5
+ #
6
+ # SPDX-License-Identifier: MIT
7
+ # -------------------------------------------------------------------------------
8
+
9
+ import os
10
+ import sys
11
+
12
+ import capycli.common.html_support
13
+ import capycli.common.json_support
14
+ import capycli.common.script_base
15
+ from capycli import get_logger
16
+ from capycli.bom.map_bom import MapBom
17
+ from capycli.common.map_result import MapResult
18
+ from capycli.common.print import print_red, print_text
19
+ from capycli.main.result_codes import ResultCode
20
+
21
+ LOG = get_logger(__name__)
22
+
23
+
24
+ class MappingToHtml(capycli.common.script_base.ScriptBase):
25
+ """Create a HTML page showing the mapping result"""
26
+
27
+ RELEASE_URL = os.environ.get("SW360ServerUrl", "") + "/group/guest/components/-/component/release/detailRelease/"
28
+
29
+ def mapping_result_to_html(self, details, outputfile):
30
+ """Create a HTML page showing the mapping overview"""
31
+ myhtml = capycli.common.html_support.HtmlSupport()
32
+ lineend = myhtml.get_lineend()
33
+
34
+ with open(outputfile, "w") as htmlfile:
35
+ myhtml.write_start(htmlfile)
36
+ style = myhtml.create_style()
37
+ myhtml.write_header(htmlfile, "Mapping Result Details", style)
38
+ myhtml.start_body(htmlfile)
39
+ myhtml.write_title_heading(htmlfile, "Mapping Result Details")
40
+
41
+ htmlfile.write("<table>" + lineend)
42
+ htmlfile.write(
43
+ "<tr><th>BOM Component</th><th>Mapping Result</th><th>Matching Component</th></tr>"
44
+ + lineend
45
+ )
46
+
47
+ full_match = True
48
+ for mapresult in details:
49
+ versiontext = mapresult["BomItem"]["Name"]
50
+ if "Version" in mapresult["BomItem"]:
51
+ versiontext = versiontext + ", " + mapresult["BomItem"]["Version"]
52
+
53
+ color = "black"
54
+ if (mapresult["Result"] == MapResult.INVALID) or (
55
+ mapresult["Result"] == MapResult.NO_MATCH
56
+ ):
57
+ color = "red"
58
+ full_match = False
59
+ else:
60
+ if MapBom.is_good_match(mapresult["Result"]):
61
+ color = "blue"
62
+ else:
63
+ color = "orange"
64
+ full_match = False
65
+
66
+ htmlfile.write("<tr>" + lineend)
67
+
68
+ htmlfile.write("<td>")
69
+ htmlfile.write('<span style="color:' + color + ';">')
70
+ htmlfile.write(versiontext)
71
+ htmlfile.write("</span>")
72
+ htmlfile.write("</td>" + lineend)
73
+
74
+ htmlfile.write("<td>")
75
+ htmlfile.write('<span style="color:' + color + ';">')
76
+ htmlfile.write(
77
+ MapResult.map_code_to_string(mapresult["Result"])
78
+ + " ("
79
+ + str(mapresult["Result"])
80
+ + ")"
81
+ )
82
+ htmlfile.write("</span>")
83
+ htmlfile.write("</td>" + lineend)
84
+
85
+ htmlfile.write("<td>")
86
+ htmlfile.write('<span style="color:' + color + ';">')
87
+ if (mapresult["Result"] == MapResult.INVALID) or (
88
+ mapresult["Result"] == MapResult.NO_MATCH
89
+ ):
90
+ htmlfile.write("(none)")
91
+ else:
92
+ for matchitem in mapresult["Matches"]:
93
+ htmlfile.write(matchitem["Name"] + ", " + matchitem["Version"])
94
+ htmlfile.write("<br/>")
95
+
96
+ if "Sw360Id" in matchitem:
97
+ id = matchitem["Sw360Id"]
98
+ else:
99
+ id = matchitem["Id"]
100
+
101
+ # htmlfile.write("Sw360Id = " + id)
102
+ htmlfile.write(
103
+ '<a href="'
104
+ + self.RELEASE_URL
105
+ + id
106
+ + '" target="_blank">'
107
+ + id
108
+ + "</a>"
109
+ )
110
+ htmlfile.write("<br/>")
111
+ mid = ""
112
+ if "RepositoryType" in matchitem:
113
+ mid = matchitem["RepositoryType"]
114
+ if "RepositoryId" in matchitem:
115
+ mid = mid + " = " + matchitem["RepositoryId"]
116
+
117
+ if mid:
118
+ htmlfile.write(mid)
119
+ htmlfile.write("<br/>")
120
+
121
+ htmlfile.write("<br/>")
122
+
123
+ htmlfile.write("</span>")
124
+ htmlfile.write("</td>" + lineend)
125
+
126
+ htmlfile.write("</tr>" + lineend)
127
+
128
+ htmlfile.write("</table>" + lineend)
129
+
130
+ htmlfile.write("<p>")
131
+ htmlfile.write("Overall Result: <span")
132
+ if full_match:
133
+ htmlfile.write(' style="color:blue;">COMPLETE')
134
+ else:
135
+ htmlfile.write(' style="color:red;">INCOMPLETE')
136
+ htmlfile.write("</span></p>" + lineend)
137
+
138
+ myhtml.end_body_and_finish(htmlfile)
139
+
140
+ def run(self, args):
141
+ """Main method()"""
142
+ if args.debug:
143
+ global LOG
144
+ LOG = capycli.get_logger(__name__)
145
+
146
+ print_text(
147
+ "\n" + capycli.APP_NAME + ", " + capycli.get_app_version() +
148
+ " - Create a HTML page showing the mapping result\n")
149
+
150
+ if args.help:
151
+ print("usage: CaPyCli mapping tohtml -i <mapping_result.json> -o <mapping_result.html>")
152
+ print("")
153
+ print("optional arguments:")
154
+ print("-h, --help show this help message and exit")
155
+ print("-i INPUTFILE, input mapping result JSON file to read from")
156
+ print("-o OUTPUTFILE, output HTML file to write to")
157
+ print("")
158
+ return
159
+
160
+ if not args.inputfile:
161
+ print_red("No input file specified!")
162
+ sys.exit(ResultCode.RESULT_COMMAND_ERROR)
163
+
164
+ if not os.path.isfile(args.inputfile):
165
+ print_red("Input file not found!")
166
+ sys.exit(ResultCode.RESULT_FILE_NOT_FOUND)
167
+
168
+ if not args.outputfile:
169
+ print_red("No output file specified!")
170
+ sys.exit(ResultCode.RESULT_COMMAND_ERROR)
171
+
172
+ print_text("Loading mapping result " + args.inputfile)
173
+ try:
174
+ mapping_result = capycli.common.json_support.load_json_file(args.inputfile)
175
+ except Exception as ex:
176
+ print_red("Error reading input file: " + repr(ex))
177
+ sys.exit(ResultCode.RESULT_COMMAND_ERROR)
178
+
179
+ print_text("Creating HTML page " + args.outputfile)
180
+ self.mapping_result_to_html(mapping_result, args.outputfile)
181
+
182
+ print()