-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpepfs.py
130 lines (112 loc) · 3.6 KB
/
pepfs.py
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
126
127
128
129
130
#!/usr/bin/env python
# coding: utf-8
from __future__ import print_function
import json
import logging
import os
import re
import requests
import sys
import time
from errno import ENOENT
from fuse import FUSE, FuseOSError, LoggingMixIn, Operations
from stat import S_IFDIR, S_IFREG
# use logging
logging.basicConfig(level=logging.DEBUG)
# github repository with all the latest versions of PEPs
PEPS_URL = 'http://api.github.com/repos/python/peps/contents/'
def get_peps():
"""Get PEPs from github repository"""
response = requests.get(PEPS_URL)
repo_files = json.loads(response.text)
peps = {}
for repo_file in repo_files:
name = repo_file['name']
# find all PEP files
if re.match(r'pep-\d+\.txt', name):
url = repo_file['download_url']
size = repo_file['size']
peps[name] = {
'url': url,
'size': size,
}
return peps
def get_data_from_url(url, timeout=10):
"""Get data from URL"""
try:
response = requests.get(url, timeout=timeout)
return response.text
except requests.exceptions.RequestException as ex:
logging.error(ex)
class PEPFS(LoggingMixIn, Operations):
"""PEP FUSE filesystem"""
def __init__(self):
# get all PEPs
self.peps_urls = get_peps()
# use for caching PEPs data
self.peps_data = {}
for pep in self.peps_urls:
self.peps_data[pep] = None
def getattr(self, path, fh=None):
"""Update files' attributes"""
now = time.time()
if path == '/':
# calculate dir size
dir_size = 0
for pep in self.peps_urls:
if self.peps_data[pep]:
dir_size += len(self.peps_data[pep])
else:
dir_size += self.peps_urls[pep]['size']
return {
'st_atime': now,
'st_ctime': now,
'st_mtime': now,
'st_mode': S_IFDIR | 0o755,
'st_nlink': 2,
'st_size': dir_size,
}
else:
name = os.path.basename(path)
# handle other files
if name not in self.peps_data:
raise FuseOSError(ENOENT)
# set files size
if self.peps_data[name]:
size = len(self.peps_data[name])
else:
size = self.peps_urls[name]['size']
return {
'st_atime': now,
'st_ctime': now,
'st_mtime': now,
'st_mode': S_IFREG | 0o644,
'st_nlink': 1,
'st_size': size,
}
def read(self, path, size, offset, fh):
"""Read file"""
name = os.path.basename(path)
data = self.peps_data[name]
if data is None:
# if file is not in cache - download it
url = self.peps_urls[name]['url']
data = get_data_from_url(url)
self.peps_data[name] = data
return data.encode('utf-8')[offset:offset + size]
def readdir(self, path, fh):
"""Return all files in mountpoint dir"""
files = ['.', '..']
return files + sorted(self.peps_data.keys())
def main():
if len(sys.argv) != 2:
print('usage: {} <mountpoint>'.format(sys.argv[0]))
exit(1)
# make mountpoint dir if not exists
mountpoint = sys.argv[1]
if not os.path.isdir(mountpoint):
os.makedirs(mountpoint)
# init FUSE
FUSE(PEPFS(), mountpoint, nothreads=True, foreground=True)
if __name__ == '__main__':
main()