Skip to content

Commit d19003b

Browse files
authored
Merge pull request #1526 from nexB/1403-declared-licenses-storage-improve
Improve declared_license storage #1403
2 parents 153a99b + 609ca7b commit d19003b

22 files changed

Lines changed: 590 additions & 289 deletions

src/packagedcode/cargo.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,6 @@ def repository_download_url(self, baseurl=default_download_baseurl):
7979
def api_data_url(self, baseurl=default_api_baseurl):
8080
return '{}/crates/{}'.format(baseurl, self.name)
8181

82-
def compute_normalized_license(self):
83-
return models.compute_normalized_license(self.declared_license)
84-
8582

8683
def is_cargo_toml(location):
8784
return (filetype.is_file(location) and fileutils.file_name(location).lower() == 'cargo.toml')
@@ -112,12 +109,15 @@ def build_package(package_data):
112109

113110
authors = core_package_data.get('authors')
114111
parties = list(party_mapper(authors, party_role='author'))
112+
113+
declared_license = core_package_data.get('license')
115114

116115
package = RustCargoCrate(
117116
name=name,
118117
version=version,
119118
description=description,
120119
parties=parties,
120+
declared_license = declared_license
121121
)
122122

123123
return package

src/packagedcode/freebsd.py

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from commoncode import fileutils
3838
from commoncode import saneyaml
3939
from packagedcode import models
40+
from packagedcode.utils import combine_expressions
4041

4142
"""
4243
Handle FreeBSD ports
@@ -66,6 +67,37 @@ def recognize(cls, location):
6667
def get_package_root(cls, manifest_resource, codebase):
6768
return manifest_resource.parent(codebase)
6869

70+
def compute_normalized_license(self):
71+
return compute_normalized_license(self.declared_license)
72+
73+
74+
def compute_normalized_license(declared_license):
75+
"""
76+
Return a normalized license expression string detected from a list of
77+
declared license items or an ordered dict.
78+
"""
79+
if not declared_license:
80+
return
81+
82+
licenses = declared_license.get('licenses')
83+
if not licenses:
84+
return
85+
86+
license_logic = declared_license.get('licenselogic')
87+
relation= 'AND'
88+
if license_logic:
89+
if license_logic == 'or' or license_logic == 'dual':
90+
relation = 'OR'
91+
92+
detected_licenses = []
93+
for declared in licenses:
94+
detected_license = models.compute_normalized_license(declared)
95+
if detected_license:
96+
detected_licenses.append(detected_license)
97+
98+
if detected_licenses:
99+
return combine_expressions(detected_licenses, relation)
100+
69101

70102
def is_freebsd_manifest(location):
71103
return (filetype.is_file(location)
@@ -148,20 +180,13 @@ def license_mapper(package_data, package):
148180
if not licenses:
149181
return
150182

151-
# licenselogic is found as 'or' in some cases in the wild
152-
if license_logic == 'or' or license_logic == 'dual':
153-
lics = [l.strip() for l in licenses if l and l.strip()]
154-
lics = ' OR '.join(lics)
155-
# licenselogic is found as 'and' in some cases in the wild
156-
elif license_logic == 'and' or license_logic == 'multi':
157-
lics = [l.strip() for l in licenses if l and l.strip()]
158-
lics = ' AND '.join(lics)
159-
# 'single' or default licenselogic value
160-
else:
161-
lics = [l.strip() for l in licenses if l and l.strip()]
162-
lics = ', '.join(lics)
163-
164-
package.declared_license = lics or None
183+
declared_license = OrderedDict()
184+
lics = [l.strip() for l in licenses if l and l.strip()]
185+
declared_license['licenses'] = lics
186+
if license_logic:
187+
declared_license['licenselogic'] = license_logic
188+
189+
package.declared_license = declared_license
165190
return package
166191

167192

src/packagedcode/phpcomposer.py

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
from commoncode import filetype
4040
from commoncode import fileutils
4141
from packagedcode import models
42+
from packagedcode.utils import combine_expressions
43+
4244

4345
"""
4446
Parse PHP composer package manifests, see https://getcomposer.org/ and
@@ -94,7 +96,39 @@ def compute_normalized_license(self):
9496
"""
9597
Per https://getcomposer.org/doc/04-schema.md#license this is an expression
9698
"""
97-
return models.Package.compute_normalized_license(self)
99+
return compute_normalized_license(self.declared_license)
100+
101+
102+
def compute_normalized_license(declared_license):
103+
"""
104+
Return a normalized license expression string detected from a list of
105+
declared license items or string type.
106+
"""
107+
if not declared_license:
108+
return
109+
110+
detected_licenses = []
111+
112+
if isinstance(declared_license, string_types):
113+
if declared_license == 'proprietary':
114+
return declared_license
115+
if '(' in declared_license and ')' in declared_license and ' or ' in declared_license:
116+
declared_license = declared_license.strip().rstrip(')').lstrip('(')
117+
declared_license = declared_license.split(' or ')
118+
else:
119+
return models.compute_normalized_license(declared_license)
120+
121+
if isinstance(declared_license, list):
122+
for declared in declared_license:
123+
detected_license = models.compute_normalized_license(declared)
124+
detected_licenses.append(detected_license)
125+
else:
126+
declared_license = repr(declared_license)
127+
detected_license = models.compute_normalized_license(declared_license)
128+
129+
if detected_licenses:
130+
# build a proper license expression: the defaultfor composer is OR
131+
return combine_expressions(detected_licenses, 'OR')
98132

