From 3c140245eaf2917d56fb3b0211f15ac67397ec15 Mon Sep 17 00:00:00 2001 From: Ilya Kulakov Date: Wed, 7 Nov 2018 12:25:25 -0800 Subject: [PATCH 1/4] Fix support for repo dir names with trailing whitespaces. --- git_archive_all.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/git_archive_all.py b/git_archive_all.py index afc28aa..8f17a07 100755 --- a/git_archive_all.py +++ b/git_archive_all.py @@ -111,7 +111,7 @@ def __init__(self, prefix='', exclude=True, force_sub=False, extra=None, main_re raise ValueError("main_repo_abspath must be an absolute path") try: - main_repo_abspath = path.abspath(self.run_git_shell('git rev-parse --show-toplevel', main_repo_abspath).rstrip()) + main_repo_abspath = path.abspath(self.run_git_shell('git rev-parse --show-toplevel', main_repo_abspath)[:-1]) except CalledProcessError: raise ValueError("{0} is not part of a git repository".format(main_repo_abspath)) @@ -143,7 +143,7 @@ def create(self, output_path, dry_run=False, output_format=None, compresslevel=N if output_format is None: file_name, file_ext = path.splitext(output_path) output_format = file_ext[len(extsep):].lower() - self.LOG.debug("Output format is not explicitly set, determined format is {0}.".format(output_format)) + self.LOG.debug("Output format is not explicitly set, determined format is %s.", output_format) if not dry_run: if output_format in self.ZIPFILE_FORMATS: @@ -184,13 +184,13 @@ def add_file(file_path, arcname): raise ValueError("unknown format: {0}".format(output_format)) def archiver(file_path, arcname): - self.LOG.debug("{0} => {1}".format(file_path, arcname)) + self.LOG.debug("%s => %s", file_path, arcname) add_file(file_path, arcname) else: archive = None def archiver(file_path, arcname): - self.LOG.info("{0} => {1}".format(file_path, arcname)) + self.LOG.info("%s => %s", file_path, arcname) self.archive_all_files(archiver) From db9d41c276d889e6506d7d9af2383367babbc844 Mon Sep 17 00:00:00 2001 From: Ilya Kulakov Date: Wed, 7 Nov 2018 13:24:49 -0800 Subject: [PATCH 2/4] Add the --exclude and --ignore-uninitialized-submodules options --no-exclude -> --ignore-gitattributes --extra -> --include --include should properly recognize directories. Refs #60 --- CHANGES.rst | 11 ++ git_archive_all.py | 247 +++++++++++++++++++++++++++++++--------- test_git_archive_all.py | 95 +++++++++++++++- 3 files changed, 297 insertions(+), 56 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 9b32637..cf7ebb7 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,17 @@ CHANGES ======= +1.20.0 +------ + +- `--no-exclude` -> `--ignore-gitattributes` +- `--extra` -> `--include` +- `--include` now recognizes directories and includes their content +- New option `--exclude` allows to exclude both files and directories +- New option `--ignore-uninitialized-submodules` allows to proceed if repo has uninitialized submodules + as if their directories were excluded +- Signature of `GitArchiver.__init__` was changed. Deprecated arguments will be removed in the next release + 1.19.1 (2018-11-01) ------------------- diff --git a/git_archive_all.py b/git_archive_all.py index 8f17a07..90e4248 100755 --- a/git_archive_all.py +++ b/git_archive_all.py @@ -27,7 +27,7 @@ from __future__ import unicode_literals import logging -from os import extsep, path, readlink +from os import extsep, path, readlink, walk from subprocess import CalledProcessError, Popen, PIPE import sys import re @@ -76,7 +76,17 @@ class GitArchiver(object): LOG = logging.getLogger('GitArchiver') - def __init__(self, prefix='', exclude=True, force_sub=False, extra=None, main_repo_abspath=None): + def __init__( + self, + prefix='', + _exclude=None, # use ignore_gitattributes instead + force_submodules=None, + include=None, + main_repo_abspath=None, + exclude=None, + ignore_gitattributes=None, + ignore_uninitialized_submodules=None, + **kwargs): """ @param prefix: Prefix used to prepend all paths in the resulting archive. Extra file paths are only prefixed if they are not relative. @@ -87,39 +97,103 @@ def __init__(self, prefix='', exclude=True, force_sub=False, extra=None, main_re bar @type prefix: str - @param exclude: Determines whether archiver should follow rules specified in .gitattributes files. - @type exclude: bool + @param force_submodules: Whether submodules are initialized and updated before archiving. + Defaults to False + @type force_submodules: bool - @param force_sub: Determines whether submodules are initialized and updated before archiving. - @type force_sub: bool - - @param extra: List of extra paths to include in the resulting archive. - @type extra: list + @param include: List of extra paths to include in the resulting archive. + Relative paths are resolved against main_repo_abspath. + @type include: [str] or None @param main_repo_abspath: Absolute path to the main repository (or one of subdirectories). - If given path is path to a subdirectory (but not a submodule directory!) it will be replaced - with abspath to top-level directory of the repository. - If None, current cwd is used. - @type main_repo_abspath: str + If given path is a path to a subdirectory (but not a submodule directory!) it will be replaced + with abspath to a top-level directory of the repository. + Defaults to the current working directory. + @type main_repo_abspath: str or None + + @param exclude: List of extra paths to exclude from the resulting archive. + Relative paths are resolved against main_repo_abspath. + @type exclude: [str] or None + + @param ignore_gitattributes: Whether archiver should follow rules specified in .gitattributes files. + Defaults to False. + @type ignore_gitattributes: bool + + @param ignore_uninitialized_submodules: Whether archiver should ignore uninitialized submodules. + Defaults to False. + @type ignore_uninitialized_submodules: bool """ - if extra is None: - extra = [] + if force_submodules is None: + force_submodules = None + + if ignore_uninitialized_submodules is None: + ignore_uninitialized_submodules = False + + if include is None: + include = [] + + if exclude is None: + exclude = [] + + # Backward compatibility with 1.19- + if isinstance(exclude, bool): + self.LOG.warning("The exclude keyword argument is now reserved for files exclusion." + " Use ignore_gitattributes instead.") + ignore_gitattributes = exclude + exclude = None + + if _exclude is not None: + self.LOG.warning("The exclude positional argument is deprecated," + " use the ignore_gitattributes keyword argument instead.") + + if ignore_gitattributes is None: + ignore_gitattributes = _exclude + else: + raise TypeError("cannot set ignore_gitattributes keyword argument" + " and _exclude positional argument at the same time") + + if 'extra' in kwargs and kwargs['extra']: + self.LOG.warning("The extra keyword argument is deprecated," + " use the include keyword argument instead.") + include.extend(kwargs['extra']) + + if 'force_sub' in kwargs: + self.LOG.warning("The force_sub keyword argument is deprecated," + " use the force_submodules keyword argument instead.") + force_submodules = kwargs['force_sub'] if main_repo_abspath is None: main_repo_abspath = path.abspath('') elif not path.isabs(main_repo_abspath): raise ValueError("main_repo_abspath must be an absolute path") + def abspath(p): + return path.normpath(path.join(main_repo_abspath, p)) + + exclude = [abspath(p) for p in exclude] + self.excluded_dirs = [p + path.sep for p in exclude if path.isdir(p)] + self.excluded_files = [p for p in exclude if path.isfile(p)] + + self.included_dirs = [] + self.included_files = [] + for file_path in include: + file_abspath = abspath(file_path) + + if path.isdir(file_abspath): + self.included_dirs.append(file_abspath) + elif path.isfile(file_abspath): + self.included_files.append(file_abspath) + try: - main_repo_abspath = path.abspath(self.run_git_shell('git rev-parse --show-toplevel', main_repo_abspath)[:-1]) + self.main_repo_abspath = path.abspath(self.run_git_shell('git rev-parse --show-toplevel', main_repo_abspath)[:-1]) except CalledProcessError: raise ValueError("{0} is not part of a git repository".format(main_repo_abspath)) self.prefix = prefix - self.exclude = exclude - self.extra = extra - self.force_sub = force_sub - self.main_repo_abspath = main_repo_abspath + self.force_submodules = force_submodules + + self.ignore_gitattributes = ignore_gitattributes + self.ignore_uninitialized_submodules = ignore_uninitialized_submodules self._check_attr_gens = {} @@ -210,23 +284,55 @@ def is_file_excluded(self, repo_abspath, repo_file_path): @return: True if file should be excluded. Otherwise False. @rtype: bool """ - next(self._check_attr_gens[repo_abspath]) - attrs = self._check_attr_gens[repo_abspath].send(repo_file_path) - return attrs['export-ignore'] == 'set' + repo_file_abspath = path.join(repo_abspath, repo_file_path) + + if self.excluded_files or self.excluded_dirs: + if repo_file_abspath in self.excluded_files or repo_file_abspath in self.excluded_dirs: + self.LOG.debug("%s is excluded explicitly.", repo_file_abspath) + return True + elif self.excluded_dirs: + for d in self.excluded_dirs: + if repo_file_abspath.startswith(d): + self.LOG.debug("%s is inside explicitly excluded directory %s.", repo_file_abspath, d) + return True + + if not self.ignore_gitattributes: + next(self._check_attr_gens[repo_abspath]) + attrs = self._check_attr_gens[repo_abspath].send(repo_file_path) + + if attrs['export-ignore'] == 'set': + self.LOG.debug("%s is excluded via .gitattributes", repo_file_abspath) + return True + + return False def archive_all_files(self, archiver): """ Archive all files using archiver. @param archiver: Callable that accepts 2 arguments: - abspath to file on the system and relative path within archive. + abspath to a file in the file system and relative path within archive. @type archiver: Callable """ - for file_path in self.extra: - archiver(path.abspath(file_path), path.join(self.prefix, file_path)) + def arcpath(p): + if p.startswith(self.main_repo_abspath + path.sep): + return path.join(self.prefix, path.relpath(p, self.main_repo_abspath)) + else: + return path.join(self.prefix, p) + + for file_abspath in self.included_files: + self.LOG.debug("%s is included explicitly.", file_abspath) + archiver(file_abspath, arcpath(file_abspath)) + + for dir_abspath in self.included_dirs: + for subdir_abspath, _, filenames in walk(dir_abspath): + for file_path in filenames: + file_abspath = path.join(subdir_abspath, file_path) + self.LOG.debug("%s is inside explicitly included directory %s.", file_abspath, dir_abspath) + archiver(file_abspath, arcpath(file_abspath)) - for file_path in self.walk_git_files(): - archiver(path.join(self.main_repo_abspath, file_path), path.join(self.prefix, file_path)) + for main_repo_file_path in self.walk_git_files(): + archiver(path.join(self.main_repo_abspath, main_repo_file_path), path.join(self.prefix, main_repo_file_path)) def walk_git_files(self, repo_path=''): """ @@ -244,8 +350,10 @@ def walk_git_files(self, repo_path=''): @rtype: Iterable """ repo_abspath = path.join(self.main_repo_abspath, repo_path) - assert repo_abspath not in self._check_attr_gens - self._check_attr_gens[repo_abspath] = self.check_attr(repo_abspath, ['export-ignore']) + + if not self.ignore_gitattributes: + assert repo_abspath not in self._check_attr_gens + self._check_attr_gens[repo_abspath] = self.check_attr(repo_abspath, ['export-ignore']) try: repo_file_paths = self.run_git_shell( @@ -266,7 +374,7 @@ def walk_git_files(self, repo_path=''): yield main_repo_file_path - if self.force_sub: + if self.force_submodules: self.run_git_shell('git submodule init', repo_abspath) self.run_git_shell('git submodule update', repo_abspath) @@ -281,11 +389,18 @@ def walk_git_files(self, repo_path=''): if m: repo_submodule_path = m.group(1) # relative to repo_path - main_repo_submodule_path = path.join(repo_path, repo_submodule_path) # relative to main_repo_abspath if self.is_file_excluded(repo_abspath, repo_submodule_path): continue + main_repo_submodule_path = path.join(repo_path, repo_submodule_path) # relative to main_repo_abspath + main_repo_submodule_abspath = path.join(self.main_repo_abspath, main_repo_submodule_path) + + if not path.exists(main_repo_submodule_abspath) and self.ignore_uninitialized_submodules: + self.LOG.debug("The %s submodule does not exist, but uninitialized submodules are ignored.", + main_repo_submodule_abspath) + continue + for main_repo_submodule_file_path in self.walk_git_files(main_repo_submodule_path): repo_submodule_file_path = main_repo_submodule_file_path.replace(repo_path, "", 1).strip("/") # relative to repo_path if self.is_file_excluded(repo_abspath, repo_submodule_file_path): @@ -411,11 +526,21 @@ def main(): from optparse import OptionParser, SUPPRESS_HELP parser = OptionParser( - usage="usage: %prog [-v] [--prefix PREFIX] [--no-exclude] [--force-submodules]" - " [--extra EXTRA1 ...] [--dry-run] [-0 | ... | -9] OUTPUT_FILE", + usage="usage: %prog [-v] [--dry-run] [--prefix PREFIX] [--ignore-gitattributes] [--ignore-uninitialized-submodules] [--force-submodules]" + " [--include FILE1 [--include FILE2 ...]] [--exclude FILE1 [--exclude FILE2 ...]] [-0 | ... | -9] OUTPUT_FILE", version="%prog {0}".format(__version__) ) + parser.add_option('-v', '--verbose', + action='store_true', + dest='verbose', + help='enable verbose mode') + + parser.add_option('--dry-run', + action='store_true', + dest='dry_run', + help="don't actually archive anything, just show what would be done") + parser.add_option('--prefix', type='string', dest='prefix', @@ -424,32 +549,46 @@ def main(): OUTPUT_FILE name is used by default to avoid tarbomb. You can set it to '' in order to explicitly request tarbomb""") - parser.add_option('-v', '--verbose', + parser.add_option('--ignore-gitattributes', action='store_true', - dest='verbose', - help='enable verbose mode') + dest='ignore_gitattributes', + default=False, + help="ignore the export-ignore attribute in .gitattributes") - parser.add_option('--no-exclude', - action='store_false', - dest='exclude', - default=True, - help="don't read .gitattributes files for patterns containing export-ignore attrib") + parser.add_option('--ignore-uninitialized-submodules', + action='store_true', + dest='ignore_uninitialized_submodules', + default=False, + help="ignore uninitialized submodules instead of failing with error") parser.add_option('--force-submodules', action='store_true', - dest='force_sub', - help='force a git submodule init && git submodule update at each level before iterating submodules') + dest='force_submodules', + help="""force a git submodule init && git submodule update at + each level before iterating submodules""") - parser.add_option('--extra', + parser.add_option('--include', action='append', - dest='extra', + dest='include', default=[], help="any additional files to include in the archive") - parser.add_option('--dry-run', + parser.add_option('--exclude', + action='append', + dest='exclude', + default=[], + help="any additional files to exclude from the archive") + + parser.add_option('--no-exclude', action='store_true', - dest='dry_run', - help="don't actually archive anything, just show what would be done") + dest='ignore_gitattributes', + help=SUPPRESS_HELP) + + parser.add_option('--extra', + action='append', + dest='include', + default=[], + help=SUPPRESS_HELP) for i in range(10): parser.add_option('-{0}'.format(i), @@ -485,10 +624,12 @@ def main(): handler.setFormatter(logging.Formatter('%(message)s')) GitArchiver.LOG.addHandler(handler) GitArchiver.LOG.setLevel(logging.DEBUG if options.verbose else logging.INFO) - archiver = GitArchiver(options.prefix, - options.exclude, - options.force_sub, - options.extra) + archiver = GitArchiver(prefix=options.prefix, + ignore_gitattributes=options.ignore_gitattributes, + ignore_uninitialized_submodules=options.ignore_uninitialized_submodules, + force_submodules=options.force_submodules, + include=options.include, + exclude=options.exclude) archiver.create(output_file_path, options.dry_run, compresslevel=options.compresslevel) except Exception as e: parser.exit(2, "{0}\n".format(e)) diff --git a/test_git_archive_all.py b/test_git_archive_all.py index 9a948b8..09ab9fb 100644 --- a/test_git_archive_all.py +++ b/test_git_archive_all.py @@ -123,8 +123,8 @@ def add_submodule(self, rel_path, contents): def commit(self, message): check_call(['git', 'commit', '-m', 'init'], cwd=self.path, env=self.git_env) - def archive(self, path): - a = GitArchiver(main_repo_abspath=self.path) + def archive(self, path, include=None, exclude=None): + a = GitArchiver(main_repo_abspath=self.path, include=include, exclude=exclude) a.create(path) @@ -265,7 +265,7 @@ def archive(self, path): pytest.param(quote_base, id="Quote"), pytest.param(quote_quoted, id="Quote (Quoted)") ]) -def test_ignore(contents, tmpdir, git_env): +def test_export_ignore(contents, tmpdir, git_env): """ Ensure that GitArchiver respects export-ignore. """ @@ -313,6 +313,95 @@ def make_actual(tar_file): assert actual == expected +@pytest.mark.parametrize('name', [ + pytest.param('repo ', id='Trailing space'), +]) +def test_repo_dirs_with_trailing_whitespaces(name, tmpdir, git_env): + repo_path = os.path.join(str(tmpdir), name) + repo = Repo(repo_path, git_env) + repo.init() + repo.add_dir('.', base) + repo.commit('init') + + repo_tar_path = os.path.join(str(tmpdir), 'repo.tar') + repo.archive(repo_tar_path) + + +def test_explicitly_included_file(tmpdir, git_env): + repo_path = os.path.join(str(tmpdir), 'repo') + repo = Repo(repo_path, git_env) + repo.init() + repo.add_dir('.', base) + repo.commit('init') + + file_path = os.path.join(repo_path, 'include') + with open(file_path, 'w') as f: + f.write('Hello') + + repo_tar_path = os.path.join(str(tmpdir), 'repo.tar') + repo.archive(repo_tar_path, include=['include']) + repo_tar = TarFile(repo_tar_path, format=PAX_FORMAT, encoding='utf-8') + + repo_tar.getmember('include') + + +def test_explicitly_included_dir(tmpdir, git_env): + repo_path = os.path.join(str(tmpdir), 'repo') + repo = Repo(repo_path, git_env) + repo.init() + repo.add_dir('.', base) + repo.commit('init') + + dir_path = os.path.join(repo_path, 'include_dir') + makedirs(dir_path) + file_path = os.path.join(dir_path, 'include_file') + with open(file_path, 'w') as f: + f.write('Hello') + + repo_tar_path = os.path.join(str(tmpdir), 'repo.tar') + repo.archive(repo_tar_path, include=['include_dir']) + repo_tar = TarFile(repo_tar_path, format=PAX_FORMAT, encoding='utf-8') + + repo_tar.getmember('include_dir/include_file') + + +def test_explicitly_excluded_file(tmpdir, git_env): + repo_path = os.path.join(str(tmpdir), 'repo') + repo = Repo(repo_path, git_env) + repo.init() + repo.add_dir('.', base) + repo.commit('init') + + repo_tar_path = os.path.join(str(tmpdir), 'repo.tar') + repo.archive(repo_tar_path, exclude=['app/__init__.py']) + repo_tar = TarFile(repo_tar_path, format=PAX_FORMAT, encoding='utf-8') + + repo_tar.getmember('lib/__init__.py') + + with pytest.raises(KeyError): + repo_tar.getmember('app/__init__.py') + + +def test_explicitly_excluded_dir(tmpdir, git_env): + repo_path = os.path.join(str(tmpdir), 'repo') + repo = Repo(repo_path, git_env) + repo.init() + repo.add_dir('.', base) + repo.commit('init') + + repo_tar_path = os.path.join(str(tmpdir), 'repo.tar') + repo.archive(repo_tar_path, exclude=['lib']) + repo_tar = TarFile(repo_tar_path, format=PAX_FORMAT, encoding='utf-8') + + repo_tar.getmember('app/__init__.py') + + with pytest.raises(KeyError): + repo_tar.getmember('lib/__init__.py') + + with pytest.raises(KeyError): + repo_tar.getmember('lib/extra/__init__.py') + + def test_pycodestyle(): style = pycodestyle.StyleGuide(repeat=True, max_line_length=240) report = style.check_files(['git_archive_all.py']) From 59768b612f03736c35e39eb2623a2626dfda15cd Mon Sep 17 00:00:00 2001 From: Ilya Kulakov Date: Wed, 7 Nov 2018 15:56:35 -0800 Subject: [PATCH 3/4] Add test fixture for a base_repo. --- test_git_archive_all.py | 56 ++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/test_git_archive_all.py b/test_git_archive_all.py index 09ab9fb..c8745cc 100644 --- a/test_git_archive_all.py +++ b/test_git_archive_all.py @@ -248,6 +248,18 @@ def archive(self, path, include=None, exclude=None): '\'\".dat\'': FileRecord('Although practicality beats purity.'), }) + +@pytest.fixture +def base_repo(tmpdir, git_env): + """Basic repository for simple tests.""" + repo_path = os.path.join(str(tmpdir), 'repo') + repo = Repo(repo_path, git_env) + repo.init() + repo.add_dir('.', base) + repo.commit('init') + return repo + + @pytest.mark.parametrize('contents', [ pytest.param(base, id='No Ignore'), pytest.param(base_quoted, id='No Ignore (Quoted)'), @@ -327,53 +339,35 @@ def test_repo_dirs_with_trailing_whitespaces(name, tmpdir, git_env): repo.archive(repo_tar_path) -def test_explicitly_included_file(tmpdir, git_env): - repo_path = os.path.join(str(tmpdir), 'repo') - repo = Repo(repo_path, git_env) - repo.init() - repo.add_dir('.', base) - repo.commit('init') - - file_path = os.path.join(repo_path, 'include') +def test_explicitly_included_file(base_repo, tmpdir, git_env): + file_path = os.path.join(base_repo.path, 'include') with open(file_path, 'w') as f: f.write('Hello') repo_tar_path = os.path.join(str(tmpdir), 'repo.tar') - repo.archive(repo_tar_path, include=['include']) + base_repo.archive(repo_tar_path, include=['include']) repo_tar = TarFile(repo_tar_path, format=PAX_FORMAT, encoding='utf-8') repo_tar.getmember('include') -def test_explicitly_included_dir(tmpdir, git_env): - repo_path = os.path.join(str(tmpdir), 'repo') - repo = Repo(repo_path, git_env) - repo.init() - repo.add_dir('.', base) - repo.commit('init') - - dir_path = os.path.join(repo_path, 'include_dir') +def test_explicitly_included_dir(base_repo, tmpdir, git_env): + dir_path = os.path.join(base_repo.path, 'include_dir') makedirs(dir_path) file_path = os.path.join(dir_path, 'include_file') with open(file_path, 'w') as f: f.write('Hello') repo_tar_path = os.path.join(str(tmpdir), 'repo.tar') - repo.archive(repo_tar_path, include=['include_dir']) + base_repo.archive(repo_tar_path, include=['include_dir']) repo_tar = TarFile(repo_tar_path, format=PAX_FORMAT, encoding='utf-8') repo_tar.getmember('include_dir/include_file') -def test_explicitly_excluded_file(tmpdir, git_env): - repo_path = os.path.join(str(tmpdir), 'repo') - repo = Repo(repo_path, git_env) - repo.init() - repo.add_dir('.', base) - repo.commit('init') - +def test_explicitly_excluded_file(base_repo, tmpdir, git_env): repo_tar_path = os.path.join(str(tmpdir), 'repo.tar') - repo.archive(repo_tar_path, exclude=['app/__init__.py']) + base_repo.archive(repo_tar_path, exclude=['app/__init__.py']) repo_tar = TarFile(repo_tar_path, format=PAX_FORMAT, encoding='utf-8') repo_tar.getmember('lib/__init__.py') @@ -382,15 +376,9 @@ def test_explicitly_excluded_file(tmpdir, git_env): repo_tar.getmember('app/__init__.py') -def test_explicitly_excluded_dir(tmpdir, git_env): - repo_path = os.path.join(str(tmpdir), 'repo') - repo = Repo(repo_path, git_env) - repo.init() - repo.add_dir('.', base) - repo.commit('init') - +def test_explicitly_excluded_dir(base_repo, tmpdir, git_env): repo_tar_path = os.path.join(str(tmpdir), 'repo.tar') - repo.archive(repo_tar_path, exclude=['lib']) + base_repo.archive(repo_tar_path, exclude=['lib']) repo_tar = TarFile(repo_tar_path, format=PAX_FORMAT, encoding='utf-8') repo_tar.getmember('app/__init__.py') From 86c0e6ad06d538a7c5fb09f5ca889c1628441445 Mon Sep 17 00:00:00 2001 From: Ilya Kulakov Date: Wed, 7 Nov 2018 15:56:53 -0800 Subject: [PATCH 4/4] Add test for every supported archive format. --- test_git_archive_all.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test_git_archive_all.py b/test_git_archive_all.py index c8745cc..503d91f 100644 --- a/test_git_archive_all.py +++ b/test_git_archive_all.py @@ -390,6 +390,24 @@ def test_explicitly_excluded_dir(base_repo, tmpdir, git_env): repo_tar.getmember('lib/extra/__init__.py') +@pytest.mark.parametrize('format', [ + 'tar', + 'tar.bz2', + 'tar.gz', + pytest.param('tar.xz', marks=pytest.mark.skipif(sys.version_info < (3, 3), reason="Requires lzma")), + 'tbz2', + 'tgz', + pytest.param('txz', marks=pytest.mark.skipif(sys.version_info < (3, 3), reason="Requires lzma")), + 'zip', + 'bz2', + 'gz', + pytest.param('xz', marks=pytest.mark.skipif(sys.version_info < (3, 3), reason="Requires lzma")), +]) +def test_formats(base_repo, tmpdir, format): + repo_archive_path = os.path.join(str(tmpdir), 'repo.' + format) + base_repo.archive(repo_archive_path) + + def test_pycodestyle(): style = pycodestyle.StyleGuide(repeat=True, max_line_length=240) report = style.check_files(['git_archive_all.py'])