borg/src/borg/archiver/config_cmd.py

182 lines
7.4 KiB
Python

import argparse
import configparser
from ._common import with_repository
from ..cache import Cache, assert_secure
from ..constants import * # NOQA
from ..helpers import Error, CommandError
from ..helpers import Location
from ..helpers import parse_file_size, hex_to_bin
from ..manifest import Manifest
from ..logger import create_logger
logger = create_logger()
class ConfigMixIn:
@with_repository(exclusive=True, manifest=False)
def do_config(self, args, repository):
"""get, set, and delete values in a repository or cache config file"""
def repo_validate(section, name, value=None, check_value=True):
if section not in ["repository"]:
raise ValueError("Invalid section")
if name in ["segments_per_dir", "last_segment_checked"]:
if check_value:
try:
int(value)
except ValueError:
raise ValueError("Invalid value") from None
elif name in ["max_segment_size", "additional_free_space", "storage_quota"]:
if check_value:
try:
parse_file_size(value)
except ValueError:
raise ValueError("Invalid value") from None
if name == "storage_quota":
if parse_file_size(value) < parse_file_size("10M"):
raise ValueError("Invalid value: storage_quota < 10M")
elif name == "max_segment_size":
if parse_file_size(value) >= MAX_SEGMENT_SIZE_LIMIT:
raise ValueError("Invalid value: max_segment_size >= %d" % MAX_SEGMENT_SIZE_LIMIT)
elif name in ["append_only"]:
if check_value and value not in ["0", "1"]:
raise ValueError("Invalid value")
elif name in ["id"]:
if check_value:
hex_to_bin(value, length=32)
else:
raise ValueError("Invalid name")
def cache_validate(section, name, value=None, check_value=True):
if section not in ["cache"]:
raise ValueError("Invalid section")
if name in ["previous_location"]:
if check_value:
Location(value)
else:
raise ValueError("Invalid name")
def list_config(config):
default_values = {
"version": "1",
"segments_per_dir": str(DEFAULT_SEGMENTS_PER_DIR),
"max_segment_size": str(MAX_SEGMENT_SIZE_LIMIT),
"additional_free_space": "0",
"storage_quota": repository.storage_quota,
"append_only": repository.append_only,
}
print("[repository]")
for key in [
"version",
"segments_per_dir",
"max_segment_size",
"storage_quota",
"additional_free_space",
"append_only",
"id",
]:
value = config.get("repository", key, fallback=False)
if value is None:
value = default_values.get(key)
if value is None:
raise Error("The repository config is missing the %s key which has no default value" % key)
print(f"{key} = {value}")
for key in ["last_segment_checked"]:
value = config.get("repository", key, fallback=None)
if value is None:
continue
print(f"{key} = {value}")
if not args.list:
if args.name is None:
raise CommandError("No config key name was provided.")
try:
section, name = args.name.split(".")
except ValueError:
section = args.cache and "cache" or "repository"
name = args.name
if args.cache:
manifest = Manifest.load(repository, (Manifest.Operation.WRITE,))
assert_secure(repository, manifest, self.lock_wait)
cache = Cache(repository, manifest, lock_wait=self.lock_wait)
try:
if args.cache:
cache.cache_config.load()
config = cache.cache_config._config
save = cache.cache_config.save
validate = cache_validate
else:
config = repository.config
save = lambda: repository.save_config(repository.path, repository.config) # noqa
validate = repo_validate
if args.delete:
validate(section, name, check_value=False)
config.remove_option(section, name)
if len(config.options(section)) == 0:
config.remove_section(section)
save()
elif args.list:
list_config(config)
elif args.value:
validate(section, name, args.value)
if section not in config.sections():
config.add_section(section)
config.set(section, name, args.value)
save()
else:
try:
print(config.get(section, name))
except (configparser.NoOptionError, configparser.NoSectionError) as e:
raise Error(e)
finally:
if args.cache:
cache.close()
def build_parser_config(self, subparsers, common_parser, mid_common_parser):
from ._common import process_epilog
config_epilog = process_epilog(
"""
This command gets and sets options in a local repository or cache config file.
For security reasons, this command only works on local repositories.
To delete a config value entirely, use ``--delete``. To list the values
of the configuration file or the default values, use ``--list``. To get and existing
key, pass only the key name. To set a key, pass both the key name and
the new value. Keys can be specified in the format "section.name" or
simply "name"; the section will default to "repository" and "cache" for
the repo and cache configs, respectively.
By default, borg config manipulates the repository config file. Using ``--cache``
edits the repository cache's config file instead.
"""
)
subparser = subparsers.add_parser(
"config",
parents=[common_parser],
add_help=False,
description=self.do_config.__doc__,
epilog=config_epilog,
formatter_class=argparse.RawDescriptionHelpFormatter,
help="get and set configuration values",
)
subparser.set_defaults(func=self.do_config)
subparser.add_argument(
"-c", "--cache", dest="cache", action="store_true", help="get and set values from the repo cache"
)
group = subparser.add_mutually_exclusive_group()
group.add_argument(
"-d", "--delete", dest="delete", action="store_true", help="delete the key from the config file"
)
group.add_argument("-l", "--list", dest="list", action="store_true", help="list the configuration of the repo")
subparser.add_argument("name", metavar="NAME", nargs="?", help="name of config key")
subparser.add_argument("value", metavar="VALUE", nargs="?", help="new value for key")