Example #1
0
 def addLogEntry(self, entry, save=True):
     """This is called when a new log entry is created"""
     # create log directory if it doesn't exist
     # error will be thrown if this is not possible
     _busy = Purr.BusyIndicator()
     self._initIndexDir()
     # discard temporary watchers -- these are only used to keep track of
     # deleted files
     self.temp_watchers = {}
     # ignored entries are only there to carry info on ignored data products
     # All we do is save them, and update DP policies based on them
     if entry.ignore:
         entry.save(self.logdir)
     # proper entries are added to list
     else:
         self.entries.append(entry)
         Purr.progressMessage("Saving new log entry")
         # find previous entry -- skip over "ignore" entries
         for prev in self.entries[-2::-1]:
             if not prev.ignore:
                 break
         else:
             prev = None
         entry.setLogDirectory(self.logdir)
         entry.setPrevUpNextLinks(prev=prev,
                                  up=os.path.join("..",
                                                  Purr.RenderIndex.INDEX))
         entry.save()
         self.timestamp = self.last_scan_timestamp
         # regenerate links of previous entry
         prev and prev.generateIndex()
         # and our log may need to be regenerated
         if save:
             self.save()
     self.updatePoliciesFromEntry(entry, new=True)
Example #2
0
 def save(self, refresh=False):
     """Saves the log.
     If refresh is set to a timestamp, will regenerate everything from scratch.
     """
     # create directory if it doesn't exist
     # error will be thrown if this is not possible
     _busy = Purr.BusyIndicator()
     Purr.progressMessage("Generating index in %s" % self.logdir)
     self._initIndexDir()
     # if refresh is True, re-save all entries.
     if refresh:
         refresh = time.time()
         for i, entry in enumerate(self.entries):
             entry.save(refresh=refresh)
     Purr.RenderIndex.writeLogIndex(self.logdir,
                                    self.logtitle,
                                    self.timestamp,
                                    self.entries,
                                    refresh=refresh)
     Purr.progressMessage("Wrote %s" % self.logdir)
