Mercurial > danboorufs
comparison danboorufs.py @ 2:85cbd44f98b1 draft
Add license, (try to) respect the PEP 8, and don’t override the file builtin.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Tue, 21 Aug 2012 20:17:49 +0200 |
parents | 63ccd8b0d615 |
children | 880904f1071f |
comparison
equal
deleted
inserted
replaced
1:63ccd8b0d615 | 2:85cbd44f98b1 |
---|---|
1 #!/usr/bin/env python2 | 1 #!/usr/bin/env python2 |
2 # -*- encoding: utf-8 -*- | 2 # -*- encoding: utf-8 -*- |
3 # | |
4 # | |
5 # Copyright © 2012 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> | |
6 # | |
7 # Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 # of this software and associated documentation files (the "Software"), to deal | |
9 # in the Software without restriction, including without limitation the rights | |
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 # copies of the Software, and to permit persons to whom the Software is | |
12 # furnished to do so, subject to the following conditions: | |
13 # | |
14 # The above copyright notice and this permission notice shall be included in | |
15 # all copies or substantial portions of the Software. | |
16 # | |
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
23 # SOFTWARE. | |
24 | |
3 | 25 |
4 from __future__ import with_statement | 26 from __future__ import with_statement |
5 | 27 |
6 from errno import ENOENT, ENOTDIR | 28 from errno import ENOENT, ENOTDIR |
7 from sys import argv, exit | 29 from sys import argv |
8 from threading import Lock | 30 from threading import Lock |
9 from time import time | 31 from time import time |
10 | 32 |
11 import os | 33 import os |
12 | 34 |
34 filename = name.replace('.tags', '') | 56 filename = name.replace('.tags', '') |
35 basename = os.path.basename(filename) | 57 basename = os.path.basename(filename) |
36 self.paths[basename] = filename | 58 self.paths[basename] = filename |
37 tags = [] | 59 tags = [] |
38 self.files[basename] = tags | 60 self.files[basename] = tags |
39 with open(name, 'r') as file: | 61 with open(name, 'r') as tagfile: |
40 for line in file: | 62 for line in tagfile: |
41 for tag in line.split(): | 63 for tag in line.split(): |
42 tag = tag.decode('UTF-8') | 64 tag = tag.decode('UTF-8') |
43 tag = tag.replace('/', u'�') #XXX | 65 tag = tag.replace('/', u'�') #XXX |
44 tags.append(tag) | 66 tags.append(tag) |
45 self.tags.setdefault(tag, []).append(basename) | 67 self.tags.setdefault(tag, []).append(basename) |
56 real_path = path[1:].split('/') | 78 real_path = path[1:].split('/') |
57 | 79 |
58 # Remove the leading - of tag exclusion. | 80 # Remove the leading - of tag exclusion. |
59 path = [tag[1:] if tag[0] == '-' else tag for tag in real_path] | 81 path = [tag[1:] if tag[0] == '-' else tag for tag in real_path] |
60 | 82 |
61 if filter(lambda tag: tag not in self.tags, path[:-1]): | 83 for tag in path[:-1]: |
62 raise FuseOSError(ENOENT) | 84 if tag not in self.tags: |
85 raise FuseOSError(ENOENT) | |
63 | 86 |
64 if path[-1] in self.tags: | 87 if path[-1] in self.tags: |
65 return (real_path, None) | 88 return (real_path, None) |
66 | 89 |
67 if path[-1] not in self.paths: | 90 if path[-1] not in self.paths: |
70 return (real_path[:-1], self.paths[real_path[-1]]) | 93 return (real_path[:-1], self.paths[real_path[-1]]) |
71 | 94 |
72 def access(self, path, mode): | 95 def access(self, path, mode): |
73 self._split_path(path) | 96 self._split_path(path) |
74 | 97 |
75 def getattr(self, path, fh=None): | 98 def getattr(self, path, file_handle=None): |
76 tags, file = self._split_path(path) | 99 _, filename = self._split_path(path) |
77 path = file if file else self.root | 100 path = filename if filename else self.root |
78 st = os.lstat(path) | 101 stat = os.lstat(path) |
79 return dict((key, getattr(st, key)) for key in ('st_atime', 'st_ctime', | 102 return dict((key, getattr(stat, key)) for key in ('st_atime', |
80 'st_gid', 'st_mode', 'st_mtime', 'st_nlink', 'st_size', 'st_uid')) | 103 'st_ctime', 'st_gid', 'st_mode', 'st_mtime', |
104 'st_nlink', 'st_size', 'st_uid')) | |
81 | 105 |
82 getxattr = None | 106 getxattr = None |
83 listxattr = None | 107 listxattr = None |
108 | |
84 def open(self, path, flags): | 109 def open(self, path, flags): |
85 tags, file = self._split_path(path) | 110 _, filename = self._split_path(path) |
86 return os.open(file, flags) | 111 return os.open(filename, flags) |
87 | 112 |
88 def read(self, path, size, offset, fh): | 113 def read(self, path, size, offset, file_handle): |
89 with self.rwlock: | 114 with self.rwlock: |
90 os.lseek(fh, offset, 0) | 115 os.lseek(file_handle, offset, 0) |
91 return os.read(fh, size) | 116 return os.read(file_handle, size) |
92 | 117 |
93 def readdir(self, path, fh): | 118 def readdir(self, path, file_handle): |
94 if path == '/': | 119 if path == '/': |
95 return ['.', '..'] + self.tags.keys() + self.files.keys() | 120 return ['.', '..'] + self.tags.keys() + self.files.keys() |
96 | 121 |
97 tags, file = self._split_path(path) | 122 tags, filename = self._split_path(path) |
98 if file: | 123 if filename: |
99 return FuseOSError(ENOTDIR) | 124 return FuseOSError(ENOTDIR) |
100 | 125 |
101 tags = set(tags) | 126 tags = set(tags) |
102 | 127 |
103 l = ' '.join(tags) | 128 key = ' '.join(tags) |
104 if l in self.cache: | 129 if key in self.cache: |
105 return ['.', '..'] + self.cache[l] | 130 return ['.', '..'] + self.cache[key] |
106 | 131 |
107 inclusion_tags = set(tag for tag in tags if tag[0] != '-') | 132 inclusion_tags = set(tag for tag in tags if tag[0] != '-') |
108 exclusion_tags = set(tag[1:] for tag in tags if tag[0] == '-') | 133 exclusion_tags = set(tag[1:] for tag in tags if tag[0] == '-') |
109 | 134 |
110 # Get the list of the files corresponding to those tags. | 135 # Get the list of the files corresponding to those tags. |
111 files = reduce((lambda s, t: s.intersection(self.tags[t])), inclusion_tags, set(self.files)) | 136 files = reduce((lambda s, t: s.intersection(self.tags[t])), |
112 files -= set([f for f in files if exclusion_tags.intersection(self.files[f])]) | 137 inclusion_tags, set(self.files)) |
138 files -= set([f for f in files | |
139 if exclusion_tags.intersection(self.files[f])]) | |
113 | 140 |
114 # Those next two steps are for useless tags removal. | 141 # Those next two steps are for useless tags removal. |
115 | 142 |
116 # Get the tags of those files. | 143 # Get the tags of those files. |
117 taglist = reduce((lambda s, f: s.union(self.files[f])), files, set()) | 144 taglist = reduce((lambda s, f: s.union(self.files[f])), files, set()) |
118 taglist -= tags | 145 taglist -= tags |
119 | 146 |
120 # Remove the tags that can’t precise the file list anymore. | 147 # Remove the tags that can’t precise the file list anymore. |
121 rm = reduce((lambda s, f: s.intersection(self.files[f])), files, taglist) | 148 remove = reduce((lambda s, f: s.intersection(self.files[f])), files, |
122 taglist -= rm | 149 taglist) |
150 taglist -= remove | |
123 | 151 |
124 self.cache[l] = list(taglist) + list(files) | 152 self.cache[key] = list(taglist) + list(files) |
125 return ['.', '..'] + self.cache[l] | 153 return ['.', '..'] + self.cache[key] |
126 | 154 |
127 readlink = os.readlink | 155 readlink = os.readlink |
128 | 156 |
129 def release(self, path, fh): | 157 def release(self, path, file_handle): |
130 return os.close(fh) | 158 return os.close(file_handle) |
131 | 159 |
132 def statfs(self, path): | 160 def statfs(self, path): |
133 tags, file = self._split_path(path) | 161 _, filename = self._split_path(path) |
134 path = file if file else self.root | 162 path = filename if filename else self.root |
135 stv = os.statvfs(path) | 163 stv = os.statvfs(path) |
136 return dict((key, getattr(stv, key)) for key in ('f_bavail', 'f_bfree', | 164 return dict((key, getattr(stv, key)) for key in ('f_bavail', 'f_bfree', |
137 'f_blocks', 'f_bsize', 'f_favail', 'f_ffree', 'f_files', 'f_flag', | 165 'f_blocks', 'f_bsize', 'f_favail', 'f_ffree', 'f_files', 'f_flag', |
138 'f_frsize', 'f_namemax')) | 166 'f_frsize', 'f_namemax')) |
139 | 167 |
145 print('usage: %s <tag file> [<tag file>...] <mountpoint>' % argv[0]) | 173 print('usage: %s <tag file> [<tag file>...] <mountpoint>' % argv[0]) |
146 exit(1) | 174 exit(1) |
147 | 175 |
148 mountpoint = argv.pop() | 176 mountpoint = argv.pop() |
149 | 177 |
150 fuse = FUSE(Danbooru(argv[1:], os.path.dirname(mountpoint)), mountpoint, foreground=True) | 178 fuse = FUSE(Danbooru(argv[1:], os.path.dirname(mountpoint)), mountpoint, |
179 foreground=True) |