From 64f6ccd17ffb53d9a71d562fdbe93b69fed39e83 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Fri, 28 May 2021 09:53:28 -0400 Subject: [PATCH] Make --exclude-from behavior consistent, at the cost of a minor incompatibility. --- docs/frontends/CLI.rst | 6 +++--- newsfragments/3716.incompat | 1 + newsfragments/3716.minor | 0 src/allmydata/scripts/cli.py | 5 ++--- src/allmydata/test/cli/test_backup.py | 20 ++++++++------------ 5 files changed, 14 insertions(+), 18 deletions(-) create mode 100644 newsfragments/3716.incompat delete mode 100644 newsfragments/3716.minor diff --git a/docs/frontends/CLI.rst b/docs/frontends/CLI.rst index 0badede98..d501b7af5 100644 --- a/docs/frontends/CLI.rst +++ b/docs/frontends/CLI.rst @@ -514,10 +514,10 @@ Command Examples the pattern will be matched against any level of the directory tree; it's still impossible to specify absolute path exclusions. -``tahoe backup --exclude-from=/path/to/filename ~ work:backups`` +``tahoe backup --exclude-from-utf-8=/path/to/filename ~ work:backups`` - ``--exclude-from`` is similar to ``--exclude``, but reads exclusion - patterns from ``/path/to/filename``, one per line. + ``--exclude-from-utf-8`` is similar to ``--exclude``, but reads exclusion + patterns from a UTF-8-encoded ``/path/to/filename``, one per line. ``tahoe backup --exclude-vcs ~ work:backups`` diff --git a/newsfragments/3716.incompat b/newsfragments/3716.incompat new file mode 100644 index 000000000..aa03eea47 --- /dev/null +++ b/newsfragments/3716.incompat @@ -0,0 +1 @@ +tahoe backup's --exclude-from has been renamed to --exclude-from-utf-8, and correspondingly requires the file to be UTF-8 encoded. \ No newline at end of file diff --git a/newsfragments/3716.minor b/newsfragments/3716.minor deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/allmydata/scripts/cli.py b/src/allmydata/scripts/cli.py index 922079c92..c58b5da41 100644 --- a/src/allmydata/scripts/cli.py +++ b/src/allmydata/scripts/cli.py @@ -357,17 +357,16 @@ class BackupOptions(FileStoreOptions): exclude = self['exclude'] exclude.add(g) - def opt_exclude_from(self, filepath): + def opt_exclude_from_utf_8(self, filepath): """Ignore file matching glob patterns listed in file, one per line. The file is assumed to be in the argv encoding.""" abs_filepath = argv_to_abspath(filepath) try: - exclude_file = open(abs_filepath, "rb") + exclude_file = open(abs_filepath, "r", encoding="utf-8") except Exception as e: raise BackupConfigurationError('Error opening exclude file %s. (Error: %s)' % ( quote_local_unicode_path(abs_filepath), e)) try: - for line in exclude_file: self.opt_exclude(line) finally: diff --git a/src/allmydata/test/cli/test_backup.py b/src/allmydata/test/cli/test_backup.py index 6ac55a9e8..dc5c3ff17 100644 --- a/src/allmydata/test/cli/test_backup.py +++ b/src/allmydata/test/cli/test_backup.py @@ -355,14 +355,14 @@ class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase): exclusion_string = "_darcs\n*py\n.svn" excl_filepath = os.path.join(basedir, 'exclusion') fileutil.write(excl_filepath, exclusion_string) - backup_options = parse(['--exclude-from', excl_filepath, 'from', 'to']) + backup_options = parse(['--exclude-from-utf-8', excl_filepath, 'from', 'to']) filtered = list(backup_options.filter_listdir(subdir_listdir)) self._check_filtering(filtered, subdir_listdir, (u'another_doc.lyx', u'CVS'), (u'.svn', u'_darcs', u'run_snake_run.py')) # test BackupConfigurationError self.failUnlessRaises(cli.BackupConfigurationError, parse, - ['--exclude-from', excl_filepath + '.no', 'from', 'to']) + ['--exclude-from-utf-8', excl_filepath + '.no', 'from', 'to']) # test that an iterator works too backup_options = parse(['--exclude', '*lyx', 'from', 'to']) @@ -373,7 +373,7 @@ class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase): def test_exclude_options_unicode(self): nice_doc = u"nice_d\u00F8c.lyx" try: - doc_pattern_arg = u"*d\u00F8c*" + doc_pattern_arg_unicode = doc_pattern_arg = u"*d\u00F8c*" if PY2: doc_pattern_arg = doc_pattern_arg.encode(get_io_encoding()) except UnicodeEncodeError: @@ -397,14 +397,10 @@ class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase): self._check_filtering(filtered, root_listdir, (u'_darcs', u'subdir'), (nice_doc, u'lib.a')) # read exclude patterns from file - exclusion_string = doc_pattern_arg + ensure_str("\nlib.?") - if PY3: - # On Python 2 this gives some garbage encoding. Also on Python 2 we - # expect exclusion string to be bytes. - exclusion_string = exclusion_string.encode(locale.getpreferredencoding(False)) + exclusion_string = (doc_pattern_arg_unicode + "\nlib.?").encode("utf-8") excl_filepath = os.path.join(basedir, 'exclusion') fileutil.write(excl_filepath, exclusion_string) - backup_options = parse(['--exclude-from', excl_filepath, 'from', 'to']) + backup_options = parse(['--exclude-from-utf-8', excl_filepath, 'from', 'to']) filtered = list(backup_options.filter_listdir(root_listdir)) self._check_filtering(filtered, root_listdir, (u'_darcs', u'subdir'), (nice_doc, u'lib.a')) @@ -427,20 +423,20 @@ class Backup(GridTestMixin, CLITestMixin, StallMixin, unittest.TestCase): ns = Namespace() ns.called = False original_open = open - def call_file(name, *args): + def call_file(name, *args, **kwargs): if name.endswith("excludes.dummy"): ns.called = True self.failUnlessEqual(name, abspath_expanduser_unicode(exclude_file)) return StringIO() else: - return original_open(name, *args) + return original_open(name, *args, **kwargs) if PY2: from allmydata.scripts import cli as module_to_patch else: import builtins as module_to_patch patcher = MonkeyPatcher((module_to_patch, 'open', call_file)) - patcher.runWithPatches(parse_options, basedir, "backup", ['--exclude-from', unicode_to_argv(exclude_file), 'from', 'to']) + patcher.runWithPatches(parse_options, basedir, "backup", ['--exclude-from-utf-8', unicode_to_argv(exclude_file), 'from', 'to']) self.failUnless(ns.called) def test_ignore_symlinks(self):