1""" 2This file is part of notmuch. 3 4Notmuch is free software: you can redistribute it and/or modify it 5under the terms of the GNU General Public License as published by the 6Free Software Foundation, either version 3 of the License, or (at your 7option) any later version. 8 9Notmuch is distributed in the hope that it will be useful, but WITHOUT 10ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12for more details. 13 14You should have received a copy of the GNU General Public License 15along with notmuch. If not, see <https://www.gnu.org/licenses/>. 16 17Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de> 18""" 19 20from ctypes import c_uint, c_long 21from .globals import ( 22 nmlib, 23 NotmuchDirectoryP, 24 NotmuchFilenamesP 25) 26from .errors import ( 27 STATUS, 28 NotmuchError, 29 NotInitializedError, 30) 31from .filenames import Filenames 32 33class Directory(object): 34 """Represents a directory entry in the notmuch directory 35 36 Modifying attributes of this object will modify the 37 database, not the real directory attributes. 38 39 The Directory object is usually derived from another object 40 e.g. via :meth:`Database.get_directory`, and will automatically be 41 become invalid whenever that parent is deleted. You should 42 therefore initialized this object handing it a reference to the 43 parent, preventing the parent from automatically being garbage 44 collected. 45 """ 46 47 """notmuch_directory_get_mtime""" 48 _get_mtime = nmlib.notmuch_directory_get_mtime 49 _get_mtime.argtypes = [NotmuchDirectoryP] 50 _get_mtime.restype = c_long 51 52 """notmuch_directory_set_mtime""" 53 _set_mtime = nmlib.notmuch_directory_set_mtime 54 _set_mtime.argtypes = [NotmuchDirectoryP, c_long] 55 _set_mtime.restype = c_uint 56 57 """notmuch_directory_get_child_files""" 58 _get_child_files = nmlib.notmuch_directory_get_child_files 59 _get_child_files.argtypes = [NotmuchDirectoryP] 60 _get_child_files.restype = NotmuchFilenamesP 61 62 """notmuch_directory_get_child_directories""" 63 _get_child_directories = nmlib.notmuch_directory_get_child_directories 64 _get_child_directories.argtypes = [NotmuchDirectoryP] 65 _get_child_directories.restype = NotmuchFilenamesP 66 67 def _assert_dir_is_initialized(self): 68 """Raises a NotmuchError(:attr:`STATUS`.NOT_INITIALIZED) 69 if dir_p is None""" 70 if not self._dir_p: 71 raise NotInitializedError() 72 73 def __init__(self, path, dir_p, parent): 74 """ 75 :param path: The absolute path of the directory object. 76 :param dir_p: The pointer to an internal notmuch_directory_t object. 77 :param parent: The object this Directory is derived from 78 (usually a :class:`Database`). We do not directly use 79 this, but store a reference to it as long as 80 this Directory object lives. This keeps the 81 parent object alive. 82 """ 83 self._path = path 84 self._dir_p = dir_p 85 self._parent = parent 86 87 def set_mtime(self, mtime): 88 """Sets the mtime value of this directory in the database 89 90 The intention is for the caller to use the mtime to allow efficient 91 identification of new messages to be added to the database. The 92 recommended usage is as follows: 93 94 * Read the mtime of a directory from the filesystem 95 96 * Call :meth:`Database.index_file` for all mail files in 97 the directory 98 99 * Call notmuch_directory_set_mtime with the mtime read from the 100 filesystem. Then, when wanting to check for updates to the 101 directory in the future, the client can call :meth:`get_mtime` 102 and know that it only needs to add files if the mtime of the 103 directory and files are newer than the stored timestamp. 104 105 .. note:: 106 107 :meth:`get_mtime` function does not allow the caller to 108 distinguish a timestamp of 0 from a non-existent timestamp. So 109 don't store a timestamp of 0 unless you are comfortable with 110 that. 111 112 :param mtime: A (time_t) timestamp 113 :raises: :exc:`XapianError` a Xapian exception occurred, mtime 114 not stored 115 :raises: :exc:`ReadOnlyDatabaseError` the database was opened 116 in read-only mode so directory mtime cannot be modified 117 :raises: :exc:`NotInitializedError` the directory object has not 118 been initialized 119 """ 120 self._assert_dir_is_initialized() 121 status = Directory._set_mtime(self._dir_p, mtime) 122 123 if status != STATUS.SUCCESS: 124 raise NotmuchError(status) 125 126 def get_mtime(self): 127 """Gets the mtime value of this directory in the database 128 129 Retrieves a previously stored mtime for this directory. 130 131 :param mtime: A (time_t) timestamp 132 :raises: :exc:`NotmuchError`: 133 134 :attr:`STATUS`.NOT_INITIALIZED 135 The directory has not been initialized 136 """ 137 self._assert_dir_is_initialized() 138 return Directory._get_mtime(self._dir_p) 139 140 # Make mtime attribute a property of Directory() 141 mtime = property(get_mtime, set_mtime, doc="""Property that allows getting 142 and setting of the Directory *mtime* (read-write) 143 144 See :meth:`get_mtime` and :meth:`set_mtime` for usage and 145 possible exceptions.""") 146 147 def get_child_files(self): 148 """Gets a Filenames iterator listing all the filenames of 149 messages in the database within the given directory. 150 151 The returned filenames will be the basename-entries only (not 152 complete paths. 153 """ 154 self._assert_dir_is_initialized() 155 files_p = Directory._get_child_files(self._dir_p) 156 return Filenames(files_p, self) 157 158 def get_child_directories(self): 159 """Gets a :class:`Filenames` iterator listing all the filenames of 160 sub-directories in the database within the given directory 161 162 The returned filenames will be the basename-entries only (not 163 complete paths. 164 """ 165 self._assert_dir_is_initialized() 166 files_p = Directory._get_child_directories(self._dir_p) 167 return Filenames(files_p, self) 168 169 @property 170 def path(self): 171 """Returns the absolute path of this Directory (read-only)""" 172 return self._path 173 174 def __repr__(self): 175 """Object representation""" 176 return "<notmuch Directory object '%s'>" % self._path 177 178 _destroy = nmlib.notmuch_directory_destroy 179 _destroy.argtypes = [NotmuchDirectoryP] 180 _destroy.restype = None 181 182 def __del__(self): 183 """Close and free the Directory""" 184 if self._dir_p: 185 self._destroy(self._dir_p) 186