#!/usr/bin/env python3 """ Traversing directories and archives with AVFS/fuse """ import os import os.path import subprocess avfs_sys_mount = os.environ['HOME'] + '/.avfs' avfs_started = False def sys_name(fpath): global avfs_started if not avfs_started: subprocess.check_call(['mountavfs']) avfs_started = True return avfs_sys_mount + os.path.abspath(fpath) def exists(fpath): return os.path.exists(sys_name(fpath)) def isdir(fpath): return os.path.isdir(sys_name(fpath)) orig_open = open def open(fpath, *pargs, **kwargs): return orig_open(sys_name(fpath), *pargs, **kwargs) # AVFS has its own automatic view selection using file extensions, but it # includes plugins (like #patch) that will lead us into an infinite loop # if we try to do a directory traversal. Also, there are a few # extensions we want to add. avfscmds = { ('.gz', '#ugz'), ('.tgz', '#ugz#utar'), ('.tar.bz2', '#ubz2#utar'), ('.bz2', '#ubz2'), ('.bz', '#ubz2'), ('.tbz2', '#ubz2#utar'), ('.tbz', '#ubz2#utar'), ('.Z', '#uz'), ('.tpz', '#uz#utar'), ('.tz', '#uz#utar'), ('.taz', '#uz#utar'), ('.a', '#uar'), ('.deb', '#uar'), ('.tar', '#utar'), ('.gem', '#utar'), # Add upstream ('.rar', '#urar'), ('.sfx', '#urar'), ('.zip', '#uzip'), ('.jar', '#uzip'), ('.ear', '#uzip'), ('.war', '#uzip'), ('.nupkg', '#uzip'), # Add upstream ('.whl', '#uzip'), # Add upstream ('.7z', '#u7z'), ('.zoo', '#uzoo'), ('.lha', '#ulha'), ('.lhz', '#ulha'), ('.arj', '#uarj'), ('.cpio', '#ucpio'), ('.rpm', '#rpm'), ('.tar.xz', '#uxze#utar'), ('.txz', '#uxze#utar'), ('.xz', '#uxze'), ('.lzma', '#uxze'), } def guesscmd(filename): for ext, cmd in avfscmds: if filename.endswith(ext): return cmd + guesscmd(filename[:-len(ext)]) return '' def find(rootdir, prunedirs): """ Recursively list all files under rootdir, including files in archives supported by AVFS. """ sys_rootdir = sys_name(rootdir) for name in os.listdir(sys_rootdir): path = rootdir + '/' + name sys_path = sys_rootdir + '/' + name if os.path.isdir(sys_path): if name not in prunedirs: yield from find(path, prunedirs) else: cmd = guesscmd(name) filtered_path = path + cmd sys_filtered_path = sys_path + cmd if cmd and os.path.exists(sys_filtered_path): if os.path.isdir(sys_filtered_path): yield from find(filtered_path, prunedirs) else: yield filtered_path else: yield path if __name__ == "__main__": import sys for f in find(sys.argv[1], {'.git'}): print(f)