class Index(MutableSequence): defIdxFilename = ".index.yaml" def __init__(self, idxfile=None, imgdir=None, hashalg=["md5"]): super(Index, self).__init__() self.directory = None self.idxfilename = None self.items = [] if idxfile: self.read(idxfile) if imgdir: imgdir = os.path.abspath(imgdir) if not self.directory: self.directory = imgdir if idxfile: known = {i.filename for i in self.items} newitems = _readdir(imgdir, self.directory, hashalg, known) self.items.extend(newitems) else: newitems = _readdir(imgdir, self.directory, hashalg) self.items = LazyList(newitems) def __len__(self): return len(self.items) def __getitem__(self, index): return self.items.__getitem__(index) def __setitem__(self, index, value): self.items.__setitem__(index, value) def __delitem__(self, index): self.items.__delitem__(index) def insert(self, index, value): self.items.insert(index, value) def _idxfilename(self, idxfile): """Determine the index file name for reading and writing. """ if idxfile is not None: idxfile = os.path.abspath(idxfile) if os.path.isdir(idxfile): idxfile = os.path.join(idxfile, self.defIdxFilename) return idxfile elif self.idxfilename is not None: return self.idxfilename else: d = self.directory if self.directory is not None else os.getcwd() return os.path.abspath(os.path.join(d, self.defIdxFilename)) def read(self, idxfile=None): """Read the index from a file. """ self.idxfilename = self._idxfilename(idxfile) self.directory = os.path.dirname(self.idxfilename) with open(self.idxfilename, "rt") as f: self.items = [IdxItem(data=i) for i in yaml.load(f)] def write(self, idxfile=None): """Write the index to a file. """ with open(self._idxfilename(idxfile), "wt") as f: items = [i.as_dict() for i in self.items] yaml.dump(items, f, default_flow_style=False)
class Index(MutableSequence): defIdxFilename = Path(".index.yaml") def __init__(self, idxfile=None, imgdir=None, hashalg=['md5']): super().__init__() self.directory = None self.idxfile = None self.items = [] if idxfile: self.read(idxfile) if imgdir: imgdir = Path(imgdir).resolve() if not self.directory: self.directory = imgdir if idxfile: self.extend_dir(imgdir, hashalg) else: newitems = _readdir(imgdir, self.directory, hashalg) self.items = LazyList(newitems) def extend_dir(self, imgdir, hashalg=['md5']): imgdir = Path(imgdir).resolve() known = {i.filename for i in self.items} newitems = _readdir(imgdir, self.directory, hashalg, known) self.items.extend(newitems) def close(self): if self.idxfile: self.idxfile.close() self.idxfile = None def __enter__(self): return self def __exit__(self, type, value, tb): self.close() def __del__(self): self.close() def __len__(self): return len(self.items) def __getitem__(self, index): return self.items.__getitem__(index) def __setitem__(self, index, value): self.items.__setitem__(index, value) def __delitem__(self, index): self.items.__delitem__(index) def index(self, value, *args): return self.items.index(value, *args) def insert(self, index, value): self.items.insert(index, value) def _get_idxfile(self, fname, flags): if fname is not None: self.close() fname = Path(fname) if fname.is_dir(): fname = fname / self.defIdxFilename self.directory = fname.parent.resolve() fd = os.open(str(fname), flags, mode=0o666) self.idxfile = os.fdopen(fd, "r+t") elif self.idxfile: self.idxfile.seek(0) else: if not self.directory: self.directory = Path.cwd() fname = self.directory / self.defIdxFilename fd = os.open(str(fname), flags, mode=0o666) self.idxfile = os.fdopen(fd, "r+t") def _lockf(self, mode=fcntl.LOCK_SH): try: fcntl.lockf(self.idxfile.fileno(), mode | fcntl.LOCK_NB) except OSError as e: if e.errno in (errno.EACCES, errno.EAGAIN): e = AlreadyLockedError(*e.args) raise e def read(self, idxfile=None): """Read the index from a file. """ self._get_idxfile(idxfile, os.O_RDWR) self._lockf() self.items = [IdxItem(data=i) for i in yaml.safe_load(self.idxfile)] def write(self, idxfile=None): """Write the index to a file. """ items = [i.as_dict() for i in self.items] self._get_idxfile(idxfile, os.O_RDWR | os.O_CREAT) self._lockf(mode=fcntl.LOCK_EX) yaml.dump(items, self.idxfile, default_flow_style=False) self.idxfile.truncate() self.idxfile.flush() self._lockf()