Back to index

moin  1.9.0~rc2
Public Member Functions | Public Attributes | Private Attributes
MoinMoin.logfile.editlog.EditLog Class Reference
Inheritance diagram for MoinMoin.logfile.editlog.EditLog:
Inheritance graph
[legend]
Collaboration diagram for MoinMoin.logfile.editlog.EditLog:
Collaboration graph
[legend]

List of all members.

Public Member Functions

def __init__
def add
def parser
def set_filter
def news
def __iter__
def reverse
def sanityCheck
def __getattr__
def size
def lines
def date
def peek
def next
def previous
def to_begin
def to_end
def position
def seek
def line_no
def calculate_line_no
def add

Public Attributes

 uid_override
 filter
 loglevel
 buffer_size

Private Attributes

 _NUM_FIELDS
 _usercache

Detailed Description

Used for accessing the global edit-log (e.g. by RecentChanges) as
    well as for the local edit-log (e.g. PageEditor, info action).

Definition at line 147 of file editlog.py.


Constructor & Destructor Documentation

def MoinMoin.logfile.editlog.EditLog.__init__ (   self,
  request,
  filename = None,
  buffer_size = 4096,
  kw 
)

Definition at line 151 of file editlog.py.

00151 
00152     def __init__(self, request, filename=None, buffer_size=4096, **kw):
00153         if filename is None:
00154             rootpagename = kw.get('rootpagename', None)
00155             if rootpagename:
00156                 filename = Page(request, rootpagename).getPagePath('edit-log', isfile=1)
00157             else:
00158                 filename = request.rootpage.getPagePath('edit-log', isfile=1)
00159         LogFile.__init__(self, filename, buffer_size)
00160         self._NUM_FIELDS = 9
00161         self._usercache = {}
00162 
00163         # Used by antispam in order to show an internal name instead
00164         # of a confusing userid
00165         self.uid_override = kw.get('uid_override', None)


Member Function Documentation

def MoinMoin.logfile.LogFile.__getattr__ (   self,
  name 
) [inherited]
generate some attributes when needed

Definition at line 130 of file __init__.py.

00130 
00131     def __getattr__(self, name):
00132         """
00133         generate some attributes when needed
00134         """
00135         if name == "_LogFile__rel_index": # Python black magic: this is the real name of the __rel_index attribute
00136             # starting iteration from begin
00137             self.__buffer1 = LineBuffer(self._input, 0, self.buffer_size)
00138             self.__buffer2 = LineBuffer(self._input,
00139                                         self.__buffer1.offsets[-1],
00140                                         self.buffer_size)
00141             self.__buffer = self.__buffer1
00142             self.__rel_index = 0
00143             return 0
00144         elif name == "_input":
00145             try:
00146                 # Open the file (NOT using codecs.open, it breaks our offset calculation. We decode it later.).
00147                 # Use binary mode in order to retain \r - otherwise the offset calculation would fail.
00148                 self._input = file(self.__filename, "rb", )
00149             except IOError, err:
00150                 if err.errno == errno.ENOENT: # "file not found"
00151                     # XXX workaround if edit-log does not exist: just create it empty
00152                     # if this workaround raises another error, we don't catch
00153                     # it, so the admin will see it.
00154                     f = file(self.__filename, "ab")
00155                     f.write('')
00156                     f.close()
00157                     self._input = file(self.__filename, "rb", )
00158                 else:
00159                     logging.error("logfile: %r IOERROR errno %d (%s)" % (self.__filename, err.errno, os.strerror(err.errno)))
00160                     raise
00161             return self._input
00162         elif name == "_output":
00163             self._output = codecs.open(self.__filename, 'a', config.charset)
00164             return self._output
00165         else:
00166             raise AttributeError(name)

def MoinMoin.logfile.LogFile.__iter__ (   self) [inherited]

Definition at line 104 of file __init__.py.

00104 
00105     def __iter__(self):
00106         return self

def MoinMoin.logfile.editlog.EditLog.add (   self,
  request,
  mtime,
  rev,
  action,
  pagename,
  host = None,
  extra = u'',
  comment = u'' 
)
Generate (and add) a line to the edit-log.

If `host` is None, it's read from request vars.

Definition at line 166 of file editlog.py.

