damned-lies r1233 - in trunk: . stats stats/management/commands stats/tests



Author: claudep
Date: Sat Dec 20 22:07:55 2008
New Revision: 1233
URL: http://svn.gnome.org/viewvc/damned-lies?rev=1233&view=rev

Log:
2008-12-20  Claude Paroz  <claude 2xlibre net>

	* stats/management/commands/update-stats.py: Enclose update_stats in a try
	statement so as failure doesn't stop further updates. 
	* stats/models.py: Use exceptions for handling errors in checkout().
	Use thread locking to prevent concurrent VCS checkout (in a same branch
	instance).
	Fix save() signature.
	Subclass delete() function for branches to remove a VCS repo on the
	filesystem when the branch is deleted.
	* stats/tests/__init__.py: Add basic unit tests.

Added:
   trunk/stats/tests/
   trunk/stats/tests/__init__.py
Modified:
   trunk/ChangeLog
   trunk/stats/management/commands/update-stats.py
   trunk/stats/models.py

Modified: trunk/stats/management/commands/update-stats.py
==============================================================================
--- trunk/stats/management/commands/update-stats.py	(original)
+++ trunk/stats/management/commands/update-stats.py	Sat Dec 20 22:07:55 2008
@@ -42,7 +42,10 @@
                 print "Updating stats for %s..." % (module_arg)
                 branches = Branch.objects.filter(module__name=module_arg)
                 for branch in branches.all():
-                    branch.update_stats(options['force'])
+                    try:
+                        branch.update_stats(options['force'])
+                    except: 
+                        print "Error while updating stats for %s (branch '%s')" % (module_arg, branch.name)
             else:
                 # Update all modules
                 modules = Module.objects.all()
@@ -50,7 +53,10 @@
                     print "Updating stats for %s..." % (mod.name)
                     branches = Branch.objects.filter(module__name=mod)
                     for branch in branches.all():
-                        branch.update_stats(options['force'])
+                        try:
+                            branch.update_stats(options['force'])
+                        except:
+                            print "Error while updating stats for %s (branch '%s')" % (module_arg, branch.name)
         else:
             return "Too much command line arguments."
 

Modified: trunk/stats/models.py
==============================================================================
--- trunk/stats/models.py	(original)
+++ trunk/stats/models.py	Sat Dec 20 22:07:55 2008
@@ -116,7 +116,9 @@
 class BranchCharField(models.CharField):
     def pre_save(self, model_instance, add):
         """ Check if branch is valid before saving the instance """
-        if not model_instance.checkout():
+        try:
+            model_instance.checkout()
+        except:
             raise ValueError("Branch not valid: error while checking out the branch.")
         return getattr(model_instance, self.attname)
 
@@ -134,14 +136,26 @@
         ordering = ('name',)
         unique_together = ('name', 'module')
 
+    def __init__(self, *args, **kwargs):
+        models.Model.__init__(self, *args, **kwargs)
+        self.checkout_lock = threading.Lock()
+
     def __unicode__(self):
         return "%s (%s)" % (self.name, self.module)
 
-    def save(self):
-        super(Branch, self).save()
+    def save(self, force_insert=False, force_update=False):
+        super(Branch, self).save(force_insert, force_update)
         # The update command is launched asynchronously in a separate thread
         upd_thread = threading.Thread(target=self.update_stats, kwargs={'force':True})
         upd_thread.start()
+    
+    def delete(self):
+        # Remove the repo checkout
+        localdir = os.path.join(settings.SCRATCHDIR, self.module.vcs_type, self.module.name + "." + self.name)
+        if os.access(localdir, os.W_OK):
+            import shutil # os.rmdir cannot delete non-empty dirs
+            shutil.rmtree(localdir)
+        models.Model.delete(self)
 
     def __cmp__(self, other):
         if self.name in BRANCH_HEAD_NAMES:
@@ -444,24 +458,22 @@
                     })
         
         # Run command(s)
-        errorsOccured = 0
         if settings.DEBUG:
             print >>sys.stdout, "Checking '%s.%s' out to '%s'..." % (module_name, self.name, modulepath)
-        for command in commandList:
-            if settings.DEBUG:
-                print >>sys.stdout, command
-            (error, output) = commands.getstatusoutput(command)
-            if settings.DEBUG:
-                print >> sys.stderr, output
-            if error:
-                errorsOccured = 1
+        # Do not allow 2 checkouts to run in parallel on the same branch
+        self.checkout_lock.acquire()
+        try:
+            for command in commandList:
                 if settings.DEBUG:
-                    print >> sys.stderr, error
-        if errorsOccured:
-            print >> sys.stderr, "Problem checking out module %s.%s" % (module_name, self.name)
-            return 0
-        else:
-            return 1
+                    print >>sys.stdout, command
+                (error, output) = commands.getstatusoutput(command)
+                if settings.DEBUG:
+                    print >> sys.stderr, output
+                if error:
+                    raise OSError(error, output)
+        finally:
+            self.checkout_lock.release()
+        return 1
 
 
 DOMAIN_TYPE_CHOICES = (

Added: trunk/stats/tests/__init__.py
==============================================================================
--- (empty file)
+++ trunk/stats/tests/__init__.py	Sat Dec 20 22:07:55 2008
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2008 Claude Paroz <claude 2xlibre net>
+#
+# This file is part of Damned Lies.
+#
+# Damned Lies 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.
+#
+# Damned Lies 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.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Damned Lies; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import unittest
+import threading
+from stats.models import Module, Domain, Branch, Statistics
+
+class ModuleTestCase(unittest.TestCase):
+    def setUp(self):
+        self.mod = Module(name="gnome-hello",
+                          bugs_base="http://bugzilla.gnome.org";,
+                          bugs_product="test", # This product really exists
+                          bugs_component="test",
+                          vcs_type="svn",
+                          vcs_root="http://svn.gnome.org/svn";,
+                          vcs_web="http://svn.gnome.org/viewvc/gnome-hello";)
+        self.mod.save()
+        dom = Domain(module=self.mod, name='po', description='UI Translations', dtype='ui', directory='po')
+        dom.save()
+        dom = Domain(module=self.mod, name='help', description='User Guide', dtype='doc', directory='help')
+        dom.save()
+            
+    def testModuleFunctions(self):
+        self.assertEquals(self.mod.get_description(), 'gnome-hello')
+        
+    def testBranch(self):
+        # Create branch (include checkout)
+        branch = Branch(name="trunk",
+                        module = self.mod)
+        branch.save()
+        
+        self.assertEquals(branch.is_head(), True)
+        self.assertEquals(branch.get_vcs_url(), "http://svn.gnome.org/svn/gnome-hello/trunk";)
+        self.assertEquals(branch.get_vcs_web_url(), "http://svn.gnome.org/viewvc/gnome-hello/trunk";)
+        
+        # save() launch update_stats in a separate thread, wait for the thread to end before pursuing the tests
+        for th in threading.enumerate():
+            if th != threading.currentThread():
+                print "Waiting for thread %s to finish" % th.getName()
+                th.join()
+        
+        # Check stats
+        fr_po_stat = Statistics.objects.get(branch=branch, domain__name='po', language__locale='fr')
+        self.assertEquals(fr_po_stat.translated, 40)
+        fr_doc_stat = Statistics.objects.get(branch=branch, domain__name='help', language__locale='fr')
+        self.assertEquals(fr_doc_stat.translated, 36)
+        
+        # Delete branch to remove the repo checkout
+        branch.delete()
+        
+        # TODO: Try to create a non-existing branch...



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]