fosslight-util 2.0.0__tar.gz → 2.0.2__tar.gz

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 (39) hide show
  1. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/PKG-INFO +1 -1
  2. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/requirements.txt +3 -2
  3. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/setup.py +1 -1
  4. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/download.py +25 -24
  5. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/oss_item.py +2 -0
  6. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/output_format.py +86 -12
  7. fosslight_util-2.0.2/src/fosslight_util/write_spdx.py +265 -0
  8. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/PKG-INFO +1 -1
  9. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/requires.txt +4 -1
  10. fosslight_util-2.0.0/src/fosslight_util/write_spdx.py +0 -222
  11. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/LICENSE +0 -0
  12. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/MANIFEST.in +0 -0
  13. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/README.md +0 -0
  14. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/setup.cfg +0 -0
  15. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/__init__.py +0 -0
  16. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/_get_downloadable_url.py +0 -0
  17. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/compare_yaml.py +0 -0
  18. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/constant.py +0 -0
  19. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/convert_excel_to_yaml.py +0 -0
  20. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/correct.py +0 -0
  21. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/cover.py +0 -0
  22. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/help.py +0 -0
  23. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/parsing_yaml.py +0 -0
  24. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/read_excel.py +0 -0
  25. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/resources/frequentLicenselist.json +0 -0
  26. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/resources/frequent_license_nick_list.json +0 -0
  27. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/resources/licenses.json +0 -0
  28. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/set_log.py +0 -0
  29. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/spdx_licenses.py +0 -0
  30. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/timer_thread.py +0 -0
  31. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_excel.py +0 -0
  32. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_opossum.py +0 -0
  33. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_scancodejson.py +0 -0
  34. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_txt.py +0 -0
  35. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util/write_yaml.py +0 -0
  36. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/SOURCES.txt +0 -0
  37. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/dependency_links.txt +0 -0
  38. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/entry_points.txt +0 -0
  39. {fosslight_util-2.0.0 → fosslight_util-2.0.2}/src/fosslight_util.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fosslight_util
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: FOSSLight Util
5
5
  Home-page: https://github.com/fosslight/fosslight_util
6
6
  Author: LG Electronics
@@ -8,9 +8,10 @@ coloredlogs
8
8
  python3-wget
9
9
  beautifulsoup4
10
10
  jsonmerge
11
- spdx-tools==0.7.0rc0
11
+ spdx-tools>=0.8.2;sys_platform!="win32"
12
12
  setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid a vulnerability
13
13
  numpy; python_version < '3.8'
14
14
  numpy>=1.22.2; python_version >= '3.8'
15
15
  npm
16
- requests
16
+ requests
17
+ GitPython
@@ -14,7 +14,7 @@ with open('requirements.txt', 'r', 'utf-8') as f:
14
14
  if __name__ == "__main__":