Example #3
0
 def _attach(self, purrlog, watchdirs=None):
     """Attaches Purr to a purrlog directory, and loads content.
     Returns False if nothing new has been loaded (because directory is the same),
     or True otherwise."""
     purrlog = os.path.abspath(purrlog)
     dprint(1, "attaching to purrlog", purrlog)
     self.logdir = purrlog
     self.indexfile = os.path.join(self.logdir, "index.html")
     self.logtitle = "Unnamed log"
     self.timestamp = self.last_scan_timestamp = time.time()
     self._initIndexDir()
     # reset internal state
     self.ignorelistfile = None
     self.autopounce = False
     self.watched_dirs = []
     self.entries = []
     self._default_dp_props = {}
     self.watchers = {}
     self.temp_watchers = {}
     self.attached = False
     self._watching_state = {}
     # check that we hold a lock on the directory
     self.lockfile = os.path.join(self.logdir, ".purrlock")
     # try to open lock file for r/w
     try:
         self.lockfile_fd = os.open(self.lockfile, os.O_RDWR | os.O_CREAT)
     except:
         raise Purrer.LockFailError(
             "failed to open lock file %s for writing" % self.lockfile)
     # try to acquire lock on the lock file
     try:
         fcntl.lockf(self.lockfile_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
     except:
         other_lock = os.fdopen(self.lockfile_fd, 'r').read()
         self.lockfile_fd = None
         raise Purrer.LockedError(other_lock)
     # got lock, write our ID to the lock file
     global _lockstring
     try:
         self.lockfile_fobj = os.fdopen(self.lockfile_fd, 'w')
         self.lockfile_fobj.write(_lockstring)
         self.lockfile_fobj.flush()
         os.fsync(self.lockfile_fd)
     except:
         raise
     #      raise Purrer.LockFailError("cannot write to lock file %s"%self.lockfile)
     # load log state if log directory already exists
     if os.path.exists(self.logdir):
         _busy = Purr.BusyIndicator()
         if os.path.exists(self.indexfile):
             try:
                 parser = Purr.Parsers.LogIndexParser()
                 for line in open(self.indexfile):
                     parser.feed(line)
                 self.logtitle = parser.title or self.logtitle
                 self.timestamp = parser.timestamp or self.timestamp
                 dprintf(
                     2, "attached log '%s', timestamp %s\n", self.logtitle,
                     time.strftime("%x %X", time.localtime(self.timestamp)))
             except:
                 traceback.print_exc()
                 print("Error parsing %s, reverting to defaults" %
                       self.indexfile)
         # load log entries
         entries = []
         for fname in os.listdir(self.logdir):
             pathname = os.path.join(self.logdir, fname)
             if Purr.LogEntry.isValidPathname(pathname):
                 try:
                     entry = Purr.LogEntry(load=pathname)
                     dprint(2, "loaded log entry", pathname)
                 except:
                     print("Error loading entry %s, skipping" % fname)
                     traceback.print_exc()
                     continue
                 entries.append(entry)
             else:
                 dprint(2, fname, "is not a valid Purr entry")
         # sort log entires by timestamp
         entries.sort(lambda a, b: cmp(a.timestamp, b.timestamp))
         self.setLogEntries(entries, save=False)
         # update own timestamp
         if entries:
             self.timestamp = max(self.timestamp, entries[-1].timestamp)
     # else logfile doesn't exist, create it
     else:
         self._initIndexDir()
     # load configuration if it exists
     # init config file
     self.dirconfig = configparser.RawConfigParser()
     self.dirconfigfile = os.path.join(self.logdir, "dirconfig")
     if os.path.exists(self.dirconfigfile):
         try:
             self.dirconfig.read(self.dirconfigfile)
         except:
             print("Error loading config file %s" % self.dirconfigfile)
             traceback.print_exc()
         # load directory configuration
         for dirname in self.dirconfig.sections():
             try:
                 watching = self.dirconfig.getint(dirname, "watching")
             except:
                 watching = Purr.WATCHED
             dirname = os.path.expanduser(dirname)
             self.addWatchedDirectory(dirname, watching, save_config=False)
     # start watching the specified directories
     for name in (watchdirs or []):
         self.addWatchedDirectory(name, watching=None)
     # Finally, go through list of ignored files and mark their watchers accordingly.
     # The ignorelist is a list of lines of the form "timestamp filename", giving the timestamp when a
     # file was last "ignored" by the purrlog user.
     self.ignorelistfile = os.path.join(self.logdir, "ignorelist")
     if os.path.exists(self.ignorelistfile):
         # read lines from file, ignore exceptions
         ignores = {}
         try:
             for line in open(self.ignorelistfile).readlines():
                 timestamp, policy, filename = line.strip().split(" ", 2)
                 # update dictiornary with latest timestamp
                 ignores[filename] = int(timestamp), policy
         except:
             print("Error reading %s" % self.ignorelistfile)
             traceback.print_exc()
         # now scan all listed files, and make sure their watchers' mtime is no older than the given
         # last-ignore-timestamp. This ensures that we don't pounce on these files after restarting purr.
         for filename, (timestamp, policy) in ignores.items():
             watcher = self.watchers.get(filename, None)
             if watcher:
                 watcher.mtime = max(watcher.mtime, timestamp)
     # init complete
     self.attached = True
     return True
Example #4
0
 def restore_from_archive(self, parent=None):
     """Function to restore a DP from archived copy
     Asks for confirmation along the way if parent is not None
     (in which case it will be the parent widget for confirmation dialogs)
     """
     from PyQt4.Qt import QMessageBox
     exists = os.path.exists(self.sourcepath)
     if parent:
         msg = """<P>Do you really want to restore <tt>%s</tt> from
         this entry's copy of <tt>%s</tt>?</P>""" % (self.sourcepath,
                                                     self.filename)
         exists = os.path.exists(self.sourcepath)
         if exists:
             msg += """<P>Current file exists, and will be overwritten.</P>"""
             if QMessageBox.warning(parent, "Restoring from archive", msg,
                                    QMessageBox.Yes,
                                    QMessageBox.No) != QMessageBox.Yes:
                 return False
         else:
             if QMessageBox.question(parent, "Restoring from archive", msg,
                                     QMessageBox.Yes,
                                     QMessageBox.No) != QMessageBox.Yes:
                 return False
     busy = Purr.BusyIndicator()
     # remove file if in the way
     if exists:
         if os.system("/bin/rm -fr '%s'" % self.sourcepath):
             busy = None
             if parent:
                 QMessageBox.warning(
                     parent, "Error removing file", """<P>
         There was an error removing %s. Archived copy was not restored.
         The text console may have more information.</P>""" %
                     self.sourcepath, QMessageBox.Ok, 0)
             return False
     # unpack archived file
     if self.fullpath.endswith('.tgz'):
         parent_dir = os.path.dirname(self.sourcepath.rstrip('/'))
         os.system("/bin/rm -fr %s" % self.sourcepath)
         if os.system("tar zxf '%s' -C '%s'" % (self.fullpath, parent_dir)):
             busy = None
             if parent:
                 QMessageBox.warning(
                     parent, "Error unpacking file", """<P>
         There was an error unpacking the archived version to %s. The text console may have more information.</P>"""
                     % self.sourcepath, QMessageBox.Ok, 0)
             return False
     # else simply copy over
     else:
         if os.system("/bin/cp -a '%s' '%s'" %
                      (self.fullpath, self.sourcepath)):
             busy = None
             if parent:
                 QMessageBox.warning(
                     parent, "Error copying file", """<P>
         There was an error copying the archived version to %s. The text console may have more information.</P>"""
                     % self.sourcepath, QMessageBox.Ok, 0)
             return False
     busy = None
     if parent:
         QMessageBox.information(
             parent, "Restored file", """<P>Restored %s from this entry's
       archived copy.</P>""" % self.sourcepath, QMessageBox.Ok, 0)
     return True