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]
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')