Mercurial > hg > mercurial-crew-with-dirclash
comparison contrib/convert-repo @ 3947:0fab73b3f453
convert-repo: add some smarts
autodetect source and destination repo types
autodetect read and write capabilities of converters
default destination directory (<src>-hg)
default map file (<dest>/.hg/shamap)
more verbose by default
add a -q switch
add IO functions
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Wed, 20 Dec 2006 16:31:46 -0600 |
parents | 645e1dd4b8ae |
children | b58c1681d23b |
comparison
equal
deleted
inserted
replaced
3943:ac02810132ca | 3947:0fab73b3f453 |
---|---|
20 # If the file doesn't exist, it's automatically created. It's updated | 20 # If the file doesn't exist, it's automatically created. It's updated |
21 # on each commit copied, so convert-repo can be interrupted and can | 21 # on each commit copied, so convert-repo can be interrupted and can |
22 # be run repeatedly to copy new commits. | 22 # be run repeatedly to copy new commits. |
23 | 23 |
24 import sys, os, zlib, sha, time | 24 import sys, os, zlib, sha, time |
25 | |
26 os.environ["HGENCODING"] = "utf-8" | 25 os.environ["HGENCODING"] = "utf-8" |
27 | 26 from mercurial import hg, ui, util, fancyopts |
28 from mercurial import hg, ui, util | 27 |
28 class Abort(Exception): pass | |
29 | |
30 quiet = 0 | |
31 def status(msg): | |
32 if not quiet: sys.stdout.write(str(msg)) | |
33 | |
34 def warn(msg): | |
35 sys.stderr.write(str(msg)) | |
36 | |
37 def abort(msg): | |
38 raise Abort(msg) | |
29 | 39 |
30 def recode(s): | 40 def recode(s): |
31 try: | 41 try: |
32 return s.decode("utf-8").encode("utf-8") | 42 return s.decode("utf-8").encode("utf-8") |
33 except: | 43 except: |
36 except: | 46 except: |
37 return s.decode("utf-8", "replace").encode("utf-8") | 47 return s.decode("utf-8", "replace").encode("utf-8") |
38 | 48 |
39 class convert_git: | 49 class convert_git: |
40 def __init__(self, path): | 50 def __init__(self, path): |
51 if os.path.isdir(path + "/.git"): | |
52 path += "/.git" | |
41 self.path = path | 53 self.path = path |
54 if not os.path.exists(path + "/HEAD"): | |
55 raise TypeError("couldn't open GIT repo %s" % path) | |
42 | 56 |
43 def getheads(self): | 57 def getheads(self): |
44 fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path) | 58 fh = os.popen("GIT_DIR=%s git-rev-parse --verify HEAD" % self.path) |
45 return [fh.read()[:-1]] | 59 return [fh.read()[:-1]] |
46 | 60 |
108 | 122 |
109 class convert_mercurial: | 123 class convert_mercurial: |
110 def __init__(self, path): | 124 def __init__(self, path): |
111 self.path = path | 125 self.path = path |
112 u = ui.ui() | 126 u = ui.ui() |
113 self.repo = hg.repository(u, path) | 127 try: |
128 self.repo = hg.repository(u, path) | |
129 except: | |
130 raise TypeError("could open hg repo %s" % path) | |
131 | |
132 def mapfile(self): | |
133 return os.path.join(self.path, ".hg", "shamap") | |
114 | 134 |
115 def getheads(self): | 135 def getheads(self): |
116 h = self.repo.changelog.heads() | 136 h = self.repo.changelog.heads() |
117 return [ hg.hex(x) for x in h ] | 137 return [ hg.hex(x) for x in h ] |
118 | 138 |
168 newlines.append("%s %s\n" % (tags[tag], tag)) | 188 newlines.append("%s %s\n" % (tags[tag], tag)) |
169 | 189 |
170 newlines.sort() | 190 newlines.sort() |
171 | 191 |
172 if newlines != oldlines: | 192 if newlines != oldlines: |
173 #print "updating tags" | 193 status("updating tags\n") |
174 f = self.repo.wfile(".hgtags", "w") | 194 f = self.repo.wfile(".hgtags", "w") |
175 f.write("".join(newlines)) | 195 f.write("".join(newlines)) |
176 f.close() | 196 f.close() |
177 if not oldlines: self.repo.add([".hgtags"]) | 197 if not oldlines: self.repo.add([".hgtags"]) |
178 date = "%s 0" % int(time.mktime(time.gmtime())) | 198 date = "%s 0" % int(time.mktime(time.gmtime())) |
179 self.repo.rawcommit([".hgtags"], "update tags", "convert-repo", | 199 self.repo.rawcommit([".hgtags"], "update tags", "convert-repo", |
180 date, self.repo.changelog.tip(), hg.nullid) | 200 date, self.repo.changelog.tip(), hg.nullid) |
181 return hg.hex(self.repo.changelog.tip()) | 201 return hg.hex(self.repo.changelog.tip()) |
182 | 202 |
203 converters = [convert_git, convert_mercurial] | |
204 | |
205 def converter(path): | |
206 if not os.path.isdir(path): | |
207 abort("%s: not a directory\n" % path) | |
208 for c in converters: | |
209 try: | |
210 return c(path) | |
211 except TypeError: | |
212 pass | |
213 abort("%s: unknown repository type\n" % path) | |
214 | |
183 class convert: | 215 class convert: |
184 def __init__(self, source, dest, mapfile): | 216 def __init__(self, source, dest, mapfile): |
217 | |
185 self.source = source | 218 self.source = source |
186 self.dest = dest | 219 self.dest = dest |
187 self.mapfile = mapfile | 220 self.mapfile = mapfile |
188 self.commitcache = {} | 221 self.commitcache = {} |
189 | 222 |
270 f = [f for f,v,e in files] | 303 f = [f for f,v,e in files] |
271 self.map[rev] = self.dest.putcommit(f, r, a, d, t) | 304 self.map[rev] = self.dest.putcommit(f, r, a, d, t) |
272 file(self.mapfile, "a").write("%s %s\n" % (rev, self.map[rev])) | 305 file(self.mapfile, "a").write("%s %s\n" % (rev, self.map[rev])) |
273 | 306 |
274 def convert(self): | 307 def convert(self): |
308 status("scanning source...\n") | |
275 heads = self.source.getheads() | 309 heads = self.source.getheads() |
276 parents = self.walktree(heads) | 310 parents = self.walktree(heads) |
311 status("sorting...\n") | |
277 t = self.toposort(parents) | 312 t = self.toposort(parents) |
278 t = [n for n in t if n not in self.map] | 313 t = [n for n in t if n not in self.map] |
279 num = len(t) | 314 num = len(t) |
280 c = None | 315 c = None |
281 | 316 |
317 status("converting...\n") | |
282 for c in t: | 318 for c in t: |
283 num -= 1 | 319 num -= 1 |
284 desc = self.commitcache[c][3].splitlines()[0] | 320 desc = self.commitcache[c][3].splitlines()[0] |
285 #print num, desc | 321 status("%d %s\n" % (num, desc)) |
286 self.copy(c) | 322 self.copy(c) |
287 | 323 |
288 tags = self.source.gettags() | 324 tags = self.source.gettags() |
289 ctags = {} | 325 ctags = {} |
290 for k in tags: | 326 for k in tags: |
297 # write another hash correspondence to override the previous | 333 # write another hash correspondence to override the previous |
298 # one so we don't end up with extra tag heads | 334 # one so we don't end up with extra tag heads |
299 if nrev: | 335 if nrev: |
300 file(self.mapfile, "a").write("%s %s\n" % (c, nrev)) | 336 file(self.mapfile, "a").write("%s %s\n" % (c, nrev)) |
301 | 337 |
302 gitpath, hgpath, mapfile = sys.argv[1:] | 338 def command(src, dest=None, mapfile=None, **opts): |
303 if os.path.isdir(gitpath + "/.git"): | 339 srcc = converter(src) |
304 gitpath += "/.git" | 340 if not hasattr(srcc, "getcommit"): |
305 | 341 abort("%s: can't read from this repo type\n" % src) |
306 c = convert(convert_git(gitpath), convert_mercurial(hgpath), mapfile) | 342 |
307 c.convert() | 343 if not dest: |
344 dest = src + "-hg" | |
345 status("assuming destination %s\n" % dest) | |
346 if not os.path.isdir(dest): | |
347 status("creating repository %s\n" % dest) | |
348 os.system("hg init " + dest) | |
349 destc = converter(dest) | |
350 if not hasattr(destc, "putcommit"): | |
351 abort("%s: can't write to this repo type\n" % src) | |
352 | |
353 if not mapfile: | |
354 try: | |
355 mapfile = destc.mapfile() | |
356 except: | |
357 mapfile = os.path.join(destc, "map") | |
358 | |
359 c = convert(srcc, destc, mapfile) | |
360 c.convert() | |
361 | |
362 options = [('q', 'quiet', None, 'suppress output')] | |
363 opts = {} | |
364 args = fancyopts.fancyopts(sys.argv[1:], options, opts) | |
365 | |
366 if opts['quiet']: | |
367 quiet = 1 | |
368 | |
369 try: | |
370 command(*args, **opts) | |
371 except Abort, inst: | |
372 warn(inst) | |
373 except KeyboardInterrupt: | |
374 status("interrupted\n") |