00166 
00167     def add(self, request, mtime, rev, action, pagename, host=None, extra=u'', comment=u''):
00168         """ Generate (and add) a line to the edit-log.
00169 
00170         If `host` is None, it's read from request vars.
00171         """
00172         if request.cfg.log_remote_addr:
00173             if host is None:
00174                 host = request.remote_addr or ''
00175 
00176             if request.cfg.log_reverse_dns_lookups:
00177                 import socket
00178                 try:
00179                     hostname = socket.gethostbyaddr(host)[0]
00180                     hostname = unicode(hostname, config.charset)
00181                 except (socket.error, UnicodeError):
00182                     hostname = host
00183             else:
00184                 hostname = host
00185         else:
00186             host = ''
00187             hostname = ''
00188 
00189         comment = wikiutil.clean_input(comment)
00190         user_id = request.user.valid and request.user.id or ''
00191 
00192         if self.uid_override is not None:
00193             user_id = ''
00194             hostname = self.uid_override
00195             host = ''
00196 
00197         line = u"\t".join((str(long(mtime)), # has to be long for py 2.2.x
00198                            "%08d" % rev,
00199                            action,
00200                            wikiutil.quoteWikinameFS(pagename),
00201                            host,
00202                            hostname,
00203                            user_id,
00204                            extra,
00205                            comment,
00206                            )) + "\n"
00207         self._add(line)

Here is the call graph for this function:

Here is the caller graph for this function:

def MoinMoin.logfile.LogFile.add (   self,
  data 
) [inherited]
add line to log file
This implementation save the values as TAB separated strings.
This method should be overwritten by the sub classes.

Definition at line 442 of file __init__.py.

00442 
00443     def add(self, *data):
00444         """
00445         add line to log file
00446         This implementation save the values as TAB separated strings.
00447         This method should be overwritten by the sub classes.
00448         """
00449         line = "\t".join(data)
00450         self._add(line)

Here is the call graph for this function:

Here is the caller graph for this function:

def MoinMoin.logfile.LogFile.calculate_line_no (   self) [inherited]
Calculate the current line number from buffer offsets

If line number is unknown it is calculated by parsing the whole file.
This may be expensive.

Definition at line 421 of file __init__.py.

00421 
00422     def calculate_line_no(self):
00423         """ Calculate the current line number from buffer offsets
00424 
00425         If line number is unknown it is calculated by parsing the whole file.
00426         This may be expensive.
00427         """
00428         self._input.seek(0, 0)
00429         lines = self._input.read(self.__buffer.offsets[self.__rel_index])
00430         self.__lineno = len(lines.splitlines())
00431         return self.__lineno

def MoinMoin.logfile.LogFile.date (   self) [inherited]
Return timestamp of log file in usecs 

Definition at line 206 of file __init__.py.

00206 
00207     def date(self):
00208         # ToDo check if we need this method
00209         """ Return timestamp of log file in usecs """
00210         try:
00211             mtime = os.path.getmtime(self.__filename)
00212         except OSError, err:
00213             if err.errno == errno.ENOENT:
00214                 # This can happen on fresh wiki when building the index
00215                 # Usually the first request will create an event log
00216                 raise LogMissing(str(err))
00217             raise
00218         return wikiutil.timestamp2version(mtime)

def MoinMoin.logfile.LogFile.line_no (   self) [inherited]
@return: the current line number or None if line number is unknown

Definition at line 417 of file __init__.py.

00417 
00418     def line_no(self):
00419         """@return: the current line number or None if line number is unknown"""
00420         return self.__lineno

def MoinMoin.logfile.LogFile.lines (   self) [inherited]
Return number of lines in the log file

Return 0 if the file does not exist. Raises other OSError.

Expensive for big log files - O(n)

@return: size of log file in lines
@rtype: Int

Definition at line 182 of file __init__.py.

00182 
00183     def lines(self):
00184         """ Return number of lines in the log file
00185 
00186         Return 0 if the file does not exist. Raises other OSError.
00187 
00188         Expensive for big log files - O(n)
00189 
00190         @return: size of log file in lines
00191         @rtype: Int
00192         """
00193         try:
00194             f = file(self.__filename, 'r')
00195             try:
00196                 count = 0
00197                 for line in f:
00198                     count += 1
00199                 return count
00200             finally:
00201                 f.close()
00202         except (OSError, IOError), err:
00203             if err.errno == errno.ENOENT:
00204                 return 0
00205             raise

def MoinMoin.logfile.editlog.EditLog.news (   self,
  oldposition 
)
What has changed in the edit-log since <oldposition>?
    Returns edit-log final position() and list of changed item names.

Definition at line 238 of file editlog.py.

