spdx_tools.spdx.spdx_element_utils

 1# SPDX-FileCopyrightText: 2022 spdx contributors
 2#
 3# SPDX-License-Identifier: Apache-2.0
 4import hashlib
 5
 6from beartype.typing import List, Optional, Type, Union
 7
 8from spdx_tools.spdx.model import (
 9    ChecksumAlgorithm,
10    Document,
11    ExternalDocumentRef,
12    File,
13    Package,
14    PackageVerificationCode,
15    Snippet,
16)
17
18
19def get_element_type_from_spdx_id(
20    spdx_id: str, document: Document
21) -> Optional[Union[Type[Package], Type[File], Type[Snippet]]]:
22    if spdx_id in [package.spdx_id for package in document.packages]:
23        return Package
24    if spdx_id in [file.spdx_id for file in document.files]:
25        return File
26    if spdx_id in [snippet.spdx_id for snippet in document.snippets]:
27        return Snippet
28    return None
29
30
31def get_full_element_spdx_id(
32    element: Union[Package, File, Snippet],
33    document_namespace: str,
34    external_document_refs: List[ExternalDocumentRef],
35) -> str:
36    """
37    Returns the spdx_id of the element prefixed with the correct document namespace and,
38    if the element is from an external document, sets the correct entry in the imports property.
39    """
40    if ":" not in element.spdx_id:
41        return f"{document_namespace}#{element.spdx_id}"
42
43    external_id, local_id = element.spdx_id.split(":")
44    external_uri = None
45    for entry in external_document_refs:
46        if entry.document_ref_id == external_id:
47            external_uri = entry.document_uri
48            break
49
50    if not external_uri:
51        raise ValueError(f"external id {external_id} not found in external document references")
52
53    return external_uri + "#" + local_id
54
55
56def calculate_package_verification_code(files: List[File]) -> PackageVerificationCode:
57    list_of_file_hashes = []
58    for file in files:
59        file_checksum_value = None
60        for checksum in file.checksums:
61            if checksum.algorithm == ChecksumAlgorithm.SHA1:
62                file_checksum_value = checksum.value
63        if not file_checksum_value:
64            try:
65                file_checksum_value = calculate_file_checksum(file.name, ChecksumAlgorithm.SHA1)
66            except FileNotFoundError:
67                raise FileNotFoundError(
68                    f"Cannot calculate package verification code because the file '{file.name}' "
69                    f"provides no SHA1 checksum and can't be found at the specified location."
70                )
71        list_of_file_hashes.append(file_checksum_value)
72
73    list_of_file_hashes.sort()
74    hasher = hashlib.new("sha1")
75    hasher.update("".join(list_of_file_hashes).encode("utf-8"))
76    value = hasher.hexdigest()
77    return PackageVerificationCode(value)
78
79
80def calculate_file_checksum(file_name: str, hash_algorithm=ChecksumAlgorithm.SHA1) -> str:
81    BUFFER_SIZE = 65536
82
83    file_hash = hashlib.new(hash_algorithm.name.lower())
84    with open(file_name, "rb") as file_handle:
85        while True:
86            data = file_handle.read(BUFFER_SIZE)
87            if not data:
88                break
89            file_hash.update(data)
90
91    return file_hash.hexdigest()
def get_element_type_from_spdx_id( spdx_id: str, document: spdx_tools.spdx.model.document.Document) -> Union[type[spdx_tools.spdx.model.package.Package], type[spdx_tools.spdx.model.file.File], type[spdx_tools.spdx.model.snippet.Snippet], NoneType]:
20def get_element_type_from_spdx_id(
21    spdx_id: str, document: Document
22) -> Optional[Union[Type[Package], Type[File], Type[Snippet]]]:
23    if spdx_id in [package.spdx_id for package in document.packages]:
24        return Package
25    if spdx_id in [file.spdx_id for file in document.files]:
26        return File
27    if spdx_id in [snippet.spdx_id for snippet in document.snippets]:
28        return Snippet
29    return None
def get_full_element_spdx_id( element: Union[spdx_tools.spdx.model.package.Package, spdx_tools.spdx.model.file.File, spdx_tools.spdx.model.snippet.Snippet], document_namespace: str, external_document_refs: list[spdx_tools.spdx.model.external_document_ref.ExternalDocumentRef]) -> str:
32def get_full_element_spdx_id(
33    element: Union[Package, File, Snippet],
34    document_namespace: str,
35    external_document_refs: List[ExternalDocumentRef],
36) -> str:
37    """
38    Returns the spdx_id of the element prefixed with the correct document namespace and,
39    if the element is from an external document, sets the correct entry in the imports property.
40    """
41    if ":" not in element.spdx_id:
42        return f"{document_namespace}#{element.spdx_id}"
43
44    external_id, local_id = element.spdx_id.split(":")
45    external_uri = None
46    for entry in external_document_refs:
47        if entry.document_ref_id == external_id:
48            external_uri = entry.document_uri
49            break
50
51    if not external_uri:
52        raise ValueError(f"external id {external_id} not found in external document references")
53
54    return external_uri + "#" + local_id

Returns the spdx_id of the element prefixed with the correct document namespace and, if the element is from an external document, sets the correct entry in the imports property.

def calculate_package_verification_code( files: list[spdx_tools.spdx.model.file.File]) -> spdx_tools.spdx.model.package.PackageVerificationCode:
57def calculate_package_verification_code(files: List[File]) -> PackageVerificationCode:
58    list_of_file_hashes = []
59    for file in files:
60        file_checksum_value = None
61        for checksum in file.checksums:
62            if checksum.algorithm == ChecksumAlgorithm.SHA1:
63                file_checksum_value = checksum.value
64        if not file_checksum_value:
65            try:
66                file_checksum_value = calculate_file_checksum(file.name, ChecksumAlgorithm.SHA1)
67            except FileNotFoundError:
68                raise FileNotFoundError(
69                    f"Cannot calculate package verification code because the file '{file.name}' "
70                    f"provides no SHA1 checksum and can't be found at the specified location."
71                )
72        list_of_file_hashes.append(file_checksum_value)
73
74    list_of_file_hashes.sort()
75    hasher = hashlib.new("sha1")
76    hasher.update("".join(list_of_file_hashes).encode("utf-8"))
77    value = hasher.hexdigest()
78    return PackageVerificationCode(value)
def calculate_file_checksum(file_name: str, hash_algorithm=<ChecksumAlgorithm.SHA1: 1>) -> str:
81def calculate_file_checksum(file_name: str, hash_algorithm=ChecksumAlgorithm.SHA1) -> str:
82    BUFFER_SIZE = 65536
83
84    file_hash = hashlib.new(hash_algorithm.name.lower())
85    with open(file_name, "rb") as file_handle:
86        while True:
87            data = file_handle.read(BUFFER_SIZE)
88            if not data:
89                break
90            file_hash.update(data)
91
92    return file_hash.hexdigest()