| #! /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() |