00238 
00239     def news(self, oldposition):
00240         """ What has changed in the edit-log since <oldposition>?
00241             Returns edit-log final position() and list of changed item names.
00242         """
00243         if oldposition is None:
00244             self.to_end()
00245         else:
00246             self.seek(oldposition)
00247         items = []
00248         for line in self:
00249             items.append(line.pagename)
00250             if line.action == 'SAVE/RENAME':
00251                 items.append(line.extra) # == old page name
00252 
00253         newposition = self.position()
00254         logging.log(logging.NOTSET, "editlog.news: new pos: %r new items: %r", newposition, items)
00255         return newposition, items
00256 

Here is the call graph for this function:

def MoinMoin.logfile.LogFile.next (   self) [inherited]
get next line that passes through the filter
@return: next entry
raises StopIteration at file end

Definition at line 294 of file __init__.py.

00294 
00295     def next(self):
00296         """get next line that passes through the filter
00297         @return: next entry
00298         raises StopIteration at file end
00299         """
00300         result = None
00301         while result is None:
00302             while result is None:
00303                 logging.log(self.loglevel, "LogFile.next %s" % self.__filename)
00304                 result = self.__next()
00305             if self.filter and not self.filter(result):
00306                 result = None
00307         return result

Here is the call graph for this function:

Here is the caller graph for this function:

def MoinMoin.logfile.editlog.EditLog.parser (   self,
  line 
)
Parse edit-log line into fields 

Reimplemented from MoinMoin.logfile.LogFile.

Definition at line 208 of file editlog.py.

00208 
00209     def parser(self, line):
00210         """ Parse edit-log line into fields """
00211         fields = line.strip().split('\t')
00212         # Pad empty fields
00213         missing = self._NUM_FIELDS - len(fields)
00214         if missing:
00215             fields.extend([''] * missing)
00216         result = EditLogLine(self._usercache)
00217         (result.ed_time_usecs, result.rev, result.action,
00218          result.pagename, result.addr, result.hostname, result.userid,
00219          result.extra, result.comment, ) = fields[:self._NUM_FIELDS]
00220         if not result.hostname:
00221             result.hostname = result.addr
00222         result.pagename = wikiutil.unquoteWikiname(result.pagename.encode('ascii'))
00223         result.ed_time_usecs = long(result.ed_time_usecs or '0') # has to be long for py 2.2.x
00224         return result

def MoinMoin.logfile.LogFile.peek (   self,
  lines 
) [inherited]
Move position in file forward or backwards by "lines" count

It adjusts .__lineno if set.
This function is not aware of filters!

@param lines: number of lines, may be negative to move backward
@rtype: boolean
@return: True if moving more than to the beginning and moving
 to the end or beyond

Definition at line 219 of file __init__.py.

00219 
00220     def peek(self, lines):
00221         """ Move position in file forward or backwards by "lines" count
00222 
00223         It adjusts .__lineno if set.
00224         This function is not aware of filters!
00225 
00226         @param lines: number of lines, may be negative to move backward
00227         @rtype: boolean
00228         @return: True if moving more than to the beginning and moving
00229                  to the end or beyond
00230         """
00231         logging.log(self.loglevel, "LogFile.peek %s" % self.__filename)
00232         self.__rel_index += lines
00233         while self.__rel_index < 0:
00234             if self.__buffer is self.__buffer2:
00235                 if self.__buffer.offsets[0] == 0:
00236                     # already at the beginning of the file
00237                     self.__rel_index = 0
00238                     self.__lineno = 0
00239                     return True
00240                 else:
00241                     # change to buffer 1
00242                     self.__buffer = self.__buffer1
00243                     self.__rel_index += self.__buffer.len
00244             else: # self.__buffer is self.__buffer1
00245                 if self.__buffer.offsets[0] == 0:
00246                     # already at the beginning of the file
00247                     self.__rel_index = 0
00248                     self.__lineno = 0
00249                     return True
00250                 else:
00251                     # load previous lines
00252                     self.__buffer2 = self.__buffer1
00253                     self.__buffer1 = LineBuffer(self._input,
00254                                                 self.__buffer.offsets[0],
00255                                                 self.buffer_size,
00256                                                 forward=False)
00257                     self.__buffer = self.__buffer1
00258                     self.__rel_index += self.__buffer.len
00259 
00260         while self.__rel_index >= self.__buffer.len:
00261             if self.__buffer is self.__buffer1:
00262                 # change to buffer 2
00263                 self.__rel_index -= self.__buffer.len
00264                 self.__buffer = self.__buffer2
00265             else: # self.__buffer is self.__buffer2
00266                 # try to load next buffer
00267                 tmpbuff = LineBuffer(self._input,
00268                                      self.__buffer.offsets[-1],
00269                                      self.buffer_size)
00270                 if tmpbuff.len == 0:
00271                     # end of file
00272                     if self.__lineno is not None:
00273                         self.__lineno += (lines -
00274                                          (self.__rel_index - self.__buffer.len))
00275                     self.__rel_index = self.__buffer.len # point to after last read line
00276                     return True
00277                 # shift buffers
00278                 self.__rel_index -= self.__buffer.len
00279                 self.__buffer1 = self.__buffer2
00280                 self.__buffer2 = tmpbuff
00281                 self.__buffer = self.__buffer2
00282 
00283         if self.__lineno is not None:
00284             self.__lineno += lines
00285         return False

