|
1 #! /usr/bin/env python |
|
2 |
|
3 """RCS Proxy. |
|
4 |
|
5 Provide a simplified interface on RCS files, locally or remotely. |
|
6 The functionality is geared towards implementing some sort of |
|
7 remote CVS like utility. It is modeled after the similar module |
|
8 FSProxy. |
|
9 |
|
10 The module defines two classes: |
|
11 |
|
12 RCSProxyLocal -- used for local access |
|
13 RCSProxyServer -- used on the server side of remote access |
|
14 |
|
15 The corresponding client class, RCSProxyClient, is defined in module |
|
16 rcsclient. |
|
17 |
|
18 The remote classes are instantiated with an IP address and an optional |
|
19 verbosity flag. |
|
20 """ |
|
21 |
|
22 import server |
|
23 import md5 |
|
24 import os |
|
25 import fnmatch |
|
26 import string |
|
27 import tempfile |
|
28 import rcslib |
|
29 |
|
30 |
|
31 class 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 |
|
73 class 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 |
|
152 class 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 |
|
168 def 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 |
|
179 def 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 |
|
197 if __name__ == '__main__': |
|
198 test() |