← Back to team overview

apport-hackers team mailing list archive

[Merge] lp:~knitzsche/apport/sandboxutils into lp:apport

 

Kyle Nitzsche has proposed merging lp:~knitzsche/apport/sandboxutils into lp:apport.

Requested reviews:
  Apport upstream developers (apport-hackers)

For more details, see:
https://code.launchpad.net/~knitzsche/apport/sandboxutils/+merge/139285

Move some code from apport-retrace into a new module apport/sandboxutils.py in order to setup things for a planned apport-valgrind implementation. 
-- 
https://code.launchpad.net/~knitzsche/apport/sandboxutils/+merge/139285
Your team Apport upstream developers is requested to review the proposed merge of lp:~knitzsche/apport/sandboxutils into lp:apport.
=== added file 'apport/sandboxutils.py'
--- apport/sandboxutils.py	1970-01-01 00:00:00 +0000
+++ apport/sandboxutils.py	2012-12-11 18:30:31 +0000
@@ -0,0 +1,170 @@
+'''Functions to manage sandboxes'''
+
+# Copyright (C) 2006 - 2009 Canonical Ltd.
+# Author: Martin Pitt <martin.pitt@xxxxxxxxxx>
+#
+# 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.  See http://www.gnu.org/copyleft/gpl.html for
+# the full text of the license.
+
+import atexit, os, os.path, shutil, sys, tempfile
+import apport, apport.fileutils
+from apport.packaging_impl import impl as packaging
+
+try:
+    from configparser import ConfigParser, NoOptionError, NoSectionError
+    (ConfigParser, NoOptionError, NoSectionError)  # pyflakes
+except ImportError:
+    # Python 2
+    from ConfigParser import ConfigParser, NoOptionError, NoSectionError
+
+def log(message, log_timestamps=None):
+    '''Log the given string to stdout. Prepend timestamp if requested'''
+
+    if log_timestamps:
+        sys.stdout.write('%s: ' % time.strftime('%x %X'))
+    print(message)
+
+
+def needed_packages(report):
+    '''Determine necessary packages for given report.
+
+    Return list of (pkgname, version) pairs. version might be None for unknown
+    package versions.
+    '''
+    pkgs = {}
+
+    # first, grab the versions that we captured at crash time
+    for l in (report['Package'] + '\n' + report.get('Dependencies',
+'')).splitlines():
+        if not l.strip():
+            continue
+        try:
+            (pkg, version) = l.split()[:2]
+        except ValueError:
+            apport.warning('invalid Package/Dependencies line: %s', l)
+            # invalid line, ignore
+            continue
+        pkgs[pkg] = version
+
+    return [(p, v) for (p, v) in pkgs.items()]
+
+
+def needed_runtime_packages(report, sandbox, cache_dir, verbose=False):
+    '''Determine necessary runtime packages for given report.
+
+    This determines libraries which were dynamically loaded at runtime, i. e.
+    appear in /proc/pid/maps, but not in Dependencies: (such as plugins).
+
+    Return list of (pkgname, None) pairs.
+
+    When cache_dir is specified, it is used as a cache for get_file_package().
+    '''
+    # check list of libraries that the crashed process referenced at
+    # runtime and warn about those which are not available
+    pkgs = set()
+    libs = set()
+    if 'ProcMaps' in report:
+        for l in report['ProcMaps'].splitlines():
+            if not l.strip():
+                continue
+            cols = l.split()
+            if len(cols) == 6 and 'x' in cols[1] and '.so' in cols[5]:
+                lib = os.path.realpath(cols[5])
+                libs.add(lib)
+
+    if sandbox:
+        cache_dir = os.path.join(cache_dir, report['DistroRelease'])
+
+    # grab as much as we can
+    for l in libs:
+        if os.path.exists(sandbox + l):
+            continue
+
+        pkg = apport.packaging.get_file_package(l, True, cache_dir)
+        if pkg:
+            if verbose:
+                log('dynamically loaded %s needs package %s, queueing' % (l,
+pkg))
+            pkgs.add(pkg)
+        else:
+                apport.warning('%s is needed, but cannot be mapped to a package', l)
+
+    return [(p, None) for p in pkgs]
+
+
+def make_sandbox(sandbox, sandbox_dir, cache, verbose, report, extra_package=[], log_timestamps=None):
+
+    if sandbox:
+        if sandbox_dir:
+            sbox = os.path.abspath(sandbox_dir)
+            if not os.path.isdir(sbox):
+                os.makedirs(sbox)
+            permanent_rootdir = True
+        else:
+            sbox = tempfile.mkdtemp()
+            atexit.register(shutil.rmtree, sbox)
+            permanent_rootdir = False
+
+        pkgs = needed_packages(report)
+        for p in extra_package:
+            pkgs.append((p, None))
+        if sandbox == 'system':
+            sandbox_arg = None
+        else:
+            sandbox_arg = sandbox
+
+        # we call install_packages() multiple times, plus get_file_package(); use
+        # a
+        # shared cache dir for these
+        if cache:
+            cache = os.path.abspath(cache)
+        else:
+            cache = tempfile.mkdtemp()
+            atexit.register(shutil.rmtree, cache)
+
+        try:
+            outdated_msg = apport.packaging.install_packages(
+                sbox, sandbox_arg, report['DistroRelease'], pkgs,
+                verbose, cache, permanent_rootdir)
+        except SystemError as e:
+            sys.stderr.write(str(e) + '\n')
+            sys.exit(1)
+
+        pkgs = needed_runtime_packages(report, sbox, cache, verbose)
+
+        # package hooks might reassign Package:, check that we have the originally
+        # crashing binary
+        for path in ('InterpreterPath', 'ExecutablePath'):
+            if path in report and not os.path.exists(sbox + report[path]):
+                pkg = apport.packaging.get_file_package(report[path], True, cache)
+                if pkg:
+                    log('Installing extra package %s to get %s' % (pkg, path))
+                    pkgs.append((pkg, None))
+                else:
+                    apport.warning('Cannot find package which ships %s', path)
+
+        if pkgs:
+            try:
+                outdated_msg += apport.packaging.install_packages(
+                    sbox, sandbox_arg, report['DistroRelease'], pkgs,
+                    cache)
+            except SystemError as e:
+                sys.stderr.write(str(e) + '\n')
+                sys.exit(1)
+
+        for path in ('InterpreterPath', 'ExecutablePath'):
+            if path in report and not os.path.exists(sbox + report[path]):
+                apport.error('%s %s does not exist (report specified package %s)',
+                             path, sbox + report[path], report['Package'])
+                sys.exit(0)
+
+        if outdated_msg:
+            report['RetraceOutdatedPackages'] = outdated_msg
+
+        apport.memdbg('built sandbox')
+
+    return sbox, outdated_msg
+

