l10n: Update Swedish translation (2228t0f0u)
[alt-git.git] / contrib / remote-helpers / git-remote-bzr
blob9abb58e6ab45077bf9b5e01658438817ea9b7126
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 author, _, _ = author
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
626 props['authors'] = author
628 mtree = CustomTree(branch, revid, parents, files)
629 changes = mtree.iter_changes()
631 branch.lock_write()
632 try:
633 builder = branch.get_commit_builder(parents, None, date, tz, committer, props, revid)
634 try:
635 list(builder.record_iter_changes(mtree, mtree.last_revision(), changes))
636 builder.finish_inventory()
637 builder.commit(data.decode('utf-8', 'replace'))
638 except Exception, e:
639 builder.abort()
640 raise
641 finally:
642 branch.unlock()
644 parsed_refs[ref] = revid
645 marks.new_mark(revid, commit_mark)
647 def parse_reset(parser):
648 ref = parser[1]
649 parser.next()
651 # ugh
652 if parser.check('commit'):
653 parse_commit(parser)
654 return
655 if not parser.check('from'):
656 return
657 from_mark = parser.get_mark()
658 parser.next()
660 parsed_refs[ref] = mark_to_rev(from_mark)
662 def do_export(parser):
663 parser.next()
665 for line in parser.each_block('done'):
666 if parser.check('blob'):
667 parse_blob(parser)
668 elif parser.check('commit'):
669 parse_commit(parser)
670 elif parser.check('reset'):
671 parse_reset(parser)
672 elif parser.check('tag'):
673 pass
674 elif parser.check('feature'):
675 pass
676 else:
677 die('unhandled export command: %s' % line)
679 for ref, revid in parsed_refs.iteritems():
680 if ref.startswith('refs/heads/'):
681 name = ref[len('refs/heads/'):]
682 branch = get_remote_branch(name)
683 branch.generate_revision_history(revid, marks.get_tip(name))
685 if name in peers:
686 peer = bzrlib.branch.Branch.open(peers[name],
687 possible_transports=transports)
688 try:
689 peer.bzrdir.push_branch(branch, revision_id=revid,
690 overwrite=force)
691 except bzrlib.errors.DivergedBranches:
692 print "error %s non-fast forward" % ref
693 continue
695 try:
696 wt = branch.bzrdir.open_workingtree()
697 wt.update()
698 except bzrlib.errors.NoWorkingTree:
699 pass
700 elif ref.startswith('refs/tags/'):
701 # TODO: implement tag push
702 print "error %s pushing tags not supported" % ref
703 continue
704 else:
705 # transport-helper/fast-export bugs
706 continue
708 print "ok %s" % ref
710 print
712 def do_capabilities(parser):
713 print "import"
714 print "export"
715 print "refspec refs/heads/*:%s/heads/*" % prefix
716 print "refspec refs/tags/*:%s/tags/*" % prefix
718 path = os.path.join(dirname, 'marks-git')
720 if os.path.exists(path):
721 print "*import-marks %s" % path
722 print "*export-marks %s" % path
724 print "option"
725 print
727 class InvalidOptionValue(Exception):
728 pass
730 def get_bool_option(val):
731 if val == 'true':
732 return True
733 elif val == 'false':
734 return False
735 else:
736 raise InvalidOptionValue()
738 def do_option(parser):
739 global force
740 opt, val = parser[1:3]
741 try:
742 if opt == 'force':
743 force = get_bool_option(val)
744 print 'ok'
745 else:
746 print 'unsupported'
747 except InvalidOptionValue:
748 print "error '%s' is not a valid value for option '%s'" % (val, opt)
750 def ref_is_valid(name):
751 return not True in [c in name for c in '~^: \\']
753 def do_list(parser):
754 master_branch = None
756 for name in branches:
757 if not master_branch:
758 master_branch = name
759 print "? refs/heads/%s" % name
761 branch = get_remote_branch(master_branch)
762 branch.lock_read()
763 for tag, revid in branch.tags.get_tag_dict().items():
764 try:
765 branch.revision_id_to_dotted_revno(revid)
766 except bzrlib.errors.NoSuchRevision:
767 continue
768 if not ref_is_valid(tag):
769 continue
770 print "? refs/tags/%s" % tag
771 tags[tag] = revid
772 branch.unlock()
774 print "@refs/heads/%s HEAD" % master_branch
775 print
777 def clone(path, remote_branch):
778 try:
779 bdir = bzrlib.bzrdir.BzrDir.create(path, possible_transports=transports)
780 except bzrlib.errors.AlreadyControlDirError:
781 bdir = bzrlib.bzrdir.BzrDir.open(path, possible_transports=transports)
782 repo = bdir.find_repository()
783 repo.fetch(remote_branch.repository)
784 return remote_branch.sprout(bdir, repository=repo)
786 def get_remote_branch(name):
787 remote_branch = bzrlib.branch.Branch.open(branches[name],
788 possible_transports=transports)
789 if isinstance(remote_branch.bzrdir.root_transport, bzrlib.transport.local.LocalTransport):
790 return remote_branch
792 branch_path = os.path.join(dirname, 'clone', name)
794 try:
795 branch = bzrlib.branch.Branch.open(branch_path,
796 possible_transports=transports)
797 except bzrlib.errors.NotBranchError:
798 # clone
799 branch = clone(branch_path, remote_branch)
800 else:
801 # pull
802 try:
803 branch.pull(remote_branch, overwrite=True)
804 except bzrlib.errors.DivergedBranches:
805 # use remote branch for now
806 return remote_branch
808 return branch
810 def find_branches(repo):
811 transport = repo.bzrdir.root_transport
813 for fn in transport.iter_files_recursive():
814 if not fn.endswith('.bzr/branch-format'):
815 continue
817 name = subdir = fn[:-len('/.bzr/branch-format')]
818 name = name if name != '' else 'master'
819 name = name.replace('/', '+')
821 try:
822 cur = transport.clone(subdir)
823 branch = bzrlib.branch.Branch.open_from_transport(cur)
824 except bzrlib.errors.NotBranchError:
825 continue
826 else:
827 yield name, branch.base
829 def get_repo(url, alias):
830 normal_url = bzrlib.urlutils.normalize_url(url)
831 origin = bzrlib.bzrdir.BzrDir.open(url, possible_transports=transports)
832 is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
834 shared_path = os.path.join(gitdir, 'bzr')
835 try:
836 shared_dir = bzrlib.bzrdir.BzrDir.open(shared_path,
837 possible_transports=transports)
838 except bzrlib.errors.NotBranchError:
839 shared_dir = bzrlib.bzrdir.BzrDir.create(shared_path,
840 possible_transports=transports)
841 try:
842 shared_repo = shared_dir.open_repository()
843 except bzrlib.errors.NoRepositoryPresent:
844 shared_repo = shared_dir.create_repository(shared=True)
846 if not is_local:
847 clone_path = os.path.join(dirname, 'clone')
848 if not os.path.exists(clone_path):
849 os.mkdir(clone_path)
850 else:
851 # check and remove old organization
852 try:
853 bdir = bzrlib.bzrdir.BzrDir.open(clone_path,
854 possible_transports=transports)
855 bdir.destroy_repository()
856 except bzrlib.errors.NotBranchError:
857 pass
858 except bzrlib.errors.NoRepositoryPresent:
859 pass
861 wanted = get_config('remote.%s.bzr-branches' % alias).rstrip().split(', ')
862 # stupid python
863 wanted = [e for e in wanted if e]
864 if not wanted:
865 wanted = get_config('remote-bzr.branches').rstrip().split(', ')
866 # stupid python
867 wanted = [e for e in wanted if e]
869 if not wanted:
870 try:
871 repo = origin.open_repository()
872 if not repo.bzrdir.root_transport.listable():
873 # this repository is not usable for us
874 raise bzrlib.errors.NoRepositoryPresent(repo.bzrdir)
875 except bzrlib.errors.NoRepositoryPresent:
876 wanted = ['master']
878 if wanted:
879 def list_wanted(url, wanted):
880 for name in wanted:
881 subdir = name if name != 'master' else ''
882 yield name, bzrlib.urlutils.join(url, subdir)
884 branch_list = list_wanted(url, wanted)
885 else:
886 branch_list = find_branches(repo)
888 for name, url in branch_list:
889 if not is_local:
890 peers[name] = url
891 branches[name] = url
893 return origin
895 def fix_path(alias, orig_url):
896 url = urlparse.urlparse(orig_url, 'file')
897 if url.scheme != 'file' or os.path.isabs(url.path):
898 return
899 abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url)
900 cmd = ['git', 'config', 'remote.%s.url' % alias, "bzr::%s" % abs_url]
901 subprocess.call(cmd)
903 def main(args):
904 global marks, prefix, gitdir, dirname
905 global tags, filenodes
906 global blob_marks
907 global parsed_refs
908 global files_cache
909 global is_tmp
910 global branches, peers
911 global transports
912 global force
914 marks = None
915 is_tmp = False
916 gitdir = os.environ.get('GIT_DIR', None)
918 if len(args) < 3:
919 die('Not enough arguments.')
921 if not gitdir:
922 die('GIT_DIR not set')
924 alias = args[1]
925 url = args[2]
927 tags = {}
928 filenodes = {}
929 blob_marks = {}
930 parsed_refs = {}
931 files_cache = {}
932 branches = {}
933 peers = {}
934 transports = []
935 force = False
937 if alias[5:] == url:
938 is_tmp = True
939 alias = hashlib.sha1(alias).hexdigest()
941 prefix = 'refs/bzr/%s' % alias
942 dirname = os.path.join(gitdir, 'bzr', alias)
944 if not is_tmp:
945 fix_path(alias, url)
947 if not os.path.exists(dirname):
948 os.makedirs(dirname)
950 if hasattr(bzrlib.ui.ui_factory, 'be_quiet'):
951 bzrlib.ui.ui_factory.be_quiet(True)
953 repo = get_repo(url, alias)
955 marks_path = os.path.join(dirname, 'marks-int')
956 marks = Marks(marks_path)
958 parser = Parser(repo)
959 for line in parser:
960 if parser.check('capabilities'):
961 do_capabilities(parser)
962 elif parser.check('list'):
963 do_list(parser)
964 elif parser.check('import'):
965 do_import(parser)
966 elif parser.check('export'):
967 do_export(parser)
968 elif parser.check('option'):
969 do_option(parser)
970 else:
971 die('unhandled command: %s' % line)
972 sys.stdout.flush()
974 def bye():
975 if not marks:
976 return
977 if not is_tmp:
978 marks.store()
979 else:
980 shutil.rmtree(dirname)
982 atexit.register(bye)
983 sys.exit(main(sys.argv))