diff --git a/CHANGES.rst b/CHANGES.rst index f2c0738..34d40c5 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,11 @@ CHANGES ======= +1.18.1 (2018-09-01) +------------------- + +- Improve support for special characters + 1.18.0 (2018-08-14) ------------------- diff --git a/git_archive_all.py b/git_archive_all.py index 4b8f3f1..8fd464f 100755 --- a/git_archive_all.py +++ b/git_archive_all.py @@ -34,7 +34,24 @@ from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED import re -__version__ = "1.18.0" +__version__ = "1.18.1" + + +try: + # Python 3.3+ + from shlex import quote +except ImportError: + _find_unsafe = re.compile(r'[^a-zA-Z0-9_@%+=:,./-]').search + + def quote(s): + """Return a shell-escaped version of the string *s*.""" + if not s: + return "''" + + if _find_unsafe(s) is None: + return s + + return "'" + s.replace("'", "'\"'\"'") + "'" class GitArchiver(object): @@ -173,8 +190,9 @@ def is_file_excluded(self, repo_abspath, repo_file_path): @return: True if file should be excluded. Otherwise False. @rtype: bool """ + print(repo_file_path) out = self.run_git_shell( - 'git check-attr -z export-ignore -- %s' % repo_file_path, + 'git check-attr -z export-ignore -- %s' % quote(repo_file_path), cwd=repo_abspath ).split('\0') diff --git a/test_git_archive_all.py b/test_git_archive_all.py index 16d8d18..9a948b8 100644 --- a/test_git_archive_all.py +++ b/test_git_archive_all.py @@ -199,6 +199,54 @@ def archive(self, path): '\'привет мир.dat\'': FileRecord('Although practicality beats purity.') }) +brackets_base = deepcopy(base) +brackets_base['data'] = DirRecord({ + '[.dat': FileRecord('Special cases aren\'t special enough to break the rules.'), + '(.dat': FileRecord('Although practicality beats purity.'), + '{.dat': FileRecord('Errors should never pass silently.'), + '].dat': FileRecord('Unless explicitly silenced.'), + ').dat': FileRecord('In the face of ambiguity, refuse the temptation to guess.'), + '}.dat': FileRecord('There should be one-- and preferably only one --obvious way to do it.'), + '[].dat': FileRecord('Although that way may not be obvious at first unless you\'re Dutch.'), + '().dat': FileRecord('Now is better than never.'), + '{}.dat': FileRecord('Although never is often better than *right* now.'), +}) + +brackets_quoted = deepcopy(base) +brackets_quoted['data'] = DirRecord({ + '\"[.dat\"': FileRecord('Special cases aren\'t special enough to break the rules.'), + '\'[.dat\'': FileRecord('Special cases aren\'t special enough to break the rules.'), + '\"(.dat\"': FileRecord('Although practicality beats purity.'), + '\'(.dat\'': FileRecord('Although practicality beats purity.'), + '\"{.dat\"': FileRecord('Errors should never pass silently.'), + '\'{.dat\'': FileRecord('Errors should never pass silently.'), + '\"].dat\"': FileRecord('Unless explicitly silenced.'), + '\'].dat\'': FileRecord('Unless explicitly silenced.'), + '\").dat\"': FileRecord('In the face of ambiguity, refuse the temptation to guess.'), + '\').dat\'': FileRecord('In the face of ambiguity, refuse the temptation to guess.'), + '\"}.dat\"': FileRecord('There should be one-- and preferably only one --obvious way to do it.'), + '\'}.dat\'': FileRecord('There should be one-- and preferably only one --obvious way to do it.'), + '\"[].dat\"': FileRecord('Although that way may not be obvious at first unless you\'re Dutch.'), + '\'[].dat\'': FileRecord('Although that way may not be obvious at first unless you\'re Dutch.'), + '\"().dat\"': FileRecord('Now is better than never.'), + '\'().dat\'': FileRecord('Now is better than never.'), + '\"{}.dat\"': FileRecord('Although never is often better than *right* now.'), + '\'{}.dat\'': FileRecord('Although never is often better than *right* now.'), +}) + +quote_base = deepcopy(base) +quote_base['data'] = DirRecord({ + '\'.dat': FileRecord('Special cases aren\'t special enough to break the rules.'), + '\".dat': FileRecord('Although practicality beats purity.'), +}) + +quote_quoted = deepcopy(base) +quote_quoted['data'] = DirRecord({ + '\"\'.dat\"': FileRecord('Special cases aren\'t special enough to break the rules.'), + '\'\'.dat\'': FileRecord('Special cases aren\'t special enough to break the rules.'), + '\"\".dat\"': FileRecord('Although practicality beats purity.'), + '\'\".dat\'': FileRecord('Although practicality beats purity.'), +}) @pytest.mark.parametrize('contents', [ pytest.param(base, id='No Ignore'), @@ -211,7 +259,11 @@ def archive(self, path): pytest.param(ignore_in_nested_submodule_from_submodule, id='Ignore in Nested Submodule from Submodule'), pytest.param(unset_export_ignore, id='-export-ignore'), pytest.param(unicode_base, id='No Ignore (Unicode)'), - pytest.param(unicode_quoted, id='No Ignore (Quoted Unicode)') + pytest.param(unicode_quoted, id='No Ignore (Quoted Unicode)'), + pytest.param(brackets_base, id='Brackets'), + pytest.param(brackets_quoted, id="Brackets (Quoted)"), + pytest.param(quote_base, id="Quote"), + pytest.param(quote_quoted, id="Quote (Quoted)") ]) def test_ignore(contents, tmpdir, git_env): """