[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#986411: marked as done (unblock: pristine-lfs/20210404.0-2)



Your message dated Thu, 8 Apr 2021 12:00:08 +0200
with message-id <1cf5ecda-9ecb-f41b-f52c-9d36208e78cf@debian.org>
and subject line Re: Bug#986411: unblock: pristine-lfs/20210404.0-2
has caused the Debian Bug report #986411,
regarding unblock: pristine-lfs/20210404.0-2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
986411: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=986411
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Please unblock package pristine-lfs

[ Reason ]
Not knowing that pristine-lfs is considered a key package, I made
changes upstream and uploaded a new release into Debian, fixing a few
bugs and improving the exported API to make the future integration
with git-buildpackage easier.

[ Impact ]
The direct impact in the event the unblock is not granted is low,
since the new features aren’t used yet and the bugs have been previously
worked around specifically in Debian bullseye.

On the other hand, for the outlined reasons the impact on unblocking
will also be very low.

[ Tests ]
- - There’s a test of tests running upstream on four Python releases (3.7,
  3.8, 3.9 and 3.10-rc) and in Debian on the current Python release at
  build time; these tests cover all features but test them directly in
  Python
- - The Debian package ships autopkgtests testing some of the basic
  features through the command-line interface.
- - The upstream Ci runs mypy static type checks.

[ Risks ]
The changes are not trivial but OTOH not big and covered by tests; the
overall test coverage has increased since the last upload, hence the
risks of accepting this package into bullseye should be relatively low.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

unblock pristine-lfs/20210404.0-1


-----BEGIN PGP SIGNATURE-----

iHUEARYIAB0WIQSD3NF/RLIsyDZW7aHoRGtKyMdyYQUCYGsP6AAKCRDoRGtKyMdy
Yc+rAQCsmONKT1dDAIwolvhF5uMJXtR9KiqIOyQi1DSosoJ1ZgEA+bf359mV6UDQ
+g2N6APILtvME0Agpz62ZKDz4YqI6wo=
=5H1H
-----END PGP SIGNATURE-----
diff --git a/PKG-INFO b/PKG-INFO
index 8db2f11..5b3e484 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pristine-lfs
-Version: 20210222.0
+Version: 20210404.0
 Summary: a pristine-tar replacement that works with Git LFS
 Home-page: https://salsa.debian.org/pristine-lfs-team/pristine-lfs
 Author: Andrej Shadura
diff --git a/debian/changelog b/debian/changelog
index 9804ad5..1afd619 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+pristine-lfs (20210404.0-1) unstable; urgency=medium
+
+  * New upstream release.
+
+ -- Andrej Shadura <andrew.shadura@collabora.co.uk>  Sun, 04 Apr 2021 22:15:42 +0200
+
 pristine-lfs (20210222.0-1) unstable; urgency=medium
 
   * New upstream release.
diff --git a/pristine_lfs.egg-info/PKG-INFO b/pristine_lfs.egg-info/PKG-INFO
index 8db2f11..5b3e484 100644
--- a/pristine_lfs.egg-info/PKG-INFO
+++ b/pristine_lfs.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pristine-lfs
-Version: 20210222.0
+Version: 20210404.0
 Summary: a pristine-tar replacement that works with Git LFS
 Home-page: https://salsa.debian.org/pristine-lfs-team/pristine-lfs
 Author: Andrej Shadura
diff --git a/pristine_lfs.egg-info/SOURCES.txt b/pristine_lfs.egg-info/SOURCES.txt
index 70a9467..2f79c38 100644
--- a/pristine_lfs.egg-info/SOURCES.txt
+++ b/pristine_lfs.egg-info/SOURCES.txt
@@ -6,8 +6,10 @@ pristine-lfs.rst
 setup.cfg
 setup.py
 pristine_lfs/__init__.py
+pristine_lfs/errors.py
 pristine_lfs/gitwrap.py
 pristine_lfs/gitwrap.pyi
+pristine_lfs/log.py
 pristine_lfs/main.py
 pristine_lfs/util.py
 pristine_lfs.egg-info/PKG-INFO
diff --git a/pristine_lfs.egg-info/requires.txt b/pristine_lfs.egg-info/requires.txt
index b065e88..9a19637 100644
--- a/pristine_lfs.egg-info/requires.txt
+++ b/pristine_lfs.egg-info/requires.txt
@@ -1,2 +1,2 @@
 python-debian
-sh
+sh>=1.14
diff --git a/pristine_lfs/__init__.py b/pristine_lfs/__init__.py
index 6df221a..ded6987 100644
--- a/pristine_lfs/__init__.py
+++ b/pristine_lfs/__init__.py
@@ -1,5 +1,6 @@
 from .main import (  # noqa: F401
     do_commit,
+    do_commit_files,
     do_checkout,
     do_list,
     do_import,
diff --git a/pristine_lfs/errors.py b/pristine_lfs/errors.py
new file mode 100644
index 0000000..ca1db96
--- /dev/null
+++ b/pristine_lfs/errors.py
@@ -0,0 +1,67 @@
+# pristine-lfs
+#
+# errors for pristine-lfs
+#
+# Copyright (C) 2021 Collabora Ltd
+# Copyright (C) 2021 Andrej Shadura <andrew.shadura@collabora.co.uk>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from __future__ import annotations
+
+from gettext import gettext as _
+
+from sh import ErrorReturnCode as CommandFailed  # noqa: F401
+
+
+class DifferentFilesExist(Exception):
+    files: list[str]
+
+    def __init__(self, files: list[str]):
+        self.files = files
+
+    def __str__(self):
+        return _("would overwrite files: {files}").format(files=', '.join(self.files))
+
+
+class UnsupportedHashAlgorithm(Exception):
+    algo: str
+
+    def __init__(self, algo: str):
+        self.algo = algo
+
+    def __str__(self):
+        return _("unsupported hash algorithm {algo}").format(
+            algo=self.algo,
+        )
+
+
+class GitError(Exception):
+    pass
+
+
+class GitFileNotFound(GitError):
+    filename: str
+    branch: str
+
+    def __init__(self, filename: str, branch: str):
+        self.filename = filename
+        self.branch = branch
+
+    def __str__(self):
+        return _('{filename} not found on branch {branch}').format(
+            filename=self.filename,
+            branch=self.branch,
+        )
+
+
+class GitBranchNotFound(GitError):
+    branch: str
+
+    def __init__(self, branch: str):
+        self.branch = branch
+
+    def __str__(self):
+        return _('No branch {branch} found, not even among remote branches').format(
+            branch=self.branch,
+        )
diff --git a/pristine_lfs/gitwrap.py b/pristine_lfs/gitwrap.py
index 0b0a83a..824988d 100644
--- a/pristine_lfs/gitwrap.py
+++ b/pristine_lfs/gitwrap.py
@@ -1,7 +1,7 @@
 # Wrapper for Git and Git LFS
 #
 # Copyright (C) 2021 Collabora Ltd
-# Andrej Shadura <andrew.shadura@collabora.co.uk>
+# Copyright (C) 2021 Andrej Shadura <andrew.shadura@collabora.co.uk>
 #
 # SPDX-License-Identifier: GPL-2.0-or-later
 
diff --git a/pristine_lfs/gitwrap.pyi b/pristine_lfs/gitwrap.pyi
index 200b212..c760b45 100644
--- a/pristine_lfs/gitwrap.pyi
+++ b/pristine_lfs/gitwrap.pyi
@@ -2,7 +2,7 @@
 # Extend as needed.
 #
 # Copyright (C) 2021 Collabora Ltd
-# Andrej Shadura <andrew.shadura@collabora.co.uk>
+# Copyright (C) 2021 Andrej Shadura <andrew.shadura@collabora.co.uk>
 
 from sh.contrib import git as sh_git
 
diff --git a/pristine_lfs/log.py b/pristine_lfs/log.py
new file mode 100644
index 0000000..a5b3cac
--- /dev/null
+++ b/pristine_lfs/log.py
@@ -0,0 +1,13 @@
+# pristine-lfs
+#
+# logging
+#
+# Copyright (C) 2021 Collabora Ltd
+# Copyright (C) 2021 Andrej Shadura <andrew.shadura@collabora.co.uk>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import logging
+
+
+logger = logging.getLogger("pristine-lfs")
diff --git a/pristine_lfs/main.py b/pristine_lfs/main.py
index 5cbaf66..921c312 100644
--- a/pristine_lfs/main.py
+++ b/pristine_lfs/main.py
@@ -3,7 +3,7 @@
 # store pristine tarballs in Git LFS
 #
 # Copyright (C) 2019—2021 Collabora Ltd
-# Andrej Shadura <andrew.shadura@collabora.co.uk>
+# Copyright (C) 2019—2021 Andrej Shadura <andrew.shadura@collabora.co.uk>
 #
 # SPDX-License-Identifier: GPL-2.0-or-later
 
@@ -18,6 +18,7 @@ from typing import (
     IO,
     Iterable,
     Optional,
+    Sequence,
     Union
 )
 
@@ -25,9 +26,14 @@ import sh
 from debian import deb822
 from debian.changelog import Changelog, Version
 
+from .errors import (
+    CommandFailed,
+    DifferentFilesExist,
+    GitError,
+    UnsupportedHashAlgorithm,
+)
+from .log import logger
 from .util import (
-    Abort,
-    GitFileNotFound,
     check_branch,
     checkout_lfs_file,
     checkout_package,
@@ -53,13 +59,29 @@ def do_commit(tarball: IO[bytes], branch: str, message: Optional[str] = None, fo
     commit_lfs_file(tarball, branch, message, overwrite=force_overwrite)
 
 
-def do_checkout(branch: str, tarball: Optional[str] = None, outdir: Union[str, Path] = '.', full: bool = False, **kwargs):
+def do_commit_files(tarballs: Sequence[IO[bytes]], branch: str, message: Optional[str] = None,
+                    force_overwrite: bool = False, **kwargs):
+    """
+    Commit open files to a branch using Git LFS.
+    Set force_overwrite to overwrite existing files with same names and different checksums.
+    Message may contain "%s" which gets replaced with a comma-separate list of the file committed.
+    """
+    if check_branch(branch) is None:
+        if find_remote_branches(branch):
+            track_remote_branch(branch)
+    commit_lfs_files(tarballs, branch, message, overwrite=force_overwrite)
+
+
+def do_checkout(branch: str, tarball: Optional[str] = None, outdir: Union[str, Path] = '.', full: bool = False,
+                package: Optional[str] = None, version: Union[str, Version, None] = None, **kwargs):
     """
     Check out one or multiple files.
     If tarball is non-None:
         * file name only: tarball to check out to outdir.
         * path with to file: the location where to check out to
     If tarball is None:
+        * if package and version are specified, that version
+          is checked out
         * a tarball corresponding to the latest entry in
           debian/changelog is found and checked out
 
@@ -74,10 +96,11 @@ def do_checkout(branch: str, tarball: Optional[str] = None, outdir: Union[str, P
         if path:
             outdir = path
     else:
-        changelog = Path("debian/changelog")
-        with changelog.open() as f:
-            ch = Changelog(f, max_blocks=1)
-        package, version = ch.package, ch.version
+        if not package or not version:
+            changelog = Path("debian/changelog")
+            with changelog.open() as f:
+                ch = Changelog(f, max_blocks=1)
+            package, version = ch.package, ch.version
 
     outdir = Path(outdir)
     outdir.mkdir(parents=True, exist_ok=True)
@@ -86,24 +109,24 @@ def do_checkout(branch: str, tarball: Optional[str] = None, outdir: Union[str, P
         if tarball:
             dsc_file = tarball
         else:
-            fver = Version(ch.version)
+            fver = Version(version)
             fver.epoch = None
             dsc_file = f'{package}_{fver}.dsc'
-        logging.info(_("Checking out file {} in {}").format(dsc_file, outdir))
+        logger.info(_("Checking out file {} in {}").format(dsc_file, outdir))
         checkout_lfs_file(branch, dsc_file, outdir)
         if dsc_file.endswith('.dsc'):
             with (outdir / dsc_file).open('r') as dsc:
                 d = deb822.Dsc(dsc)
-            package = d['Source']
+            package = str(d['Source'])
             version = Version(d['Version'])
             files = [f["name"] for f in d["Files"]]
             checkout_package(package, version, branch, outdir, files)
     else:
         if tarball:
-            logging.info(_("Checking out file {} in {}").format(tarball, outdir))
+            logger.info(_("Checking out file {} in {}").format(tarball, outdir))
             checkout_lfs_file(branch, tarball, outdir)
         else:
-            checkout_package(package, version, branch, outdir)
+            checkout_package(str(package), Version(version), branch, outdir)
 
 
 def do_list(branch: str, **kwargs) -> Iterable[str]:
@@ -116,7 +139,8 @@ def do_list(branch: str, **kwargs) -> Iterable[str]:
             yield f
 
 
-def do_import(dsc: IO[str], branch: str, message: Optional[str] = None, force_overwrite: bool = False, full: bool = False, **kwargs):
+def do_import(dsc: IO[str], branch: str, message: Optional[str] = None, force_overwrite: bool = False,
+              full: bool = False, **kwargs):
     """
     Import all tarballs and detached signatures related to an open .dsc file.
     Set force_overwrite to overwrite an existing file with the same name and a different checksum.
@@ -135,12 +159,13 @@ def do_import(dsc: IO[str], branch: str, message: Optional[str] = None, force_ov
         if find_remote_branches(branch):
             track_remote_branch(branch)
 
-    tarballs = [os.path.join(dsc_dir, f['name']) for f in d['Files'] if full or fnmatch(f['name'], tarball_glob) or fnmatch(f['name'], component_tarball_glob)]
+    tarballs = [os.path.join(dsc_dir, f['name']) for f in d['Files']
+                if full or fnmatch(f['name'], tarball_glob) or fnmatch(f['name'], component_tarball_glob)]
     if full:
         tarballs += [dsc.name]
 
     if tarballs:
-        logging.info("Importing: %s" % " ".join(tarballs))
+        logger.info("Importing: %s" % " ".join(tarballs))
         commit_lfs_files([open(tarball, 'rb') for tarball in tarballs], branch, message, overwrite=force_overwrite)
 
 
@@ -156,7 +181,10 @@ def do_verify(branch: str, tarball: Union[str, Path], **kwargs) -> bool:
 def main(*args):
     prog = os.path.basename(sys.argv[0])
 
-    parser = argparse.ArgumentParser(description=_('store pristine tarballs in Git LFS'), prog=prog, exit_on_error=not args)
+    parser = argparse.ArgumentParser(description=_('store pristine tarballs in Git LFS'), prog=prog)
+    if args and hasattr(parser, 'exit_on_error'):
+        parser.exit_on_error = False
+
     parser.add_argument('-v', '--verbose', action='count', help=_('be more verbose'))
     parser.add_argument('--debug', action='store_const', const=2, dest='verbose', help=_('be debuggingly verbose'))
     parser.set_defaults(verbose=0, func=lambda *x, **kw: parser.print_usage(file=sys.stderr))
@@ -173,10 +201,12 @@ def main(*args):
     # we have to do some trickery since argparse doesn’t support this syntax natively
     parser_checkout = subparsers.add_parser('checkout', help=_('checkout a tarball'))
     parser_checkout.add_argument('-b', '--branch', default='pristine-lfs', help=_('branch to store metadata on'))
-    parser_checkout.add_argument('--full', default=False, action='store_true', help=_('also check out all related files of the Debian package'))
+    parser_checkout.add_argument('--full', default=False, action='store_true',
+                                 help=_('also check out all related files of the Debian package'))
     parser_checkout.add_argument('-o', '--outdir', default='.', help=_('output directory for the tarball'))
     checkout_group = parser_checkout.add_mutually_exclusive_group(required=True)
-    checkout_group.add_argument('--auto', default=False, action='store_true', help=_('check out all tarballs required by the currently checked out Debian package'))
+    checkout_group.add_argument('--auto', default=False, action='store_true',
+                                help=_('check out all tarballs required by the currently checked out Debian package'))
     checkout_group.add_argument('tarball', nargs='?', default=None, help=_('tarball to check out'))
     parser_checkout.set_defaults(func=do_checkout)
 
@@ -187,7 +217,8 @@ def main(*args):
     parser_import = subparsers.add_parser('import-dsc', help=_('import tarballs and their signatures from a .dsc'))
     parser_import.add_argument('dsc', type=argparse.FileType('r'), help='.dsc file to use')
     parser_import.add_argument('--force-overwrite', action='store_true', help=_('overwrite already stored files'))
-    parser_import.add_argument('--full', default=False, action='store_true', help=_('also import all related files of the Debian package'))
+    parser_import.add_argument('--full', default=False, action='store_true',
+                               help=_('also import all related files of the Debian package'))
     parser_import.add_argument('-m', '--message', default=None, help=_('commit message'))
     parser_import.add_argument('-b', '--branch', default='pristine-lfs', help=_('branch to store metadata on'))
     parser_import.set_defaults(func=do_import)
@@ -211,7 +242,7 @@ def main(*args):
                 print(item)
         elif isinstance(ret, bool):
             return 0 if ret else 1
-    except sh.ErrorReturnCode as e:
+    except CommandFailed as e:
         print(_('Failed to run %s:') % e.full_cmd, file=sys.stderr)
         print(e.stderr.decode(sh.DEFAULT_ENCODING, "replace"), file=sys.stderr)
         return e.exit_code
@@ -225,6 +256,6 @@ def main(*args):
         print(file=sys.stderr)
         print(_('about: Interrupted by user'), file=sys.stderr)
         return 1
-    except (Abort, GitFileNotFound) as e:
+    except (DifferentFilesExist, GitError, UnsupportedHashAlgorithm) as e:
         print(_("abort: %s\n") % e, file=sys.stderr)
         return 1
diff --git a/pristine_lfs/util.py b/pristine_lfs/util.py
index ba7f908..48b07ef 100644
--- a/pristine_lfs/util.py
+++ b/pristine_lfs/util.py
@@ -4,14 +4,13 @@
 # This requires Git and git-lfs to be installed.
 #
 # Copyright (C) 2019—2021 Collabora Ltd
-# Andrej Shadura <andrew.shadura@collabora.co.uk>
+# Copyright (C) 2019—2021 Andrej Shadura <andrew.shadura@collabora.co.uk>
 #
 # SPDX-License-Identifier: GPL-2.0-or-later
 
 from __future__ import annotations
 
 import hashlib
-import logging
 import os
 from contextlib import contextmanager
 from fnmatch import fnmatch, fnmatchcase
@@ -22,7 +21,14 @@ from typing import IO, Any, Generator, Iterable, Mapping, Optional, Sequence, Tu
 import sh
 from debian.changelog import Version
 
+from .errors import (
+    DifferentFilesExist,
+    GitBranchNotFound,
+    GitFileNotFound,
+    UnsupportedHashAlgorithm,
+)
 from .gitwrap import git
+from .log import logger
 
 
 gitattributes = """*.tar.* filter=lfs diff=lfs merge=lfs -text
@@ -133,22 +139,6 @@ def parse_git_attributes(s: str) -> Iterable[tuple[str, Mapping[str, AttributeVa
 default_gitattributes = list(parse_git_attributes(gitattributes))
 
 
-class Abort(Exception):
-    pass
-
-
-class GitFileNotFound(Exception):
-    filename: str
-    branch: str
-
-    def __init__(self, filename: str, branch: str):
-        self.filename = filename
-        self.branch = branch
-
-    def __str__(self):
-        return _('%s not found on branch %s') % (self.filename, self.branch)
-
-
 def check_branch(name: str) -> Optional[str]:
     """
     Check a branch exists, return the hash it points at, if it does.
@@ -187,9 +177,9 @@ def find_remote_branches(name: str) -> list[tuple[str, str]]:
 
 
 def preferred_remote_branch(remote_branches: list[tuple[str, str]]) -> tuple[str, str]:
-    logging.debug("Remote branches: %r", remote_branches)
+    logger.debug("Remote branches: %r", remote_branches)
     current_remote = branch_remote(git_head())
-    logging.debug("Current remote: %r", current_remote)
+    logger.debug("Current remote: %r", current_remote)
     remote_branches = [
         (commit, ref) for (commit, ref) in remote_branches
         if current_remote and ref.startswith('refs/remotes/' + current_remote)
@@ -211,7 +201,7 @@ def find_branch(branch: str) -> str:
         if remote_branches:
             commit, branch = preferred_remote_branch(remote_branches)
         else:
-            raise Abort(_('No branch {branch} found, not even among remote branches').format(branch=branch))
+            raise GitBranchNotFound(branch)
     return branch
 
 
@@ -307,7 +297,7 @@ def commit_lfs_files(ios: Sequence[IO[bytes]], branch: str, template: str = None
             hook_path.write_text(pre_push_hook)
             hook_path.chmod(0o755)
         except IOError as e:
-            logging.warning(_('Failed to set up pre-push hook: %s') % e.strerror)
+            logger.warning(_('Failed to set up pre-push hook: %s') % e.strerror)
 
     with open_index("pristine-lfs") as index:
         # make sure we include all previously committed files
@@ -328,12 +318,12 @@ def commit_lfs_files(ios: Sequence[IO[bytes]], branch: str, template: str = None
         if check_branch(branch) is not None:
             diff = git('diff-index', '--cached', branch, index=index).strip().splitlines()
             if not diff:
-                logging.info(_("Nothing to commit"))
+                logger.info(_("Nothing to commit"))
                 return
             parsed_diff = [parse_diff_entry(d) for d in diff]
             overwritten = [d['srcname'] for d in parsed_diff if d['srchash'] != ('0' * 40) and d['srcname'] != '.gitattributes']
             if any(overwritten) and not overwrite:
-                raise Abort(_('would overwrite files: %s') % ', '.join(overwritten))
+                raise DifferentFilesExist(overwritten)
 
         if not template:
             template = "pristine-lfs data for %s"
@@ -399,7 +389,7 @@ def verify_lfs_file(branch: str, tarball: Path) -> bool:
     oid = parsed_metadata['oid']
     algo, hashsum = oid.split(':', 1)
     if algo not in supported_lfs_hashsums:
-        raise Abort(_("unsupported hash algorithm %s, cannot verify") % algo)
+        raise UnsupportedHashAlgorithm(algo)
 
     h = getattr(hashlib, algo)()
     with open(tarball, mode='rb') as f:
@@ -410,9 +400,9 @@ def verify_lfs_file(branch: str, tarball: Path) -> bool:
             h.update(chunk)
     calc_hashsum = h.hexdigest()
     if hashsum == calc_hashsum:
-        logging.info(f"{algo} hash for the tarball: {hashsum}, matches the stored one")
+        logger.info(f"{algo} hash for the tarball: {hashsum}, matches the stored one")
     else:
-        logging.warning(_("%(tarball)s does not match stored hash (expected %(stored_hash)s, got %(tarball_hash)s)") % {
+        logger.warning(_("%(tarball)s does not match stored hash (expected %(stored_hash)s, got %(tarball_hash)s)") % {
             'tarball': filename,
             'stored_hash': hashsum,
             'tarball_hash': calc_hashsum,
@@ -420,8 +410,12 @@ def verify_lfs_file(branch: str, tarball: Path) -> bool:
     return hashsum == calc_hashsum
 
 
-def checkout_package(package: str, version: Version, branch: str, outdir: Union[str, Path], requested: Optional[Sequence[str]] = None):
-    logging.info(_("Checking out files for {package} version {version} to {outdir}:").format(package=package, version=version, outdir=outdir))
+def checkout_package(package: str, version: Version, branch: str, outdir: Union[str, Path],
+                     requested: Optional[Sequence[str]] = None):
+    logger.info(_("Checking out files for {package} version {version} to {outdir}:").format(
+        package=package,
+        version=version, outdir=outdir
+    ))
     tarball_glob = f'{package}_{version.upstream_version}.orig.tar.*'
     component_tarball_glob = f'{package}_{version.upstream_version}.orig-*.tar.*'
 
@@ -433,9 +427,9 @@ def checkout_package(package: str, version: Version, branch: str, outdir: Union[
         tarballs = [f for f in files if fnmatch(f, tarball_glob) or fnmatch(f, component_tarball_glob)]
 
     for f in tarballs:
-        logging.info("         ... {}".format(f))
+        logger.info("         ... {}".format(f))
         checkout_lfs_file(branch, f, outdir)
-    logging.info(_("Done."))
+    logger.info(_("Done."))
 
 
 def parse_pointer(pointer: IO[str]) -> Iterable[tuple[str, str]]:
diff --git a/setup.cfg b/setup.cfg
index 04de573..16535af 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = pristine-lfs
-version = 20210222.0
+version = 20210404.0
 author = Andrej Shadura
 author_email = andrew.shadura@collabora.co.uk
 url = https://salsa.debian.org/pristine-lfs-team/pristine-lfs
@@ -28,7 +28,7 @@ packages = find:
 setup_requires = 
 	docutils >= 0.12
 install_requires = 
-	sh
+	sh >= 1.14
 	python-debian
 include_package_data = True
 tests_require = 
@@ -43,9 +43,11 @@ pristine_lfs = stubs/*
 
 [mypy]
 allow_redefinition = True
+junit_xml = mypy.xml
 
 [tool:pytest]
-addopts = --doctest-modules
+addopts = --doctest-modules --junit-xml=test-results.xml
+junit_family = xunit2
 doctest_optionflags = NORMALIZE_WHITESPACE
 markers = 
 	smoke
@@ -54,7 +56,7 @@ markers =
 doctests = yes
 max-line-length = 130
 exclude = .git,build,__pycache__,setup.py
-ignore = E121,E123,E126,E133,E226,E241,E242,E704,E501,E301,E261,E127,E128,W391,W503,W504
+ignore = E121,E123,E126,E133,E226,E241,E242,E704,E261,E127,E128,W503,W504
 
 [isort]
 multi_line_output = 3
@@ -64,6 +66,9 @@ line_length = 130
 reverse_relative = true
 default_section = THIRDPARTY
 
+[pylint.FORMAT]
+max-line-length = 130
+
 [egg_info]
 tag_build = 
 tag_date = 0
diff --git a/tests/test_checkout.py b/tests/test_checkout.py
index f3c289a..9582527 100644
--- a/tests/test_checkout.py
+++ b/tests/test_checkout.py
@@ -1,4 +1,5 @@
 from pristine_lfs import do_checkout
+from pristine_lfs.util import Version
 
 
 def test_pristine_lfs_simple_checkout(fake_pristine_lfs):
@@ -16,15 +17,33 @@ def test_pristine_lfs_auto_checkout(test_git_repo):
     outdir = repo / 'tmp-explicit'
 
     do_checkout('pristine-lfs', tarball=tarball.name, outdir=outdir)
-    assert len(list(outdir.glob('**'))) == 1, list(outdir.glob('**'))
+    assert len(list(outdir.glob('*'))) == 1, list(outdir.glob('*'))
     assert (outdir / tarball.name).is_file()
     assert (outdir / tarball.name).stat().st_size == size
 
     outdir = repo / 'tmp-auto'
 
     do_checkout('pristine-lfs', tarball=None, outdir=outdir)
-    assert len(list(outdir.glob('**'))) == 1, list(outdir.glob('**'))
+    assert len(list(outdir.glob('*'))) == 1, list(outdir.glob('*'))
     assert (outdir / tarball.name).is_file(), 'Extracted tarball not found'
     assert (outdir / tarball.name).stat().st_size == size, 'Extracted tarball of a wrong size'
 
+    outdir = repo / 'tmp-empty'
+
+    do_checkout('pristine-lfs', package='true', version='1', outdir=outdir)
+    assert len(list(outdir.glob('*'))) == 0, list(outdir.glob('*'))
+    assert not (outdir / tarball.name).is_file(), 'Found a tarball which should not be there'
+
+    do_checkout('pristine-lfs', package='true', version=Version('1'), outdir=outdir)
+    assert len(list(outdir.glob('*'))) == 0, list(outdir.glob('*'))
+    assert not (outdir / tarball.name).is_file(), 'Found a tarball which should not be there'
 
+    do_checkout('pristine-lfs', package='true', version='0', outdir=outdir)
+    assert len(list(outdir.glob('*'))) == 1, list(outdir.glob('*'))
+    assert (outdir / tarball.name).is_file(), 'Extracted tarball not found'
+
+    outdir = repo / 'tmp-empty-2'
+
+    do_checkout('pristine-lfs', package='true', version='0', outdir=outdir)
+    assert len(list(outdir.glob('*'))) == 1, list(outdir.glob('*'))
+    assert (outdir / tarball.name).is_file(), 'Extracted tarball not found'
diff --git a/tests/test_commit.py b/tests/test_commit.py
index c578d86..207b662 100644
--- a/tests/test_commit.py
+++ b/tests/test_commit.py
@@ -1,8 +1,10 @@
 from textwrap import dedent
 
+import pytest
 from sh.contrib import git
 
 from pristine_lfs import do_commit
+from pristine_lfs.errors import DifferentFilesExist
 
 
 def test_pristine_lfs_commit(fake_tarball):
@@ -24,3 +26,13 @@ def test_pristine_lfs_commit(fake_tarball):
 
     stored = repo / '.git' / 'lfs' / 'objects' / sha[:2] / sha[2:4] / sha
     assert stored.is_file(), 'Object has not been stored by LFS'
+
+
+def test_pristine_lfs_commit_overwrite(fake_tarball):
+    repo, tarball, size, sha = fake_tarball
+
+    do_commit(tarball.open('rb'), branch='pristine-lfs')
+    tarball.write_text('Text')
+
+    with pytest.raises(DifferentFilesExist):
+        do_commit(tarball.open('rb'), branch='pristine-lfs', message='blip %s %s %s')
diff --git a/tests/test_import_dsc.py b/tests/test_import_dsc.py
index e5e5a4c..df94fda 100644
--- a/tests/test_import_dsc.py
+++ b/tests/test_import_dsc.py
@@ -40,4 +40,3 @@ def test_pristine_lfs_import_dsc(fake_tarball):
 
     ret = list(do_list(branch='pristine-lfs-source'))
     assert ['true_0.dsc', 'true_0.orig.tar.gz'] == ret
-

--- End Message ---
--- Begin Message ---
Hi Andrej,

On 06-04-2021 15:23, Andrej Shadura wrote:
> unblock pristine-lfs/20210404.0-2

Sorry, but no, too late.

Paul

Attachment: OpenPGP_signature
Description: OpenPGP digital signature


--- End Message ---

Reply to: