Compare commits

...
47 Commits
Author SHA1 Message Date
Dan Helfman 9417359da3 Fix for regression with missing verbose log entries (#177). 2019-05-16 10:50:19 -07:00
Dan Helfman 1cf0e1bd84 Support for various Borg directory environment variables (#153). 2019-05-16 10:34:52 -07:00
Dan Helfman 223f803e87 Fix formatting. 2019-05-14 13:09:36 -07:00
Dan Helfman 6cb901d083 Bump version for release. 2019-05-14 13:07:49 -07:00
Dan HelfmanandGitea 096be14230 Run tests for all installed versions of Python (#166). 2019-05-14 20:06:08 +00:00
Dan Helfman bb8b1e58e8 PR feedback: Consistency. 2019-05-14 12:19:56 -07:00
Dan Helfman 06261d8c86 Merge branch 'master' into tox-skip-missing-interpreters 2019-05-14 12:18:30 -07:00
Dan HelfmanandGitea 869cccf884 Upgrade pip to a particular version during local test and CI. 2019-05-14 19:17:30 +00:00
Dan Helfman 0defaf9cb5 Run tests for all installed versions of Python (#166). 2019-05-14 12:09:07 -07:00
Dan Helfman 60b1f9921d Don't use pip wrapper script in CI. 2019-05-14 12:01:40 -07:00
Dan Helfman f61bc91b0f Merge branch 'master' into upgrade-pip 2019-05-14 10:31:03 -07:00
Dan Helfman ed2c6053de Upgrade pip to a particular version during local test and CI. 2019-05-14 10:28:04 -07:00
Dan Helfman 2cffa8deaa Add missing ticket number to NEWS item. 2019-05-14 10:07:46 -07:00
Dan Helfman f0581271f6 Automatically sort Python imports in code. 2019-05-14 10:02:41 -07:00
Dan HelfmanandGitea 99522234ea Automatically sort Python imports in code. 2019-05-14 17:02:37 +00:00
Dan Helfman 67f2862fb1 Change paths to reflect new pip install --user documentation. 2019-05-14 10:00:50 -07:00
Luke Murphy 1c0dc3f904 Run isort over the source 2019-05-14 18:59:19 +02:00
Luke Murphy b94dbff216 Add isort configuration
Closes https://projects.torsion.org/witten/borgmatic/issues/169.
2019-05-14 18:59:19 +02:00
Dan Helfman 7388c723cd Mention tox.ini refactoring in NEWS. 2019-05-14 09:45:39 -07:00
Dan HelfmanandGitea 128be3c17d Factor out build/test configuration from tox.ini file. 2019-05-14 16:45:24 +00:00
Luke Murphy 4c30c94258 Add workaround for editable failure
See https://projects.torsion.org/witten/borgmatic/pulls/165#issuecomment-1416.
2019-05-14 13:17:15 +02:00
Luke Murphy 20b8b45aeb Remove all configuration from Tox file
This puts tool configuration in their familiar and standard
locations and simplifies the Tox configuration to just laying
out the environments and factors.

This also allows users who do not want to deal with overhead of Tox (for
whatever reasons ...) to run pytest/black/etc. and have the same
behaviour.
2019-05-14 13:17:15 +02:00
Dan Helfman 2dd899f287 Linkify build status badge. 2019-05-13 22:33:28 -07:00
Dan Helfman a13cc0ab17 More tests for colored logging. 2019-05-13 21:10:26 -07:00
Dan Helfman 620f9e64d6 A few more tests for new colored logging. 2019-05-13 20:49:20 -07:00
Dan Helfman 25c320b281 Pin pip version: cherrypick of https://projects.torsion.org/witten/borgmatic/pulls/172 2019-05-13 20:01:25 -07:00
Dan Helfman f19eec56ac Add tox pin to NEWS. 2019-05-13 17:07:20 -07:00
Dan HelfmanandGitea 7cbcff2e9b Pin tox version. 2019-05-14 00:06:07 +00:00
Dan Helfman 9f6407ada6 Mention continuous integration badge in NEWS. 2019-05-13 14:54:24 -07:00
Dan HelfmanandGitea e933ecf046 Add drone CI note and badge. 2019-05-13 21:51:00 +00:00
Luke Murphy 4010a2ed77 Add note about Drone CI to contributing docs 2019-05-13 23:43:11 +02:00
Luke Murphy 2f36096e1a Add Drone build badge 2019-05-13 23:42:11 +02:00
Luke Murphy 82ec45e375 Pin tox version
Towards more reproducible results with Tox.
2019-05-13 23:12:18 +02:00
Dan Helfman 37362150fe Color records that are logged via logger.handle() as well. 2019-05-13 13:50:32 -07:00
Dan Helfman a7ba97803f Add colored output to NEWS. 2019-05-13 19:52:54 +00:00
Dan HelfmanandGitea 31dc903877 Integrate colorama for colored output. 2019-05-13 19:50:36 +00:00
Dan Helfman 8943867433 Bump to dev version. 2019-05-13 19:07:27 +00:00
Dan Helfman d9cb110563 Document installing borgmatic with pip install --user instead of a system Python install. 2019-05-13 19:06:42 +00:00
Dan HelfmanandGitea 32113cee67 Document installing borgmatic with pip install --user instead of a system Python install. 2019-05-13 19:04:24 +00:00
Luke Murphy a621ce199a Add tests for borgmatic.logger.to_bool 2019-05-13 13:40:23 +02:00
Luke Murphy 1f524d6c87 Add borgmatic custom logger 2019-05-13 13:40:18 +02:00
Luke Murphy 0320d449ec Add documentation about colorama 2019-05-13 13:40:17 +02:00
Luke Murphy 30f007687a Add colorama to testing dependencies 2019-05-13 13:40:17 +02:00
Luke Murphy adf7856162 Add new colorama dependency 2019-05-13 13:40:17 +02:00
Luke Murphy f9dce8b2d3 Recommend user installs when upgrading 2019-05-13 13:18:59 +02:00
Luke Murphy 15cb6270ef Recommend a tox user install for developing 2019-05-13 13:18:45 +02:00
Luke Murphy ed14fdbac9 Recommend root user package install
This can do bad things to a system Python install. So, we try to
mitigate this by recommending a root user user site installation.
2019-05-13 13:18:37 +02:00
55 changed files with 387 additions and 114 deletions
+2 -1
View File
@@ -3,7 +3,8 @@ pipeline:
image: python:${PYTHON_VERSION}-alpine${ALPINE_VERSION}
pull: true
commands:
- pip install tox
- python -m pip install --upgrade pip==19.1.1
- pip install tox==3.10.0
- tox
- apk add --no-cache borgbackup
- tox -e end-to-end
+14
View File
@@ -1,3 +1,17 @@
1.3.5
* #153: Support for various Borg directory environment variables (BORG_CONFIG_DIR, BORG_CACHE_DIR,
etc.) via options in borgmatic's storage configuration.
* #177: Fix for regression with missing verbose log entries.
1.3.4
* Part of #125: Color borgmatic (but not Borg) output when using an interactive terminal.
* #166: Run tests for all installed versions of Python.
* #168: Update README with continuous integration badge.
* #169: Automatically sort Python imports in code.
* Document installing borgmatic with pip install --user instead of a system Python install.
* Get more reproducible builds by pinning the versions of pip and tox used to run tests.
* Factor out build/test configuration from tox.ini file.
1.3.3
* Add validate-borgmatic-config command, useful for validating borgmatic config generated by
configuration management or even edited by hand.
+3 -1
View File
@@ -2,9 +2,11 @@
title: borgmatic
permalink: borgmatic/index.html
---
<a href="https://build.torsion.org/witten/borgmatic" alt="build status">![Build Status](https://build.torsion.org/api/badges/witten/borgmatic/status.svg)</a>
## Overview
<img src="https://projects.torsion.org/witten/borgmatic/raw/branch/master/static/borgmatic.png" width="150px" style="float: right; padding-left: 1em;">
<img src="https://projects.torsion.org/witten/borgmatic/raw/branch/master/static/borgmatic.png" alt="borgmatic logo" width="150px" style="float: right; padding-left: 1em;">
borgmatic is a simple Python wrapper script for the
[Borg](https://www.borgbackup.org/) backup software that initiates a backup,
+2 -2
View File
@@ -3,13 +3,13 @@ import os
import subprocess
from borgmatic.borg import extract
from borgmatic.logger import get_logger
DEFAULT_CHECKS = ('repository', 'archives')
DEFAULT_PREFIX = '{hostname}-'
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def _parse_checks(consistency_config):
+2 -2
View File
@@ -5,9 +5,9 @@ import os
import tempfile
from borgmatic.borg.execute import execute_command
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def _expand_directory(directory):
+15 -11
View File
@@ -1,15 +1,19 @@
import os
OPTION_TO_ENVIRONMENT_VARIABLE = {
'borg_base_directory': 'BORG_BASE_DIR',
'borg_config_directory': 'BORG_CONFIG_DIR',
'borg_cache_directory': 'BORG_CACHE_DIR',
'borg_security_directory': 'BORG_SECURITY_DIR',
'borg_keys_directory': 'BORG_KEYS_DIR',
'encryption_passcommand': 'BORG_PASSCOMMAND',
'encryption_passphrase': 'BORG_PASSPHRASE',
'ssh_command': 'BORG_RSH',
}
def initialize(storage_config):
passcommand = storage_config.get('encryption_passcommand')
if passcommand:
os.environ['BORG_PASSCOMMAND'] = passcommand
passphrase = storage_config.get('encryption_passphrase')
if passphrase:
os.environ['BORG_PASSPHRASE'] = passphrase
ssh_command = storage_config.get('ssh_command')
if ssh_command:
os.environ['BORG_RSH'] = ssh_command
for option_name, environment_variable_name in OPTION_TO_ENVIRONMENT_VARIABLE.items():
value = storage_config.get(option_name)
if value:
os.environ[environment_variable_name] = value
+2 -2
View File
@@ -1,8 +1,8 @@
import logging
import subprocess
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def execute_command(full_command, capture_output=False):
+3 -2
View File
@@ -1,9 +1,10 @@
import logging
import sys
import subprocess
import sys
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def extract_last_archive_dry_run(repository, lock_wait=None, local_path='borg', remote_path=None):
+2 -2
View File
@@ -1,9 +1,9 @@
import logging
from borgmatic.borg.execute import execute_command
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def display_archives_info(
+2 -1
View File
@@ -1,8 +1,9 @@
import logging
import subprocess
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def initialize_repository(
+2 -2
View File
@@ -1,9 +1,9 @@
import logging
from borgmatic.borg.execute import execute_command
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def list_archives(
+2 -1
View File
@@ -1,8 +1,9 @@
import logging
import subprocess
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def _make_prune_flags(retention_config):
+18 -15
View File
@@ -1,31 +1,29 @@
from argparse import ArgumentParser
import collections
import json
import logging
import os
from subprocess import CalledProcessError
import sys
from argparse import ArgumentParser
from subprocess import CalledProcessError
import colorama
import pkg_resources
from borgmatic.borg import (
check as borg_check,
create as borg_create,
environment as borg_environment,
prune as borg_prune,
extract as borg_extract,
list as borg_list,
info as borg_info,
init as borg_init,
)
from borgmatic.borg import check as borg_check
from borgmatic.borg import create as borg_create
from borgmatic.borg import environment as borg_environment
from borgmatic.borg import extract as borg_extract
from borgmatic.borg import info as borg_info
from borgmatic.borg import init as borg_init
from borgmatic.borg import list as borg_list
from borgmatic.borg import prune as borg_prune
from borgmatic.commands import hook
from borgmatic.config import checks, collect, convert, validate
from borgmatic.logger import get_logger, should_do_markup
from borgmatic.signals import configure_signals
from borgmatic.verbosity import verbosity_to_log_level
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
LEGACY_CONFIG_PATH = '/etc/borgmatic/config'
@@ -169,6 +167,9 @@ def parse_arguments(*arguments):
action='store_true',
help='Go through the motions, but do not actually write to any repositories',
)
common_group.add_argument(
'-nc', '--no-color', dest='no_color', action='store_true', help='Disable colored output'
)
common_group.add_argument(
'-v',
'--verbosity',
@@ -472,6 +473,8 @@ def main(): # pragma: no cover
logger.critical(error)
exit_with_help_link()
colorama.init(autoreset=True, strip=not should_do_markup(args.no_color))
logging.basicConfig(level=verbosity_to_log_level(args.verbosity), format='%(message)s')
if args.version:
+1 -2
View File
@@ -1,13 +1,12 @@
from argparse import ArgumentParser
import os
import sys
import textwrap
from argparse import ArgumentParser
from ruamel import yaml
from borgmatic.config import convert, generate, legacy, validate
DEFAULT_SOURCE_CONFIG_FILENAME = '/etc/borgmatic/config'
DEFAULT_SOURCE_EXCLUDES_FILENAME = '/etc/borgmatic/excludes'
DEFAULT_DESTINATION_CONFIG_FILENAME = '/etc/borgmatic/config.yaml'
+1 -2
View File
@@ -1,9 +1,8 @@
from argparse import ArgumentParser
import sys
from argparse import ArgumentParser
from borgmatic.config import generate, validate
DEFAULT_DESTINATION_CONFIG_FILENAME = '/etc/borgmatic/config.yaml'
+2 -2
View File
@@ -1,8 +1,8 @@
import logging
import subprocess
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def execute_hook(commands, config_filename, description, dry_run):
+4 -3
View File
@@ -1,10 +1,11 @@
from argparse import ArgumentParser
import sys
import logging
import sys
from argparse import ArgumentParser
from borgmatic.config import collect, validate
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def parse_arguments(*arguments):
+4 -4
View File
@@ -64,9 +64,9 @@ def convert_legacy_parsed_config(source_config, source_excludes, schema):
return destination_config
class LegacyConfigurationNotUpgraded(FileNotFoundError):
class Legacy_configuration_not_upgraded(FileNotFoundError):
def __init__(self):
super(LegacyConfigurationNotUpgraded, self).__init__(
super(Legacy_configuration_not_upgraded, self).__init__(
'''borgmatic changed its configuration file format in version 1.1.0 from INI-style
to YAML. This better supports validation, and has a more natural way to express
lists of values. To upgrade your existing configuration, run:
@@ -83,7 +83,7 @@ instead of the old one.'''
def guard_configuration_upgraded(source_config_filename, destination_config_filenames):
'''
If legacy source configuration exists but no destination upgraded configs do, raise
LegacyConfigurationNotUpgraded.
Legacy_configuration_not_upgraded.
The idea is that we want to alert the user about upgrading their config if they haven't already.
'''
@@ -92,4 +92,4 @@ def guard_configuration_upgraded(source_config_filename, destination_config_file
)
if os.path.exists(source_config_filename) and not destination_config_exists:
raise LegacyConfigurationNotUpgraded()
raise Legacy_configuration_not_upgraded()
-1
View File
@@ -2,7 +2,6 @@ import os
from ruamel import yaml
INDENT = 4
-1
View File
@@ -1,7 +1,6 @@
from collections import OrderedDict, namedtuple
from configparser import RawConfigParser
Section_format = namedtuple('Section_format', ('name', 'options'))
Config_option = namedtuple('Config_option', ('name', 'value_type', 'required'))
+2 -2
View File
@@ -1,10 +1,10 @@
import os
import logging
import ruamel.yaml
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def load_configuration(filename):
+26
View File
@@ -168,6 +168,32 @@ map:
Command to use instead of "ssh". This can be used to specify ssh options.
Defaults to not set.
example: ssh -i /path/to/private/key
borg_base_directory:
type: scalar
desc: |
Base path used for various Borg directories. Defaults to $HOME, ~$USER, or ~.
See https://borgbackup.readthedocs.io/en/stable/usage/general.html#environment-variables for details.
example: /path/to/base
borg_config_directory:
type: scalar
desc: |
Path for Borg configuration files. Defaults to $borg_base_directory/.config/borg
example: /path/to/base/config
borg_cache_directory:
type: scalar
desc: |
Path for Borg cache files. Defaults to $borg_base_directory/.cache/borg
example: /path/to/base/cache
borg_security_directory:
type: scalar
desc: |
Path for Borg security and encryption nonce files. Defaults to $borg_base_directory/.config/borg/security
example: /path/to/base/config/security
borg_keys_directory:
type: scalar
desc: |
Path for Borg encryption key files. Defaults to $borg_base_directory/.config/borg/keys
example: /path/to/base/config/keys
umask:
type: scalar
desc: Umask to be used for borg create. Defaults to 0077.
+2 -2
View File
@@ -6,9 +6,9 @@ import pykwalify.errors
import ruamel.yaml
from borgmatic.config import load
from borgmatic.logger import get_logger
logger = logging.getLogger(__name__)
logger = get_logger(__name__)
def schema_filename():
+99
View File
@@ -0,0 +1,99 @@
import logging
import os
import sys
import colorama
def to_bool(arg):
'''
Return a boolean value based on `arg`.
'''
if arg is None or isinstance(arg, bool):
return arg
if isinstance(arg, str):
arg = arg.lower()
if arg in ('yes', 'on', '1', 'true', 1):
return True
return False
def should_do_markup(no_color):
'''
Determine if we should enable colorama marking up.
'''
if no_color:
return False
py_colors = os.environ.get('PY_COLORS', None)
if py_colors is not None:
return to_bool(py_colors)
return sys.stdout.isatty() and os.environ.get('TERM') != 'dumb'
LOG_LEVEL_TO_COLOR = {
logging.CRITICAL: colorama.Fore.RED,
logging.ERROR: colorama.Fore.RED,
logging.WARN: colorama.Fore.YELLOW,
logging.INFO: colorama.Fore.GREEN,
logging.DEBUG: colorama.Fore.CYAN,
}
class Borgmatic_logger(logging.Logger):
def critical(self, msg, *args, **kwargs):
color = LOG_LEVEL_TO_COLOR.get(logging.CRITICAL)
return super(Borgmatic_logger, self).critical(color_text(color, msg), *args, **kwargs)
def error(self, msg, *args, **kwargs):
color = LOG_LEVEL_TO_COLOR.get(logging.ERROR)
return super(Borgmatic_logger, self).error(color_text(color, msg), *args, **kwargs)
def warn(self, msg, *args, **kwargs):
color = LOG_LEVEL_TO_COLOR.get(logging.WARN)
return super(Borgmatic_logger, self).warn(color_text(color, msg), *args, **kwargs)
def info(self, msg, *args, **kwargs):
color = LOG_LEVEL_TO_COLOR.get(logging.INFO)
return super(Borgmatic_logger, self).info(color_text(color, msg), *args, **kwargs)
def debug(self, msg, *args, **kwargs):
color = LOG_LEVEL_TO_COLOR.get(logging.DEBUG)
return super(Borgmatic_logger, self).debug(color_text(color, msg), *args, **kwargs)
def handle(self, record):
color = LOG_LEVEL_TO_COLOR.get(record.levelno)
colored_record = logging.makeLogRecord(
dict(levelno=record.levelno, msg=color_text(color, record.msg))
)
return super(Borgmatic_logger, self).handle(colored_record)
def get_logger(name=None):
'''
Build a logger with the given name.
'''
logging.setLoggerClass(Borgmatic_logger)
logger = logging.getLogger(name)
return logger
def color_text(color, message):
'''
Give colored text.
'''
if not color:
return message
return '{}{}{}'.format(color, message, colorama.Style.RESET_ALL)
-1
View File
@@ -1,6 +1,5 @@
import logging
VERBOSITY_WARNING = 0
VERBOSITY_SOME = 1
VERBOSITY_LOTS = 2
+7 -1
View File
@@ -41,7 +41,7 @@ you're in the `borgmatic/` working copy, install tox, which is used for
setting up testing environments:
```bash
sudo pip3 install tox
pip3 install --user tox
```
Finally, to actually run tests, run:
@@ -91,6 +91,12 @@ formatter and [Flake8](http://flake8.pycqa.org/en/latest/) code checker, so
certain code style requirements will be enforced when running automated tests.
See the Black and Flake8 documentation for more information.
## Continuous integration
Each pull request triggers a continuous integration build which runs the test
suite. You can view these builds on
[build.torsion.org](https://build.torsion.org/witten/borgmatic), and they're
also linked from the commits list on each pull request.
## Related documentation
+17 -3
View File
@@ -7,16 +7,24 @@ To get up and running, first [install
Borg](https://borgbackup.readthedocs.io/en/latest/installation.html), at
least version 1.1.
Then, run the following command to download and install borgmatic:
Borgmatic consumes configurations in `/etc/borgmatic/` and `/etc/borgmatic.d/`
by default. Therefore, we show how to install borgmatic for the root user which
will have access permissions for these locations by default.
Run the following commands to download and install borgmatic:
```bash
sudo pip3 install --upgrade borgmatic
sudo pip3 install --user --upgrade borgmatic
```
This is a [recommended user site
installation](https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site).
You will need to ensure that `/root/.local/bin` is available on your `$PATH` so
that the borgmatic executable is available.
Note that your pip binary may have a different name than "pip3". Make sure
you're using Python 3, as borgmatic does not support Python 2.
### Other ways to install
Along with the above process, you have several other options for installing
@@ -179,6 +187,12 @@ sudo systemctl start borgmatic.timer
Feel free to modify the timer file based on how frequently you'd like
borgmatic to run.
## Colored Output
Borgmatic uses [colorama](https://pypi.org/project/colorama/) to produce
colored terminal output by default. It is disabled when a non-interactive
terminal is detected (like a cron job). Otherwise, it can be disabled by
passing `--no-color` or by setting the environment variable `PY_COLORS=False`.
## Troubleshooting
+4 -4
View File
@@ -7,7 +7,7 @@ In general, all you should need to do to upgrade borgmatic is run the
following:
```bash
sudo pip3 install --upgrade borgmatic
sudo pip3 install --user --upgrade borgmatic
```
See below about special cases.
@@ -25,14 +25,14 @@ already running borgmatic with Python 3, then you can upgrade borgmatic
in-place:
```bash
sudo pip3 install --upgrade borgmatic
sudo pip3 install --user --upgrade borgmatic
```
But if you were running borgmatic with Python 2, uninstall and reinstall instead:
```bash
sudo pip uninstall borgmatic
sudo pip3 install borgmatic
sudo pip3 install --user borgmatic
```
The pip binary names for different versions of Python can differ, so the above
@@ -67,7 +67,7 @@ from atticmatic to borgmatic by running the following commands:
```bash
sudo pip3 uninstall atticmatic
sudo pip3 install borgmatic
sudo pip3 install --user borgmatic
```
That's it! borgmatic will continue using your /etc/borgmatic configuration
+3
View File
@@ -0,0 +1,3 @@
[tool.black]
line-length = 100
skip-string-normalization = true
+1 -1
View File
@@ -1,3 +1,3 @@
# You can drop this file into /etc/cron.d/ to run borgmatic nightly.
0 3 * * * PATH=$PATH:/usr/bin /usr/bin/borgmatic
0 3 * * * PATH=$PATH:/usr/bin /root/.local/bin/borgmatic
+1 -1
View File
@@ -1,3 +1,3 @@
# You can drop this file into /etc/cron.d/ to run borgmatic nightly.
0 3 * * * root PATH=$PATH:/usr/local/bin /usr/local/bin/borgmatic
0 3 * * * root PATH=$PATH:/usr/local/bin /root/.local/bin/borgmatic
+1 -1
View File
@@ -3,4 +3,4 @@ Description=borgmatic backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/borgmatic
ExecStart=/root/.local/bin/borgmatic
-7
View File
@@ -1,7 +0,0 @@
#!/usr/bin/env sh
if which black; then
black --skip-string-normalization --line-length 100 --check .
else
echo "Skipping black due to not being installed."
fi
Executable
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env sh
# Temporary work around for https://github.com/pypa/pip/issues/6434
python -m pip install --upgrade pip==19.1.1
python -m pip install --no-use-pep517 $*
+16
View File
@@ -1,2 +1,18 @@
[metadata]
description-file=README.md
[tool:pytest]
testpaths = tests
addopts = --cov-report term-missing:skip-covered --cov=borgmatic --ignore=tests/end-to-end
[flake8]
ignore = E501,W503
exclude = *.*/*
[tool:isort]
force_single_line = False
include_trailing_comma = True
known_first_party = borgmatic
line_length = 100
multi_line_output = 3
skip = .tox
+8 -4
View File
@@ -1,7 +1,6 @@
from setuptools import setup, find_packages
from setuptools import find_packages, setup
VERSION = '1.3.3'
VERSION = '1.3.5'
setup(
@@ -30,6 +29,11 @@ setup(
]
},
obsoletes=['atticmatic'],
install_requires=('pykwalify>=1.6.0,<14.06', 'ruamel.yaml>0.15.0,<0.16.0', 'setuptools'),
install_requires=(
'pykwalify>=1.6.0,<14.06',
'ruamel.yaml>0.15.0,<0.16.0',
'setuptools',
'colorama>=0.4.1,<0.5',
),
include_package_data=True,
)
+2
View File
@@ -3,10 +3,12 @@ atomicwrites==1.2.1
attrs==18.2.0
black==18.9b0; python_version >= '3.6'
Click==7.0
colorama==0.4.1
coverage==4.5.1
docopt==0.6.2
flake8==3.5.0
flexmock==0.10.2
isort==4.3.19
mccabe==0.6.1
more-itertools==4.3.0
pluggy==0.7.1
+1 -1
View File
@@ -1,7 +1,7 @@
import subprocess
from flexmock import flexmock
import pytest
from flexmock import flexmock
from borgmatic.commands import borgmatic as module
@@ -1,7 +1,7 @@
import os
from flexmock import flexmock
import pytest
from flexmock import flexmock
from borgmatic.commands import convert_config as module
+2 -2
View File
@@ -1,9 +1,9 @@
from io import StringIO
import os
import sys
from io import StringIO
from flexmock import flexmock
import pytest
from flexmock import flexmock
from borgmatic.config import generate as module
+2 -3
View File
@@ -1,7 +1,6 @@
from io import StringIO
from collections import OrderedDict
import string
from collections import OrderedDict
from io import StringIO
from borgmatic.config import legacy as module
+1 -1
View File
@@ -2,8 +2,8 @@ import io
import string
import sys
from flexmock import flexmock
import pytest
from flexmock import flexmock
from borgmatic.config import validate as module
+3 -2
View File
@@ -1,11 +1,12 @@
from subprocess import STDOUT
import logging
import sys
from subprocess import STDOUT
from flexmock import flexmock
import pytest
from flexmock import flexmock
from borgmatic.borg import check as module
from ..test_verbosity import insert_logging_mock
+1
View File
@@ -3,6 +3,7 @@ import logging
from flexmock import flexmock
from borgmatic.borg import create as module
from ..test_verbosity import insert_logging_mock
+2 -3
View File
@@ -42,8 +42,7 @@ def test_initialize_without_configuration_should_not_set_environment():
try:
os.environ = {}
module.initialize({})
assert os.environ.get('BORG_PASSCOMMAND') is None
assert os.environ.get('BORG_PASSPHRASE') is None
assert os.environ.get('BORG_RSH') is None
assert sum(1 for key in os.environ.keys() if key.startswith('BORG_')) == 0
finally:
os.environ = orig_environ
+1
View File
@@ -1,4 +1,5 @@
from flexmock import flexmock
from borgmatic.borg import execute as module
+1
View File
@@ -4,6 +4,7 @@ import sys
from flexmock import flexmock
from borgmatic.borg import extract as module
from ..test_verbosity import insert_logging_mock
+1 -1
View File
@@ -3,8 +3,8 @@ import logging
from flexmock import flexmock
from borgmatic.borg import info as module
from ..test_verbosity import insert_logging_mock
from ..test_verbosity import insert_logging_mock
INFO_COMMAND = ('borg', 'info', 'repo')
+1 -1
View File
@@ -3,8 +3,8 @@ import logging
from flexmock import flexmock
from borgmatic.borg import init as module
from ..test_verbosity import insert_logging_mock
from ..test_verbosity import insert_logging_mock
INFO_REPOSITORY_EXISTS_RESPONSE_CODE = 0
INFO_REPOSITORY_NOT_FOUND_RESPONSE_CODE = 2
+1 -1
View File
@@ -3,8 +3,8 @@ import logging
from flexmock import flexmock
from borgmatic.borg import list as module
from ..test_verbosity import insert_logging_mock
from ..test_verbosity import insert_logging_mock
LIST_COMMAND = ('borg', 'list', 'repo')
+1
View File
@@ -4,6 +4,7 @@ from collections import OrderedDict
from flexmock import flexmock
from borgmatic.borg import prune as module
from ..test_verbosity import insert_logging_mock
+3 -4
View File
@@ -1,12 +1,11 @@
from collections import defaultdict, OrderedDict, namedtuple
import os
from collections import OrderedDict, defaultdict, namedtuple
from flexmock import flexmock
import pytest
from flexmock import flexmock
from borgmatic.config import convert as module
Parsed_config = namedtuple('Parsed_config', ('location', 'storage', 'retention', 'consistency'))
@@ -91,7 +90,7 @@ def test_guard_configuration_upgraded_raises_when_only_source_config_present():
flexmock(os.path).should_receive('exists').with_args('config.yaml').and_return(False)
flexmock(os.path).should_receive('exists').with_args('other.yaml').and_return(False)
with pytest.raises(module.LegacyConfigurationNotUpgraded):
with pytest.raises(module.Legacy_configuration_not_upgraded):
module.guard_configuration_upgraded('config', ('config.yaml', 'other.yaml'))
+1 -1
View File
@@ -1,7 +1,7 @@
from collections import OrderedDict
from flexmock import flexmock
import pytest
from flexmock import flexmock
from borgmatic.config import legacy as module
+74
View File
@@ -0,0 +1,74 @@
import pytest
from flexmock import flexmock
from borgmatic import logger as module
@pytest.mark.parametrize('bool_val', (True, 'yes', 'on', '1', 'true', 'True', 1))
def test_to_bool_parses_true_values(bool_val):
assert module.to_bool(bool_val)
@pytest.mark.parametrize('bool_val', (False, 'no', 'off', '0', 'false', 'False', 0))
def test_to_bool_parses_false_values(bool_val):
assert not module.to_bool(bool_val)
def test_to_bool_passes_none_through():
assert module.to_bool(None) is None
def test_should_do_markup_respects_no_color_value():
assert module.should_do_markup(no_color=True) is False
def test_should_do_markup_respects_PY_COLORS_environment_variable():
flexmock(module.os.environ).should_receive('get').and_return('True')
flexmock(module).should_receive('to_bool').and_return(True)
assert module.should_do_markup(no_color=False) is True
def test_should_do_markup_prefers_no_color_value_to_PY_COLORS():
flexmock(module.os.environ).should_receive('get').and_return('True')
flexmock(module).should_receive('to_bool').and_return(True)
assert module.should_do_markup(no_color=True) is False
def test_should_do_markup_respects_stdout_tty_value():
flexmock(module.os.environ).should_receive('get').and_return(None)
assert module.should_do_markup(no_color=False) is False
def test_should_do_markup_prefers_PY_COLORS_to_stdout_tty_value():
flexmock(module.os.environ).should_receive('get').and_return('True')
flexmock(module).should_receive('to_bool').and_return(True)
assert module.should_do_markup(no_color=False) is True
@pytest.mark.parametrize('method_name', ('critical', 'error', 'warn', 'info', 'debug'))
def test_borgmatic_logger_log_method_does_not_raise(method_name):
flexmock(module).should_receive('color_text')
flexmock(module.logging.Logger).should_receive(method_name)
getattr(module.Borgmatic_logger('test'), method_name)(msg='hi')
def test_borgmatic_logger_handle_does_not_raise():
flexmock(module).should_receive('color_text')
flexmock(module.logging.Logger).should_receive('handle')
module.Borgmatic_logger('test').handle(
module.logging.makeLogRecord(dict(levelno=module.logging.CRITICAL, msg='hi'))
)
def test_color_text_does_not_raise():
module.color_text(module.colorama.Fore.RED, 'hi')
def test_color_text_without_color_does_not_raise():
module.color_text(None, 'hi')
+14 -9
View File
@@ -1,27 +1,32 @@
[tox]
envlist = py3
envlist = py35,py36,py37
skip_missing_interpreters = True
skipsdist = True
minversion = 3.10.0
[testenv]
usedevelop = True
deps = -rtest_requirements.txt
whitelist_externals = sh
install_command =
sh scripts/pip {opts} {packages}
commands =
py.test --cov-report term-missing:skip-covered --cov=borgmatic --ignore=tests/end-to-end \
tests []
sh scripts/black
pytest
py36,py37: black --check .
isort --recursive --check-only --settings-path setup.cfg .
flake8 .
[testenv:black]
basepython = python3.7
commands =
black --skip-string-normalization --line-length 100 .
black .
[testenv:end-to-end]
deps = -rtest_requirements.txt
commands =
py.test tests/end-to-end []
pytest tests/end-to-end
[flake8]
ignore = E501,W503
exclude = *.*/*
[testenv:isort]
deps = {[testenv]deps}
commands =
isort {posargs:--recursive} --settings-path setup.cfg .