hg-fast-export: support new --hgtags option
[python/fast-export.git] / hg2git.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2007, 2008 Rocco Rutte <pdmef@gmx.net> and others.
4 # License: MIT <http://www.opensource.org/licenses/mit-license.php>
5
6 from mercurial import hg,util,ui,templatefilters
7 import re
8 import os
9 import sys
10
11 # default git branch name
12 cfg_master='master'
13 # default origin name
14 origin_name=''
15 # silly regex to see if user field has email address
16 user_re=re.compile('([^<]+) (<[^>]*>)$')
17 # silly regex to clean out user names
18 user_clean_re=re.compile('^["]([^"]+)["]$')
19
20 def set_default_branch(name):
21   global cfg_master
22   cfg_master = name
23
24 def set_origin_name(name):
25   global origin_name
26   origin_name = name
27
28 def setup_repo(url):
29   try:
30     myui=ui.ui(interactive=False)
31   except TypeError:
32     myui=ui.ui()
33     myui.setconfig('ui', 'interactive', 'off')
34   return myui,hg.repository(myui,url)
35
36 def fixup_user(user,authors):
37   user=user.strip("\"")
38   if authors!=None:
39     # if we have an authors table, try to get mapping
40     # by defaulting to the current value of 'user'
41     user=authors.get(user,user)
42   name,mail,m='','',user_re.match(user)
43   if m==None:
44     # if we don't have 'Name <mail>' syntax, extract name
45     # and mail from hg helpers. this seems to work pretty well.
46     # if email doesn't contain @, replace it with devnull@localhost
47     name=templatefilters.person(user)
48     mail='<%s>' % util.email(user)
49     if '@' not in mail:
50       mail = '<devnull@localhost>'
51   else:
52     # if we have 'Name <mail>' syntax, everything is fine :)
53     name,mail=m.group(1),m.group(2)
54
55   # remove any silly quoting from username
56   m2=user_clean_re.match(name)
57   if m2!=None:
58     name=m2.group(1)
59   return '%s %s' % (name,mail)
60
61 def get_branch(name):
62   # 'HEAD' is the result of a bug in mutt's cvs->hg conversion,
63   # other CVS imports may need it, too
64   if name=='HEAD' or name=='default' or name=='':
65     name=cfg_master
66   if origin_name:
67     return origin_name + '/' + name
68   return name
69
70 def get_changeset(ui,repo,revision,authors={}):
71   node=repo.lookup(revision)
72   (manifest,user,(time,timezone),files,desc,extra)=repo.changelog.read(node)
73   tz="%+03d%02d" % (-timezone / 3600, ((-timezone % 3600) / 60))
74   branch=get_branch(extra.get('branch','master'))
75   return (node,manifest,fixup_user(user,authors),(time,tz),files,desc,branch,extra)
76
77 def mangle_key(key):
78   return key
79
80 def load_cache(filename,get_key=mangle_key):
81   cache={}
82   if not os.path.exists(filename):
83     return cache
84   f=open(filename,'r')
85   l=0
86   for line in f.readlines():
87     l+=1
88     fields=line.split(' ')
89     if fields==None or not len(fields)==2 or fields[0][0]!=':':
90       sys.stderr.write('Invalid file format in [%s], line %d\n' % (filename,l))
91       continue
92     # put key:value in cache, key without ^:
93     cache[get_key(fields[0][1:])]=fields[1].split('\n')[0]
94   f.close()
95   return cache
96
97 def save_cache(filename,cache):
98   f=open(filename,'w+')
99   map(lambda x: f.write(':%s %s\n' % (str(x),str(cache.get(x)))),cache.keys())
100   f.close()
101
102 def get_git_sha1(name,type='heads'):
103   try:
104     # use git-rev-parse to support packed refs
105     cmd="git rev-parse --verify refs/%s/%s 2>%s" % (type,name,os.devnull)
106     p=os.popen(cmd)
107     l=p.readline()
108     p.close()
109     if l == None or len(l) == 0:
110       return None
111     return l[0:40]
112   except IOError:
113     return None