in contrib/client-side/svnmerge/svnmerge-migrate-history-remotely.py [0:0]
def migrate_path(self, path):
sys.stdout.write("Searching for merge tracking information...\n")
# Get svnmerge-integrated property for PATH, as Subversion mergeinfo.
integrated_mergeinfo = svnmerge_prop_to_mergeinfo(
self.cc.get_path_property(path, 'svnmerge-integrated'))
if integrated_mergeinfo and self.verbose:
sys.stdout.write("Found svnmerge-integrated:\n")
pretty_print_mergeinfo(integrated_mergeinfo, 3)
# Get svnmerge-blocked property for PATH, as Subversion mergeinfo.
blocked_mergeinfo = svnmerge_prop_to_mergeinfo(
self.cc.get_path_property(path, 'svnmerge-blocked'))
if blocked_mergeinfo and self.verbose:
sys.stdout.write("Found svnmerge-blocked:\n")
pretty_print_mergeinfo(blocked_mergeinfo, 3)
# No svnmerge tracking data? Nothing to do.
if not (integrated_mergeinfo or blocked_mergeinfo):
errput("No svnmerge.py tracking data found for '%s'." % (path),
True)
return
# Fetch Subversion mergeinfo for PATH. Hopefully there is
# none, but if there is, we'll assume folks want to keep it.
orig_mergeinfo = self.cc.get_path_mergeinfo(path)
if orig_mergeinfo and self.verbose:
sys.stdout.write("Found Subversion mergeinfo:\n")
pretty_print_mergeinfo(orig_mergeinfo, 3)
# Merge all our mergeinfos together.
new_mergeinfo = mergeinfo_merge(orig_mergeinfo, integrated_mergeinfo)
new_mergeinfo = mergeinfo_merge(new_mergeinfo, blocked_mergeinfo)
# Unless we're doing a naive migration (or we've no, or only
# empty, mergeinfo anyway), start trying to cleanup after
# svnmerge.py's history-ignorant initialization.
if not self.naive and new_mergeinfo:
sys.stdout.write("Sanitizing mergeinfo (this can take a "
"while)...\n")
# What we need:
# - the relative path in the repository for PATH
# - repository root URL and an RA session rooted thereat
# - the base revision of PATH
path_url, root_url = self.cc.get_path_urls(path)
if root_url:
ras = self.cc.open_ra_session(root_url)
else:
ras = self.cc.open_ra_session(path_url)
root_url = ra.get_repos_root(ras)
ra.reparent(ras, root_url)
assert path_url.startswith(root_url)
rel_path = relative_path_from_urls(root_url, path_url)
path_rev = self.cc.get_path_revision(path)
# We begin by subtracting the natural history of the merge
# target from its own mergeinfo.
implicit_mergeinfo = \
self.cc.get_history_as_mergeinfo(ras, rel_path, path_rev)
if self.verbose:
sys.stdout.write(" subtracting natural history:\n")
pretty_print_mergeinfo(implicit_mergeinfo, 6)
new_mergeinfo = core.svn_mergeinfo_remove(implicit_mergeinfo,
new_mergeinfo)
if self.verbose:
sys.stdout.write(" remaining mergeinfo to be filtered:\n")
pretty_print_mergeinfo(new_mergeinfo, 6)
# Unfortunately, svnmerge.py tends to initialize using
# oft-bogus revision ranges like 1-SOMETHING when the
# merge source didn't even exist in r1. So if the natural
# history of a branch begins in some revision other than
# r1, there's still going to be cruft revisions left in
# NEW_MERGEINFO after subtracting the natural history.
# So, we also examine the natural history of the merge
# sources, and use that as a filter for the explicit
# mergeinfo we've calculated so far.
mergeinfo_so_far = new_mergeinfo
new_mergeinfo = {}
for source_path, ranges in mergeinfo_so_far.items():
# If by some chance it is the case that /path:RANGE1
# and /path:RANGE2 a) represent different lines of
# history, and b) were combined into
# /path:RANGE1+RANGE2 (due to the ranges being
# contiguous), we'll foul this up. But the chances
# are preeeeeeeetty slim.
for range in ranges:
try:
history = self.cc.get_history_as_mergeinfo(
ras, source_path[1:], range.end, range.start + 1)
if self.verbose:
sys.stdout.write(" new sanitized chunk:\n")
pretty_print_mergeinfo(history, 6)
new_mergeinfo = mergeinfo_merge(new_mergeinfo, history)
except core.SubversionException as e:
if not (e.apr_err == core.SVN_ERR_FS_NOT_FOUND
or e.apr_err == core.SVN_ERR_FS_NO_SUCH_REVISION):
raise
if self.verbose:
sys.stdout.write("New converted mergeinfo:\n")
pretty_print_mergeinfo(new_mergeinfo, 3)
sys.stdout.write("Locally removing svnmerge properties and setting "
"new svn:mergeinfo property.\n")
self.cc.set_path_property(path, 'svnmerge-integrated', None)
self.cc.set_path_property(path, 'svnmerge-blocked', None)
self.cc.set_path_property(path, 'svn:mergeinfo',
core.svn_mergeinfo_to_string(new_mergeinfo))