Exemple #1
0
def strip_nested_removes(targets):
    """Strip files within removed folders and return a cleaned up list."""
    # We're going a safe way here: "svn info" fails on items within removed
    # dirs.
    clean_targets = []
    for target in targets:
        try:
            run_svn(['info', '--xml', target], mask_atsign=True)
        except ExternalCommandFailed, err:
            ui.status(str(err), level=ui.DEBUG)
            continue
        clean_targets.append(target)
Exemple #2
0
def strip_nested_removes(targets):
    """Strip files within removed folders and return a cleaned up list."""
    # We're going a safe way here: "svn info" fails on items within removed
    # dirs.
    clean_targets = []
    for target in targets:
        try:
            run_svn(['info', '--xml', target], mask_atsign=True)
        except ExternalCommandFailed, err:
            ui.status(str(err), level=ui.DEBUG)
            continue
        clean_targets.append(target)
Exemple #3
0
def adjust_executable_property(files):
    execflags = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
    svn_map = {}
    for fname in files:
        if run_svn(['propget', 'svn:executable', fname],
                   mask_atsign=True).strip():
            svn_map[fname] = True
        else:
            svn_map[fname] = False
    for fname in files:
        m = os.stat(fname).st_mode & 0777
        is_exec = bool(m & execflags)
        if is_exec and not svn_map[fname]:
            run_svn(['propset', 'svn:executable', 'ON', fname],
                    mask_atsign=True)
        elif not is_exec and svn_map[fname]:
            run_svn(['propdel', 'svn:executable', fname], mask_atsign=True)
Exemple #4
0
def adjust_executable_property(files):
    execflags = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
    svn_map = {}
    for fname in files:
        if run_svn(['propget', 'svn:executable', fname],
                   mask_atsign=True).strip():
            svn_map[fname] = True
        else:
            svn_map[fname] = False
    for fname in files:
        m = os.stat(fname).st_mode & 0777
        is_exec = bool(m & execflags)
        if is_exec and not svn_map[fname]:
            run_svn(['propset', 'svn:executable', 'ON', fname],
                    mask_atsign=True)
        elif not is_exec and svn_map[fname]:
            run_svn(['propdel', 'svn:executable', fname], mask_atsign=True)
Exemple #5
0
def svn_checkout(svn_url, checkout_dir, rev_number=None):
    """
    Checkout the given URL at an optional revision number.
    """
    args = []
    if rev_number is not None:
        args += ['-r', rev_number]
    args += [svn_url, checkout_dir]
    return run_svn(svn_checkout_args + args)
Exemple #6
0
def svn_checkout(svn_url, checkout_dir, rev_number=None):
    """
    Checkout the given URL at an optional revision number.
    """
    args = []
    if rev_number is not None:
        args += ['-r', rev_number]
    args += [svn_url, checkout_dir]
    return run_svn(svn_checkout_args + args)
Exemple #7
0
def do_svn_copy(src, dest):
    """
    Call Svn copy command to record copying file src to file dest.
    If src is present then backup src before other tasks.
    Before issuing copy command move dest to src and remove src after
    """
    backup_src = ''
    if os.path.exists(src):
        backup_src = os.path.join(hgsvn_private_dir, "hgpushsvn_backup.tmp")
        os.rename(src, backup_src)

    try:
        try:
            # We assume that src is cotrolled by svn
            os.rename(dest, src)

            # Create svn subdirectories if needed
            # We know that subdirectories themselves are present
            # as dest is present
            pattern = re.compile(r"[/\\]")
            pos = 0
            while(True):
                match = pattern.search(dest, pos + 1)
                if match == None:
                    break

                pos = match.start()
                run_svn(['add', '--depth=empty'], [dest[:pos]],
                        mask_atsign=True)
                pos = match.end() - 1

            # Do the copy itself
            run_svn(['copy', src, dest], mask_atsign=True)
        except ExternalCommandFailed:
            # Revert rename
            os.rename(src, dest)
    finally:
        if os.path.isfile(src):
            os.remove(src)

        if(backup_src):
            os.rename(backup_src, src)
Exemple #8
0
def do_svn_copy(src, dest):
    """
    Call Svn copy command to record copying file src to file dest.
    If src is present then backup src before other tasks.
    Before issuing copy command move dest to src and remove src after
    """
    backup_src = ''
    if os.path.exists(src):
        backup_src = os.path.join(hgsvn_private_dir, "hgpushsvn_backup.tmp")
        os.rename(src, backup_src)

    try:
        try:
            # We assume that src is cotrolled by svn
            os.rename(dest, src)

            # Create svn subdirectories if needed
            # We know that subdirectories themselves are present
            # as dest is present
            pattern = re.compile(r"[/\\]")
            pos = 0
            while (True):
                match = pattern.search(dest, pos + 1)
                if match == None:
                    break

                pos = match.start()
                run_svn(['add', '--depth=empty'], [dest[:pos]],
                        mask_atsign=True)
                pos = match.end() - 1

            # Do the copy itself
            run_svn(['copy', src, dest], mask_atsign=True)
        except ExternalCommandFailed:
            # Revert rename
            os.rename(src, dest)
    finally:
        if os.path.isfile(src):
            os.remove(src)

        if (backup_src):
            os.rename(backup_src, src)
Exemple #9
0
def run_svn_log(svn_url, rev_start, rev_end, limit, stop_on_copy=False):
    """
    Fetch up to 'limit' SVN log entries between the given revisions.
    """
    if stop_on_copy:
        args = ['--stop-on-copy']
    else:
        args = []
    args += ['-r', '%s:%s' % (rev_start, rev_end), '--limit', limit, svn_url]
    xml_string = run_svn(svn_log_args + args)
    return parse_svn_log_xml(xml_string)
