[game-data-packager] 05/11: Reduce circular imports by introducing packaging modules

Simon McVittie smcv at debian.org
Tue Jan 5 09:55:27 UTC 2016


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 5fe449739788ffdf3a1c9f4dcdce77ca74337077
Author: Simon McVittie <smcv at debian.org>
Date:   Mon Jan 4 23:47:51 2016 +0000

    Reduce circular imports by introducing packaging modules
    
    Also stop deleting non-native packaging systems in g-d-p's packaging:
    in principle, there's nothing to stop us producing a working .deb
    on a Fedora system or a working RPM on a Debian system, if the right
    tools are installed.
---
 debian/rules                                       |   4 -
 game_data_packager/build.py                        |  33 +++--
 game_data_packager/games/z_code.py                 |   5 +-
 game_data_packager/gog.py                          |   7 +-
 game_data_packager/packaging/__init__.py           |  70 ++++++++++
 .../{util_arch.py => packaging/arch.py}            |  35 ++---
 .../{util_deb.py => packaging/deb.py}              | 103 +++++++--------
 game_data_packager/packaging/rpm.py                | 146 +++++++++++++++++++++
 game_data_packager/steam.py                        |  11 +-
 game_data_packager/util.py                         |  10 +-
 game_data_packager/util_deb.py                     |  99 +-------------
 game_data_packager/util_fedora.py                  |  53 --------
 game_data_packager/util_rpm.py                     |  33 -----
 game_data_packager/util_suse.py                    |  53 --------
 tools/babel.py                                     |   5 +-
 tools/game-data-packager.spec                      |   3 -
 16 files changed, 318 insertions(+), 352 deletions(-)

diff --git a/debian/rules b/debian/rules
index 1b99807..afcc122 100755
--- a/debian/rules
+++ b/debian/rules
@@ -38,10 +38,6 @@ override_dh_install:
 		touch debian/game-data-packager/usr/share/games/game-data-packager/is-ubuntu-derived; \
 	fi
 	install -D -m755 runtime/doom2-masterlevels.py debian/game-data-packager/usr/games/doom2-masterlevels
-	rm -f debian/game-data-packager/usr/share/games/game-data-packager/game_data_packager/util_arch.py
-	rm -f debian/game-data-packager/usr/share/games/game-data-packager/game_data_packager/util_fedora.py
-	rm -f debian/game-data-packager/usr/share/games/game-data-packager/game_data_packager/util_rpm.py
-	rm -f debian/game-data-packager/usr/share/games/game-data-packager/game_data_packager/util_suse.py
 
 override_dh_installdocs:
 	dh_installdocs -XTODO
diff --git a/game_data_packager/build.py b/game_data_packager/build.py
index 8c5bd88..221fbf9 100644
--- a/game_data_packager/build.py
+++ b/game_data_packager/build.py
@@ -40,18 +40,17 @@ except ImportError:
     from distutils.version import LooseVersion as Version
 
 from .gog import GOG
