Mercurial > hgsubversion
comparison svnwrap/svn_swig_wrapper.py @ 89:edeec6829d80
SubversionRepo: remember svn.diff3() does not work
Calling it repeatedly is expensive, files and directories are created,
svn transport layer is reset.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Fri, 14 Nov 2008 16:18:24 -0600 |
parents | b033d74be76b |
children | 7486c6f6cccc |
comparison
equal
deleted
inserted
replaced
88:3b60f223893a | 89:edeec6829d80 |
---|---|
11 from svn import delta | 11 from svn import delta |
12 from svn import ra | 12 from svn import ra |
13 | 13 |
14 if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_MICRO) < (1, 5, 0): #pragma: no cover | 14 if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_MICRO) < (1, 5, 0): #pragma: no cover |
15 raise ImportError, 'You must have Subversion 1.5.0 or newer and matching SWIG bindings.' | 15 raise ImportError, 'You must have Subversion 1.5.0 or newer and matching SWIG bindings.' |
16 | |
17 class SubversionRepoCanNotReplay(Exception): | |
18 """Exception raised when the svn server is too old to have replay. | |
19 """ | |
20 | |
21 class SubversionRepoCanNotDiff(Exception): | |
22 """Exception raised when the svn API diff3() command cannot be used | |
23 """ | |
16 | 24 |
17 def optrev(revnum): | 25 def optrev(revnum): |
18 optrev = core.svn_opt_revision_t() | 26 optrev = core.svn_opt_revision_t() |
19 optrev.kind = core.svn_opt_revision_number | 27 optrev.kind = core.svn_opt_revision_number |
20 optrev.value.number = revnum | 28 optrev.value.number = revnum |
109 repo_root = ra.get_repos_root(self.ra, self.pool) | 117 repo_root = ra.get_repos_root(self.ra, self.pool) |
110 # *will* have a leading '/', would not if we used get_repos_root2 | 118 # *will* have a leading '/', would not if we used get_repos_root2 |
111 self.subdir = url[len(repo_root):] | 119 self.subdir = url[len(repo_root):] |
112 if not self.subdir or self.subdir[-1] != '/': | 120 if not self.subdir or self.subdir[-1] != '/': |
113 self.subdir += '/' | 121 self.subdir += '/' |
122 self.hasdiff3 = True | |
114 | 123 |
115 def init_ra_and_client(self): | 124 def init_ra_and_client(self): |
116 """Initializes the RA and client layers, because sometimes getting | 125 """Initializes the RA and client layers, because sometimes getting |
117 unified diffs runs the remote server out of open files. | 126 unified diffs runs the remote server out of open files. |
118 """ | 127 """ |
365 | 374 |
366 def get_unified_diff(self, path, revision, other_path=None, other_rev=None, | 375 def get_unified_diff(self, path, revision, other_path=None, other_rev=None, |
367 deleted=True, ignore_type=False): | 376 deleted=True, ignore_type=False): |
368 """Gets a unidiff of path at revision against revision-1. | 377 """Gets a unidiff of path at revision against revision-1. |
369 """ | 378 """ |
379 if not self.hasdiff3: | |
380 raise SubversionRepoCanNotDiff() | |
370 # works around an svn server keeping too many open files (observed | 381 # works around an svn server keeping too many open files (observed |
371 # in an svnserve from the 1.2 era) | 382 # in an svnserve from the 1.2 era) |
372 self.init_ra_and_client() | 383 self.init_ra_and_client() |
373 | 384 |
374 assert path[0] != '/' | 385 assert path[0] != '/' |
378 url2 = self.svn_url + '/' + other_path | 389 url2 = self.svn_url + '/' + other_path |
379 if other_rev is None: | 390 if other_rev is None: |
380 other_rev = revision - 1 | 391 other_rev = revision - 1 |
381 old_cwd = os.getcwd() | 392 old_cwd = os.getcwd() |
382 tmpdir = tempfile.mkdtemp('svnwrap_temp') | 393 tmpdir = tempfile.mkdtemp('svnwrap_temp') |
394 out, err = None, None | |
383 try: | 395 try: |
384 # hot tip: the swig bridge doesn't like StringIO for these bad boys | 396 # hot tip: the swig bridge doesn't like StringIO for these bad boys |
385 out_path = os.path.join(tmpdir, 'diffout') | 397 out_path = os.path.join(tmpdir, 'diffout') |
386 error_path = os.path.join(tmpdir, 'differr') | 398 error_path = os.path.join(tmpdir, 'differr') |
387 out, err = None, None | 399 out = open(out_path, 'w') |
400 err = open(error_path, 'w') | |
388 try: | 401 try: |
389 out = open(out_path, 'w') | |
390 err = open(error_path, 'w') | |
391 client.diff3([], url2, optrev(other_rev), url, optrev(revision), | 402 client.diff3([], url2, optrev(other_rev), url, optrev(revision), |
392 True, True, deleted, ignore_type, 'UTF-8', out, err, | 403 True, True, deleted, ignore_type, 'UTF-8', out, err, |
393 self.client_context, self.pool) | 404 self.client_context, self.pool) |
394 finally: | 405 except core.SubversionException, e: |
395 if out: out.close() | 406 # "Can't write to stream: The handle is invalid." |
396 if err: err.close() | 407 # This error happens systematically under Windows, possibly |
408 # related to file handles being non-write shareable by default. | |
409 if e.apr_err != 720006: | |
410 raise | |
411 self.hasdiff3 = False | |
412 raise SubversionRepoCanNotDiff() | |
413 out.close() | |
414 err.close() | |
415 out, err = None, None | |
397 assert len(open(error_path).read()) == 0 | 416 assert len(open(error_path).read()) == 0 |
398 diff = open(out_path).read() | 417 diff = open(out_path).read() |
399 return diff | 418 return diff |
400 finally: | 419 finally: |
420 if out: out.close() | |
421 if err: err.close() | |
401 shutil.rmtree(tmpdir) | 422 shutil.rmtree(tmpdir) |
402 os.chdir(old_cwd) | 423 os.chdir(old_cwd) |
403 | 424 |
404 def get_file(self, path, revision): | 425 def get_file(self, path, revision): |
405 """Return content and mode of file at given path and revision. | 426 """Return content and mode of file at given path and revision. |
471 """Return the entry type at the given revision, 'f', 'd' or None | 492 """Return the entry type at the given revision, 'f', 'd' or None |
472 if the entry does not exist. | 493 if the entry does not exist. |
473 """ | 494 """ |
474 kind = ra.check_path(self.ra, path.strip('/'), revision) | 495 kind = ra.check_path(self.ra, path.strip('/'), revision) |
475 return _svntypes.get(kind) | 496 return _svntypes.get(kind) |
476 | |
477 class SubversionRepoCanNotReplay(Exception): | |
478 """Exception raised when the svn server is too old to have replay. | |
479 """ |