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.
- License.md +27 -0
- capycli/__init__.py +214 -0
- capycli/__main__.py +13 -0
- capycli/bom/__init__.py +10 -0
- capycli/bom/bom_convert.py +163 -0
- capycli/bom/check_bom.py +187 -0
- capycli/bom/check_bom_item_status.py +197 -0
- capycli/bom/check_granularity.py +244 -0
- capycli/bom/create_components.py +644 -0
- capycli/bom/csv.py +69 -0
- capycli/bom/diff_bom.py +279 -0
- capycli/bom/download_sources.py +227 -0
- capycli/bom/filter_bom.py +323 -0
- capycli/bom/findsources.py +278 -0
- capycli/bom/handle_bom.py +134 -0
- capycli/bom/html.py +67 -0
- capycli/bom/legacy.py +312 -0
- capycli/bom/legacy_cx.py +151 -0
- capycli/bom/map_bom.py +1039 -0
- capycli/bom/merge_bom.py +155 -0
- capycli/bom/plaintext.py +69 -0
- capycli/bom/show_bom.py +77 -0
- capycli/common/__init__.py +9 -0
- capycli/common/capycli_bom_support.py +629 -0
- capycli/common/comparable_version.py +161 -0
- capycli/common/component_cache.py +240 -0
- capycli/common/dependencies_base.py +48 -0
- capycli/common/file_support.py +28 -0
- capycli/common/html_support.py +119 -0
- capycli/common/json_support.py +36 -0
- capycli/common/map_result.py +116 -0
- capycli/common/print.py +55 -0
- capycli/common/purl_service.py +169 -0
- capycli/common/purl_store.py +100 -0
- capycli/common/purl_utils.py +85 -0
- capycli/common/script_base.py +165 -0
- capycli/common/script_support.py +78 -0
- capycli/data/__init__.py +9 -0
- capycli/data/granularity_list.csv +1338 -0
- capycli/dependencies/__init__.py +9 -0
- capycli/dependencies/handle_dependencies.py +70 -0
- capycli/dependencies/javascript.py +261 -0
- capycli/dependencies/maven_list.py +333 -0
- capycli/dependencies/maven_pom.py +150 -0
- capycli/dependencies/nuget.py +184 -0
- capycli/dependencies/python.py +345 -0
- capycli/main/__init__.py +9 -0
- capycli/main/application.py +165 -0
- capycli/main/argument_parser.py +101 -0
- capycli/main/cli.py +28 -0
- capycli/main/exceptions.py +14 -0
- capycli/main/options.py +424 -0
- capycli/main/result_codes.py +41 -0
- capycli/mapping/handle_mapping.py +46 -0
- capycli/mapping/mapping_to_html.py +182 -0
- capycli/mapping/mapping_to_xlsx.py +197 -0
- capycli/moverview/handle_moverview.py +46 -0
- capycli/moverview/moverview_to_html.py +122 -0
- capycli/moverview/moverview_to_xlsx.py +170 -0
- capycli/project/__init__.py +9 -0
- capycli/project/check_prerequisites.py +304 -0
- capycli/project/create_bom.py +190 -0
- capycli/project/create_project.py +335 -0
- capycli/project/create_readme.py +546 -0
- capycli/project/find_project.py +128 -0
- capycli/project/get_license_info.py +246 -0
- capycli/project/handle_project.py +118 -0
- capycli/project/show_ecc.py +200 -0
- capycli/project/show_licenses.py +211 -0
- capycli/project/show_project.py +215 -0
- capycli/project/show_vulnerabilities.py +238 -0
- capycli-2.0.0.dev8.dist-info/LICENSES/CC0-1.0.txt +121 -0
- capycli-2.0.0.dev8.dist-info/LICENSES/MIT.txt +27 -0
- capycli-2.0.0.dev8.dist-info/License.md +27 -0
- capycli-2.0.0.dev8.dist-info/METADATA +268 -0
- capycli-2.0.0.dev8.dist-info/RECORD +78 -0
- capycli-2.0.0.dev8.dist-info/WHEEL +4 -0
- capycli-2.0.0.dev8.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,197 @@
|
|
|
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
|
+
from openpyxl import Workbook
|
|
13
|
+
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
|
|
14
|
+
|
|
15
|
+
import capycli.common.html_support
|
|
16
|
+
import capycli.common.json_support
|
|
17
|
+
import capycli.common.script_base
|
|
18
|
+
from capycli import get_logger
|
|
19
|
+
from capycli.bom.map_bom import MapBom
|
|
20
|
+
from capycli.common.map_result import MapResult
|
|
21
|
+
from capycli.common.print import print_red, print_text
|
|
22
|
+
from capycli.main.result_codes import ResultCode
|
|
23
|
+
|
|
24
|
+
LOG = get_logger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MappingToExcelXlsx(capycli.common.script_base.ScriptBase):
|
|
28
|
+
"""Create an Excel sheet showing the mapping result"""
|
|
29
|
+
|
|
30
|
+
def define_styles(self):
|
|
31
|
+
"""Define style for Excel"""
|
|
32
|
+
# fontDefault = Font(
|
|
33
|
+
# name="Calibri", size=11, bold=False, italic=False,vertAlign=None,
|
|
34
|
+
# underline="none", strike=False, color="FF000000")
|
|
35
|
+
# fillDefault = PatternFill(
|
|
36
|
+
# fill_type=None, start_color="FFFFFFFF", end_color="FF000000")
|
|
37
|
+
# borderDefault = Border(
|
|
38
|
+
# left=Side(border_style=None, color="FF000000"),
|
|
39
|
+
# right=Side(border_style=None, color="FF000000"),
|
|
40
|
+
# top=Side(border_style=None, color="FF000000"),
|
|
41
|
+
# bottom=Side(border_style=None, color="FF000000"),
|
|
42
|
+
# diagonal=Side(border_style=None, color="FF000000"),
|
|
43
|
+
# diagonal_direction=0,
|
|
44
|
+
# outline=Side(border_style=None, color="FF000000"),
|
|
45
|
+
# vertical=Side(border_style=None, color="FF000000"),
|
|
46
|
+
# horizontal=Side(border_style=None, color="FF000000"))
|
|
47
|
+
|
|
48
|
+
self.fontBold = Font(name="Calibri", size=11, bold=True)
|
|
49
|
+
self.fontBoldBlue = Font(name="Calibri", size=11, bold=True, color="FF0000FF")
|
|
50
|
+
self.fontBoldOrange = Font(name="Calibri", size=11, bold=True, color="FFFFCC00")
|
|
51
|
+
self.fontBoldRed = Font(name="Calibri", size=11, bold=True, color="FFFF0000")
|
|
52
|
+
self.fontBold16 = Font(name="Calibri", size=16, bold=True)
|
|
53
|
+
|
|
54
|
+
self.fillGray = PatternFill(
|
|
55
|
+
fill_type="solid", start_color="FFC0C0C0", end_color="FFC0C0C0")
|
|
56
|
+
self.border = Border(
|
|
57
|
+
left=Side(border_style="thin", color="FF000000"),
|
|
58
|
+
right=Side(border_style="thin", color="FF000000"),
|
|
59
|
+
top=Side(border_style="thin", color="FF000000"),
|
|
60
|
+
bottom=Side(border_style="thin", color="FF000000"))
|
|
61
|
+
|
|
62
|
+
def mapping_result_to_xlsx(self, details, outputfile):
|
|
63
|
+
"""Create an Excel sheet showing the mapping overview"""
|
|
64
|
+
wb = Workbook()
|
|
65
|
+
ws = wb.active
|
|
66
|
+
self.define_styles()
|
|
67
|
+
|
|
68
|
+
ws["A1"] = "Mapping Result Overview"
|
|
69
|
+
ws["A1"].font = self.fontBold16
|
|
70
|
+
|
|
71
|
+
ws["A3"] = "SBOM Component"
|
|
72
|
+
ws["A3"].fill = self.fillGray
|
|
73
|
+
ws["A3"].border = self.border
|
|
74
|
+
ws["B3"] = "Mapping Result"
|
|
75
|
+
ws["B3"].fill = self.fillGray
|
|
76
|
+
ws["B3"].border = self.border
|
|
77
|
+
ws["C3"] = "Matching Component"
|
|
78
|
+
ws["C3"].fill = self.fillGray
|
|
79
|
+
ws["C3"].border = self.border
|
|
80
|
+
|
|
81
|
+
row = 4
|
|
82
|
+
max_width_component = 0
|
|
83
|
+
max_width_result = 0
|
|
84
|
+
max_width_match = 0
|
|
85
|
+
for mapresult in details:
|
|
86
|
+
versiontext = mapresult["BomItem"]["Name"]
|
|
87
|
+
if "Version" in mapresult["BomItem"]:
|
|
88
|
+
versiontext = versiontext + ", " + mapresult["BomItem"]["Version"]
|
|
89
|
+
|
|
90
|
+
if (mapresult["Result"] == MapResult.INVALID) or \
|
|
91
|
+
(mapresult["Result"] == MapResult.NO_MATCH):
|
|
92
|
+
font = self.fontBoldRed
|
|
93
|
+
else:
|
|
94
|
+
if MapBom.is_good_match(mapresult["Result"]):
|
|
95
|
+
font = self.fontBoldBlue
|
|
96
|
+
else:
|
|
97
|
+
font = self.fontBoldOrange
|
|
98
|
+
|
|
99
|
+
c = ws.cell(row=row, column=1, value=versiontext)
|
|
100
|
+
c.font = font
|
|
101
|
+
c.border = self.border
|
|
102
|
+
c.alignment = Alignment(vertical="top")
|
|
103
|
+
if len(versiontext) > max_width_component:
|
|
104
|
+
max_width_component = len(versiontext)
|
|
105
|
+
|
|
106
|
+
text = MapResult.map_code_to_string(mapresult["Result"]) + \
|
|
107
|
+
" (" + str(mapresult["Result"]) + ")"
|
|
108
|
+
c = ws.cell(row=row, column=2, value=text)
|
|
109
|
+
c.font = font
|
|
110
|
+
c.border = self.border
|
|
111
|
+
c.alignment = Alignment(vertical="top")
|
|
112
|
+
if len(text) > max_width_result:
|
|
113
|
+
max_width_result = len(text)
|
|
114
|
+
|
|
115
|
+
text = ""
|
|
116
|
+
if (mapresult["Result"] == MapResult.INVALID) or \
|
|
117
|
+
(mapresult["Result"] == MapResult.NO_MATCH):
|
|
118
|
+
text = "(none)"
|
|
119
|
+
else:
|
|
120
|
+
for matchitem in mapresult["Matches"]:
|
|
121
|
+
line = matchitem["Name"] + ", " + matchitem["Version"] + "\n"
|
|
122
|
+
if len(line) > max_width_match:
|
|
123
|
+
max_width_match = len(line)
|
|
124
|
+
|
|
125
|
+
text += line
|
|
126
|
+
mid = ""
|
|
127
|
+
if "RepositoryType" in matchitem:
|
|
128
|
+
mid = matchitem["RepositoryType"]
|
|
129
|
+
if "RepositoryId" in matchitem:
|
|
130
|
+
mid = mid + " = " + matchitem["RepositoryId"]
|
|
131
|
+
|
|
132
|
+
if mid:
|
|
133
|
+
text = mid + "\n"
|
|
134
|
+
|
|
135
|
+
if len(line) > max_width_match:
|
|
136
|
+
max_width_match = len(line)
|
|
137
|
+
|
|
138
|
+
c = ws.cell(row=row, column=3, value=text)
|
|
139
|
+
c.alignment = Alignment(wrapText=True)
|
|
140
|
+
c.font = font
|
|
141
|
+
c.border = self.border
|
|
142
|
+
|
|
143
|
+
row += 1
|
|
144
|
+
|
|
145
|
+
ws.column_dimensions["A"].width = max_width_component
|
|
146
|
+
ws.column_dimensions["B"].width = max_width_result
|
|
147
|
+
ws.column_dimensions["C"].width = max_width_match
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
wb.save(outputfile)
|
|
151
|
+
except Exception as ex:
|
|
152
|
+
print_red("Error wirting Excel sheet: " + repr(ex))
|
|
153
|
+
sys.exit(ResultCode.RESULT_ERROR_WRITING_FILE)
|
|
154
|
+
|
|
155
|
+
def run(self, args):
|
|
156
|
+
"""Main method()"""
|
|
157
|
+
if args.debug:
|
|
158
|
+
global LOG
|
|
159
|
+
LOG = capycli.get_logger(__name__)
|
|
160
|
+
|
|
161
|
+
print_text(
|
|
162
|
+
"\n" + capycli.APP_NAME + ", " + capycli.get_app_version() +
|
|
163
|
+
" - Create an Excel sheet showing the mapping result\n")
|
|
164
|
+
|
|
165
|
+
if args.help:
|
|
166
|
+
print("usage: CaPyCli mapping toxlsx -i <mapping_result.json> -o <mapping_result.xlsx>")
|
|
167
|
+
print("")
|
|
168
|
+
print("optional arguments:")
|
|
169
|
+
print("-h, --help show this help message and exit")
|
|
170
|
+
print("-i INPUTFILE, input mapping result JSON file to read from")
|
|
171
|
+
print("-o OUTPUTFILE, output XLSX file to write to")
|
|
172
|
+
print("")
|
|
173
|
+
return
|
|
174
|
+
|
|
175
|
+
if not args.inputfile:
|
|
176
|
+
print_red("No input file specified!")
|
|
177
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
178
|
+
|
|
179
|
+
if not os.path.isfile(args.inputfile):
|
|
180
|
+
print_red("Input file not found!")
|
|
181
|
+
sys.exit(ResultCode.RESULT_FILE_NOT_FOUND)
|
|
182
|
+
|
|
183
|
+
if not args.outputfile:
|
|
184
|
+
print_red("No output file specified!")
|
|
185
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
186
|
+
|
|
187
|
+
print_text("Loading mapping result " + args.inputfile)
|
|
188
|
+
try:
|
|
189
|
+
mapping_result = capycli.common.json_support.load_json_file(args.inputfile)
|
|
190
|
+
except Exception as ex:
|
|
191
|
+
print_red("Error reading input file: " + repr(ex))
|
|
192
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
193
|
+
|
|
194
|
+
print_text("Creating Excel sheet " + args.outputfile)
|
|
195
|
+
self.mapping_result_to_xlsx(mapping_result, args.outputfile)
|
|
196
|
+
|
|
197
|
+
print()
|
|
@@ -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.moverview.moverview_to_html
|
|
12
|
+
import capycli.moverview.moverview_to_xlsx
|
|
13
|
+
from capycli.common.print import print_red
|
|
14
|
+
from capycli.main.result_codes import ResultCode
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def run_moverview_command(args):
|
|
18
|
+
command = args.command[0].lower()
|
|
19
|
+
if command != "moverview":
|
|
20
|
+
return
|
|
21
|
+
|
|
22
|
+
if len(args.command) < 2:
|
|
23
|
+
print_red("No subcommand specified!")
|
|
24
|
+
print()
|
|
25
|
+
|
|
26
|
+
# display `moverview` related help
|
|
27
|
+
print("moverview - mapping overview sub-commands")
|
|
28
|
+
print(" ToHtml create a HTML page showing the mapping result overview")
|
|
29
|
+
print(" ToXlsx create an Excel sheet showing the mapping result overview")
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
subcommand = args.command[1].lower()
|
|
33
|
+
if subcommand == "tohtml":
|
|
34
|
+
"""Create a HTML page showing the mapping overview."""
|
|
35
|
+
app = capycli.moverview.moverview_to_html.MappingOverviewToHtml()
|
|
36
|
+
app.run(args)
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
if subcommand == "toxlsx":
|
|
40
|
+
"""Create an Excel sheet showing the mapping overview."""
|
|
41
|
+
app = capycli.moverview.moverview_to_xlsx.MappingOverviewToExcelXlsx()
|
|
42
|
+
app.run(args)
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
print_red("Unknown sub-command: " + subcommand)
|
|
46
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
@@ -0,0 +1,122 @@
|
|
|
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 MappingOverviewToHtml(capycli.common.script_base.ScriptBase):
|
|
25
|
+
"""Create a HTML page showing the mapping overview."""
|
|
26
|
+
|
|
27
|
+
def mapping_overview_to_html(self, overview, outputfile):
|
|
28
|
+
"""Create a HTML page showing the mapping overview"""
|
|
29
|
+
myhtml = capycli.common.html_support.HtmlSupport()
|
|
30
|
+
lineend = myhtml.get_lineend()
|
|
31
|
+
|
|
32
|
+
with open(outputfile, "w") as htmlfile:
|
|
33
|
+
myhtml.write_start(htmlfile)
|
|
34
|
+
style = myhtml.create_style()
|
|
35
|
+
myhtml.write_header(htmlfile, "Mapping Result Overview", style)
|
|
36
|
+
myhtml.start_body(htmlfile)
|
|
37
|
+
myhtml.write_title_heading(htmlfile, "Mapping Result Overview")
|
|
38
|
+
|
|
39
|
+
htmlfile.write("<p>")
|
|
40
|
+
htmlfile.write("Overall Result: <span")
|
|
41
|
+
if overview["OverallResult"] == "COMPLETE":
|
|
42
|
+
htmlfile.write(' style="color:blue;">')
|
|
43
|
+
else:
|
|
44
|
+
htmlfile.write(' style="color:red;">')
|
|
45
|
+
|
|
46
|
+
htmlfile.write(overview["OverallResult"])
|
|
47
|
+
htmlfile.write("</span></p>" + lineend)
|
|
48
|
+
|
|
49
|
+
htmlfile.write("<table>" + lineend)
|
|
50
|
+
|
|
51
|
+
htmlfile.write("<tr><th>Component</th><th>Mapping Result</th></tr>" + lineend)
|
|
52
|
+
|
|
53
|
+
for item in overview["Details"]:
|
|
54
|
+
htmlfile.write("<tr>" + lineend)
|
|
55
|
+
htmlfile.write("<td>" + item["BomItem"] + "</td><td>")
|
|
56
|
+
|
|
57
|
+
if (item["ResultCode"] == MapResult.INVALID) or (
|
|
58
|
+
item["ResultCode"] == MapResult.NO_MATCH
|
|
59
|
+
):
|
|
60
|
+
htmlfile.write('<span style="color:red;">')
|
|
61
|
+
else:
|
|
62
|
+
if MapBom.is_good_match(item["ResultCode"]):
|
|
63
|
+
htmlfile.write('<span style="color:blue;">')
|
|
64
|
+
else:
|
|
65
|
+
htmlfile.write('<span style="color:orange;">')
|
|
66
|
+
|
|
67
|
+
htmlfile.write(item["ResultText"] + " (" + str(item["ResultCode"]) + ")")
|
|
68
|
+
htmlfile.write("</span>")
|
|
69
|
+
htmlfile.write("</td>" + lineend)
|
|
70
|
+
htmlfile.write("</tr>" + lineend)
|
|
71
|
+
|
|
72
|
+
htmlfile.write("</table>" + lineend)
|
|
73
|
+
|
|
74
|
+
myhtml.end_body_and_finish(htmlfile)
|
|
75
|
+
|
|
76
|
+
def run(self, args):
|
|
77
|
+
"""Main method()"""
|
|
78
|
+
if args.debug:
|
|
79
|
+
global LOG
|
|
80
|
+
LOG = capycli.get_logger(__name__)
|
|
81
|
+
|
|
82
|
+
print_text(
|
|
83
|
+
"\n" + capycli.APP_NAME + ", " + capycli.get_app_version() +
|
|
84
|
+
" - Create a HTML page showing the mapping overview\n")
|
|
85
|
+
|
|
86
|
+
if args.help:
|
|
87
|
+
print("usage: CaPyCli moverview tohtml -i <mapping_overview.json> -o <mapping_overview.html>")
|
|
88
|
+
print("")
|
|
89
|
+
print("optional arguments:")
|
|
90
|
+
print("-h, --help show this help message and exit")
|
|
91
|
+
print("-i INPUTFILE, input mapping result JSON file to read from")
|
|
92
|
+
print("-o OUTPUTFILE, output HTML file to write to")
|
|
93
|
+
print("")
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
if not args.inputfile:
|
|
97
|
+
print_red("No input file specified!")
|
|
98
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
99
|
+
|
|
100
|
+
if not os.path.isfile(args.inputfile):
|
|
101
|
+
print_red("Input file not found!")
|
|
102
|
+
sys.exit(ResultCode.RESULT_FILE_NOT_FOUND)
|
|
103
|
+
|
|
104
|
+
if not args.outputfile:
|
|
105
|
+
print_red("No output file specified!")
|
|
106
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
107
|
+
|
|
108
|
+
print_text("Loading mapping overview " + args.inputfile)
|
|
109
|
+
try:
|
|
110
|
+
overview = capycli.common.json_support.load_json_file(args.inputfile)
|
|
111
|
+
except Exception as ex:
|
|
112
|
+
print_red("Error reading input file: " + repr(ex))
|
|
113
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
114
|
+
|
|
115
|
+
print_text("Creating HTML page " + args.outputfile)
|
|
116
|
+
try:
|
|
117
|
+
self.mapping_overview_to_html(overview, args.outputfile)
|
|
118
|
+
except Exception as ex:
|
|
119
|
+
print_red("Error creating overview file: " + repr(ex))
|
|
120
|
+
sys.exit(ResultCode.RESULT_GENERAL_ERROR)
|
|
121
|
+
|
|
122
|
+
print()
|
|
@@ -0,0 +1,170 @@
|
|
|
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
|
+
from openpyxl import Workbook
|
|
13
|
+
from openpyxl.styles import Border, Font, PatternFill, Side
|
|
14
|
+
|
|
15
|
+
import capycli.common.html_support
|
|
16
|
+
import capycli.common.json_support
|
|
17
|
+
import capycli.common.script_base
|
|
18
|
+
from capycli import get_logger
|
|
19
|
+
from capycli.bom.map_bom import MapBom
|
|
20
|
+
from capycli.common.map_result import MapResult
|
|
21
|
+
from capycli.common.print import print_red, print_text
|
|
22
|
+
from capycli.main.result_codes import ResultCode
|
|
23
|
+
|
|
24
|
+
LOG = get_logger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MappingOverviewToExcelXlsx(capycli.common.script_base.ScriptBase):
|
|
28
|
+
"""Create an Excel sheet showing the mapping overview."""
|
|
29
|
+
|
|
30
|
+
def define_styles(self):
|
|
31
|
+
"""Define style for Excel"""
|
|
32
|
+
# fontDefault = Font(
|
|
33
|
+
# name="Calibri", size=11, bold=False, italic=False,vertAlign=None,
|
|
34
|
+
# underline="none", strike=False, color="FF000000")
|
|
35
|
+
# fillDefault = PatternFill(
|
|
36
|
+
# fill_type=None, start_color="FFFFFFFF", end_color="FF000000")
|
|
37
|
+
# borderDefault = Border(
|
|
38
|
+
# left=Side(border_style=None, color="FF000000"),
|
|
39
|
+
# right=Side(border_style=None, color="FF000000"),
|
|
40
|
+
# top=Side(border_style=None, color="FF000000"),
|
|
41
|
+
# bottom=Side(border_style=None, color="FF000000"),
|
|
42
|
+
# diagonal=Side(border_style=None, color="FF000000"),
|
|
43
|
+
# diagonal_direction=0,
|
|
44
|
+
# outline=Side(border_style=None, color="FF000000"),
|
|
45
|
+
# vertical=Side(border_style=None, color="FF000000"),
|
|
46
|
+
# horizontal=Side(border_style=None, color="FF000000"))
|
|
47
|
+
|
|
48
|
+
self.fontBold = Font(name="Calibri", size=11, bold=True)
|
|
49
|
+
self.fontBoldBlue = Font(name="Calibri", size=11, bold=True, color="FF0000FF")
|
|
50
|
+
self.fontBoldOrange = Font(name="Calibri", size=11, bold=True, color="FFFFCC00")
|
|
51
|
+
self.fontBoldRed = Font(name="Calibri", size=11, bold=True, color="FFFF0000")
|
|
52
|
+
self.fontBold16 = Font(name="Calibri", size=16, bold=True)
|
|
53
|
+
|
|
54
|
+
self.fillGray = PatternFill(
|
|
55
|
+
fill_type="solid", start_color="FFC0C0C0", end_color="FFC0C0C0")
|
|
56
|
+
self.border = Border(
|
|
57
|
+
left=Side(border_style="thin", color="FF000000"),
|
|
58
|
+
right=Side(border_style="thin", color="FF000000"),
|
|
59
|
+
top=Side(border_style="thin", color="FF000000"),
|
|
60
|
+
bottom=Side(border_style="thin", color="FF000000"))
|
|
61
|
+
|
|
62
|
+
def mapping_overview_to_xlsx(self, overview, outputfile):
|
|
63
|
+
"""Create an Excel sheet showing the mapping overview"""
|
|
64
|
+
wb = Workbook()
|
|
65
|
+
ws = wb.active
|
|
66
|
+
self.define_styles()
|
|
67
|
+
|
|
68
|
+
ws["A1"] = "Mapping Result Overview"
|
|
69
|
+
ws["A1"].font = self.fontBold16
|
|
70
|
+
|
|
71
|
+
ws["A3"] = "Overall Result: " + overview["OverallResult"]
|
|
72
|
+
if overview["OverallResult"] == "COMPLETE":
|
|
73
|
+
ws["A3"].font = self.fontBoldBlue
|
|
74
|
+
else:
|
|
75
|
+
ws["A3"].font = self.fontBoldRed
|
|
76
|
+
|
|
77
|
+
ws["A5"] = "Component"
|
|
78
|
+
ws["A5"].fill = self.fillGray
|
|
79
|
+
ws["A5"].border = self.border
|
|
80
|
+
ws["B5"] = "Mapping Result"
|
|
81
|
+
ws["B5"].fill = self.fillGray
|
|
82
|
+
ws["B5"].border = self.border
|
|
83
|
+
ws["C5"] = "Mapping Code"
|
|
84
|
+
ws["C5"].fill = self.fillGray
|
|
85
|
+
ws["C5"].border = self.border
|
|
86
|
+
|
|
87
|
+
row = 6
|
|
88
|
+
max_width_component = 0
|
|
89
|
+
max_width_text = 0
|
|
90
|
+
for item in overview["Details"]:
|
|
91
|
+
if (item["ResultCode"] == MapResult.INVALID) or \
|
|
92
|
+
(item["ResultCode"] == MapResult.NO_MATCH):
|
|
93
|
+
font = self.fontBoldRed
|
|
94
|
+
else:
|
|
95
|
+
if MapBom.is_good_match(item["ResultCode"]):
|
|
96
|
+
font = self.fontBoldBlue
|
|
97
|
+
else:
|
|
98
|
+
font = self.fontBoldOrange
|
|
99
|
+
|
|
100
|
+
c = ws.cell(row=row, column=1, value=item["BomItem"])
|
|
101
|
+
c.font = font
|
|
102
|
+
c.border = self.border
|
|
103
|
+
if len(item["BomItem"]) > max_width_component:
|
|
104
|
+
max_width_component = len(item["BomItem"])
|
|
105
|
+
|
|
106
|
+
c = ws.cell(row=row, column=2, value=item["ResultText"])
|
|
107
|
+
c.font = font
|
|
108
|
+
c.border = self.border
|
|
109
|
+
if len(item["ResultText"]) > max_width_text:
|
|
110
|
+
max_width_text = len(item["ResultText"])
|
|
111
|
+
|
|
112
|
+
c = ws.cell(row=row, column=3, value=item["ResultCode"])
|
|
113
|
+
c.font = font
|
|
114
|
+
c.border = self.border
|
|
115
|
+
|
|
116
|
+
row += 1
|
|
117
|
+
|
|
118
|
+
ws.column_dimensions["A"].width = max_width_component
|
|
119
|
+
ws.column_dimensions["B"].width = max_width_text
|
|
120
|
+
ws.column_dimensions["C"].width = len("Mapping Code")
|
|
121
|
+
|
|
122
|
+
wb.save(outputfile)
|
|
123
|
+
|
|
124
|
+
def run(self, args):
|
|
125
|
+
"""Main method()"""
|
|
126
|
+
if args.debug:
|
|
127
|
+
global LOG
|
|
128
|
+
LOG = capycli.get_logger(__name__)
|
|
129
|
+
|
|
130
|
+
print_text(
|
|
131
|
+
"\n" + capycli.APP_NAME + ", " + capycli.get_app_version() +
|
|
132
|
+
" - Create an Excel sheet showing the mapping overview\n")
|
|
133
|
+
|
|
134
|
+
if args.help:
|
|
135
|
+
print("usage: CaPyCli moverview toxlsx -i <mapping_overview.json> -o <mapping_overview.xlsx>")
|
|
136
|
+
print("")
|
|
137
|
+
print("optional arguments:")
|
|
138
|
+
print("-h, --help show this help message and exit")
|
|
139
|
+
print("-i INPUTFILE, input mapping result JSON file to read from")
|
|
140
|
+
print("-o OUTPUTFILE, output XLSX file to write to")
|
|
141
|
+
print("")
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
if not args.inputfile:
|
|
145
|
+
print_red("No input file specified!")
|
|
146
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
147
|
+
|
|
148
|
+
if not os.path.isfile(args.inputfile):
|
|
149
|
+
print_red("Input file not found!")
|
|
150
|
+
sys.exit(ResultCode.RESULT_FILE_NOT_FOUND)
|
|
151
|
+
|
|
152
|
+
if not args.outputfile:
|
|
153
|
+
print_red("No output file specified!")
|
|
154
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
155
|
+
|
|
156
|
+
print_text("Loading mapping overview " + args.inputfile)
|
|
157
|
+
try:
|
|
158
|
+
overview = capycli.common.json_support.load_json_file(args.inputfile)
|
|
159
|
+
except Exception as ex:
|
|
160
|
+
print_red("Error reading input file: " + repr(ex))
|
|
161
|
+
sys.exit(ResultCode.RESULT_COMMAND_ERROR)
|
|
162
|
+
|
|
163
|
+
print_text("Creating Excel sheet " + args.outputfile)
|
|
164
|
+
try:
|
|
165
|
+
self.mapping_overview_to_xlsx(overview, args.outputfile)
|
|
166
|
+
except Exception as ex:
|
|
167
|
+
print_red("Error creating overview file: " + repr(ex))
|
|
168
|
+
sys.exit(ResultCode.RESULT_GENERAL_ERROR)
|
|
169
|
+
|
|
170
|
+
print()
|
|
@@ -0,0 +1,9 @@
|
|
|
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
|
+
"""Project specific methods"""
|