Browse Source

Improve documentation search results for individual configuration options.

Dan Helfman 4 weeks ago
parent
commit
859c338d06

+ 1 - 0
NEWS

@@ -1,6 +1,7 @@
 2.0.12.dev0
 2.0.12.dev0
  * Add documentation on repositories, including SSH, Rclone, S3, and B2:
  * Add documentation on repositories, including SSH, Rclone, S3, and B2:
    https://torsion.org/borgmatic/reference/configuration/repositories/
    https://torsion.org/borgmatic/reference/configuration/repositories/
+ * Improve documentation search results for individual configuration options.
 
 
 2.0.11
 2.0.11
  * #957: Document borgmatic's limitations around parallelism—both its own and Borg's. See the
  * #957: Document borgmatic's limitations around parallelism—both its own and Borg's. See the

+ 28 - 3
borgmatic/config/generate.py

@@ -1,6 +1,7 @@
 import collections
 import collections
 import contextlib
 import contextlib
 import io
 import io
+import json
 import os
 import os
 import re
 import re
 
 
@@ -316,6 +317,24 @@ def merge_source_configuration_into_destination(destination_config, source_confi
     return destination_config
     return destination_config
 
 
 
 
+def get_configuration_subset(config, option_name):  # pragma: no cover
+    '''
+    Given configuration as a ruamel.yaml.CommentedMap and an option name found within it at the top
+    level, return a new CommentedMap containing a subset of the configuration with only the given
+    option and no other top-level options.
+
+    This is useful when generating the sample configuration for a single option instead of a whole
+    configuration file.
+    '''
+    option_config = ruamel.yaml.CommentedMap({option_name: config[option_name]})
+
+    # Due to a quirk of ruamel.yaml, the comment right before a top-level key is not on that key and
+    # needs to get copied separately.
+    option_config.ca.items[option_name] = config.ca.items[option_name]
+
+    return option_config
+
+
 def generate_sample_configuration(
 def generate_sample_configuration(
     dry_run,
     dry_run,
     source_filename,
     source_filename,
@@ -359,16 +378,22 @@ def generate_sample_configuration(
 
 
         os.makedirs(destination_path, exist_ok=True)
         os.makedirs(destination_path, exist_ok=True)
 
 
-        for option_name, option_config in destination_config.items():
+        for option_name in destination_config:
             write_configuration(
             write_configuration(
                 os.path.join(destination_path, f'{option_name}.yaml'),
                 os.path.join(destination_path, f'{option_name}.yaml'),
                 transform_optional_configuration(
                 transform_optional_configuration(
-                    render_configuration({option_name: option_config}),
+                    render_configuration(get_configuration_subset(destination_config, option_name)),
                     comment_out=False,
                     comment_out=False,
-                ),
+                ).strip(),
                 overwrite=overwrite,
                 overwrite=overwrite,
             )
             )
 
 
+        # Also dump a manifest listing all the options we've written.
+        json.dump(
+            {'option_names': list(destination_config.keys())},
+            open(os.path.join(destination_path, 'options.json'), 'w', encoding='utf-8'),
+        )
+
         return
         return
 
 
     if os.path.exists(destination_path) and not os.path.isfile(destination_path):
     if os.path.exists(destination_path) and not os.path.isfile(destination_path):

+ 1 - 0
docs/Dockerfile

@@ -24,6 +24,7 @@ RUN npm install @11ty/eleventy \
     markdown-it-anchor \
     markdown-it-anchor \
     markdown-it-replace-link
     markdown-it-replace-link
 COPY --from=borgmatic /etc/borgmatic/* /source/docs/_includes/borgmatic/
 COPY --from=borgmatic /etc/borgmatic/* /source/docs/_includes/borgmatic/
+COPY --from=borgmatic /etc/borgmatic/options.json /source/docs/reference/configuration/index.json
 COPY --from=borgmatic /command-line/* /source/docs/_includes/borgmatic/command-line/
 COPY --from=borgmatic /command-line/* /source/docs/_includes/borgmatic/command-line/
 COPY --from=borgmatic /contributors.html /source/docs/_includes/borgmatic/contributors.html
 COPY --from=borgmatic /contributors.html /source/docs/_includes/borgmatic/contributors.html
 COPY . /source
 COPY . /source

+ 9 - 4
docs/reference/configuration/index.md

@@ -5,10 +5,10 @@ eleventyNavigation:
   parent: Reference guides
   parent: Reference guides
   order: 0
   order: 0
 ---
 ---
-Below is a sample borgmatic configuration file including all available options
-for the [most recent version of
+Below is a sample borgmatic configuration snippet for every available option in
+the [most recent version of
 borgmatic](https://projects.torsion.org/borgmatic-collective/borgmatic/releases).
 borgmatic](https://projects.torsion.org/borgmatic-collective/borgmatic/releases).
-This file is also [available for
+A full example configuration file is also [available for
 download](https://torsion.org/borgmatic/reference/config.yaml).
 download](https://torsion.org/borgmatic/reference/config.yaml).
 
 
 If you're using an older version of borgmatic, some of these options may not
 If you're using an older version of borgmatic, some of these options may not
@@ -16,6 +16,11 @@ work, and you should instead [generate a sample configuration file specific to
 your borgmatic
 your borgmatic
 version](https://torsion.org/borgmatic/how-to/set-up-backups/#configuration).
 version](https://torsion.org/borgmatic/how-to/set-up-backups/#configuration).
 
 
+<span data-pagefind-weight="6.0">
+{% for option_name in option_names %}
+### {{ option_name }} option
 ```yaml
 ```yaml
-{% include borgmatic/config.yaml %}
+{% include borgmatic/{{ option_name }}.yaml %}
 ```
 ```
+{% endfor %}
+</span>

+ 11 - 3
tests/integration/config/test_generate.py

@@ -512,6 +512,12 @@ def test_generate_sample_configuration_with_dry_run_does_not_write_file():
 def test_generate_sample_configuration_with_split_writes_each_option_to_file():
 def test_generate_sample_configuration_with_split_writes_each_option_to_file():
     builtins = flexmock(sys.modules['builtins'])
     builtins = flexmock(sys.modules['builtins'])
     builtins.should_receive('open').with_args('schema.yaml', encoding='utf-8').and_return('')
     builtins.should_receive('open').with_args('schema.yaml', encoding='utf-8').and_return('')
+    builtins.should_receive('open').with_args(
+        'dest/options.json', 'w', encoding='utf-8'
+    ).and_return(flexmock())
+    flexmock(module.json).should_receive('dump').with_args(
+        {'option_names': ['foo', 'bar']}, object
+    ).once()
     flexmock(module.ruamel.yaml).should_receive('YAML').and_return(
     flexmock(module.ruamel.yaml).should_receive('YAML').and_return(
         flexmock(load=lambda filename: {})
         flexmock(load=lambda filename: {})
     )
     )
@@ -520,17 +526,18 @@ def test_generate_sample_configuration_with_split_writes_each_option_to_file():
         {'foo': 1, 'bar': 2}
         {'foo': 1, 'bar': 2}
     )
     )
     flexmock(module.os.path).should_receive('exists').and_return(False)
     flexmock(module.os.path).should_receive('exists').and_return(False)
+    flexmock(module).should_receive('get_configuration_subset')
     flexmock(module).should_receive('render_configuration')
     flexmock(module).should_receive('render_configuration')
-    flexmock(module).should_receive('transform_optional_configuration')
+    flexmock(module).should_receive('transform_optional_configuration').and_return(' ')
     flexmock(module.os).should_receive('makedirs')
     flexmock(module.os).should_receive('makedirs')
     flexmock(module).should_receive('write_configuration').with_args(
     flexmock(module).should_receive('write_configuration').with_args(
         'dest/foo.yaml',
         'dest/foo.yaml',
-        None,
+        '',
         overwrite=False,
         overwrite=False,
     ).once()
     ).once()
     flexmock(module).should_receive('write_configuration').with_args(
     flexmock(module).should_receive('write_configuration').with_args(
         'dest/bar.yaml',
         'dest/bar.yaml',
-        None,
+        '',
         overwrite=False,
         overwrite=False,
     ).once()
     ).once()
 
 
@@ -549,6 +556,7 @@ def test_generate_sample_configuration_with_split_and_file_destination_errors():
     )
     )
     flexmock(module.os.path).should_receive('exists').and_return(True)
     flexmock(module.os.path).should_receive('exists').and_return(True)
     flexmock(module.os.path).should_receive('isdir').and_return(False)
     flexmock(module.os.path).should_receive('isdir').and_return(False)
+    flexmock(module).should_receive('get_configuration_subset').never()
     flexmock(module).should_receive('render_configuration').never()
     flexmock(module).should_receive('render_configuration').never()
     flexmock(module).should_receive('transform_optional_configuration').never()
     flexmock(module).should_receive('transform_optional_configuration').never()
     flexmock(module.os).should_receive('makedirs').never()
     flexmock(module.os).should_receive('makedirs').never()