log_source.py
changeset 54 b65a95eb9f6b
parent 50 f13cf27a360b
child 55 5667d2bbdc50
--- a/log_source.py	Mon Feb 09 03:05:43 2009 +0200
+++ b/log_source.py	Mon Feb 09 04:39:24 2009 +0200
@@ -2,7 +2,7 @@
     A source of IRC log files
 """
 
-import datetime, itertools
+import datetime, calendar, itertools
 import os, errno
 import pytz
 
@@ -24,10 +24,19 @@
         """
 
         abstract
+    
+    def get_month_days (self, dt) :
+        """
+            Get a set of dates, telling which days in the given month (as a datetime) have logs available
+        """
 
-class LogFile (LogSource) :
+        abstract
+        
+class LogFile (object) :
     """
         A file containing LogEvents
+
+        XXX: modify to implement LogSource?
     """
 
     def __init__ (self, path, parser, start_date=None, charset='utf-8', sep='\n') :
@@ -168,7 +177,7 @@
             for line in lines[:0:-1] :
                 yield line.decode(self.charset)
 
-    def get_latest (self, count) :
+    def read_latest (self, count) :
         """
             Returns up to count events, from the end of the file, or less, if the file doesn't contain that many lines.
         """
@@ -221,9 +230,12 @@
         # convert to date and use that
         return self._get_logfile_date(dtz.date())
 
-    def _get_logfile_date (self, d) :
+    def _get_logfile_date (self, d, load=True) :
         """
-            Get the logfile corresponding to the given naive date in our timezone
+            Get the logfile corresponding to the given naive date in our timezone. If load is False, only test for the
+            presence of the logfile, do not actually open it.
+
+            Returns None if the logfile does not exist.
         """
 
         # format filename
@@ -231,9 +243,24 @@
 
         # build path
         path = os.path.join(self.path, filename)
+        
+        try :
+            if load :
+                # open+return the LogFile
+                return LogFile(path, self.parser, d, self.charset)
+            
+            else :
+                # test
+                return os.path.exists(path)
 
-        # return the LogFile
-        return LogFile(path, self.parser, d, self.charset)
+        # XXX: move to LogFile
+        except IOError, e :
+            # return None for missing files
+            if e.errno == errno.ENOENT :
+                return None
+
+            else :
+                raise
     
     def _iter_date_reverse (self, dt=None) :
         """
@@ -280,18 +307,13 @@
         while len(lines) < count :
             logfile = None
 
-            try :
-                # get next logfile
-                files += 1
-                
-                # open
-                logfile = self._get_logfile_date(day_iter.next())
+            # get next logfile
+            files += 1
             
-            except IOError, e :
-                # skip nonexistant days if we haven't found any logs yet
-                if e.errno != errno.ENOENT :
-                    raise
-
+            # open
+            logfile = self._get_logfile_date(day_iter.next())
+            
+            if not logfile :
                 if files > MAX_FILES :
                     raise Exception("No recent logfiles found")
                 
@@ -301,7 +323,7 @@
             
             # read the events
             # XXX: use a queue
-            lines = list(logfile.get_latest(count)) + lines
+            lines = list(logfile.read_latest(count)) + lines
         
         # return the events
         return lines
@@ -333,3 +355,27 @@
             # chain together the two sources
             return itertools.chain(f_begin.read_from(dtz_begin), f_end.read_until(dtz_end))
 
+    def get_month_days (self, month) :
+        """
+            Returns a set of dates for which logfiles are available in the given datetime's month
+        """
+        
+        # the set of days
+        days = set()
+        
+        # iterate over month's days using Calendar
+        for date in calendar.Calendar().itermonthdates(month.year, month.month) :
+            # convert date to target datetime
+            dtz = month.tzinfo.localize(datetime.datetime.combine(date, datetime.time(0))).astimezone(self.tz)
+
+            # date in our target timezone
+            log_date = dtz.date()
+            
+            # test for it
+            if self._get_logfile_date(log_date, load=False) :
+                # add to set
+                days.add(date)
+
+        # return set
+        return days
+