Exemple #10
0
def run_svn_log(svn_url, rev_start, rev_end, limit, stop_on_copy=False):
    """
    Fetch up to 'limit' SVN log entries between the given revisions.
    """
    if stop_on_copy:
        args = ['--stop-on-copy']
    else:
        args = []
    args += ['-r', '%s:%s' % (rev_start, rev_end), '--limit', limit, svn_url]
    xml_string = run_svn(svn_log_args + args)
    return parse_svn_log_xml(xml_string)
Exemple #11
0
def get_svn_client_version():
    """Returns the SVN client version as a tuple.

    The returned tuple only contains numbers, non-digits in version string are
    silently ignored.
    """
    global _svn_client_version
    if _svn_client_version is None:
        raw = run_svn(['--version', '-q']).strip()
        _svn_client_version = tuple(map(int, [x for x in raw.split('.')
                                              if x.isdigit()]))
    return _svn_client_version
Exemple #12
0
def get_svn_client_version():
    """Returns the SVN client version as a tuple.

    The returned tuple only contains numbers, non-digits in version string are
    silently ignored.
    """
    global _svn_client_version
    if _svn_client_version is None:
        raw = run_svn(['--version', '-q']).strip()
        _svn_client_version = tuple(
            map(int, [x for x in raw.split('.') if x.isdigit()]))
    return _svn_client_version
Exemple #13
0
def get_svn_status(svn_wc, quiet=False):
    """
    Get SVN status information about the given working copy.
    """
    # Ensure proper stripping by canonicalizing the path
    svn_wc = os.path.abspath(svn_wc)
    args = [svn_wc]
    if quiet:
        args += ['-q']
    else:
        args += ['-v']
    xml_string = run_svn(svn_status_args + args)
    return parse_svn_status_xml(xml_string, svn_wc, ignore_externals=True)
Exemple #14
0
def get_svn_info(svn_url_or_wc, rev_number=None):
    """
    Get SVN information for the given URL or working copy, with an optionally
    specified revision number.
    Returns a dict as created by parse_svn_info_xml().
    """
    if rev_number is not None:
        args = ['-r', rev_number]
    else:
        args = []
    xml_string = run_svn(svn_info_args + args + [svn_url_or_wc],
        fail_if_stderr=True)
    return parse_svn_info_xml(xml_string)
Exemple #15
0
def get_svn_info(svn_url_or_wc, rev_number=None):
    """
    Get SVN information for the given URL or working copy, with an optionally
    specified revision number.
    Returns a dict as created by parse_svn_info_xml().
    """
    if rev_number is not None:
        args = ['-r', rev_number]
    else:
        args = []
    xml_string = run_svn(svn_info_args + args + [svn_url_or_wc],
                         fail_if_stderr=True)
    return parse_svn_info_xml(xml_string)
Exemple #16
0
def get_svn_status(svn_wc, quiet=False):
    """
    Get SVN status information about the given working copy.
    """
    # Ensure proper stripping by canonicalizing the path
    svn_wc = os.path.abspath(svn_wc)
    args = [svn_wc]
    if quiet:
        args += ['-q']
    else:
        args += ['-v']
    xml_string = run_svn(svn_status_args + args)
    return parse_svn_status_xml(xml_string, svn_wc, ignore_externals=True)
Exemple #17
0
def real_main(options, args):
    if check_for_applied_patches():
        print ("There are applied mq patches. Put them aside before "
               "running hgpullsvn.")
        return 1
    svn_wc = "."

    # Get SVN info
    svn_info = get_svn_info('.')
    current_rev = svn_info['revision']
    next_rev = current_rev + 1
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted'
    repos_url = svn_info['repos_url']
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted/branches/xmpp-subprotocols-2178-2'
    wc_url = svn_info['url']
    assert wc_url.startswith(repos_url)
    # e.g. u'/branches/xmpp-subprotocols-2178-2'
    wc_base = wc_url[len(repos_url):]
    # e.g. 'xmpp-subprotocols-2178-2'
    svn_branch = wc_url.split("/")[-1]

    # if --branch was passed, override the branch name derived above
    if options.svn_branch:
        svn_branch = options.svn_branch

    if options.svn_peg:
       wc_url += "@" + str(options.svn_peg)

    # Get remote SVN info
    ui.status("Retrieving remote SVN info...", level=ui.VERBOSE)
    svn_greatest_rev = get_svn_info(wc_url)['last_changed_rev']
    if svn_greatest_rev < next_rev:
        ui.status("No revisions after %s in SVN repo, nothing to do",
                  svn_greatest_rev)
        return
    elif options.svn_rev != None:
        if options.svn_rev < next_rev:
            ui.status("All revisions up to %s are already pulled in, "
                      "nothing to do",
                      options.svn_rev)
            return
        svn_greatest_rev = options.svn_rev

    # Show incoming changes if in dry-run mode.
    if options.dryrun:
        ui.status("Incoming SVN revisions:")
        for entry in iter_svn_log_entries(wc_url, next_rev, svn_greatest_rev,
                                          options.svnretry):
            if entry["message"]:
                msg = entry["message"].splitlines()[0].strip()
            else:
                msg = ""
            line = "[%d] %s (%s)" % (entry["revision"], msg, entry["author"])
            ui.status(line)
        return

    # Prepare and/or switch named branches
    orig_branch = run_hg(["branch"]).strip()
    if orig_branch != svn_branch:
        # Update to or create the "pristine" branch
        if not hg_switch_branch(orig_branch, svn_branch):
            return 1
    elif not hg_is_clean(svn_branch):
        return 1

    # Detect that a previously aborted hgpullsvn retrieved an SVN revision
    # without committing it to hg.
    # If there is no SVN tag in current head, we may have been interrupted
    # during the previous "hg tag".
    hgsvn_rev = get_svn_rev_from_hg()
    if hgsvn_rev is not None and hgsvn_rev != current_rev:
        ui.status(("\nNote: hgsvn repository is in an unclean state "
                   "(probably because of an aborted hgpullsvn). \n"
                   "Let's first update to the last good SVN rev."),
                  level=ui.VERBOSE)
        run_svn(["revert", "-R", "."])
        run_svn(["up", "--ignore-externals", "-r", hgsvn_rev, svn_wc])
        next_rev = hgsvn_rev + 1

    # Reset working branch to last svn head to have a clean and linear SVN
    # history.
    heads_before = None
    if hgsvn_rev is None:
        heads_before = run_hg(["heads", "--template",
                               "{node}%s" % os.linesep]).splitlines()
        run_hg(["update", "-C", "svn.%d" % current_rev])

    # Load SVN log starting from current rev
    it_log_entries = iter_svn_log_entries(wc_url, next_rev, svn_greatest_rev, options.svnretry)

    try:
        try:
            for log_entry in it_log_entries:
                current_rev = pull_svn_rev(log_entry, current_rev,
                                           svn_wc, wc_url, wc_base, options.svnretry)
                if current_rev is None:
                    return 1
                ui.status("Pulled r%d %s (%s)", log_entry["revision"],
                          log_entry["message"], log_entry["author"])

        # TODO: detect externals with "svn status" and update them as well

        finally:
            if heads_before is not None:  # we have reset the SVN branch
                heads_now = run_hg(["heads", "--template",
                                    "{node}%s" % os.linesep]).splitlines()
                if len(heads_now) != len(heads_before):
                    ui.status("created new head in branch '%s'", svn_branch)
            work_branch = orig_branch or svn_branch
            if work_branch != svn_branch:
                run_hg(["up", '-C', work_branch])
                run_hg(["branch", work_branch])

    except KeyboardInterrupt:
        ui.status("\nStopped by user.", level=ui.ERROR)
    except ExternalCommandFailed, e:
        ui.status(str(e), level=ui.ERROR)
