[game-data-packager] 05/09: Add support for games with platform-specific binary executables

Simon McVittie smcv at debian.org
Sun Oct 25 22:13:36 UTC 2015


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 2a03f7482b325ea9b3895cdbbb4a086109d49cf3
Author: Simon McVittie <smcv at debian.org>
Date:   Sun Oct 25 18:09:01 2015 +0000

    Add support for games with platform-specific binary executables
    
    These games are disabled unless --binary-executables is given,
    because nobody can audit them (let alone fix their bugs). However,
    we can at least verify that the binaries are the ones we expected,
    and in the case of dedicated servers, provide systemd units that
    confine them as much as possible.
---
 game_data_packager/__init__.py | 17 +++++++++++-
 game_data_packager/build.py    | 59 ++++++++++++++++++++++++++++++++++++------
 game_data_packager/steam.py    | 10 +++++--
 3 files changed, 75 insertions(+), 11 deletions(-)

diff --git a/game_data_packager/__init__.py b/game_data_packager/__init__.py
index 8649e46..736f869 100644
--- a/game_data_packager/__init__.py
+++ b/game_data_packager/__init__.py
@@ -342,6 +342,10 @@ class GameData(object):
         # Extra directories where we might find game files
         self.try_repack_from = []
 
+        # If non-empty, the game requires binary executables which are only
+        # available for the given architectures (typically i386)
+        self.binary_executables = ''
+
         # online stores metadata
         self.steam = {}
         self.gog = {}
@@ -367,7 +371,8 @@ class GameData(object):
 
         for k in ('longname', 'copyright', 'compress_deb', 'help_text', 'disks', 'fanmade',
                   'engine', 'genre', 'missing_langs', 'franchise', 'wiki', 'wikibase',
-                  'steam', 'gog', 'dotemu', 'origin', 'url_misc', 'wikipedia'):
+                  'steam', 'gog', 'dotemu', 'origin', 'url_misc', 'wikipedia',
+                  'binary_executables'):
             if k in self.data:
                 setattr(self, k, self.data[k])
 
@@ -1016,6 +1021,15 @@ def run_command_line():
             dest='gain_root_command',
             help='Use METHOD (su, sudo, pkexec) to gain root if needed')
 
