88#
99
1010import xmltodict
11+ from packageurl import PackageURL
1112
1213from packagedcode import models
1314from packagedcode .utils import build_description
1415
15-
1616"""
1717Handle NuGet packages and their manifests.
1818"""
1919
20- # TODO: Add section to handle dependencies of dependencies
21-
2220
2321def get_dependencies (nuspec ):
2422 """
25- Return a list of Dependent package objects found in a NuGet `nuspec` object.
23+ Yield DependentPackage found in a NuGet ``nuspec`` object.
24+ """
25+ # This is either a list of dependency or a list of group/dependency
26+ # or a single dep or a single group mapping
27+
28+ dependencies = nuspec .get ('dependencies' ) or []
29+ if isinstance (dependencies , dict ):
30+ # wrap the mapping in a list if we have more than one dependencies
31+ dependencies = [dependencies ]
32+
33+ for depends in dependencies :
34+ groups = depends .get ('group' ) or []
35+ if groups :
36+ if isinstance (groups , dict ):
37+ # wrap the mapping in a list
38+ groups = [groups ]
39+
40+ for group in groups :
41+ extra_data = dict (framework = group ['@targetFramework' ])
42+ deps = group .get ('dependency' ) or []
43+ yield from _get_dep_packs (deps , extra_data )
44+ else :
45+ # {'dependency': {'@id': 'jQuery', '@version': '1.9.1'}}
46+ deps = depends .get ('dependency' ) or []
47+ yield from _get_dep_packs (deps , extra_data = {})
48+
49+
50+ def _get_dep_packs (deps , extra_data ):
2651 """
27- dependencies = []
28- try :
29- if "dependencies" in nuspec :
30- if "group" in nuspec ["dependencies" ]:
31- for group in nuspec ["dependencies" ]["group" ]:
32- if "dependency" in group :
33- for dependency in group ["dependency" ]:
34- #dependencies.append(dependency)
35- dpurl = models .PackageURL (
36- type = 'nuget' ,
37- namespace = None ,
38- name = dependency .get ("@id" ),
39- version = dependency .get ("@version" ),
40- qualifiers = None
41- )
42- dep_pack = models .DependentPackage (
43- purl = str (dpurl ),
44- extracted_requirement = dependency .get ("@version" ),
45- scope = "dependency" ,
46- is_runtime = False ,
47- is_optional = False ,
48- is_resolved = True ,
49- )
50-
51- dependencies .append (dep_pack )
52-
53- if "dependency" in nuspec .get ("dependencies" ):
54- if "@id" and "@version" in nuspec .get ("dependencies" ).get ("dependency" ):
55- dpurl = models .PackageURL (
56- type = 'nuget' ,
57- namespace = None ,
58- name = nuspec .get ("dependencies" ).get (
59- "dependency" ).get ("@id" ),
60- version = nuspec .get ("dependencies" ).get (
61- "dependency" ).get ("@version" ),
62- qualifiers = None
63- )
64- dep_pack = models .DependentPackage (
65- purl = str (dpurl ),
66- extracted_requirement = nuspec .get ("dependencies" ).get (
67- "dependency" ).get ("@version" ),
68- scope = "dependency" ,
69- is_runtime = False ,
70- is_optional = False ,
71- is_resolved = True ,
72- )
73-
74- dependencies .append (dep_pack )
75-
76- else :
77- for dependency in nuspec .get ("dependencies" ).get ("dependency" ):
78- dpurl = models .PackageURL (
79- type = 'nuget' ,
80- namespace = None ,
81- name = dependency .get ("@id" ),
82- version = dependency .get ("@version" ),
83- qualifiers = None
84- )
85- dep_pack = models .DependentPackage (
86- purl = str (dpurl ),
87- extracted_requirement = dependency .get (
88- "@version" ),
89- scope = "dependency" ,
90- is_runtime = False ,
91- is_optional = False ,
92- is_resolved = True ,
93- )
94- dependencies .append (dep_pack )
95-
96- return dependencies
97-
98- except Exception as e :
99- print (e )
100- return dependencies
52+ Yield DependentPackage found in a NuGet ``deps`` mapping or list of mappings.
53+ """
54+ if not deps :
55+ return
56+
57+ if isinstance (deps , dict ):
58+ # wrap the mapping in a list
59+ deps = [deps ]
60+
61+ for dep in deps :
62+ extra = dict (extra_data ) or {}
63+ include = dep .get ('@include' )
64+ if include :
65+ extra ['include' ] = include
66+ exclude = dep .get ('@exclude' )
67+ if exclude :
68+ extra ['exclude' ] = exclude
69+
70+ yield models .DependentPackage (
71+ purl = str (PackageURL (type = 'nuget' , name = dep .get ('@id' ))),
72+ # this is a range, not a version
73+ extracted_requirement = dep .get ('@version' ),
74+ scope = 'dependency' ,
75+ is_runtime = True ,
76+ is_optional = False ,
77+ is_resolved = False ,
78+ extra_data = extra ,
79+ )
10180
10281
10382def get_urls (name , version , ** kwargs ):
@@ -144,15 +123,14 @@ def parse(cls, location):
144123
145124 # Summary: A short description of the package for UI display. If omitted, a
146125 # truncated version of description is used.
147- description = build_description (
148- nuspec .get ('summary' ), nuspec .get ('description' ))
126+ description = build_description (nuspec .get ('summary' ), nuspec .get ('description' ))
149127
150128 # title: A human-friendly title of the package, typically used in UI
151129 # displays as on nuget.org and the Package Manager in Visual Studio. If not
152130 # specified, the package ID is used.
153131 title = nuspec .get ('title' )
154132 if title and title != name :
155- description = build_description (nuspec . get ( ' title' ) , description )
133+ description = build_description (title , description )
156134
157135 parties = []
158136 authors = nuspec .get ('authors' )
@@ -181,11 +159,10 @@ def parse(cls, location):
181159 # This is a SPDX license expression
182160 if 'license' in nuspec :
183161 extracted_license_statement = nuspec .get ('license' )
184- # TODO: try to convert to normal license expression
185162 # Deprecated and not a license expression, just a URL
186163 elif 'licenseUrl' in nuspec :
187164 extracted_license_statement = nuspec .get ('licenseUrl' )
188-
165+
189166 yield models .PackageData (
190167 datasource_id = cls .datasource_id ,
191168 type = cls .default_package_type ,
@@ -194,7 +171,7 @@ def parse(cls, location):
194171 description = description or None ,
195172 homepage_url = nuspec .get ('projectUrl' ) or None ,
196173 parties = parties ,
197- dependencies = get_dependencies (nuspec ),
174+ dependencies = list ( get_dependencies (nuspec ) ),
198175 extracted_license_statement = extracted_license_statement ,
199176 copyright = nuspec .get ('copyright' ) or None ,
200177 vcs_url = vcs_url ,
0 commit comments