chris@1544: #!/usr/bin/env python chris@1544: chris@1544: # Copyright (c) 2007, 2008 Rocco Rutte and others. chris@1544: # License: GPLv2 chris@1544: chris@1544: from mercurial import node chris@1544: from hg2git import setup_repo,load_cache,get_changeset,get_git_sha1 chris@1544: from optparse import OptionParser chris@1544: import sys chris@1544: chris@1544: def heads(ui,repo,start=None,stop=None,max=None): chris@1544: # this is copied from mercurial/revlog.py and differs only in chris@1544: # accepting a max argument for xrange(startrev+1,...) defaulting chris@1544: # to the original repo.changelog.count() chris@1544: if start is None: chris@1544: start = node.nullid chris@1544: if stop is None: chris@1544: stop = [] chris@1544: if max is None: chris@1544: max = repo.changelog.count() chris@1544: stoprevs = dict.fromkeys([repo.changelog.rev(n) for n in stop]) chris@1544: startrev = repo.changelog.rev(start) chris@1544: reachable = {startrev: 1} chris@1544: heads = {startrev: 1} chris@1544: chris@1544: parentrevs = repo.changelog.parentrevs chris@1544: for r in xrange(startrev + 1, max): chris@1544: for p in parentrevs(r): chris@1544: if p in reachable: chris@1544: if r not in stoprevs: chris@1544: reachable[r] = 1 chris@1544: heads[r] = 1 chris@1544: if p in heads and p not in stoprevs: chris@1544: del heads[p] chris@1544: chris@1544: return [(repo.changelog.node(r),str(r)) for r in heads] chris@1544: chris@1544: def get_branches(ui,repo,heads_cache,marks_cache,mapping_cache,max): chris@1544: h=heads(ui,repo,max=max) chris@1544: stale=dict.fromkeys(heads_cache) chris@1544: changed=[] chris@1544: unchanged=[] chris@1544: for node,rev in h: chris@1544: _,_,user,(_,_),_,desc,branch,_=get_changeset(ui,repo,rev) chris@1544: del stale[branch] chris@1544: git_sha1=get_git_sha1(branch) chris@1544: cache_sha1=marks_cache.get(str(int(rev)+1)) chris@1544: if git_sha1!=None and git_sha1==cache_sha1: chris@1544: unchanged.append([branch,cache_sha1,rev,desc.split('\n')[0],user]) chris@1544: else: chris@1544: changed.append([branch,cache_sha1,rev,desc.split('\n')[0],user]) chris@1544: changed.sort() chris@1544: unchanged.sort() chris@1544: return stale,changed,unchanged chris@1544: chris@1544: def get_tags(ui,repo,marks_cache,mapping_cache,max): chris@1544: l=repo.tagslist() chris@1544: good,bad=[],[] chris@1544: for tag,node in l: chris@1544: if tag=='tip': continue chris@1544: rev=int(mapping_cache[node.encode('hex_codec')]) chris@1544: cache_sha1=marks_cache.get(str(int(rev)+1)) chris@1544: _,_,user,(_,_),_,desc,branch,_=get_changeset(ui,repo,rev) chris@1544: if int(rev)>int(max): chris@1544: bad.append([tag,branch,cache_sha1,rev,desc.split('\n')[0],user]) chris@1544: else: chris@1544: good.append([tag,branch,cache_sha1,rev,desc.split('\n')[0],user]) chris@1544: good.sort() chris@1544: bad.sort() chris@1544: return good,bad chris@1544: chris@1544: def mangle_mark(mark): chris@1544: return str(int(mark)-1) chris@1544: chris@1544: if __name__=='__main__': chris@1544: def bail(parser,opt): chris@1544: sys.stderr.write('Error: No option %s given\n' % opt) chris@1544: parser.print_help() chris@1544: sys.exit(2) chris@1544: chris@1544: parser=OptionParser() chris@1544: chris@1544: parser.add_option("--marks",dest="marksfile", chris@1544: help="File to read git-fast-import's marks from") chris@1544: parser.add_option("--mapping",dest="mappingfile", chris@1544: help="File to read last run's hg-to-git SHA1 mapping") chris@1544: parser.add_option("--heads",dest="headsfile", chris@1544: help="File to read last run's git heads from") chris@1544: parser.add_option("--status",dest="statusfile", chris@1544: help="File to read status from") chris@1544: parser.add_option("-r","--repo",dest="repourl", chris@1544: help="URL of repo to import") chris@1544: parser.add_option("-R","--revision",type=int,dest="revision", chris@1544: help="Revision to reset to") chris@1544: chris@1544: (options,args)=parser.parse_args() chris@1544: chris@1544: if options.marksfile==None: bail(parser,'--marks option') chris@1544: if options.mappingfile==None: bail(parser,'--mapping option') chris@1544: if options.headsfile==None: bail(parser,'--heads option') chris@1544: if options.statusfile==None: bail(parser,'--status option') chris@1544: if options.repourl==None: bail(parser,'--repo option') chris@1544: if options.revision==None: bail(parser,'-R/--revision') chris@1544: chris@1544: heads_cache=load_cache(options.headsfile) chris@1544: marks_cache=load_cache(options.marksfile,mangle_mark) chris@1544: state_cache=load_cache(options.statusfile) chris@1544: mapping_cache = load_cache(options.mappingfile) chris@1544: chris@1544: l=int(state_cache.get('tip',options.revision)) chris@1544: if options.revision+1>l: chris@1544: sys.stderr.write('Revision is beyond last revision imported: %d>%d\n' % (options.revision,l)) chris@1544: sys.exit(1) chris@1544: chris@1544: ui,repo=setup_repo(options.repourl) chris@1544: chris@1544: stale,changed,unchanged=get_branches(ui,repo,heads_cache,marks_cache,mapping_cache,options.revision+1) chris@1544: good,bad=get_tags(ui,repo,marks_cache,mapping_cache,options.revision+1) chris@1544: chris@1544: print "Possibly stale branches:" chris@1544: map(lambda b: sys.stdout.write('\t%s\n' % b),stale.keys()) chris@1544: chris@1544: print "Possibly stale tags:" chris@1544: map(lambda b: sys.stdout.write('\t%s on %s (r%s)\n' % (b[0],b[1],b[3])),bad) chris@1544: chris@1544: print "Unchanged branches:" chris@1544: map(lambda b: sys.stdout.write('\t%s (r%s)\n' % (b[0],b[2])),unchanged) chris@1544: chris@1544: print "Unchanged tags:" chris@1544: map(lambda b: sys.stdout.write('\t%s on %s (r%s)\n' % (b[0],b[1],b[3])),good) chris@1544: chris@1544: print "Reset branches in '%s' to:" % options.headsfile chris@1544: map(lambda b: sys.stdout.write('\t:%s %s\n\t\t(r%s: %s: %s)\n' % (b[0],b[1],b[2],b[4],b[3])),changed) chris@1544: chris@1544: print "Reset ':tip' in '%s' to '%d'" % (options.statusfile,options.revision)