3 # Copyright (c) 2007, 2008 Rocco Rutte <pdmef@gmx.net> and others.
4 # License: MIT <http://www.opensource.org/licenses/mit-license.php>
6 from mercurial
import node
7 from mercurial
.scmutil
import revsymbol
8 from hg2git
import setup_repo
,fixup_user
,get_branch
,get_changeset
9 from hg2git
import load_cache
,save_cache
,get_git_sha1
,set_default_branch
,set_origin_name
10 from optparse
import OptionParser
14 from binascii
import hexlify
16 PY2
= sys
.version_info
.major
== 2
20 if PY2
and sys
.platform
== "win32":
21 # On Windows, sys.stdout is initially opened in text mode, which means that
22 # when a LF (\n) character is written to sys.stdout, it will be converted
23 # into CRLF (\r\n). That makes git blow up, so use this platform-specific
24 # code to change the mode of sys.stdout to binary.
26 msvcrt
.setmode(sys
.stdout
.fileno(), os
.O_BINARY
)
28 # silly regex to catch Signed-off-by lines in log message
29 sob_re
=re
.compile(b
'^Signed-[Oo]ff-[Bb]y: (.+)$')
30 # insert 'checkpoint' command after this many commits or none at all if 0
31 cfg_checkpoint_count
=0
32 # write some progress message every this many file contents written
33 cfg_export_boundary
=1000
36 submodule_mappings
=None
38 # True if fast export should automatically try to sanitize
39 # author/branch/tag names.
42 stdout_buffer
= sys
.stdout
if PY2
else sys
.stdout
.buffer
43 stderr_buffer
= sys
.stderr
if PY2
else sys
.stderr
.buffer
46 return b
'l' in flags
and b
'120000' or b
'x' in flags
and b
'100755' or b
'100644'
48 def wr_no_nl(msg
=b
''):
49 assert isinstance(msg
, bytes
)
51 stdout_buffer
.write(msg
)
55 stdout_buffer
.write(b
'\n')
56 #map(lambda x: sys.stderr.write('\t[%s]\n' % x),msg.split('\n'))
58 def checkpoint(count
):
60 if cfg_checkpoint_count
>0 and count
%cfg_checkpoint
_count
==0:
61 stderr_buffer
.write(b
"Checkpoint after %d commits\n" % count
)
66 def revnum_to_revref(rev
, old_marks
):
67 """Convert an hg revnum to a git-fast-import rev reference (an SHA1
69 return old_marks
.get(rev
) or b
':%d' % (rev
+1)
71 def file_mismatch(f1
,f2
):
72 """See if two revisions of a file are not equal."""
73 return node
.hex(f1
)!=node
.hex(f2
)
75 def split_dict(dleft
,dright
,l
=[],c
=[],r
=[],match
=file_mismatch
):
76 """Loop over our repository and find all changed and missing files."""
77 for left
in dleft
.keys():
78 right
=dright
.get(left
,None)
80 # we have the file but our parent hasn't: add to left set
82 elif match(dleft
[left
],right
) or gitmode(dleft
.flags(left
))!=gitmode(dright
.flags(left
)):
83 # we have it but checksums mismatch: add to center set
85 for right
in dright
.keys():
86 left
=dleft
.get(right
,None)
88 # if parent has file but we don't: add to right set
90 # change is already handled when comparing child against parent
93 def get_filechanges(repo
,revision
,parents
,mleft
):
94 """Given some repository and revision, find all changed/deleted files."""
98 mright
=revsymbol(repo
,b
"%d" %p
).manifest()
99 l
,c
,r
=split_dict(mleft
,mright
,l
,c
,r
)
105 def get_author(logmessage
,committer
,authors
):
106 """As git distincts between author and committer of a patch, try to
107 extract author by detecting Signed-off-by lines.
109 This walks from the end of the log message towards the top skipping
110 empty lines. Upon the first non-empty line, it walks all Signed-off-by
111 lines upwards to find the first one. For that (if found), it extracts
112 authorship information the usual way (authors table, cleaning, etc.)
114 If no Signed-off-by line is found, this defaults to the committer.
116 This may sound stupid (and it somehow is), but in log messages we
117 accidentially may have lines in the middle starting with
118 "Signed-off-by: foo" and thus matching our detection regex. Prevent
121 loglines
=logmessage
.split(b
'\n')
123 # from tail walk to top skipping empty lines
126 if len(loglines
[i
].strip())==0: continue
129 # walk further upwards to find first sob line, store in 'first'
132 m
=sob_re
.match(loglines
[i
])
136 # if the last non-empty line matches our Signed-Off-by regex: extract username
138 r
=fixup_user(first
.group(1),authors
)
142 def remove_gitmodules(ctx
):
143 """Removes all submodules of ctx parents"""
144 # Removing all submoduies coming from all parents is safe, as the submodules
145 # of the current commit will be re-added below. A possible optimization would
146 # be to only remove the submodules of the first parent.
147 for parent_ctx
in ctx
.parents():
148 for submodule
in parent_ctx
.substate
.keys():
149 wr(b
'D %s' % submodule
)
152 def refresh_git_submodule(name
,subrepo_info
):
153 wr(b
'M 160000 %s %s' % (subrepo_info
[1],name
))
155 b
"Adding/updating submodule %s, revision %s\n" % (name
, subrepo_info
[1])
157 return b
'[submodule "%s"]\n\tpath = %s\n\turl = %s\n' % (name
, name
, subrepo_info
[0])
159 def refresh_hg_submodule(name
,subrepo_info
):
160 gitRepoLocation
=submodule_mappings
[name
] + b
"/.git"
162 # Populate the cache to map mercurial revision to git revision
163 if not name
in subrepo_cache
:
164 subrepo_cache
[name
]=(load_cache(gitRepoLocation
+b
"/hg2git-mapping"),
165 load_cache(gitRepoLocation
+b
"/hg2git-marks",
168 (mapping_cache
,marks_cache
)=subrepo_cache
[name
]
169 subrepo_hash
=subrepo_info
[1]
170 if subrepo_hash
in mapping_cache
:
171 revnum
=mapping_cache
[subrepo_hash
]
172 gitSha
=marks_cache
[int(revnum
)]
173 wr(b
'M 160000 %s %s' % (gitSha
,name
))
175 b
"Adding/updating submodule %s, revision %s->%s\n"
176 % (name
, subrepo_hash
, gitSha
)
178 return b
'[submodule "%s"]\n\tpath = %s\n\turl = %s\n' % (name
,name
,
179 submodule_mappings
[name
])
182 b
"Warning: Could not find hg revision %s for %s in git %s\n"
183 % (subrepo_hash
, name
, gitRepoLocation
,)
187 def refresh_gitmodules(ctx
):
188 """Updates list of ctx submodules according to .hgsubstate file"""
189 remove_gitmodules(ctx
)
191 # Create the .gitmodules file and all submodules
192 for name
,subrepo_info
in ctx
.substate
.items():
193 if subrepo_info
[2]==b
'git':
194 gitmodules
+=refresh_git_submodule(name
,subrepo_info
)
195 elif submodule_mappings
and name
in submodule_mappings
:
196 gitmodules
+=refresh_hg_submodule(name
,subrepo_info
)
199 wr(b
'M 100644 inline .gitmodules')
200 wr(b
'data %d' % (len(gitmodules
)+1))
203 def export_file_contents(ctx
,manifest
,files
,hgtags
,encoding
='',plugins
={}):
206 is_submodules_refreshed
=False
208 if not is_submodules_refreshed
and (file==b
'.hgsub' or file==b
'.hgsubstate'):
209 is_submodules_refreshed
=True
210 refresh_gitmodules(ctx
)
211 # Skip .hgtags files. They only get us in trouble.
212 if not hgtags
and file == b
".hgtags":
213 stderr_buffer
.write(b
'Skip %s\n' % file)
216 filename
=file.decode(encoding
).encode('utf8')
219 if b
'.git' in filename
.split(b
'/'): # Even on Windows, the path separator is / here.
221 b
'Ignoring file %s which cannot be tracked by git\n' % filename
224 file_ctx
=ctx
.filectx(file)
227 if plugins
and plugins
['file_data_filters']:
228 file_data
= {'filename':filename
,'file_ctx':file_ctx
,'data':d
}
229 for filter in plugins
['file_data_filters']:
232 filename
=file_data
['filename']
233 file_ctx
=file_data
['file_ctx']
235 wr(b
'M %s inline %s' % (gitmode(manifest
.flags(file)),
236 strip_leading_slash(filename
)))
237 wr(b
'data %d' % len(d
)) # had some trouble with size()
240 if count
%cfg_export
_boundary
==0:
241 stderr_buffer
.write(b
'Exported %d/%d files\n' % (count
,max))
242 if max>cfg_export_boundary
:
243 stderr_buffer
.write(b
'Exported %d/%d files\n' % (count
,max))
245 def sanitize_name(name
,what
="branch", mapping
={}):
246 """Sanitize input roughly according to git-check-ref-format(1)"""
248 # NOTE: Do not update this transform to work around
249 # incompatibilities on your platform. If you change it and it starts
250 # modifying names which previously were not touched it will break
251 # preexisting setups which are doing incremental imports.
253 # Fast-export tries to not inflict arbitrary naming policy on the
254 # user, instead it aims to provide mechanisms allowing the user to
255 # apply their own policy. Therefore do not add a transform which can
256 # already be implemented with the -B and -T options to mangle branch
257 # and tag names. If you have a source repository where this is too
258 # much work to do manually, write a tool that does it for you.
262 if not name
: return name
263 if name
[0:1] == b
'.': return b
'_'+name
[1:]
266 if not auto_sanitize
:
267 return mapping
.get(name
,name
)
268 n
=mapping
.get(name
,name
)
269 p
=re
.compile(b
'([[ ~^:?\\\\*]|\.\.)')
271 if n
[-1:] in (b
'/', b
'.'): n
=n
[:-1]+b
'_'
272 n
=b
'/'.join([dot(s
) for s
in n
.split(b
'/')])
278 b
'Warning: sanitized %s [%s] to [%s]\n' % (what
.encode(), name
, n
)
282 def strip_leading_slash(filename
):
283 if filename
[0:1] == b
'/':
287 def export_commit(ui
,repo
,revision
,old_marks
,max,count
,authors
,
288 branchesmap
,sob
,brmap
,hgtags
,encoding
='',fn_encoding
='',
290 def get_branchname(name
):
293 n
=sanitize_name(name
, "branch", branchesmap
)
297 (revnode
,_
,user
,(time
,timezone
),files
,desc
,branch
,_
)=get_changeset(ui
,repo
,revision
,authors
,encoding
)
298 if repo
[revnode
].hidden():
301 branch
=get_branchname(branch
)
303 parents
= [p
for p
in repo
.changelog
.parentrevs(revision
) if p
>= 0]
304 author
= get_author(desc
,user
,authors
)
306 if plugins
and plugins
['commit_message_filters']:
307 commit_data
= {'branch': branch
, 'parents': parents
, 'author': author
, 'desc': desc
}
308 for filter in plugins
['commit_message_filters']:
310 branch
= commit_data
['branch']
311 parents
= commit_data
['parents']
312 author
= commit_data
['author']
313 desc
= commit_data
['desc']
315 if len(parents
)==0 and revision
!= 0:
316 wr(b
'reset refs/heads/%s' % branch
)
318 wr(b
'commit refs/heads/%s' % branch
)
319 wr(b
'mark :%d' % (revision
+1))
321 wr(b
'author %s %d %s' % (author
,time
,timezone
))
322 wr(b
'committer %s %d %s' % (user
,time
,timezone
))
323 wr(b
'data %d' % (len(desc
)+1)) # wtf?
327 ctx
=revsymbol(repo
, b
"%d" % revision
)
329 added
,changed
,removed
,type=[],[],[],''
331 if len(parents
) == 0:
332 # first revision: feed in full manifest
337 wr(b
'from %s' % revnum_to_revref(parents
[0], old_marks
))
338 if len(parents
) == 1:
339 # later non-merge revision: feed in changed manifest
340 # if we have exactly one parent, just take the changes from the
341 # manifest without expensively comparing checksums
342 f
=repo
.status(parents
[0],revnode
)
343 added
,changed
,removed
=f
.added
,f
.modified
,f
.removed
345 else: # a merge with two parents
346 wr(b
'merge %s' % revnum_to_revref(parents
[1], old_marks
))
347 # later merge revision: feed in changed manifest
348 # for many files comparing checksums is expensive so only do it for
349 # merges where we really need it due to hg's revlog logic
350 added
,changed
,removed
=get_filechanges(repo
,revision
,parents
,man
)
351 type='thorough delta'
354 b
'%s: Exporting %s revision %d/%d with %d/%d/%d added/changed/removed files\n'
355 % (branch
, type.encode(), revision
+ 1, max, len(added
), len(changed
), len(removed
))
358 for filename
in removed
:
360 filename
=filename
.decode(fn_encoding
).encode('utf8')
361 filename
=strip_leading_slash(filename
)
362 if filename
==b
'.hgsub':
363 remove_gitmodules(ctx
)
364 wr(b
'D %s' % filename
)
366 export_file_contents(ctx
,man
,added
,hgtags
,fn_encoding
,plugins
)
367 export_file_contents(ctx
,man
,changed
,hgtags
,fn_encoding
,plugins
)
370 return checkpoint(count
)
372 def export_note(ui
,repo
,revision
,count
,authors
,encoding
,is_first
):
373 (revnode
,_
,user
,(time
,timezone
),_
,_
,_
,_
)=get_changeset(ui
,repo
,revision
,authors
,encoding
)
374 if repo
[revnode
].hidden():
377 parents
= [p
for p
in repo
.changelog
.parentrevs(revision
) if p
>= 0]
379 wr(b
'commit refs/notes/hg')
380 wr(b
'committer %s %d %s' % (user
,time
,timezone
))
383 wr(b
'from refs/notes/hg^0')
384 wr(b
'N inline :%d' % (revision
+1))
385 hg_hash
=revsymbol(repo
,b
"%d" % revision
).hex()
386 wr(b
'data %d' % (len(hg_hash
)))
389 return checkpoint(count
)
391 def export_tags(ui
,repo
,old_marks
,mapping_cache
,count
,authors
,tagsmap
):
394 # Remap the branch name
395 tag
=sanitize_name(tag
,"tag",tagsmap
)
396 # ignore latest revision
397 if tag
==b
'tip': continue
398 # ignore tags to nodes that are missing (ie, 'in the future')
399 if hexlify(node
) not in mapping_cache
:
400 stderr_buffer
.write(b
'Tag %s refers to unseen node %s\n' % (tag
, hexlify(node
)))
403 rev
=int(mapping_cache
[hexlify(node
)])
405 ref
=revnum_to_revref(rev
, old_marks
)
408 b
'Failed to find reference for creating tag %s at r%d\n' % (tag
, rev
)
411 stderr_buffer
.write(b
'Exporting tag [%s] at [hg r%d] [git %s]\n' % (tag
, rev
, ref
))
412 wr(b
'reset refs/tags/%s' % tag
)
415 count
=checkpoint(count
)
418 def load_mapping(name
, filename
, mapping_is_raw
):
419 raw_regexp
=re
.compile(b
'^([^=]+)[ ]*=[ ]*(.+)$')
420 string_regexp
=b
'"(((\\.)|(\\")|[^"])*)"'
421 quoted_regexp
=re
.compile(b
'^'+string_regexp
+b
'[ ]*=[ ]*'+string_regexp
+b
'$')
423 def parse_raw_line(line
):
424 m
=raw_regexp
.match(line
)
427 return (m
.group(1).strip(), m
.group(2).strip())
429 def process_unicode_escape_sequences(s
):
430 # Replace unicode escape sequences in the otherwise UTF8-encoded bytestring s with
431 # the UTF8-encoded characters they represent. We need to do an additional
432 # .decode('utf8').encode('unicode-escape') to convert any non-ascii characters into
433 # their escape sequences so that the subsequent .decode('unicode-escape') succeeds:
434 return s
.decode('utf8').encode('unicode-escape').decode('unicode-escape').encode('utf8')
436 def parse_quoted_line(line
):
437 m
=quoted_regexp
.match(line
)
441 return (process_unicode_escape_sequences(m
.group(1)),
442 process_unicode_escape_sequences(m
.group(5)))
445 if not os
.path
.exists(filename
):
446 sys
.stderr
.write('Could not open mapping file [%s]\n' % (filename
))
448 f
=open(filename
,'rb')
451 for line
in f
.readlines():
454 if l
==1 and line
[0:1]==b
'#' and line
==b
'# quoted-escaped-strings':
456 elif line
==b
'' or line
[0:1]==b
'#':
458 m
=parse_raw_line(line
) if mapping_is_raw
else parse_quoted_line(line
)
460 sys
.stderr
.write('Invalid file format in [%s], line %d\n' % (filename
,l
))
462 # put key:value in cache, key without ^:
466 sys
.stderr
.write('Loaded %d %s\n' % (a
, name
))
469 def branchtip(repo
, heads
):
470 '''return the tipmost branch head in heads'''
472 for h
in reversed(heads
):
473 if 'close' not in repo
.changelog
.read(h
)[5]:
478 def verify_heads(ui
,repo
,cache
,force
,branchesmap
):
480 for bn
, heads
in repo
.branchmap().iteritems():
481 branches
[bn
] = branchtip(repo
, heads
)
482 l
=[(-repo
.changelog
.rev(n
), n
, t
) for t
, n
in branches
.items()]
485 # get list of hg's branches to verify, don't take all git has
488 sanitized_name
=sanitize_name(b
,"branch",branchesmap
)
489 sha1
=get_git_sha1(sanitized_name
)
490 c
=cache
.get(sanitized_name
)
493 b
'Error: Branch [%s] modified outside hg-fast-export:'
494 b
'\n%s (repo) != %s (cache)\n' % (b
, b
'<None>' if sha1
is None else sha1
, c
)
496 if not force
: return False
498 # verify that branch has exactly one head
500 for h
in repo
.filtered(b
'visible').heads():
501 (_
,_
,_
,_
,_
,_
,branch
,_
)=get_changeset(ui
,repo
,h
)
502 if t
.get(branch
,False):
504 b
'Error: repository has at least one unnamed head: hg r%d\n'
505 % repo
.changelog
.rev(h
)
507 if not force
: return False
512 def hg2git(repourl
,m
,marksfile
,mappingfile
,headsfile
,tipfile
,
513 authors
={},branchesmap
={},tagsmap
={},
514 sob
=False,force
=False,hgtags
=False,notes
=False,encoding
='',fn_encoding
='',
516 def check_cache(filename
, contents
):
517 if len(contents
) == 0:
518 sys
.stderr
.write('Warning: %s does not contain any data, this will probably make an incremental import fail\n' % filename
)
522 old_marks
=load_cache(marksfile
,lambda s
: int(s
)-1)
523 mapping_cache
=load_cache(mappingfile
)
524 heads_cache
=load_cache(headsfile
)
525 state_cache
=load_cache(tipfile
)
527 if len(state_cache
) != 0:
528 for (name
, data
) in [(marksfile
, old_marks
),
529 (mappingfile
, mapping_cache
),
530 (headsfile
, state_cache
)]:
531 check_cache(name
, data
)
533 ui
,repo
=setup_repo(repourl
)
535 if not verify_heads(ui
,repo
,heads_cache
,force
,branchesmap
):
539 tip
=repo
.changelog
.count()
540 except AttributeError:
543 min=int(state_cache
.get('tip',0))
545 if _max
<0 or max>tip
:
548 for rev
in range(0,max):
549 (revnode
,_
,_
,_
,_
,_
,_
,_
)=get_changeset(ui
,repo
,rev
,authors
)
550 if repo
[revnode
].hidden():
552 mapping_cache
[hexlify(revnode
)] = b
"%d" % rev
554 if submodule_mappings
:
555 # Make sure that all mercurial submodules are registered in the submodule-mappings file
556 for rev
in range(0,max):
557 ctx
=revsymbol(repo
,b
"%d" % rev
)
561 for key
in ctx
.substate
:
562 if ctx
.substate
[key
][2]=='hg' and key
not in submodule_mappings
:
563 sys
.stderr
.write("Error: %s not found in submodule-mappings\n" % (key
))
568 for rev
in range(min,max):
569 c
=export_commit(ui
,repo
,rev
,old_marks
,max,c
,authors
,branchesmap
,
570 sob
,brmap
,hgtags
,encoding
,fn_encoding
,
573 for rev
in range(min,max):
574 c
=export_note(ui
,repo
,rev
,c
,authors
, encoding
, rev
== min and min != 0)
576 state_cache
['tip']=max
577 state_cache
['repo']=repourl
578 save_cache(tipfile
,state_cache
)
579 save_cache(mappingfile
,mapping_cache
)
581 c
=export_tags(ui
,repo
,old_marks
,mapping_cache
,c
,authors
,tagsmap
)
583 sys
.stderr
.write('Issued %d commands\n' % c
)
587 if __name__
=='__main__':
588 def bail(parser
,opt
):
589 sys
.stderr
.write('Error: No %s option given\n' % opt
)
593 parser
=OptionParser()
595 parser
.add_option("-n", "--no-auto-sanitize",action
="store_false",
596 dest
="auto_sanitize",default
=True,
597 help="Do not perform built-in (broken in many cases) sanitizing of names")
598 parser
.add_option("-m","--max",type="int",dest
="max",
599 help="Maximum hg revision to import")
600 parser
.add_option("--mapping",dest
="mappingfile",
601 help="File to read last run's hg-to-git SHA1 mapping")
602 parser
.add_option("--marks",dest
="marksfile",
603 help="File to read git-fast-import's marks from")
604 parser
.add_option("--heads",dest
="headsfile",
605 help="File to read last run's git heads from")
606 parser
.add_option("--status",dest
="statusfile",
607 help="File to read status from")
608 parser
.add_option("-r","--repo",dest
="repourl",
609 help="URL of repo to import")
610 parser
.add_option("-s",action
="store_true",dest
="sob",
611 default
=False,help="Enable parsing Signed-off-by lines")
612 parser
.add_option("--hgtags",action
="store_true",dest
="hgtags",
613 default
=False,help="Enable exporting .hgtags files")
614 parser
.add_option("-A","--authors",dest
="authorfile",
615 help="Read authormap from AUTHORFILE")
616 parser
.add_option("-B","--branches",dest
="branchesfile",
617 help="Read branch map from BRANCHESFILE")
618 parser
.add_option("-T","--tags",dest
="tagsfile",
619 help="Read tags map from TAGSFILE")
620 parser
.add_option("-f","--force",action
="store_true",dest
="force",
621 default
=False,help="Ignore validation errors by force")
622 parser
.add_option("-M","--default-branch",dest
="default_branch",
623 help="Set the default branch")
624 parser
.add_option("-o","--origin",dest
="origin_name",
625 help="use <name> as namespace to track upstream")
626 parser
.add_option("--hg-hash",action
="store_true",dest
="notes",
627 default
=False,help="Annotate commits with the hg hash as git notes in the hg namespace")
628 parser
.add_option("-e",dest
="encoding",
629 help="Assume commit and author strings retrieved from Mercurial are encoded in <encoding>")
630 parser
.add_option("--fe",dest
="fn_encoding",
631 help="Assume file names from Mercurial are encoded in <filename_encoding>")
632 parser
.add_option("--mappings-are-raw",dest
="raw_mappings", default
=False,
633 help="Assume mappings are raw <key>=<value> lines")
634 parser
.add_option("--filter-contents",dest
="filter_contents",
635 help="Pipe contents of each exported file through FILTER_CONTENTS <file-path> <hg-hash> <is-binary>")
636 parser
.add_option("--plugin-path", type="string", dest
="pluginpath",
637 help="Additional search path for plugins ")
638 parser
.add_option("--plugin", action
="append", type="string", dest
="plugins",
639 help="Add a plugin with the given init string <name=init>")
640 parser
.add_option("--subrepo-map", type="string", dest
="subrepo_map",
641 help="Provide a mapping file between the subrepository name and the submodule name")
643 (options
,args
)=parser
.parse_args()
646 auto_sanitize
= options
.auto_sanitize
647 if options
.max!=None: m
=options
.max
649 if options
.marksfile
==None: bail(parser
,'--marks')
650 if options
.mappingfile
==None: bail(parser
,'--mapping')
651 if options
.headsfile
==None: bail(parser
,'--heads')
652 if options
.statusfile
==None: bail(parser
,'--status')
653 if options
.repourl
==None: bail(parser
,'--repo')
655 if options
.subrepo_map
:
656 if not os
.path
.exists(options
.subrepo_map
):
657 sys
.stderr
.write('Subrepo mapping file not found %s\n'
658 % options
.subrepo_map
)
660 submodule_mappings
=load_mapping('subrepo mappings',
661 options
.subrepo_map
,False)
664 if options
.authorfile
!=None:
665 a
=load_mapping('authors', options
.authorfile
, options
.raw_mappings
)
668 if options
.branchesfile
!=None:
669 b
=load_mapping('branches', options
.branchesfile
, options
.raw_mappings
)
672 if options
.tagsfile
!=None:
673 t
=load_mapping('tags', options
.tagsfile
, options
.raw_mappings
)
675 if options
.default_branch
!=None:
676 set_default_branch(options
.default_branch
)
678 if options
.origin_name
!=None:
679 set_origin_name(options
.origin_name
)
682 if options
.encoding
!=None:
683 encoding
=options
.encoding
686 if options
.fn_encoding
!=None:
687 fn_encoding
=options
.fn_encoding
690 if options
.plugins
!=None:
691 plugins
+=options
.plugins
693 if options
.filter_contents
!=None:
694 plugins
+=['shell_filter_file_contents='+options
.filter_contents
]
697 plugins_dict
['commit_message_filters']=[]
698 plugins_dict
['file_data_filters']=[]
700 if plugins
and options
.pluginpath
:
701 sys
.stderr
.write('Using additional plugin path: ' + options
.pluginpath
+ '\n')
703 for plugin
in plugins
:
704 split
= plugin
.split('=')
705 name
, opts
= split
[0], '='.join(split
[1:])
706 i
= pluginloader
.get_plugin(name
,options
.pluginpath
)
707 sys
.stderr
.write('Loaded plugin ' + i
['name'] + ' from path: ' + i
['path'] +' with opts: ' + opts
+ '\n')
708 plugin
= pluginloader
.load_plugin(i
).build_filter(opts
)
709 if hasattr(plugin
,'file_data_filter') and callable(plugin
.file_data_filter
):
710 plugins_dict
['file_data_filters'].append(plugin
.file_data_filter
)
711 if hasattr(plugin
, 'commit_message_filter') and callable(plugin
.commit_message_filter
):
712 plugins_dict
['commit_message_filters'].append(plugin
.commit_message_filter
)
714 sys
.exit(hg2git(options
.repourl
,m
,options
.marksfile
,options
.mappingfile
,
715 options
.headsfile
, options
.statusfile
,
716 authors
=a
,branchesmap
=b
,tagsmap
=t
,
717 sob
=options
.sob
,force
=options
.force
,hgtags
=options
.hgtags
,
718 notes
=options
.notes
,encoding
=encoding
,fn_encoding
=fn_encoding
,
719 plugins
=plugins_dict
))