r286 - in branches/rewrite: . src

Otavio Salvador partial-mirror-devel@lists.alioth.debian.org
Wed, 10 Nov 2004 16:20:43 -0700


Author: otavio
Date: Wed Nov 10 16:20:42 2004
New Revision: 286

Modified:
   branches/rewrite/   (props changed)
   branches/rewrite/src/DisplayInfo.py
   branches/rewrite/src/Download.py
Log:
 r213@nurf:  otavio | 2004-11-10T23:19:40.486144Z
 Reimplement DisplayInfo in new way, proposed by Enrico.


Modified: branches/rewrite/src/DisplayInfo.py
==============================================================================
--- branches/rewrite/src/DisplayInfo.py	(original)
+++ branches/rewrite/src/DisplayInfo.py	Wed Nov 10 16:20:42 2004
@@ -1,5 +1,5 @@
 # debpartial-mirror - partial debian mirror package tool
-# (c) 2004 Otavio Salvador <otavio@debian.org>
+# (c) 2004 Otavio Salvador <otavio@debian.org>, Enrico Zini <enrico@debian.org>
 #
 # 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
@@ -17,51 +17,81 @@
 # $Id$
 
 import sys
-import os
+from os.path import basename
 
-class BaseDisplayInfo:
-    _info_windows = []
-
-    def add(self, window):
-        if window not in self._info_windows:
-            self._info_windows.append(window)
-
-    def remove(self, window):
-        if window in self._info_windows:
-            self._info_windows.remove(window)
-            
-    def refresh(self):
-        map(lambda x: x.refresh(), self._info_windows)
-
-    def done(self, file):
-        pass
-
-    def failed(self, file):
-        pass
-
-class TextDisplayInfo(BaseDisplayInfo):
-    def refresh(self):
-        sys.stdout.write('\r' + (" "*80) + '\r')
-        BaseDisplayInfo.refresh(self)
-
-    def done(self, file):
-        sys.stdout.write("\rDone: %s\n" % file)
-
-    def failed(self, file):
-        sys.stdout.write("\rFailed: %s\n" % file)
-
-class TextProgressBar:
-    def __init__(self, min=0, max=100, text=''):
-        self.min = min
-        self.max = max
-        self.text = text
-        self.current = min
-
-    def refresh(self):
-        try:
-            sys.stdout.write("[%s: %.2f%%]" % (os.path.basename(self.text).split('_')[0],
-                                               self.current*100/(self.max - self.min)))
-        except ZeroDivisionError:
-            pass
+class StatusItem:
+    id = 0
+    def __init__(self):
+        self._properties = None
+        
+    def __getitem__(self, key):
+        if key not in ['id', 'finished', 'current', 'size', 'errored']:
+            raise KeyError("%s is not allowed on StatusItem." % key)
+
+        if self._properties is None:
+            StatusItem.id += 1
+            self._properties = {'id'      : StatusItem.id,
+                                'finished': False,
+                                'current' : 0,
+                                'size'    : 0,
+                                'errored' : ''}
+
+        return self._properties.get(key)
+
+    def __setitem__(self, key, value):
+        if key not in ['id', 'finished', 'current', 'size', 'errored']:
+            raise KeyError("%s is not allowed on StatusItem." % key)
+
+        if self._properties is None:
+            StatusItem.id += 1
+            self._properties = {'id'      : StatusItem.id,
+                                'finished': False,
+                                'current' : 0,
+                                'size'    : 0,
+                                'errored' : ''}
+
+        self._properties[key] = value
+
+class BaseDisplayStatus:
+    _items = {}
+
+    def __getitem__ (self, key):
+        return self._items.get(key, None)
+
+    def start(self, url, size):
+        self._items[url] = StatusItem()
+        self._items[url]['size'] = size
+        
+    def update(self, url, current):
+        self._items[url]['current'] = current
+        
+    def errored(self, url, message):
+        if not self._items.has_key(url):
+            self._items[url] = StatusItem()
+        self._items[url]['errored'] = message
+
+class TextDisplayStatus(BaseDisplayStatus):
+    def start(self, url, size):
+        BaseDisplayStatus.start(self, url, size)
+        sys.stdout.write("\r" + " " * 80 + "\rGetting %d: %s\n" % (self._items[url]['id'], url))
+        
+    def update(self, url, current):
+        BaseDisplayStatus.update(self, url, current)
+        if self._items[url]['current'] == self._items[url]['size']:
+            self._items[url]['finished'] = True
+        sys.stdout.write("\r" + " " * 80 + "\r")
+        for url in self._items.keys():
+            if self._items[url]['finished'] or self._items[url]['errored']:
+                continue
+            try:
+                sys.stdout.write("[%d %s: %.2f%%]" % (self._items[url]['id'],
+                                                      basename(url).split('_')[0],
+                                                      self._items[url]['current']*100/(self._items[url]['size'])))
+            except ZeroDivisionError:
+                pass
 
         sys.stdout.flush()