Exemple #18
0
                           run_hg(["remove", "-A"], file_path)
                except (ExternalCommandFailed), e:
                    if str(e).find("file is untracked") > 0:
                        ui.status("Ignoring warnings about untracked files: '%s'" % str(e), level=ui.VERBOSE)
                    else:
                        raise
            hg_commit_from_svn_log_entry(log_entry)
        elif unrelated_paths:
            detect_overwritten_svn_branch(wc_url, svn_rev)
    # NOTE: in Python 2.5, KeyboardInterrupt isn't a subclass of Exception anymore
    except (Exception, KeyboardInterrupt), e:
        ui.status("\nInterrupted, please wait for cleanup!\n", level=ui.ERROR)
        # NOTE: at this point, running SVN sometimes gives "write lock failures"
        # which leave the WC in a weird state.
        time.sleep(0.3)
        run_svn(["cleanup"])
        hgsvn_rev = get_svn_rev_from_hg()
        if hgsvn_rev != svn_rev:
            # Unless the tag is there, revert to the last stable state
            run_svn(["up", "--ignore-externals", "-r", current_rev, svn_wc])
            run_hg(["revert", "--all"])
        raise

    return svn_rev


def real_main(options, args):
    if check_for_applied_patches():
        print ("There are applied mq patches. Put them aside before "
               "running hgpullsvn.")
        return 1
Exemple #19
0
 def test_svn(self):
     s = common.run_svn(['--version', '-q'])
     eq_(s.split('.')[0], '1')
Exemple #20
0
def hg_push_svn(start_rev, end_rev, edit, username, password, cache):
    """
    Commit the changes between two hg revisions into the SVN repository.
    Returns the SVN revision object, or None if nothing needed checking in.
    """
    added, removed, modified, copied = get_hg_changes(start_rev+':'+end_rev)

    # Before replicating changes revert directory to previous state...
    run_hg(['revert', '--all', '--no-backup', '-r', end_rev])

    # ... and restore .svn directories, if we lost some of them due to removes
    run_svn(['revert', '--recursive', '.'])

    # Do the rest over up-to-date working copy
    # Issue 94 - moved this line to prevent do_svn_copy crashing when its not the first changeset
    run_hg(["up", "-C", end_rev])

    # Record copyies into svn
    for dest, src in copied.iteritems():
        do_svn_copy(src,dest)

    # Add new files and dirs
    if added:
        bulk_args = get_ordered_dirs(added) + added
        run_svn(["add", "--depth=empty"], bulk_args,
                mask_atsign=True)
    removed = cleanup_svn_unversioned(removed)
    modified = cleanup_svn_unversioned(modified)
    # Remove old files and empty dirs
    if removed:
        empty_dirs = [d for d in reversed(get_ordered_dirs(removed))
                      if not run_hg(["st", "-c", "%s" %d])]
        # When running "svn rm" all files within removed folders needs to
        # be removed from "removed". Otherwise "svn rm" will fail. For example
        # instead of "svn rm foo/bar foo" it should be "svn rm foo".
        # See issue15.
        svn_removed = strip_nested_removes(removed + empty_dirs)
        run_svn(["rm"], svn_removed, mask_atsign=True)
    if added or removed or modified:
        svn_sep_line = "--This line, and those below, will be ignored--\n"
        adjust_executable_property(added+modified)  # issue24
        description = get_hg_csets_description(start_rev, end_rev)
        fname = os.path.join(hgsvn_private_dir, 'commit-%s.txt' % end_rev)
        lines = description.splitlines()+[""]
        lines.append(svn_sep_line)
        lines.append("To cancel commit just delete text in top message part")
        lines.append("")
        lines.append("Changes to be committed into svn:")
        lines.extend([item.decode("utf-8")
                      for item in run_svn(["st", "-q"]).splitlines()])
        lines.append("")
        lines.append(("These changes are produced from the following "
                      "Hg changesets:"))
        lines.extend(get_hg_log(start_rev, end_rev).splitlines())
        f = codecs.open(fname, "wb", "utf-8")
        f.write(os.linesep.join(lines))
        f.close()

        try:
            if edit:
                editor=(os.environ.get("HGEDITOR") or
                        os.environ.get("SVNEDITOR") or
                        os.environ.get("VISUAL") or
                        os.environ.get("EDITOR", "vi"))

                rc = os.system("%s \"%s\"" % (editor, fname) )
                if(rc):
                    raise ExternalCommandFailed("Can't launch editor")

                empty = True

                f=open(fname, "r")
                for line in f:
                    if(line == svn_sep_line):
                        break

                    if(line.strip() != ""):
                        empty = False
                        break
                f.close()

                if(empty):
                    raise EmptySVNLog("Commit cancelled by user\n")

            svn_rev = None
            svn_commands = ["commit", "-F", fname, "--encoding", get_encoding()]
            if username is not None:
                svn_commands += ["--username", username]
            if password is not None:
                svn_commands += ["--password", password]
            if cache:
                svn_commands.append("--no-auth-cache")
            out = run_svn(svn_commands)

            outlines = out.splitlines()
            outlines.reverse()
            for line in outlines:
                # one of the last lines holds the revision.
                # The previous approach to set LC_ALL to C and search
                # for "Committed revision XXX" doesn't work since
                # svn is unable to convert filenames containing special
                # chars:
                # http://svnbook.red-bean.com/en/1.2/svn.advanced.l10n.html
                match = re.search("(\d+)", line)
                if match:
                    svn_rev = int(match.group(1))
                    break

            return svn_rev
        finally:
            # Exceptions are handled by main().
            os.remove(fname)
    else:
        print "*", "svn: nothing to do"
        return None