15
15
  setup(
16
16
  name='fosslight_util',
17
- version='2.0.0',
17
+ version='2.0.2',
18
18
  package_dir={"": "src"},
19
19
  packages=find_packages(where='src'),
20
20
  description='FOSSLight Util',
@@ -10,7 +10,7 @@ import zipfile
10
10
  import logging
11
11
  import argparse
12
12
  import shutil
13
- import pygit2 as git
13
+ from git import Repo, GitCommandError
14
14
  import bz2
15
15
  import contextlib
16
16
  from datetime import datetime
@@ -230,14 +230,10 @@ def get_github_token(git_url):
230
230
 
231
231
 
232
232
  def download_git_clone(git_url, target_dir, checkout_to="", tag="", branch=""):
233
- ref_to_checkout = decide_checkout(checkout_to, tag, branch)
234
- msg = ""
235
233
  oss_name = get_github_ossname(git_url)
236
- oss_version = ""
237
- github_token = get_github_token(git_url)
238
- callbacks = None
239
- if github_token != "":
240
- callbacks = git.RemoteCallbacks(credentials=git.UserPass("foo", github_token)) # username is not used, so set to dummy
234
+ refs_to_checkout = decide_checkout(checkout_to, tag, branch)
235
+ clone_default_branch_flag = False
236
+ msg = ""
241
237
 
242
238
  try:
243
239
  if platform.system() != "Windows":
@@ -248,9 +244,26 @@ def download_git_clone(git_url, target_dir, checkout_to="", tag="", branch=""):
248
244
  alarm.start()
249
245
 
250
246
  Path(target_dir).mkdir(parents=True, exist_ok=True)
251
- repo = git.clone_repository(git_url, target_dir,
252
- bare=False, repository=None,
253
- remote=None, callbacks=callbacks)
247
+ if refs_to_checkout != "":
248
+ try:
249
+ # gitPython uses the branch argument the same whether you check out to a branch or a tag.
250
+ repo = Repo.clone_from(git_url, target_dir, branch=refs_to_checkout)
251
+ except GitCommandError as error:
252
+ error_msg = error.args[2].decode("utf-8")
253
+ if "Remote branch " + refs_to_checkout + " not found in upstream origin" in error_msg:
254
+ # clone default branch, when non-existent branch or tag entered
255
+ repo = Repo.clone_from(git_url, target_dir)
256
+ clone_default_branch_flag = True
257
+ else:
258
+ repo = Repo.clone_from(git_url, target_dir)
259
+ clone_default_branch_flag = True
260
+
261
+ if refs_to_checkout != tag or clone_default_branch_flag:
262
+ oss_version = repo.active_branch.name
263
+ else:
264
+ oss_version = repo.git.describe('--tags')
265
+ logger.info(f"git checkout: {oss_version}")
266
+
254
267
  if platform.system() != "Windows":
255
268
  signal.alarm(0)
256
269
  else:
@@ -258,20 +271,8 @@ def download_git_clone(git_url, target_dir, checkout_to="", tag="", branch=""):
258
271
  except Exception as error:
259
272
  logger.warning(f"git clone - failed: {error}")
260
273
  msg = str(error)
261
- return False, msg, oss_name, oss_version
262
- try:
263
- if ref_to_checkout != "":
264
- ref_list = [x for x in repo.references]
265
- ref_to_checkout = get_ref_to_checkout(ref_to_checkout, ref_list)
266
- logger.info(f"git checkout: {ref_to_checkout}")
267
- repo.checkout(ref_to_checkout)
274
+ return False, msg, oss_name, refs_to_checkout
268
275
 
269
- for prefix_ref in prefix_refs:
270
- if ref_to_checkout.startswith(prefix_ref):
271
- oss_version = ref_to_checkout[len(prefix_ref):]
272
-
273
- except Exception as error:
274
- logger.warning(f"git checkout to {ref_to_checkout} - failed: {error}")
275
276
  return True, msg, oss_name, oss_version
276
277
 
277
278
 
@@ -10,6 +10,7 @@ from fosslight_util.cover import CoverItem
10
10
  from typing import List, Dict
11
11
 
12
12
  _logger = logging.getLogger(LOGGER_NAME)
13
+ CHECKSUM_NULL = "0"
13
14
 
14
15
 
15
16
  class OssItem:
@@ -98,6 +99,7 @@ class FileItem:
98
99
  self._comment = ""
99
100
  self.is_binary = False
100
101
  self.oss_items: List[OssItem] = []
102
+ self.checksum = CHECKSUM_NULL
101
103
 
102
104
  def __del__(self):
103
105
  pass
@@ -3,12 +3,16 @@
3
3
  # Copyright (c) 2021 LG Electronics Inc.
4
4
  # SPDX-License-Identifier: Apache-2.0
5
5
  import os
6
+ import platform
6
7
  from fosslight_util.write_excel import write_result_to_excel, write_result_to_csv
7
8
  from fosslight_util.write_opossum import write_opossum
8
9
  from fosslight_util.write_yaml import write_yaml
10
+ from fosslight_util.write_spdx import write_spdx
9
11
  from typing import Tuple
10
12
 
11
- SUPPORT_FORMAT = {'excel': '.xlsx', 'csv': '.csv', 'opossum': '.json', 'yaml': '.yaml'}
13
+ SUPPORT_FORMAT = {'excel': '.xlsx', 'csv': '.csv', 'opossum': '.json', 'yaml': '.yaml',
14
+ 'spdx-yaml': '.yaml', 'spdx-json': '.json', 'spdx-xml': '.xml',
15
+ 'spdx-tag': '.tag'}
12
16
 
13
17
 
14
18
  def check_output_format(output='', format='', customized_format={}):
@@ -106,8 +110,62 @@ def check_output_formats(output='', formats=[], customized_format={}):
106
110
  return success, msg, output_path, output_files, output_extensions
107
111
 
108
112
 
113
+ def check_output_formats_v2(output='', formats=[], customized_format={}):
114
+ success = True
115
+ msg = ''
116
+ output_path = ''
117
+ output_files = []
118
+ output_extensions = []
119
+
120
+ if customized_format:
121
+ support_format = customized_format
122
+ else:
123
+ support_format = SUPPORT_FORMAT
124
+
125
+ if formats:
126
+ # If -f option exist
127
+ formats = [format.lower() for format in formats]
128
+ for format in formats:
129
+ if format not in list(support_format.keys()):
130
+ success = False
131
+ msg = 'Enter the supported format with -f option: ' + ', '.join(list(support_format.keys()))
132
+ else:
133
+ output_extensions.append(support_format[format])
134
+
135
+ if success:
136
+ if output != '':
137
+ basename_extension = ''
138
+ if not os.path.isdir(output):
139
+ output_path = os.path.dirname(output)
140
+
141
+ basename = os.path.basename(output)
142
+ basename_file, basename_extension = os.path.splitext(basename)
143
+ if basename_extension:
144
+ if formats:
145
+ if basename_extension not in output_extensions:
146
+ success = False
147
+ msg = f"The format of output file(-o:'{output}') should be in the format list(-f:'{formats}')."
148
+ else:
149
+ if basename_extension not in support_format.values():
150
+ success = False
151
+ msg = 'Enter the supported file extension: ' + ', '.join(list(support_format.values()))
152
+ output_extensions.append(basename_extension)
153
+ output_files = [basename_file for _ in range(len(output_extensions))]
154
+ else:
155
+ output_path = output
156
+ if not output_extensions:
157
+ output_extensions = ['.xlsx']
158
+ if not formats:
159
+ for ext in output_extensions:
160
+ for key, value in support_format.items():
161
+ if value == ext:
162
+ formats.append(key)
163
+ break
164
+ return success, msg, output_path, output_files, output_extensions, formats
165
+
166
+
109
167
  def write_output_file(output_file_without_ext: str, file_extension: str, scan_item, extended_header: dict = {},
110
- hide_header: dict = {}) -> Tuple[bool, str, str]:
168
+ hide_header: dict = {}, format: str = '', spdx_version: str = '2.3') -> Tuple[bool, str, str]:
111
169
  success = True