+
+    def errored(self, url, message):
+        BaseDisplayStatus.errored(self, url, message)
+        sys.stdout.write("\r" + " " * 80 + "\rFailed: %s\n" % url)

Modified: branches/rewrite/src/Download.py
==============================================================================
--- branches/rewrite/src/Download.py	(original)
+++ branches/rewrite/src/Download.py	Wed Nov 10 16:20:42 2004
@@ -31,24 +31,18 @@
             self.queue.append(item)
 
 class DownloadThread(threading.Thread):
-    """ Implement a Download Thread and use a DisplayInfo class to
+    """ Implement a Download Thread and use a DisplayStatus class to
     notify the user about what it's currently doing."""
     _Lock = threading.Lock()
 
-    DisplayInfo = None
+    DisplayStatus = None
     
-    def __init__(self, info = None, progress = None):
+    def __init__(self, info = None):
         if info == None:
-            self.DisplayInfo = TextDisplayInfo()
+            self.DisplayStatus = TextDisplayStatus()
         else:
-            self.DisplayInfo = info
-            
-        if progress == None:
-            self._ProgressBar = TextProgressBar()
-        else:
-            self._ProgressBar = progress
+            self.DisplayStatus = info
 
-        self.DisplayInfo.add(self._ProgressBar)
         threading.Thread.__init__(self)
         
     def run(self):
@@ -56,14 +50,14 @@
             try:
                 url, filename = Download.queue.get_nowait()
             except Empty:
-                self.DisplayInfo.remove(self._ProgressBar)
+                pass
                 
             f = open(filename, "wb")
             curl = pycurl.Curl()
             curl.setopt(pycurl.FOLLOWLOCATION, 1)
             curl.setopt(pycurl.MAXREDIRS, 5)
             curl.setopt(pycurl.URL, url)
-            curl.setopt(pycurl.WRITEDATA, f)
+            curl.setopt(pycurl.WRITEFUNCTION, f.write)
             curl.setopt(pycurl.NOSIGNAL, 1)
             curl.setopt(pycurl.CONNECTTIMEOUT, 30)
             curl.setopt(pycurl.PROGRESSFUNCTION, self.progress)
@@ -72,8 +66,6 @@
 
             self.url = url
 
-            self._ProgressBar.text = self.url
-
             # Store counter information about it
             self._Lock.acquire()
             DownloadQueue.counter += 1
@@ -83,13 +75,13 @@
             try:
                 curl.perform()
             except:
-                self.DisplayInfo.failed(url)
+                self.DisplayStatus.errored(url, "")
 
             curl.close()
             try:
                 f.close()
-            except IOError:
-                pass
+            except IOError, e:
+                print e
 
             # Store counter information about it
             self._Lock.acquire()
@@ -97,12 +89,10 @@
             self._counter = DownloadQueue.counter
             self._Lock.release()
 
-            self.DisplayInfo.done(url)
-
     def progress(self, download_t, download_d, upload_t, upload_d):
-        self._ProgressBar.max = download_t
-        self._ProgressBar.current = download_d
-        self.DisplayInfo.refresh()
+        if self.DisplayStatus[self.url] == None:
+            self.DisplayStatus.start(self.url, download_t)
+        self.DisplayStatus.update(self.url, download_d)
 
 class Download:
     """ Download queue """
@@ -110,7 +100,7 @@
     """ Fetcher to use """
     fetchers = []
 
-    def __init__(self, uri, destine, max_threads=2):
+    def __init__(self, uri, destine, max_threads=3):
         self.queue.put((uri, destine))
 
         # Alloc all needed threads.