diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 257b077..4696cda 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,13 @@ Changelog ========= +1.3.0 (2019-04-10) +------------------ + +* Allow passing multiple directories on the CLI +* Allow glob patterns of directories on the CLI + + 1.2.1 ----- diff --git a/README.rst b/README.rst index d346825..05f23b0 100644 --- a/README.rst +++ b/README.rst @@ -17,11 +17,12 @@ Usage $ purge-old-files -h usage: purge-old-files [-h] [--debug | --quiet] [--syslog] [--dry-run] [--include PATTERN] [--exclude PATTERN] - MIN_AGE DIRECTORY + MIN_AGE [DIRECTORY [DIRECTORY ...]] positional arguments: MIN_AGE Minimum age of files - DIRECTORY Directory to be scanned + DIRECTORY Directory or glob pattern to be scanned (multiple + directories can be provided) optional arguments: -h, --help show this help message and exit diff --git a/purge_old_files/__init__.py b/purge_old_files/__init__.py index 3f262a6..19b4f1d 100644 --- a/purge_old_files/__init__.py +++ b/purge_old_files/__init__.py @@ -1 +1 @@ -__version__ = '1.2.1' +__version__ = '1.3.0' diff --git a/purge_old_files/cli.py b/purge_old_files/cli.py index 0297f8a..48ab0e7 100644 --- a/purge_old_files/cli.py +++ b/purge_old_files/cli.py @@ -1,4 +1,5 @@ from argparse import ArgumentParser, Namespace +from glob import glob import logging import logging.handlers from os import unlink, getpid @@ -46,7 +47,9 @@ def parse_arguments(argv=None): type=lambda x: filters.age(age.parse(x)), help='Minimum age of files') parser.add_argument( - 'directory', metavar='DIRECTORY', help='Directory to be scanned') + 'directories', metavar='DIRECTORY', nargs='*', + help='Directory or glob pattern to be scanned ' + '(multiple directories can be provided)') # Create a namespace and set the default log_level namespace = Namespace(log_level=logging.INFO) @@ -81,7 +84,12 @@ def main(argv=None): arguments = parse_arguments(argv) configure_logging(arguments.log_level, arguments.syslog) - files = finder.find(arguments.directory, arguments.filters) + files = [ + file_ + for pattern in arguments.directories + for directory in glob(pattern) + for file_ in finder.find(directory, arguments.filters) + ] for file_ in files: if arguments.dry_run: diff --git a/tests/helpers.py b/tests/helpers.py index 81074b6..4e9d92a 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -21,3 +21,8 @@ def make_test_files_hierarchy(tmpdir): baz = foo.mkdir('bar').join('baz') baz.write('baz') utime(str(baz), (one_year_ago, one_year_ago)) + + foobar = tmpdir.mkdir('foobar') + foobar_1 = foobar.join('1') + foobar_1.write('1') + utime(str(foobar_1), (one_month_ago, one_month_ago)) diff --git a/tests/test_cli.py b/tests/test_cli.py index 30af0ad..1ade24d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,4 +1,5 @@ from os.path import join +from glob import glob import logging import logging.handlers @@ -10,39 +11,85 @@ @pytest.mark.parametrize( - 'arguments, remaining, log_level, log_handler_class', + 'arguments, directories, expected_remaining, log_level, log_handler_class', ( ( - ['--dry-run', '10s'], ['foo/1', 'foo/2', 'foo/bar/baz'], - logging.INFO, logging.StreamHandler, + ['--dry-run', '10s'], + ['foo'], + ['foo/1', 'foo/2', 'foo/bar/baz'], + logging.INFO, + logging.StreamHandler, + ), + ( + ['-Ds', '1d'], + ['foo'], + [], + logging.DEBUG, + logging.handlers.SysLogHandler, + ), + ( + ['3M'], + ['foo'], + ['foo/1', 'foo/2'], + logging.INFO, + logging.StreamHandler, ), - (['-Ds', '1d'], [], logging.DEBUG, logging.handlers.SysLogHandler), - (['3M'], ['foo/1', 'foo/2'], logging.INFO, logging.StreamHandler), ( - ['--include', '[0-9]', '10d'], ['foo/1', 'foo/bar/baz'], - logging.INFO, logging.StreamHandler, + ['--include', '[0-9]', '10d'], + ['foo'], + ['foo/1', 'foo/bar/baz'], + logging.INFO, + logging.StreamHandler, ), ( - ['--exclude', '[0-9]', '10d'], ['foo/1', 'foo/2'], - logging.INFO, logging.StreamHandler, + ['--exclude', '[0-9]', '10d'], + ['foo'], + ['foo/1', 'foo/2'], + logging.INFO, + logging.StreamHandler, ), ( ['--include', '[0-9]', '--exclude', '2', '-q', '10d'], + ['foo'], ['foo/1', 'foo/2', 'foo/bar/baz'], - logging.WARNING, logging.StreamHandler + logging.WARNING, + logging.StreamHandler + ), + ( + ['10d'], + ['foo', 'foobar'], + ['foo/1'], + logging.INFO, + logging.StreamHandler, + ), + ( + ['10d'], + ['foo*'], + ['foo/1'], + logging.INFO, + logging.StreamHandler, ), ), ) -def test(arguments, remaining, log_level, log_handler_class, tmpdir): +def test( # pylint: disable=too-many-arguments + arguments, directories, expected_remaining, log_level, + log_handler_class, tmpdir): # Prepare the environment make_test_files_hierarchy(tmpdir) str_tmpdir = str(tmpdir) root_logger = logging.getLogger() # Call the CLI - cli.main(arguments + [str_tmpdir]) + absolute_directories = [ + join(str_tmpdir, directory) for directory in directories] + cli.main(arguments + absolute_directories) # Ensure results are consistent - assert sorted(finder.find(str_tmpdir)) == [ - finder.File(join(str_tmpdir, path)) for path in remaining] + remaining_files = sorted( + file_ + for pattern in absolute_directories + for directory in glob(pattern) + for file_ in finder.find(directory)) + assert remaining_files == [ + finder.File(join(str_tmpdir, path)) for path in expected_remaining] # Ensure verbosity control works as expected assert root_logger.level == log_level # Ensure the request log handler is used diff --git a/tests/test_finder.py b/tests/test_finder.py index 597e05f..f1eaf24 100644 --- a/tests/test_finder.py +++ b/tests/test_finder.py @@ -15,6 +15,7 @@ def test_find(tmpdir): File('%s/foo/1' % tmpdir), File('%s/foo/2' % tmpdir), File('%s/foo/bar/baz' % tmpdir), + File('%s/foobar/1' % tmpdir), ] # Test filtering based on time @@ -26,11 +27,13 @@ def test_find(tmpdir): assert sorted(find(str(tmpdir), [glob('[0-9]')])) == [ File('%s/foo/1' % tmpdir), File('%s/foo/2' % tmpdir), + File('%s/foobar/1' % tmpdir), ] # Test with a mix of filters assert find(str(tmpdir), [glob('[0-9]'), age(timedelta(days=8))]) == [ File('%s/foo/2' % tmpdir), + File('%s/foobar/1' % tmpdir), ]