99133

100134
def is_phpcomposer_json(location):
@@ -200,25 +234,11 @@ def licensing_mapper(licenses, package, is_private=False):
200234
license and the `is_private` Fkag is True, we return a "proprietary-license"
201235
license.
202236
"""
203-
if not licenses:
237+
if not licenses and is_private:
238+
package.declared_license = 'proprietary-license'
204239
return package
205240

206-
if isinstance(licenses, list):
207-
# For a package, when there is a choice between licenses
208-
# ("disjunctive license"), multiple can be specified as array.
209-
# build a proper license expression: the defaultfor composer is OR
210-
lics = [l.strip() for l in licenses if l and l.strip()]
211-
lics = ' OR '.join(lics)
212-
213-
elif not isinstance(licenses, string_types):
214-
lics = repr(licenses)
215-
else:
216-
lics = licenses
217-
218-
if not lics and is_private:
219-
lics ='proprietary-license'
220-
221-
package.declared_license = lics or None
241+
package.declared_license = licenses
222242
return package
223243

224244

src/packagedcode/utils.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ def build_description(summary, description):
150150
return description
151151

152152

153-
def combine_expressions(expressions, licensing=Licensing()):
153+
def combine_expressions(expressions, relation='AND', licensing=Licensing()):
154154
"""
155-
Return a combined license expression string with AND, given a list of
155+
Return a combined license expression string with relation, given a list of
156156
license expressions strings.
157157
158158
For example:
@@ -181,4 +181,7 @@ def combine_expressions(expressions, licensing=Licensing()):
181181
return expressions[0]
182182

183183
expressions = [licensing.parse(le, simple=True) for le in expressions]
184-
return str(licensing.AND(*expressions))
184+
if relation == 'OR':
185+
return str(licensing.OR(*expressions))
186+
else:
187+
return str(licensing.AND(*expressions))
Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,43 @@
11
{
2-
"type": "cargo",
3-
"namespace": null,
4-
"name": "clap",
5-
"version": "2.32.0",
6-
"qualifiers": null,
7-
"subpath": null,
8-
"primary_language": "Rust",
9-
"description": "A simple to use, efficient, and full featured Command Line Argument Parser",
10-
"release_date": null,
11-
"parties": [
12-
{
13-
"type": "person",
14-
"role": "author",
15-
"name": "Kevin K.",
16-
"email": "kbknapp@gmail.com",
17-
"url": null
18-
}
19-
],
20-
"keywords": [],
21-
"homepage_url": null,
22-
"download_url": null,
23-
"size": null,
24-
"sha1": null,
25-
"md5": null,
26-
"sha256": null,
27-
"sha512": null,
28-
"bug_tracking_url": null,
29-
"code_view_url": null,
30-
"vcs_url": null,
31-
"copyright": null,
32-
"license_expression": null,
33-
"declared_license": null,
34-
"notice_text": null,
35-
"manifest_path": null,
36-
"dependencies": [],
37-
"contains_source_code": null,
38-
"source_packages": [],
39-
"purl": "pkg:cargo/clap@2.32.0",
40-
"repository_homepage_url": "https://crates.io/crates/clap",
41-
"repository_download_url": "https://crates.io/api/v1/crates/clap/2.32.0/download",
42-
"api_data_url": "https://crates.io/api/v1/crates/clap"
43-
}
2+
"type": "cargo",
3+
"namespace": null,
4+
"name": "clap",
5+
"version": "2.32.0",
6+
"qualifiers": null,
7+
"subpath": null,
8+
"primary_language": "Rust",
9+
"description": "A simple to use, efficient, and full featured Command Line Argument Parser",
10+
"release_date": null,
11+
"parties": [
12+
{
13+
"type": "person",
14+
"role": "author",
15+
"name": "Kevin K.",
16+
"email": "kbknapp@gmail.com",
17+
"url": null
18+
}
19+
],
20+
"keywords": [],
21+
"homepage_url": null,
22+
"download_url": null,
23+
"size": null,
24+
"sha1": null,
25+
"md5": null,
26+
"sha256": null,
27+
"sha512": null,
28+
"bug_tracking_url": null,
29+
"code_view_url": null,
30+
"vcs_url": null,
31+
"copyright": null,
32+
"license_expression": "mit",
33+
"declared_license": "MIT",
34+
"notice_text": null,
35+
"manifest_path": null,
36+
"dependencies": [],
37+
"contains_source_code": null,
38+
"source_packages": [],
39+
"purl": "pkg:cargo/clap@2.32.0",
40+
"repository_homepage_url": "https://crates.io/crates/clap",
41+
"repository_download_url": "https://crates.io/api/v1/crates/clap/2.32.0/download",
42+
"api_data_url": "https://crates.io/api/v1/crates/clap"
43+
}

0 commit comments

Comments
 (0)