112
170
  msg = ''
113
171
 
@@ -115,16 +173,32 @@ def write_output_file(output_file_without_ext: str, file_extension: str, scan_it
115
173
  file_extension = '.xlsx'
116
174
  result_file = output_file_without_ext + file_extension
117
175
 
118
- if file_extension == '.xlsx':
119
- success, msg = write_result_to_excel(result_file, scan_item, extended_header, hide_header)
120
- elif file_extension == '.csv':
121
- success, msg, result_file = write_result_to_csv(result_file, scan_item, False, extended_header)
122
- elif file_extension == '.json':
123
- success, msg = write_opossum(result_file, scan_item)
124
- elif file_extension == '.yaml':
125
- success, msg, result_file = write_yaml(result_file, scan_item, False)
176
+ if format:
177
+ if format == 'excel':
178
+ success, msg = write_result_to_excel(result_file, scan_item, extended_header, hide_header)
179
+ elif format == 'csv':
180
+ success, msg, _ = write_result_to_csv(result_file, scan_item, False, extended_header)
181
+ elif format == 'opossum':
182
+ success, msg = write_opossum(result_file, scan_item)
183
+ elif format == 'yaml':
184
+ success, msg, _ = write_yaml(result_file, scan_item, False)
185
+ elif format.startswith('spdx'):
186
+ if platform.system() != 'Windows':
187
+ success, msg, _ = write_spdx(output_file_without_ext, file_extension, scan_item, spdx_version)
188
+ else:
189
+ success = False
190
+ msg = 'Windows not support spdx format.'
126
191
  else:
127
- success = False
128
- msg = f'Not supported file extension({file_extension})'
192
+ if file_extension == '.xlsx':
193
+ success, msg = write_result_to_excel(result_file, scan_item, extended_header, hide_header)
194
+ elif file_extension == '.csv':
195
+ success, msg, result_file = write_result_to_csv(result_file, scan_item, False, extended_header)
196
+ elif file_extension == '.json':
197
+ success, msg = write_opossum(result_file, scan_item)
198
+ elif file_extension == '.yaml':
199
+ success, msg, result_file = write_yaml(result_file, scan_item, False)
200
+ else:
201
+ success = False
202
+ msg = f'Not supported file extension({file_extension})'
129
203
 
130
204
  return success, msg, result_file
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # Copyright (c) 2022 LG Electronics Inc.
4
+ # SPDX-License-Identifier: Apache-2.0
5
+
6
+ import os
7
+ import uuid
8
+ import logging
9
+ import re
10
+ from pathlib import Path
11
+ from datetime import datetime
12
+ from fosslight_util.spdx_licenses import get_spdx_licenses_json, get_license_from_nick
13
+ from fosslight_util.constant import (LOGGER_NAME, FOSSLIGHT_DEPENDENCY, FOSSLIGHT_SCANNER,
14
+ FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE)
15
+ import traceback
16
+
17
+ logger = logging.getLogger(LOGGER_NAME)
18
+
19
+ try:
20
+ from spdx_tools.common.spdx_licensing import spdx_licensing
21
+ from spdx_tools.spdx.model import (
22
+ Actor,
23
+ ActorType,
24
+ Checksum,
25
+ ChecksumAlgorithm,
26
+ CreationInfo,
27
+ Document,
28
+ File,
29
+ Package,
30
+ Relationship,
31
+ RelationshipType,
32
+ SpdxNoAssertion,
33
+ SpdxNone
34
+ )
35
+ from spdx_tools.spdx.validation.document_validator import validate_full_spdx_document
36
+ from spdx_tools.spdx.writer.write_anything import write_file
37
+ except Exception:
38
+ logger.info('No import spdx-tools')
39
+
40
+
41
+ def get_license_list_version():
42
+ version = 'N/A'
43
+ success, error_msg, licenses = get_spdx_licenses_json()
44
+ if success:
45
+ version = licenses['licenseListVersion']
46
+ else:
47
+ logger.info(f'Fail to get spdx license list version:{error_msg}')
48
+ return version
49
+
50
+
51
+ def write_spdx(output_file_without_ext, output_extension, scan_item, spdx_version='2.3'):
52
+ success = True
53
+ error_msg = ''
54
+
55
+ if scan_item:
56
+ try:
57
+ cover_name = scan_item.cover.get_print_json()["Tool information"].split('(').pop(0).strip()
58
+ match = re.search(r"(.+) v([0-9.]+)", cover_name)
59
+ if match:
60
+ scanner_name = match.group(1)
61
+ else:
62
+ scanner_name = FOSSLIGHT_SCANNER
63
+ except Exception:
64
+ cover_name = FOSSLIGHT_SCANNER
65
+ scanner_name = FOSSLIGHT_SCANNER
66
+ creation_info = CreationInfo(spdx_version=f'SPDX-{spdx_version}',
67
+ spdx_id='SPDXRef-DOCUMENT',
68
+ name=f'SPDX Document by {scanner_name.upper()}',
69
+ data_license='CC0-1.0',
70
+ document_namespace=f'http://spdx.org/spdxdocs/{scanner_name.lower()}-{uuid.uuid4()}',
71
+ creators=[Actor(name=cover_name, actor_type=ActorType.TOOL)],
72
+ created=datetime.now())
73
+ doc = Document(creation_info=creation_info)
74
+
75
+ relation_tree = {}
76
+ spdx_id_packages = []
77
+
78
+ output_dir = os.path.dirname(output_file_without_ext)
79
+ Path(output_dir).mkdir(parents=True, exist_ok=True)
80
+ try:
81
+ file_id = 0
82
+ package_id = 0
83
+ root_package = False
84
+ for scanner_name, file_items in scan_item.file_items.items():
85
+ for file_item in file_items:
86
+ file = '' # file의 license, copyright은 oss item에서 append
87
+ if scanner_name in [FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE]:
88
+ file_id += 1
89
+ file = File(name=file_item.source_name_or_path,
90
+ spdx_id=f'SPDXRef-File{file_id}',
91
+ checksums=[Checksum(ChecksumAlgorithm.SHA1, file_item.checksum)])
92
+ file_license = []
93
+ file_copyright = []
94
+ file_comment = []
95
+ for oss_item in file_item.oss_items:
96
+ oss_licenses = []
97
+ declared_oss_licenses = []
98
+ lic_comment = []
99
+ for oi in oss_item.license:
100
+ oi = check_input_license_format(oi)
101
+ try:
102
+ oi_spdx = spdx_licensing.parse(oi, validate=True)
103
+ oss_licenses.append(oi_spdx)
104
+ declared_oss_licenses.append(oi)
105
+ except Exception:
106
+ logger.debug(f'No spdx license name: {oi}')
107
+ lic_comment.append(oi)
108
+ file_comment.append(oi)
109
+ if oss_licenses:
110
+ file_license.extend(oss_licenses)
111
+ if oss_item.copyright != '':
112
+ file_copyright.append(oss_item.copyright)
113
+
114
+ if oss_item.download_location == '':
115
+ if scanner_name == FOSSLIGHT_DEPENDENCY:
116
+ download_location = SpdxNone()
117
+ else:
118
+ continue
119
+ else:
120
+ download_location = oss_item.download_location
121
+ if scanner_name != FOSSLIGHT_DEPENDENCY and oss_item.name == '':
122
+ continue
123
+ package_id += 1
124
+ package = Package(name=oss_item.name,
125
+ spdx_id=f'SPDXRef-Package{package_id}',
126
+ download_location=download_location)
127
+
128
+ if oss_item.version != '':
129
+ package.version = oss_item.version
130
+
131
+ if scanner_name == FOSSLIGHT_DEPENDENCY:
132
+ package.files_analyzed = False # If omitted, the default value of true is assumed.
133
+ else:
134
+ package.files_analyzed = True
135
+ if oss_item.copyright != '':
136
+ package.cr_text = oss_item.copyright
137
+ if oss_item.homepage != '':
138
+ package.homepage = oss_item.homepage
139
+
140
+ if declared_oss_licenses:
141
+ package.license_declared = spdx_licensing.parse(' AND '.join(declared_oss_licenses))
142
+ if lic_comment:
143
+ package.license_comment = ' '.join(lic_comment)
144
+
145
+ doc.packages.append(package)
146
+
147
+ if scanner_name == FOSSLIGHT_DEPENDENCY:
148
+ purl = file_item.purl
149
+ spdx_id_packages.append([purl, package.spdx_id])
150
+ relation_tree[purl] = {}
151
+ relation_tree[purl]['id'] = package.spdx_id
152
+ relation_tree[purl]['dep'] = []
153
+ if 'root package' in oss_item.comment:
154
+ root_package = True
155
+ relationship = Relationship(doc.creation_info.spdx_id,
156
+ RelationshipType.DESCRIBES,
157
+ package.spdx_id)
158
+ doc.relationships.append(relationship)
159
+ relation_tree[purl]['dep'].extend(file_item.depends_on)
160
+
161
+ if scanner_name in [FOSSLIGHT_BINARY, FOSSLIGHT_SOURCE]:
162
+ if file_license:
163
+ file.license_info_in_file = file_license
164
+ if file_copyright:
165
+ file.copyright_text = '\n'.join(file_copyright)
166
+ if file_comment:
167
+ file.license_comment = ' '.join(file_comment)
168
+ doc.files.append(file)
169
+
170
+ if len(doc.packages) > 0:
171
+ for pkg in relation_tree:
172
+ if len(relation_tree[pkg]['dep']) > 0:
173
+ pkg_spdx_id = relation_tree[pkg]['id']
174
+ if len(relation_tree[pkg]['dep']) > 0:
175
+ for pname in relation_tree[pkg]['dep']:
176
+ ans = next(filter(lambda x: x[0] == pname, spdx_id_packages), None)
177
+ if ans is None:
178
+ continue
179
+ rel_pkg_spdx_id = ans[1]
180
+ relationship = Relationship(pkg_spdx_id, RelationshipType.DEPENDS_ON, rel_pkg_spdx_id)
181
+ doc.relationships.append(relationship)
182
+ if not root_package:
183
+ root_package = Package(name='root package',
184
+ spdx_id='SPDXRef-ROOT-PACKAGE',
185
+ download_location=SpdxNoAssertion())
186
+ root_package.files_analyzed = False
187
+ root_package.license_declared = SpdxNoAssertion()
188
+ doc.packages.append(root_package)
189
+ relationship = Relationship(doc.creation_info.spdx_id, RelationshipType.DESCRIBES, root_package.spdx_id)
190
+ doc.relationships.append(relationship)
191
+
192
+ except Exception as e:
193
+ success = False
194
+ error_msg = f'Failed to create spdx document object:{e}, {traceback.format_exc()}'
195
+ else:
196
+ success = False
197
+ error_msg = 'No item to write in output file.'
198
+
199
+ validation_messages = validate_full_spdx_document(doc)
200
+ for message in validation_messages:
201
+ logger.warning(message.validation_message)
202
+ logger.warning(message.context)
203
+
204
+ # assert validation_messages == []
205
+
206
+ result_file = ''
207
+ if success:
208
+ result_file = output_file_without_ext + output_extension
209
+ try:
210
+ write_file(doc, result_file)
211
+ except Exception as e:
212
+ success = False
213
+ error_msg = f'Failed to write spdx document: {e}'
214
+ if os.path.exists(result_file):
215
+ os.remove(result_file)
216
+
217
+ return success, error_msg, result_file
218
+
219
+
220
+ def convert_to_spdx_style(input_string):
221
+ input_string = re.sub(r'[^\w\s\.\-]', '', input_string)
222
+ input_string = re.sub(r'[\s\_]', '-', input_string)
223
+ input_converted = f"LicenseRef-{input_string}"
224
+ return input_converted
225
+
226
+
227
+ def check_input_license_format(input_license):
228
+ spdx_licenses = get_spdx_licensename()
229
+ for spdx in spdx_licenses:
230
+ if input_license.casefold() == spdx.casefold():
231
+ return spdx
232
+
233
+ if input_license.startswith('LicenseRef-'):
234
+ return input_license
235
+
236
+ licensesfromJson = get_license_from_nick()
237
+ if licensesfromJson == "":
238
+ logger.warning(" Error - Return Value to get license from Json is none")
239
+
240
+ try:
241
+ converted_license = licensesfromJson.get(input_license.casefold())
242
+ if converted_license is None:
243
+ converted_license = convert_to_spdx_style(input_license)
244
+ except Exception as ex:
245
+ logger.warning(f"Error - Get frequetly used license : {ex}")
246
+
247
+ return converted_license
248
+
249
+
250
+ def get_spdx_licensename():
251
+ spdx_licenses = []
252
+ try:
253
+ success, error_msg, licenses = get_spdx_licenses_json()
254
+ if success is False:
255
+ logger.warning(f"Error to get SPDX Licesens : {error_msg}")
256
+
257
+ licenseInfo = licenses.get("licenses")
258
+ for info in licenseInfo:
259
+ shortID = info.get("licenseId")
260
+ isDeprecated = info.get("isDeprecatedLicenseId")
261
+ if isDeprecated is False:
262
+ spdx_licenses.append(shortID)
263
+ except Exception as ex:
264
+ logger.warning(f"Error access to get_spdx_licenses_json : {ex}")
265
+ return spdx_licenses
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fosslight-util
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: FOSSLight Util
5
5
  Home-page: https://github.com/fosslight/fosslight_util
6
6
  Author: LG Electronics
@@ -8,10 +8,10 @@ coloredlogs
8
8
  python3-wget
9
9
  beautifulsoup4
10
10
  jsonmerge
11
- spdx-tools==0.7.0rc0
12
11
  setuptools>=65.5.1
13
12
  npm
14
13
  requests
14
+ GitPython
15
15
 
16
16
  [:python_version < "3.8"]
17
17
  numpy
@@ -24,3 +24,6 @@ pygit2==1.6.1
24
24
 
25
25
  [:python_version>='3.7']
26
26
  pygit2>=1.10.1
27
+
28
+ [:sys_platform != "win32"]
29
+ spdx-tools>=0.8.2
@@ -1,222 +0,0 @@
1
- #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
- # Copyright (c) 2022 LG Electronics Inc.
4
- # SPDX-License-Identifier: Apache-2.0
5
-
6
- import os
7
- import uuid
8
- import logging
9
- import re
10
- from pathlib import Path
11
- from spdx.creationinfo import Tool
12
- from spdx.document import Document
13
- from spdx.package import Package
14
- from spdx.relationship import Relationship
15
- from spdx.license import License, LicenseConjunction
16
- from spdx.utils import SPDXNone
17
- from spdx.utils import NoAssert
18
- from spdx.version import Version
19
- from spdx.writers import json
20
- from spdx.writers import yaml
21
- from spdx.writers import xml
22
- from spdx.writers import tagvalue
23
- from fosslight_util.spdx_licenses import get_spdx_licenses_json, get_license_from_nick
24
- from fosslight_util.constant import LOGGER_NAME, FOSSLIGHT_DEPENDENCY
25
- import traceback
26
-
27
- logger = logging.getLogger(LOGGER_NAME)
28
-
29
-
30
- def get_license_list_version():
31
- version = 'N/A'
32
- success, error_msg, licenses = get_spdx_licenses_json()
33
- if success:
34
- version = licenses['licenseListVersion']
35
- else:
36
- logger.info(f'Fail to get spdx license list version:{error_msg}')
37
- return version
38
-
39
-
40
- def write_spdx(output_file_without_ext, output_extension, scan_item,
41
- scanner_name, scanner_version, spdx_version=(2, 3)):
42
- success = True
43
- error_msg = ''
44
- if scan_item:
45
- doc = Document(version=Version(*spdx_version),
46
- data_license=License.from_identifier('CC0-1.0'),
47
- namespace=f'http://spdx.org/spdxdocs/{scanner_name.lower()}-{uuid.uuid4()}',
48
- name=f'SPDX Document by {scanner_name.upper()}',
49
- spdx_id='SPDXRef-DOCUMENT')
50
-
51
- doc.creation_info.set_created_now()
52
- doc.creation_info.add_creator(Tool(f'{scanner_name.upper()} {scanner_version}'))
53
- doc.creation_info.license_list_version = Version(*tuple(get_license_list_version().split('.')))
54
-
55
- relation_tree = {}
56
- spdx_id_packages = []
57
-
58
- output_dir = os.path.dirname(output_file_without_ext)
59
- Path(output_dir).mkdir(parents=True, exist_ok=True)
60
- try:
61
- package_id = 0
62
- root_package = False
63
- for scanner_name, _ in scan_item.file_items.items():
64
- json_contents = scan_item.get_print_json(scanner_name)
65
- for oss_item in json_contents:
66
- package_id += 1
67
- package = Package(spdx_id=f'SPDXRef-{package_id}')
68
-
69
- if oss_item.get('name', '') != '':
70
- package.name = oss_item.get('name', '') # required
71
- else:
72
- package.name = SPDXNone()
73
-
74
- if oss_item.get('version', '') != '':
75
- package.version = oss_item.get('version', '') # no required
76
-
77
- if oss_item.get('download location', '') != '':
78
- package.download_location = oss_item.get('download location', '') # required
79
- else:
80
- package.download_location = SPDXNone()
81
-
82
- if scanner_name == FOSSLIGHT_DEPENDENCY:
83
- package.files_analyzed = False # If omitted, the default value of true is assumed.
84
- else:
85
- package.files_analyzed = True
86
-
87
- if oss_item.get('homepage', '') != '':
88
- package.homepage = oss_item.get('homepage', '') # no required
89
-
90
- if oss_item.get('copyright text', '') != '':
91
- package.cr_text = oss_item.get('copyright text', '') # required
92
- else:
93
- package.cr_text = SPDXNone()
94
- if oss_item.get('license', []) != '':
95
- lic_list = [check_input_license_format(lic.strip()) for lic in oss_item.get('license', [])]
96
- first_lic = License.from_identifier(lic_list.pop(0))
97
- while lic_list:
98
- next_lic = License.from_identifier(lic_list.pop(0))
99
- license_conjunction = LicenseConjunction(first_lic, next_lic)
100
- first_lic = license_conjunction
101
- package.license_declared = first_lic
102
- else:
103
- package.license_declared = NoAssert() # required
104
-
105
- doc.add_package(package)
106
-
107
- if scanner_name == FOSSLIGHT_DEPENDENCY:
108
- purl = oss_item.get('package url', '')
109
- spdx_id_packages.append([purl, package.spdx_id])
110
- comment = oss_item.get('comment', '')
111
- relation_tree[purl] = {}
112
- relation_tree[purl]['id'] = package.spdx_id
113
- relation_tree[purl]['dep'] = []
114
-
115
- if 'root package' in comment.split(','):
116
- root_package = True
117
- relationship = Relationship(f"{doc.spdx_id} DESCRIBES {package.spdx_id}")
118
- doc.add_relationship(relationship)
119
- deps = oss_item.get('depends on', '')
120
- relation_tree[purl]['dep'].extend([di.strip().split('(')[0] for di in deps])
121
- if scanner_name == FOSSLIGHT_DEPENDENCY and len(relation_tree) > 0:
122
- for pkg in relation_tree:
123
- if len(relation_tree[pkg]['dep']) > 0:
124
- pkg_spdx_id = relation_tree[pkg]['id']
125
- if len(relation_tree[pkg]['dep']) > 0:
126
- for pname in relation_tree[pkg]['dep']:
127
- ans = next(filter(lambda x: x[0] == pname, spdx_id_packages), None)
128
- if ans is None:
129
- continue
130
- rel_pkg_spdx_id = ans[1]
131
- relationship = Relationship(f'{pkg_spdx_id} DEPENDS_ON {rel_pkg_spdx_id}')
132
- doc.add_relationship(relationship)
133
- if not root_package:
134
- root_package = Package(spdx_id='SPDXRef-ROOT-PACKAGE')
135
- root_package.name = 'root package'
136
- root_package.download_location = NoAssert()
137
- root_package.files_analyzed = False
138
- root_package.cr_text = SPDXNone()
139
- root_package.license_declared = NoAssert()
140
- doc.add_package(root_package)
141
- relationship = Relationship(f"{doc.spdx_id} DESCRIBES {root_package.spdx_id}")
142
- doc.add_relationship(relationship)
143
- except Exception as e:
144
- success = False
145
- error_msg = f'Failed to create spdx document object:{e}, {traceback.format_exc()}'
146
- else:
147
- success = False
148
- error_msg = 'No item to write in output file.'
149
-
150
- result_file = ''
151
- if success:
152
- result_file = output_file_without_ext + output_extension
153
- try:
154
- out_mode = "w"
155
- if result_file.endswith(".tag"):
156
- writer_module = tagvalue
157
- elif result_file.endswith(".json"):
158
- writer_module = json
159
- elif result_file.endswith(".xml"):
160
- writer_module = xml
161
- elif result_file.endswith(".yaml"):
162
- writer_module = yaml
163
- else:
164
- raise Exception("FileType Not Supported")
165
-
166
- with open(result_file, out_mode) as out:
167
- writer_module.write_document(doc, out, True)
168
- except Exception as e:
169
- success = False
170
- error_msg = f'Failed to write spdx document: {e}'
171
- if os.path.exists(result_file):
172
- os.remove(result_file)
173
-
174
- return success, error_msg, result_file
175
-
176
-
177
- def convert_to_spdx_style(input_string):
178
- input_string = re.sub(r'[^\w\s\.\-]', '', input_string)
179
- input_string = re.sub(r'[\s\_]', '-', input_string)
180
- input_converted = f"LicenseRef-{input_string}"
181
- return input_converted
182
-
183
-
184
- def check_input_license_format(input_license):
185
- spdx_licenses = get_spdx_licensename()
186
- for spdx in spdx_licenses:
187
- if input_license.casefold() == spdx.casefold():
188
- return spdx
189
-
190
- if input_license.startswith('LicenseRef-'):
191
- return input_license
192
-
193
- licensesfromJson = get_license_from_nick()
194
- if licensesfromJson == "":
195
- logger.warning(" Error - Return Value to get license from Json is none")
196
-
197
- try:
198
- converted_license = licensesfromJson.get(input_license.casefold())
199
- if converted_license is None:
200
- converted_license = convert_to_spdx_style(input_license)
201
- except Exception as ex:
202
- logger.warning(f"Error - Get frequetly used license : {ex}")
203
-
204
- return converted_license
205
-
206
-
207
- def get_spdx_licensename():
208
- spdx_licenses = []
209
- try:
210
- success, error_msg, licenses = get_spdx_licenses_json()
211
- if success is False:
212
- logger.warning(f"Error to get SPDX Licesens : {error_msg}")
213
-
214
- licenseInfo = licenses.get("licenses")
215
- for info in licenseInfo:
216
- shortID = info.get("licenseId")
217
- isDeprecated = info.get("isDeprecatedLicenseId")
218
- if isDeprecated is False:
219
- spdx_licenses.append(shortID)
220
- except Exception as ex:
221
- logger.warning(f"Error access to get_spdx_licenses_json : {ex}")
222
- return spdx_licenses
File without changes
File without changes
File without changes