=== modified file 'bin/apport-retrace'
--- bin/apport-retrace	2012-12-10 09:32:53 +0000
+++ bin/apport-retrace	2012-12-11 18:30:31 +0000
@@ -14,7 +14,7 @@
 
 import sys, os, os.path, subprocess, optparse, shutil, tempfile, re, zlib
 import tty, termios, gettext, atexit, time
-import apport, apport.fileutils
+import apport, apport.fileutils, apport.sandboxutils
 from apport.crashdb import get_crashdb
 from apport import unicode_gettext as _
 
@@ -203,72 +203,6 @@
         pass
 
 
-def needed_packages(report):
-    '''Determine necessary packages for given report.
-
-    Return list of (pkgname, version) pairs. version might be None for unknown
-    package versions.
-    '''
-    pkgs = {}
-
-    # first, grab the versions that we captured at crash time
-    for l in (report['Package'] + '\n' + report.get('Dependencies', '')).splitlines():
-        if not l.strip():
-            continue
-        try:
-            (pkg, version) = l.split()[:2]
-        except ValueError:
-            apport.warning('invalid Package/Dependencies line: %s', l)
-            # invalid line, ignore
-            continue
-        pkgs[pkg] = version
-
-    return [(p, v) for (p, v) in pkgs.items()]
-
-
-def needed_runtime_packages(report, sandbox, cache_dir, verbose=False):
-    '''Determine necessary runtime packages for given report.
-
-    This determines libraries which were dynamically loaded at runtime, i. e.
-    appear in /proc/pid/maps, but not in Dependencies: (such as plugins).
-
-    Return list of (pkgname, None) pairs.
-
-    When cache_dir is specified, it is used as a cache for get_file_package().
-    '''
-    # check list of libraries that the crashed process referenced at
-    # runtime and warn about those which are not available
-    pkgs = set()
-    libs = set()
-    if 'ProcMaps' in report:
-        for l in report['ProcMaps'].splitlines():
-            if not l.strip():
-                continue
-            cols = l.split()
-            if len(cols) == 6 and 'x' in cols[1] and '.so' in cols[5]:
-                lib = os.path.realpath(cols[5])
-                libs.add(lib)
-
-    if sandbox:
-        cache_dir = os.path.join(cache_dir, report['DistroRelease'])
-
-    # grab as much as we can
-    for l in libs:
-        if os.path.exists(sandbox + l):
-            continue
-
-        pkg = apport.packaging.get_file_package(l, True, cache_dir,
-                                                arch=report.get('Architecture'))
-        if pkg:
-            if verbose:
-                log('dynamically loaded %s needs package %s, queueing' % (l, pkg))
-            pkgs.add(pkg)
-        else:
-                apport.warning('%s is needed, but cannot be mapped to a package', l)
-
-    return [(p, None) for p in pkgs]
-
-
 def print_traces(report):
     '''Print stack traces from given report'''
 