Here is the caller graph for this function:

def MoinMoin.logfile.LogFile.position (   self) [inherited]
Return the current file position

This can be converted into a String using back-ticks and then be rebuild.
For this plain file implementation position is an Integer.

Definition at line 361 of file __init__.py.

00361 
00362     def position(self):
00363         """ Return the current file position
00364 
00365         This can be converted into a String using back-ticks and then be rebuild.
00366         For this plain file implementation position is an Integer.
00367         """
00368         return self.__buffer.offsets[self.__rel_index]

Here is the caller graph for this function:

def MoinMoin.logfile.LogFile.previous (   self) [inherited]
get previous line that passes through the filter
@return: previous entry
raises StopIteration at file begin

Definition at line 314 of file __init__.py.

00314 
00315     def previous(self):
00316         """get previous line that passes through the filter
00317         @return: previous entry
00318         raises StopIteration at file begin
00319         """
00320         result = None
00321         while result is None:
00322             while result is None:
00323                 logging.log(self.loglevel, "LogFile.previous %s" % self.__filename)
00324                 result = self.__previous()
00325             if self.filter and not self.filter(result):
00326                 result = None
00327         return result

Here is the call graph for this function:

Here is the caller graph for this function:

def MoinMoin.logfile.LogFile.reverse (   self) [inherited]
yield log entries in reverse direction starting from last one

@rtype: iterator

Definition at line 107 of file __init__.py.

00107 
00108     def reverse(self):
00109         """ yield log entries in reverse direction starting from last one
00110 
00111         @rtype: iterator
00112         """
00113         self.to_end()
00114         while 1:
00115             try:
00116                 logging.log(self.loglevel, "LogFile.reverse %s" % self.__filename)
00117                 result = self.previous()
00118             except StopIteration:
00119                 return
00120             yield result

Here is the call graph for this function:

def MoinMoin.logfile.LogFile.sanityCheck (   self) [inherited]
Check for log file write access.

@rtype: string (error message) or None

Definition at line 121 of file __init__.py.

00121 
00122     def sanityCheck(self):
00123         """ Check for log file write access.
00124 
00125         @rtype: string (error message) or None
00126         """
00127         if not os.access(self.__filename, os.W_OK):
00128             return "The log '%s' is not writable!" % (self.__filename, )
00129         return None

def MoinMoin.logfile.LogFile.seek (   self,
  position,
  line_no = None 
) [inherited]
moves file position to an value formerly gotten from .position().
To enable line counting line_no must be provided.
.seek is much more efficient for moving long distances than .peek.
raises ValueError if position is invalid

Definition at line 369 of file __init__.py.

00369 
00370     def seek(self, position, line_no=None):
00371         """ moves file position to an value formerly gotten from .position().
00372         To enable line counting line_no must be provided.
00373         .seek is much more efficient for moving long distances than .peek.
00374         raises ValueError if position is invalid
00375         """
00376         logging.log(self.loglevel, "LogFile.seek %s pos %d" % (self.__filename, position))
00377         if self.__buffer1:
00378             logging.log(self.loglevel, "b1 %r %r" % (self.__buffer1.offsets[0], self.__buffer1.offsets[-1]))
00379         if self.__buffer2:
00380             logging.log(self.loglevel, "b2 %r %r" % (self.__buffer2.offsets[0], self.__buffer2.offsets[-1]))
00381         if self.__buffer1 and self.__buffer1.offsets[0] <= position < self.__buffer1.offsets[-1]:
00382             # position is in .__buffer1
00383             self.__rel_index = self.__buffer1.offsets.index(position)
00384             self.__buffer = self.__buffer1
00385         elif self.__buffer2 and self.__buffer2.offsets[0] <= position < self.__buffer2.offsets[-1]:
00386             # position is in .__buffer2
00387             self.__rel_index = self.__buffer2.offsets.index(position)
00388             self.__buffer = self.__buffer2
00389         elif self.__buffer1 and self.__buffer1.offsets[-1] == position:
00390             # we already have one buffer directly before where we want to go
00391             self.__buffer2 = LineBuffer(self._input,
00392                                         position,
00393                                         self.buffer_size)
00394             self.__buffer = self.__buffer2
00395             self.__rel_index = 0
00396         elif self.__buffer2 and self.__buffer2.offsets[-1] == position:
00397             # we already have one buffer directly before where we want to go
00398             self.__buffer1 = self.__buffer2
00399             self.__buffer2 = LineBuffer(self._input,
00400                                         position,
00401                                         self.buffer_size)
00402             self.__buffer = self.__buffer2
00403             self.__rel_index = 0
00404         else:
00405             # load buffers around position
00406             self.__buffer1 = LineBuffer(self._input,
00407                                         position,
00408                                         self.buffer_size,
00409                                         forward=False)
00410             self.__buffer2 = LineBuffer(self._input,
00411                                         position,
00412                                         self.buffer_size)
00413             self.__buffer = self.__buffer2
00414             self.__rel_index = 0
00415             # XXX test for valid position
00416         self.__lineno = line_no

