comparison extra/fast-export/hg-fast-export.py @ 1567:3ad53f43483d live

Update hg-fast-export to current version (with fix-broken-bare upstream branch) for compatibility with current git
author Chris Cannam
date Mon, 10 Oct 2016 12:56:28 +0100
parents e9e55585ebf2
children
comparison
equal deleted inserted replaced
1566:ac2e4a54a6a6 1567:3ad53f43483d
143 if count%cfg_export_boundary==0: 143 if count%cfg_export_boundary==0:
144 sys.stderr.write('Exported %d/%d files\n' % (count,max)) 144 sys.stderr.write('Exported %d/%d files\n' % (count,max))
145 if max>cfg_export_boundary: 145 if max>cfg_export_boundary:
146 sys.stderr.write('Exported %d/%d files\n' % (count,max)) 146 sys.stderr.write('Exported %d/%d files\n' % (count,max))
147 147
148 def sanitize_name(name,what="branch"): 148 def sanitize_name(name,what="branch", mapping={}):
149 """Sanitize input roughly according to git-check-ref-format(1)""" 149 """Sanitize input roughly according to git-check-ref-format(1)"""
150
151 # NOTE: Do not update this transform to work around
152 # incompatibilities on your platform. If you change it and it starts
153 # modifying names which previously were not touched it will break
154 # preexisting setups which are doing incremental imports.
155 #
156 # Use the -B and -T options to mangle branch and tag names
157 # instead. If you have a source repository where this is too much
158 # work to do manually, write a tool that does it for you.
150 159
151 def dot(name): 160 def dot(name):
152 if name[0] == '.': return '_'+name[1:] 161 if name[0] == '.': return '_'+name[1:]
153 return name 162 return name
154 163
155 n=name 164 n=mapping.get(name,name)
156 p=re.compile('([[ ~^:?\\\\*]|\.\.)') 165 p=re.compile('([[ ~^:?\\\\*]|\.\.)')
157 n=p.sub('_', n) 166 n=p.sub('_', n)
158 if n[-1] in ('/', '.'): n=n[:-1]+'_' 167 if n[-1] in ('/', '.'): n=n[:-1]+'_'
159 n='/'.join(map(dot,n.split('/'))) 168 n='/'.join(map(dot,n.split('/')))
160 p=re.compile('_+') 169 p=re.compile('_+')
168 if filename[0] == '/': 177 if filename[0] == '/':
169 return filename[1:] 178 return filename[1:]
170 return filename 179 return filename
171 180
172 def export_commit(ui,repo,revision,old_marks,max,count,authors, 181 def export_commit(ui,repo,revision,old_marks,max,count,authors,
173 branchesmap,sob,brmap,hgtags,notes,encoding='',fn_encoding=''): 182 branchesmap,sob,brmap,hgtags,encoding='',fn_encoding=''):
174 def get_branchname(name): 183 def get_branchname(name):
175 if brmap.has_key(name): 184 if brmap.has_key(name):
176 return brmap[name] 185 return brmap[name]
177 n=sanitize_name(branchesmap.get(name,name)) 186 n=sanitize_name(name, "branch", branchesmap)
178 brmap[name]=n 187 brmap[name]=n
179 return n 188 return n
180 189
181 (revnode,_,user,(time,timezone),files,desc,branch,_)=get_changeset(ui,repo,revision,authors,encoding) 190 (revnode,_,user,(time,timezone),files,desc,branch,_)=get_changeset(ui,repo,revision,authors,encoding)
182 191
233 map(lambda r: wr('D %s' % r),removed) 242 map(lambda r: wr('D %s' % r),removed)
234 export_file_contents(ctx,man,added,hgtags,fn_encoding) 243 export_file_contents(ctx,man,added,hgtags,fn_encoding)
235 export_file_contents(ctx,man,changed,hgtags,fn_encoding) 244 export_file_contents(ctx,man,changed,hgtags,fn_encoding)
236 wr() 245 wr()
237 246
238 count=checkpoint(count) 247 return checkpoint(count)
239 count=generate_note(user,time,timezone,revision,ctx,count,notes) 248
240 return count 249 def export_note(ui,repo,revision,count,authors,encoding,is_first):
241 250 (revnode,_,user,(time,timezone),_,_,_,_)=get_changeset(ui,repo,revision,authors,encoding)
242 def generate_note(user,time,timezone,revision,ctx,count,notes): 251
243 if not notes: 252 parents = [p for p in repo.changelog.parentrevs(revision) if p >= 0]
244 return count 253
245 wr('commit refs/notes/hg') 254 wr('commit refs/notes/hg')
246 wr('committer %s %d %s' % (user,time,timezone)) 255 wr('committer %s %d %s' % (user,time,timezone))
247 wr('data 0') 256 wr('data 0')
257 if is_first:
258 wr('from refs/notes/hg^0')
248 wr('N inline :%d' % (revision+1)) 259 wr('N inline :%d' % (revision+1))
249 hg_hash=ctx.hex() 260 hg_hash=repo.changectx(str(revision)).hex()
250 wr('data %d' % (len(hg_hash))) 261 wr('data %d' % (len(hg_hash)))
251 wr_no_nl(hg_hash) 262 wr_no_nl(hg_hash)
252 wr() 263 wr()
253 return checkpoint(count) 264 return checkpoint(count)
254 265
266 wr('data %d' % (len(desc)+1)) # wtf?
267 wr(desc)
268 wr()
269
255 def export_tags(ui,repo,old_marks,mapping_cache,count,authors,tagsmap): 270 def export_tags(ui,repo,old_marks,mapping_cache,count,authors,tagsmap):
256 l=repo.tagslist() 271 l=repo.tagslist()
257 for tag,node in l: 272 for tag,node in l:
258 # Remap the branch name 273 # Remap the branch name
259 tag=sanitize_name(tagsmap.get(tag,tag),"tag") 274 tag=sanitize_name(tag,"tag",tagsmap)
260 # ignore latest revision 275 # ignore latest revision
261 if tag=='tip': continue 276 if tag=='tip': continue
262 # ignore tags to nodes that are missing (ie, 'in the future') 277 # ignore tags to nodes that are missing (ie, 'in the future')
263 if node.encode('hex_codec') not in mapping_cache: 278 if node.encode('hex_codec') not in mapping_cache:
264 sys.stderr.write('Tag %s refers to unseen node %s\n' % (tag, node.encode('hex_codec'))) 279 sys.stderr.write('Tag %s refers to unseen node %s\n' % (tag, node.encode('hex_codec')))
279 return count 294 return count
280 295
281 def load_mapping(name, filename): 296 def load_mapping(name, filename):
282 cache={} 297 cache={}
283 if not os.path.exists(filename): 298 if not os.path.exists(filename):
299 sys.stderr.write('Could not open mapping file [%s]\n' % (filename))
284 return cache 300 return cache
285 f=open(filename,'r') 301 f=open(filename,'r')
286 l=0 302 l=0
287 a=0 303 a=0
288 lre=re.compile('^([^=]+)[ ]*=[ ]*(.+)$') 304 lre=re.compile('^([^=]+)[ ]*=[ ]*(.+)$')
309 if 'close' not in repo.changelog.read(h)[5]: 325 if 'close' not in repo.changelog.read(h)[5]:
310 tip = h 326 tip = h
311 break 327 break
312 return tip 328 return tip
313 329
314 def verify_heads(ui,repo,cache,force): 330 def verify_heads(ui,repo,cache,force,branchesmap):
315 branches={} 331 branches={}
316 for bn, heads in repo.branchmap().iteritems(): 332 for bn, heads in repo.branchmap().iteritems():
317 branches[bn] = branchtip(repo, heads) 333 branches[bn] = branchtip(repo, heads)
318 l=[(-repo.changelog.rev(n), n, t) for t, n in branches.items()] 334 l=[(-repo.changelog.rev(n), n, t) for t, n in branches.items()]
319 l.sort() 335 l.sort()
320 336
321 # get list of hg's branches to verify, don't take all git has 337 # get list of hg's branches to verify, don't take all git has
322 for _,_,b in l: 338 for _,_,b in l:
323 b=get_branch(b) 339 b=get_branch(b)
324 sha1=get_git_sha1(b) 340 sanitized_name=sanitize_name(b,"branch",branchesmap)
325 c=cache.get(b) 341 sha1=get_git_sha1(sanitized_name)
342 c=cache.get(sanitized_name)
326 if sha1!=c: 343 if sha1!=c:
327 sys.stderr.write('Error: Branch [%s] modified outside hg-fast-export:' 344 sys.stderr.write('Error: Branch [%s] modified outside hg-fast-export:'
328 '\n%s (repo) != %s (cache)\n' % (b,sha1,c)) 345 '\n%s (repo) != %s (cache)\n' % (b,sha1,c))
329 if not force: return False 346 if not force: return False
330 347
341 return True 358 return True
342 359
343 def hg2git(repourl,m,marksfile,mappingfile,headsfile,tipfile, 360 def hg2git(repourl,m,marksfile,mappingfile,headsfile,tipfile,
344 authors={},branchesmap={},tagsmap={}, 361 authors={},branchesmap={},tagsmap={},
345 sob=False,force=False,hgtags=False,notes=False,encoding='',fn_encoding=''): 362 sob=False,force=False,hgtags=False,notes=False,encoding='',fn_encoding=''):
363 def check_cache(filename, contents):
364 if len(contents) == 0:
365 sys.stderr.write('Warning: %s does not contain any data, this will probably make an incremental import fail\n' % filename)
366
346 _max=int(m) 367 _max=int(m)
347 368
348 old_marks=load_cache(marksfile,lambda s: int(s)-1) 369 old_marks=load_cache(marksfile,lambda s: int(s)-1)
349 mapping_cache=load_cache(mappingfile) 370 mapping_cache=load_cache(mappingfile)
350 heads_cache=load_cache(headsfile) 371 heads_cache=load_cache(headsfile)
351 state_cache=load_cache(tipfile) 372 state_cache=load_cache(tipfile)
352 373
374 if len(state_cache) != 0:
375 for (name, data) in [(marksfile, old_marks),
376 (mappingfile, mapping_cache),
377 (headsfile, state_cache)]:
378 check_cache(name, data)
379
353 ui,repo=setup_repo(repourl) 380 ui,repo=setup_repo(repourl)
354 381
355 if not verify_heads(ui,repo,heads_cache,force): 382 if not verify_heads(ui,repo,heads_cache,force,branchesmap):
356 return 1 383 return 1
357 384
358 try: 385 try:
359 tip=repo.changelog.count() 386 tip=repo.changelog.count()
360 except AttributeError: 387 except AttributeError:
372 399
373 c=0 400 c=0
374 brmap={} 401 brmap={}
375 for rev in range(min,max): 402 for rev in range(min,max):
376 c=export_commit(ui,repo,rev,old_marks,max,c,authors,branchesmap, 403 c=export_commit(ui,repo,rev,old_marks,max,c,authors,branchesmap,
377 sob,brmap,hgtags,notes,encoding,fn_encoding) 404 sob,brmap,hgtags,encoding,fn_encoding)
405 if notes:
406 for rev in range(min,max):
407 c=export_note(ui,repo,rev,c,authors, encoding, rev == min and min != 0)
378 408
379 state_cache['tip']=max 409 state_cache['tip']=max
380 state_cache['repo']=repourl 410 state_cache['repo']=repourl
381 save_cache(tipfile,state_cache) 411 save_cache(tipfile,state_cache)
382 save_cache(mappingfile,mapping_cache) 412 save_cache(mappingfile,mapping_cache)