11import sys
2+ from typing import Dict , Optional
23
34from strictdoc .backend .sdoc .errors .document_tree_error import DocumentTreeError
5+ from strictdoc .backend .sdoc .models .node import SDocNode
46from strictdoc .backend .sdoc .writer import SDWriter
57from strictdoc .backend .sdoc_source_code .marker_writer import MarkerWriter
68from strictdoc .backend .sdoc_source_code .models .source_file_info import (
1618from strictdoc .core .traceability_index import TraceabilityIndex
1719from strictdoc .core .traceability_index_builder import TraceabilityIndexBuilder
1820from strictdoc .helpers .parallelizer import Parallelizer
19- from strictdoc .helpers .sha256 import get_random_sha256 , get_sha256
21+ from strictdoc .helpers .sha256 import get_random_sha256 , get_sha256 , is_sha256
2022from strictdoc .helpers .string import (
2123 create_safe_acronym ,
2224)
@@ -97,6 +99,13 @@ def execute(
9799 )
98100 next_number += 1
99101
102+ for (
103+ trace_info_
104+ ) in traceability_index .get_file_traceability_index ().trace_infos :
105+ ManageAutoUIDCommand ._rewrite_source_file (
106+ trace_info_ , project_config
107+ )
108+
100109 for document in traceability_index .document_tree .document_list :
101110 assert document .meta is not None
102111
@@ -116,21 +125,15 @@ def execute(
116125 ) as output_file :
117126 output_file .write (document_content )
118127
119- for (
120- trace_info_
121- ) in traceability_index .get_file_traceability_index ().trace_infos :
122- ManageAutoUIDCommand ._rewrite_source_file (
123- trace_info_ , project_config
124- )
125-
126128 @staticmethod
127129 def _rewrite_source_file (
128- trace_info : SourceFileTraceabilityInfo , project_config : ProjectConfig
130+ trace_info : SourceFileTraceabilityInfo ,
131+ project_config : ProjectConfig ,
129132 ) -> None :
130133 """
131134 NOTE: This only updates the source code with the new calculated value.
132- All links in the graph database and links in the search index are
133- not modified for now.
135+ All links in the graph database and links in the search index
136+ ARE NOT! modified for now.
134137 """
135138
136139 assert trace_info .source_file is not None
@@ -146,7 +149,19 @@ def _rewrite_source_file(
146149 with open (trace_info .source_file .full_path , "rb" ) as source_file_ :
147150 file_bytes = source_file_ .read ()
148151
149- rewrites = {}
152+ field_remapped_mid = "MID"
153+
154+ relevant_source_node_config = (
155+ project_config .get_relevant_source_nodes_entry (
156+ trace_info .source_file .in_doctree_source_file_rel_path_posix
157+ )
158+ )
159+ if relevant_source_node_config is not None :
160+ field_remapped_mid = (
161+ relevant_source_node_config .sdoc_to_source_map .get ("MID" , "MID" )
162+ )
163+
164+ file_rewrites = {}
150165 for source_node_ in trace_info .source_nodes :
151166 function = source_node_ .function
152167 if function is None or function .code_byte_range is None :
@@ -157,50 +172,101 @@ def _rewrite_source_file(
157172 if source_node_ .comment_byte_range is None :
158173 continue
159174
160- # FILE_PATH: The file the code resides in, relative to the root of the project repository.
161- file_path = bytes (
162- trace_info .source_file .in_doctree_source_file_rel_path_posix ,
163- encoding = "utf8" ,
164- )
175+ if field_remapped_mid not in source_node_ .fields :
176+ continue
165177
166- # INSTANCE: The requirement template instance, minus tags with hash strings.
167- instance_bytes = bytearray ()
168- for field_name_ , field_value_ in source_node_ .fields .items ():
169- if field_name_ in ("SPDX-Req-ID" , "SPDX-Req-HKey" ):
170- continue
171- instance_bytes += bytes (field_value_ , encoding = "utf8" )
172-
173- # CODE: The code that the SPDX-Req applies to.
174- code = file_bytes [
175- function .code_byte_range .start : function .code_byte_range .end
176- ]
177-
178- # This is important for Windows. Otherwise, the hash key will be calculated incorrectly.
179- instance_bytes = instance_bytes .replace (b"\r \n " , b"\n " )
180- code = code .replace (b"\r \n " , b"\n " )
181-
182- hash_spdx_id = bytes (get_random_sha256 (), encoding = "utf8" )
183- hash_spdx_hash = generate_code_hash (
184- project = bytes (project_config .project_title , encoding = "utf8" ),
185- file_path = file_path ,
186- instance = bytes (instance_bytes ),
187- code = code ,
188- )
189- patched_node = MarkerWriter ().write (
190- source_node_ ,
191- rewrites = {
192- "SPDX-Req-ID" : hash_spdx_id ,
193- "SPDX-Req-HKey" : hash_spdx_hash ,
194- },
195- comment_file_bytes = file_bytes [
196- source_node_ .comment_byte_range .start : source_node_ .comment_byte_range .end
197- ],
198- )
199- rewrites [source_node_ ] = patched_node
178+ node_rewrites : Dict [str , bytes ] = {}
179+
180+ # If the source node has the MID (SPDX-REQ-ID), but it is not yet a
181+ # valid SHA256 identifier, create one and patch the node.
182+ existing_req_id = source_node_ .fields [field_remapped_mid ]
183+ if not is_sha256 (existing_req_id ):
184+ hash_spdx_id_str = get_random_sha256 ()
185+ hash_spdx_id = bytes (hash_spdx_id_str , encoding = "utf8" )
186+
187+ if (sdoc_node_ := source_node_ .sdoc_node ) is not None :
188+ sdoc_node_ .set_field_value (
189+ field_name = "MID" ,
190+ form_field_index = 0 ,
191+ value = hash_spdx_id_str ,
192+ )
193+ node_rewrites [field_remapped_mid ] = hash_spdx_id
194+
195+ patched_node = MarkerWriter ().write (
196+ source_node_ ,
197+ rewrites = node_rewrites ,
198+ comment_file_bytes = file_bytes [
199+ source_node_ .comment_byte_range .start : source_node_ .comment_byte_range .end
200+ ],
201+ )
202+ file_rewrites [source_node_ ] = patched_node
203+
204+ # If a source node has no sidecar SDoc node attached, there is
205+ # nothing else to do.
206+ if source_node_ .sdoc_node is None :
207+ continue
208+
209+ #
210+ # The following is only applicable to the Linux Kernel Requirements
211+ # Template proposal:
212+ #
213+ # Generate HASH field if it is not present. The HASH field is only
214+ # generated for SDoc nodes, the source code nodes are not modified.
215+ #
216+ sdoc_node : SDocNode = source_node_ .sdoc_node
217+
218+ existing_req_hash : Optional [str ] = None
219+ if "HASH" in sdoc_node .ordered_fields_lookup :
220+ hash_field = sdoc_node .get_field_by_name ("HASH" )
221+ existing_req_hash = hash_field .get_text_value ()
222+
223+ if existing_req_hash is None or not is_sha256 (existing_req_hash ):
224+ # FILE_PATH: The file the code resides in, relative to the root of the project repository.
225+ file_path = bytes (
226+ trace_info .source_file .in_doctree_source_file_rel_path_posix ,
227+ encoding = "utf8" ,
228+ )
229+
230+ # INSTANCE: The requirement template instance, minus tags with hash strings.
231+ instance_bytes = bytearray ()
232+ for (
233+ field_name_ ,
234+ field_values_ ,
235+ ) in sdoc_node .ordered_fields_lookup .items ():
236+ if field_name_ in ("MID" , "HASH" ):
237+ continue
238+ for field_value_ in field_values_ :
239+ instance_bytes += bytes (
240+ field_value_ .get_text_value (), encoding = "utf8"
241+ )
242+
243+ # CODE: The code that the node hash applies to.
244+ code = file_bytes [
245+ function .code_byte_range .start : function .code_byte_range .end
246+ ]
247+
248+ # This is important for Windows. Otherwise, the hash key will be calculated incorrectly.
249+ instance_bytes = instance_bytes .replace (b"\r \n " , b"\n " )
250+ code = code .replace (b"\r \n " , b"\n " )
251+
252+ hash_spdx_hash = generate_code_hash (
253+ project = bytes (
254+ project_config .project_title , encoding = "utf8"
255+ ),
256+ file_path = file_path ,
257+ instance = bytes (instance_bytes ),
258+ code = code ,
259+ )
260+ hash_spdx_hash_str = hash_spdx_hash .decode ("utf8" )
261+ sdoc_node .set_field_value (
262+ field_name = "HASH" ,
263+ form_field_index = 0 ,
264+ value = hash_spdx_hash_str ,
265+ )
200266
201267 source_writer = SourceWriter ()
202268 output_string = source_writer .write (
203- trace_info , rewrites = rewrites , file_bytes = file_bytes
269+ trace_info , rewrites = file_rewrites , file_bytes = file_bytes
204270 )
205271
206272 with open (trace_info .source_file .full_path , "wb" ) as source_file_ :
0 commit comments