[PATCH] convert: make convert from cvs recognise branch points correctly [revised, 3]

Henrik Stuart henrik.stuart at edlund.dk
Tue Apr 14 06:04:01 CDT 2009


# HG changeset patch
# User Henrik Stuart <henrik.stuart at edlund.dk>
# Date 1239706830 -7200
# Node ID f8fd162954633e67b27605b2541eb46e155d4780
# Parent  aece3c9e62f1a685e4cebd3ecf0b22e1c8101ae1
convert: make convert from cvs recognise branch points correctly

This patch fixes issue 1447 by using the symbolic names for branches
in the rlog output to determine the branch point for each file and
then finding the latest possible branch point in the given changesets
such that all the file revisions match and the date is earlier than
the branch commit. For commits on non-branches, the current
functionality is maintained.

Co-contributor: Greg Ward <greg-hg at gerg.ca>

diff --git a/hgext/convert/cvsps.py b/hgext/convert/cvsps.py
--- a/hgext/convert/cvsps.py
+++ b/hgext/convert/cvsps.py
@@ -35,6 +35,7 @@
         .tags      - list of tags on the file
         .synthetic - is this a synthetic "file ... added on ..." revision?
         .mergepoint- the branch that has been merged from (if present in rlog output)
+        .branchesto- list of branches that occur at this revision
     '''
     def __init__(self, **entries):
         self.__dict__.update(entries)
@@ -378,6 +379,13 @@
             # clean up the results and save in the log.
             store = False
             e.tags = util.sort([scache(x) for x in tags.get(e.revision, [])])
+            e.branchesto = []
+            for tag in branchmap:
+                tag_parts = branchmap[tag].split('.')
+                if len(tag_parts) > 2 and tag_parts[-2] == '0' and (
+                    e.revision == tuple([int(x) for x in tag_parts[:-2]])):
+                    e.branchesto.append(tag)
+
             e.comment = scache('\n'.join(e.comment))
 
             revn = len(e.revision)
@@ -582,6 +590,8 @@
 
     versions = {}    # changeset index where we saw any particular file version
     branches = {}    # changeset index where we saw a branch
+    # variable to only output warning for missing branchesto once
+    has_logentry_without_branchesto = False
     n = len(changesets)
     i = 0
     while i<n:
@@ -599,8 +609,46 @@
 
         c.parents = []
         if p is not None:
+            parent_idx = p
             p = changesets[p]
 
+            if p is not None:
+                if c.branch != p.branch:
+                    # necessary as the first commit on a branch can be
+                    # broken into multiple bites
+                    earliest_commit = min([l.date for l in log if l.branch == c.branch])
+
+                    q = parent_idx
+                    # already in p at the latest
+                    seen_branched_files = util.set([e.file for e in c.entries])
+                    while q + 1 < i: # only need to search up to current
+                        qcs = changesets[q + 1]
+
+                        if qcs.date >= earliest_commit:
+                            break
+
+                        if [e.file for e in qcs.entries if 
+                                e.file in seen_branched_files]:
+                            break # we cannot progress past this place
+
+                        branchesto = getattr(e, 'branchesto', None)
+                        if branchesto == None and not has_logentry_without_branchesto:
+                            has_logentry_without_branchesto = True
+                            ui.warn(_("CVS cache has been compiled without "
+                                "correct branch information.\n"
+                                "If you have branches in your CVS repository "
+                                "it is strongly adviced to\n"
+                                "delete the cache and start over.\n"))
+                        if branchesto == None:
+                            branchesto = []
+                        seen_branched_files |= util.set([
+                            e.file for e in qcs.entries if 
+                                c.branch in branchesto])
+                                
+                        q += 1
+
+                    p = changesets[q]
+
             # Ensure no changeset has a synthetic changeset as a parent.
             while p.synthetic:
                 assert len(p.parents) <= 1, \
diff --git a/tests/test-convert-cvs-branchpoints b/tests/test-convert-cvs-branchpoints
new file mode 100755
--- /dev/null
+++ b/tests/test-convert-cvs-branchpoints
@@ -0,0 +1,166 @@
+#!/bin/sh
+
+"$TESTDIR/hghave" cvs || exit 80
+
+cvscall()
+{
+    echo cvs -f "$@"
+    cvs -f "$@"
+    sleep 1
+}
+
+# output of 'cvs ci' varies unpredictably, so just discard it
+cvsci()
+{
+    echo cvs -f ci "$@"
+    cvs -f ci "$@" >/dev/null 2>&1
+    sleep 1
+}
+
+createmaster()
+{
+    rm -rf master
+    mkdir master
+    export CVSROOT=`pwd`/master
+    cvscall -q init
+    mkdir -p master/work
+    rm -rf work
+    cvscall -q co -d work work
+}
+
+hgcvsps()
+{
+    sleep 1
+    hg debugcvsps -x --parents work | sed -e 's/Author:.*/Author:/' -e 's/Date:.*/Date:/'
+}
+
+echo "[extensions]" >> $HGRCPATH
+echo "convert = " >> $HGRCPATH
+echo "graphlog = " >> $HGRCPATH
+echo "[convert]" >> $HGRCPATH
+echo "cvsps=builtin" >> $HGRCPATH
+
+createvar0()
+{
+    echo Creating 1447 var 0
+    createmaster
+    cd work
+    echo a > a.txt
+    echo b > b.txt
+    cvscall -Q add *.txt
+    cvsci -m "initial"
+    echo "b fix" >> b.txt
+    cvsci -m "b fix"
+    echo "a fix" >> a.txt
+    cvsci -m "a fix"
+    cvscall -q rtag -b BRANCH work
+    cvscall -q up -r BRANCH
+    echo "b branch fix" >> b.txt
+    cvsci -m "b branch fix"
+    hgcvsps
+    cd ..
+}
+
+createvar1()
+{
+    echo Creating 1447 var 1
+    createmaster
+    cd work
+    echo a > a.txt
+    echo b > b.txt
+    cvscall -Q add *.txt
+    cvsci -m "initial"
+    echo "b fix" >> b.txt
+    cvsci -m "b fix"
+    echo "a fix" >> a.txt
+    cvsci -m "a fix"
+    cvscall -q tag FOO
+    echo "b fix 2" >> b.txt
+    cvsci -m "b fix 2"
+    cvscall -q up -r 1.2 *.txt
+    cvscall -q rtag -b -r FOO BRANCH work
+    cvscall -q up -r BRANCH
+    echo "b branch fix" >> b.txt
+    cvsci -m "b branch fix"
+    hgcvsps
+    cd ..
+}
+
+createvar2()
+{
+    echo Creating 1447 var 2
+    createmaster
+    cd work
+    echo a > a.txt
+    echo b > b.txt
+    cvscall -Q add *.txt
+    cvsci -m "initial"
+    echo "b fix" >> b.txt
+    cvsci -m "b fix"
+    echo "a fix" >> a.txt
+    cvsci -m "a fix"
+    cvscall -q tag FOO
+    echo "a fix 2" >> a.txt
+    cvsci -m "a fix 2"
+    cvscall -q up -r 1.2 *.txt
+    cvscall -q rtag -b -r FOO BRANCH work
+    cvscall -q up -r BRANCH
+    echo "b branch fix" >> b.txt
+    cvsci -m "b branch fix"
+    hgcvsps
+    cd ..
+}
+
+createvar3()
+{
+    echo Creating 1447 var 3
+    createmaster
+    cd work
+    echo a > a.txt
+    echo b > b.txt
+    cvscall -Q add *.txt
+    cvsci -m "initial"
+    echo "b fix" >> b.txt
+    cvsci -m "b fix"
+    echo "a fix" >> a.txt
+    cvsci -m "a fix"
+    cvscall -q rtag -b BRANCH work
+    cvscall -q up -r BRANCH
+    echo "b branch fix" >> b.txt
+    cvsci -m "b branch fix"
+    cvscall -q up -A
+    echo "b fix 2" >> b.txt
+    cvsci -m "b fix 2"
+    hgcvsps
+    cd ..
+}
+
+createvar4()
+{
+    echo Creating 1447 var 3
+    createmaster
+    cd work
+    echo a > a.txt
+    echo b > b.txt
+    cvscall -Q add *.txt
+    cvsci -m "initial"
+    echo "b fix" >> b.txt
+    cvsci -m "b fix"
+    echo "a fix" >> a.txt
+    cvsci -m "a fix"
+    cvscall -q rtag -b BRANCH work
+    cvscall -q up -r BRANCH
+    echo "b branch fix" >> b.txt
+    cvsci -m "b branch fix"
+    cvscall -q up -A
+    echo "a fix 2" >> a.txt
+    cvsci -m "a fix 2"
+    hgcvsps
+    cd ..
+}
+
+createvar0
+createvar1
+createvar2
+createvar3
+createvar4
diff --git a/tests/test-convert-cvs-branchpoints.out b/tests/test-convert-cvs-branchpoints.out
new file mode 100644
--- /dev/null
+++ b/tests/test-convert-cvs-branchpoints.out
@@ -0,0 +1,400 @@
+Creating 1447 var 0
+cvs -f -q init
+cvs -f -q co -d work work
+cvs -f -Q add a.txt b.txt
+cvs -f ci -m initial
+cvs -f ci -m b fix
+cvs -f ci -m a fix
+cvs -f -q rtag -b BRANCH work
+cvs -f -q up -r BRANCH
+cvs -f ci -m b branch fix
+collecting CVS rlog
+5 log entries
+creating changesets
+4 changeset entries
+---------------------
+PatchSet 1 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Log:
+initial
+
+Members: 
+	a.txt:INITIAL->1.1 
+	b.txt:INITIAL->1.1 
+
+---------------------
+PatchSet 2 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 1
+Log:
+b fix
+
+Members: 
+	b.txt:1.1->1.2 
+
+---------------------
+PatchSet 3 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 2
+Log:
+a fix
+
+Members: 
+	a.txt:1.1->1.2 
+
+---------------------
+PatchSet 4 
+Date:
+Author:
+Branch: BRANCH
+Tag: (none) 
+Parent: 3
+Log:
+b branch fix
+
+Members: 
+	b.txt:1.2->1.2.2.1 
+
+Creating 1447 var 1
+cvs -f -q init
+cvs -f -q co -d work work
+cvs -f -Q add a.txt b.txt
+cvs -f ci -m initial
+cvs -f ci -m b fix
+cvs -f ci -m a fix
+cvs -f -q tag FOO
+T a.txt
+T b.txt
+cvs -f ci -m b fix 2
+cvs -f -q up -r 1.2 a.txt b.txt
+U b.txt
+cvs -f -q rtag -b -r FOO BRANCH work
+cvs -f -q up -r BRANCH
+cvs -f ci -m b branch fix
+collecting CVS rlog
+6 log entries
+creating changesets
+5 changeset entries
+---------------------
+PatchSet 1 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Log:
+initial
+
+Members: 
+	a.txt:INITIAL->1.1 
+	b.txt:INITIAL->1.1 
+
+---------------------
+PatchSet 2 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 1
+Log:
+b fix
+
+Members: 
+	b.txt:1.1->1.2 
+
+---------------------
+PatchSet 3 
+Date:
+Author:
+Branch: HEAD
+Tag: FOO 
+Parent: 2
+Log:
+a fix
+
+Members: 
+	a.txt:1.1->1.2 
+
+---------------------
+PatchSet 4 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 3
+Log:
+b fix 2
+
+Members: 
+	b.txt:1.2->1.3 
+
+---------------------
+PatchSet 5 
+Date:
+Author:
+Branch: BRANCH
+Tag: (none) 
+Parent: 3
+Log:
+b branch fix
+
+Members: 
+	b.txt:1.2->1.2.2.1 
+
+Creating 1447 var 2
+cvs -f -q init
+cvs -f -q co -d work work
+cvs -f -Q add a.txt b.txt
+cvs -f ci -m initial
+cvs -f ci -m b fix
+cvs -f ci -m a fix
+cvs -f -q tag FOO
+T a.txt
+T b.txt
+cvs -f ci -m a fix 2
+cvs -f -q up -r 1.2 a.txt b.txt
+U a.txt
+cvs -f -q rtag -b -r FOO BRANCH work
+cvs -f -q up -r BRANCH
+cvs -f ci -m b branch fix
+collecting CVS rlog
+6 log entries
+creating changesets
+5 changeset entries
+---------------------
+PatchSet 1 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Log:
+initial
+
+Members: 
+	a.txt:INITIAL->1.1 
+	b.txt:INITIAL->1.1 
+
+---------------------
+PatchSet 2 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 1
+Log:
+b fix
+
+Members: 
+	b.txt:1.1->1.2 
+
+---------------------
+PatchSet 3 
+Date:
+Author:
+Branch: HEAD
+Tag: FOO 
+Parent: 2
+Log:
+a fix
+
+Members: 
+	a.txt:1.1->1.2 
+
+---------------------
+PatchSet 4 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 3
+Log:
+a fix 2
+
+Members: 
+	a.txt:1.2->1.3 
+
+---------------------
+PatchSet 5 
+Date:
+Author:
+Branch: BRANCH
+Tag: (none) 
+Parent: 3
+Log:
+b branch fix
+
+Members: 
+	b.txt:1.2->1.2.2.1 
+
+Creating 1447 var 3
+cvs -f -q init
+cvs -f -q co -d work work
+cvs -f -Q add a.txt b.txt
+cvs -f ci -m initial
+cvs -f ci -m b fix
+cvs -f ci -m a fix
+cvs -f -q rtag -b BRANCH work
+cvs -f -q up -r BRANCH
+cvs -f ci -m b branch fix
+cvs -f -q up -A
+U b.txt
+cvs -f ci -m b fix 2
+collecting CVS rlog
+6 log entries
+creating changesets
+5 changeset entries
+---------------------
+PatchSet 1 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Log:
+initial
+
+Members: 
+	a.txt:INITIAL->1.1 
+	b.txt:INITIAL->1.1 
+
+---------------------
+PatchSet 2 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 1
+Log:
+b fix
+
+Members: 
+	b.txt:1.1->1.2 
+
+---------------------
+PatchSet 3 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 2
+Log:
+a fix
+
+Members: 
+	a.txt:1.1->1.2 
+
+---------------------
+PatchSet 4 
+Date:
+Author:
+Branch: BRANCH
+Tag: (none) 
+Parent: 3
+Log:
+b branch fix
+
+Members: 
+	b.txt:1.2->1.2.2.1 
+
+---------------------
+PatchSet 5 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 3
+Log:
+b fix 2
+
+Members: 
+	b.txt:1.2->1.3 
+
+Creating 1447 var 3
+cvs -f -q init
+cvs -f -q co -d work work
+cvs -f -Q add a.txt b.txt
+cvs -f ci -m initial
+cvs -f ci -m b fix
+cvs -f ci -m a fix
+cvs -f -q rtag -b BRANCH work
+cvs -f -q up -r BRANCH
+cvs -f ci -m b branch fix
+cvs -f -q up -A
+U b.txt
+cvs -f ci -m a fix 2
+collecting CVS rlog
+6 log entries
+creating changesets
+5 changeset entries
+---------------------
+PatchSet 1 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Log:
+initial
+
+Members: 
+	a.txt:INITIAL->1.1 
+	b.txt:INITIAL->1.1 
+
+---------------------
+PatchSet 2 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 1
+Log:
+b fix
+
+Members: 
+	b.txt:1.1->1.2 
+
+---------------------
+PatchSet 3 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 2
+Log:
+a fix
+
+Members: 
+	a.txt:1.1->1.2 
+
+---------------------
+PatchSet 4 
+Date:
+Author:
+Branch: BRANCH
+Tag: (none) 
+Parent: 3
+Log:
+b branch fix
+
+Members: 
+	b.txt:1.2->1.2.2.1 
+
+---------------------
+PatchSet 5 
+Date:
+Author:
+Branch: HEAD
+Tag: (none) 
+Parent: 3
+Log:
+a fix 2
+
+Members: 
+	a.txt:1.2->1.3 
+


More information about the Mercurial-devel mailing list