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 parse_quoted_line(line
):
430 m
=quoted_regexp
.match(line
)
433 return (m
.group(1).decode('unicode_escape').encode('utf8'),
434 m
.group(5).decode('unicode_escape').encode('utf8'))
437 if not os
.path
.exists(filename
):
438 sys
.stderr
.write('Could not open mapping file [%s]\n' % (filename
))
440 f
=open(filename
,'rb')
443 for line
in f
.readlines():
446 if l
==1 and line
[0:1]==b
'#' and line
==b
'# quoted-escaped-strings':
448 elif line
==b
'' or line
[0:1]==b
'#':
450 m
=parse_raw_line(line
) if mapping_is_raw
else parse_quoted_line(line
)
452 sys
.stderr
.write('Invalid file format in [%s], line %d\n' % (filename
,l
))
454 # put key:value in cache, key without ^:
458 sys
.stderr
.write('Loaded %d %s\n' % (a
, name
))
461 def branchtip(repo
, heads
):
462 '''return the tipmost branch head in heads'''
464 for h
in reversed(heads
):
465 if 'close' not in repo
.changelog
.read(h
)[5]:
470 def verify_heads(ui
,repo
,cache
,force
,branchesmap
):
472 for bn
, heads
in repo
.branchmap().items():
473 branches
[bn
] = branchtip(repo
, heads
)
474 l
=[(-repo
.changelog
.rev(n
), n
, t
) for t
, n
in branches
.items()]
477 # get list of hg's branches to verify, don't take all git has
480 sanitized_name
=sanitize_name(b
,"branch",branchesmap
)
481 sha1
=get_git_sha1(sanitized_name
)
482 c
=cache
.get(sanitized_name
)
485 b
'Error: Branch [%s] modified outside hg-fast-export:'
486 b
'\n%s (repo) != %s (cache)\n' % (b
, b
'<None>' if sha1
is None else sha1
, c
)
488 if not force
: return False
490 # verify that branch has exactly one head
492 for h
in repo
.filtered(b
'visible').heads():
493 (_
,_
,_
,_
,_
,_
,branch
,_
)=get_changeset(ui
,repo
,h
)
494 if t
.get(branch
,False):
496 b
'Error: repository has at least one unnamed head: hg r%d\n'
497 % repo
.changelog
.rev(h
)
499 if not force
: return False
504 def hg2git(repourl
,m
,marksfile
,mappingfile
,headsfile
,tipfile
,
505 authors
={},branchesmap
={},tagsmap
={},
506 sob
=False,force
=False,hgtags
=False,notes
=False,encoding
='',fn_encoding
='',
508 def check_cache(filename
, contents
):
509 if len(contents
) == 0:
510 sys
.stderr
.write('Warning: %s does not contain any data, this will probably make an incremental import fail\n' % filename
)
514 old_marks
=load_cache(marksfile
,lambda s
: int(s
)-1)
515 mapping_cache
=load_cache(mappingfile
)
516 heads_cache
=load_cache(headsfile
)
517 state_cache
=load_cache(tipfile
)
519 if len(state_cache
) != 0:
520 for (name
, data
) in [(marksfile
, old_marks
),
521 (mappingfile
, mapping_cache
),
522 (headsfile
, state_cache
)]:
523 check_cache(name
, data
)
525 ui
,repo
=setup_repo(repourl
)
527 if not verify_heads(ui
,repo
,heads_cache
,force
,branchesmap
):
531 tip
=repo
.changelog
.count()
532 except AttributeError:
535 min=int(state_cache
.get('tip',0))
537 if _max
<0 or max>tip
:
540 for rev
in range(0,max):
541 (revnode
,_
,_
,_
,_
,_
,_
,_
)=get_changeset(ui
,repo
,rev
,authors
)
542 if repo
[revnode
].hidden():
544 mapping_cache
[hexlify(revnode
)] = b
"%d" % rev
546 if submodule_mappings
:
547 # Make sure that all submodules are registered in the submodule-mappings file
548 for rev
in range(0,max):
549 ctx
=revsymbol(repo
,b
"%d" % rev
)
553 for key
in ctx
.substate
:
554 if key
not in submodule_mappings
:
555 sys
.stderr
.write("Error: %s not found in submodule-mappings\n" % (key
))
560 for rev
in range(min,max):
561 c
=export_commit(ui
,repo
,rev
,old_marks
,max,c
,authors
,branchesmap
,
562 sob
,brmap
,hgtags
,encoding
,fn_encoding
,
565 for rev
in range(min,max):
566 c
=export_note(ui
,repo
,rev
,c
,authors
, encoding
, rev
== min and min != 0)
568 state_cache
['tip']=max
569 state_cache
['repo']=repourl
570 save_cache(tipfile
,state_cache
)
571 save_cache(mappingfile
,mapping_cache
)
573 c
=export_tags(ui
,repo
,old_marks
,mapping_cache
,c
,authors
,tagsmap
)
575 sys
.stderr
.write('Issued %d commands\n' % c
)
579 if __name__
=='__main__':
580 def bail(parser
,opt
):
581 sys
.stderr
.write('Error: No %s option given\n' % opt
)
585 parser
=OptionParser()
587 parser
.add_option("-n", "--no-auto-sanitize",action
="store_false",
588 dest
="auto_sanitize",default
=True,
589 help="Do not perform built-in (broken in many cases) sanitizing of names")
590 parser
.add_option("-m","--max",type="int",dest
="max",
591 help="Maximum hg revision to import")
592 parser
.add_option("--mapping",dest
="mappingfile",
593 help="File to read last run's hg-to-git SHA1 mapping")
594 parser
.add_option("--marks",dest
="marksfile",
595 help="File to read git-fast-import's marks from")
596 parser
.add_option("--heads",dest
="headsfile",
597 help="File to read last run's git heads from")
598 parser
.add_option("--status",dest
="statusfile",
599 help="File to read status from")
600 parser
.add_option("-r","--repo",dest
="repourl",
601 help="URL of repo to import")
602 parser
.add_option("-s",action
="store_true",dest
="sob",
603 default
=False,help="Enable parsing Signed-off-by lines")
604 parser
.add_option("--hgtags",action
="store_true",dest
="hgtags",
605 default
=False,help="Enable exporting .hgtags files")
606 parser
.add_option("-A","--authors",dest
="authorfile",
607 help="Read authormap from AUTHORFILE")
608 parser
.add_option("-B","--branches",dest
="branchesfile",
609 help="Read branch map from BRANCHESFILE")
610 parser
.add_option("-T","--tags",dest
="tagsfile",
611 help="Read tags map from TAGSFILE")
612 parser
.add_option("-f","--force",action
="store_true",dest
="force",
613 default
=False,help="Ignore validation errors by force")
614 parser
.add_option("-M","--default-branch",dest
="default_branch",
615 help="Set the default branch")
616 parser
.add_option("-o","--origin",dest
="origin_name",
617 help="use <name> as namespace to track upstream")
618 parser
.add_option("--hg-hash",action
="store_true",dest
="notes",
619 default
=False,help="Annotate commits with the hg hash as git notes in the hg namespace")
620 parser
.add_option("-e",dest
="encoding",
621 help="Assume commit and author strings retrieved from Mercurial are encoded in <encoding>")
622 parser
.add_option("--fe",dest
="fn_encoding",
623 help="Assume file names from Mercurial are encoded in <filename_encoding>")
624 parser
.add_option("--mappings-are-raw",dest
="raw_mappings", default
=False,
625 help="Assume mappings are raw <key>=<value> lines")
626 parser
.add_option("--filter-contents",dest
="filter_contents",
627 help="Pipe contents of each exported file through FILTER_CONTENTS <file-path> <hg-hash> <is-binary>")
628 parser
.add_option("--plugin-path", type="string", dest
="pluginpath",
629 help="Additional search path for plugins ")
630 parser
.add_option("--plugin", action
="append", type="string", dest
="plugins",
631 help="Add a plugin with the given init string <name=init>")
632 parser
.add_option("--subrepo-map", type="string", dest
="subrepo_map",
633 help="Provide a mapping file between the subrepository name and the submodule name")
635 (options
,args
)=parser
.parse_args()
638 auto_sanitize
= options
.auto_sanitize
639 if options
.max!=None: m
=options
.max
641 if options
.marksfile
==None: bail(parser
,'--marks')
642 if options
.mappingfile
==None: bail(parser
,'--mapping')
643 if options
.headsfile
==None: bail(parser
,'--heads')
644 if options
.statusfile
==None: bail(parser
,'--status')
645 if options
.repourl
==None: bail(parser
,'--repo')
647 if options
.subrepo_map
:
648 if not os
.path
.exists(options
.subrepo_map
):
649 sys
.stderr
.write('Subrepo mapping file not found %s\n'
650 % options
.subrepo_map
)
652 submodule_mappings
=load_mapping('subrepo mappings',
653 options
.subrepo_map
,False)
656 if options
.authorfile
!=None:
657 a
=load_mapping('authors', options
.authorfile
, options
.raw_mappings
)
660 if options
.branchesfile
!=None:
661 b
=load_mapping('branches', options
.branchesfile
, options
.raw_mappings
)
664 if options
.tagsfile
!=None:
665 t
=load_mapping('tags', options
.tagsfile
, options
.raw_mappings
)
667 if options
.default_branch
!=None:
668 set_default_branch(options
.default_branch
)
670 if options
.origin_name
!=None:
671 set_origin_name(options
.origin_name
)
674 if options
.encoding
!=None:
675 encoding
=options
.encoding
678 if options
.fn_encoding
!=None:
679 fn_encoding
=options
.fn_encoding
682 if options
.plugins
!=None:
683 plugins
+=options
.plugins
685 if options
.filter_contents
!=None:
686 plugins
+=['shell_filter_file_contents='+options
.filter_contents
]
689 plugins_dict
['commit_message_filters']=[]
690 plugins_dict
['file_data_filters']=[]
692 if plugins
and options
.pluginpath
:
693 sys
.stderr
.write('Using additional plugin path: ' + options
.pluginpath
+ '\n')
695 for plugin
in plugins
:
696 split
= plugin
.split('=')
697 name
, opts
= split
[0], '='.join(split
[1:])
698 i
= pluginloader
.get_plugin(name
,options
.pluginpath
)
699 sys
.stderr
.write('Loaded plugin ' + i
['name'] + ' from path: ' + i
['path'] +' with opts: ' + opts
+ '\n')
700 plugin
= pluginloader
.load_plugin(i
).build_filter(opts
)
701 if hasattr(plugin
,'file_data_filter') and callable(plugin
.file_data_filter
):
702 plugins_dict
['file_data_filters'].append(plugin
.file_data_filter
)
703 if hasattr(plugin
, 'commit_message_filter') and callable(plugin
.commit_message_filter
):
704 plugins_dict
['commit_message_filters'].append(plugin
.commit_message_filter
)
706 sys
.exit(hg2git(options
.repourl
,m
,options
.marksfile
,options
.mappingfile
,
707 options
.headsfile
, options
.statusfile
,
708 authors
=a
,branchesmap
=b
,tagsmap
=t
,
709 sob
=options
.sob
,force
=options
.force
,hgtags
=options
.hgtags
,
710 notes
=options
.notes
,encoding
=encoding
,fn_encoding
=fn_encoding
,
711 plugins
=plugins_dict
))