Exemple #21
0
def main():
    usage = """1. %prog [-r SVN rev] [-p SVN peg rev] <SVN URL> [local checkout]
       2. %prog --local-only <local checkout>"""
    parser = OptionParser(usage)
    parser.add_option("-r", "--svn-rev", type="int", dest="svn_rev",
        help="SVN revision to checkout from")
    parser.add_option("-p", "--svn-peg", type="int", dest="svn_peg",
        help="SVN peg revision to locate checkout URL")
    parser.add_option("--no-hgignore", dest="hgignore", action="store_false",
        default=True, help="Don't autogenerate .hgignore")
    parser.add_option("--local-only", action="store_true", default=False,
        help="Don't use the server, just build from a local checkout")
    parser.add_option("--branch", type="string", dest="svn_branch",
        help="Override branch name (defaults to last path component of <SVN URL>)")
    (options, args) = run_parser(parser, __doc__)
    if not 1 <= len(args) <= 2:
        display_parser_error(parser, "incorrect number of arguments")

    target_svn_url = args.pop(0).rstrip("/")
    local_repo = args and args.pop(0) or None
    if options.svn_peg:
       target_svn_url += "@" + str(options.svn_peg)

    if options.local_only:
        if options.svn_peg:
            display_parser_error(parser,
                    "--local-only and --svn-peg are mutually exclusive")
        if options.svn_rev:
            display_parser_error(parser,
                    "--local-only and --svn-rev are mutually exclusive")
        if local_repo:
            display_parser_error(parser,
                    "--local-only does not accept a target directory")



    # Get SVN info
    svn_info = get_svn_info(target_svn_url, options.svn_rev)
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted'
    repos_url = svn_info['repos_url']
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted/branches/xmpp-subprotocols-2178-2'
    actual_svn_url = svn_info['url']
    assert actual_svn_url.startswith(repos_url)

    # if we are allowed to go to the server, lets use it
    if options.local_only:
        target_svn_url = os.path.abspath(target_svn_url)
        local_repo = target_svn_url

    # e.g. u'/branches/xmpp-subprotocols-2178-2'
    svn_path = actual_svn_url[len(repos_url):]
    # e.g. 'xmpp-subprotocols-2178-2'
    svn_branch = actual_svn_url.split("/")[-1]

    # if --branch was passed, override the branch name derived above
    if options.svn_branch:
        svn_branch = options.svn_branch

    svn_greatest_rev = svn_info['last_changed_rev']
    if options.svn_peg:
       actual_svn_url += "@" + str(options.svn_peg)

    if not local_repo:
        local_repo = actual_svn_url.split("/")[-1]
    if os.path.exists(local_repo):
        if not os.path.isdir(local_repo):
            raise ValueError("%s is not a directory" % local_repo)
        is_svn_dir = os.path.isdir(os.path.join(local_repo, '.svn'))
        if is_svn_dir and not options.local_only:
            nlocal_repo = os.path.abspath(local_repo)
            print "%s is already a SVN checkout." % nlocal_repo
            sys.exit(1)
        elif not is_svn_dir and options.local_only:
            nlocal_repo = os.path.abspath(local_repo)
            print "%s must be a SVN checkout for --local-only" % nlocal_repo
            sys.exit(1)
        elif options.local_only and is_svn_dir:
            status = get_svn_status(local_repo, quiet=True)
            if status:
                print ("There are uncommitted changes. Either commit them "
                       "or put them aside before running hgimportsvn.")
                sys.exit(1)
    else:
        os.mkdir(local_repo)
    fixup_hgsvn_dir(local_repo)
    os.chdir(local_repo)

    # Get log entry for the SVN revision we will check out
    svn_copyfrom_path = None
    svn_copyfrom_revision = None
    if options.local_only or svn_greatest_rev == 0:
        # fake up a log message for the initial commit
        svn_start_log = {}
        svn_start_log['message'] = 'initial import by hgimportsvn'
        svn_start_log['revision'] = svn_info['last_changed_rev']
        svn_start_log['author'] = svn_info.get('last_changed_author')
        svn_start_log['date'] = svn_info['last_changed_date']
    elif options.svn_rev:
        # If a specific rev was requested, get log entry just before or at rev
        svn_start_log = get_last_svn_log_entry(actual_svn_url, 1, options.svn_rev)
    else:
        # Otherwise, get log entry of branch creation
        svn_start_log = get_first_svn_log_entry(actual_svn_url, 1, svn_greatest_rev)
        for p in svn_start_log['changed_paths']:
            if p['path'] == svn_path:
                svn_copyfrom_path = p['copyfrom_path']
                svn_copyfrom_revision = p['copyfrom_revision']
                break
        if svn_copyfrom_path:
            print "SVN branch was copied from '%s' at rev %s" % (
                svn_copyfrom_path, svn_copyfrom_revision)
        else:
            print "SVN branch isn't a copy"
    # This is the revision we will checkout from
    svn_rev = svn_start_log['revision']

    # Initialize hg repo
    if not os.path.exists(".hg"):
        run_hg(["init"])
    if svn_copyfrom_path:
        # Try to find an hg repo tracking the SVN branch which was copied
        copyfrom_branch = svn_copyfrom_path.split("/")[-1]
        hg_copyfrom = os.path.join("..", copyfrom_branch)
        if (os.path.exists(os.path.join(hg_copyfrom, ".hg")) and
            os.path.exists(os.path.join(hg_copyfrom, svn_private_dir))):
            u = get_svn_info(hg_copyfrom)['url']
            if u != repos_url + svn_copyfrom_path:
                print "SVN URL %s in working copy %s doesn't match, ignoring" % (u, hg_copyfrom)
            else:
                # Find closest hg tag before requested SVN rev
                best_tag = None
                for line in run_hg(["tags", "-R", hg_copyfrom]).splitlines():
                    if not line.startswith("svn."):
                        continue
                    tag = line.split(None, 1)[0]
                    tag_num = int(tag.split(".")[1])
                    if tag_num <= svn_copyfrom_revision and (not best_tag or best_tag < tag_num):
                        best_tag = tag_num
                if not best_tag:
                    print "No hg tag matching rev %s in %s" % (svn_rev, hg_copyfrom)
                else:
                    # Don't use "pull -u" because it fails with hg 0.9.5
                    # ("branch default not found")
                    run_hg(["pull", "-r", "svn.%d" % best_tag, hg_copyfrom])
                    # Not specifying "tip" fails with hg 0.9.5
                    # ("branch default not found")
                    run_hg(["up", "tip"])
    run_hg(["branch", svn_branch])


    # Stay on the same filesystem so as to have fast moves
    if options.local_only:
        checkout_dir = target_svn_url
    else:
        checkout_dir = tempfile.mkdtemp(dir=".")

    try:
        # Get SVN manifest and checkout
        if not options.local_only:
            svn_checkout(target_svn_url, checkout_dir, svn_rev)
        svn_manifest = get_svn_versioned_files(checkout_dir)

        svn_files = set(skip_dirs(svn_manifest, checkout_dir))
        svn_dirs = sorted(set(svn_manifest) - svn_files)
        svn_files = list(svn_files)

        # in the local case the files here already
        if not options.local_only:
            # All directories must exist, including empty ones
            # (both for hg and for moving .svn dirs later)
            for d in svn_dirs:
                if not os.path.isdir(d):
                    if os.path.exists(d):
                        os.remove(d)
                    os.mkdir(d)
            # Replace checked out files
            for f in svn_files:
                if os.path.exists(f):
                    os.remove(f)
                os.rename(os.path.join(checkout_dir, f), f)

        try:
            # Add/remove new/old files
            if svn_files:
                run_hg(["addremove"] + hg_exclude_options, svn_files)
            hg_commit_from_svn_log_entry(svn_start_log)
            #hg_commit_from_svn_log_entry(svn_start_log, svn_files)
        except:
            run_hg(["revert", "--all"])
            raise

        # in the local case the files here already
        if not options.local_only:
            # Move SVN working copy here (don't forget base directory)
            for d in chain([""], svn_dirs):
                os.rename(os.path.join(checkout_dir, d, svn_private_dir), os.path.join(d, svn_private_dir))

    finally:
        # in the local case the checkout_dir is the target, so don't delete it
        if not options.local_only:
            rmtree(checkout_dir)

    if options.hgignore:
        svn_ignores = []
        # we use '.' because that it the location of the hg repo that we are
        # building and at this point we have already copied all of svn to the
        # checkout (for both the local and non-local case)
        for (path, dirs, files) in os.walk('.'):
            if '.svn' in dirs:
                dirs.remove('.svn')

                # the [2:] strips off the initial './'
                local_ignores = [os.path.join(path, s.strip())[2:]
                    for s in run_svn(['propget', 'svn:ignore', path],
                                     mask_atsign=True).splitlines()
                    if bool(s.strip())
                ]
                svn_ignores += local_ignores
            else:
                # if we are not inside an svn world
                # we can just bail
                del dirs[:]


        # Generate .hgignore file to ignore .svn and .hgsvn directories
        f = open(".hgignore", "a")
        try:
            f.write("\n# Automatically generated by `hgimportsvn`\n")
            f.write("syntax:glob\n%s\n" %
                "\n".join([svn_private_dir, hgsvn_private_dir]))
            f.write("\n# These lines are suggested according to the svn:ignore property")
            f.write("\n# Feel free to enable them by uncommenting them")
            f.write("\nsyntax:glob\n")
            f.write("".join("#%s\n" % s for s in svn_ignores))
        finally:
            f.close()

    print "Finished! You can now pull all SVN history with 'hgpullsvn'."