+from .packaging import (get_native_packaging_system)
 from .paths import (DATADIR, ETCDIR)
 from .unpack import (TarUnpacker, ZipUnpacker)
 from .unpack.umod import (Umod)
 from .util import (AGENT,
         MEBIBYTE,
-        PACKAGE_CACHE,
         TemporaryUmask,
         check_call,
         check_output,
         copy_with_substitutions,
         human_size,
-        install_packages,
         lang_score,
         lintian_license,
         mkdir_p,
@@ -344,10 +343,16 @@ def iter_fat_mounts(folder):
                     yield path
 
 class PackagingTask(object):
-    def __init__(self, game):
+    def __init__(self, game, packaging=None):
         # A GameData object.
         self.game = game
 
+        if packaging is None:
+            packaging = get_native_packaging_system()
+
+        # A packaging system.
+        self.packaging = packaging
+
         # A temporary directory.
         self.__workdir = None
 
@@ -1418,7 +1423,8 @@ class PackagingTask(object):
         size = int(size.split()[0])
         with open(PKGINFO, 'w',  encoding='utf-8') as pkginfo:
             pkginfo.write('# Generated by game-data-packager %s\n' % package.version.split('+')[-1])
-            pkginfo.write('# using fakeroot version %s\n' % PACKAGE_CACHE.current_version('fakeroot'))
+            pkginfo.write('# using fakeroot version %s\n' %
+                    self.packaging.current_version('fakeroot'))
             pkginfo.write('# %s\n' % time.strftime("%a %b %d %H:%M:%S UTC %Y", time.gmtime()))
             pkginfo.write('pkgname = %s\n' % package.name)
             pkginfo.write('pkgver = %s-1\n' % package.version)
@@ -1882,8 +1888,8 @@ class PackagingTask(object):
             ver = None
 
         # check engine
-        is_installed = PACKAGE_CACHE.is_installed(engine)
-        if not is_installed and not PACKAGE_CACHE.is_available(engine):
+        is_installed = self.packaging.is_installed(engine)
+        if not is_installed and not self.packaging.is_available(engine):
             return FillResult.IMPOSSIBLE
         if ver is None:
             if is_installed:
@@ -1893,9 +1899,9 @@ class PackagingTask(object):
 
         # check version
         if is_installed:
-            current_ver = PACKAGE_CACHE.current_version(engine)
+            current_ver = self.packaging.current_version(engine)
         else:
-            current_ver = PACKAGE_CACHE.available_version(engine)
+            current_ver = self.packaging.available_version(engine)
 
         if current_ver and Version(current_ver) >= Version(ver):
             return FillResult.COMPLETE
@@ -2070,7 +2076,8 @@ class PackagingTask(object):
                 print('generated "%s"' % os.path.abspath(deb))
 
         if install_debs:
-            install_packages(debs, args.install_method, args.gain_root_command)
+            self.packaging.install_packages(debs, method=args.install_method,
+                    gain_root=args.gain_root_command)
 
         engines_alt = set((p.engine or self.game.engine) for p in ready)
         engines_alt.discard(None)
@@ -2078,7 +2085,7 @@ class PackagingTask(object):
         for engine_alt in engines_alt:
             for engine in reversed(engine_alt.split('|')):
                 engine = engine.split('(')[0].strip()
-                if PACKAGE_CACHE.is_installed(engine):
+                if self.packaging.is_installed(engine):
                     break
             else:
                 engines.add(engine)
@@ -2268,7 +2275,7 @@ class PackagingTask(object):
             if 'build-depends' in package.debian:
                 for tool in package.debian['build-depends']:
                     tool = tool.strip()
-                    if not which(tool) and not PACKAGE_CACHE.is_installed(tool):
+                    if not which(tool) and not self.packaging.is_installed(tool):
                         logger.error('package "%s" is needed to build "%s"' %
                                      (tool, package.name))
                         possible.discard(package)
@@ -2319,7 +2326,7 @@ class PackagingTask(object):
             if (package.expansion_for
               and (package.expansion_for not in self.game.packages
                    or  self.game.packages[package.expansion_for] not in possible)
-              and not PACKAGE_CACHE.is_installed(package.expansion_for)):
+              and not self.packaging.is_installed(package.expansion_for)):
                 for fullgame in possible:
                     if fullgame.type == 'full':
                         logger.warning("won't generate '%s' expansion, because "
@@ -2719,7 +2726,7 @@ class PackagingTask(object):
 
         # unace-nonfree package diverts /usr/bin/unace from unace package
         if (fmt == 'unace-nonfree' and
-                PACKAGE_CACHE.is_installed('unace-nonfree')):
+                self.packaging.is_installed('unace-nonfree')):
             return True
 
         logger.warning('cannot unpack "%s": tool "%s" is not ' +
diff --git a/game_data_packager/games/z_code.py b/game_data_packager/games/z_code.py
index 7f244a8..010b03b 100644
--- a/game_data_packager/games/z_code.py
+++ b/game_data_packager/games/z_code.py
@@ -23,7 +23,6 @@ import os
 from .. import GameData
 from ..build import (PackagingTask)
 from ..util import (TemporaryUmask,
-                    PACKAGE_CACHE,
                     mkdir_p,
                     lintian_desktop)
 from ..version import (BINDIR)
@@ -59,8 +58,8 @@ class ZCodeTask(PackagingTask):
             entry['Categories'] = 'Game;'
             entry['GenericName'] = self.game.genre + ' Game'
             entry['Name'] = package.longname or self.game.longname
-            if (PACKAGE_CACHE.is_installed('frotz') and
-                    not PACKAGE_CACHE.is_installed('gargoyle-free')):
+            if (self.packaging.is_installed('frotz') and
+                    not self.packaging.is_installed('gargoyle-free')):
                 engine = 'frotz'
                 entry['Terminal'] = 'true'
             else:
diff --git a/game_data_packager/gog.py b/game_data_packager/gog.py
index c09ec86..eb4c47c 100644
--- a/game_data_packager/gog.py
+++ b/game_data_packager/gog.py
@@ -20,8 +20,8 @@ import logging
 import os
 import subprocess
 
-from .util import (PACKAGE_CACHE,
-        ascii_safe,
+from .packaging import (get_native_packaging_system)
+from .util import (ascii_safe,
         check_output,
         lang_score,
         which)
@@ -132,6 +132,7 @@ def run_gog_meta_mode(parsed, games):
         owned = GOG.owned_games()
     logger.info("Found %d game(s) !" % len(owned))
 
+    packaging = get_native_packaging_system()
     found_games = set()
     found_packages = []
     for game, data in games.items():
@@ -144,7 +145,7 @@ def run_gog_meta_mode(parsed, games):
             if package.better_version:
                 if data.gog_download_name(data.packages[package.better_version]):
                     continue
-            installed = PACKAGE_CACHE.is_installed(package.name)
+            installed = packaging.is_installed(package.name)
             if parsed.new and installed:
                 continue
             found_games.add(game)
diff --git a/game_data_packager/packaging/__init__.py b/game_data_packager/packaging/__init__.py
new file mode 100644
index 0000000..93bcd1d
--- /dev/null
+++ b/game_data_packager/packaging/__init__.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python3
+# encoding=utf-8
+#
+# Copyright © 2014-2016 Simon McVittie <smcv at debian.org>
+#           © 2015 Alexandre Detiste <alexandre at detiste.be>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# You can find the GPL license text on a Debian system under
+# /usr/share/common-licenses/GPL-2.
+
+from abc import (ABCMeta, abstractmethod)
+
+class PackagingSystem(metaclass=ABCMeta):
+
+    def is_installed(self, package):
+        """Return boolean: is a package with the given name installed?"""
+        return (self.current_version(package) is not None)
+
+    def is_available(self, package):
+        """Return boolean: is a package with the given name available
+        to apt or equivalent?
+        """
+        try:
+            self.available_version(package)
+        except:
+            return False
+        else:
+            return True
+
+    @abstractmethod
+    def current_version(self, package):
+        """Return the version number of the given package as a string,
+        or None.
+        """
+        raise NotImplementedError
+
+    @abstractmethod
+    def available_version(self, package):
+        """Return the version number of the given package available in
+        apt or equivalent, or raise an exception if unavailable.
+        """
+        raise NotImplementedError
+
+    @abstractmethod
+    def install_packages(self, packages, method=None, gain_root='su'):
+        """Install one or more packages (a list of filenames)."""
+        raise NotImplementedError
+
+def get_native_packaging_system():
+    # lazy import when actually needed
+    from ..version import (FORMAT)
+
+    if FORMAT == 'deb':
+        from .deb import (get_distro_packaging)
+    elif FORMAT == 'arch':
+        from .arch import (get_distro_packaging)
+    elif FORMAT == 'rpm':
+        from .rpm import (get_distro_packaging)
+    else:
+        raise RuntimeError('Unable to determine native packaging system')
+
+    return get_distro_packaging()
diff --git a/game_data_packager/util_arch.py b/game_data_packager/packaging/arch.py
similarity index 76%
rename from game_data_packager/util_arch.py
rename to game_data_packager/packaging/arch.py
index 33438f3..c772783 100644
--- a/game_data_packager/util_arch.py
+++ b/game_data_packager/packaging/arch.py
@@ -2,6 +2,7 @@
 # encoding=utf-8
 #
 # Copyright © 2015 Alexandre Detiste <alexandre at detiste.be>
+# Copyright © 2016 Simon McVittie <smcv at debian.org>
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -11,32 +12,36 @@
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# You can find the GPL license text on a Debian system under
+# /usr/share/common-licenses/GPL-2.
 
 import logging
 import subprocess
 
-from .util import (run_as_root, check_output)
+from . import (PackagingSystem)
+from ..util import (run_as_root, check_output)
 
-logger = logging.getLogger('game-data-packager.util_arch')
+logger = logging.getLogger(__name__)
 
-class PackageCache:
+class ArchPackaging(PackagingSystem):
     def is_installed(self, package):
         return subprocess.call(['pacman', '-Q', package],
                                 stdout=subprocess.DEVNULL,
                                 stderr=subprocess.DEVNULL) == 0
 
-    def is_available(self, package):
-        return subprocess.call(['pacman', '-Si', package],
-                                stdout=subprocess.DEVNULL,
-                                stderr=subprocess.DEVNULL) == 0
-
     def current_version(self, package):
         try:
             return check_output(['pacman', '-Q', package],
                                 stderr=subprocess.DEVNULL,
                                 universal_newlines=True).split()[1]
         except subprocess.CalledProcessError:
-            return
+            return None
+
+    def is_available(self, package):
+        return subprocess.call(['pacman', '-Si', package],
+                                stdout=subprocess.DEVNULL,
+                                stderr=subprocess.DEVNULL) == 0
 
     def available_version(self, package):
         try:
@@ -47,12 +52,12 @@ class PackageCache:
                 k, _, v = line.split(maxsplit=2)
                 if k == 'Version':
                     return v
-                
+
         except subprocess.CalledProcessError:
-            return
+            return None
 
-PACKAGE_CACHE = PackageCache()
+    def install_packages(self, pkgs, method=None, gain_root='su'):
+        run_as_root(['pacman', '-U'] + list(pkgs), gain_root)
 
-def install_packages(pkgs, method, gain_root='su'):
-    """Install one or more packages (a list of filenames)."""
-    run_as_root(['pacman', '-U'] + list(pkgs), gain_root)
+def get_distro_packaging():
+    return ArchPackaging()
diff --git a/game_data_packager/util_deb.py b/game_data_packager/packaging/deb.py
similarity index 56%
copy from game_data_packager/util_deb.py
copy to game_data_packager/packaging/deb.py
index cd9d766..9c8f44f 100644
--- a/game_data_packager/util_deb.py
+++ b/game_data_packager/packaging/deb.py
@@ -1,7 +1,7 @@
 #!/usr/bin/python3
 # encoding=utf-8
 #
-# Copyright © 2014-2015 Simon McVittie <smcv at debian.org>
+# Copyright © 2014-2016 Simon McVittie <smcv at debian.org>
 #           © 2015 Alexandre Detiste <alexandre at detiste.be>
 #
 # This program is free software; you can redistribute it and/or
@@ -20,14 +20,17 @@ import logging
 import os
 import subprocess
 
-from .util import (run_as_root, check_output, mkdir_p)
 from debian.debian_support import Version
 
-logger = logging.getLogger('game-data-packager.util_deb')
+from . import (PackagingSystem)
+from ..util import (check_output, run_as_root)
 
-class PackageCache:
-    installed = None
-    available = None
+logger = logging.getLogger(__name__)
+
+class DebPackaging(PackagingSystem):
+    def __init__(self):
+        self.__installed = None
+        self.__available = None
 
     def is_installed(self, package):
         # FIXME: this shouldn't be hard-coded
@@ -48,7 +51,7 @@ class PackageCache:
         if os.path.isdir(os.path.join('/usr/share/doc', package)):
             return True
 
-        if self.installed is None:
+        if self.__installed is None:
             cache = set()
             proc = subprocess.Popen(['dpkg-query', '--show',
                         '--showformat', '${Package}\\n'],
@@ -56,21 +59,21 @@ class PackageCache:
                     stdout=subprocess.PIPE)
             for line in proc.stdout:
                 cache.add(line.rstrip())
-            self.installed = cache
+            self.__installed = cache
 
-        return package in self.installed
+        return package in self.__installed
 
     def is_available(self, package):
-        if self.available is None:
+        if self.__available is None:
             cache = set()
             proc = subprocess.Popen(['apt-cache', 'pkgnames'],
                     universal_newlines=True,
                     stdout=subprocess.PIPE)
             for line in proc.stdout:
                 cache.add(line.rstrip())
-            self.available = cache
+            self.__available = cache
 
-        return package in self.available
+        return package in self.__available
 
     def current_version(self, package):
         # 'dpkg-query: no packages found matching $package'
@@ -80,7 +83,7 @@ class PackageCache:
             return check_output(['dpkg-query', '--show',
               '--showformat', '${Version}', package], universal_newlines=True)
         except subprocess.CalledProcessError:
-            return
+            return None
 
     def available_version(self, package):
         current_ver = check_output(['apt-cache', 'madison', package],
@@ -89,50 +92,32 @@ class PackageCache:
         current_ver = current_ver.split('|')[1].strip()
         return current_ver
 
-PACKAGE_CACHE = PackageCache()
-
-def install_packages(debs, method, gain_root='su'):
-    """Install one or more packages (a list of filenames)."""
-
-    if method and method not in (
-            'apt', 'dpkg',
-            'gdebi', 'gdebi-gtk', 'gdebi-kde',
-            ):
-        logger.warning(('Unknown installation method %r, using apt or dpkg ' +
-            'instead') % method)
-        method = None
-
-    if not method:
-        apt_ver = PACKAGE_CACHE.current_version('apt')
-        if Version(apt_ver.strip()) >= Version('1.1~0'):
-            method = 'apt'
+    def install_packages(self, debs, method=None, gain_root='su'):
+        if method and method not in (
+                'apt', 'dpkg',
+                'gdebi', 'gdebi-gtk', 'gdebi-kde',
+                ):
+            logger.warning(('Unknown installation method %r, using apt or ' +
+                'dpkg instead') % method)
+            method = None
+
+        if not method:
+            apt_ver = self.current_version('apt')
+            if Version(apt_ver.strip()) >= Version('1.1~0'):
+                method = 'apt'
+            else:
+                method = 'dpkg'
+
+        if method == 'apt':
+            run_as_root(['apt-get', 'install', '--install-recommends'] +
+                    list(debs), gain_root)
+        elif method == 'dpkg':
+            run_as_root(['dpkg', '-i'] + list(debs), gain_root)
+        elif method == 'gdebi':
+            run_as_root(['gdebi'] + list(debs), gain_root)
         else:
-            method = 'dpkg'
-
-    if method == 'apt':
-        run_as_root(['apt-get', 'install', '--install-recommends'] + list(debs),
-                gain_root)
-    elif method == 'dpkg':
-        run_as_root(['dpkg', '-i'] + list(debs), gain_root)
-    elif method == 'gdebi':
-        run_as_root(['gdebi'] + list(debs), gain_root)
-    else:
-        # gdebi-gtk etc.
-        subprocess.call([method] + list(debs))
-
-def lintian_license(destdir, package, file):
-    assert type(package) is str
-    lintiandir = os.path.join(destdir, 'usr/share/lintian/overrides')
-    mkdir_p(lintiandir)
-    with open(os.path.join(lintiandir, package), 'a', encoding='utf-8') as l:
-        l.write('%s: extra-license-file usr/share/doc/%s/%s\n'
-                % (package, package, file))
-
-def lintian_desktop(destdir, package, program):
-    assert type(package) is str
-    lintiandir = os.path.join(destdir, 'usr/share/lintian/overrides')
-    mkdir_p(lintiandir)
-    with open(os.path.join(lintiandir, package), 'a', encoding='utf-8') as l:
-        l.write('%s: desktop-command-not-in-package '
-                'usr/share/applications/%s.desktop %s\n'
-                 % (package, package, program))
+            # gdebi-gtk etc.
+            subprocess.call([method] + list(debs))
+
+def get_distro_packaging():
+    return DebPackaging()
diff --git a/game_data_packager/packaging/rpm.py b/game_data_packager/packaging/rpm.py
new file mode 100644
index 0000000..b74f8f9
--- /dev/null
+++ b/game_data_packager/packaging/rpm.py
@@ -0,0 +1,146 @@
+#!/usr/bin/python3
+# encoding=utf-8
+#
+# Copyright © 2015 Alexandre Detiste <alexandre at detiste.be>
+# Copyright © 2016 Simon McVittie <smcv at debian.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# You can find the GPL license text on a Debian system under
+# /usr/share/common-licenses/GPL-2.
+
+import logging
+import os
+import subprocess
+
+from . import (PackagingSystem)
+from ..util import (check_output, run_as_root)
+
+logger = logging.getLogger(__name__)
+
+class RpmPackaging(PackagingSystem):
+    def is_installed(self, package):
+        return 0 == subprocess.call(['rpm', '-q', package],
+                                    stdout=subprocess.DEVNULL,
+                                    stderr=subprocess.DEVNULL)
+
+    def current_version(self, package):
+        try:
+            return check_output(['rpm', '-q',
+              '--qf', '%{VERSION}', package], universal_newlines=True)
+        except subprocess.CalledProcessError:
+            return None
+
+    def is_available(self, package):
+        # assume no apt-like system in this base class
+        return self.is_installed(package)
+
+    def available_version(self, package):
+        # assume no apt-like system in this base class
+        return self.current_version(package)
+
+    def install_packages(self, rpms, method=None, gain_root='su'):
+        """Install one or more packages (a list of filenames)."""
+
+        if method is None:
+            method = 'rpm'
+
+        if method == 'dnf':
+            run_as_root(['dnf', 'install'] + list(rpms), gain_root)
+        elif method == 'zypper':
+            run_as_root(['zypper', 'install'] + list(rpms), gain_root)
+        elif method == 'rpm':
+            run_as_root(['rpm', '-U'] + list(rpms), gain_root)
+
+class DnfPackaging(RpmPackaging):
+    def __init__(self):
+        self.__available = None
+
+    def is_available(self, package):
+        if self.available is None:
+            cache = set()
+            proc = subprocess.Popen(['dnf', 'list'],
+                    universal_newlines=True,
+                    stdout=subprocess.PIPE)
+            for line in proc.stdout:
+                if '.' in line:
+                    cache.add(line.split('.')[0])
+            self.available = cache
+
+        return package in self.available
+
+    def available_version(self, package):
+        proc = subprocess.Popen(['dnf', 'list', package],
+                                 universal_newlines=True,
+                                 stderr=subprocess.DEVNULL,
+                                 stdout=subprocess.PIPE)
+        # keep only last line
+        for line in proc.stdout:
+            pass
+        return line.split()[1]
+
+    def install_packages(self, rpms, method='dnf', gain_root='su'):
+        super(DnfPackaging, self).install_packages(rpms, method=method,
+                gain_root=gain_root)
+
+class ZypperPackaging(RpmPackaging):
+    def is_available(self, package):
+        proc = subprocess.Popen(['zypper', 'info', package],
+                universal_newlines=True,
+                stdout=subprocess.PIPE,
+                env={'LANG':'C'})
+        for line in proc.stdout:
+            if ':' not in line:
+                continue
+            k, _, v = line.split(maxsplit=2)
+            if k == 'Version':
+                return True
+        return False
+
+    def available_version(self, package):
+        proc = subprocess.Popen(['zypper', 'info', package],
+                universal_newlines=True,
+                stdout=subprocess.PIPE,
+                env={'LANG':'C'})
+        for line in proc.stdout:
+            if ':' not in line:
+                continue
+            k, _, v = line.split(maxsplit=2)
+            if k == 'Version':
+                return v
+
+    def install_packages(self, rpms, method='zypper', gain_root='su'):
+        super(ZypperPackaging, self).install_packages(rpms, method=method,
+                gain_root=gain_root)
+
+def get_distro_packaging():
+    if os.path.isfile('/etc/redhat-release'):
+        return ZypperPackaging()
+
+    if os.path.isfile('/etc/SuSE-release'):
+        return DnfPackaging()
+
+    try:
+        maybe = DnfPackaging()
+
+        if maybe.is_available('rpm'):
+            return maybe
+    except:
+        pass
+
+    try:
+        maybe = ZypperPackaging()
+
+        if maybe.is_available('rpm'):
+            return maybe
+    except:
+        pass
+
+    return RpmPackaging()
diff --git a/game_data_packager/steam.py b/game_data_packager/steam.py
index 4f11a9a..2950a49 100644
--- a/game_data_packager/steam.py
+++ b/game_data_packager/steam.py
@@ -25,10 +25,9 @@ import urllib.request
 from .build import (BinaryExecutablesNotAllowed,
         DownloadsFailed,
         NoPackagesPossible)
+from .packaging import (get_native_packaging_system)
 from .util import (AGENT,
-        PACKAGE_CACHE,
         ascii_safe,
-        install_packages,
         lang_score,
         rm_rf)
 
@@ -114,6 +113,8 @@ def run_steam_meta_mode(args, games):
     found_games = []
     found_packages = []
     tasks = {}
+    packaging = get_native_packaging_system()
+
     for game, gamedata in games.items():
         for package in gamedata.packages.values():
             id = package.steam.get('id') or gamedata.steam.get('id')
@@ -126,12 +127,12 @@ def run_steam_meta_mode(args, games):
             if lang_score(package.lang) == 0:
                 continue
 
-            installed = PACKAGE_CACHE.is_installed(package.name)
+            installed = packaging.is_installed(package.name)
             if args.new and installed:
                 continue
 
             if game not in tasks:
-                tasks[game] = gamedata.construct_task()
+                tasks[game] = gamedata.construct_task(packaging=packaging)
 
             paths = []
             for path in tasks[game].iter_steam_paths((package,)):
@@ -236,6 +237,6 @@ def run_steam_meta_mode(args, games):
         raise SystemExit(1)
 
     if install_debs:
-        install_packages(all_debs, args.install_method, args.gain_root_command)
+        packaging.install_packages(all_debs, args.install_method, args.gain_root_command)
     if workdir:
         rm_rf(workdir)
diff --git a/game_data_packager/util.py b/game_data_packager/util.py
index ea22d5e..84edbb0 100644
--- a/game_data_packager/util.py
+++ b/game_data_packager/util.py
@@ -217,25 +217,17 @@ def recursive_utime(directory, orig_time):
 
 # loaded at the end to avoid failed cyclic loads
 if FORMAT == 'deb':
-    from .util_deb import (PACKAGE_CACHE,
-                           install_packages,
-                           lintian_license,
-                           lintian_desktop)
+    from .util_deb import (lintian_license, lintian_desktop)
 elif FORMAT == 'arch':
-    from .util_arch import (PACKAGE_CACHE, install_packages)
     lintian_license = lambda a,b,c: None
     lintian_desktop = lambda a,b,c: None
 elif DISTRO == 'fedora':
-    from .util_fedora import (PACKAGE_CACHE, install_packages)
     lintian_license = lambda a,b,c: None
     lintian_desktop = lambda a,b,c: None
 elif DISTRO == 'suse':
-    from .util_suse import (PACKAGE_CACHE, install_packages)
     lintian_license = lambda a,b,c: None
     lintian_desktop = lambda a,b,c: None
 
 # pyflakes
-PACKAGE_CACHE
-install_packages
 lintian_license
 lintian_desktop
diff --git a/game_data_packager/util_deb.py b/game_data_packager/util_deb.py
index cd9d766..e502b9a 100644
--- a/game_data_packager/util_deb.py
+++ b/game_data_packager/util_deb.py
@@ -18,108 +18,11 @@
 
 import logging
 import os
-import subprocess
 
-from .util import (run_as_root, check_output, mkdir_p)
-from debian.debian_support import Version
+from .util import (mkdir_p)
 
 logger = logging.getLogger('game-data-packager.util_deb')
 
-class PackageCache:
-    installed = None
-    available = None
-
-    def is_installed(self, package):
-        # FIXME: this shouldn't be hard-coded
-        if package == 'doom-engine':
-            return (self.is_installed('chocolate-doom')
-                 or self.is_installed('prboom-plus')
-                 or self.is_installed('doomsday'))
-        if package == 'boom-engine':
-            return (self.is_installed('prboom-plus')
-                 or self.is_installed('doomsday'))
-        if package == 'heretic-engine':
-            return (self.is_installed('chocolate-heretic')
-                 or self.is_installed('doomsday'))
-        if package == 'hexen-engine':
-            return (self.is_installed('chocolate-hexen')
-                 or self.is_installed('doomsday'))
-
-        if os.path.isdir(os.path.join('/usr/share/doc', package)):
-            return True
-
-        if self.installed is None:
-            cache = set()
-            proc = subprocess.Popen(['dpkg-query', '--show',
-                        '--showformat', '${Package}\\n'],
-                    universal_newlines=True,
-                    stdout=subprocess.PIPE)
-            for line in proc.stdout:
-                cache.add(line.rstrip())
-            self.installed = cache
-
-        return package in self.installed
-
-    def is_available(self, package):
-        if self.available is None:
-            cache = set()
-            proc = subprocess.Popen(['apt-cache', 'pkgnames'],
-                    universal_newlines=True,
-                    stdout=subprocess.PIPE)
-            for line in proc.stdout:
-                cache.add(line.rstrip())
-            self.available = cache
-
-        return package in self.available
-
-    def current_version(self, package):
-        # 'dpkg-query: no packages found matching $package'
-        # will leak on stderr if called with an unknown package,
-        # but that should never happen
-        try:
-            return check_output(['dpkg-query', '--show',
-              '--showformat', '${Version}', package], universal_newlines=True)
-        except subprocess.CalledProcessError:
-            return
-
-    def available_version(self, package):
-        current_ver = check_output(['apt-cache', 'madison', package],
-                                    universal_newlines=True)
-        current_ver = current_ver.splitlines()[0]
-        current_ver = current_ver.split('|')[1].strip()
-        return current_ver
-
-PACKAGE_CACHE = PackageCache()
-
-def install_packages(debs, method, gain_root='su'):
-    """Install one or more packages (a list of filenames)."""
-
-    if method and method not in (
-            'apt', 'dpkg',
-            'gdebi', 'gdebi-gtk', 'gdebi-kde',
-            ):
-        logger.warning(('Unknown installation method %r, using apt or dpkg ' +
-            'instead') % method)
-        method = None
-
-    if not method:
-        apt_ver = PACKAGE_CACHE.current_version('apt')
-        if Version(apt_ver.strip()) >= Version('1.1~0'):
-            method = 'apt'
-        else:
-            method = 'dpkg'
-
-    if method == 'apt':
-        run_as_root(['apt-get', 'install', '--install-recommends'] + list(debs),
-                gain_root)
-    elif method == 'dpkg':
-        run_as_root(['dpkg', '-i'] + list(debs), gain_root)
-    elif method == 'gdebi':
-        run_as_root(['gdebi'] + list(debs), gain_root)
-    else:
-        # gdebi-gtk etc.
-        subprocess.call([method] + list(debs))
-
 def lintian_license(destdir, package, file):
     assert type(package) is str
     lintiandir = os.path.join(destdir, 'usr/share/lintian/overrides')
diff --git a/game_data_packager/util_fedora.py b/game_data_packager/util_fedora.py
deleted file mode 100644
index c2caa03..0000000
--- a/game_data_packager/util_fedora.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/python3
-# encoding=utf-8
-#
-# Copyright © 2015 Alexandre Detiste <alexandre at detiste.be>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-import logging
-import subprocess
-
-from .util import (run_as_root)
-from .util_rpm import (RPM_PackageCache)
-
-logger = logging.getLogger('game-data-packager.util_fedora')
-
-class PackageCache(RPM_PackageCache):
-    available = None
-
-    def is_available(self, package):
-        if self.available is None:
-            cache = set()
-            proc = subprocess.Popen(['dnf', 'list'],
-                    universal_newlines=True,
-                    stdout=subprocess.PIPE)
-            for line in proc.stdout:
-                if '.' in line:
-                    cache.add(line.split('.')[0])
-            self.available = cache
-
-        return package in self.available
-
-    def available_version(self, package):
-        proc = subprocess.Popen(['dnf', 'list', package],
-                                 universal_newlines=True,
-                                 stderr=subprocess.DEVNULL,
-                                 stdout=subprocess.PIPE)
-        # keep only last line
-        for line in proc.stdout:
-            pass
-        return line.split()[1]
-
-PACKAGE_CACHE = PackageCache()
-
-def install_packages(debs, method, gain_root='su'):
-    """Install one or more packages (a list of filenames)."""
-    run_as_root(['dnf', 'install'] + list(debs), gain_root)
diff --git a/game_data_packager/util_rpm.py b/game_data_packager/util_rpm.py
deleted file mode 100644
index 03e9fa0..0000000
--- a/game_data_packager/util_rpm.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/python3
-# encoding=utf-8
-#
-# Copyright © 2015 Alexandre Detiste <alexandre at detiste.be>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-import logging
-import subprocess
-
-from .util import (check_output)
-
-logger = logging.getLogger('game-data-packager.util_rpm')
-
-class RPM_PackageCache:
-    def is_installed(self, package):
-        return 0 == subprocess.call(['rpm', '-q', package],
-                                    stdout=subprocess.DEVNULL,
-                                    stderr=subprocess.DEVNULL)
-
-    def current_version(self, package):
-        try:
-            return check_output(['rpm', '-q',
-              '--qf', '%{VERSION}', package], universal_newlines=True)
-        except subprocess.CalledProcessError:
-            return
diff --git a/game_data_packager/util_suse.py b/game_data_packager/util_suse.py
deleted file mode 100644
index 60d8ecb..0000000
--- a/game_data_packager/util_suse.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/python3
-# encoding=utf-8
-#
-# Copyright © 2015 Alexandre Detiste <alexandre at detiste.be>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-import logging
-import subprocess
-
-from .util import (run_as_root)
-from .util_rpm import (RPM_PackageCache)
-
-logger = logging.getLogger('game-data-packager.util_suse')
-
-class PackageCache(RPM_PackageCache):
-    def is_available(self, package):
-        proc = subprocess.Popen(['zypper', 'info', package],
-                universal_newlines=True,
-                stdout=subprocess.PIPE,
-                env={'LANG':'C'})
-        for line in proc.stdout:
-            if ':' not in line:
-                continue
-            k, _, v = line.split(maxsplit=2)
-            if k == 'Version':
-                return True
-        return False
-
-    def available_version(self, package):
-        proc = subprocess.Popen(['zypper', 'info', package],
-                universal_newlines=True,
-                stdout=subprocess.PIPE,
-                env={'LANG':'C'})
-        for line in proc.stdout:
-            if ':' not in line:
-                continue
-            k, _, v = line.split(maxsplit=2)
-            if k == 'Version':
-                return v
-
-PACKAGE_CACHE = PackageCache()
-
-def install_packages(rpms, method, gain_root='su'):
-    """Install one or more packages (a list of filenames)."""
-    run_as_root(['zypper', 'install'] + list(rpms), gain_root)
diff --git a/tools/babel.py b/tools/babel.py
index 7826b25..b618e14 100755
--- a/tools/babel.py
+++ b/tools/babel.py
@@ -20,11 +20,14 @@
 
 from game_data_packager import (load_games)
 from game_data_packager.build import (FillResult)
+from game_data_packager.packaging import (get_native_packaging_system)
 
 games = []
 genres = dict()
 langs = dict()
 langs['total'] = 0
+packaging = get_native_packaging_system()
+
 for name, game in load_games().items():
     stats = dict()
     for package in game.packages.values():
@@ -43,7 +46,7 @@ for name, game in load_games().items():
             for m_lang in package.langs:
                 if m_lang not in stats:
                     stats[m_lang] = '*'
-        with game.construct_task() as task:
+        with game.construct_task(packaging=packaging) as task:
             if task.fill_gaps(package=package,
                      log=False) is FillResult.IMPOSSIBLE:
                  if package.better_version is None:
diff --git a/tools/game-data-packager.spec b/tools/game-data-packager.spec
index 21936d3..6481ca0 100644
--- a/tools/game-data-packager.spec
+++ b/tools/game-data-packager.spec
@@ -79,9 +79,6 @@ echo 'DISTRO = "fedora"' >> $VERSION_PY
 echo 'BINDIR = "usr/bin"' >> $VERSION_PY
 echo 'LICENSEDIR = "usr/share/licenses"' >> $VERSION_PY
 echo 'ASSETS = "usr/share"' >> $VERSION_PY
-rm $RPM_BUILD_ROOT/usr/share/games/game-data-packager/game_data_packager/util_arch.py
-rm $RPM_BUILD_ROOT/usr/share/games/game-data-packager/game_data_packager/util_deb.py
-rm $RPM_BUILD_ROOT/usr/share/games/game-data-packager/game_data_packager/util_suse.py
 find $RPM_BUILD_ROOT/usr/share/games/game-data-packager/game_data_packager -name '*.py' -exec chmod 755 {} \;
 find $RPM_BUILD_ROOT/etc/game-data-packager -empty -exec sh -c "echo '# we need more mirrors' > {}" \;
 

-- 
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