1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#!/usr/bin/env python3
"""
Traversing directories and archives with AVFS/fuse
"""
import os
import os.path
import subprocess
import stat
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 get_lstat_mode(filename):
"""
Get the st_mode stat value of the given file, or None if the stat fails
(doesn't exist, I/O error)
"""
try:
return os.lstat(filename).st_mode
except:
return None
def find(path, excludes):
"""
Recursively list all files under path, including files in archives
supported by AVFS.
"""
sys_path = sys_name(path)
name = os.path.basename(path)
mode = get_lstat_mode(sys_path)
if mode is None:
return
if name in excludes:
return
# If AVFS provides a cooked view of the file, substitute the view
# for the original file.
if stat.S_ISREG(mode):
cmd = guesscmd(name)
if cmd:
cmd_mode = get_lstat_mode(sys_path + cmd)
if cmd_mode is not None:
path = path + cmd
sys_path = sys_path + cmd
name = name + cmd
mode = cmd_mode
if stat.S_ISDIR(mode):
for entry in os.listdir(sys_path):
yield from find(path + '/' + entry, excludes)
elif stat.S_ISREG(mode):
yield path
if __name__ == "__main__":
import sys
for f in find(sys.argv[1], {'.git'}):
print(f)
|