def find(self, tags): """Return a list of files with all of the given tags. Parameters ---------- tags : list List of tags. List is not changed. Returns ------- list List of absolute paths, to the hard link under the first tag given. """ logger.debug("find(%r)", tags) assert len(tags) > 0 tagpaths = (dpath.pathfromtag(tag, self.root) if dpath.istag(tag) else tag for tag in tags) inodes = (set(os.lstat(x) for x in dpath.listdir(path)) for path in tagpaths) inodes = functools.reduce(set.intersection, inodes) logger.debug("found unique inodes %r", inodes) map = dict((os.lstat(x), x) for x in dpath.listdir( dpath.pathfromtag(tags[0], self.root))) logger.debug("using map %r", map) return [map[x] for x in inodes]
def find(self, tags): """Return a list of files with all of the given tags. Parameters ---------- tags : list List of tags. List is not changed. Returns ------- list List of absolute paths, to the hard link under the first tag given. """ logger.debug("find(%r)", tags) assert len(tags) > 0 tagpaths = (dpath.pathfromtag(tag, self.root) if dpath.istag(tag) else tag for tag in tags) inodes = (set(os.lstat(x) for x in dpath.listdir(path)) for path in tagpaths) inodes = functools.reduce(set.intersection, inodes) logger.debug("found unique inodes %r", inodes) map = dict( (os.lstat(x), x) for x in dpath.listdir(dpath.pathfromtag(tags[0], self.root))) logger.debug("using map %r", map) return [map[x] for x in inodes]
def create(self, path, mode): logger.debug("create(%r, %r)", path, mode) node, path = self._getnode(path) if len(path) == 1 and isinstance(node, tree.TagNode): t = list(node.tags) file = path[0] path = os.path.join(dpath.pathfromtag(t.pop(0), self.root), file) fd = os.open(path, os.O_WRONLY | os.O_CREAT, mode) for tag in t: self.root.tag(path, tag) return fd else: fd = os.open(_getpath(node, path), os.O_WRONLY | os.O_CREAT, mode) return fd
def tag(self, file, tag): """Tag file with tag. If `file` is already tagged, nothing happens. This includes if the file is hardlinked under another name. Parameters ---------- file : str Path to the file, relative to the working directory. tag : str Tag, relative to the library root, starting with '/'. Raises ------ IsADirectoryError file is an unconverted directory. NotADirectoryError tag is not a directory/tag. """ file = os.path.normpath(file) # get rid of trailing slashes if os.path.isdir(file) and not os.path.islink(file): raise IsADirectoryError( '{} is a directory; convert it first'.format(file)) if dpath.istag(tag): p_dest = dpath.pathfromtag(tag, self.root) else: if not os.path.isdir(tag): raise NotADirectoryError( '{} is not a directory/tag'.format(tag)) p_dest = tag logger.info( 'Checking if %r is already tagged with %r', file, tag) for f in dpath.listdir(p_dest): if os.path.samefile(f, file): return logger.info('Check okay') name = os.path.basename(file) while True: dest = os.path.join(p_dest, dpath.resolve_name(p_dest, name)) logger.debug('linking %r %r', file, dest) try: os.link(file, dest) except FileExistsError: continue else: break
def tag(self, file, tag): """Tag file with tag. If `file` is already tagged, nothing happens. This includes if the file is hardlinked under another name. Parameters ---------- file : str Path to the file, relative to the working directory. tag : str Tag, relative to the library root, starting with '/'. Raises ------ IsADirectoryError file is an unconverted directory. NotADirectoryError tag is not a directory/tag. """ file = os.path.normpath(file) # get rid of trailing slashes if os.path.isdir(file) and not os.path.islink(file): raise IsADirectoryError( '{} is a directory; convert it first'.format(file)) if dpath.istag(tag): p_dest = dpath.pathfromtag(tag, self.root) else: if not os.path.isdir(tag): raise NotADirectoryError( '{} is not a directory/tag'.format(tag)) p_dest = tag logger.info('Checking if %r is already tagged with %r', file, tag) for f in dpath.listdir(p_dest): if os.path.samefile(f, file): return logger.info('Check okay') name = os.path.basename(file) while True: dest = os.path.join(p_dest, dpath.resolve_name(p_dest, name)) logger.debug('linking %r %r', file, dest) try: os.link(file, dest) except FileExistsError: continue else: break
def untag(self, file, tag): """Remove tag from file. If file is not tagged, nothing happens. Remove *all* hard links to the file in the directory corresponding to the given tag. Log a warning when an OSError is caught. Parameters ---------- file : str Path to the file, relative to the working directory. tag : str Tag, relative to the library root, starting with '/'. Raises ------ NotADirectoryError tag is not a directory/tag. """ logger.debug('untag(%r, %r)', file, tag) assert isinstance(file, str) assert isinstance(tag, str) if dpath.istag(tag): p_dest = dpath.pathfromtag(tag, self.root) else: if not os.path.isdir(tag): raise NotADirectoryError( '{} is not a directory/tag'.format(tag)) p_dest = tag inode = os.lstat(file) logger.debug('file inode is %r', inode) for f in dpath.listdir(p_dest): logger.debug('checking %r', f) st = os.lstat(f) logger.debug('inode is %r', st) if os.path.samestat(inode, st): logger.debug('unlinking %r', f) try: os.unlink(f) except OSError as e: logger.warning('Caught OSError: %s', e)
def rmtag(self, tag): if dpath.istag(tag): shutil.rmtree(dpath.pathfromtag(tag, self.root)) else: shutil.rmtree(tag)
def mktag(self, tag): if dpath.istag(tag): os.mkdir(dpath.pathfromtag(tag, self.root)) else: os.mkdir(tag)
def test_pathfromtag(self): r = os.getcwd() o = os.path.join(r, 'tag') self.assertEquals(dpath.pathfromtag('//tag', r), o)