C: have space around && and || operators
[git.git] / contrib / remote-helpers / git-remote-bzr
blob054161ae21b0c884d314c984992a6c7aa8276a96
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 possible_transports=transports)
687 try:
688 peer.bzrdir.push_branch(branch, revision_id=revid)
689 except bzrlib.errors.DivergedBranches:
690 print "error %s non-fast forward" % ref
691 continue
693 try:
694 wt = branch.bzrdir.open_workingtree()
695 wt.update()
696 except bzrlib.errors.NoWorkingTree:
697 pass
698 elif ref.startswith('refs/tags/'):
699 # TODO: implement tag push
700 print "error %s pushing tags not supported" % ref
701 continue
702 else:
703 # transport-helper/fast-export bugs
704 continue
706 print "ok %s" % ref
708 print
710 def do_capabilities(parser):
711 print "import"
712 print "export"
713 print "refspec refs/heads/*:%s/heads/*" % prefix
714 print "refspec refs/tags/*:%s/tags/*" % prefix
716 path = os.path.join(dirname, 'marks-git')
718 if os.path.exists(path):
719 print "*import-marks %s" % path
720 print "*export-marks %s" % path
722 print
724 def ref_is_valid(name):
725 return not True in [c in name for c in '~^: \\']
727 def do_list(parser):
728 master_branch = None
730 for name in branches:
731 if not master_branch:
732 master_branch = name
733 print "? refs/heads/%s" % name
735 branch = get_remote_branch(master_branch)
736 branch.lock_read()
737 for tag, revid in branch.tags.get_tag_dict().items():
738 try:
739 branch.revision_id_to_dotted_revno(revid)
740 except bzrlib.errors.NoSuchRevision:
741 continue
742 if not ref_is_valid(tag):
743 continue
744 print "? refs/tags/%s" % tag
745 tags[tag] = revid
746 branch.unlock()
748 print "@refs/heads/%s HEAD" % master_branch
749 print
751 def clone(path, remote_branch):
752 try:
753 bdir = bzrlib.bzrdir.BzrDir.create(path, possible_transports=transports)
754 except bzrlib.errors.AlreadyControlDirError:
755 bdir = bzrlib.bzrdir.BzrDir.open(path, possible_transports=transports)
756 repo = bdir.find_repository()
757 repo.fetch(remote_branch.repository)
758 return remote_branch.sprout(bdir, repository=repo)
760 def get_remote_branch(name):
761 remote_branch = bzrlib.branch.Branch.open(branches[name],
762 possible_transports=transports)
763 if isinstance(remote_branch.user_transport, bzrlib.transport.local.LocalTransport):
764 return remote_branch
766 branch_path = os.path.join(dirname, 'clone', name)
768 try:
769 branch = bzrlib.branch.Branch.open(branch_path,
770 possible_transports=transports)
771 except bzrlib.errors.NotBranchError:
772 # clone
773 branch = clone(branch_path, remote_branch)
774 else:
775 # pull
776 try:
777 branch.pull(remote_branch, overwrite=True)
778 except bzrlib.errors.DivergedBranches:
779 # use remote branch for now
780 return remote_branch
782 return branch
784 def find_branches(repo):
785 transport = repo.bzrdir.root_transport
787 for fn in transport.iter_files_recursive():
788 if not fn.endswith('.bzr/branch-format'):
789 continue
791 name = subdir = fn[:-len('/.bzr/branch-format')]
792 name = name if name != '' else 'master'
793 name = name.replace('/', '+')
795 try:
796 cur = transport.clone(subdir)
797 branch = bzrlib.branch.Branch.open_from_transport(cur)
798 except bzrlib.errors.NotBranchError:
799 continue
800 else:
801 yield name, branch.base
803 def get_repo(url, alias):
804 normal_url = bzrlib.urlutils.normalize_url(url)
805 origin = bzrlib.bzrdir.BzrDir.open(url, possible_transports=transports)
806 is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
808 shared_path = os.path.join(gitdir, 'bzr')
809 try:
810 shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path,
811 possible_transports=transports)
812 except bzrlib.errors.NotBranchError:
813 shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path,
814 possible_transports=transports)
815 try:
816 shared_repo = shared_dir.open_repository()
817 except bzrlib.errors.NoRepositoryPresent:
818 shared_repo = shared_dir.create_repository(shared=True)
820 if not is_local:
821 clone_path = os.path.join(dirname, 'clone')
822 if not os.path.exists(clone_path):
823 os.mkdir(clone_path)
824 else:
825 # check and remove old organization
826 try:
827 bdir = bzrlib.bzrdir.BzrDir.open(clone_path,
828 possible_transports=transports)
829 bdir.destroy_repository()
830 except bzrlib.errors.NotBranchError:
831 pass
832 except bzrlib.errors.NoRepositoryPresent:
833 pass
835 wanted = get_config('remote.%s.bzr-branches' % alias).rstrip().split(', ')
836 # stupid python
837 wanted = [e for e in wanted if e]
838 if not wanted:
839 wanted = get_config('remote-bzr.branches').rstrip().split(', ')
840 # stupid python
841 wanted = [e for e in wanted if e]
843 if not wanted:
844 try:
845 repo = origin.open_repository()
846 if not repo.user_transport.listable():
847 # this repository is not usable for us
848 raise bzrlib.errors.NoRepositoryPresent(repo.bzrdir)
849 except bzrlib.errors.NoRepositoryPresent:
850 wanted = ['master']
852 if wanted:
853 def list_wanted(url, wanted):
854 for name in wanted:
855 subdir = name if name != 'master' else ''
856 yield name, bzrlib.urlutils.join(url, subdir)
858 branch_list = list_wanted(url, wanted)
859 else:
860 branch_list = find_branches(repo)
862 for name, url in branch_list:
863 if not is_local:
864 peers[name] = url
865 branches[name] = url
867 return origin
869 def fix_path(alias, orig_url):
870 url = urlparse.urlparse(orig_url, 'file')
871 if url.scheme != 'file' or os.path.isabs(url.path):
872 return
873 abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url)
874 cmd = ['git', 'config', 'remote.%s.url' % alias, "bzr::%s" % abs_url]
875 subprocess.call(cmd)
877 def main(args):
878 global marks, prefix, gitdir, dirname
879 global tags, filenodes
880 global blob_marks
881 global parsed_refs
882 global files_cache
883 global is_tmp
884 global branches, peers
885 global transports
887 alias = args[1]
888 url = args[2]
890 tags = {}
891 filenodes = {}
892 blob_marks = {}
893 parsed_refs = {}
894 files_cache = {}
895 marks = None
896 branches = {}
897 peers = {}
898 transports = []
900 if alias[5:] == url:
901 is_tmp = True
902 alias = hashlib.sha1(alias).hexdigest()
903 else:
904 is_tmp = False
906 prefix = 'refs/bzr/%s' % alias
907 gitdir = os.environ['GIT_DIR']
908 dirname = os.path.join(gitdir, 'bzr', alias)
910 if not is_tmp:
911 fix_path(alias, url)
913 if not os.path.exists(dirname):
914 os.makedirs(dirname)
916 if hasattr(bzrlib.ui.ui_factory, 'be_quiet'):
917 bzrlib.ui.ui_factory.be_quiet(True)
919 repo = get_repo(url, alias)
921 marks_path = os.path.join(dirname, 'marks-int')
922 marks = Marks(marks_path)
924 parser = Parser(repo)
925 for line in parser:
926 if parser.check('capabilities'):
927 do_capabilities(parser)
928 elif parser.check('list'):
929 do_list(parser)
930 elif parser.check('import'):
931 do_import(parser)
932 elif parser.check('export'):
933 do_export(parser)
934 else:
935 die('unhandled command: %s' % line)
936 sys.stdout.flush()
938 def bye():
939 if not marks:
940 return
941 if not is_tmp:
942 marks.store()
943 else:
944 shutil.rmtree(dirname)
946 atexit.register(bye)
947 sys.exit(main(sys.argv))