Exemple #22
0
def real_main(options, args):
    if run_hg(["st", "-m"]):
        print(
            "There are uncommitted changes. Either commit them or put "
            "them aside before running hgpushsvn.")
        return 1
    if check_for_applied_patches():
        print(
            "There are applied mq patches. Put them aside before "
            "running hgpushsvn.")
        return 1
    svn_info = get_svn_info(".")
    svn_current_rev = svn_info["last_changed_rev"]
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted'
    repos_url = svn_info["repos_url"]
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted/branches/xmpp-subprotocols-2178-2'
    wc_url = svn_info["url"]
    assert wc_url.startswith(repos_url)
    # e.g. u'/branches/xmpp-subprotocols-2178-2'
    wc_base = wc_url[len(repos_url):]

    svn_branch = wc_url.split("/")[-1]

    # Get remote SVN info
    svn_greatest_rev = get_svn_info(wc_url)['last_changed_rev']

    if svn_greatest_rev != svn_current_rev:
        # We can't go on if the pristine branch isn't up to date.
        # If the pristine branch lacks some revisions from SVN we are not
        # able to pull them afterwards.
        # For example, if the last SVN revision in out hgsvn repository is
        # r100 and the latest SVN revision is r101, hgpushsvn would create
        # a tag svn.102 on top of svn.100, but svn.101 isn't in hg history.
        print("Branch '%s' out of date. Run 'hgpullsvn' first." % svn_branch)
        return 1

    # Switch branches if necessary.
    orig_branch = run_hg(["branch"]).strip()
    if orig_branch != svn_branch:
        if not hg_switch_branch(orig_branch, svn_branch):
            return 1

    hg_start_rev = "svn.%d" % svn_current_rev
    hg_revs = None
    try:
        hg_start_cset = get_hg_cset(hg_start_rev)
    except RuntimeError:
        if not options.force:
            raise
        hg_start_cset = get_hg_cset("0")
        print "Warning: revision '%s' not found, forcing to first rev '%s'" % (
            hg_start_rev, hg_start_cset)
    else:
        if not options.collapse:
            hg_revs = get_hg_revs(hg_start_cset, svn_branch)
    if hg_revs is None:
        hg_revs = [
            strip_hg_rev(hg_start_cset),
            strip_hg_rev(get_hg_cset("tip"))
        ]

    pushed_svn_revs = []
    try:
        if options.dryrun:
            print "Outgoing revisions that would be pushed to SVN:"
        try:
            for prev_rev, next_rev in get_pairs(hg_revs):
                if not options.dryrun:
                    if not options.edit:
                        ui.status("Committing changes up to revision %s",
                                  get_hg_cset(next_rev))
                    username = options.username
                    if options.keep_author:
                        username = run_hg(
                            ["log", "-r", next_rev, "--template", "{author}"])
                    svn_rev = hg_push_svn(prev_rev,
                                          next_rev,
                                          edit=options.edit,
                                          username=username,
                                          password=options.password,
                                          cache=options.cache)
                    if svn_rev:
                        # Issue 95 - added update to prevent add/modify/delete crash
                        run_svn(["up"])
                        map_svn_rev_to_hg(svn_rev, next_rev, local=True)
                        pushed_svn_revs.append(svn_rev)
                else:
                    print run_hg([
                        "log", "-r", next_rev, "--template",
                        "{rev}:{node|short} {desc}"
                    ])
        except:
            # TODO: Add --no-backup to leave a "clean" repo behind if something
            #   fails?
            run_hg(["revert", "--all"])
            raise

    finally:
        work_branch = orig_branch or svn_branch
        if work_branch != svn_branch:
            run_hg(["up", "-C", work_branch])
            run_hg(["branch", work_branch])

    if pushed_svn_revs:
        if len(pushed_svn_revs) == 1:
            msg = "Pushed one revision to SVN: "
        else:
            msg = "Pushed %d revisions to SVN: " % len(pushed_svn_revs)
        run_svn(["up", "-r", pushed_svn_revs[-1]])
        ui.status("%s %s", msg, ", ".join(str(x) for x in pushed_svn_revs))
        for line in run_hg(["st"]).splitlines():
            if line.startswith("M"):
                ui.status(("Mercurial repository has local changes after "
                           "SVN update."))
                ui.status(("This may happen with SVN keyword expansions."))
                break
    elif not options.dryrun:
        ui.status("Nothing to do.")
