# License: MIT <http://www.opensource.org/licenses/mit-license.php>
from mercurial import repo,hg,cmdutil,util,ui,revlog,node
-from hg2git import setup_repo,fixup_user,get_branch,get_changeset,load_cache,save_cache
+from hg2git import setup_repo,fixup_user,get_branch,get_changeset,load_cache,save_cache,get_git_sha1
from tempfile import mkstemp
from optparse import OptionParser
import re
return x and '100755' or '100644'
def wr(msg=''):
+ if msg == None:
+ msg = ''
print msg
#map(lambda x: sys.stderr.write('\t[%s]\n' % x),msg.split('\n'))
"""Get the mark for some parent.
If we saw it in the current session, return :%d syntax and
otherwise the SHA1 from the cache."""
- return marks.get(str(parent+1),':%d' % (parent+1))
+ return marks.get(str(parent),':%d' % (parent+1))
-def mismatch(f1,f2):
+def file_mismatch(f1,f2):
"""See if two revisions of a file are not equal."""
return node.hex(f1)!=node.hex(f2)
-def outer_set(dleft,dright,l,c,r):
+def split_dict(dleft,dright,l=[],c=[],r=[],match=file_mismatch):
"""Loop over our repository and find all changed and missing files."""
for left in dleft.keys():
right=dright.get(left,None)
if right==None:
# we have the file but our parent hasn't: add to left set
l.append(left)
- elif mismatch(dleft[left],right):
+ elif match(dleft[left],right):
# we have it but checksums mismatch: add to center set
c.append(left)
for right in dright.keys():
for p in parents:
if p<0: continue
mright=repo.changectx(p).manifest()
- dleft=mleft.keys()
- dleft.sort()
- dright=mright.keys()
- dright.sort()
- l,c,r=outer_set(mleft,mright,l,c,r)
+ l,c,r=split_dict(mleft,mright,l,c,r)
+ l.sort()
+ c.sort()
+ r.sort()
return l,c,r
def get_author(logmessage,committer,authors):
def export_file_contents(ctx,manifest,files):
count=0
- files.sort()
max=len(files)
for file in files:
- fctx=ctx.filectx(file)
- d=fctx.data()
+ d=ctx.filectx(file).data()
wr('M %s inline %s' % (gitmode(manifest.execf(file)),file))
wr('data %d' % len(d)) # had some trouble with size()
wr(d)
c+=1
return c>1
+def sanitize_name(name,what="branch"):
+ """Sanitize input roughly according to git-check-ref-format(1)"""
+
+ def dot(name):
+ if name[0] == '.': return '_'+name[1:]
+ return name
+
+ n=name
+ p=re.compile('([[ ^:?*]|\.\.)')
+ n=p.sub('_', n)
+ if n[-1] == '/': n=n[:-1]+'_'
+ n='/'.join(map(dot,n.split('/')))
+ p=re.compile('_+')
+ n=p.sub('_', n)
+
+ if n!=name:
+ sys.stderr.write('Warning: sanitized %s [%s] to [%s]\n' % (what,name,n))
+ return n
+
def export_commit(ui,repo,revision,marks,heads,last,max,count,authors,sob):
(revnode,_,user,(time,timezone),files,desc,branch,_)=get_changeset(ui,repo,revision,authors)
parents=repo.changelog.parentrevs(revision)
+ branch=sanitize_name(branch)
+
wr('commit refs/heads/%s' % branch)
wr('mark :%d' % (revision+1))
if sob:
wr(desc)
wr()
+ pidx1, pidx2 = 0, 1
+ if parents[0] < parents[1]:
+ pidx1, pidx2 = 1, 0
+
src=heads.get(branch,'')
link=''
if src!='':
# and kill reference so we won't init it again
wr('from %s' % src)
heads[branch]=''
- sys.stderr.write('Initializing branch [%s] to parent [%s]\n' %
+ sys.stderr.write('%s: Initializing to parent [%s]\n' %
(branch,src))
link=src # avoid making a merge commit for incremental import
elif link=='' and not heads.has_key(branch) and revision>0:
# newly created branch and not the first one: connect to parent
tmp=get_parent_mark(parents[0],marks)
wr('from %s' % tmp)
- sys.stderr.write('Link new branch [%s] to parent [%s]\n' %
+ sys.stderr.write('%s: Link new branch to parent [%s]\n' %
(branch,tmp))
link=tmp # avoid making a merge commit for branch fork
-
- if parents:
- l=last.get(branch,revision)
- for p in parents:
- # 1) as this commit implicitely is the child of the most recent
- # commit of this branch, ignore this parent
- # 2) ignore nonexistent parents
- # 3) merge otherwise
- if p==l or p==revision or p<0:
- continue
- tmp=get_parent_mark(p,marks)
- # if we fork off a branch, don't merge with our parent via 'merge'
- # as we have 'from' already above
- if tmp==link:
- continue
- sys.stderr.write('Merging branch [%s] with parent [%s] from [r%d]\n' %
- (branch,tmp,p))
- wr('merge %s' % tmp)
+ elif last.get(branch,revision) != parents[pidx1] and parents[pidx1] > 0 and revision > 0:
+ pm=get_parent_mark(parents[pidx1],marks)
+ sys.stderr.write('%s: Placing commit [r%d] in branch [%s] on top of [r%d]\n' %
+ (branch,revision,branch,parents[pidx1]));
+ wr('from %s' % pm)
+
+ if parents[pidx2] > 0:
+ pm=get_parent_mark(parents[pidx2],marks)
+ sys.stderr.write('%s: Merging with parent [%s] from [r%d]\n' %
+ (branch,pm,parents[pidx2]))
+ wr('merge %s' % pm)
last[branch]=revision
heads[branch]=''
if revision==0:
# first revision: feed in full manifest
added=man.keys()
+ added.sort()
type='full'
elif is_merge(parents):
# later merge revision: feed in changed manifest
added,changed,removed=f[1],f[0],f[2]
type='simple delta'
- sys.stderr.write('Exporting %s revision %d/%d with %d/%d/%d added/changed/removed files\n' %
- (type,revision+1,max,len(added),len(changed),len(removed)))
+ sys.stderr.write('%s: Exporting %s revision %d/%d with %d/%d/%d added/changed/removed files\n' %
+ (branch,type,revision+1,max,len(added),len(changed),len(removed)))
map(lambda r: wr('D %s' % r),removed)
- export_file_contents(ctx,man,added+changed)
+ export_file_contents(ctx,man,added)
+ export_file_contents(ctx,man,changed)
wr()
return checkpoint(count)
def export_tags(ui,repo,marks_cache,start,end,count,authors):
l=repo.tagslist()
for tag,node in l:
+ tag=sanitize_name(tag,"tag")
# ignore latest revision
if tag=='tip': continue
rev=repo.changelog.rev(node)
return cache
def verify_heads(ui,repo,cache,force):
- def getsha1(branch):
- try:
- f=open(os.getenv('GIT_DIR','/dev/null')+'/refs/heads/'+branch)
- sha1=f.readlines()[0].split('\n')[0]
- f.close()
- return sha1
- except IOError:
- return None
-
branches=repo.branchtags()
l=[(-repo.changelog.rev(n), n, t) for t, n in branches.items()]
l.sort()
# get list of hg's branches to verify, don't take all git has
for _,_,b in l:
b=get_branch(b)
- sha1=getsha1(b)
+ sha1=get_git_sha1(b)
c=cache.get(b)
if sha1!=None and c!=None:
sys.stderr.write('Verifying branch [%s]\n' % b)
return True
+def mangle_mark(mark):
+ return str(int(mark)-1)
+
def hg2git(repourl,m,marksfile,headsfile,tipfile,authors={},sob=False,force=False):
_max=int(m)
- marks_cache=load_cache(marksfile)
+ marks_cache=load_cache(marksfile,mangle_mark)
heads_cache=load_cache(headsfile)
state_cache=load_cache(tipfile)
min=int(state_cache.get('tip',0))
max=_max
- if _max<0:
+ if _max<0 or max>tip:
max=tip
c=0
if options.max!=None: m=options.max
if options.marksfile==None: bail(parser,'--marks')
- if options.marksfile==None: bail(parser,'--heads')
- if options.marksfile==None: bail(parser,'--status')
- if options.marksfile==None: bail(parser,'--repo')
+ if options.headsfile==None: bail(parser,'--heads')
+ if options.statusfile==None: bail(parser,'--status')
+ if options.repourl==None: bail(parser,'--repo')
a={}
if options.authorfile!=None: