comparison hgext/convert/cvs.py @ 6690:127e8c3466d1

convert: cvs.py - Allow user to use built-in CVS changeset code. tests: add two testcases for CVS conversion with builtin CVS including a testcase for issue 1148.
author Frank Kingswood <frank@kingswood-consulting.co.uk>
date Sun, 15 Jun 2008 16:05:46 +0100
parents 308988071b90
children f67d1468ac50
comparison
equal deleted inserted replaced
6689:d2ac53fe216e 6690:127e8c3466d1
1 # CVS conversion code inspired by hg-cvs-import and git-cvsimport 1 # CVS conversion code inspired by hg-cvs-import and git-cvsimport
2 2
3 import os, locale, re, socket 3 import os, locale, re, socket
4 from cStringIO import StringIO 4 from cStringIO import StringIO
5 from mercurial import util 5 from mercurial import util
6 from mercurial.i18n import _
6 7
7 from common import NoRepo, commit, converter_source, checktool 8 from common import NoRepo, commit, converter_source, checktool
9 import cvsps
8 10
9 class convert_cvs(converter_source): 11 class convert_cvs(converter_source):
10 def __init__(self, ui, path, rev=None): 12 def __init__(self, ui, path, rev=None):
11 super(convert_cvs, self).__init__(ui, path, rev=rev) 13 super(convert_cvs, self).__init__(ui, path, rev=rev)
12 14
13 cvs = os.path.join(path, "CVS") 15 cvs = os.path.join(path, "CVS")
14 if not os.path.exists(cvs): 16 if not os.path.exists(cvs):
15 raise NoRepo("%s does not look like a CVS checkout" % path) 17 raise NoRepo("%s does not look like a CVS checkout" % path)
16 18
19 checktool('cvs')
17 self.cmd = ui.config('convert', 'cvsps', 'cvsps -A -u --cvs-direct -q') 20 self.cmd = ui.config('convert', 'cvsps', 'cvsps -A -u --cvs-direct -q')
18 cvspsexe = self.cmd.split(None, 1)[0] 21 cvspsexe = self.cmd.split(None, 1)[0]
19 for tool in (cvspsexe, 'cvs'): 22 self.builtin = cvspsexe == 'builtin'
20 checktool(tool) 23
24 if not self.builtin:
25 checktool(cvspsexe)
21 26
22 self.changeset = {} 27 self.changeset = {}
23 self.files = {} 28 self.files = {}
24 self.tags = {} 29 self.tags = {}
25 self.lastbranch = {} 30 self.lastbranch = {}
26 self.parent = {} 31 self.parent = {}
27 self.socket = None 32 self.socket = None
28 self.cvsroot = file(os.path.join(cvs, "Root")).read()[:-1] 33 self.cvsroot = file(os.path.join(cvs, "Root")).read()[:-1]
29 self.cvsrepo = file(os.path.join(cvs, "Repository")).read()[:-1] 34 self.cvsrepo = file(os.path.join(cvs, "Repository")).read()[:-1]
30 self.encoding = locale.getpreferredencoding() 35 self.encoding = locale.getpreferredencoding()
31 self._parse() 36
37 self._parse(ui)
32 self._connect() 38 self._connect()
33 39
34 def _parse(self): 40 def _parse(self, ui):
35 if self.changeset: 41 if self.changeset:
36 return 42 return
37 43
38 maxrev = 0 44 maxrev = 0
39 cmd = self.cmd 45 cmd = self.cmd
54 try: 60 try:
55 os.chdir(self.path) 61 os.chdir(self.path)
56 id = None 62 id = None
57 state = 0 63 state = 0
58 filerevids = {} 64 filerevids = {}
59 for l in util.popen(cmd): 65
60 if state == 0: # header 66 if self.builtin:
61 if l.startswith("PatchSet"): 67 # builtin cvsps code
62 id = l[9:-2] 68 ui.status(_('using builtin cvsps\n'))
63 if maxrev and int(id) > maxrev: 69
64 # ignore everything 70 db = cvsps.createlog(ui, cache='update')
65 state = 3 71 db = cvsps.createchangeset(ui, db,
66 elif l.startswith("Date"): 72 fuzz=int(ui.config('convert', 'cvsps.fuzz', 60)),
67 date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"]) 73 mergeto=ui.config('convert', 'cvsps.mergeto', None),
68 date = util.datestr(date) 74 mergefrom=ui.config('convert', 'cvsps.mergefrom', None))
69 elif l.startswith("Branch"): 75
70 branch = l[8:-1] 76 for cs in db:
71 self.parent[id] = self.lastbranch.get(branch, 'bad') 77 if maxrev and cs.id>maxrev:
72 self.lastbranch[branch] = id 78 break
73 elif l.startswith("Ancestor branch"): 79 id = str(cs.id)
74 ancestor = l[17:-1] 80 cs.author = self.recode(cs.author)
75 # figure out the parent later 81 self.lastbranch[cs.branch] = id
76 self.parent[id] = self.lastbranch[ancestor] 82 cs.comment = self.recode(cs.comment)
77 elif l.startswith("Author"): 83 date = util.datestr(cs.date)
78 author = self.recode(l[8:-1]) 84 self.tags.update(dict.fromkeys(cs.tags, id))
79 elif l.startswith("Tag:") or l.startswith("Tags:"): 85
80 t = l[l.index(':')+1:] 86 files = {}
81 t = [ut.strip() for ut in t.split(',')] 87 for f in cs.entries:
82 if (len(t) > 1) or (t[0] and (t[0] != "(none)")): 88 files[f.file] = "%s%s" % ('.'.join([str(x) for x in f.revision]),
83 self.tags.update(dict.fromkeys(t, id)) 89 ['', '(DEAD)'][f.dead])
84 elif l.startswith("Log:"): 90
85 # switch to gathering log 91 # add current commit to set
86 state = 1 92 c = commit(author=cs.author, date=date,
87 log = "" 93 parents=[str(p.id) for p in cs.parents],
88 elif state == 1: # log 94 desc=cs.comment, branch=cs.branch or '')
89 if l == "Members: \n": 95 self.changeset[id] = c
90 # switch to gathering members 96 self.files[id] = files
91 files = {} 97 else:
92 oldrevs = [] 98 # external cvsps
93 log = self.recode(log[:-1]) 99 for l in util.popen(cmd):
94 state = 2 100 if state == 0: # header
95 else: 101 if l.startswith("PatchSet"):
96 # gather log 102 id = l[9:-2]
97 log += l 103 if maxrev and int(id) > maxrev:
98 elif state == 2: # members 104 # ignore everything
99 if l == "\n": # start of next entry 105 state = 3
100 state = 0 106 elif l.startswith("Date"):
101 p = [self.parent[id]] 107 date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
102 if id == "1": 108 date = util.datestr(date)
103 p = [] 109 elif l.startswith("Branch"):
104 if branch == "HEAD": 110 branch = l[8:-1]
105 branch = "" 111 self.parent[id] = self.lastbranch.get(branch, 'bad')
106 if branch: 112 self.lastbranch[branch] = id
107 latest = None 113 elif l.startswith("Ancestor branch"):
108 # the last changeset that contains a base 114 ancestor = l[17:-1]
109 # file is our parent 115 # figure out the parent later
110 for r in oldrevs: 116 self.parent[id] = self.lastbranch[ancestor]
111 latest = max(filerevids.get(r, None), latest) 117 elif l.startswith("Author"):
112 if latest: 118 author = self.recode(l[8:-1])
113 p = [latest] 119 elif l.startswith("Tag:") or l.startswith("Tags:"):
114 120 t = l[l.index(':')+1:]
115 # add current commit to set 121 t = [ut.strip() for ut in t.split(',')]
116 c = commit(author=author, date=date, parents=p, 122 if (len(t) > 1) or (t[0] and (t[0] != "(none)")):
117 desc=log, branch=branch) 123 self.tags.update(dict.fromkeys(t, id))
118 self.changeset[id] = c 124 elif l.startswith("Log:"):
119 self.files[id] = files 125 # switch to gathering log
120 else: 126 state = 1
121 colon = l.rfind(':') 127 log = ""
122 file = l[1:colon] 128 elif state == 1: # log
123 rev = l[colon+1:-2] 129 if l == "Members: \n":
124 oldrev, rev = rev.split("->") 130 # switch to gathering members
125 files[file] = rev 131 files = {}
126 132 oldrevs = []
127 # save some information for identifying branch points 133 log = self.recode(log[:-1])
128 oldrevs.append("%s:%s" % (oldrev, file)) 134 state = 2
129 filerevids["%s:%s" % (rev, file)] = id 135 else:
130 elif state == 3: 136 # gather log
131 # swallow all input 137 log += l
132 continue 138 elif state == 2: # members
139 if l == "\n": # start of next entry
140 state = 0
141 p = [self.parent[id]]
142 if id == "1":
143 p = []
144 if branch == "HEAD":
145 branch = ""
146 if branch:
147 latest = None
148 # the last changeset that contains a base
149 # file is our parent
150 for r in oldrevs:
151 latest = max(filerevids.get(r, None), latest)
152 if latest:
153 p = [latest]
154
155 # add current commit to set
156 c = commit(author=author, date=date, parents=p,
157 desc=log, branch=branch)
158 self.changeset[id] = c
159 self.files[id] = files
160 else:
161 colon = l.rfind(':')
162 file = l[1:colon]
163 rev = l[colon+1:-2]
164 oldrev, rev = rev.split("->")
165 files[file] = rev
166
167 # save some information for identifying branch points
168 oldrevs.append("%s:%s" % (oldrev, file))
169 filerevids["%s:%s" % (rev, file)] = id
170 elif state == 3:
171 # swallow all input
172 continue
133 173
134 self.heads = self.lastbranch.values() 174 self.heads = self.lastbranch.values()
135 finally: 175 finally:
136 os.chdir(d) 176 os.chdir(d)
137 177