Exemple #23
0
def real_main(options, args):
    if run_hg(["st", "-m"]):
        print ("There are uncommitted changes. Either commit them or put "
               "them aside before running hgpushsvn.")
        return 1
    if check_for_applied_patches():
        print ("There are applied mq patches. Put them aside before "
               "running hgpushsvn.")
        return 1
    svn_info = get_svn_info(".")
    svn_current_rev = svn_info["last_changed_rev"]
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted'
    repos_url = svn_info["repos_url"]
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted/branches/xmpp-subprotocols-2178-2'
    wc_url = svn_info["url"]
    assert wc_url.startswith(repos_url)
    # e.g. u'/branches/xmpp-subprotocols-2178-2'
    wc_base = wc_url[len(repos_url):]

    svn_branch = wc_url.split("/")[-1]

    # Get remote SVN info
    svn_greatest_rev = get_svn_info(wc_url)['last_changed_rev']

    if svn_greatest_rev != svn_current_rev:
        # We can't go on if the pristine branch isn't up to date.
        # If the pristine branch lacks some revisions from SVN we are not
        # able to pull them afterwards.
        # For example, if the last SVN revision in out hgsvn repository is
        # r100 and the latest SVN revision is r101, hgpushsvn would create
        # a tag svn.102 on top of svn.100, but svn.101 isn't in hg history.
        print ("Branch '%s' out of date. Run 'hgpullsvn' first."
               % svn_branch)
        return 1

    # Switch branches if necessary.
    orig_branch = run_hg(["branch"]).strip()
    if orig_branch != svn_branch:
        if not hg_switch_branch(orig_branch, svn_branch):
            return 1

    hg_start_rev = "svn.%d" % svn_current_rev
    hg_revs = None
    try:
        hg_start_cset = get_hg_cset(hg_start_rev)
    except RuntimeError:
        if not options.force:
            raise
        hg_start_cset = get_hg_cset("0")
        print "Warning: revision '%s' not found, forcing to first rev '%s'" % (
            hg_start_rev, hg_start_cset)
    else:
        if not options.collapse:
            hg_revs = get_hg_revs(hg_start_cset, svn_branch)
    if hg_revs is None:
        hg_revs = [strip_hg_rev(hg_start_cset), strip_hg_rev(get_hg_cset("tip"))]

    pushed_svn_revs = []
    try:
        if options.dryrun:
            print "Outgoing revisions that would be pushed to SVN:"
        try:
            for prev_rev, next_rev in get_pairs(hg_revs):
                if not options.dryrun:
                    if not options.edit:
                        ui.status("Committing changes up to revision %s",
                                    get_hg_cset(next_rev))
                    username = options.username
                    if options.keep_author:
                        username = run_hg(["log", "-r", next_rev,
                                            "--template", "{author}"])
                    svn_rev = hg_push_svn(prev_rev, next_rev,
                                            edit=options.edit,
                                            username=username,
                                            password=options.password,
                                            cache=options.cache)
                    if svn_rev:
                        # Issue 95 - added update to prevent add/modify/delete crash
                        run_svn(["up"])
                        map_svn_rev_to_hg(svn_rev, next_rev, local=True)
                        pushed_svn_revs.append(svn_rev)
                else:
                    print run_hg(["log", "-r", next_rev,
                              "--template", "{rev}:{node|short} {desc}"])
        except:
            # TODO: Add --no-backup to leave a "clean" repo behind if something
            #   fails?
            run_hg(["revert", "--all"])
            raise

    finally:
        work_branch = orig_branch or svn_branch
        if work_branch != svn_branch:
            run_hg(["up", "-C", work_branch])
            run_hg(["branch", work_branch])

    if pushed_svn_revs:
        if len(pushed_svn_revs) == 1:
            msg = "Pushed one revision to SVN: "
        else:
            msg = "Pushed %d revisions to SVN: " % len(pushed_svn_revs)
        run_svn(["up", "-r", pushed_svn_revs[-1]])
        ui.status("%s %s", msg, ", ".join(str(x) for x in pushed_svn_revs))
        for line in run_hg(["st"]).splitlines():
            if line.startswith("M"):
                ui.status(("Mercurial repository has local changes after "
                           "SVN update."))
                ui.status(("This may happen with SVN keyword expansions."))
                break
    elif not options.dryrun:
        ui.status("Nothing to do.")
