[yum-git] Branch 'yum-3_2_X' - 2 commits - yum/rpmtrans.py

James Antill james at linux.duke.edu
Tue Sep 23 14:34:52 UTC 2008


 yum/rpmtrans.py |   59 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 51 insertions(+), 8 deletions(-)

New commits:
commit 0aed92573666a4e09650e5a5c0f25357ac957d2a
Author: James Antill <james at and.org>
Date:   Tue Sep 23 10:34:44 2008 -0400

     Protect I/O calls within RPMTransaction itself, due to rpm insane mode.
     Try and cleanup if they trigger, so we don't have half a transaction saved
    in the log files.

diff --git a/yum/rpmtrans.py b/yum/rpmtrans.py
index 98faa9a..0961b34 100644
--- a/yum/rpmtrans.py
+++ b/yum/rpmtrans.py
@@ -138,6 +138,11 @@ class SimpleCliCallBack(RPMBaseCallback):
         if msgs:
             print msgs,
 
+#  This is ugly, but atm. rpm can go insane and run the "cleanup" phase
+# without the "install" phase if it gets an exception in it's callback. The
+# following means that we don't really need to know/care about that in the
+# display callback functions.
+#  Note try/except's in RPMTransaction are for the same reason.
 class _WrapNoExceptions:
     def __init__(self, parent):
         self.__parent = parent
@@ -292,8 +297,17 @@ class RPMTransaction:
         # hope springs eternal that this isn't wrong
         msg = '%s %s:%s-%s-%s.%s\n' % (t,e,n,v,r,a)
 
-        self._ts_done.write(msg)
-        self._ts_done.flush()
+        try:
+            self._ts_done.write(msg)
+            self._ts_done.flush()
+        except (IOError, OSError), e:
+            try:
+                #  Having incomplete transactions is probably worse than having
+                # nothing.
+                del self._ts_done
+                os.unlink(self.ts_done_fn)
+            except:
+                pass
         self._te_tuples.pop(0)
     
     def ts_all(self):
@@ -333,12 +347,20 @@ class RPMTransaction:
             self.display.errorlog('could not open ts_all file: %s' % e)
             return
 
-        for (t,e,n,v,r,a) in self._te_tuples:
-            msg = "%s %s:%s-%s-%s.%s\n" % (t,e,n,v,r,a)
-            fo.write(msg)
-        fo.flush()
-        fo.close()
-    
+        try:
+            for (t,e,n,v,r,a) in self._te_tuples:
+                msg = "%s %s:%s-%s-%s.%s\n" % (t,e,n,v,r,a)
+                fo.write(msg)
+            fo.flush()
+            fo.close()
+        except (IOError, OSError), e:
+            try:
+                #  Having incomplete transactions is probably worse than having
+                # nothing.
+                os.unlink(self.ts_all_fn)
+            except:
+                pass
+
     def callback( self, what, bytes, total, h, user ):
         if what == rpm.RPMCALLBACK_TRANS_START:
             self._transStart( bytes, total, h )
commit cf896fc7ccc135aeb94d69739bb625fc44934377
Author: James Antill <james at and.org>
Date:   Tue Sep 23 10:25:05 2008 -0400

     Wrap all calls to the display callbacks within the rpm transaction.
     The problem here is that rpm gets _very_ unhappy if exceptions happen in
    any of the code it calls during the transaction, and can basically destroy
    the system (stopping the install phase but doing the cleanup phase).
    
     This doesn't 100% protect us, as we can still have errors in our code
    but it'll protect against anything in the callbacks.

diff --git a/yum/rpmtrans.py b/yum/rpmtrans.py
index 34fa178..98faa9a 100644
--- a/yum/rpmtrans.py
+++ b/yum/rpmtrans.py
@@ -138,12 +138,33 @@ class SimpleCliCallBack(RPMBaseCallback):
         if msgs:
             print msgs,
 
+class _WrapNoExceptions:
+    def __init__(self, parent):
+        self.__parent = parent
+
+    def __getattr__(self, name):
+        """ Wraps all access to the parent functions. This is so it'll eat all
+            exceptions because rpm doesn't like exceptions in the callback. """
+        func = getattr(self.__parent, name)
+
+        def newFunc(*args, **kwargs):
+            try:
+                func(*args, **kwargs)
+            except:
+                pass
+
+        newFunc.__name__ = func.__name__
+        newFunc.__doc__ = func.__doc__
+        newFunc.__dict__.update(func.__dict__)
+        return newFunc
+
 class RPMTransaction:
     def __init__(self, base, test=False, display=NoOutputCallBack):
         if not callable(display):
             self.display = display
         else:
             self.display = display() # display callback
+        self.display = _WrapNoExceptions(self.display)
         self.base = base # base yum object b/c we need so much
         self.test = test # are we a test?
         self.trans_running = False



More information about the Yum-cvs-commits mailing list