| #! /usr/bin/env python | 
 |  | 
 | """RCS Proxy. | 
 |  | 
 | Provide a simplified interface on RCS files, locally or remotely. | 
 | The functionality is geared towards implementing some sort of | 
 | remote CVS like utility.  It is modeled after the similar module | 
 | FSProxy. | 
 |  | 
 | The module defines two classes: | 
 |  | 
 | RCSProxyLocal  -- used for local access | 
 | RCSProxyServer -- used on the server side of remote access | 
 |  | 
 | The corresponding client class, RCSProxyClient, is defined in module | 
 | rcsclient. | 
 |  | 
 | The remote classes are instantiated with an IP address and an optional | 
 | verbosity flag. | 
 | """ | 
 |  | 
 | import server | 
 | import md5 | 
 | import os | 
 | import fnmatch | 
 | import string | 
 | import tempfile | 
 | import rcslib | 
 |  | 
 |  | 
 | class DirSupport: | 
 |  | 
 |     def __init__(self): | 
 |         self._dirstack = [] | 
 |  | 
 |     def __del__(self): | 
 |         self._close() | 
 |  | 
 |     def _close(self): | 
 |         while self._dirstack: | 
 |             self.back() | 
 |  | 
 |     def pwd(self): | 
 |         return os.getcwd() | 
 |  | 
 |     def cd(self, name): | 
 |         save = os.getcwd() | 
 |         os.chdir(name) | 
 |         self._dirstack.append(save) | 
 |  | 
 |     def back(self): | 
 |         if not self._dirstack: | 
 |             raise os.error, "empty directory stack" | 
 |         dir = self._dirstack[-1] | 
 |         os.chdir(dir) | 
 |         del self._dirstack[-1] | 
 |  | 
 |     def listsubdirs(self, pat = None): | 
 |         files = os.listdir(os.curdir) | 
 |         files = filter(os.path.isdir, files) | 
 |         return self._filter(files, pat) | 
 |  | 
 |     def isdir(self, name): | 
 |         return os.path.isdir(name) | 
 |  | 
 |     def mkdir(self, name): | 
 |         os.mkdir(name, 0777) | 
 |  | 
 |     def rmdir(self, name): | 
 |         os.rmdir(name) | 
 |  | 
 |  | 
 | class RCSProxyLocal(rcslib.RCS, DirSupport): | 
 |  | 
 |     def __init__(self): | 
 |         rcslib.RCS.__init__(self) | 
 |         DirSupport.__init__(self) | 
 |  | 
 |     def __del__(self): | 
 |         DirSupport.__del__(self) | 
 |         rcslib.RCS.__del__(self) | 
 |  | 
 |     def sumlist(self, list = None): | 
 |         return self._list(self.sum, list) | 
 |  | 
 |     def sumdict(self, list = None): | 
 |         return self._dict(self.sum, list) | 
 |  | 
 |     def sum(self, name_rev): | 
 |         f = self._open(name_rev) | 
 |         BUFFERSIZE = 1024*8 | 
 |         sum = md5.new() | 
 |         while 1: | 
 |             buffer = f.read(BUFFERSIZE) | 
 |             if not buffer: | 
 |                 break | 
 |             sum.update(buffer) | 
 |         self._closepipe(f) | 
 |         return sum.digest() | 
 |  | 
 |     def get(self, name_rev): | 
 |         f = self._open(name_rev) | 
 |         data = f.read() | 
 |         self._closepipe(f) | 
 |         return data | 
 |  | 
 |     def put(self, name_rev, data, message=None): | 
 |         name, rev = self._unmangle(name_rev) | 
 |         f = open(name, 'w') | 
 |         f.write(data) | 
 |         f.close() | 
 |         self.checkin(name_rev, message) | 
 |         self._remove(name) | 
 |  | 
 |     def _list(self, function, list = None): | 
 |         """INTERNAL: apply FUNCTION to all files in LIST. | 
 |  | 
 |         Return a list of the results. | 
 |  | 
 |         The list defaults to all files in the directory if None. | 
 |  | 
 |         """ | 
 |         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 _dict(self, function, list = None): | 
 |         """INTERNAL: apply FUNCTION to all files in LIST. | 
 |  | 
 |         Return a dictionary mapping files to results. | 
 |  | 
 |         The list defaults to all files in the directory if None. | 
 |  | 
 |         """ | 
 |         if list is None: | 
 |             list = self.listfiles() | 
 |         dict = {} | 
 |         for name in list: | 
 |             try: | 
 |                 dict[name] = function(name) | 
 |             except (os.error, IOError): | 
 |                 pass | 
 |         return dict | 
 |  | 
 |  | 
 | class RCSProxyServer(RCSProxyLocal, server.SecureServer): | 
 |  | 
 |     def __init__(self, address, verbose = server.VERBOSE): | 
 |         RCSProxyLocal.__init__(self) | 
 |         server.SecureServer.__init__(self, address, verbose) | 
 |  | 
 |     def _close(self): | 
 |         server.SecureServer._close(self) | 
 |         RCSProxyLocal._close(self) | 
 |  | 
 |     def _serve(self): | 
 |         server.SecureServer._serve(self) | 
 |         # Retreat into start directory | 
 |         while self._dirstack: self.back() | 
 |  | 
 |  | 
 | def test_server(): | 
 |     import string | 
 |     import sys | 
 |     if sys.argv[1:]: | 
 |         port = string.atoi(sys.argv[1]) | 
 |     else: | 
 |         port = 4127 | 
 |     proxy = RCSProxyServer(('', port)) | 
 |     proxy._serverloop() | 
 |  | 
 |  | 
 | def test(): | 
 |     import sys | 
 |     if not sys.argv[1:] or sys.argv[1] and sys.argv[1][0] in '0123456789': | 
 |         test_server() | 
 |         sys.exit(0) | 
 |     proxy = RCSProxyLocal() | 
 |     what = sys.argv[1] | 
 |     if hasattr(proxy, what): | 
 |         attr = getattr(proxy, what) | 
 |         if callable(attr): | 
 |             print apply(attr, tuple(sys.argv[2:])) | 
 |         else: | 
 |             print repr(attr) | 
 |     else: | 
 |         print "%s: no such attribute" % what | 
 |         sys.exit(2) | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     test() |