35 self.ui = ui |
35 self.ui = ui |
36 self.opts = opts |
36 self.opts = opts |
37 self.commitcache = {} |
37 self.commitcache = {} |
38 self.mapfile = mapfile |
38 self.mapfile = mapfile |
39 self.mapfilefd = None |
39 self.mapfilefd = None |
|
40 self.authors = {} |
|
41 self.writeauthors = False |
40 |
42 |
41 self.map = {} |
43 self.map = {} |
42 try: |
44 try: |
43 origmapfile = open(self.mapfile, 'r') |
45 origmapfile = open(self.mapfile, 'r') |
44 for l in origmapfile: |
46 for l in origmapfile: |
45 sv, dv = l[:-1].split() |
47 sv, dv = l[:-1].split() |
46 self.map[sv] = dv |
48 self.map[sv] = dv |
47 origmapfile.close() |
49 origmapfile.close() |
48 except IOError: |
50 except IOError: |
49 pass |
51 pass |
|
52 |
|
53 # Read first the dst author map if any |
|
54 if hasattr(self.dest, 'authorfile'): |
|
55 self.readauthormap(self.dest.authorfile()) |
|
56 # Extend/Override with new author map if necessary |
|
57 if 'authors' in opts: |
|
58 self.readauthormap(opts.get('authors')) |
|
59 self.writeauthors = True |
50 |
60 |
51 def walktree(self, heads): |
61 def walktree(self, heads): |
52 visit = heads |
62 visit = heads |
53 known = {} |
63 known = {} |
54 parents = {} |
64 parents = {} |
129 raise util.Abort("Could not open map file %s: %s, %s\n" % (self.mapfile, errno, strerror)) |
139 raise util.Abort("Could not open map file %s: %s, %s\n" % (self.mapfile, errno, strerror)) |
130 self.map[src] = dst |
140 self.map[src] = dst |
131 self.mapfilefd.write("%s %s\n" % (src, dst)) |
141 self.mapfilefd.write("%s %s\n" % (src, dst)) |
132 self.mapfilefd.flush() |
142 self.mapfilefd.flush() |
133 |
143 |
|
144 def writeauthormap(self): |
|
145 if self.writeauthors == True and len(self.authors) > 0 and hasattr(self.dest, 'authorfile'): |
|
146 authorfile = self.dest.authorfile() |
|
147 self.ui.status('Writing author map file %s\n' % authorfile) |
|
148 ofile = open(authorfile, 'w+') |
|
149 for author in self.authors: |
|
150 ofile.write("%s=%s\n" % (author, self.authors[author])) |
|
151 ofile.close() |
|
152 |
|
153 def readauthormap(self, authorfile): |
|
154 try: |
|
155 afile = open(authorfile, 'r') |
|
156 for line in afile: |
|
157 try: |
|
158 srcauthor = line.split('=')[0].strip() |
|
159 dstauthor = line.split('=')[1].strip() |
|
160 if srcauthor in self.authors and dstauthor != self.authors[srcauthor]: |
|
161 self.ui.status( |
|
162 'Overriding mapping for author %s, was %s, will be %s\n' |
|
163 % (srcauthor, self.authors[srcauthor], dstauthor)) |
|
164 else: |
|
165 self.ui.debug('Mapping author %s to %s\n' |
|
166 % (srcauthor, dstauthor)) |
|
167 self.authors[srcauthor] = dstauthor |
|
168 |
|
169 except IndexError: |
|
170 self.ui.warn( |
|
171 'Ignoring bad line in author file map %s: %s\n' |
|
172 % (authorfile, line)) |
|
173 afile.close() |
|
174 except IOError: |
|
175 self.ui.warn('Error reading author file map %s.\n' % authorfile) |
|
176 |
134 def copy(self, rev): |
177 def copy(self, rev): |
135 c = self.commitcache[rev] |
178 c = self.commitcache[rev] |
136 files = self.source.getchanges(rev) |
179 files = self.source.getchanges(rev) |
137 |
180 |
138 for f, v in files: |
181 for f, v in files: |
163 for c in t: |
206 for c in t: |
164 num -= 1 |
207 num -= 1 |
165 desc = self.commitcache[c].desc |
208 desc = self.commitcache[c].desc |
166 if "\n" in desc: |
209 if "\n" in desc: |
167 desc = desc.splitlines()[0] |
210 desc = desc.splitlines()[0] |
|
211 author = self.commitcache[c].author |
|
212 author = self.authors.get(author, author) |
|
213 self.commitcache[c].author = author |
168 self.ui.status("%d %s\n" % (num, desc)) |
214 self.ui.status("%d %s\n" % (num, desc)) |
169 self.copy(c) |
215 self.copy(c) |
170 |
216 |
171 tags = self.source.gettags() |
217 tags = self.source.gettags() |
172 ctags = {} |
218 ctags = {} |
179 nrev = self.dest.puttags(ctags) |
225 nrev = self.dest.puttags(ctags) |
180 # write another hash correspondence to override the previous |
226 # write another hash correspondence to override the previous |
181 # one so we don't end up with extra tag heads |
227 # one so we don't end up with extra tag heads |
182 if nrev: |
228 if nrev: |
183 self.mapentry(c, nrev) |
229 self.mapentry(c, nrev) |
|
230 |
|
231 self.writeauthormap() |
184 finally: |
232 finally: |
185 self.cleanup() |
233 self.cleanup() |
186 |
234 |
187 def cleanup(self): |
235 def cleanup(self): |
188 if self.mapfilefd: |
236 if self.mapfilefd: |
202 be created. If <mapfile> isn't given, it will be put in a default |
250 be created. If <mapfile> isn't given, it will be put in a default |
203 location (<dest>/.hg/shamap by default) |
251 location (<dest>/.hg/shamap by default) |
204 |
252 |
205 The <mapfile> is a simple text file that maps each source commit ID to |
253 The <mapfile> is a simple text file that maps each source commit ID to |
206 the destination ID for that revision, like so: |
254 the destination ID for that revision, like so: |
207 |
|
208 <source ID> <destination ID> |
255 <source ID> <destination ID> |
209 |
256 |
210 If the file doesn't exist, it's automatically created. It's updated |
257 If the file doesn't exist, it's automatically created. It's updated |
211 on each commit copied, so convert-repo can be interrupted and can |
258 on each commit copied, so convert-repo can be interrupted and can |
212 be run repeatedly to copy new commits. |
259 be run repeatedly to copy new commits. |
|
260 |
|
261 The [username mapping] file is a simple text file that maps each source |
|
262 commit author to a destination commit author. It is handy for source SCMs |
|
263 that use unix logins to identify authors (eg: CVS). One line per author |
|
264 mapping and the line format is: |
|
265 srcauthor=whatever string you want |
213 ''' |
266 ''' |
214 |
267 |
215 srcc = converter(ui, src) |
268 srcc = converter(ui, src) |
216 if not hasattr(srcc, "getcommit"): |
269 if not hasattr(srcc, "getcommit"): |
217 raise util.Abort("%s: can't read from this repo type" % src) |
270 raise util.Abort("%s: can't read from this repo type" % src) |
255 c.convert() |
308 c.convert() |
256 |
309 |
257 cmdtable = { |
310 cmdtable = { |
258 "convert": |
311 "convert": |
259 (_convert, |
312 (_convert, |
260 [('', 'datesort', None, 'try to sort changesets by date')], |
313 [('A', 'authors', '', 'username mapping filename'), |
|
314 ('', 'datesort', None, 'try to sort changesets by date')], |
261 'hg convert [OPTION]... SOURCE [DEST [MAPFILE]]'), |
315 'hg convert [OPTION]... SOURCE [DEST [MAPFILE]]'), |
262 } |
316 } |