Skip to content

Commit daa41a2

Browse files
committed
Skip ensure_writable for custom removal commands (#18, #21)
1 parent 5f067bf commit daa41a2

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

rotate_backups/__init__.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# rotate-backups: Simple command line interface for backup rotation.
22
#
33
# Author: Peter Odding <peter@peterodding.com>
4-
# Last Change: August 3, 2018
4+
# Last Change: February 11, 2020
55
# URL: https://github.com/xolox/python-rotate-backups
66

77
"""
@@ -89,6 +89,9 @@
8989
filenames.
9090
"""
9191

92+
DEFAULT_REMOVAL_COMMAND = ['rm', '-fR']
93+
"""The default removal command (a list of strings)."""
94+
9295

9396
def coerce_location(value, **options):
9497
"""
@@ -348,7 +351,7 @@ def removal_command(self):
348351
349352
.. _pull request 11: https://github.com/xolox/python-rotate-backups/pull/11
350353
"""
351-
return ['rm', '-fR']
354+
return DEFAULT_REMOVAL_COMMAND
352355

353356
@required_property
354357
def rotation_scheme(self):
@@ -468,8 +471,12 @@ class together to implement backup rotation with an easy to use Python
468471
if not sorted_backups:
469472
logger.info("No backups found in %s.", location)
470473
return
471-
# Make sure the directory is writable.
472-
if not self.dry_run:
474+
# Make sure the directory is writable, but only when the default
475+
# removal command is being used (because custom removal commands
476+
# imply custom semantics that we shouldn't get in the way of, see
477+
# https://github.com/xolox/python-rotate-backups/issues/18 for
478+
# more details about one such use case).
479+
if not self.dry_run and (self.removal_command == DEFAULT_REMOVAL_COMMAND):
473480
location.ensure_writable()
474481
most_recent_backup = sorted_backups[-1]
475482
# Group the backups by the rotation frequencies.

rotate_backups/tests.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# Test suite for the `rotate-backups' Python package.
22
#
33
# Author: Peter Odding <peter@peterodding.com>
4-
# Last Change: August 3, 2018
4+
# Last Change: February 11, 2020
55
# URL: https://github.com/xolox/python-rotate-backups
66

77
"""Test suite for the `rotate-backups` package."""
88

99
# Standard library modules.
10+
import contextlib
1011
import datetime
1112
import logging
1213
import os
@@ -392,6 +393,27 @@ def test_removal_command(self):
392393
commands = program.rotate_backups(root, prepare=True)
393394
assert any(cmd.command_line[0] == 'rmdir' for cmd in commands)
394395

396+
def test_ensure_writable(self):
397+
"""Test that ensure_writable() complains when the location isn't writable."""
398+
with TemporaryDirectory(prefix='rotate-backups-', suffix='-test-suite') as root:
399+
for date in '2019-03-05', '2019-03-06':
400+
os.mkdir(os.path.join(root, date))
401+
with readonly_directory(root):
402+
program = RotateBackups(rotation_scheme=dict(monthly='always'))
403+
self.assertRaises(ValueError, program.rotate_backups, root)
404+
405+
def test_ensure_writable_optional(self):
406+
"""Test that ensure_writable() isn't called when a custom removal command is used."""
407+
with TemporaryDirectory(prefix='rotate-backups-', suffix='-test-suite') as root:
408+
for date in '2019-03-05', '2019-03-06':
409+
os.mkdir(os.path.join(root, date))
410+
with readonly_directory(root):
411+
program = RotateBackups(
412+
removal_command=['echo', 'Deleting'],
413+
rotation_scheme=dict(monthly='always'),
414+
)
415+
program.rotate_backups(root)
416+
395417
def test_filename_patterns(self):
396418
"""Test support for filename patterns in configuration files."""
397419
with TemporaryDirectory(prefix='rotate-backups-', suffix='-test-suite') as root:
@@ -424,3 +446,11 @@ def create_sample_backup_set(self, root):
424446
"""Create a sample backup set to be rotated."""
425447
for name in SAMPLE_BACKUP_SET:
426448
os.mkdir(os.path.join(root, name))
449+
450+
451+
@contextlib.contextmanager
452+
def readonly_directory(pathname):
453+
"""Context manager to temporarily make something read only."""
454+
os.chmod(pathname, 0o555)
455+
yield
456+
os.chmod(pathname, 0o775)

0 commit comments

Comments
 (0)