# HG changeset patch # User Augie Fackler # Date 1334874608 18000 # Node ID 39d45f2190ee7a8079b9bfc32b9ac4d8181dbd8e # Parent 6ef6c413d6ded4b367e0f7be7990d5b449dace1b# Parent c24130e9ddb79d6a6efcf00a790d5910344a69f1 Merge diff --git a/hgsubversion/editor.py b/hgsubversion/editor.py --- a/hgsubversion/editor.py +++ b/hgsubversion/editor.py @@ -10,6 +10,18 @@ import svnwrap import util import svnexternals +class NeverClosingStringIO(object): + def __init__(self): + self._fp = cStringIO.StringIO() + + def __getattr__(self, name): + return getattr(self._fp, name) + + def close(self): + # svn 1.7 apply_delta driver now calls close() on passed file + # object which prevent us from calling getvalue() afterwards. + pass + class RevisionData(object): __slots__ = [ @@ -331,7 +343,7 @@ class HgEditor(svnwrap.Editor): if self.current.file in self.current.missing: return lambda x: None base = self.current.files[self.current.file] - target = cStringIO.StringIO() + target = NeverClosingStringIO() self.stream = target handler = svnwrap.apply_txdelta(base, target) @@ -342,13 +354,10 @@ class HgEditor(svnwrap.Editor): try: if not self.meta.is_path_valid(self.current.file): return - # Already get and store the value here, because calling - # handler(window) seems to close the target in Subversion 1.7. - val = target.getvalue() handler(window) # window being None means commit this file if not window: - self.current.files[self.current.file] = val + self.current.files[self.current.file] = target.getvalue() except svnwrap.SubversionException, e: # pragma: no cover if e.args[1] == svnwrap.ERR_INCOMPLETE_DATA: self.current.missing.add(self.current.file) diff --git a/hgsubversion/stupid.py b/hgsubversion/stupid.py --- a/hgsubversion/stupid.py +++ b/hgsubversion/stupid.py @@ -80,6 +80,10 @@ class filediff: def isempty(self): return (not self.diff and not self.binary and not self.hasprops) + def maybedir(self): + return (not self.diff and not self.binary and self.hasprops + and self.symlink is None and self.executable is None) + def parsediff(diff): changes = {} headers = headers_re.split(diff)[1:] @@ -320,6 +324,23 @@ def diff_branchrev(ui, svn, meta, branch touched_files.update(files_data) touched_files.update(unknown_files) + # As of svn 1.7, diff may contain a lot of property changes for + # directories. We do not what to include these in our touched + # files list so we try to filter them while minimizing the number + # of svn API calls. + property_files = set(f.name for f in changed if f.maybedir()) + property_files.discard('.') + touched_files.discard('.') + branchprefix = (branchpath and branchpath + '/') or branchpath + for f in list(property_files): + if f in parentctx: + continue + # We can be smarter here by checking if f is a subcomponent + # of a know path in parentctx or touched_files. KISS for now. + kind = svn.checkpath(branchprefix + f, r.revnum) + if kind == 'd': + touched_files.discard(f) + copies = getcopies(svn, meta, branch, branchpath, r, touched_files, parentctx) @@ -694,7 +715,13 @@ def convert_rev(ui, meta, svn, r, tbdelt deleted_branches[b] = parentctx.node() continue - incremental = (meta.revmap.oldest > 0) + # The nullrev check might not be necessary in theory but svn < + # 1.7 failed to diff branch creation so the diff_branchrev() + # path does not support this case with svn >= 1.7. We can fix + # it, or we can force the existing fetch_branchrev() path. Do + # the latter for now. + incremental = (meta.revmap.oldest > 0 and + parentctx.rev() != node.nullrev) if incremental: try: