Beispiel #1
0
 def collect_tags(self, querystring):
     """returns tags of messages that match `querystring`"""
     db = Database(path=self.path, mode=Database.MODE.READ_ONLY)
     tagset = notmuch2._tags.ImmutableTagSet(
         db.messages(querystring, exclude_tags=self.exclude_tags),
         '_iter_p', notmuch2.capi.lib.notmuch_messages_collect_tags)
     return [t for t in tagset]
Beispiel #2
0
    def flush(self):
        """
        write out all queued write-commands in order, each one in a separate
        :meth:`atomic <notmuch2.Database.atomic>` transaction.

        If this fails the current action is rolled back, stays in the write
        queue and an exception is raised.
        You are responsible to retry flushing at a later time if you want to
        ensure that the cached changes are applied to the database.

        :exception: :exc:`~errors.DatabaseROError` if db is opened read-only
        :exception: :exc:`~errors.DatabaseLockedError` if db is locked
        """
        if self.ro:
            raise DatabaseROError()
        if self.writequeue:
            # read notmuch's config regarding imap flag synchronization
            sync = settings.get_notmuch_setting('maildir', 'synchronize_flags')

            # go through writequeue entries
            while self.writequeue:
                current_item = self.writequeue.popleft()
                logging.debug('write-out item: %s', str(current_item))

                # watch out for notmuch errors to re-insert current_item
                # to the queue on errors
                try:
                    # the first two coordinants are cnmdname and post-callback
                    cmd, afterwards = current_item[:2]
                    logging.debug('cmd created')

                    # acquire a writeable db handler
                    try:
                        mode = Database.MODE.READ_WRITE
                        db = Database(path=self.path, mode=mode)
                    except NotmuchError:
                        raise DatabaseLockedError()
                    logging.debug('got write lock')

                    # make this a transaction
                    with db.atomic():
                        logging.debug('got atomic')

                        if cmd == 'add':
                            logging.debug('add')
                            path, tags = current_item[2:]
                            msg, _ = db.add(path, sync_flags=sync)
                            logging.debug('added msg')
                            with msg.frozen():
                                logging.debug('freeze')
                                for tag in tags:
                                    msg.tags.add(tag)
                                if sync:
                                    msg.tags.to_maildir_flags()
                                logging.debug('added tags ')
                            logging.debug('thaw')

                        elif cmd == 'remove':
                            path = current_item[2]
                            db.remove(path)

                        elif cmd == 'setconfig':
                            key = current_item[2]
                            value = current_item[3]
                            db.config[key] = value

                        else:  # tag/set/untag
                            querystring, tags = current_item[2:]
                            if cmd == 'toggle':
                                presenttags = self.collect_tags(querystring)
                                to_remove = []
                                to_add = []
                                for tag in tags:
                                    if tag in presenttags:
                                        to_remove.append(tag)
                                    else:
                                        to_add.append(tag)

                            for msg in db.messages(querystring):
                                with msg.frozen():
                                    if cmd == 'toggle':
                                        for tag in to_remove:
                                            msg.tags.discard(tag)
                                        for tag in to_add:
                                            msg.tags.add(tag)
                                    else:
                                        if cmd == 'set':
                                            msg.tags.clear()

                                        for tag in tags:
                                            if cmd == 'tag' or cmd == 'set':
                                                msg.tags.add(tag)
                                            elif cmd == 'untag':
                                                msg.tags.discard(tag)
                                    if sync:
                                        msg.tags.to_maildir_flags()

                        logging.debug('ended atomic')

                    # close db
                    db.close()
                    logging.debug('closed db')

                    # call post-callback
                    if callable(afterwards):
                        logging.debug(str(afterwards))
                        afterwards()
                        logging.debug('called callback')

                # re-insert item to the queue upon Xapian/NotmuchErrors
                except (XapianError, NotmuchError) as e:
                    logging.exception(e)
                    self.writequeue.appendleft(current_item)
                    raise DatabaseError(str(e))
                except DatabaseLockedError as e:
                    logging.debug('index temporarily locked')
                    self.writequeue.appendleft(current_item)
                    raise e
                logging.debug('flush finished')