Show More
@@ -0,0 +1,65 b'' | |||
|
1 | #!/bin/sh | |
|
2 | ||
|
3 | # This feature requires use of builtin cvsps! | |
|
4 | "$TESTDIR/hghave" cvs || exit 80 | |
|
5 | ||
|
6 | # XXX lots of duplication with other test-convert-cvs* scripts | |
|
7 | ||
|
8 | set -e | |
|
9 | ||
|
10 | echo "[extensions]" >> $HGRCPATH | |
|
11 | echo "convert = " >> $HGRCPATH | |
|
12 | echo "[convert]" >> $HGRCPATH | |
|
13 | echo "cvsps=builtin" >> $HGRCPATH | |
|
14 | ||
|
15 | echo % create cvs repository with one project | |
|
16 | mkdir cvsrepo | |
|
17 | cd cvsrepo | |
|
18 | export CVSROOT=`pwd` | |
|
19 | export CVS_OPTIONS=-f | |
|
20 | cd .. | |
|
21 | ||
|
22 | filter='sed "s:$CVSROOT:*REPO*:g"' | |
|
23 | cvscall() | |
|
24 | { | |
|
25 | cvs -f "$@" | eval $filter | |
|
26 | } | |
|
27 | ||
|
28 | cvscall -q -d "$CVSROOT" init | |
|
29 | mkdir cvsrepo/proj | |
|
30 | ||
|
31 | cvscall co proj | |
|
32 | ||
|
33 | echo % create file1 on the trunk | |
|
34 | cd proj | |
|
35 | touch file1 | |
|
36 | cvscall add file1 | |
|
37 | cvscall ci -m"add file1 on trunk" file1 | |
|
38 | ||
|
39 | echo % create two branches | |
|
40 | cvscall tag -b v1_0 | |
|
41 | cvscall tag -b v1_1 | |
|
42 | ||
|
43 | echo % create file2 on branch v1_0 | |
|
44 | cvs up -rv1_0 | |
|
45 | touch file2 | |
|
46 | cvscall add file2 | |
|
47 | cvscall ci -m"add file2 on branch v1_0" file2 | |
|
48 | ||
|
49 | echo % create file3, file4 on branch v1_1 | |
|
50 | cvs up -rv1_1 | |
|
51 | touch file3 | |
|
52 | touch file4 | |
|
53 | cvscall add file3 file4 | |
|
54 | cvscall ci -m"add file3, file4 on branch v1_1" file3 file4 | |
|
55 | ||
|
56 | echo % merge file2 from v1_0 to v1_1 | |
|
57 | cvscall up -jv1_0 | |
|
58 | cvscall ci -m"merge file2 from v1_0 to v1_1" | |
|
59 | ||
|
60 | echo % convert to hg | |
|
61 | cd .. | |
|
62 | hg convert proj proj.hg | eval $filter | |
|
63 | ||
|
64 | echo % hg log output | |
|
65 | hg -R proj.hg log --template "{rev} {desc}\n" |
@@ -0,0 +1,72 b'' | |||
|
1 | % create cvs repository with one project | |
|
2 | cvs checkout: Updating proj | |
|
3 | % create file1 on the trunk | |
|
4 | cvs add: scheduling file `file1' for addition | |
|
5 | cvs add: use 'cvs commit' to add this file permanently | |
|
6 | RCS file: *REPO*/proj/file1,v | |
|
7 | done | |
|
8 | Checking in file1; | |
|
9 | *REPO*/proj/file1,v <-- file1 | |
|
10 | initial revision: 1.1 | |
|
11 | done | |
|
12 | % create two branches | |
|
13 | cvs tag: Tagging . | |
|
14 | T file1 | |
|
15 | cvs tag: Tagging . | |
|
16 | T file1 | |
|
17 | % create file2 on branch v1_0 | |
|
18 | cvs update: Updating . | |
|
19 | cvs add: scheduling file `file2' for addition on branch `v1_0' | |
|
20 | cvs add: use 'cvs commit' to add this file permanently | |
|
21 | RCS file: *REPO*/proj/Attic/file2,v | |
|
22 | done | |
|
23 | Checking in file2; | |
|
24 | *REPO*/proj/Attic/file2,v <-- file2 | |
|
25 | new revision: 1.1.2.1; previous revision: 1.1 | |
|
26 | done | |
|
27 | % create file3, file4 on branch v1_1 | |
|
28 | cvs update: Updating . | |
|
29 | cvs update: file2 is no longer in the repository | |
|
30 | cvs add: scheduling file `file3' for addition on branch `v1_1' | |
|
31 | cvs add: scheduling file `file4' for addition on branch `v1_1' | |
|
32 | cvs add: use 'cvs commit' to add these files permanently | |
|
33 | RCS file: *REPO*/proj/Attic/file3,v | |
|
34 | done | |
|
35 | Checking in file3; | |
|
36 | *REPO*/proj/Attic/file3,v <-- file3 | |
|
37 | new revision: 1.1.2.1; previous revision: 1.1 | |
|
38 | done | |
|
39 | RCS file: *REPO*/proj/Attic/file4,v | |
|
40 | done | |
|
41 | Checking in file4; | |
|
42 | *REPO*/proj/Attic/file4,v <-- file4 | |
|
43 | new revision: 1.1.2.1; previous revision: 1.1 | |
|
44 | done | |
|
45 | % merge file2 from v1_0 to v1_1 | |
|
46 | cvs update: Updating . | |
|
47 | U file2 | |
|
48 | cvs commit: Examining . | |
|
49 | Checking in file2; | |
|
50 | *REPO*/proj/Attic/file2,v <-- file2 | |
|
51 | new revision: 1.1.4.2; previous revision: 1.1.4.1 | |
|
52 | done | |
|
53 | % convert to hg | |
|
54 | initializing destination proj.hg repository | |
|
55 | using builtin cvsps | |
|
56 | collecting CVS rlog | |
|
57 | 9 log entries | |
|
58 | creating changesets | |
|
59 | 4 changeset entries | |
|
60 | connecting to *REPO* | |
|
61 | scanning source... | |
|
62 | sorting... | |
|
63 | converting... | |
|
64 | 3 add file1 on trunk | |
|
65 | 2 add file2 on branch v1_0 | |
|
66 | 1 add file3, file4 on branch v1_1 | |
|
67 | 0 merge file2 from v1_0 to v1_1 | |
|
68 | % hg log output | |
|
69 | 3 merge file2 from v1_0 to v1_1 | |
|
70 | 2 add file3, file4 on branch v1_1 | |
|
71 | 1 add file2 on branch v1_0 | |
|
72 | 0 add file1 on trunk |
@@ -33,6 +33,7 b' class logentry(object):' | |||
|
33 | 33 | .rcs - name of file as returned from CVS |
|
34 | 34 | .revision - revision number as tuple |
|
35 | 35 | .tags - list of tags on the file |
|
36 | .synthetic - is this a synthetic "file ... added on ..." revision? | |
|
36 | 37 | ''' |
|
37 | 38 | def __init__(self, **entries): |
|
38 | 39 | self.__dict__.update(entries) |
@@ -107,6 +108,8 b' def createlog(ui, directory=None, root="' | |||
|
107 | 108 | re_60 = re.compile(r'date:\s+(.+);\s+author:\s+(.+);\s+state:\s+(.+?);(\s+lines:\s+(\+\d+)?\s+(-\d+)?;)?') |
|
108 | 109 | re_70 = re.compile('branches: (.+);$') |
|
109 | 110 | |
|
111 | file_added_re = re.compile(r'file [^/]+ was (initially )?added on branch') | |
|
112 | ||
|
110 | 113 | prefix = '' # leading path to strip of what we get from CVS |
|
111 | 114 | |
|
112 | 115 | if directory is None: |
@@ -279,7 +282,8 b' def createlog(ui, directory=None, root="' | |||
|
279 | 282 | assert match, _('expected revision number') |
|
280 | 283 | e = logentry(rcs=scache(rcs), file=scache(filename), |
|
281 | 284 | revision=tuple([int(x) for x in match.group(1).split('.')]), |
|
282 |
branches=[], parent=None |
|
|
285 | branches=[], parent=None, | |
|
286 | synthetic=False) | |
|
283 | 287 | state = 6 |
|
284 | 288 | |
|
285 | 289 | elif state == 6: |
@@ -338,6 +342,22 b' def createlog(ui, directory=None, root="' | |||
|
338 | 342 | else: |
|
339 | 343 | e.comment.append(line) |
|
340 | 344 | |
|
345 | # When a file is added on a branch B1, CVS creates a synthetic | |
|
346 | # dead trunk revision 1.1 so that the branch has a root. | |
|
347 | # Likewise, if you merge such a file to a later branch B2 (one | |
|
348 | # that already existed when the file was added on B1), CVS | |
|
349 | # creates a synthetic dead revision 1.1.x.1 on B2. Don't drop | |
|
350 | # these revisions now, but mark them synthetic so | |
|
351 | # createchangeset() can take care of them. | |
|
352 | if (store and | |
|
353 | e.dead and | |
|
354 | e.revision[-1] == 1 and # 1.1 or 1.1.x.1 | |
|
355 | len(e.comment) == 1 and | |
|
356 | file_added_re.match(e.comment[0])): | |
|
357 | ui.debug(_('found synthetic rev in %s: %r\n') | |
|
358 | % (e.rcs, e.comment[0])) | |
|
359 | e.synthetic = True | |
|
360 | ||
|
341 | 361 | if store: |
|
342 | 362 | # clean up the results and save in the log. |
|
343 | 363 | store = False |
@@ -399,6 +419,7 b' class changeset(object):' | |||
|
399 | 419 | .entries - list of logentry objects in this changeset |
|
400 | 420 | .parents - list of one or two parent changesets |
|
401 | 421 | .tags - list of tags on this changeset |
|
422 | .synthetic - from synthetic revision "file ... added on branch ..." | |
|
402 | 423 | ''' |
|
403 | 424 | def __init__(self, **entries): |
|
404 | 425 | self.__dict__.update(entries) |
@@ -438,6 +459,19 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
438 | 459 | files[e.file] = True |
|
439 | 460 | c.date = e.date # changeset date is date of latest commit in it |
|
440 | 461 | |
|
462 | # Mark synthetic changesets | |
|
463 | ||
|
464 | for c in changesets: | |
|
465 | # Synthetic revisions always get their own changeset, because | |
|
466 | # the log message includes the filename. E.g. if you add file3 | |
|
467 | # and file4 on a branch, you get four log entries and three | |
|
468 | # changesets: | |
|
469 | # "File file3 was added on branch ..." (synthetic, 1 entry) | |
|
470 | # "File file4 was added on branch ..." (synthetic, 1 entry) | |
|
471 | # "Add file3 and file4 to fix ..." (real, 2 entries) | |
|
472 | # Hence the check for 1 entry here. | |
|
473 | c.synthetic = (len(c.entries) == 1 and c.entries[0].synthetic) | |
|
474 | ||
|
441 | 475 | # Sort files in each changeset |
|
442 | 476 | |
|
443 | 477 | for c in changesets: |
@@ -546,7 +580,20 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
546 | 580 | |
|
547 | 581 | c.parents = [] |
|
548 | 582 | if p is not None: |
|
549 |
|
|
|
583 | p = changesets[p] | |
|
584 | ||
|
585 | # Ensure no changeset has a synthetic changeset as a parent. | |
|
586 | while p.synthetic: | |
|
587 | assert len(p.parents) <= 1, \ | |
|
588 | _('synthetic changeset cannot have multiple parents') | |
|
589 | if p.parents: | |
|
590 | p = p.parents[0] | |
|
591 | else: | |
|
592 | p = None | |
|
593 | break | |
|
594 | ||
|
595 | if p is not None: | |
|
596 | c.parents.append(p) | |
|
550 | 597 | |
|
551 | 598 | if mergefrom: |
|
552 | 599 | m = mergefrom.search(c.comment) |
@@ -582,6 +629,15 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
582 | 629 | branches[c.branch] = i |
|
583 | 630 | i += 1 |
|
584 | 631 | |
|
632 | # Drop synthetic changesets (safe now that we have ensured no other | |
|
633 | # changesets can have them as parents). | |
|
634 | i = 0 | |
|
635 | while i < len(changesets): | |
|
636 | if changesets[i].synthetic: | |
|
637 | del changesets[i] | |
|
638 | else: | |
|
639 | i += 1 | |
|
640 | ||
|
585 | 641 | # Number changesets |
|
586 | 642 | |
|
587 | 643 | for i, c in enumerate(changesets): |
General Comments 0
You need to be logged in to leave comments.
Login now