remote-bzr: reorganize the way 'wanted' works
[git.git] / contrib / remote-helpers / git-remote-bzr
blob3248586b13d8c1b43697cf85107a9f4708563a38
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 track (per repo):
17 # git config remote-bzr.branches 'trunk, devel, test'
20 import sys
22 import bzrlib
23 if hasattr(bzrlib, "initialize"):
24 bzrlib.initialize()
26 import bzrlib.plugin
27 bzrlib.plugin.load_plugins()
29 import bzrlib.generate_ids
30 import bzrlib.transport
31 import bzrlib.errors
32 import bzrlib.ui
33 import bzrlib.urlutils
34 import bzrlib.branch
36 import sys
37 import os
38 import json
39 import re
40 import StringIO
41 import atexit, shutil, hashlib, urlparse, subprocess
43 NAME_RE = re.compile('^([^<>]+)')
44 AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]*)>$')
45 EMAIL_RE = re.compile('^([^<>]+[^ \\\t<>])?\\b(?:[ \\t<>]*?)\\b([^ \\t<>]+@[^ \\t<>]+)')
46 RAW_AUTHOR_RE = re.compile('^(\w+) (.+)? <(.*)> (\d+) ([+-]\d+)')
48 def die(msg, *args):
49 sys.stderr.write('ERROR: %s\n' % (msg % args))
50 sys.exit(1)
52 def warn(msg, *args):
53 sys.stderr.write('WARNING: %s\n' % (msg % args))
55 def gittz(tz):
56 return '%+03d%02d' % (tz / 3600, tz % 3600 / 60)
58 def get_config(config):
59 cmd = ['git', 'config', '--get', config]
60 process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
61 output, _ = process.communicate()
62 return output
64 class Marks:
66 def __init__(self, path):
67 self.path = path
68 self.tips = {}
69 self.marks = {}
70 self.rev_marks = {}
71 self.last_mark = 0
72 self.load()
74 def load(self):
75 if not os.path.exists(self.path):
76 return
78 tmp = json.load(open(self.path))
79 self.tips = tmp['tips']
80 self.marks = tmp['marks']
81 self.last_mark = tmp['last-mark']
83 for rev, mark in self.marks.iteritems():
84 self.rev_marks[mark] = rev
86 def dict(self):
87 return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark }
89 def store(self):
90 json.dump(self.dict(), open(self.path, 'w'))
92 def __str__(self):
93 return str(self.dict())
95 def from_rev(self, rev):
96 return self.marks[rev]
98 def to_rev(self, mark):
99 return str(self.rev_marks[mark])
101 def next_mark(self):
102 self.last_mark += 1
103 return self.last_mark
105 def get_mark(self, rev):
106 self.last_mark += 1
107 self.marks[rev] = self.last_mark
108 return self.last_mark
110 def is_marked(self, rev):
111 return rev in self.marks
113 def new_mark(self, rev, mark):
114 self.marks[rev] = mark
115 self.rev_marks[mark] = rev
116 self.last_mark = mark
118 def get_tip(self, branch):
119 return self.tips.get(branch, None)
121 def set_tip(self, branch, tip):
122 self.tips[branch] = tip
124 class Parser:
126 def __init__(self, repo):
127 self.repo = repo
128 self.line = self.get_line()
130 def get_line(self):
131 return sys.stdin.readline().strip()
133 def __getitem__(self, i):
134 return self.line.split()[i]
136 def check(self, word):
137 return self.line.startswith(word)
139 def each_block(self, separator):
140 while self.line != separator:
141 yield self.line
142 self.line = self.get_line()
144 def __iter__(self):
145 return self.each_block('')
147 def next(self):
148 self.line = self.get_line()
149 if self.line == 'done':
150 self.line = None
152 def get_mark(self):
153 i = self.line.index(':') + 1
154 return int(self.line[i:])
156 def get_data(self):
157 if not self.check('data'):
158 return None
159 i = self.line.index(' ') + 1
160 size = int(self.line[i:])
161 return sys.stdin.read(size)
163 def get_author(self):
164 m = RAW_AUTHOR_RE.match(self.line)
165 if not m:
166 return None
167 _, name, email, date, tz = m.groups()
168 committer = '%s <%s>' % (name, email)
169 tz = int(tz)
170 tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
171 return (committer, int(date), tz)
173 def rev_to_mark(rev):
174 global marks
175 return marks.from_rev(rev)
177 def mark_to_rev(mark):
178 global marks
179 return marks.to_rev(mark)
181 def fixup_user(user):
182 name = mail = None
183 user = user.replace('"', '')
184 m = AUTHOR_RE.match(user)
185 if m:
186 name = m.group(1)
187 mail = m.group(2).strip()
188 else:
189 m = EMAIL_RE.match(user)
190 if m:
191 name = m.group(1)
192 mail = m.group(2)
193 else:
194 m = NAME_RE.match(user)
195 if m:
196 name = m.group(1).strip()
198 if not name:
199 name = 'unknown'
200 if not mail:
201 mail = 'Unknown'
203 return '%s <%s>' % (name, mail)
205 def get_filechanges(cur, prev):
206 modified = {}
207 removed = {}
209 changes = cur.changes_from(prev)
211 def u(s):
212 return s.encode('utf-8')
214 for path, fid, kind in changes.added:
215 modified[u(path)] = fid
216 for path, fid, kind in changes.removed:
217 removed[u(path)] = None
218 for path, fid, kind, mod, _ in changes.modified:
219 modified[u(path)] = fid
220 for oldpath, newpath, fid, kind, mod, _ in changes.renamed:
221 removed[u(oldpath)] = None
222 if kind == 'directory':
223 lst = cur.list_files(from_dir=newpath, recursive=True)
224 for path, file_class, kind, fid, entry in lst:
225 if kind != 'directory':
226 modified[u(newpath + '/' + path)] = fid
227 else:
228 modified[u(newpath)] = fid
230 return modified, removed
232 def export_files(tree, files):
233 global marks, filenodes
235 final = []
236 for path, fid in files.iteritems():
237 kind = tree.kind(fid)
239 h = tree.get_file_sha1(fid)
241 if kind == 'symlink':
242 d = tree.get_symlink_target(fid)
243 mode = '120000'
244 elif kind == 'file':
246 if tree.is_executable(fid):
247 mode = '100755'
248 else:
249 mode = '100644'
251 # is the blob already exported?
252 if h in filenodes:
253 mark = filenodes[h]
254 final.append((mode, mark, path))
255 continue
257 d = tree.get_file_text(fid)
258 elif kind == 'directory':
259 continue
260 else:
261 die("Unhandled kind '%s' for path '%s'" % (kind, path))
263 mark = marks.next_mark()
264 filenodes[h] = mark
266 print "blob"
267 print "mark :%u" % mark
268 print "data %d" % len(d)
269 print d
271 final.append((mode, mark, path))
273 return final
275 def export_branch(repo, name):
276 global prefix
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 global tags, prefix
380 ref = '%s/tags/%s' % (prefix, name)
381 print "reset %s" % ref
382 print "from :%u" % rev_to_mark(tags[name])
383 print
385 def do_import(parser):
386 global dirname
388 repo = parser.repo
389 path = os.path.join(dirname, 'marks-git')
391 print "feature done"
392 if os.path.exists(path):
393 print "feature import-marks=%s" % path
394 print "feature export-marks=%s" % path
395 print "feature force"
396 sys.stdout.flush()
398 while parser.check('import'):
399 ref = parser[1]
400 if ref.startswith('refs/heads/'):
401 name = ref[len('refs/heads/'):]
402 export_branch(repo, name)
403 if ref.startswith('refs/tags/'):
404 name = ref[len('refs/tags/'):]
405 export_tag(repo, name)
406 parser.next()
408 print 'done'
410 sys.stdout.flush()
412 def parse_blob(parser):
413 global blob_marks
415 parser.next()
416 mark = parser.get_mark()
417 parser.next()
418 data = parser.get_data()
419 blob_marks[mark] = data
420 parser.next()
422 class CustomTree():
424 def __init__(self, branch, revid, parents, files):
425 global files_cache
427 self.updates = {}
428 self.branch = branch
430 def copy_tree(revid):
431 files = files_cache[revid] = {}
432 branch.lock_read()
433 tree = branch.repository.revision_tree(revid)
434 try:
435 for path, entry in tree.iter_entries_by_dir():
436 files[path] = [entry.file_id, None]
437 finally:
438 branch.unlock()
439 return files
441 if len(parents) == 0:
442 self.base_id = bzrlib.revision.NULL_REVISION
443 self.base_files = {}
444 else:
445 self.base_id = parents[0]
446 self.base_files = files_cache.get(self.base_id, None)
447 if not self.base_files:
448 self.base_files = copy_tree(self.base_id)
450 self.files = files_cache[revid] = self.base_files.copy()
451 self.rev_files = {}
453 for path, data in self.files.iteritems():
454 fid, mark = data
455 self.rev_files[fid] = [path, mark]
457 for path, f in files.iteritems():
458 fid, mark = self.files.get(path, [None, None])
459 if not fid:
460 fid = bzrlib.generate_ids.gen_file_id(path)
461 f['path'] = path
462 self.rev_files[fid] = [path, mark]
463 self.updates[fid] = f
465 def last_revision(self):
466 return self.base_id
468 def iter_changes(self):
469 changes = []
471 def get_parent(dirname, basename):
472 parent_fid, mark = self.base_files.get(dirname, [None, None])
473 if parent_fid:
474 return parent_fid
475 parent_fid, mark = self.files.get(dirname, [None, None])
476 if parent_fid:
477 return parent_fid
478 if basename == '':
479 return None
480 fid = bzrlib.generate_ids.gen_file_id(path)
481 add_entry(fid, dirname, 'directory')
482 return fid
484 def add_entry(fid, path, kind, mode = None):
485 dirname, basename = os.path.split(path)
486 parent_fid = get_parent(dirname, basename)
488 executable = False
489 if mode == '100755':
490 executable = True
491 elif mode == '120000':
492 kind = 'symlink'
494 change = (fid,
495 (None, path),
496 True,
497 (False, True),
498 (None, parent_fid),
499 (None, basename),
500 (None, kind),
501 (None, executable))
502 self.files[path] = [change[0], None]
503 changes.append(change)
505 def update_entry(fid, path, kind, mode = None):
506 dirname, basename = os.path.split(path)
507 parent_fid = get_parent(dirname, basename)
509 executable = False
510 if mode == '100755':
511 executable = True
512 elif mode == '120000':
513 kind = 'symlink'
515 change = (fid,
516 (path, path),
517 True,
518 (True, True),
519 (None, parent_fid),
520 (None, basename),
521 (None, kind),
522 (None, executable))
523 self.files[path] = [change[0], None]
524 changes.append(change)
526 def remove_entry(fid, path, kind):
527 dirname, basename = os.path.split(path)
528 parent_fid = get_parent(dirname, basename)
529 change = (fid,
530 (path, None),
531 True,
532 (True, False),
533 (parent_fid, None),
534 (None, None),
535 (None, None),
536 (None, None))
537 del self.files[path]
538 changes.append(change)
540 for fid, f in self.updates.iteritems():
541 path = f['path']
543 if 'deleted' in f:
544 remove_entry(fid, path, 'file')
545 continue
547 if path in self.base_files:
548 update_entry(fid, path, 'file', f['mode'])
549 else:
550 add_entry(fid, path, 'file', f['mode'])
552 self.files[path][1] = f['mark']
553 self.rev_files[fid][1] = f['mark']
555 return changes
557 def get_content(self, file_id):
558 path, mark = self.rev_files[file_id]
559 if mark:
560 return blob_marks[mark]
562 # last resort
563 tree = self.branch.repository.revision_tree(self.base_id)
564 return tree.get_file_text(file_id)
566 def get_file_with_stat(self, file_id, path=None):
567 content = self.get_content(file_id)
568 return (StringIO.StringIO(content), None)
570 def get_symlink_target(self, file_id):
571 return self.get_content(file_id)
573 def id2path(self, file_id):
574 path, mark = self.rev_files[file_id]
575 return path
577 def c_style_unescape(string):
578 if string[0] == string[-1] == '"':
579 return string.decode('string-escape')[1:-1]
580 return string
582 def parse_commit(parser):
583 global marks, blob_marks, parsed_refs
584 global mode
586 parents = []
588 ref = parser[1]
589 parser.next()
591 if ref.startswith('refs/heads/'):
592 name = ref[len('refs/heads/'):]
593 branch = get_remote_branch(name)
594 else:
595 die('unknown ref')
597 commit_mark = parser.get_mark()
598 parser.next()
599 author = parser.get_author()
600 parser.next()
601 committer = parser.get_author()
602 parser.next()
603 data = parser.get_data()
604 parser.next()
605 if parser.check('from'):
606 parents.append(parser.get_mark())
607 parser.next()
608 while parser.check('merge'):
609 parents.append(parser.get_mark())
610 parser.next()
612 # fast-export adds an extra newline
613 if data[-1] == '\n':
614 data = data[:-1]
616 files = {}
618 for line in parser:
619 if parser.check('M'):
620 t, m, mark_ref, path = line.split(' ', 3)
621 mark = int(mark_ref[1:])
622 f = { 'mode' : m, 'mark' : mark }
623 elif parser.check('D'):
624 t, path = line.split(' ', 1)
625 f = { 'deleted' : True }
626 else:
627 die('Unknown file command: %s' % line)
628 path = c_style_unescape(path).decode('utf-8')
629 files[path] = f
631 committer, date, tz = committer
632 parents = [mark_to_rev(p) for p in parents]
633 revid = bzrlib.generate_ids.gen_revision_id(committer, date)
634 props = {}
635 props['branch-nick'] = branch.nick
637 mtree = CustomTree(branch, revid, parents, files)
638 changes = mtree.iter_changes()
640 branch.lock_write()
641 try:
642 builder = branch.get_commit_builder(parents, None, date, tz, committer, props, revid)
643 try:
644 list(builder.record_iter_changes(mtree, mtree.last_revision(), changes))
645 builder.finish_inventory()
646 builder.commit(data.decode('utf-8', 'replace'))
647 except Exception, e:
648 builder.abort()
649 raise
650 finally:
651 branch.unlock()
653 parsed_refs[ref] = revid
654 marks.new_mark(revid, commit_mark)
656 def parse_reset(parser):
657 global parsed_refs
659 ref = parser[1]
660 parser.next()
662 # ugh
663 if parser.check('commit'):
664 parse_commit(parser)
665 return
666 if not parser.check('from'):
667 return
668 from_mark = parser.get_mark()
669 parser.next()
671 parsed_refs[ref] = mark_to_rev(from_mark)
673 def do_export(parser):
674 global parsed_refs, dirname
676 parser.next()
678 for line in parser.each_block('done'):
679 if parser.check('blob'):
680 parse_blob(parser)
681 elif parser.check('commit'):
682 parse_commit(parser)
683 elif parser.check('reset'):
684 parse_reset(parser)
685 elif parser.check('tag'):
686 pass
687 elif parser.check('feature'):
688 pass
689 else:
690 die('unhandled export command: %s' % line)
692 for ref, revid in parsed_refs.iteritems():
693 if ref.startswith('refs/heads/'):
694 name = ref[len('refs/heads/'):]
695 branch = get_remote_branch(name)
696 branch.generate_revision_history(revid, marks.get_tip(name))
698 if name in peers:
699 peer = bzrlib.branch.Branch.open(peers[name])
700 try:
701 peer.bzrdir.push_branch(branch, revision_id=revid)
702 except bzrlib.errors.DivergedBranches:
703 print "error %s non-fast forward" % ref
704 continue
706 try:
707 wt = branch.bzrdir.open_workingtree()
708 wt.update()
709 except bzrlib.errors.NoWorkingTree:
710 pass
711 elif ref.startswith('refs/tags/'):
712 # TODO: implement tag push
713 print "error %s pushing tags not supported" % ref
714 continue
715 else:
716 # transport-helper/fast-export bugs
717 continue
719 print "ok %s" % ref
721 print
723 def do_capabilities(parser):
724 global dirname
726 print "import"
727 print "export"
728 print "refspec refs/heads/*:%s/heads/*" % prefix
729 print "refspec refs/tags/*:%s/tags/*" % prefix
731 path = os.path.join(dirname, 'marks-git')
733 if os.path.exists(path):
734 print "*import-marks %s" % path
735 print "*export-marks %s" % path
737 print
739 def ref_is_valid(name):
740 return not True in [c in name for c in '~^: \\']
742 def do_list(parser):
743 global tags
745 master_branch = None
747 for name in branches:
748 if not master_branch:
749 master_branch = name
750 print "? refs/heads/%s" % name
752 branch = get_remote_branch(master_branch)
753 branch.lock_read()
754 for tag, revid in branch.tags.get_tag_dict().items():
755 try:
756 branch.revision_id_to_dotted_revno(revid)
757 except bzrlib.errors.NoSuchRevision:
758 continue
759 if not ref_is_valid(tag):
760 continue
761 print "? refs/tags/%s" % tag
762 tags[tag] = revid
763 branch.unlock()
765 print "@refs/heads/%s HEAD" % master_branch
766 print
768 def clone(path, remote_branch):
769 bdir = bzrlib.bzrdir.BzrDir.create(path)
770 repo = bdir.find_repository()
771 repo.fetch(remote_branch.repository)
772 return remote_branch.sprout(bdir, repository=repo)
774 def get_remote_branch(name):
775 global dirname, branches
777 remote_branch = bzrlib.branch.Branch.open(branches[name])
778 if isinstance(remote_branch.user_transport, bzrlib.transport.local.LocalTransport):
779 return remote_branch
781 branch_path = os.path.join(dirname, 'clone', name)
783 try:
784 branch = bzrlib.branch.Branch.open(branch_path)
785 except bzrlib.errors.NotBranchError:
786 # clone
787 branch = clone(branch_path, remote_branch)
788 else:
789 # pull
790 try:
791 branch.pull(remote_branch, overwrite=True)
792 except bzrlib.errors.DivergedBranches:
793 # use remote branch for now
794 return remote_branch
796 return branch
798 def find_branches(repo):
799 transport = repo.bzrdir.root_transport
801 for fn in transport.iter_files_recursive():
802 if not fn.endswith('.bzr/branch-format'):
803 continue
805 name = subdir = fn[:-len('/.bzr/branch-format')]
806 name = name if name != '' else 'master'
807 name = name.replace('/', '+')
809 try:
810 cur = transport.clone(subdir)
811 branch = bzrlib.branch.Branch.open_from_transport(cur)
812 except bzrlib.errors.NotBranchError:
813 continue
814 else:
815 yield name, branch.base
817 def get_repo(url, alias):
818 global dirname, peer, branches
820 normal_url = bzrlib.urlutils.normalize_url(url)
821 origin = bzrlib.bzrdir.BzrDir.open(url)
822 is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
824 shared_path = os.path.join(gitdir, 'bzr')
825 try:
826 shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path)
827 except bzrlib.errors.NotBranchError:
828 shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path)
829 try:
830 shared_repo = shared_dir.open_repository()
831 except bzrlib.errors.NoRepositoryPresent:
832 shared_repo = shared_dir.create_repository(shared=True)
834 if not is_local:
835 clone_path = os.path.join(dirname, 'clone')
836 if not os.path.exists(clone_path):
837 os.mkdir(clone_path)
838 else:
839 # check and remove old organization
840 try:
841 bdir = bzrlib.bzrdir.BzrDir.open(clone_path)
842 bdir.destroy_repository()
843 except bzrlib.errors.NotBranchError:
844 pass
845 except bzrlib.errors.NoRepositoryPresent:
846 pass
848 wanted = get_config('remote-bzr.branches').rstrip().split(', ')
849 # stupid python
850 wanted = [e for e in wanted if e]
852 if not wanted:
853 try:
854 repo = origin.open_repository()
855 if not repo.user_transport.listable():
856 # this repository is not usable for us
857 raise bzrlib.errors.NoRepositoryPresent(repo.bzrdir)
858 except bzrlib.errors.NoRepositoryPresent:
859 wanted = ['master']
861 if wanted:
862 def list_wanted(url, wanted):
863 for name in wanted:
864 subdir = name if name != 'master' else ''
865 yield name, bzrlib.urlutils.join(url, subdir)
867 branch_list = list_wanted(url, wanted)
868 else:
869 branch_list = find_branches(repo)
871 for name, url in branch_list:
872 if not is_local:
873 peers[name] = url
874 branches[name] = url
876 return origin
878 def fix_path(alias, orig_url):
879 url = urlparse.urlparse(orig_url, 'file')
880 if url.scheme != 'file' or os.path.isabs(url.path):
881 return
882 abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url)
883 cmd = ['git', 'config', 'remote.%s.url' % alias, "bzr::%s" % abs_url]
884 subprocess.call(cmd)
886 def main(args):
887 global marks, prefix, gitdir, dirname
888 global tags, filenodes
889 global blob_marks
890 global parsed_refs
891 global files_cache
892 global is_tmp
893 global branches, peers
895 alias = args[1]
896 url = args[2]
898 tags = {}
899 filenodes = {}
900 blob_marks = {}
901 parsed_refs = {}
902 files_cache = {}
903 marks = None
904 branches = {}
905 peers = {}
907 if alias[5:] == url:
908 is_tmp = True
909 alias = hashlib.sha1(alias).hexdigest()
910 else:
911 is_tmp = False
913 prefix = 'refs/bzr/%s' % alias
914 gitdir = os.environ['GIT_DIR']
915 dirname = os.path.join(gitdir, 'bzr', alias)
917 if not is_tmp:
918 fix_path(alias, url)
920 if not os.path.exists(dirname):
921 os.makedirs(dirname)
923 if hasattr(bzrlib.ui.ui_factory, 'be_quiet'):
924 bzrlib.ui.ui_factory.be_quiet(True)
926 repo = get_repo(url, alias)
928 marks_path = os.path.join(dirname, 'marks-int')
929 marks = Marks(marks_path)
931 parser = Parser(repo)
932 for line in parser:
933 if parser.check('capabilities'):
934 do_capabilities(parser)
935 elif parser.check('list'):
936 do_list(parser)
937 elif parser.check('import'):
938 do_import(parser)
939 elif parser.check('export'):
940 do_export(parser)
941 else:
942 die('unhandled command: %s' % line)
943 sys.stdout.flush()
945 def bye():
946 if not marks:
947 return
948 if not is_tmp:
949 marks.store()
950 else:
951 shutil.rmtree(dirname)
953 atexit.register(bye)
954 sys.exit(main(sys.argv))