Win32: fix potential multi-threading issue
[git/raj.git] / contrib / remote-helpers / git-remote-bzr
blob332aba784b8810120df8e1ddfafeb034a55337a3
1 #!/usr/bin/env python
3 # Copyright (c) 2012 Felipe Contreras
7 # Just copy to your ~/bin, or anywhere in your $PATH.
8 # Then you can clone with:
9 # % git clone bzr::/path/to/bzr/repo/or/url
11 # For example:
12 # % git clone bzr::$HOME/myrepo
13 # or
14 # % git clone bzr::lp:myrepo
16 # If you want to specify which branches you want to track (per repo):
17 # % git config remote.origin.bzr-branches 'trunk, devel, test'
19 # Where 'origin' is the name of the repository you want to specify the
20 # branches.
23 import sys
25 import bzrlib
26 if hasattr(bzrlib, "initialize"):
27 bzrlib.initialize()
29 import bzrlib.plugin
30 bzrlib.plugin.load_plugins()
32 import bzrlib.generate_ids
33 import bzrlib.transport
34 import bzrlib.errors
35 import bzrlib.ui
36 import bzrlib.urlutils
37 import bzrlib.branch
39 import sys
40 import os
41 import json
42 import re
43 import StringIO
44 import atexit, shutil, hashlib, urlparse, subprocess
46 NAME_RE = re.compile('^([^<>]+)')
47 AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)')
48 EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)')
49 RAW_AUTHOR_RE = re.compile('^(\w+) (.+)? <(.*)> (\d+) ([+-]\d+)')
51 def die(msg, *args):
52 sys.stderr.write('ERROR: %s\n' % (msg % args))
53 sys.exit(1)
55 def warn(msg, *args):
56 sys.stderr.write('WARNING: %s\n' % (msg % args))
58 def gittz(tz):
59 return '%+03d%02d' % (tz / 3600, tz % 3600 / 60)
61 def get_config(config):
62 cmd = ['git', 'config', '--get', config]
63 process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
64 output, _ = process.communicate()
65 return output
67 class Marks:
69 def __init__(self, path):
70 self.path = path
71 self.tips = {}
72 self.marks = {}
73 self.rev_marks = {}
74 self.last_mark = 0
75 self.load()
77 def load(self):
78 if not os.path.exists(self.path):
79 return
81 tmp = json.load(open(self.path))
82 self.tips = tmp['tips']
83 self.marks = tmp['marks']
84 self.last_mark = tmp['last-mark']
86 for rev, mark in self.marks.iteritems():
87 self.rev_marks[mark] = rev
89 def dict(self):
90 return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark }
92 def store(self):
93 json.dump(self.dict(), open(self.path, 'w'))
95 def __str__(self):
96 return str(self.dict())
98 def from_rev(self, rev):
99 return self.marks[rev]
101 def to_rev(self, mark):
102 return str(self.rev_marks[mark])
104 def next_mark(self):
105 self.last_mark += 1
106 return self.last_mark
108 def get_mark(self, rev):
109 self.last_mark += 1
110 self.marks[rev] = self.last_mark
111 return self.last_mark
113 def is_marked(self, rev):
114 return rev in self.marks
116 def new_mark(self, rev, mark):
117 self.marks[rev] = mark
118 self.rev_marks[mark] = rev
119 self.last_mark = mark
121 def get_tip(self, branch):
122 try:
123 return str(self.tips[branch])
124 except KeyError:
125 return None
127 def set_tip(self, branch, tip):
128 self.tips[branch] = tip
130 class Parser:
132 def __init__(self, repo):
133 self.repo = repo
134 self.line = self.get_line()
136 def get_line(self):
137 return sys.stdin.readline().strip()
139 def __getitem__(self, i):
140 return self.line.split()[i]
142 def check(self, word):
143 return self.line.startswith(word)
145 def each_block(self, separator):
146 while self.line != separator:
147 yield self.line
148 self.line = self.get_line()
150 def __iter__(self):
151 return self.each_block('')
153 def next(self):
154 self.line = self.get_line()
155 if self.line == 'done':
156 self.line = None
158 def get_mark(self):
159 i = self.line.index(':') + 1
160 return int(self.line[i:])
162 def get_data(self):
163 if not self.check('data'):
164 return None
165 i = self.line.index(' ') + 1
166 size = int(self.line[i:])
167 return sys.stdin.read(size)
169 def get_author(self):
170 m = RAW_AUTHOR_RE.match(self.line)
171 if not m:
172 return None
173 _, name, email, date, tz = m.groups()
174 name = name.decode('utf-8')
175 committer = '%s <%s>' % (name, email)
176 tz = int(tz)
177 tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
178 return (committer, int(date), tz)
180 def rev_to_mark(rev):
181 return marks.from_rev(rev)
183 def mark_to_rev(mark):
184 return marks.to_rev(mark)
186 def fixup_user(user):
187 name = mail = None
188 user = user.replace('"', '')
189 m = AUTHOR_RE.match(user)
190 if m:
191 name = m.group(1)
192 mail = m.group(2).strip()
193 else:
194 m = EMAIL_RE.match(user)
195 if m:
196 mail = m.group(1)
197 else:
198 m = NAME_RE.match(user)
199 if m:
200 name = m.group(1).strip()
202 if not name:
203 name = 'unknown'
204 if not mail:
205 mail = 'Unknown'
207 return '%s <%s>' % (name, mail)
209 def get_filechanges(cur, prev):
210 modified = {}
211 removed = {}
213 changes = cur.changes_from(prev)
215 def u(s):
216 return s.encode('utf-8')
218 for path, fid, kind in changes.added:
219 modified[u(path)] = fid
220 for path, fid, kind in changes.removed:
221 removed[u(path)] = None
222 for path, fid, kind, mod, _ in changes.modified:
223 modified[u(path)] = fid
224 for oldpath, newpath, fid, kind, mod, _ in changes.renamed:
225 removed[u(oldpath)] = None
226 if kind == 'directory':
227 lst = cur.list_files(from_dir=newpath, recursive=True)
228 for path, file_class, kind, fid, entry in lst:
229 if kind != 'directory':
230 modified[u(newpath + '/' + path)] = fid
231 else:
232 modified[u(newpath)] = fid
234 return modified, removed
236 def export_files(tree, files):
237 final = []
238 for path, fid in files.iteritems():
239 kind = tree.kind(fid)
241 h = tree.get_file_sha1(fid)
243 if kind == 'symlink':
244 d = tree.get_symlink_target(fid)
245 mode = '120000'
246 elif kind == 'file':
248 if tree.is_executable(fid):
249 mode = '100755'
250 else:
251 mode = '100644'
253 # is the blob already exported?
254 if h in filenodes:
255 mark = filenodes[h]
256 final.append((mode, mark, path))
257 continue
259 d = tree.get_file_text(fid)
260 elif kind == 'directory':
261 continue
262 else:
263 die("Unhandled kind '%s' for path '%s'" % (kind, path))
265 mark = marks.next_mark()
266 filenodes[h] = mark
268 print "blob"
269 print "mark :%u" % mark
270 print "data %d" % len(d)
271 print d
273 final.append((mode, mark, path))
275 return final
277 def export_branch(repo, name):
278 ref = '%s/heads/%s' % (prefix, name)
279 tip = marks.get_tip(name)
281 branch = get_remote_branch(name)
282 repo = branch.repository
284 branch.lock_read()
285 revs = branch.iter_merge_sorted_revisions(None, tip, 'exclude', 'forward')
286 try:
287 tip_revno = branch.revision_id_to_revno(tip)
288 last_revno, _ = branch.last_revision_info()
289 total = last_revno - tip_revno
290 except bzrlib.errors.NoSuchRevision:
291 tip_revno = 0
292 total = 0
294 for revid, _, seq, _ in revs:
296 if marks.is_marked(revid):
297 continue
299 rev = repo.get_revision(revid)
300 revno = seq[0]
302 parents = rev.parent_ids
303 time = rev.timestamp
304 tz = rev.timezone
305 committer = rev.committer.encode('utf-8')
306 committer = "%s %u %s" % (fixup_user(committer), time, gittz(tz))
307 authors = rev.get_apparent_authors()
308 if authors:
309 author = authors[0].encode('utf-8')
310 author = "%s %u %s" % (fixup_user(author), time, gittz(tz))
311 else:
312 author = committer
313 msg = rev.message.encode('utf-8')
315 msg += '\n'
317 if len(parents) == 0:
318 parent = bzrlib.revision.NULL_REVISION
319 else:
320 parent = parents[0]
322 cur_tree = repo.revision_tree(revid)
323 prev = repo.revision_tree(parent)
324 modified, removed = get_filechanges(cur_tree, prev)
326 modified_final = export_files(cur_tree, modified)
328 if len(parents) == 0:
329 print 'reset %s' % ref
331 print "commit %s" % ref
332 print "mark :%d" % (marks.get_mark(revid))
333 print "author %s" % (author)
334 print "committer %s" % (committer)
335 print "data %d" % (len(msg))
336 print msg
338 for i, p in enumerate(parents):
339 try:
340 m = rev_to_mark(p)
341 except KeyError:
342 # ghost?
343 continue
344 if i == 0:
345 print "from :%s" % m
346 else:
347 print "merge :%s" % m
349 for f in removed:
350 print "D %s" % (f,)
351 for f in modified_final:
352 print "M %s :%u %s" % f
353 print
355 if len(seq) > 1:
356 # let's skip branch revisions from the progress report
357 continue
359 progress = (revno - tip_revno)
360 if (progress % 100 == 0):
361 if total:
362 print "progress revision %d '%s' (%d/%d)" % (revno, name, progress, total)
363 else:
364 print "progress revision %d '%s' (%d)" % (revno, name, progress)
366 branch.unlock()
368 revid = branch.last_revision()
370 # make sure the ref is updated
371 print "reset %s" % ref
372 print "from :%u" % rev_to_mark(revid)
373 print
375 marks.set_tip(name, revid)
377 def export_tag(repo, name):
378 ref = '%s/tags/%s' % (prefix, name)
379 print "reset %s" % ref
380 print "from :%u" % rev_to_mark(tags[name])
381 print
383 def do_import(parser):
384 repo = parser.repo
385 path = os.path.join(dirname, 'marks-git')
387 print "feature done"
388 if os.path.exists(path):
389 print "feature import-marks=%s" % path
390 print "feature export-marks=%s" % path
391 print "feature force"
392 sys.stdout.flush()
394 while parser.check('import'):
395 ref = parser[1]
396 if ref.startswith('refs/heads/'):
397 name = ref[len('refs/heads/'):]
398 export_branch(repo, name)
399 if ref.startswith('refs/tags/'):
400 name = ref[len('refs/tags/'):]
401 export_tag(repo, name)
402 parser.next()
404 print 'done'
406 sys.stdout.flush()
408 def parse_blob(parser):
409 parser.next()
410 mark = parser.get_mark()
411 parser.next()
412 data = parser.get_data()
413 blob_marks[mark] = data
414 parser.next()
416 class CustomTree():
418 def __init__(self, branch, revid, parents, files):
419 self.updates = {}
420 self.branch = branch
422 def copy_tree(revid):
423 files = files_cache[revid] = {}
424 branch.lock_read()
425 tree = branch.repository.revision_tree(revid)
426 try:
427 for path, entry in tree.iter_entries_by_dir():
428 files[path] = [entry.file_id, None]
429 finally:
430 branch.unlock()
431 return files
433 if len(parents) == 0:
434 self.base_id = bzrlib.revision.NULL_REVISION
435 self.base_files = {}
436 else:
437 self.base_id = parents[0]
438 self.base_files = files_cache.get(self.base_id, None)
439 if not self.base_files:
440 self.base_files = copy_tree(self.base_id)
442 self.files = files_cache[revid] = self.base_files.copy()
443 self.rev_files = {}
445 for path, data in self.files.iteritems():
446 fid, mark = data
447 self.rev_files[fid] = [path, mark]
449 for path, f in files.iteritems():
450 fid, mark = self.files.get(path, [None, None])
451 if not fid:
452 fid = bzrlib.generate_ids.gen_file_id(path)
453 f['path'] = path
454 self.rev_files[fid] = [path, mark]
455 self.updates[fid] = f
457 def last_revision(self):
458 return self.base_id
460 def iter_changes(self):
461 changes = []
463 def get_parent(dirname, basename):
464 parent_fid, mark = self.base_files.get(dirname, [None, None])
465 if parent_fid:
466 return parent_fid
467 parent_fid, mark = self.files.get(dirname, [None, None])
468 if parent_fid:
469 return parent_fid
470 if basename == '':
471 return None
472 fid = bzrlib.generate_ids.gen_file_id(path)
473 add_entry(fid, dirname, 'directory')
474 return fid
476 def add_entry(fid, path, kind, mode=None):
477 dirname, basename = os.path.split(path)
478 parent_fid = get_parent(dirname, basename)
480 executable = False
481 if mode == '100755':
482 executable = True
483 elif mode == '120000':
484 kind = 'symlink'
486 change = (fid,
487 (None, path),
488 True,
489 (False, True),
490 (None, parent_fid),
491 (None, basename),
492 (None, kind),
493 (None, executable))
494 self.files[path] = [change[0], None]
495 changes.append(change)
497 def update_entry(fid, path, kind, mode=None):
498 dirname, basename = os.path.split(path)
499 parent_fid = get_parent(dirname, basename)
501 executable = False
502 if mode == '100755':
503 executable = True
504 elif mode == '120000':
505 kind = 'symlink'
507 change = (fid,
508 (path, path),
509 True,
510 (True, True),
511 (None, parent_fid),
512 (None, basename),
513 (None, kind),
514 (None, executable))
515 self.files[path] = [change[0], None]
516 changes.append(change)
518 def remove_entry(fid, path, kind):
519 dirname, basename = os.path.split(path)
520 parent_fid = get_parent(dirname, basename)
521 change = (fid,
522 (path, None),
523 True,
524 (True, False),
525 (parent_fid, None),
526 (None, None),
527 (None, None),
528 (None, None))
529 del self.files[path]
530 changes.append(change)
532 for fid, f in self.updates.iteritems():
533 path = f['path']
535 if 'deleted' in f:
536 remove_entry(fid, path, 'file')
537 continue
539 if path in self.base_files:
540 update_entry(fid, path, 'file', f['mode'])
541 else:
542 add_entry(fid, path, 'file', f['mode'])
544 self.files[path][1] = f['mark']
545 self.rev_files[fid][1] = f['mark']
547 return changes
549 def get_content(self, file_id):
550 path, mark = self.rev_files[file_id]
551 if mark:
552 return blob_marks[mark]
554 # last resort
555 tree = self.branch.repository.revision_tree(self.base_id)
556 return tree.get_file_text(file_id)
558 def get_file_with_stat(self, file_id, path=None):
559 content = self.get_content(file_id)
560 return (StringIO.StringIO(content), None)
562 def get_symlink_target(self, file_id):
563 return self.get_content(file_id)
565 def id2path(self, file_id):
566 path, mark = self.rev_files[file_id]
567 return path
569 def c_style_unescape(string):
570 if string[0] == string[-1] == '"':
571 return string.decode('string-escape')[1:-1]
572 return string
574 def parse_commit(parser):
575 parents = []
577 ref = parser[1]
578 parser.next()
580 if ref.startswith('refs/heads/'):
581 name = ref[len('refs/heads/'):]
582 branch = get_remote_branch(name)
583 else:
584 die('unknown ref')
586 commit_mark = parser.get_mark()
587 parser.next()
588 author = parser.get_author()
589 parser.next()
590 committer = parser.get_author()
591 parser.next()
592 data = parser.get_data()
593 parser.next()
594 if parser.check('from'):
595 parents.append(parser.get_mark())
596 parser.next()
597 while parser.check('merge'):
598 parents.append(parser.get_mark())
599 parser.next()
601 # fast-export adds an extra newline
602 if data[-1] == '\n':
603 data = data[:-1]
605 files = {}
607 for line in parser:
608 if parser.check('M'):
609 t, m, mark_ref, path = line.split(' ', 3)
610 mark = int(mark_ref[1:])
611 f = { 'mode' : m, 'mark' : mark }
612 elif parser.check('D'):
613 t, path = line.split(' ', 1)
614 f = { 'deleted' : True }
615 else:
616 die('Unknown file command: %s' % line)
617 path = c_style_unescape(path).decode('utf-8')
618 files[path] = f
620 committer, date, tz = committer
621 parents = [mark_to_rev(p) for p in parents]
622 revid = bzrlib.generate_ids.gen_revision_id(committer, date)
623 props = {}
624 props['branch-nick'] = branch.nick
626 mtree = CustomTree(branch, revid, parents, files)
627 changes = mtree.iter_changes()
629 branch.lock_write()
630 try:
631 builder = branch.get_commit_builder(parents, None, date, tz, committer, props, revid)
632 try:
633 list(builder.record_iter_changes(mtree, mtree.last_revision(), changes))
634 builder.finish_inventory()
635 builder.commit(data.decode('utf-8', 'replace'))
636 except Exception, e:
637 builder.abort()
638 raise
639 finally:
640 branch.unlock()
642 parsed_refs[ref] = revid
643 marks.new_mark(revid, commit_mark)
645 def parse_reset(parser):
646 ref = parser[1]
647 parser.next()
649 # ugh
650 if parser.check('commit'):
651 parse_commit(parser)
652 return
653 if not parser.check('from'):
654 return
655 from_mark = parser.get_mark()
656 parser.next()
658 parsed_refs[ref] = mark_to_rev(from_mark)
660 def do_export(parser):
661 parser.next()
663 for line in parser.each_block('done'):
664 if parser.check('blob'):
665 parse_blob(parser)
666 elif parser.check('commit'):
667 parse_commit(parser)
668 elif parser.check('reset'):
669 parse_reset(parser)
670 elif parser.check('tag'):
671 pass
672 elif parser.check('feature'):
673 pass
674 else:
675 die('unhandled export command: %s' % line)
677 for ref, revid in parsed_refs.iteritems():
678 if ref.startswith('refs/heads/'):
679 name = ref[len('refs/heads/'):]
680 branch = get_remote_branch(name)
681 branch.generate_revision_history(revid, marks.get_tip(name))
683 if name in peers:
684 peer = bzrlib.branch.Branch.open(peers[name],
685 possible_transports=transports)
686 try:
687 peer.bzrdir.push_branch(branch, revision_id=revid)
688 except bzrlib.errors.DivergedBranches:
689 print "error %s non-fast forward" % ref
690 continue
692 try:
693 wt = branch.bzrdir.open_workingtree()
694 wt.update()
695 except bzrlib.errors.NoWorkingTree:
696 pass
697 elif ref.startswith('refs/tags/'):
698 # TODO: implement tag push
699 print "error %s pushing tags not supported" % ref
700 continue
701 else:
702 # transport-helper/fast-export bugs
703 continue
705 print "ok %s" % ref
707 print
709 def do_capabilities(parser):
710 print "import"
711 print "export"
712 print "refspec refs/heads/*:%s/heads/*" % prefix
713 print "refspec refs/tags/*:%s/tags/*" % prefix
715 path = os.path.join(dirname, 'marks-git')
717 if os.path.exists(path):
718 print "*import-marks %s" % path
719 print "*export-marks %s" % path
721 print
723 def ref_is_valid(name):
724 return not True in [c in name for c in '~^: \\']
726 def do_list(parser):
727 master_branch = None
729 for name in branches:
730 if not master_branch:
731 master_branch = name
732 print "? refs/heads/%s" % name
734 branch = get_remote_branch(master_branch)
735 branch.lock_read()
736 for tag, revid in branch.tags.get_tag_dict().items():
737 try:
738 branch.revision_id_to_dotted_revno(revid)
739 except bzrlib.errors.NoSuchRevision:
740 continue
741 if not ref_is_valid(tag):
742 continue
743 print "? refs/tags/%s" % tag
744 tags[tag] = revid
745 branch.unlock()
747 print "@refs/heads/%s HEAD" % master_branch
748 print
750 def clone(path, remote_branch):
751 try:
752 bdir = bzrlib.bzrdir.BzrDir.create(path, possible_transports=transports)
753 except bzrlib.errors.AlreadyControlDirError:
754 bdir = bzrlib.bzrdir.BzrDir.open(path, possible_transports=transports)
755 repo = bdir.find_repository()
756 repo.fetch(remote_branch.repository)
757 return remote_branch.sprout(bdir, repository=repo)
759 def get_remote_branch(name):
760 remote_branch = bzrlib.branch.Branch.open(branches[name],
761 possible_transports=transports)
762 if isinstance(remote_branch.user_transport, bzrlib.transport.local.LocalTransport):
763 return remote_branch
765 branch_path = os.path.join(dirname, 'clone', name)
767 try:
768 branch = bzrlib.branch.Branch.open(branch_path,
769 possible_transports=transports)
770 except bzrlib.errors.NotBranchError:
771 # clone
772 branch = clone(branch_path, remote_branch)
773 else:
774 # pull
775 try:
776 branch.pull(remote_branch, overwrite=True)
777 except bzrlib.errors.DivergedBranches:
778 # use remote branch for now
779 return remote_branch
781 return branch
783 def find_branches(repo):
784 transport = repo.bzrdir.root_transport
786 for fn in transport.iter_files_recursive():
787 if not fn.endswith('.bzr/branch-format'):
788 continue
790 name = subdir = fn[:-len('/.bzr/branch-format')]
791 name = name if name != '' else 'master'
792 name = name.replace('/', '+')
794 try:
795 cur = transport.clone(subdir)
796 branch = bzrlib.branch.Branch.open_from_transport(cur)
797 except bzrlib.errors.NotBranchError:
798 continue
799 else:
800 yield name, branch.base
802 def get_repo(url, alias):
803 normal_url = bzrlib.urlutils.normalize_url(url)
804 origin = bzrlib.bzrdir.BzrDir.open(url, possible_transports=transports)
805 is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
807 shared_path = os.path.join(gitdir, 'bzr')
808 try:
809 shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path,
810 possible_transports=transports)
811 except bzrlib.errors.NotBranchError:
812 shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path,
813 possible_transports=transports)
814 try:
815 shared_repo = shared_dir.open_repository()
816 except bzrlib.errors.NoRepositoryPresent:
817 shared_repo = shared_dir.create_repository(shared=True)
819 if not is_local:
820 clone_path = os.path.join(dirname, 'clone')
821 if not os.path.exists(clone_path):
822 os.mkdir(clone_path)
823 else:
824 # check and remove old organization
825 try:
826 bdir = bzrlib.bzrdir.BzrDir.open(clone_path,
827 possible_transports=transports)
828 bdir.destroy_repository()
829 except bzrlib.errors.NotBranchError:
830 pass
831 except bzrlib.errors.NoRepositoryPresent:
832 pass
834 wanted = get_config('remote.%s.bzr-branches' % alias).rstrip().split(', ')
835 # stupid python
836 wanted = [e for e in wanted if e]
837 if not wanted:
838 wanted = get_config('remote-bzr.branches').rstrip().split(', ')
839 # stupid python
840 wanted = [e for e in wanted if e]
842 if not wanted:
843 try:
844 repo = origin.open_repository()
845 if not repo.user_transport.listable():
846 # this repository is not usable for us
847 raise bzrlib.errors.NoRepositoryPresent(repo.bzrdir)
848 except bzrlib.errors.NoRepositoryPresent:
849 wanted = ['master']
851 if wanted:
852 def list_wanted(url, wanted):
853 for name in wanted:
854 subdir = name if name != 'master' else ''
855 yield name, bzrlib.urlutils.join(url, subdir)
857 branch_list = list_wanted(url, wanted)
858 else:
859 branch_list = find_branches(repo)
861 for name, url in branch_list:
862 if not is_local:
863 peers[name] = url
864 branches[name] = url
866 return origin
868 def fix_path(alias, orig_url):
869 url = urlparse.urlparse(orig_url, 'file')
870 if url.scheme != 'file' or os.path.isabs(url.path):
871 return
872 abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url)
873 cmd = ['git', 'config', 'remote.%s.url' % alias, "bzr::%s" % abs_url]
874 subprocess.call(cmd)
876 def main(args):
877 global marks, prefix, gitdir, dirname
878 global tags, filenodes
879 global blob_marks
880 global parsed_refs
881 global files_cache
882 global is_tmp
883 global branches, peers
884 global transports
886 marks = None
887 is_tmp = False
888 gitdir = os.environ.get('GIT_DIR', None)
890 if len(args) < 3:
891 die('Not enough arguments.')
893 if not gitdir:
894 die('GIT_DIR not set')
896 alias = args[1]
897 url = args[2]
899 tags = {}
900 filenodes = {}
901 blob_marks = {}
902 parsed_refs = {}
903 files_cache = {}
904 branches = {}
905 peers = {}
906 transports = []
908 if alias[5:] == url:
909 is_tmp = True
910 alias = hashlib.sha1(alias).hexdigest()
912 prefix = 'refs/bzr/%s' % alias
913 dirname = os.path.join(gitdir, 'bzr', alias)
915 if not is_tmp:
916 fix_path(alias, url)
918 if not os.path.exists(dirname):
919 os.makedirs(dirname)
921 if hasattr(bzrlib.ui.ui_factory, 'be_quiet'):
922 bzrlib.ui.ui_factory.be_quiet(True)
924 repo = get_repo(url, alias)
926 marks_path = os.path.join(dirname, 'marks-int')
927 marks = Marks(marks_path)
929 parser = Parser(repo)
930 for line in parser:
931 if parser.check('capabilities'):
932 do_capabilities(parser)
933 elif parser.check('list'):
934 do_list(parser)
935 elif parser.check('import'):
936 do_import(parser)
937 elif parser.check('export'):
938 do_export(parser)
939 else:
940 die('unhandled command: %s' % line)
941 sys.stdout.flush()
943 def bye():
944 if not marks:
945 return
946 if not is_tmp:
947 marks.store()
948 else:
949 shutil.rmtree(dirname)
951 atexit.register(bye)
952 sys.exit(main(sys.argv))