def pretty_print_mergeinfo(mergeinfo, indent=0):
    """Print MERGEINFO hash, one source per line, with a given INDENT."""

    mstr = core.svn_mergeinfo_to_string(mergeinfo)
    sys.stdout.write('\n'.join(
        map(lambda x: indent * ' ' + x, filter(None, mstr.split('\n')))) +
                     '\n')
Esempio n. 2
0
def hasher(hash_file, newmergeinfo_file):
  new_mergeinfo =  core.svn_mergeinfo_to_string(mergeinfo)
  with open(newmergeinfo_file, "a") as buffer_file:
    pickle.dump(new_mergeinfo, buffer_file)
  buffer_file.close()

  with open(newmergeinfo_file, "rb") as buffer_file:
    hash_of_buffer_file = md5_of_file(buffer_file)
  buffer_file.close()

  with open(hash_file, "w") as hash_file:
    pickle.dump(hash_of_buffer_file, hash_file)
  hash_file.close()
Esempio n. 3
0
def hasher(hash_file, newmergeinfo_file):
    new_mergeinfo = core.svn_mergeinfo_to_string(mergeinfo)
    with open(newmergeinfo_file, "a") as buffer_file:
        pickle.dump(new_mergeinfo, buffer_file)
    buffer_file.close()

    with open(newmergeinfo_file, "rb") as buffer_file:
        hash_of_buffer_file = md5_of_file(buffer_file)
    buffer_file.close()

    with open(hash_file, "w") as hash_file:
        pickle.dump(hash_of_buffer_file, hash_file)
    hash_file.close()
def pretty_print_mergeinfo(mergeinfo, indent=0):
    """Print MERGEINFO hash, one source per line, with a given INDENT."""

    mstr = core.svn_mergeinfo_to_string(mergeinfo)
    sys.stdout.write('\n'.join(map(lambda x: indent * ' ' + x,
                                   filter(None, mstr.split('\n')))) + '\n')
class SvnmergeHistoryMigrator:
    """svnmerge.py tracking data conversion class."""
    def __init__(self, client_context, verbose=False, naive=False):
        self.cc = client_context
        self.verbose = verbose
        self.naive = naive

    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, 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))
    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))