[game-data-packager] 34/51: make_template: Use a new dpkg-deb unpacker instead of reinventing it

Simon McVittie smcv at debian.org
Fri Dec 29 01:23:37 UTC 2017


This is an automated email from the git hooks/post-receive script.

smcv pushed a commit to branch master
in repository game-data-packager.

commit c6f08b644a1b959d53e9aba6cb2f8d3991b197ba
Author: Simon McVittie <smcv at debian.org>
Date:   Thu Dec 28 17:16:05 2017 +0000

    make_template: Use a new dpkg-deb unpacker instead of reinventing it
    
    Signed-off-by: Simon McVittie <smcv at debian.org>
---
 game_data_packager/make_template.py   | 151 +++++++++++++++++-----------------
 game_data_packager/unpack/__init__.py |  72 ++++++++++++++++
 2 files changed, 147 insertions(+), 76 deletions(-)

diff --git a/game_data_packager/make_template.py b/game_data_packager/make_template.py
index fcfc3dc..a836174 100644
--- a/game_data_packager/make_template.py
+++ b/game_data_packager/make_template.py
@@ -39,7 +39,7 @@ from .data import (FileGroup, HashedFile)
 from .game import (GameData)
 from .gog import GOG
 from .steam import parse_acf
-from .unpack import TarUnpacker
+from .unpack import (DpkgDebUnpacker, TarUnpacker)
 from .unpack.auto import automatic_unpacker
 from .util import (
         check_output,
@@ -475,85 +475,84 @@ class Template:
 
         install_to = None
 
-        with subprocess.Popen(['dpkg-deb', '--fsys-tarfile', deb],
-                stdout=subprocess.PIPE) as fsys_process:
-            with tarfile.open(deb + '//data.tar.*', mode='r|',
-                    fileobj=fsys_process.stdout) as fsys_tarfile:
-                for entry in fsys_tarfile:
-                    name = entry.name
-                    if name.startswith('./'):
-                        name = name[2:]
+        with DpkgDebUnpacker(deb) as unpacker:
+            for entry in unpacker:
+                name = entry.name
+                if name.startswith('./'):
+                    name = name[2:]
 
-                    if self.is_scummvm(name) or is_runtime(name):
-                        continue
-                    if (name.startswith('usr/share/doc/') and
-                            name.endswith('changelog.gz')):
-                        continue
-                    if (name.startswith('usr/share/doc/') and
-                            name.endswith('changelog.Debian.gz')):
-                        continue
+                if self.is_scummvm(name) or is_runtime(name):
+                    continue
+                if (name.startswith('usr/share/doc/') and
+                        name.endswith('changelog.gz')):
+                    continue
+                if (name.startswith('usr/share/doc/') and
+                        name.endswith('changelog.Debian.gz')):
+                    continue
 
-                    if (name.startswith('usr/share/doc/') and
-                            name.endswith('copyright')):
-                        print('# data/%s.copyright' % control['package'])
-                        for line in fsys_tarfile.extractfile(entry):
-                            print(line.decode('utf-8'), end='')
-                        print('')
-                        continue
+                if (name.startswith('usr/share/doc/') and
+                        name.endswith('copyright')):
+                    print('# data/%s.copyright' % control['package'])
+                    for line in unpacker.open(entry):
+                        print(line.decode('utf-8'), end='')
+                    print('')
+                    continue
 
-                    if (entry.isfile() and install_to is None):
-                        # assume this is the place
-                        if name.startswith('usr/share/games/'):
-                            there = name[len('usr/share/games/'):]
-                            there = there.split('/', 1)[0]
-                            install_to = ('usr/share/games/' + there)
-                        elif name.startswith('opt/GOG Games/'):
-                            there = name[len('opt/GOG Games/'):]
-                            there = there.split('/', 1)[0]
-                            install_to = ('opt/GOG Games/' + there)
-                            self.gog['path'] = '"%s"' % there
-
-                    if entry.isfile():
-                        hf = HashedFile.from_file(deb + '//data.tar.*//' + name,
-                                fsys_tarfile.extractfile(entry))
-                        name_l = name.lower()
-                        basename_l = os.path.basename(name_l)
-
-                        if os.path.splitext(name_l)[1] in ('.exe', '.bat'):
-                            self.unwanted.group_members.add(name_l)
-                        elif 'support/gog' in name_l or os.path.basename(name_l) in (
-                                                        'start.sh', 'uninstall.sh'):
-                            self.unwanted.group_members.add(name_l)
-                        elif name.startswith('opt/') and is_license(name):
-                            name = basename_l
-                            self.licenses.group_members.add(name)
-                        elif name.startswith('opt/') and is_doc(name):
-                            name = basename_l
-                            self.documentation.group_members.add(name)
-                        elif (install_to is not None and
-                            name.startswith(install_to + '/')):
-                            name = name[len(install_to) + 1:]
-                            if lower:
-                                name = name.lower()
-                            if self.gog and name.startswith('data/'):
-                                name = name[len('data/'):]
-                            self.required.group_members.add(name)
-                        else:
-                            self.optional.group_members.add(name)
-                            self.file_data[name] = dict(install_to='.')
-
-                        self.size[name] = entry.size
-                        self.md5[name] = hf.md5
-                        self.sha1[name] = hf.sha1
-                        self.sha256[name] = hf.sha256
-                    elif entry.isdir():
-                        pass
-                    elif entry.issym():
-                        self.package.setdefault('symlinks', {})[name] = os.path.join(
-                            os.path.dirname(name), entry.linkname)
+                if entry.is_regular_file and install_to is None:
+                    # assume this is the place
+                    if name.startswith('usr/share/games/'):
+                        there = name[len('usr/share/games/'):]
+                        there = there.split('/', 1)[0]
+                        install_to = ('usr/share/games/' + there)
+                    elif name.startswith('opt/GOG Games/'):
+                        there = name[len('opt/GOG Games/'):]
+                        there = there.split('/', 1)[0]
+                        install_to = ('opt/GOG Games/' + there)
+                        self.gog['path'] = '"%s"' % there
+
+                target = entry.get_symbolic_link_target()
+
+                if entry.is_regular_file:
+                    hf = HashedFile.from_file(deb + '//data.tar.*//' + name,
+                            unpacker.open(entry), size=entry.size)
+                    name_l = name.lower()
+                    basename_l = os.path.basename(name_l)
+
+                    if os.path.splitext(name_l)[1] in ('.exe', '.bat'):
+                        self.unwanted.group_members.add(name_l)
+                    elif 'support/gog' in name_l or os.path.basename(name_l) in (
+                                                    'start.sh', 'uninstall.sh'):
+                        self.unwanted.group_members.add(name_l)
+                    elif name.startswith('opt/') and is_license(name):
+                        name = basename_l
+                        self.licenses.group_members.add(name)
+                    elif name.startswith('opt/') and is_doc(name):
+                        name = basename_l
+                        self.documentation.group_members.add(name)
+                    elif (install_to is not None and
+                        name.startswith(install_to + '/')):
+                        name = name[len(install_to) + 1:]
+                        if lower:
+                            name = name.lower()
+                        if self.gog and name.startswith('data/'):
+                            name = name[len('data/'):]
+                        self.required.group_members.add(name)
                     else:
-                        logger.warning('unhandled data.tar entry type: %s: %s',
-                            name, entry.type)
+                        self.optional.group_members.add(name)
+                        self.file_data[name] = dict(install_to='.')
+
+                    self.size[name] = hf.size
+                    self.md5[name] = hf.md5
+                    self.sha1[name] = hf.sha1
+                    self.sha256[name] = hf.sha256
+                elif entry.is_directory:
+                    pass
+                elif target is not None:
+                    self.package.setdefault('symlinks', {})[name] = os.path.join(
+                        os.path.dirname(name), target)
+                else:
+                    logger.warning('unhandled data.tar entry type: %s: %s',
+                        name, entry.type_indicator)
 
         if self.plugin != 'scummvm_common' and install_to is not None:
             self.package['install_to'] = os.path.join('/',
diff --git a/game_data_packager/unpack/__init__.py b/game_data_packager/unpack/__init__.py
index f08ff85..f0a7123 100644
--- a/game_data_packager/unpack/__init__.py
+++ b/game_data_packager/unpack/__init__.py
@@ -21,6 +21,7 @@ import errno
 import os
 import shlex
 import shutil
+import subprocess
 import tarfile
 import time
 import zipfile
@@ -50,6 +51,12 @@ class UnpackableEntry(metaclass=ABCMeta):
         """
         return self.is_regular_file
 
+    def get_symbolic_link_target(self):
+        """Target of the symbolic link, or None if this is not a
+        symbolic link.
+        """
+        return None
+
     @property
     def mtime(self):
         """The last-modification time, or None if unspecified."""
@@ -74,6 +81,8 @@ class UnpackableEntry(metaclass=ABCMeta):
             ret = 'd'
         elif self.is_regular_file:
             ret = '-'
+        elif self.get_symbolic_link_target() is not None:
+            ret = 'l'
         else:
             ret = '?'
 
@@ -230,6 +239,69 @@ class TarEntry(UnpackableEntry):
     def size(self):
         return self.impl.size
 
+    def get_symbolic_link_target(self):
+        if self.impl.issym():
+            return self.impl.linkname
+        else:
+            return None
+
+    @property
+    def type_indicator(self):
+        """One or more ASCII symbols indicating the file type."""
+        if self.impl.isdir():
+            ret = 'd'
+        elif self.impl.isfile():
+            ret = '-'
+        elif self.impl.issym():
+            ret = 'l'
+        else:
+            ret = '?<%s>' % self.impl.type
+
+        if self.is_extractable:
+            ret += 'r'
+        else:
+            ret += '-'
+
+        return ret
+
+class DpkgDebUnpacker(WrapperUnpacker):
+    def __init__(self, path):
+        self._path = path
+        self._fsys_process = None
+
+    def __enter__(self):
+        self._fsys_process = subprocess.Popen(
+            ['dpkg-deb', '--fsys-tarfile', self._path],
+            stdout=subprocess.PIPE,
+        ).__enter__()
+        self._impl = tarfile.open(
+            self._path, mode='r|', fileobj=self._fsys_process.stdout,
+        ).__enter__()
+        return self
+
+    def __exit__(self, ex_type, ex_value, ex_traceback):
+        if self._impl is not None:
+            self._impl.__exit__(ex_type, ex_value, ex_traceback)
+            self._impl = None
+
+        if self._fsys_process is not None:
+            self._fsys_process.__exit__(ex_type, ex_value, ex_traceback)
+            self._fsys_process = None
+
+    @property
+    def format(self):
+        return 'deb'
+
+    def open(self, entry):
+        assert isinstance(entry, TarEntry)
+        return self._impl.extractfile(entry.impl)
+
+    def _is_entry(self, entry):
+        return isinstance(entry, TarEntry)
+
+    def _wrap_entry(self, entry):
+        return TarEntry(entry)
+
 class TarUnpacker(WrapperUnpacker):
     def __init__(self, name, reader=None, compression='*', skip=0):
         super(TarUnpacker, self).__init__()

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/game-data-packager.git



More information about the Pkg-games-commits mailing list