+    # This is about ability to audit, not freeness. We don't have an
+    # option to restrict g-d-p to dealing with Free Software, because
+    # that would rule out the vast majority of its packages: if a game's
+    # data is Free Software, we could put it in main or contrib and not need
+    # g-d-p at all.
+    base_parser.add_argument('--binary-executables', action='store_true',
+            help='allow installation of executable code that was not built ' +
+                'from public source code')
+
     # Misc options
     group = base_parser.add_mutually_exclusive_group()
     group.add_argument('-i', '--install', action='store_true',
@@ -1118,6 +1132,7 @@ def run_command_line():
 
     config = read_config()
     parsed = argparse.Namespace(
+            binary_executables=False,
             compress=None,
             destination=None,
             download=True,
diff --git a/game_data_packager/build.py b/game_data_packager/build.py
index 0873fc1..4390645 100644
--- a/game_data_packager/build.py
+++ b/game_data_packager/build.py
@@ -103,6 +103,9 @@ class FillResult(Enum):
 
         return FillResult.IMPOSSIBLE
 
+class BinaryExecutablesNotAllowed(Exception):
+    pass
+
 class NoPackagesPossible(Exception):
     pass
 
@@ -1576,7 +1579,7 @@ class PackagingTask(object):
             control['Architecture'] = 'all'
             control['Multi-Arch'] = 'foreign'
         else:
-            control['Architecture'] = self.get_architecture()
+            control['Architecture'] = self.get_architecture(package.architecture)
 
         def read_control_set(package, control, field):
             result = set()
@@ -1777,9 +1780,27 @@ class PackagingTask(object):
     def iter_extra_paths(self, packages):
         return []
 
-    def look_for_files(self, paths=(), search=True, packages=None):
+    def look_for_files(self, paths=(), search=True, packages=None,
+            binary_executables=False):
         paths = list(paths)
 
+        if self.game.binary_executables:
+            if not binary_executables:
+                logger.error('%s requires binary-only executables which are '
+                        'currently disallowed', self.game.longname)
+                logger.info('Use the --binary-executables option to allow this, '
+                        'at your own risk')
+                raise BinaryExecutablesNotAllowed()
+
+            if self.get_architecture(self.game.binary_executables) not in \
+                    self.game.binary_executables.split():
+                logger.error('%s requires binary-only executables which are '
+                        'only available for %s', self.game.longname,
+                        ', '.join(self.game.binary_executables.split()))
+                logger.info('If your CPU can run one of those architectures, '
+                        'use dpkg --add-architecture to enable multiarch')
+                raise NoPackagesPossible()
+
         if self.save_downloads is not None and self.save_downloads not in paths:
             paths.append(self.save_downloads)
 
@@ -1863,8 +1884,14 @@ class PackagingTask(object):
 
         self.look_for_engines(packages, force=not args.install)
 
-        self.look_for_files(paths=args.paths, search=args.search,
-                packages=packages)
+        try:
+            self.look_for_files(paths=args.paths, search=args.search,
+                    packages=packages,
+                    binary_executables=args.binary_executables)
+        except BinaryExecutablesNotAllowed:
+            raise SystemExit(1)
+        except NoPackagesPossible:
+            raise SystemExit(1)
 
         try:
             ready = self.prepare_packages(packages,
@@ -1962,10 +1989,25 @@ class PackagingTask(object):
                     package.name)
             raise CDRipFailed()
 
-    def get_architecture(self):
+    def get_architecture(self, archs=''):
         if self._architecture is None:
             self._architecture = check_output(['dpkg',
                 '--print-architecture']).strip().decode('ascii')
+            self._foreign_architectures = set(check_output(['dpkg',
+                '--print-foreign-architectures']
+                ).strip().decode('ascii').split())
+
+        if archs:
+            # In theory this should deal with wildcards like linux-any,
+            # but it's unlikely to be relevant in practice.
+            archs = archs.split()
+
+            if self._architecture in archs or 'any' in archs:
+                return self._architecture
+
+            for arch in archs:
+                if arch in self._foreign_architectures:
+                    return arch
 
         return self._architecture
 
@@ -2056,9 +2098,10 @@ class PackagingTask(object):
                 self.get_architecture()
             else:
                 archs = package.architecture.split()
-                if self.get_architecture() not in archs:
+                arch = self.get_architecture(package.architecture)
+                if arch not in archs:
                     logger.warning('cannot produce "%s" on architecture %s',
-                            package.name, self.get_architecture())
+                            package.name, archs)
                     possible.discard(package)
 
         for package in set(possible):
@@ -2368,7 +2411,7 @@ class PackagingTask(object):
 
         arch = package.architecture
         if arch != 'all':
-            arch = self.get_architecture()
+            arch = self.get_architecture(arch)
 
         deb_basename = '%s_%s_%s.deb' % (package.name, package.version, arch)
 
diff --git a/game_data_packager/steam.py b/game_data_packager/steam.py
index 034dc83..c2c4817 100644
--- a/game_data_packager/steam.py
+++ b/game_data_packager/steam.py
@@ -22,7 +22,8 @@ import tempfile
 import xml.etree.ElementTree
 import urllib.request
 
-from .build import (DownloadsFailed,
+from .build import (BinaryExecutablesNotAllowed,
+        DownloadsFailed,
         NoPackagesPossible)
 from .util import (AGENT,
         PACKAGE_CACHE,
@@ -167,7 +168,12 @@ def run_steam_meta_mode(args, games):
         task = tasks[shortname]
         task.verbose = getattr(args, 'verbose', False)
         task.save_downloads = args.save_downloads
-        task.look_for_files()
+        try:
+            task.look_for_files(binary_executables=args.binary_executables)
+        except BinaryExecutablesNotAllowed:
+            continue
+        except NoPackagesPossible:
+            continue
 
         todo = list()
         for packages in found_packages:

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