import logging as _logging
import os as _os
import re as _re
-import shutil as _shutil
import subprocess as _subprocess
import sys as _sys
import tempfile as _tempfile
stdout=_subprocess.PIPE, wait=True)
if status != 0:
_LOG.error("failed to run notmuch config")
- sys.exit(1)
+ _sys.exit(1)
return int(stdout.rstrip())
def get_tags(prefix=None):
"Get a list of tags with a given prefix."
(status, stdout, stderr) = _spawn(
- args=['notmuch', 'search', '--query=sexp', '--output=tags', _tag_query(prefix)],
+ args=['notmuch', 'search', '--exclude=false', '--query=sexp', '--output=tags', _tag_query(prefix)],
stdout=_subprocess.PIPE, wait=True)
return [tag for tag in stdout.splitlines()]
total = count_messages (TAG_PREFIX)
if total == 0:
- _LOG.error('No existing tags with given prefix, stopping.'.format(safe))
+ _LOG.error('No existing tags with given prefix, stopping.')
_LOG.error('Use --force to override.')
exit(1)
change = len(status['added'])+len(status['deleted'])
stdout=_subprocess.PIPE, wait=True)
return base != fetch_head
+class DatabaseCache:
+ def __init__(self):
+ try:
+ from notmuch2 import Database
+ self._notmuch = Database()
+ except ImportError:
+ self._notmuch = None
+ self._known = {}
+
+ def known(self,id):
+ if id in self._known:
+ return self._known[id];
+
+ if self._notmuch:
+ try:
+ _ = self._notmuch.find(id)
+ self._known[id] = True
+ except LookupError:
+ self._known[id] = False
+ else:
+ (_, stdout, stderr) = _spawn(
+ args=['notmuch', 'search', '--exclude=false', '--output=files', 'id:{0}'.format(id)],
+ stdout=_subprocess.PIPE,
+ wait=True)
+ self._known[id] = stdout != None
+ return self._known[id]
@timed
def get_status():
'deleted': {},
'missing': {},
}
+ db = DatabaseCache()
with PrivateIndex(repo=NOTMUCH_GIT_DIR, prefix=TAG_PREFIX) as index:
maybe_deleted = index.diff(filter='D')
for id, tags in maybe_deleted.items():
- (_, stdout, stderr) = _spawn(
- args=['notmuch', 'search', '--output=files', 'id:{0}'.format(id)],
- stdout=_subprocess.PIPE,
- wait=True)
- if stdout:
+ if db.known(id):
status['deleted'][id] = tags
else:
status['missing'][id] = tags
self.lastmod = None
self.checksum = None
self._load_cache_file()
+ self.file_tree = None
self._index_tags()
def __enter__(self):
_LOG.error("Error decoding cache")
_sys.exit(1)
+ @timed
+ def _read_file_tree(self):
+ self.file_tree = {}
+
+ with _git(
+ args=['ls-files', 'tags'],
+ additional_env={'GIT_INDEX_FILE': self.index_path},
+ stdout=_subprocess.PIPE) as git:
+ for file in git.stdout:
+ dir=_os.path.dirname(file)
+ tag=_os.path.basename(file).rstrip()
+ if dir not in self.file_tree:
+ self.file_tree[dir]=[tag]
+ else:
+ self.file_tree[dir].append(tag)
+
+
+ def _clear_tags_for_message(self, id):
+ """
+ Clear any existing index entries for message 'id'
+
+ Neither 'id' nor the tags in 'tags' should be encoded/escaped.
+ """
+
+ if self.file_tree == None:
+ self._read_file_tree()
+
+ dir = _id_path(id)
+
+ if dir not in self.file_tree:
+ return
+
+ for file in self.file_tree[dir]:
+ line = '0 0000000000000000000000000000000000000000\t{:s}/{:s}\n'.format(dir,file)
+ yield line
+
+
@timed
def _index_tags(self):
"Write notmuch tags to private git index."
if tag.startswith(prefix)]
id = _xapian_unquote(string=id)
if clear_tags:
- for line in _clear_tags_for_message(index=self.index_path, id=id):
+ for line in self._clear_tags_for_message(id=id):
git.stdin.write(line)
for line in _index_tags_for_message(
id=id, status='A', tags=tags):
except FileNotFoundError:
return None
-
-def _clear_tags_for_message(index, id):
- """
- Clear any existing index entries for message 'id'
-
- Neither 'id' nor the tags in 'tags' should be encoded/escaped.
- """
-
- dir = _id_path(id)
-
- with _git(
- args=['ls-files', dir],
- additional_env={'GIT_INDEX_FILE': index},
- stdout=_subprocess.PIPE) as git:
- for file in git.stdout:
- line = '0 0000000000000000000000000000000000000000\t{:s}\n'.format(file.strip())
- yield line
-
def _read_database_lastmod():
with _spawn(
args=['notmuch', 'count', '--lastmod', '*'],