@@ -372,75 +306,14 @@
 
 sandbox = None
 outdated_msg = None
-if options.sandbox:
-    if options.sandbox_dir:
-        sandbox = os.path.abspath(options.sandbox_dir)
-        if not os.path.isdir(sandbox):
-            os.makedirs(sandbox)
-        permanent_rootdir = True
-    else:
-        sandbox = tempfile.mkdtemp(prefix='apport_sandbox_')
-        atexit.register(shutil.rmtree, sandbox)
-        permanent_rootdir = False
-
-    pkgs = needed_packages(report)
-    for p in options.extra_package:
-        pkgs.append((p, None))
-    if options.sandbox == 'system':
-        sandbox_arg = None
-    else:
-        sandbox_arg = options.sandbox
-
-    # we call install_packages() multiple times, plus get_file_package(); use a
-    # shared cache dir for these
-    if options.cache:
-        options.cache = os.path.abspath(options.cache)
-    else:
-        options.cache = tempfile.mkdtemp()
-        atexit.register(shutil.rmtree, options.cache)
-
-    try:
-        outdated_msg = apport.packaging.install_packages(
-            sandbox, sandbox_arg, report['DistroRelease'], pkgs,
-            options.verbose, options.cache, permanent_rootdir,
-            architecture=report.get('Architecture'))
-    except SystemError as e:
-        sys.stderr.write(str(e) + '\n')
-        sys.exit(1)
-
-    pkgs = needed_runtime_packages(report, sandbox, options.cache, options.verbose)
-
-    # package hooks might reassign Package:, check that we have the originally crashing binary
-    for path in ('InterpreterPath', 'ExecutablePath'):
-        if path in report and not os.path.exists(sandbox + report[path]):
-            pkg = apport.packaging.get_file_package(report[path], True, options.cache,
-                                                    arch=report.get('Architecture'))
-            if pkg:
-                log('Installing extra package %s to get %s' % (pkg, path))
-                pkgs.append((pkg, None))
-            else:
-                apport.warning('Cannot find package which ships %s', path)
-
-    if pkgs:
-        try:
-            outdated_msg += apport.packaging.install_packages(
-                sandbox, sandbox_arg, report['DistroRelease'], pkgs,
-                options.verbose, options.cache,
-                architecture=report.get('Architecture'))
-        except SystemError as e:
-            sys.stderr.write(str(e) + '\n')
-            sys.exit(1)
-
-    for path in ('InterpreterPath', 'ExecutablePath'):
-        if path in report and not os.path.exists(sandbox + report[path]):
-            apport.error('%s %s does not exist (report specified package %s)',
-                         path, sandbox + report[path], report['Package'])
-            sys.exit(0)
-
-    if outdated_msg:
-        report['RetraceOutdatedPackages'] = outdated_msg
-
-    apport.memdbg('built sandbox')
+sandbox, outdated_msg = apport.sandboxutils.make_sandbox(
+        options.sandbox,
+        options.sandbox_dir,
+        options.cache,
+        options.verbose,
+        report,
+        options.extra_package,
+        )
 
 # interactive gdb session
 if options.gdb:


Follow ups