22
33import subprocess
44import tempfile
5+ from dataclasses import dataclass
56from inspect import cleandoc
67from json import loads
78from typing import Optional
89
910from pydantic import field_validator
1011
11- from exasol .toolbox .util .dependencies .shared_models import Package
12+ from exasol .toolbox .util .dependencies .shared_models import (
13+ NormalizedPackageStr ,
14+ Package ,
15+ normalize_package_name ,
16+ )
1217
1318LICENSE_MAPPING_TO_ABBREVIATION = {
1419 "BSD License" : "BSD" ,
@@ -88,20 +93,20 @@ def select_most_restrictive(licenses: list[str]) -> str:
8893 return LICENSE_MAPPING_TO_ABBREVIATION .get (_license , _license )
8994
9095
91- def _packages_from_json (json : str ) -> list [ PackageLicense ]:
96+ def _packages_from_json (json : str ) -> dict [ NormalizedPackageStr , PackageLicense ]:
9297 packages = loads (json )
93- return [
94- PackageLicense (
98+ return {
99+ normalize_package_name ( package [ "Name" ]): PackageLicense (
95100 name = package ["Name" ],
96101 package_link = package ["URL" ],
97102 version = package ["Version" ],
98103 license = package ["License" ],
99104 )
100105 for package in packages
101- ]
106+ }
102107
103108
104- def licenses () -> list [ PackageLicense ]:
109+ def get_licenses () -> dict [ NormalizedPackageStr , PackageLicense ]:
105110 with tempfile .NamedTemporaryFile () as file :
106111 subprocess .run (
107112 [
@@ -117,62 +122,56 @@ def licenses() -> list[PackageLicense]:
117122 return _packages_from_json (file .read ().decode ())
118123
119124
120- def packages_to_markdown (
121- dependencies : dict [str , list ], packages : list [PackageLicense ]
122- ) -> str :
123- def heading ():
124- return "# Dependencies\n "
125-
126- def dependency (
127- group : str ,
128- group_packages : list [Package ],
129- packages : list [PackageLicense ],
130- ) -> str :
131- def _header (_group : str ):
132- _group = "" .join ([word .capitalize () for word in _group .strip ().split ()])
133- text = f"## { _group } Dependencies\n "
134- text += "|Package|Version|License|\n "
135- text += "|---|---|---|\n "
136- return text
137-
138- def _rows (
139- _group_packages : list [Package ], _packages : list [PackageLicense ]
140- ) -> str :
141- text = ""
142- for package in _group_packages :
143- consistent = filter (
144- lambda elem : elem .normalized_name == package .normalized_name ,
145- _packages ,
146- )
147- for content in consistent :
148- if content .package_link :
149- text += f"|[{ content .name } ]({ content .package_link } )"
150- else :
151- text += f"|{ content .name } "
152- text += f"|{ content .version } "
153- if content .license_link :
154- text += f"|[{ content .license } ]({ content .license_link } )|\n "
155- else :
156- text += f"|{ content .license } |\n "
157- text += "\n "
158- return text
159-
160- _template = cleandoc (
161- """
162- {header}{rows}
163- """
164- )
165- return _template .format (
166- header = _header (group ), rows = _rows (group_packages , packages )
167- )
168-
169- template = cleandoc (
170- """
171- {heading}{rows}
172- """
173- )
174-
175- rows = ""
176- for group in dependencies :
177- rows += dependency (group , dependencies [group ], packages )
178- return template .format (heading = heading (), rows = rows )
125+ @dataclass (frozen = True )
126+ class PackageLicenseReport :
127+ dependencies : dict [str , dict [NormalizedPackageStr , Package ]]
128+ licenses : dict [NormalizedPackageStr , PackageLicense ]
129+
130+ @staticmethod
131+ def _format_group_table_header (group : str ):
132+ _group = "" .join ([word .capitalize () for word in group .strip ().split ()])
133+ text = f"## `{ group } ` Dependencies\n "
134+ text += "|Package|Version|License|\n "
135+ text += "|---|---|---|\n "
136+ return text
137+
138+ def _format_group_table (
139+ self , group : str , group_package_names : set [NormalizedPackageStr ]
140+ ):
141+ group_header = self ._format_group_table_header (group = group )
142+
143+ rows_text = ""
144+ for package_name in group_package_names :
145+ if license_info := self .licenses .get (package_name ):
146+ rows_text += self ._format_table_row (license_info = license_info )
147+
148+ return f"""{ group_header } { rows_text } \n """
149+
150+ @staticmethod
151+ def _format_table_row (license_info : PackageLicense ) -> str :
152+ text = ""
153+ # column: package
154+ if license_info .package_link :
155+ text += f"|[{ license_info .name } ]({ license_info .package_link } )"
156+ else :
157+ text += f"|{ license_info .name } "
158+
159+ # column: version
160+ text += f"|{ license_info .version } "
161+
162+ # column: license
163+ if license_info .license_link :
164+ text += f"|[{ license_info .license } ]({ license_info .license_link } )|"
165+ else :
166+ text += f"|{ license_info .license } |"
167+
168+ return text + "\n "
169+
170+ def to_markdown (self ) -> str :
171+ rows = ""
172+ for group in self .dependencies :
173+ group_package_names = set (self .dependencies [group ].keys ())
174+ rows += self ._format_group_table (
175+ group = group , group_package_names = group_package_names
176+ )
177+ return cleandoc (f"""# Dependencies\n \n { rows } """ )
0 commit comments