1#! /usr/bin/env python
2
3"""RCS Proxy.
4
5Provide a simplified interface on RCS files, locally or remotely.
6The functionality is geared towards implementing some sort of
7remote CVS like utility.  It is modeled after the similar module
8FSProxy.
9
10The module defines two classes:
11
12RCSProxyLocal  -- used for local access
13RCSProxyServer -- used on the server side of remote access
14
15The corresponding client class, RCSProxyClient, is defined in module
16rcsclient.
17
18The remote classes are instantiated with an IP address and an optional
19verbosity flag.
20"""
21
22import server
23import md5
24import os
25import fnmatch
26import string
27import tempfile
28import rcslib
29
30
31class DirSupport:
32
33    def __init__(self):
34        self._dirstack = []
35
36    def __del__(self):
37        self._close()
38
39    def _close(self):
40        while self._dirstack:
41            self.back()
42
43    def pwd(self):
44        return os.getcwd()
45
46    def cd(self, name):
47        save = os.getcwd()
48        os.chdir(name)
49        self._dirstack.append(save)
50
51    def back(self):
52        if not self._dirstack:
53            raise os.error, "empty directory stack"
54        dir = self._dirstack[-1]
55        os.chdir(dir)
56        del self._dirstack[-1]
57
58    def listsubdirs(self, pat = None):
59        files = os.listdir(os.curdir)
60        files = filter(os.path.isdir, files)
61        return self._filter(files, pat)
62
63    def isdir(self, name):
64        return os.path.isdir(name)
65
66    def mkdir(self, name):
67        os.mkdir(name, 0777)
68
69    def rmdir(self, name):
70        os.rmdir(name)
71
72
73class RCSProxyLocal(rcslib.RCS, DirSupport):
74
75    def __init__(self):
76        rcslib.RCS.__init__(self)
77        DirSupport.__init__(self)
78
79    def __del__(self):
80        DirSupport.__del__(self)
81        rcslib.RCS.__del__(self)
82
83    def sumlist(self, list = None):
84        return self._list(self.sum, list)
85
86    def sumdict(self, list = None):
87        return self._dict(self.sum, list)
88
89    def sum(self, name_rev):
90        f = self._open(name_rev)
91        BUFFERSIZE = 1024*8
92        sum = md5.new()
93        while 1:
94            buffer = f.read(BUFFERSIZE)
95            if not buffer:
96                break
97            sum.update(buffer)
98        self._closepipe(f)
99        return sum.digest()
100
101    def get(self, name_rev):
102        f = self._open(name_rev)
103        data = f.read()
104        self._closepipe(f)
105        return data
106
107    def put(self, name_rev, data, message=None):
108        name, rev = self._unmangle(name_rev)
109        f = open(name, 'w')
110        f.write(data)
111        f.close()
112        self.checkin(name_rev, message)
113        self._remove(name)
114
115    def _list(self, function, list = None):
116        """INTERNAL: apply FUNCTION to all files in LIST.
117
118        Return a list of the results.
119
120        The list defaults to all files in the directory if None.
121
122        """
123        if list is None:
124            list = self.listfiles()
125        res = []
126        for name in list:
127            try:
128                res.append((name, function(name)))
129            except (os.error, IOError):
130                res.append((name, None))
131        return res
132
133    def _dict(self, function, list = None):
134        """INTERNAL: apply FUNCTION to all files in LIST.
135
136        Return a dictionary mapping files to results.
137
138        The list defaults to all files in the directory if None.
139
140        """
141        if list is None:
142            list = self.listfiles()
143        dict = {}
144        for name in list:
145            try:
146                dict[name] = function(name)
147            except (os.error, IOError):
148                pass
149        return dict
150
151
152class RCSProxyServer(RCSProxyLocal, server.SecureServer):
153
154    def __init__(self, address, verbose = server.VERBOSE):
155        RCSProxyLocal.__init__(self)
156        server.SecureServer.__init__(self, address, verbose)
157
158    def _close(self):
159        server.SecureServer._close(self)
160        RCSProxyLocal._close(self)
161
162    def _serve(self):
163        server.SecureServer._serve(self)
164        # Retreat into start directory
165        while self._dirstack: self.back()
166
167
168def test_server():
169    import string
170    import sys
171    if sys.argv[1:]:
172        port = string.atoi(sys.argv[1])
173    else:
174        port = 4127
175    proxy = RCSProxyServer(('', port))
176    proxy._serverloop()
177
178
179def test():
180    import sys
181    if not sys.argv[1:] or sys.argv[1] and sys.argv[1][0] in '0123456789':
182        test_server()
183        sys.exit(0)
184    proxy = RCSProxyLocal()
185    what = sys.argv[1]
186    if hasattr(proxy, what):
187        attr = getattr(proxy, what)
188        if callable(attr):
189            print apply(attr, tuple(sys.argv[2:]))
190        else:
191            print repr(attr)
192    else:
193        print "%s: no such attribute" % what
194        sys.exit(2)
195
196
197if __name__ == '__main__':
198    test()
199