remote-helpers: cleanup more global variables
[git/mjg.git] / contrib / remote-helpers / git-remote-bzr
blob42cec58a00aad15f7daef4a26caffca79e839778
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('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\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 name = m.group(1)
197 mail = m.group(2)
198 else:
199 m = NAME_RE.match(user)
200 if m:
201 name = m.group(1).strip()
203 if not name:
204 name = 'unknown'
205 if not mail:
206 mail = 'Unknown'
208 return '%s <%s>' % (name, mail)
210 def get_filechanges(cur, prev):
211 modified = {}
212 removed = {}
214 changes = cur.changes_from(prev)
216 def u(s):
217 return s.encode('utf-8')
219 for path, fid, kind in changes.added:
220 modified[u(path)] = fid
221 for path, fid, kind in changes.removed:
222 removed[u(path)] = None
223 for path, fid, kind, mod, _ in changes.modified:
224 modified[u(path)] = fid
225 for oldpath, newpath, fid, kind, mod, _ in changes.renamed:
226 removed[u(oldpath)] = None
227 if kind == 'directory':
228 lst = cur.list_files(from_dir=newpath, recursive=True)
229 for path, file_class, kind, fid, entry in lst:
230 if kind != 'directory':
231 modified[u(newpath + '/' + path)] = fid
232 else:
233 modified[u(newpath)] = fid
235 return modified, removed
237 def export_files(tree, files):
238 final = []
239 for path, fid in files.iteritems():
240 kind = tree.kind(fid)
242 h = tree.get_file_sha1(fid)
244 if kind == 'symlink':
245 d = tree.get_symlink_target(fid)
246 mode = '120000'
247 elif kind == 'file':
249 if tree.is_executable(fid):
250 mode = '100755'
251 else:
252 mode = '100644'
254 # is the blob already exported?
255 if h in filenodes:
256 mark = filenodes[h]
257 final.append((mode, mark, path))
258 continue
260 d = tree.get_file_text(fid)
261 elif kind == 'directory':
262 continue
263 else:
264 die("Unhandled kind '%s' for path '%s'" % (kind, path))
266 mark = marks.next_mark()
267 filenodes[h] = mark
269 print "blob"
270 print "mark :%u" % mark
271 print "data %d" % len(d)
272 print d
274 final.append((mode, mark, path))
276 return final
278 def export_branch(repo, name):
279 ref = '%s/heads/%s' % (prefix, name)
280 tip = marks.get_tip(name)
282 branch = get_remote_branch(name)
283 repo = branch.repository
285 branch.lock_read()
286 revs = branch.iter_merge_sorted_revisions(None, tip, 'exclude', 'forward')
287 try:
288 tip_revno = branch.revision_id_to_revno(tip)
289 last_revno, _ = branch.last_revision_info()
290 total = last_revno - tip_revno
291 except bzrlib.errors.NoSuchRevision:
292 tip_revno = 0
293 total = 0
295 for revid, _, seq, _ in revs:
297 if marks.is_marked(revid):
298 continue
300 rev = repo.get_revision(revid)
301 revno = seq[0]
303 parents = rev.parent_ids
304 time = rev.timestamp
305 tz = rev.timezone
306 committer = rev.committer.encode('utf-8')
307 committer = "%s %u %s" % (fixup_user(committer), time, gittz(tz))
308 authors = rev.get_apparent_authors()
309 if authors:
310 author = authors[0].encode('utf-8')
311 author = "%s %u %s" % (fixup_user(author), time, gittz(tz))
312 else:
313 author = committer
314 msg = rev.message.encode('utf-8')
316 msg += '\n'
318 if len(parents) == 0:
319 parent = bzrlib.revision.NULL_REVISION
320 else:
321 parent = parents[0]
323 cur_tree = repo.revision_tree(revid)
324 prev = repo.revision_tree(parent)
325 modified, removed = get_filechanges(cur_tree, prev)
327 modified_final = export_files(cur_tree, modified)
329 if len(parents) == 0:
330 print 'reset %s' % ref
332 print "commit %s" % ref
333 print "mark :%d" % (marks.get_mark(revid))
334 print "author %s" % (author)
335 print "committer %s" % (committer)
336 print "data %d" % (len(msg))
337 print msg
339 for i, p in enumerate(parents):
340 try:
341 m = rev_to_mark(p)
342 except KeyError:
343 # ghost?
344 continue
345 if i == 0:
346 print "from :%s" % m
347 else:
348 print "merge :%s" % m
350 for f in removed:
351 print "D %s" % (f,)
352 for f in modified_final:
353 print "M %s :%u %s" % f
354 print
356 if len(seq) > 1:
357 # let's skip branch revisions from the progress report
358 continue
360 progress = (revno - tip_revno)
361 if (progress % 100 == 0):
362 if total:
363 print "progress revision %d '%s' (%d/%d)" % (revno, name, progress, total)
364 else:
365 print "progress revision %d '%s' (%d)" % (revno, name, progress)
367 branch.unlock()
369 revid = branch.last_revision()
371 # make sure the ref is updated
372 print "reset %s" % ref
373 print "from :%u" % rev_to_mark(revid)
374 print
376 marks.set_tip(name, revid)
378 def export_tag(repo, name):
379 ref = '%s/tags/%s' % (prefix, name)
380 print "reset %s" % ref
381 print "from :%u" % rev_to_mark(tags[name])
382 print
384 def do_import(parser):
385 repo = parser.repo
386 path = os.path.join(dirname, 'marks-git')
388 print "feature done"
389 if os.path.exists(path):
390 print "feature import-marks=%s" % path
391 print "feature export-marks=%s" % path
392 print "feature force"
393 sys.stdout.flush()
395 while parser.check('import'):
396 ref = parser[1]
397 if ref.startswith('refs/heads/'):
398 name = ref[len('refs/heads/'):]
399 export_branch(repo, name)
400 if ref.startswith('refs/tags/'):
401 name = ref[len('refs/tags/'):]
402 export_tag(repo, name)
403 parser.next()
405 print 'done'
407 sys.stdout.flush()
409 def parse_blob(parser):
410 parser.next()
411 mark = parser.get_mark()
412 parser.next()
413 data = parser.get_data()
414 blob_marks[mark] = data
415 parser.next()
417 class CustomTree():
419 def __init__(self, branch, revid, parents, files):
420 self.updates = {}
421 self.branch = branch
423 def copy_tree(revid):
424 files = files_cache[revid] = {}
425 branch.lock_read()
426 tree = branch.repository.revision_tree(revid)
427 try:
428 for path, entry in tree.iter_entries_by_dir():
429 files[path] = [entry.file_id, None]
430 finally:
431 branch.unlock()
432 return files
434 if len(parents) == 0:
435 self.base_id = bzrlib.revision.NULL_REVISION
436 self.base_files = {}
437 else:
438 self.base_id = parents[0]
439 self.base_files = files_cache.get(self.base_id, None)
440 if not self.base_files:
441 self.base_files = copy_tree(self.base_id)
443 self.files = files_cache[revid] = self.base_files.copy()
444 self.rev_files = {}
446 for path, data in self.files.iteritems():
447 fid, mark = data
448 self.rev_files[fid] = [path, mark]
450 for path, f in files.iteritems():
451 fid, mark = self.files.get(path, [None, None])
452 if not fid:
453 fid = bzrlib.generate_ids.gen_file_id(path)
454 f['path'] = path
455 self.rev_files[fid] = [path, mark]
456 self.updates[fid] = f
458 def last_revision(self):
459 return self.base_id
461 def iter_changes(self):
462 changes = []
464 def get_parent(dirname, basename):
465 parent_fid, mark = self.base_files.get(dirname, [None, None])
466 if parent_fid:
467 return parent_fid
468 parent_fid, mark = self.files.get(dirname, [None, None])
469 if parent_fid:
470 return parent_fid
471 if basename == '':
472 return None
473 fid = bzrlib.generate_ids.gen_file_id(path)
474 add_entry(fid, dirname, 'directory')
475 return fid
477 def add_entry(fid, path, kind, mode=None):
478 dirname, basename = os.path.split(path)
479 parent_fid = get_parent(dirname, basename)
481 executable = False
482 if mode == '100755':
483 executable = True
484 elif mode == '120000':
485 kind = 'symlink'
487 change = (fid,
488 (None, path),
489 True,
490 (False, True),
491 (None, parent_fid),
492 (None, basename),
493 (None, kind),
494 (None, executable))
495 self.files[path] = [change[0], None]
496 changes.append(change)
498 def update_entry(fid, path, kind, mode=None):
499 dirname, basename = os.path.split(path)
500 parent_fid = get_parent(dirname, basename)
502 executable = False
503 if mode == '100755':
504 executable = True
505 elif mode == '120000':
506 kind = 'symlink'
508 change = (fid,
509 (path, path),
510 True,
511 (True, True),
512 (None, parent_fid),
513 (None, basename),
514 (None, kind),
515 (None, executable))
516 self.files[path] = [change[0], None]
517 changes.append(change)
519 def remove_entry(fid, path, kind):
520 dirname, basename = os.path.split(path)
521 parent_fid = get_parent(dirname, basename)
522 change = (fid,
523 (path, None),
524 True,
525 (True, False),
526 (parent_fid, None),
527 (None, None),
528 (None, None),
529 (None, None))
530 del self.files[path]
531 changes.append(change)
533 for fid, f in self.updates.iteritems():
534 path = f['path']
536 if 'deleted' in f:
537 remove_entry(fid, path, 'file')
538 continue
540 if path in self.base_files:
541 update_entry(fid, path, 'file', f['mode'])
542 else:
543 add_entry(fid, path, 'file', f['mode'])
545 self.files[path][1] = f['mark']
546 self.rev_files[fid][1] = f['mark']
548 return changes
550 def get_content(self, file_id):
551 path, mark = self.rev_files[file_id]
552 if mark:
553 return blob_marks[mark]
555 # last resort
556 tree = self.branch.repository.revision_tree(self.base_id)
557 return tree.get_file_text(file_id)
559 def get_file_with_stat(self, file_id, path=None):
560 content = self.get_content(file_id)
561 return (StringIO.StringIO(content), None)
563 def get_symlink_target(self, file_id):
564 return self.get_content(file_id)
566 def id2path(self, file_id):
567 path, mark = self.rev_files[file_id]
568 return path
570 def c_style_unescape(string):
571 if string[0] == string[-1] == '"':
572 return string.decode('string-escape')[1:-1]
573 return string
575 def parse_commit(parser):
576 parents = []
578 ref = parser[1]
579 parser.next()
581 if ref.startswith('refs/heads/'):
582 name = ref[len('refs/heads/'):]
583 branch = get_remote_branch(name)
584 else:
585 die('unknown ref')
587 commit_mark = parser.get_mark()
588 parser.next()
589 author = parser.get_author()
590 parser.next()
591 committer = parser.get_author()
592 parser.next()
593 data = parser.get_data()
594 parser.next()
595 if parser.check('from'):
596 parents.append(parser.get_mark())
597 parser.next()
598 while parser.check('merge'):
599 parents.append(parser.get_mark())
600 parser.next()
602 # fast-export adds an extra newline
603 if data[-1] == '\n':
604 data = data[:-1]
606 files = {}
608 for line in parser:
609 if parser.check('M'):
610 t, m, mark_ref, path = line.split(' ', 3)
611 mark = int(mark_ref[1:])
612 f = { 'mode' : m, 'mark' : mark }
613 elif parser.check('D'):
614 t, path = line.split(' ', 1)
615 f = { 'deleted' : True }
616 else:
617 die('Unknown file command: %s' % line)
618 path = c_style_unescape(path).decode('utf-8')
619 files[path] = f
621 committer, date, tz = committer
622 parents = [mark_to_rev(p) for p in parents]
623 revid = bzrlib.generate_ids.gen_revision_id(committer, date)
624 props = {}
625 props['branch-nick'] = branch.nick
627 mtree = CustomTree(branch, revid, parents, files)
628 changes = mtree.iter_changes()
630 branch.lock_write()
631 try:
632 builder = branch.get_commit_builder(parents, None, date, tz, committer, props, revid)
633 try:
634 list(builder.record_iter_changes(mtree, mtree.last_revision(), changes))
635 builder.finish_inventory()
636 builder.commit(data.decode('utf-8', 'replace'))
637 except Exception, e:
638 builder.abort()
639 raise
640 finally:
641 branch.unlock()
643 parsed_refs[ref] = revid
644 marks.new_mark(revid, commit_mark)
646 def parse_reset(parser):
647 ref = parser[1]
648 parser.next()
650 # ugh
651 if parser.check('commit'):
652 parse_commit(parser)
653 return
654 if not parser.check('from'):
655 return
656 from_mark = parser.get_mark()
657 parser.next()
659 parsed_refs[ref] = mark_to_rev(from_mark)
661 def do_export(parser):
662 parser.next()
664 for line in parser.each_block('done'):
665 if parser.check('blob'):
666 parse_blob(parser)
667 elif parser.check('commit'):
668 parse_commit(parser)
669 elif parser.check('reset'):
670 parse_reset(parser)
671 elif parser.check('tag'):
672 pass
673 elif parser.check('feature'):
674 pass
675 else:
676 die('unhandled export command: %s' % line)
678 for ref, revid in parsed_refs.iteritems():
679 if ref.startswith('refs/heads/'):
680 name = ref[len('refs/heads/'):]
681 branch = get_remote_branch(name)
682 branch.generate_revision_history(revid, marks.get_tip(name))
684 if name in peers:
685 peer = bzrlib.branch.Branch.open(peers[name])
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)
753 except bzrlib.errors.AlreadyControlDirError:
754 bdir = bzrlib.bzrdir.BzrDir.open(path)
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 if isinstance(remote_branch.user_transport, bzrlib.transport.local.LocalTransport):
762 return remote_branch
764 branch_path = os.path.join(dirname, 'clone', name)
766 try:
767 branch = bzrlib.branch.Branch.open(branch_path)
768 except bzrlib.errors.NotBranchError:
769 # clone
770 branch = clone(branch_path, remote_branch)
771 else:
772 # pull
773 try:
774 branch.pull(remote_branch, overwrite=True)
775 except bzrlib.errors.DivergedBranches:
776 # use remote branch for now
777 return remote_branch
779 return branch
781 def find_branches(repo):
782 transport = repo.bzrdir.root_transport
784 for fn in transport.iter_files_recursive():
785 if not fn.endswith('.bzr/branch-format'):
786 continue
788 name = subdir = fn[:-len('/.bzr/branch-format')]
789 name = name if name != '' else 'master'
790 name = name.replace('/', '+')
792 try:
793 cur = transport.clone(subdir)
794 branch = bzrlib.branch.Branch.open_from_transport(cur)
795 except bzrlib.errors.NotBranchError:
796 continue
797 else:
798 yield name, branch.base
800 def get_repo(url, alias):
801 normal_url = bzrlib.urlutils.normalize_url(url)
802 origin = bzrlib.bzrdir.BzrDir.open(url)
803 is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
805 shared_path = os.path.join(gitdir, 'bzr')
806 try:
807 shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path)
808 except bzrlib.errors.NotBranchError:
809 shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path)
810 try:
811 shared_repo = shared_dir.open_repository()
812 except bzrlib.errors.NoRepositoryPresent:
813 shared_repo = shared_dir.create_repository(shared=True)
815 if not is_local:
816 clone_path = os.path.join(dirname, 'clone')
817 if not os.path.exists(clone_path):
818 os.mkdir(clone_path)
819 else:
820 # check and remove old organization
821 try:
822 bdir = bzrlib.bzrdir.BzrDir.open(clone_path)
823 bdir.destroy_repository()
824 except bzrlib.errors.NotBranchError:
825 pass
826 except bzrlib.errors.NoRepositoryPresent:
827 pass
829 wanted = get_config('remote.%s.bzr-branches' % alias).rstrip().split(', ')
830 # stupid python
831 wanted = [e for e in wanted if e]
832 if not wanted:
833 wanted = get_config('remote-bzr.branches').rstrip().split(', ')
834 # stupid python
835 wanted = [e for e in wanted if e]
837 if not wanted:
838 try:
839 repo = origin.open_repository()
840 if not repo.user_transport.listable():
841 # this repository is not usable for us
842 raise bzrlib.errors.NoRepositoryPresent(repo.bzrdir)
843 except bzrlib.errors.NoRepositoryPresent:
844 wanted = ['master']
846 if wanted:
847 def list_wanted(url, wanted):
848 for name in wanted:
849 subdir = name if name != 'master' else ''
850 yield name, bzrlib.urlutils.join(url, subdir)
852 branch_list = list_wanted(url, wanted)
853 else:
854 branch_list = find_branches(repo)
856 for name, url in branch_list:
857 if not is_local:
858 peers[name] = url
859 branches[name] = url
861 return origin
863 def fix_path(alias, orig_url):
864 url = urlparse.urlparse(orig_url, 'file')
865 if url.scheme != 'file' or os.path.isabs(url.path):
866 return
867 abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url)
868 cmd = ['git', 'config', 'remote.%s.url' % alias, "bzr::%s" % abs_url]
869 subprocess.call(cmd)
871 def main(args):
872 global marks, prefix, gitdir, dirname
873 global tags, filenodes
874 global blob_marks
875 global parsed_refs
876 global files_cache
877 global is_tmp
878 global branches, peers
880 alias = args[1]
881 url = args[2]
883 tags = {}
884 filenodes = {}
885 blob_marks = {}
886 parsed_refs = {}
887 files_cache = {}
888 marks = None
889 branches = {}
890 peers = {}
892 if alias[5:] == url:
893 is_tmp = True
894 alias = hashlib.sha1(alias).hexdigest()
895 else:
896 is_tmp = False
898 prefix = 'refs/bzr/%s' % alias
899 gitdir = os.environ['GIT_DIR']
900 dirname = os.path.join(gitdir, 'bzr', alias)
902 if not is_tmp:
903 fix_path(alias, url)
905 if not os.path.exists(dirname):
906 os.makedirs(dirname)
908 if hasattr(bzrlib.ui.ui_factory, 'be_quiet'):
909 bzrlib.ui.ui_factory.be_quiet(True)
911 repo = get_repo(url, alias)
913 marks_path = os.path.join(dirname, 'marks-int')
914 marks = Marks(marks_path)
916 parser = Parser(repo)
917 for line in parser:
918 if parser.check('capabilities'):
919 do_capabilities(parser)
920 elif parser.check('list'):
921 do_list(parser)
922 elif parser.check('import'):
923 do_import(parser)
924 elif parser.check('export'):
925 do_export(parser)
926 else:
927 die('unhandled command: %s' % line)
928 sys.stdout.flush()
930 def bye():
931 if not marks:
932 return
933 if not is_tmp:
934 marks.store()
935 else:
936 shutil.rmtree(dirname)
938 atexit.register(bye)
939 sys.exit(main(sys.argv))