commit -- why not
diff --git a/Demo/pdist/FSProxy.py b/Demo/pdist/FSProxy.py
new file mode 100755
index 0000000..7510d1e
--- /dev/null
+++ b/Demo/pdist/FSProxy.py
@@ -0,0 +1,322 @@
+"""File System Proxy.
+
+Provide an OS-neutral view on a file system, locally or remotely.
+The functionality is geared towards implementing some sort of
+rdist-like utility between a Mac and a UNIX system.
+
+The module defines three classes:
+
+FSProxyLocal -- used for local access
+FSProxyServer -- used on the server side of remote access
+FSProxyClient -- used on the client side of remote access
+
+The remote classes are instantiated with an IP address and an optional
+verbosity flag.
+"""
+
+import server
+import client
+import md5
+import os
+import fnmatch
+from stat import *
+import time
+import fnmatch
+
+if os.name == 'mac':
+ import macfs
+ maxnamelen = 31
+else:
+ macfs = None
+ maxnamelen = 255
+
+skipnames = (os.curdir, os.pardir)
+
+
+class FSProxyLocal:
+
+ def __init__(self):
+ self._dirstack = []
+ self._ignore = ['*.pyc'] + self._readignore()
+
+ def _close(self):
+ while self._dirstack:
+ self.back()
+
+ def _readignore(self):
+ file = self._hide('ignore')
+ try:
+ f = open(file)
+ except IOError:
+ file = self._hide('synctree.ignorefiles')
+ try:
+ f = open(file)
+ except IOError:
+ return []
+ ignore = []
+ while 1:
+ line = f.readline()
+ if not line: break
+ if line[-1] == '\n': line = line[:-1]
+ ignore.append(line)
+ f.close()
+ return ignore
+
+ def _hidden(self, name):
+ if os.name == 'mac':
+ return name[0] == '(' and name[-1] == ')'
+ else:
+ return name[0] == '.'
+
+ def _hide(self, name):
+ if os.name == 'mac':
+ return '(%s)' % name
+ else:
+ return '.%s' % name
+
+ def visible(self, name):
+ if len(name) > maxnamelen: return 0
+ if name[-1] == '~': return 0
+ if name in skipnames: return 0
+ if self._hidden(name): return 0
+ head, tail = os.path.split(name)
+ if head or not tail: return 0
+ if macfs:
+ if os.path.exists(name) and not os.path.isdir(name):
+ try:
+ fs = macfs.FSSpec(name)
+ c, t = fs.GetCreatorType()
+ if t != 'TEXT': return 0
+ except macfs.error, msg:
+ print "***", name, msg
+ return 0
+ else:
+ if os.path.islink(name): return 0
+ if '\0' in open(name, 'rb').read(512): return 0
+ for ign in self._ignore:
+ if fnmatch.fnmatch(name, ign): return 0
+ return 1
+
+ def check(self, name):
+ if not self.visible(name):
+ raise os.error, "protected name %s" % repr(name)
+
+ def checkfile(self, name):
+ self.check(name)
+ if not os.path.isfile(name):
+ raise os.error, "not a plain file %s" % repr(name)
+
+ def pwd(self):
+ return os.getcwd()
+
+ def cd(self, name):
+ self.check(name)
+ save = os.getcwd(), self._ignore
+ os.chdir(name)
+ self._dirstack.append(save)
+ self._ignore = self._ignore + self._readignore()
+
+ def back(self):
+ if not self._dirstack:
+ raise os.error, "empty directory stack"
+ dir, ignore = self._dirstack[-1]
+ os.chdir(dir)
+ del self._dirstack[-1]
+ self._ignore = ignore
+
+ def _filter(self, files, pat = None):
+ if pat:
+ def keep(name, pat = pat):
+ return fnmatch.fnmatch(name, pat)
+ files = filter(keep, files)
+ files = filter(self.visible, files)
+ files.sort()
+ return files
+
+ def list(self, pat = None):
+ files = os.listdir(os.curdir)
+ return self._filter(files, pat)
+
+ def listfiles(self, pat = None):
+ files = os.listdir(os.curdir)
+ files = filter(os.path.isfile, files)
+ return self._filter(files, pat)
+
+ def listsubdirs(self, pat = None):
+ files = os.listdir(os.curdir)
+ files = filter(os.path.isdir, files)
+ return self._filter(files, pat)
+
+ def exists(self, name):
+ return self.visible(name) and os.path.exists(name)
+
+ def isdir(self, name):
+ return self.visible(name) and os.path.isdir(name)
+
+ def islink(self, name):
+ return self.visible(name) and os.path.islink(name)
+
+ def isfile(self, name):
+ return self.visible(name) and os.path.isfile(name)
+
+ def sum(self, name):
+ self.checkfile(name)
+ BUFFERSIZE = 1024*8
+ f = open(name)
+ sum = md5.new()
+ while 1:
+ buffer = f.read(BUFFERSIZE)
+ if not buffer:
+ break
+ sum.update(buffer)
+ return sum.digest()
+
+ def size(self, name):
+ self.checkfile(name)
+ return os.stat(name)[ST_SIZE]
+
+ def mtime(self, name):
+ self.checkfile(name)
+ return time.localtime(os.stat(name)[ST_MTIME])
+
+ def stat(self, name):
+ self.checkfile(name)
+ size = os.stat(name)[ST_SIZE]
+ mtime = time.localtime(os.stat(name)[ST_MTIME])
+ return size, mtime
+
+ def info(self, name):
+ sum = self.sum(name)
+ size = os.stat(name)[ST_SIZE]
+ mtime = time.localtime(os.stat(name)[ST_MTIME])
+ return sum, size, mtime
+
+ def _list(self, function, list):
+ if list is None:
+ list = self.listfiles()
+ res = []
+ for name in list:
+ try:
+ res.append((name, function(name)))
+ except (os.error, IOError):
+ res.append((name, None))
+ return res
+
+ def sumlist(self, list = None):
+ return self._list(self.sum, list)
+
+ def statlist(self, list = None):
+ return self._list(self.stat, list)
+
+ def mtimelist(self, list = None):
+ return self._list(self.mtime, list)
+
+ def sizelist(self, list = None):
+ return self._list(self.size, list)
+
+ def infolist(self, list = None):
+ return self._list(self.info, list)
+
+ def _dict(self, function, list):
+ if list is None:
+ list = self.listfiles()
+ dict = {}
+ for name in list:
+ try:
+ dict[name] = function(name)
+ except (os.error, IOError):
+ pass
+ return dict
+
+ def sumdict(self, list = None):
+ return self.dict(self.sum, list)
+
+ def sizedict(self, list = None):
+ return self.dict(self.size, list)
+
+ def mtimedict(self, list = None):
+ return self.dict(self.mtime, list)
+
+ def statdict(self, list = None):
+ return self.dict(self.stat, list)
+
+ def infodict(self, list = None):
+ return self._dict(self.info, list)
+
+ def read(self, name, offset = 0, length = -1):
+ self.checkfile(name)
+ f = open(name)
+ f.seek(offset)
+ if length == 0:
+ data = ''
+ elif length < 0:
+ data = f.read()
+ else:
+ data = f.read(length)
+ f.close()
+ return data
+
+ def create(self, name):
+ self.check(name)
+ if os.path.exists(name):
+ self.checkfile(name)
+ bname = name + '~'
+ try:
+ os.unlink(bname)
+ except os.error:
+ pass
+ os.rename(name, bname)
+ f = open(name, 'w')
+ f.close()
+
+ def write(self, name, data, offset = 0):
+ self.checkfile(name)
+ f = open(name, 'r+')
+ f.seek(offset)
+ f.write(data)
+ f.close()
+
+ def mkdir(self, name):
+ self.check(name)
+ os.mkdir(name, 0777)
+
+ def rmdir(self, name):
+ self.check(name)
+ os.rmdir(name)
+
+
+class FSProxyServer(FSProxyLocal, server.Server):
+
+ def __init__(self, address, verbose = server.VERBOSE):
+ FSProxyLocal.__init__(self)
+ server.Server.__init__(self, address, verbose)
+
+ def _close(self):
+ server.Server._close(self)
+ FSProxyLocal._close(self)
+
+ def _serve(self):
+ server.Server._serve(self)
+ # Retreat into start directory
+ while self._dirstack: self.back()
+
+
+class FSProxyClient(client.Client):
+
+ def __init__(self, address, verbose = client.VERBOSE):
+ client.Client.__init__(self, address, verbose)
+
+
+def test():
+ import string
+ import sys
+ if sys.argv[1:]:
+ port = string.atoi(sys.argv[1])
+ else:
+ port = 4127
+ proxy = FSProxyServer(('', port))
+ proxy._serverloop()
+
+
+if __name__ == '__main__':
+ test()