#7342: make sure that the datetime object in test_fraction always has a number of...
[python.git] / Demo / pdist / FSProxy.py
bloba1ab635c08bafd4b5c051ab912a974b06c27beaa
1 """File System Proxy.
3 Provide an OS-neutral view on a file system, locally or remotely.
4 The functionality is geared towards implementing some sort of
5 rdist-like utility between a Mac and a UNIX system.
7 The module defines three classes:
9 FSProxyLocal -- used for local access
10 FSProxyServer -- used on the server side of remote access
11 FSProxyClient -- used on the client side of remote access
13 The remote classes are instantiated with an IP address and an optional
14 verbosity flag.
15 """
17 import server
18 import client
19 import md5
20 import os
21 import fnmatch
22 from stat import *
23 import time
24 import fnmatch
26 if os.name == 'mac':
27 import macfs
28 maxnamelen = 31
29 else:
30 macfs = None
31 maxnamelen = 255
33 skipnames = (os.curdir, os.pardir)
36 class FSProxyLocal:
38 def __init__(self):
39 self._dirstack = []
40 self._ignore = ['*.pyc'] + self._readignore()
42 def _close(self):
43 while self._dirstack:
44 self.back()
46 def _readignore(self):
47 file = self._hide('ignore')
48 try:
49 f = open(file)
50 except IOError:
51 file = self._hide('synctree.ignorefiles')
52 try:
53 f = open(file)
54 except IOError:
55 return []
56 ignore = []
57 while 1:
58 line = f.readline()
59 if not line: break
60 if line[-1] == '\n': line = line[:-1]
61 ignore.append(line)
62 f.close()
63 return ignore
65 def _hidden(self, name):
66 if os.name == 'mac':
67 return name[0] == '(' and name[-1] == ')'
68 else:
69 return name[0] == '.'
71 def _hide(self, name):
72 if os.name == 'mac':
73 return '(%s)' % name
74 else:
75 return '.%s' % name
77 def visible(self, name):
78 if len(name) > maxnamelen: return 0
79 if name[-1] == '~': return 0
80 if name in skipnames: return 0
81 if self._hidden(name): return 0
82 head, tail = os.path.split(name)
83 if head or not tail: return 0
84 if macfs:
85 if os.path.exists(name) and not os.path.isdir(name):
86 try:
87 fs = macfs.FSSpec(name)
88 c, t = fs.GetCreatorType()
89 if t != 'TEXT': return 0
90 except macfs.error, msg:
91 print "***", name, msg
92 return 0
93 else:
94 if os.path.islink(name): return 0
95 if '\0' in open(name, 'rb').read(512): return 0
96 for ign in self._ignore:
97 if fnmatch.fnmatch(name, ign): return 0
98 return 1
100 def check(self, name):
101 if not self.visible(name):
102 raise os.error, "protected name %s" % repr(name)
104 def checkfile(self, name):
105 self.check(name)
106 if not os.path.isfile(name):
107 raise os.error, "not a plain file %s" % repr(name)
109 def pwd(self):
110 return os.getcwd()
112 def cd(self, name):
113 self.check(name)
114 save = os.getcwd(), self._ignore
115 os.chdir(name)
116 self._dirstack.append(save)
117 self._ignore = self._ignore + self._readignore()
119 def back(self):
120 if not self._dirstack:
121 raise os.error, "empty directory stack"
122 dir, ignore = self._dirstack[-1]
123 os.chdir(dir)
124 del self._dirstack[-1]
125 self._ignore = ignore
127 def _filter(self, files, pat = None):
128 if pat:
129 def keep(name, pat = pat):
130 return fnmatch.fnmatch(name, pat)
131 files = filter(keep, files)
132 files = filter(self.visible, files)
133 files.sort()
134 return files
136 def list(self, pat = None):
137 files = os.listdir(os.curdir)
138 return self._filter(files, pat)
140 def listfiles(self, pat = None):
141 files = os.listdir(os.curdir)
142 files = filter(os.path.isfile, files)
143 return self._filter(files, pat)
145 def listsubdirs(self, pat = None):
146 files = os.listdir(os.curdir)
147 files = filter(os.path.isdir, files)
148 return self._filter(files, pat)
150 def exists(self, name):
151 return self.visible(name) and os.path.exists(name)
153 def isdir(self, name):
154 return self.visible(name) and os.path.isdir(name)
156 def islink(self, name):
157 return self.visible(name) and os.path.islink(name)
159 def isfile(self, name):
160 return self.visible(name) and os.path.isfile(name)
162 def sum(self, name):
163 self.checkfile(name)
164 BUFFERSIZE = 1024*8
165 f = open(name)
166 sum = md5.new()
167 while 1:
168 buffer = f.read(BUFFERSIZE)
169 if not buffer:
170 break
171 sum.update(buffer)
172 return sum.digest()
174 def size(self, name):
175 self.checkfile(name)
176 return os.stat(name)[ST_SIZE]
178 def mtime(self, name):
179 self.checkfile(name)
180 return time.localtime(os.stat(name)[ST_MTIME])
182 def stat(self, name):
183 self.checkfile(name)
184 size = os.stat(name)[ST_SIZE]
185 mtime = time.localtime(os.stat(name)[ST_MTIME])
186 return size, mtime
188 def info(self, name):
189 sum = self.sum(name)
190 size = os.stat(name)[ST_SIZE]
191 mtime = time.localtime(os.stat(name)[ST_MTIME])
192 return sum, size, mtime
194 def _list(self, function, list):
195 if list is None:
196 list = self.listfiles()
197 res = []
198 for name in list:
199 try:
200 res.append((name, function(name)))
201 except (os.error, IOError):
202 res.append((name, None))
203 return res
205 def sumlist(self, list = None):
206 return self._list(self.sum, list)
208 def statlist(self, list = None):
209 return self._list(self.stat, list)
211 def mtimelist(self, list = None):
212 return self._list(self.mtime, list)
214 def sizelist(self, list = None):
215 return self._list(self.size, list)
217 def infolist(self, list = None):
218 return self._list(self.info, list)
220 def _dict(self, function, list):
221 if list is None:
222 list = self.listfiles()
223 dict = {}
224 for name in list:
225 try:
226 dict[name] = function(name)
227 except (os.error, IOError):
228 pass
229 return dict
231 def sumdict(self, list = None):
232 return self.dict(self.sum, list)
234 def sizedict(self, list = None):
235 return self.dict(self.size, list)
237 def mtimedict(self, list = None):
238 return self.dict(self.mtime, list)
240 def statdict(self, list = None):
241 return self.dict(self.stat, list)
243 def infodict(self, list = None):
244 return self._dict(self.info, list)
246 def read(self, name, offset = 0, length = -1):
247 self.checkfile(name)
248 f = open(name)
249 f.seek(offset)
250 if length == 0:
251 data = ''
252 elif length < 0:
253 data = f.read()
254 else:
255 data = f.read(length)
256 f.close()
257 return data
259 def create(self, name):
260 self.check(name)
261 if os.path.exists(name):
262 self.checkfile(name)
263 bname = name + '~'
264 try:
265 os.unlink(bname)
266 except os.error:
267 pass
268 os.rename(name, bname)
269 f = open(name, 'w')
270 f.close()
272 def write(self, name, data, offset = 0):
273 self.checkfile(name)
274 f = open(name, 'r+')
275 f.seek(offset)
276 f.write(data)
277 f.close()
279 def mkdir(self, name):
280 self.check(name)
281 os.mkdir(name, 0777)
283 def rmdir(self, name):
284 self.check(name)
285 os.rmdir(name)
288 class FSProxyServer(FSProxyLocal, server.Server):
290 def __init__(self, address, verbose = server.VERBOSE):
291 FSProxyLocal.__init__(self)
292 server.Server.__init__(self, address, verbose)
294 def _close(self):
295 server.Server._close(self)
296 FSProxyLocal._close(self)
298 def _serve(self):
299 server.Server._serve(self)
300 # Retreat into start directory
301 while self._dirstack: self.back()
304 class FSProxyClient(client.Client):
306 def __init__(self, address, verbose = client.VERBOSE):
307 client.Client.__init__(self, address, verbose)
310 def test():
311 import string
312 import sys
313 if sys.argv[1:]:
314 port = string.atoi(sys.argv[1])
315 else:
316 port = 4127
317 proxy = FSProxyServer(('', port))
318 proxy._serverloop()
321 if __name__ == '__main__':
322 test()