1010#
1111# SPDX-License-Identifier: Apache-2.0
1212# *******************************************************************************
13+ import tempfile
1314from pathlib import Path
1415
1516from sphinx .application import Sphinx
1617
1718from src .helper_lib import config_setdefault
1819
1920
20- def _write_needs_fields_toml (app : Sphinx ) -> Path :
21+ def _generate_needs_fields_toml (app : Sphinx ) -> str :
2122 """Serialize ``app.config.needs_fields`` as ``[needs.fields.*]`` TOML entries.
2223
2324 ``needs_config_writer`` cannot serialize the nested dicts that make up
@@ -26,31 +27,24 @@ def _write_needs_fields_toml(app: Sphinx) -> Path:
2627 from ``ubproject.toml``. Without them, ubCode does not know these are valid
2728 options and will report them as unknown fields.
2829
29- This function writes only the ``default`` value for each field, which is
30- sufficient for ubCode to recognise the field as valid.
30+ Returns only the ``default`` value for each field, which is sufficient for
31+ ubCode to recognise the field as valid.
3132
3233 Must be called *after* ``score_metamodel.setup()`` has run (i.e. after
3334 ``app.config.needs_fields`` has been extended with the metamodel fields).
3435 """
35- lines : list [str ] = [
36- "# Auto-generated – do not edit manually.\n " ,
37- "# Contains [needs.fields.*] entries derived from metamodel.yaml.\n " ,
38- "# Required for the ubCode language server to recognise custom need fields.\n \n " ,
39- ]
36+ lines : list [str ] = []
4037 for field_name , field_config in sorted (app .config .needs_fields .items ()):
4138 default = field_config .get ("default" , "" )
4239 # TOML-escape the default value (handle quotes)
4340 escaped = str (default ).replace ("\\ " , "\\ \\ " ).replace ('"' , '\\ "' )
4441 lines .append (f"[needs.fields.{ field_name } ]\n " )
4542 lines .append (f'default = "{ escaped } "\n ' )
4643 lines .append ("\n " )
47-
48- output_path = Path (app .confdir ) / "needs_fields_generated.toml"
49- output_path .write_text ("" .join (lines ), encoding = "utf-8" )
50- return output_path
44+ return "" .join (lines )
5145
5246
53- def _write_needs_links_toml (app : Sphinx ) -> Path :
47+ def _generate_needs_links_toml (app : Sphinx ) -> str :
5448 """Serialize ``app.config.needs_links`` as ``[needs.links.*]`` TOML entries.
5549
5650 ``needs_config_writer`` cannot serialize the ``needs_links`` dict of dicts
@@ -62,11 +56,7 @@ def _write_needs_links_toml(app: Sphinx) -> Path:
6256 Must be called *after* ``score_metamodel.setup()`` has run (i.e. after
6357 ``app.config.needs_links`` has been updated with the metamodel links).
6458 """
65- lines : list [str ] = [
66- "# Auto-generated – do not edit manually.\n " ,
67- "# Contains [needs.links.*] entries derived from metamodel.yaml.\n " ,
68- "# Required for the ubCode language server to recognise custom link types.\n \n " ,
69- ]
59+ lines : list [str ] = []
7060 for link_name , link_config in sorted (app .config .needs_links .items ()):
7161 incoming = (
7262 str (link_config .get ("incoming" , "" ))
@@ -82,13 +72,10 @@ def _write_needs_links_toml(app: Sphinx) -> Path:
8272 lines .append (f'incoming = "{ incoming } "\n ' )
8373 lines .append (f'outgoing = "{ outgoing } "\n ' )
8474 lines .append ("\n " )
85-
86- output_path = Path (app .confdir ) / "needs_links_generated.toml"
87- output_path .write_text ("" .join (lines ), encoding = "utf-8" )
88- return output_path
75+ return "" .join (lines )
8976
9077
91- def _write_needs_types_toml (app : Sphinx ) -> Path :
78+ def _generate_needs_types_toml (app : Sphinx ) -> str :
9279 """Serialize ``app.config.needs_types`` as ``[[needs.types]]`` TOML entries.
9380
9481 ``needs_config_writer`` cannot serialize the complex ``ScoreNeedType``
@@ -97,19 +84,13 @@ def _write_needs_types_toml(app: Sphinx) -> Path:
9784 the ubCode language server does not recognise any RST directives as needs
9885 and indexes nothing.
9986
100- This function writes only the fields that ubCode requires to identify
101- need directives (``directive``, ``title``, ``prefix``, and optionally
102- ``color``/``style``) to a separate TOML file that is then merged into
103- ``ubproject.toml`` by ``needs_config_writer``.
87+ Returns only the fields that ubCode requires to identify need directives
88+ (``directive``, ``title``, ``prefix``, and optionally ``color``/``style``).
10489
10590 Must be called *after* ``score_metamodel.setup()`` has run (i.e. after
10691 ``app.config.needs_types`` has been extended with the metamodel types).
10792 """
108- lines : list [str ] = [
109- "# Auto-generated – do not edit manually.\n " ,
110- "# Contains [[needs.types]] entries derived from metamodel.yaml.\n " ,
111- "# Required for the ubCode language server to recognise need directives.\n \n " ,
112- ]
93+ lines : list [str ] = []
11394 for nt in app .config .needs_types :
11495 lines .append ("[[needs.types]]\n " )
11596 lines .append (f'directive = "{ nt ["directive" ]} "\n ' )
@@ -120,10 +101,7 @@ def _write_needs_types_toml(app: Sphinx) -> Path:
120101 if style := nt .get ("style" ):
121102 lines .append (f'style = "{ style } "\n ' )
122103 lines .append ("\n " )
123-
124- output_path = Path (app .confdir ) / "needs_types_generated.toml"
125- output_path .write_text ("" .join (lines ), encoding = "utf-8" )
126- return output_path
104+ return "" .join (lines )
127105
128106
129107def setup (app : Sphinx ) -> dict [str , str | bool ]:
@@ -171,29 +149,22 @@ def setup(app: Sphinx) -> dict[str, str | bool]:
171149 )
172150 """Merge the static TOML file into the generated configuration."""
173151
174- # Write [[needs.types]] from the metamodel into a separate TOML fragment and
175- # merge it. needs_config_writer cannot serialise the complex ScoreNeedType
176- # dicts itself (unsupported_type), so ubproject.toml would otherwise contain
177- # no type definitions and the ubCode language server would index nothing.
178- needs_types_toml = _write_needs_types_toml (app )
179- app .config .needscfg_merge_toml_files .append (str (needs_types_toml ))
180- """Merge the generated [[needs.types]] TOML into the final ubproject.toml."""
181-
182- # Write [needs.fields.*] from the metamodel into a separate TOML fragment and
183- # merge it. needs_config_writer cannot serialise the nested field dicts, so
184- # custom fields like 'safety', 'security', 'reqtype' etc. would be absent from
185- # ubproject.toml and ubCode would flag them as unknown.
186- needs_fields_toml = _write_needs_fields_toml (app )
187- app .config .needscfg_merge_toml_files .append (str (needs_fields_toml ))
188- """Merge the generated [needs.fields.*] TOML into the final ubproject.toml."""
189-
190- # Write [needs.links.*] from the metamodel into a separate TOML fragment and
191- # merge it. needs_config_writer cannot serialise the nested link dicts, so
192- # custom link types like 'satisfies', 'fulfils', 'belongs_to' etc. would be
193- # absent from ubproject.toml and ubCode would not recognise them.
194- needs_links_toml = _write_needs_links_toml (app )
195- app .config .needscfg_merge_toml_files .append (str (needs_links_toml ))
196- """Merge the generated [needs.links.*] TOML into the final ubproject.toml."""
152+ # Generate TOML fragments for types, fields, and links from the metamodel.
153+ # needs_config_writer cannot serialise these structures itself, so we combine
154+ # them into a single temporary file and register it for merging.
155+ # A NamedTemporaryFile with delete=False is used so the path remains valid
156+ # when needs_config_writer reads it later during the write phase.
157+ metamodel_toml = (
158+ _generate_needs_types_toml (app )
159+ + _generate_needs_fields_toml (app )
160+ + _generate_needs_links_toml (app )
161+ )
162+ with tempfile .NamedTemporaryFile (
163+ mode = "w" , suffix = ".toml" , delete = False , encoding = "utf-8"
164+ ) as tmp :
165+ tmp .write (metamodel_toml )
166+ app .config .needscfg_merge_toml_files .append (tmp .name )
167+ """Merge the generated metamodel TOML (types, fields, links) into the final ubproject.toml."""
197168
198169 app .config .needscfg_relative_path_fields .extend (
199170 [
0 commit comments