Skip to content

Commit a4160cf

Browse files
authored
✨ Convert absolute to relative paths (#22)
Expand tests for SN 6.1
1 parent 303c56b commit a4160cf

File tree

9 files changed

+926
-109
lines changed

9 files changed

+926
-109
lines changed

docs/configuration.rst

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,185 @@ value. If they match, the option is excluded from the output file.
373373
configuration that includes all customized values while excluding unchanged defaults.
374374
This provides a clean view of what's been explicitly configured.
375375

376+
.. _`config_relativize_paths`:
377+
378+
needscfg_relative_path_fields
379+
-----------------------------
380+
381+
**Type:** ``list[str | dict]``
382+
383+
**Default:** ``[]``
384+
385+
Specifies which configuration fields should have their absolute paths converted to relative paths
386+
in the output file. This is particularly useful when working with build systems like Bazel that
387+
generate absolute paths, but you want the configuration file to use relative paths for portability.
388+
389+
Each entry in the list can be either:
390+
391+
1. **String format** (simple field pattern):
392+
393+
- ``"needs_schema_debug_path"`` - Matches the field directly
394+
- ``"needs_external_needs[*].json"`` - Supports ``*`` wildcards for array indices
395+
396+
2. **Dict format** (for paths embedded in strings with prefix/suffix):
397+
398+
- ``field`` (required): The field pattern to match (e.g., ``"needs_flow_configs.my_config"``)
399+
- ``prefix`` (optional): String prefix before the path (e.g., ``"!include "``)
400+
- ``suffix`` (optional): String suffix after the path (e.g., ``"?raw=true"``)
401+
402+
**When a field matches a pattern:**
403+
404+
1. Check if the value is an absolute path (``Path`` object or string)
405+
2. Extract the path portion (removing prefix/suffix if configured)
406+
3. Calculate a relative path from the output file location to the target path
407+
4. Replace with relative path (preserving prefix/suffix if configured)
408+
409+
**Configuration Formats:**
410+
411+
.. code-block:: python
412+
413+
needscfg_relative_path_fields = [
414+
# Simple string format - for direct path values
415+
"needs_schema_debug_path",
416+
417+
# String with wildcards - for array fields
418+
"needs_external_needs[*].json_path",
419+
420+
# Dict with prefix - for paths embedded in strings like "!include /path/to/file"
421+
{
422+
"field": "needs_flow_configs.plantuml_config",
423+
"prefix": "!include ",
424+
},
425+
426+
# Dict with suffix - for paths like "/path/to/file?option=value"
427+
{
428+
"field": "needs_asset_url",
429+
"suffix": "?raw=true",
430+
},
431+
432+
# Dict with both prefix and suffix
433+
{
434+
"field": "needs_custom_path",
435+
"prefix": "file://",
436+
"suffix": "#anchor",
437+
},
438+
439+
# Dict with just field (equivalent to string format)
440+
{
441+
"field": "needs_build_json_path",
442+
},
443+
]
444+
445+
**Use Cases:**
446+
447+
- Working with Bazel or similar build systems that use absolute paths
448+
- Making configuration files portable across different machines/environments
449+
- Handling PlantUML ``!include`` directives with absolute paths
450+
- Processing URL-like strings with path components
451+
- Keeping paths relative to the repository root instead of absolute system paths
452+
453+
**Example with Bazel:**
454+
455+
If you have a Bazel-generated path like:
456+
457+
.. code-block:: python
458+
459+
# In conf.py (generated by Bazel)
460+
needs_schema_debug_path = "/home/user/.cache/bazel/.../execroot/_main/bazel-out/k8-fastbuild/bin/docs.runfiles/project/schema_debug"
461+
462+
And your configuration file output is at:
463+
464+
.. code-block:: text
465+
466+
/home/user/git/project/docs/ubproject.toml
467+
/home/user/git/project/bazel-out > /home/user/.cache/bazel/.../execroot/_main/bazel-out
468+
469+
Note that Bazel creates a ``bazel-out`` symlink in the project directory
470+
(``/home/user/git/project/bazel-out``) that points into the Bazel cache.
471+
The extension detects this symlink and uses it to create a shorter relative path.
472+
473+
With this setting:
474+
475+
.. code-block:: python
476+
477+
needscfg_relative_path_fields = ["needs_schema_debug_path"]
478+
479+
The output will contain:
480+
481+
.. code-block:: toml
482+
483+
[needs]
484+
schema_debug_path = "../bazel-out/k8-fastbuild/bin/docs.runfiles/project/schema_debug"
485+
486+
**Example with Prefix (PlantUML !include directive):**
487+
488+
If you have a PlantUML configuration with an ``!include`` directive:
489+
490+
.. code-block:: python
491+
492+
# In conf.py
493+
needs_flow_configs = {
494+
"plantuml_theme": "!include /home/user/project/assets/theme.puml"
495+
}
496+
497+
With this configuration:
498+
499+
.. code-block:: python
500+
501+
needscfg_relative_path_fields = [
502+
{
503+
"field": "needs_flow_configs.plantuml_theme",
504+
"prefix": "!include ",
505+
}
506+
]
507+
508+
The output will preserve the ``!include`` prefix with a relative path:
509+
510+
.. code-block:: toml
511+
512+
[needs.flow_configs]
513+
plantuml_theme = "!include ../assets/theme.puml"
514+
515+
**Example with Suffix (URL parameters):**
516+
517+
For paths that include URL parameters or anchors:
518+
519+
.. code-block:: python
520+
521+
# In conf.py
522+
needs_asset_url = "/home/user/project/docs/image.png?width=500"
523+
524+
needscfg_relative_path_fields = [
525+
{
526+
"field": "needs_asset_url",
527+
"suffix": "?width=500",
528+
}
529+
]
530+
531+
The output preserves the suffix:
532+
533+
.. code-block:: toml
534+
535+
[needs]
536+
asset_url = "../image.png?width=500"
537+
538+
.. warning::.. warning::
539+
540+
Path relativization is only applied to fields explicitly listed in the allowlist.
541+
This is a safety feature to prevent unintended path transformations. You must
542+
explicitly specify which fields should have their paths relativized.
543+
544+
.. note::
545+
546+
- All relative paths are converted to POSIX format (forward slashes) on all platforms,
547+
including Windows. This ensures configuration files are portable across operating systems.
548+
- The extension correctly handles output file paths that don't exist yet (common for
549+
generated configuration files) by detecting file suffixes like ``.toml`` or ``.json``.
550+
- On Unix systems, the extension attempts to find symlinks (like Bazel's ``bazel-out``)
551+
to create shorter relative paths when possible.
552+
- If no common ancestor exists (e.g., paths on different drives on Windows), the
553+
absolute path will be returned unchanged.
554+
376555
Examples
377556
--------
378557

0 commit comments

Comments
 (0)