mirror of
https://github.com/borgbackup/borg.git
synced 2026-04-27 09:07:31 -04:00
add support for yaml config files, default config
This commit is contained in:
parent
2f778b974b
commit
63a45c6c21
8 changed files with 103 additions and 5 deletions
58
docs/usage/general/config.rst.inc
Normal file
58
docs/usage/general/config.rst.inc
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
Configuration files
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Borg supports reading options from YAML configuration files. This is
|
||||
implemented via `jsonargparse <https://jsonargparse.readthedocs.io/>`_
|
||||
and works for all options that can also be set on the command line.
|
||||
|
||||
Default configuration file
|
||||
``$BORG_CONFIG_DIR/default.yaml`` is loaded automatically on every Borg
|
||||
invocation if it exists. You do not need to pass ``--config`` explicitly
|
||||
for this file.
|
||||
|
||||
``--config PATH``
|
||||
Load additional options from the YAML file at *PATH*.
|
||||
Options in this file take precedence over the default config file but are
|
||||
overridden by explicit command-line arguments. This option can be used
|
||||
multiple times, with later files overriding earlier ones.
|
||||
|
||||
``--print_config``
|
||||
Print the current effective configuration (all options in YAML format) to
|
||||
stdout and exit. This reflects the merged result of the default config
|
||||
file, any ``--config`` file, environment variables, and command-line
|
||||
arguments given before ``--print_config``. The output can be used as a
|
||||
starting point for a config file.
|
||||
|
||||
File format
|
||||
Config files are YAML documents. Top-level keys are option names
|
||||
(without leading ``--`` and with ``-`` replaced by ``_``).
|
||||
Nested keys correspond to subcommands.
|
||||
|
||||
Example ``default.yaml``::
|
||||
|
||||
# apply to all borg commands:
|
||||
log_level: info
|
||||
show_rc: true
|
||||
|
||||
# options specific to "borg create":
|
||||
create:
|
||||
compression: zstd,3
|
||||
stats: true
|
||||
|
||||
The top-level keys set options that are common to all commands (equivalent
|
||||
to placing them before the subcommand on the command line). Keys nested
|
||||
under a subcommand name (e.g. ``create:``) are only applied when that
|
||||
subcommand is invoked.
|
||||
|
||||
Precedence (lowest to highest)
|
||||
1. Default config file (``$BORG_CONFIG_DIR/default.yaml``)
|
||||
2. ``--config`` file(s) (in the order given)
|
||||
3. Environment variables (e.g. ``BORG_REPO``)
|
||||
4. Command-line arguments
|
||||
|
||||
.. note::
|
||||
``--print_config`` shows the merged effective configuration and is a
|
||||
convenient way to check what values Borg will actually use, and to
|
||||
generate contents for your borg config file(s)::
|
||||
|
||||
borg --repo /backup/main create --compression zstd,3 --print_config
|
||||
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
.. include:: general/return-codes.rst.inc
|
||||
|
||||
.. _config:
|
||||
|
||||
.. include:: general/config.rst.inc
|
||||
|
||||
.. _env_vars:
|
||||
|
||||
.. include:: general/environment.rst.inc
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ dependencies = [
|
|||
"backports-zstd; python_version < '3.14'", # for python < 3.14.
|
||||
"xxhash>=2.0.0",
|
||||
"jsonargparse @ git+https://github.com/omni-us/jsonargparse.git@main",
|
||||
"PyYAML>=6.0.2", # we need to register our types with yaml, jsonargparse uses yaml for config files
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
|
@ -260,7 +261,7 @@ deps = ["ruff"]
|
|||
commands = [["ruff", "check", "."]]
|
||||
|
||||
[tool.tox.env.mypy]
|
||||
deps = ["pytest", "mypy", "pkgconfig"]
|
||||
deps = ["pytest", "mypy", "pkgconfig", "types-PyYAML"]
|
||||
commands = [["mypy", "--ignore-missing-imports"]]
|
||||
|
||||
[tool.tox.env.docs]
|
||||
|
|
|
|||
|
|
@ -14,3 +14,4 @@ pytest-cov==7.0.0
|
|||
pytest-benchmark==5.2.3
|
||||
Cython==3.2.4
|
||||
pre-commit==4.5.1
|
||||
types-PyYAML==6.0.12.20250915
|
||||
|
|
|
|||
|
|
@ -15,3 +15,4 @@ pytest-benchmark
|
|||
Cython
|
||||
pre-commit
|
||||
bandit[toml]
|
||||
types-PyYAML
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ try:
|
|||
from ..helpers import ErrorIgnoringTextIOWrapper
|
||||
from ..helpers import msgpack
|
||||
from ..helpers import sig_int
|
||||
from ..helpers import get_config_dir
|
||||
from ..remote import RemoteRepository
|
||||
from ..selftest import selftest
|
||||
except BaseException:
|
||||
|
|
@ -246,7 +247,12 @@ class Archiver(
|
|||
def build_parser(self):
|
||||
from ._common import define_common_options
|
||||
|
||||
parser = ArgumentParser(prog=self.prog, description="Borg - Deduplicated Backups")
|
||||
parser = ArgumentParser(
|
||||
prog=self.prog,
|
||||
description="Borg - Deduplicated Backups",
|
||||
default_config_files=[os.path.join(get_config_dir(), "default.yaml")],
|
||||
)
|
||||
parser.add_argument("--config", action="config")
|
||||
# paths and patterns must have an empty list as default everywhere
|
||||
parser.common_options = self.CommonOptions(define_common_options)
|
||||
parser.add_argument(
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ from typing import Any
|
|||
from argparse import Action, ArgumentError, ArgumentTypeError, RawDescriptionHelpFormatter # noqa: F401
|
||||
from jsonargparse import ArgumentParser as _ArgumentParser # we subclass that to add custom behavior
|
||||
from jsonargparse import Namespace, SUPPRESS, REMAINDER # noqa: F401
|
||||
from jsonargparse.typing import register_type # noqa: F401
|
||||
|
||||
# borg completion uses these private symbols, so we need to import them:
|
||||
from jsonargparse._actions import _ActionSubCommands # noqa: F401
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@ from ..logger import create_logger
|
|||
|
||||
logger = create_logger()
|
||||
|
||||
import yaml
|
||||
|
||||
from .errors import Error
|
||||
from .fs import get_keys_dir, make_path_safe, slashify
|
||||
from .argparsing import Action, ArgumentError, ArgumentTypeError
|
||||
from .argparsing import Action, ArgumentError, ArgumentTypeError, register_type
|
||||
from .msgpack import Timestamp
|
||||
from .time import OutputTimestamp, format_time, safe_timestamp
|
||||
from .. import __version__ as borg_version
|
||||
|
|
@ -236,10 +238,22 @@ class CompressionSpec:
|
|||
elif self.name == "obfuscate":
|
||||
return get_compressor(self.name, level=self.level, compressor=self.inner.compressor)
|
||||
|
||||
def __str__(self):
|
||||
if self.name in ("none", "lz4"):
|
||||
return f"{self.name}"
|
||||
elif self.name in ("zlib", "lzma", "zstd", "zlib_legacy"):
|
||||
return f"{self.name},{self.level}"
|
||||
elif self.name == "auto":
|
||||
return f"auto,{self.inner}"
|
||||
elif self.name == "obfuscate":
|
||||
return f"obfuscate,{self.level},{self.inner}"
|
||||
else:
|
||||
raise ValueError(f"unsupported compression type: {self.name}")
|
||||
|
||||
|
||||
def ChunkerParams(s):
|
||||
if isinstance(s, tuple):
|
||||
return s
|
||||
if isinstance(s, (list, tuple)):
|
||||
return tuple(s)
|
||||
params = s.strip().split(",")
|
||||
count = len(params)
|
||||
if count == 0:
|
||||
|
|
@ -714,6 +728,18 @@ def location_validator(proto=None, other=False):
|
|||
return validator
|
||||
|
||||
|
||||
# Register types with jsonargparse so they can be represented in config files
|
||||
# (e.g. for --print_config). Two things are needed:
|
||||
# 1. A YAML representer so yaml.safe_dump can serialize Location objects to strings.
|
||||
# 2. A jsonargparse register_type so it knows how to deserialize strings back to Location.
|
||||
|
||||
yaml.SafeDumper.add_representer(Location, lambda dumper, loc: dumper.represent_str(loc.raw or ""))
|
||||
register_type(Location, serializer=lambda loc: loc.raw or "")
|
||||
|
||||
yaml.SafeDumper.add_representer(CompressionSpec, lambda dumper, cs: dumper.represent_str(str(cs)))
|
||||
register_type(CompressionSpec)
|
||||
|
||||
|
||||
def relative_time_marker_validator(text: str):
|
||||
time_marker_regex = r"^\d+[ymwdHMS]$"
|
||||
match = re.compile(time_marker_regex).search(text)
|
||||
|
|
|
|||
Loading…
Reference in a new issue