Exemple #24
0
                        ui.status(
                            "Ignoring warnings about untracked files: '%s'" %
                            str(e),
                            level=ui.VERBOSE)
                    else:
                        raise
            hg_commit_from_svn_log_entry(log_entry)
        elif unrelated_paths:
            detect_overwritten_svn_branch(wc_url, svn_rev)
    # NOTE: in Python 2.5, KeyboardInterrupt isn't a subclass of Exception anymore
    except (Exception, KeyboardInterrupt), e:
        ui.status("\nInterrupted, please wait for cleanup!\n", level=ui.ERROR)
        # NOTE: at this point, running SVN sometimes gives "write lock failures"
        # which leave the WC in a weird state.
        time.sleep(0.3)
        run_svn(["cleanup"])
        hgsvn_rev = get_svn_rev_from_hg()
        if hgsvn_rev != svn_rev:
            # Unless the tag is there, revert to the last stable state
            run_svn(["up", "--ignore-externals", "-r", current_rev, svn_wc])
            run_hg(["revert", "--all"])
        raise

    return svn_rev


def real_main(options, args):
    if check_for_applied_patches():
        print("There are applied mq patches. Put them aside before "
              "running hgpullsvn.")
        return 1
Exemple #25
0
def real_main(options, args):
    if check_for_applied_patches():
        print("There are applied mq patches. Put them aside before "
              "running hgpullsvn.")
        return 1
    svn_wc = "."

    # Get SVN info
    svn_info = get_svn_info('.')
    current_rev = svn_info['revision']
    next_rev = current_rev + 1
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted'
    repos_url = svn_info['repos_url']
    # e.g. u'svn://svn.twistedmatrix.com/svn/Twisted/branches/xmpp-subprotocols-2178-2'
    wc_url = svn_info['url']
    assert wc_url.startswith(repos_url)
    # e.g. u'/branches/xmpp-subprotocols-2178-2'
    wc_base = wc_url[len(repos_url):]
    # e.g. 'xmpp-subprotocols-2178-2'
    svn_branch = wc_url.split("/")[-1]

    # if --branch was passed, override the branch name derived above
    if options.svn_branch:
        svn_branch = options.svn_branch

    if options.svn_peg:
        wc_url += "@" + str(options.svn_peg)

    # Get remote SVN info
    ui.status("Retrieving remote SVN info...", level=ui.VERBOSE)
    svn_greatest_rev = get_svn_info(wc_url)['last_changed_rev']
    if svn_greatest_rev < next_rev:
        ui.status("No revisions after %s in SVN repo, nothing to do",
                  svn_greatest_rev)
        return
    elif options.svn_rev != None:
        if options.svn_rev < next_rev:
            ui.status(
                "All revisions up to %s are already pulled in, "
                "nothing to do", options.svn_rev)
            return
        svn_greatest_rev = options.svn_rev

    # Show incoming changes if in dry-run mode.
    if options.dryrun:
        ui.status("Incoming SVN revisions:")
        for entry in iter_svn_log_entries(wc_url, next_rev, svn_greatest_rev,
                                          options.svnretry):
            if entry["message"]:
                msg = entry["message"].splitlines()[0].strip()
            else:
                msg = ""
            line = "[%d] %s (%s)" % (entry["revision"], msg, entry["author"])
            ui.status(line)
        return

    # Prepare and/or switch named branches
    orig_branch = run_hg(["branch"]).strip()
    if orig_branch != svn_branch:
        # Update to or create the "pristine" branch
        if not hg_switch_branch(orig_branch, svn_branch):
            return 1
    elif not hg_is_clean(svn_branch):
        return 1

    # Detect that a previously aborted hgpullsvn retrieved an SVN revision
    # without committing it to hg.
    # If there is no SVN tag in current head, we may have been interrupted
    # during the previous "hg tag".
    hgsvn_rev = get_svn_rev_from_hg()
    if hgsvn_rev is not None and hgsvn_rev != current_rev:
        ui.status(("\nNote: hgsvn repository is in an unclean state "
                   "(probably because of an aborted hgpullsvn). \n"
                   "Let's first update to the last good SVN rev."),
                  level=ui.VERBOSE)
        run_svn(["revert", "-R", "."])
        run_svn(["up", "--ignore-externals", "-r", hgsvn_rev, svn_wc])
        next_rev = hgsvn_rev + 1

    # Reset working branch to last svn head to have a clean and linear SVN
    # history.
    heads_before = None
    if hgsvn_rev is None:
        heads_before = run_hg(["heads", "--template",
                               "{node}%s" % os.linesep]).splitlines()
        run_hg(["update", "-C", "svn.%d" % current_rev])

    # Load SVN log starting from current rev
    it_log_entries = iter_svn_log_entries(wc_url, next_rev, svn_greatest_rev,
                                          options.svnretry)

    try:
        try:
            for log_entry in it_log_entries:
                current_rev = pull_svn_rev(log_entry, current_rev, svn_wc,
                                           wc_url, wc_base, options.svnretry)
                if current_rev is None:
                    return 1
                ui.status("Pulled r%d %s (%s)", log_entry["revision"],
                          log_entry["message"], log_entry["author"])

        # TODO: detect externals with "svn status" and update them as well

        finally:
            if heads_before is not None:  # we have reset the SVN branch
                heads_now = run_hg(
                    ["heads", "--template",
                     "{node}%s" % os.linesep]).splitlines()
                if len(heads_now) != len(heads_before):
                    ui.status("created new head in branch '%s'", svn_branch)
            work_branch = orig_branch or svn_branch
            if work_branch != svn_branch:
                run_hg(["up", '-C', work_branch])
                run_hg(["branch", work_branch])

    except KeyboardInterrupt:
        ui.status("\nStopped by user.", level=ui.ERROR)
    except ExternalCommandFailed, e:
        ui.status(str(e), level=ui.ERROR)