Here is the caller graph for this function:

optionally filter for specific pagenames, addrs, hostnames, userids 

Definition at line 225 of file editlog.py.

00225 
00226     def set_filter(self, **kw):
00227         """ optionally filter for specific pagenames, addrs, hostnames, userids """
00228         expr = "1"
00229         for field in ['pagename', 'addr', 'hostname', 'userid']:
00230             if field in kw:
00231                 expr = "%s and x.%s == %s" % (expr, field, repr(kw[field]))
00232 
00233         if 'ed_time_usecs' in kw:
00234             expr = "%s and long(x.ed_time_usecs) == %s" % (expr, long(kw['ed_time_usecs'])) # must be long for py 2.2.x
00235 
00236         self.filter = eval("lambda x: " + expr)
00237 

def MoinMoin.logfile.LogFile.size (   self) [inherited]
Return log size in bytes

Return 0 if the file does not exist. Raises other OSError.

@return: size of log file in bytes
@rtype: Int

Definition at line 167 of file __init__.py.

00167 
00168     def size(self):
00169         """ Return log size in bytes
00170 
00171         Return 0 if the file does not exist. Raises other OSError.
00172 
00173         @return: size of log file in bytes
00174         @rtype: Int
00175         """
00176         try:
00177             return os.path.getsize(self.__filename)
00178         except OSError, err:
00179             if err.errno == errno.ENOENT:
00180                 return 0
00181             raise

def MoinMoin.logfile.LogFile.to_begin (   self) [inherited]
moves file position to the begin

Definition at line 328 of file __init__.py.

00328 
00329     def to_begin(self):
00330         """moves file position to the begin"""
00331         logging.log(self.loglevel, "LogFile.to_begin %s" % self.__filename)
00332         if self.__buffer1 is None or self.__buffer1.offsets[0] != 0:
00333             self.__buffer1 = LineBuffer(self._input,
00334                                         0,
00335                                         self.buffer_size)
00336             self.__buffer2 = LineBuffer(self._input,
00337                                         self.__buffer1.offsets[-1],
00338                                         self.buffer_size)
00339         self.__buffer = self.__buffer1
00340         self.__rel_index = 0
00341         self.__lineno = 0

def MoinMoin.logfile.LogFile.to_end (   self) [inherited]
moves file position to the end

Definition at line 342 of file __init__.py.

00342 
00343     def to_end(self):
00344         """moves file position to the end"""
00345         logging.log(self.loglevel, "LogFile.to_end %s" % self.__filename)
00346         self._input.seek(0, 2) # to end of file
00347         size = self._input.tell()
00348         if self.__buffer2 is None or size > self.__buffer2.offsets[-1]:
00349             self.__buffer2 = LineBuffer(self._input,
00350                                         size,
00351                                         self.buffer_size,
00352                                         forward=False)
00353 
00354             self.__buffer1 = LineBuffer(self._input,
00355                                         self.__buffer2.offsets[0],
00356                                         self.buffer_size,
00357                                         forward=False)
00358         self.__buffer = self.__buffer2
00359         self.__rel_index = self.__buffer2.len
00360         self.__lineno = None

Here is the caller graph for this function:


Member Data Documentation

Definition at line 159 of file editlog.py.

Definition at line 160 of file editlog.py.

Definition at line 100 of file __init__.py.

Reimplemented from MoinMoin.logfile.LogFile.

Definition at line 235 of file editlog.py.

Definition at line 95 of file __init__.py.

Definition at line 164 of file editlog.py.


The documentation for this class was generated from the following file: