| #! /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 `attr` |
| else: |
| print "%s: no such attribute" % what |
| sys.exit(2) |
| |
| |
| if __name__ == '__main__': |
| test() |