Exemple #26
0
def hg_push_svn(start_rev, end_rev, edit, username, password, cache):
    """
    Commit the changes between two hg revisions into the SVN repository.
    Returns the SVN revision object, or None if nothing needed checking in.
    """
    added, removed, modified, copied = get_hg_changes(start_rev + ':' +
                                                      end_rev)

    # Before replicating changes revert directory to previous state...
    run_hg(['revert', '--all', '--no-backup', '-r', end_rev])

    # ... and restore .svn directories, if we lost some of them due to removes
    run_svn(['revert', '--recursive', '.'])

    # Do the rest over up-to-date working copy
    # Issue 94 - moved this line to prevent do_svn_copy crashing when its not the first changeset
    run_hg(["up", "-C", end_rev])

    # Record copyies into svn
    for dest, src in copied.iteritems():
        do_svn_copy(src, dest)

    # Add new files and dirs
    if added:
        bulk_args = get_ordered_dirs(added) + added
        run_svn(["add", "--depth=empty"], bulk_args, mask_atsign=True)
    removed = cleanup_svn_unversioned(removed)
    modified = cleanup_svn_unversioned(modified)
    # Remove old files and empty dirs
    if removed:
        empty_dirs = [
            d for d in reversed(get_ordered_dirs(removed))
            if not run_hg(["st", "-c", "%s" % d])
        ]
        # When running "svn rm" all files within removed folders needs to
        # be removed from "removed". Otherwise "svn rm" will fail. For example
        # instead of "svn rm foo/bar foo" it should be "svn rm foo".
        # See issue15.
        svn_removed = strip_nested_removes(removed + empty_dirs)
        run_svn(["rm"], svn_removed, mask_atsign=True)
    if added or removed or modified:
        svn_sep_line = "--This line, and those below, will be ignored--\n"
        adjust_executable_property(added + modified)  # issue24
        description = get_hg_csets_description(start_rev, end_rev)
        fname = os.path.join(hgsvn_private_dir, 'commit-%s.txt' % end_rev)
        lines = description.splitlines() + [""]
        lines.append(svn_sep_line)
        lines.append("To cancel commit just delete text in top message part")
        lines.append("")
        lines.append("Changes to be committed into svn:")
        lines.extend([
            item.decode("utf-8")
            for item in run_svn(["st", "-q"]).splitlines()
        ])
        lines.append("")
        lines.append(("These changes are produced from the following "
                      "Hg changesets:"))
        lines.extend(get_hg_log(start_rev, end_rev).splitlines())
        f = codecs.open(fname, "wb", "utf-8")
        f.write(os.linesep.join(lines))
        f.close()

        try:
            if edit:
                editor = (os.environ.get("HGEDITOR")
                          or os.environ.get("SVNEDITOR")
                          or os.environ.get("VISUAL")
                          or os.environ.get("EDITOR", "vi"))

                rc = os.system("%s \"%s\"" % (editor, fname))
                if (rc):
                    raise ExternalCommandFailed("Can't launch editor")

                empty = True

                f = open(fname, "r")
                for line in f:
                    if (line == svn_sep_line):
                        break

                    if (line.strip() != ""):
                        empty = False
                        break
                f.close()

                if (empty):
                    raise EmptySVNLog("Commit cancelled by user\n")

            svn_rev = None
            svn_commands = [
                "commit", "-F", fname, "--encoding",
                get_encoding()
            ]
            if username is not None:
                svn_commands += ["--username", username]
            if password is not None:
                svn_commands += ["--password", password]
            if cache:
                svn_commands.append("--no-auth-cache")
            out = run_svn(svn_commands)

            outlines = out.splitlines()
            outlines.reverse()
            for line in outlines:
                # one of the last lines holds the revision.
                # The previous approach to set LC_ALL to C and search
                # for "Committed revision XXX" doesn't work since
                # svn is unable to convert filenames containing special
                # chars:
                # http://svnbook.red-bean.com/en/1.2/svn.advanced.l10n.html
                match = re.search("(\d+)", line)
                if match:
                    svn_rev = int(match.group(1))
                    break

            return svn_rev
        finally:
            # Exceptions are handled by main().
            os.remove(fname)
    else:
        print "*", "svn: nothing to do"
        return None