ó
ýGpNc           @   s›   d  Z  d d l Z d d l Z d d l Z d d l Z d d l m Z d d l m Z	 d „  Z
 d f  d „  ƒ  YZ e e d „ Z d	 e f d
 „  ƒ  YZ d S(   s"   Abstract crash database interface.iÿÿÿÿN(   t	   Exception(   t   implc         C   s,   t  |  ƒ t  d ƒ k r( |  j d d ƒ S|  S(   s.   Convert str to an unicode if it isn't already.t    s   utf-8t   ignore(   t   typet   decode(   t   str(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   _u   s    t   CrashDatabasec           B   s.  e  Z d  „  Z d „  Z d „  Z d d „ Z d „  Z d „  Z d „  Z	 d „  Z
 e d „ Z d	 „  Z d d
 „ Z d „  Z d „  Z e d d d „ Z d d „ Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d „  Z d d „ Z  d „  Z! RS(    c         C   s(   | |  _  | |  _ | |  _ d |  _ d S(   s‹  Initialize crash database connection. 
        
        You need to specify an implementation specific file with the
        authentication credentials for retracing access for download() and
        update(). For upload() and get_comment_url() you can use None.
        
        options is a dictionary with additional settings from crashdb.conf; see
        get_crashdb() for details.
        N(   t	   auth_filet   optionst   bugpattern_baseurlt   Nonet   duplicate_db(   t   selfR	   R   R
   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   __init__   s    
			c         C   s   |  j  S(   sµ   Return the base URL for bug patterns.

        See apport.report.Report.search_bug_patterns() for details. If this
        function returns None, bug patterns are disabled.
        (   R   (   R   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   get_bugpattern_baseurl(   s    c         C   sù   d d l  } | j d k s$ t d ‚ t j j | ƒ pX | d k pX t j j | ƒ d k } | j | d d ƒ|  _ | r¥ |  j j	 ƒ  } | j
 d	 ƒ |  j j ƒ  n  |  j j	 ƒ  } | j
 d
 ƒ | j ƒ  } | d g k rõ t d t | ƒ ƒ ‚ n  d S(   sˆ   Initialize duplicate database.

        path specifies an SQLite database. It will be created if it does not
        exist yet.
        iÿÿÿÿNt   qmarks/   this module assumes qmark dbapi parameter styles   :memory:i    t   timeouti   sÄ   CREATE TABLE crashes (
                signature VARCHAR(255) NOT NULL,
                crash_id INTEGER NOT NULL,
                fixed_version VARCHAR(50),
                last_change TIMESTAMP)s   PRAGMA integrity_checkt   oks   Corrupt duplicate db:(   s   ok(   t   sqlite3t
   paramstylet   AssertionErrort   ost   patht   existst   getsizet   connectR   t   cursort   executet   committ   fetchallt   SystemErrorR   (   R   R   t   dbapi2t   initt   curt   result(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   init_duplicate_db5   s     c         C   s  |  j  s t d ‚ | s* |  j | ƒ } n  |  j | | ƒ d | k rS | d } n | j ƒ  } | si d
 S|  j | | ƒ } d „  } | j | d „  ƒ | ré x! | D] \ } } |  j | ƒ q¤ W|  j | | ƒ } | j | d „  ƒ n  | s.|  j  j	 ƒ  } | j
 d t | ƒ | d
 f ƒ |  j  j ƒ  d
 Sy | d j ƒ  d }	 Wn t t f k
 red
 }	 n Xx | D]F \ } }
 |
 sŸ|	 sŸt j |	 |
 ƒ d	 k  rm|  j | | ƒ PqmqmW|  j | | ƒ |  j  j	 ƒ  } | j
 d t | ƒ | d
 f ƒ |  j  j ƒ  d
 S| |
 f S(   s)  Check whether a crash is already known.

        If the crash is new, it will be added to the duplicate database and the
        function returns None. If the crash is already known, the function
        returns a pair (crash_id, fixed_version), where fixed_version might be
        None if the crash is not fixed in the latest version yet. Depending on
        whether the version in report is smaller than/equal to the fixed
        version or larger, this calls close_duplicate() or mark_regression().
        
        If the report does not have a valid crash signature, this function does
        nothing and just returns None.
        
        By default, the report gets download()ed, but for performance reasons
        it can be explicitly passed to this function if it is already available.
        s-   init_duplicate_db() needs to be called beforet   DuplicateSignaturec         S   s†   |  | k r d S|  d k r3 | d  k r, d Sd Sn  | d k rV |  d  k rO d Sd Sn  |  d  k rf d S| d  k rv d St j |  | ƒ S(   Ni    R   iÿÿÿÿi   (   R   t	   packagingt   compare_versions(   t   xt   y(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   cmpw   s    c         S   s   |  d S(   Ni   (    (   t   k(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   <lambda>Š   s    c         S   s   |  d S(   Ni   (    (   R,   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyR-   ‘   s    s7   INSERT INTO crashes VALUES (?, ?, ?, CURRENT_TIMESTAMP)t   Packagei   i    N(   R   R   t   downloadt   _mark_dup_checkedt   crash_signatureR   t   _duplicate_search_signaturet   sortt   _duplicate_db_sync_statusR   R   R   R   t   splitt   KeyErrort
   IndexErrorR'   R(   t   close_duplicatet   mark_regression(   R   t   idt   reportt   sigt   existingR+   t   ex_idt   _R#   t   report_package_versiont   ex_ver(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   check_duplicateU   sL    	
c         C   s_   |  j  s t d ‚ |  j  j ƒ  } | j d | | f ƒ } | j d k sN t ‚ |  j  j ƒ  d S(   s²   Mark given crash ID as fixed in the duplicate database.
        
        version specifies the package version the crash was fixed in (None for
        'still unfixed').
        s-   init_duplicate_db() needs to be called beforesX   UPDATE crashes SET fixed_version = ?, last_change = CURRENT_TIMESTAMP WHERE crash_id = ?i   N(   R   R   R   R   t   rowcountR   (   R   R:   t   versionR#   t   n(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   duplicate_db_fixed¶   s    	c         C   sE   |  j  s t d ‚ |  j  j ƒ  } | j d | g ƒ |  j  j ƒ  d S(   sƒ   Remove crash from the duplicate database.
        
        This happens when a report got rejected or manually duplicated.
        s-   init_duplicate_db() needs to be called befores&   DELETE FROM crashes WHERE crash_id = ?N(   R   R   R   R   R   (   R   R:   R#   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   duplicate_db_removeÄ   s    c         C   sH   |  j  s t d ‚ |  j  j ƒ  } | j d | | g ƒ |  j  j ƒ  d S(   s   Change a crash ID.s-   init_duplicate_db() needs to be called beforesS   UPDATE crashes SET crash_id = ?, last_change = CURRENT_TIMESTAMP WHERE crash_id = ?N(   R   R   R   R   R   (   R   t   old_idt   new_idR#   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   duplicate_db_change_master_idÏ   s
    	c         C   s5   |  j  j ƒ  } | j d t | ƒ | g ƒ | j ƒ  S(   sŸ  Look up signature in the duplicate db.
        
        Return [(id, fixed_version)] tuple list.
        
        There might be several matches if a crash has been reintroduced in a
        later version.

        id is the bug we are looking to find a duplicate for. The result will
        never contain id, to avoid marking a bug as a duplicate of itself if a
        bug is reprocessed more than once.
        sQ   SELECT crash_id, fixed_version FROM crashes WHERE signature = ? AND crash_id <> ?(   R   R   R   R   R   (   R   R<   R:   R#   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyR2   Ù   s    c         C   s   |  j  s t d ‚ i  } |  j  j ƒ  } | j d ƒ xF | D]> \ } } } } | ri | | | f | | <q; | | f | | <q; W| S(   sa  Return the entire duplicate database as a dictionary.
        
        The returned dictionary maps "signature" to (crash_id, fixed_version)
        pairs.

        If with_timestamps is True, then the map will contain triples
        (crash_id, fixed_version, last_change) instead.

        This is mainly useful for debugging and test suites.
        s-   init_duplicate_db() needs to be called befores   SELECT * FROM crashes(   R   R   R   R   (   R   t   with_timestampst   dumpR#   R<   R:   t   vert   last_change(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   _duplicate_db_dumpé   s    c         C   sí   |  j  s t d ‚ |  j  j ƒ  } | j d | g ƒ | j ƒ  } | sJ d S| d } |  j | ƒ } | d k r‰ d | GH|  j | ƒ d S| r¹ | r¹ d | | f GH|  j | | ƒ d S| ré | ré d | | f GH|  j | | ƒ d Sd S(	   s$  Update the duplicate db to the reality of the report in the crash db.
        
        This uses get_fixed_version() to get the status of the given crash.
        An invalid ID gets removed from the duplicate db, and a crash which got
        fixed is marked as such in the database.
        s-   init_duplicate_db() needs to be called befores4   SELECT fixed_version FROM crashes WHERE crash_id = ?Ni    t   invalids5   DEBUG: bug %i was invalidated, removing from databases8   DEBUG: bug %i got fixed in version %s, updating databasesC   DEBUG: bug %i got reopened, dropping fixed version %s from database(   R   R   R   R   t   fetchonet   get_fixed_versionRG   RF   (   R   R:   R#   t   db_fixed_versiont   real_fixed_version(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyR4      s(    
	c         C   s   t  d ƒ ‚ d S(   s  Upload given problem report return a handle for it. 
        
        This should happen noninteractively. 
        
        If the implementation supports it, and a function progress_callback is
        passed, that is called repeatedly with two arguments: the number of
        bytes already sent, and the total number of bytes to send. This can be
        used to provide a proper upload progress indication on frontends.

        This method can raise a NeedsCredentials exception in case of failure.
        s6   this method must be implemented by a concrete subclassN(   t   NotImplementedError(   R   R;   t   progress_callback(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   upload(  s    c         C   s   t  d ƒ ‚ d S(   s8  Return an URL that should be opened after report has been uploaded
        and upload() returned handle.

        Should return None if no URL should be opened (anonymous filing without
        user comments); in that case this function should do whichever
        interactive steps it wants to perform.
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   R;   t   handle(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   get_comment_url6  s    c         C   s   t  d ƒ ‚ d S(   s>   Download the problem report from given ID and return a Report.s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyR/   @  s    c         C   s   t  d ƒ ‚ d S(   sq  Update the given report ID with all data from report.

        This creates a text comment with the "short" data (see
        ProblemReport.write_mime()), and creates attachments for all the
        bulk/binary data. 
        
        If change_description is True, and the crash db implementation supports
        it, the short data will be put into the description instead (like in a
        new bug).

        comment will be added to the "short" data. If attachment_comment is
        given, it will be added to the attachment uploads.

        If key_filter is a list or set, then only those keys will be added.
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   R;   t   commentt   change_descriptiont   attachment_commentt
   key_filter(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   updateE  s    R   c      	   C   s)   |  j  | | | d d d d d g ƒd S(   sÎ   Update the given report ID for retracing results.
        
        This updates Stacktrace, ThreadStacktrace, StacktraceTop,
        and StacktraceSource. You can also supply an additional comment.
        R]   t
   Stacktracet   ThreadStacktracet   StacktraceSourcet   StacktraceTopN(   R^   (   R   R:   R;   RZ   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   update_tracesX  s    c         C   s   t  d ƒ ‚ d S(   s   Set username and password.s6   this method must be implemented by a concrete subclassN(   RU   (   R   t   usernamet   password(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   set_credentialsa  s    c         C   s   t  d ƒ ‚ d S(   s2   Get 'DistroRelease: <release>' from the report ID.s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   get_distro_releasef  s    c         C   s   t  d ƒ ‚ d S(   s§   Return set of crash IDs which have not been retraced yet.
        
        This should only include crashes which match the current host
        architecture.
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   get_unretracedk  s    c         C   s   t  d ƒ ‚ d S(   s  Return set of crash IDs which need duplicate checking.

        This is mainly useful for crashes of scripting languages such as
        Python, since they do not need to be retraced. It should not return
        bugs that are covered by get_unretraced().
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   get_dup_uncheckeds  s    c         C   s   t  d ƒ ‚ d S(   s`  Return an ID set of all crashes which are not yet fixed.

        The list must not contain bugs which were rejected or duplicate.
        
        This function should make sure that the returned list is correct. If
        there are any errors with connecting to the crash database, it should
        raise an exception (preferably IOError).
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   get_unfixed|  s    	c         C   s   t  d ƒ ‚ d S(   s  Return the package version that fixes a given crash.

        Return None if the crash is not yet fixed, or an empty string if the
        crash is fixed, but it cannot be determined by which version. Return
        'invalid' if the crash report got invalidated, such as closed a
        duplicate or rejected.

        This function should make sure that the returned result is correct. If
        there are any errors with connecting to the crash database, it should
        raise an exception (preferably IOError).
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyRR   ‡  s    c         C   s   t  d ƒ ‚ d S(   s5   Return list of affected source packages for given ID.s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   get_affected_packages•  s    c         C   s   t  d ƒ ‚ d S(   s3   Check whether the user is the reporter of given ID.s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   is_reporterš  s    c         C   s   t  d ƒ ‚ d S(   sB  Check whether the user is eligible to update a report.

        A user should add additional information to an existing ID if (s)he is
        the reporter or subscribed, the bug is open, not a duplicate, etc. The
        exact policy and checks should be done according to  the particular
        implementation.
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt
   can_updateŸ  s    c         C   s   t  d ƒ ‚ d S(   sc   Return master ID for a duplicate bug.

        If the bug is not a duplicate, return None.
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   duplicate_of©  s    c         C   s   t  d ƒ ‚ d S(   st   Mark a crash id as duplicate of given master ID.
        
        If master is None, id gets un-duplicated.
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   t   master(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyR8   °  s    c         C   s   t  d ƒ ‚ d S(   sp   Mark a crash id as reintroducing an earlier crash which is
        already marked as fixed (having ID 'master').s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   Ro   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyR9   ·  s    c         C   s   t  d ƒ ‚ d S(   s   Mark crash id as retraced.s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   mark_retraced½  s    c         C   s   t  d ƒ ‚ d S(   s  Mark crash id as 'failed to retrace'.

        If invalid_msg is given, the bug should be closed as invalid with given
        message, otherwise just marked as a failed retrace.
        
        This can be a no-op if you are not interested in this.
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   t   invalid_msg(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   mark_retrace_failedÂ  s    c         C   s   t  d ƒ ‚ d S(   s‹   Mark crash id as checked for being a duplicate
        
        This is an internal method that should not be called from outside.
        s6   this method must be implemented by a concrete subclassN(   RU   (   R   R:   R;   (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyR0   Ì  s    N("   t   __name__t
   __module__R   R   R%   R   RB   RF   RG   RJ   R2   t   FalseRO   R4   RW   RY   R/   R^   Rc   Rf   Rg   Rh   Ri   Rj   RR   Rk   Rl   Rm   Rn   R8   R9   Rp   Rr   R0   (    (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyR      s>   			 a			
		(	
												
				
c         C   s{  | s t  j j d d ƒ } n  i  } t | | ƒ | d } t  j j | ƒ rî xž t  j | ƒ D]Š } t  j j | | ƒ } t  j j | ƒ r] | j	 d ƒ r] y t | | d ƒ Wqç t
 k
 rã } t j j d | t | ƒ f ƒ qç Xq] q] Wn  | s| d } n  | d | } | j d ƒ }	 |	 sB| d | d j d ƒ }	 n  t d	 | d
 t ƒ  t ƒ  d g ƒ }
 |
 j |  |	 | ƒ S(   sw  Return a CrashDatabase object for the given crash db name.
    
    This reads the configuration file 'conf'.
    
    If name is None, it defaults to the 'default' value in conf.

    If conf is None, it defaults to the environment variable
    APPORT_CRASHDB_CONF; if that does not exist, the hardcoded default is
    /etc/apport/crashdb.conf. This Python syntax file needs to specify:

    - A string variable 'default', giving a default value for 'name' if that is
      None.

    - A dictionary 'databases' which maps names to crash db configuration
      dictionaries. These need to have at least the keys 'impl' (Python module
      in apport.crashdb_impl which contains a concrete 'CrashDatabase' class
      implementation for that crash db type) and 'bug_pattern_url', which
      specifies an URL for bug patterns (or None if those are not used for that
      crash db).
    t   APPORT_CRASHDB_CONFs   /etc/apport/crashdb.confs   .ds   .conft	   databasess   Invalid file %s: %s
t   defaultt   bug_pattern_urls   apport.crashdb_impl.R   R   (   R   t   environt   gett   execfileR   t   isdirt   listdirt   joint   isfilet   endswithR    t   syst   stderrt   writeR   t
   __import__t   globalst   localsR   (   R	   t   namet   conft   settingst   confdDirt   cft   cfpatht   et   dbRy   t   m(    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   get_crashdb×  s,    
! &t   NeedsCredentialsc           B   s   e  Z d  Z RS(   s8   This may be raised when unable to log in to the crashdb.(   Rs   Rt   t   __doc__(    (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyR’     s   (   R“   R   t   os.patht   datetimeR‚   t
   exceptionsR    t   packaging_implR   R'   R   R   R   R‘   R’   (    (    (    s2   /usr/lib/python2.7/dist-packages/apport/crashdb.pyt   <module>   s   0	ÿ À4