22 # e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing |
22 # e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing |
23 # these bindings. |
23 # these bindings. |
24 |
24 |
25 from cStringIO import StringIO |
25 from cStringIO import StringIO |
26 |
26 |
27 from common import NoRepo, commit, converter_source |
27 from common import NoRepo, commit, converter_source, encodeargs |
28 |
28 |
29 try: |
29 try: |
30 from svn.core import SubversionException, Pool |
30 from svn.core import SubversionException, Pool |
31 import svn |
31 import svn |
32 import svn.client |
32 import svn.client |
55 class changedpath(object): |
55 class changedpath(object): |
56 def __init__(self, p): |
56 def __init__(self, p): |
57 self.copyfrom_path = p.copyfrom_path |
57 self.copyfrom_path = p.copyfrom_path |
58 self.copyfrom_rev = p.copyfrom_rev |
58 self.copyfrom_rev = p.copyfrom_rev |
59 self.action = p.action |
59 self.action = p.action |
|
60 |
|
61 def get_log_child(fp, url, paths, start, end, limit=0, discover_changed_paths=True, |
|
62 strict_node_history=False): |
|
63 protocol = -1 |
|
64 def receiver(orig_paths, revnum, author, date, message, pool): |
|
65 if orig_paths is not None: |
|
66 for k, v in orig_paths.iteritems(): |
|
67 orig_paths[k] = changedpath(v) |
|
68 pickle.dump((orig_paths, revnum, author, date, message), |
|
69 fp, protocol) |
|
70 |
|
71 try: |
|
72 # Use an ra of our own so that our parent can consume |
|
73 # our results without confusing the server. |
|
74 t = transport.SvnRaTransport(url=url) |
|
75 svn.ra.get_log(t.ra, paths, start, end, limit, |
|
76 discover_changed_paths, |
|
77 strict_node_history, |
|
78 receiver) |
|
79 except SubversionException, (_, num): |
|
80 pickle.dump(num, fp, protocol) |
|
81 else: |
|
82 pickle.dump(None, fp, protocol) |
|
83 fp.close() |
60 |
84 |
61 # SVN conversion code stolen from bzr-svn and tailor |
85 # SVN conversion code stolen from bzr-svn and tailor |
62 class convert_svn(converter_source): |
86 class convert_svn(converter_source): |
63 def __init__(self, ui, url, rev=None): |
87 def __init__(self, ui, url, rev=None): |
64 super(convert_svn, self).__init__(ui, url, rev=rev) |
88 super(convert_svn, self).__init__(ui, url, rev=rev) |
194 del self.commits[rev] |
218 del self.commits[rev] |
195 return commit |
219 return commit |
196 |
220 |
197 def get_log(self, paths, start, end, limit=0, discover_changed_paths=True, |
221 def get_log(self, paths, start, end, limit=0, discover_changed_paths=True, |
198 strict_node_history=False): |
222 strict_node_history=False): |
199 '''wrapper for svn.ra.get_log. |
|
200 on a large repository, svn.ra.get_log pins huge amounts of |
|
201 memory that cannot be recovered. work around it by forking |
|
202 and writing results over a pipe.''' |
|
203 |
|
204 def child(fp): |
|
205 protocol = -1 |
|
206 def receiver(orig_paths, revnum, author, date, message, pool): |
|
207 if orig_paths is not None: |
|
208 for k, v in orig_paths.iteritems(): |
|
209 orig_paths[k] = changedpath(v) |
|
210 pickle.dump((orig_paths, revnum, author, date, message), |
|
211 fp, protocol) |
|
212 |
|
213 try: |
|
214 # Use an ra of our own so that our parent can consume |
|
215 # our results without confusing the server. |
|
216 t = transport.SvnRaTransport(url=self.url) |
|
217 svn.ra.get_log(t.ra, paths, start, end, limit, |
|
218 discover_changed_paths, |
|
219 strict_node_history, |
|
220 receiver) |
|
221 except SubversionException, (_, num): |
|
222 self.ui.print_exc() |
|
223 pickle.dump(num, fp, protocol) |
|
224 else: |
|
225 pickle.dump(None, fp, protocol) |
|
226 fp.close() |
|
227 |
223 |
228 def parent(fp): |
224 def parent(fp): |
229 while True: |
225 while True: |
230 entry = pickle.load(fp) |
226 entry = pickle.load(fp) |
231 try: |
227 try: |
233 except: |
229 except: |
234 if entry is None: |
230 if entry is None: |
235 break |
231 break |
236 raise SubversionException("child raised exception", entry) |
232 raise SubversionException("child raised exception", entry) |
237 yield entry |
233 yield entry |
238 |
234 |
239 rfd, wfd = os.pipe() |
235 args = [self.url, paths, start, end, limit, discover_changed_paths, |
240 pid = os.fork() |
236 strict_node_history] |
241 if pid: |
237 arg = encodeargs(args) |
242 os.close(wfd) |
238 hgexe = util.hgexecutable() |
243 for p in parent(os.fdopen(rfd, 'rb')): |
239 cmd = '"%s "debug-svn-log""' % util.shellquote(hgexe) |
244 yield p |
240 stdin, stdout = os.popen2(cmd, 'b') |
245 ret = os.waitpid(pid, 0)[1] |
241 |
246 if ret: |
242 stdin.write(arg) |
247 raise util.Abort(_('get_log %s') % util.explain_exit(ret)) |
243 stdin.close() |
248 else: |
244 |
249 os.close(rfd) |
245 for p in parent(stdout): |
250 child(os.fdopen(wfd, 'wb')) |
246 yield p |
251 os._exit(0) |
|
252 |
247 |
253 def gettags(self): |
248 def gettags(self): |
254 tags = {} |
249 tags = {} |
255 start = self.revnum(self.head) |
250 start = self.revnum(self.head) |
256 try: |
251 try: |