# HG changeset patch # User Patrick Mezard # Date 1226701104 21600 # Node ID edeec6829d8071f82abb1a13437ae0b85616a72a # Parent 3b60f223893af24997440ca6e8140def265bfb7f SubversionRepo: remember svn.diff3() does not work Calling it repeatedly is expensive, files and directories are created, svn transport layer is reset. diff --git a/fetch_command.py b/fetch_command.py --- a/fetch_command.py +++ b/fetch_command.py @@ -368,28 +368,20 @@ def stupid_svn_server_pull_rev(ui, svn, link_files = {} exec_files = {} try: - try: - if br_p == b: - # letting patch handle binaries sounded - # cool, but it breaks patch in sad ways - d = svn.get_unified_diff(diff_path, r.revnum, deleted=False, - ignore_type=False) - else: - d = svn.get_unified_diff(diff_path, r.revnum, - other_path=make_diff_path(br_p), - other_rev=parent_rev, - deleted=True, ignore_type=True) - if d: - ui.status('Branch creation with mods, pulling full rev.\n') - raise BadPatchApply() - except core.SubversionException, e: - # "Can't write to stream: The handle is invalid." - # This error happens systematically under Windows, possibly - # related to file handles being non-write shareable by default. - if e.apr_err != 720006: - raise - raise BadPatchApply() - + if br_p == b: + # letting patch handle binaries sounded + # cool, but it breaks patch in sad ways + d = svn.get_unified_diff(diff_path, r.revnum, deleted=False, + ignore_type=False) + else: + d = svn.get_unified_diff(diff_path, r.revnum, + other_path=make_diff_path(br_p), + other_rev=parent_rev, + deleted=True, ignore_type=True) + if d: + ui.status('Branch creation with mods, pulling full rev.\n') + raise BadPatchApply() + for m in binary_file_re.findall(d): # we have to pull each binary file by hand as a fulltext, # which sucks but we've got no choice @@ -517,7 +509,9 @@ def stupid_svn_server_pull_rev(ui, svn, os.remove(path) link_files[m] = link_path files_touched.add(m) - except (core.SubversionException, BadPatchApply), e: + except (core.SubversionException, + BadPatchApply, + svnwrap.SubversionRepoCanNotDiff), e: if (hasattr(e, 'apr_err') and e.apr_err != 160013): raise # Either this revision or the previous one does not exist. diff --git a/svnwrap/svn_swig_wrapper.py b/svnwrap/svn_swig_wrapper.py --- a/svnwrap/svn_swig_wrapper.py +++ b/svnwrap/svn_swig_wrapper.py @@ -14,6 +14,14 @@ from svn import ra if (core.SVN_VER_MAJOR, core.SVN_VER_MINOR, core.SVN_VER_MICRO) < (1, 5, 0): #pragma: no cover raise ImportError, 'You must have Subversion 1.5.0 or newer and matching SWIG bindings.' +class SubversionRepoCanNotReplay(Exception): + """Exception raised when the svn server is too old to have replay. + """ + +class SubversionRepoCanNotDiff(Exception): + """Exception raised when the svn API diff3() command cannot be used + """ + def optrev(revnum): optrev = core.svn_opt_revision_t() optrev.kind = core.svn_opt_revision_number @@ -111,6 +119,7 @@ class SubversionRepo(object): self.subdir = url[len(repo_root):] if not self.subdir or self.subdir[-1] != '/': self.subdir += '/' + self.hasdiff3 = True def init_ra_and_client(self): """Initializes the RA and client layers, because sometimes getting @@ -367,6 +376,8 @@ class SubversionRepo(object): deleted=True, ignore_type=False): """Gets a unidiff of path at revision against revision-1. """ + if not self.hasdiff3: + raise SubversionRepoCanNotDiff() # works around an svn server keeping too many open files (observed # in an svnserve from the 1.2 era) self.init_ra_and_client() @@ -380,24 +391,34 @@ class SubversionRepo(object): other_rev = revision - 1 old_cwd = os.getcwd() tmpdir = tempfile.mkdtemp('svnwrap_temp') + out, err = None, None try: # hot tip: the swig bridge doesn't like StringIO for these bad boys out_path = os.path.join(tmpdir, 'diffout') error_path = os.path.join(tmpdir, 'differr') - out, err = None, None + out = open(out_path, 'w') + err = open(error_path, 'w') try: - out = open(out_path, 'w') - err = open(error_path, 'w') client.diff3([], url2, optrev(other_rev), url, optrev(revision), True, True, deleted, ignore_type, 'UTF-8', out, err, self.client_context, self.pool) - finally: - if out: out.close() - if err: err.close() + except core.SubversionException, e: + # "Can't write to stream: The handle is invalid." + # This error happens systematically under Windows, possibly + # related to file handles being non-write shareable by default. + if e.apr_err != 720006: + raise + self.hasdiff3 = False + raise SubversionRepoCanNotDiff() + out.close() + err.close() + out, err = None, None assert len(open(error_path).read()) == 0 diff = open(out_path).read() return diff finally: + if out: out.close() + if err: err.close() shutil.rmtree(tmpdir) os.chdir(old_cwd) @@ -473,7 +494,3 @@ class SubversionRepo(object): """ kind = ra.check_path(self.ra, path.strip('/'), revision) return _svntypes.get(kind) - -class SubversionRepoCanNotReplay(Exception): - """Exception raised when the svn server is too old to have replay. - """