Merge lp:~jelmer/brz/git-config-branches into lp:brz

Proposed by Jelmer Vernooij on 2018-11-01
Status: Merged
Approved by: Jelmer Vernooij on 2019-03-04
Approved revision: 7148
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/git-config-branches
Merge into: lp:brz
Diff against target: 302 lines (+139/-55)
6 files modified
breezy/git/branch.py (+68/-35)
breezy/git/tests/test_urls.py (+23/-4)
breezy/git/urls.py (+39/-12)
breezy/tests/per_branch/test_branch.py (+3/-1)
breezy/tests/per_branch/test_sprout.py (+4/-1)
breezy/urlutils.py (+2/-2)
To merge this branch: bzr merge lp:~jelmer/brz/git-config-branches
Reviewer Review Type Date Requested Status
Martin Packman 2018-11-01 Approve on 2018-11-16
Review via email: mp+358140@code.launchpad.net

Commit message

Support reading related branches from git configs.

Description of the change

Support reading related branches from git configs.

To post a comment you must log in.
Martin Packman (gz) wrote :

Looks good, see a couple of inline comments.

review: Approve
lp:~jelmer/brz/git-config-branches updated on 2019-03-04
7147. By Jelmer Vernooij on 2019-03-04

Merge trunk.

7148. By Jelmer Vernooij on 2019-03-04

Fix tests.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'breezy/git/branch.py'
--- breezy/git/branch.py 2019-01-19 17:13:53 +0000
+++ breezy/git/branch.py 2019-03-04 05:19:37 +0000
@@ -76,7 +76,10 @@
76from .unpeel_map import (76from .unpeel_map import (
77 UnpeelMap,77 UnpeelMap,
78 )78 )
79from .urls import git_url_to_bzr_url79from .urls import (
80 git_url_to_bzr_url,
81 bzr_url_to_git_url,
82 )
8083
8184
82class GitPullResult(branch.PullResult):85class GitPullResult(branch.PullResult):
@@ -464,49 +467,76 @@
464 # Git doesn't do stacking (yet...)467 # Git doesn't do stacking (yet...)
465 raise branch.UnstackableBranchFormat(self._format, self.base)468 raise branch.UnstackableBranchFormat(self._format, self.base)
466469
470 def _get_push_origin(self, cs):
471 """Get the name for the push origin.
472
473 The exact behaviour is documented in the git-config(1) manpage.
474 """
475 try:
476 return cs.get((b'branch', self.name.encode('utf-8')), b'pushRemote')
477 except KeyError:
478 try:
479 return cs.get((b'branch', ), b'remote')
480 except KeyError:
481 try:
482 return cs.get((b'branch', self.name.encode('utf-8')), b'remote')
483 except KeyError:
484 return b'origin'
485
486 def _get_origin(self, cs):
487 try:
488 return cs.get((b'branch', self.name.encode('utf-8')), b'remote')
489 except KeyError:
490 return b'origin'
491
492 def _get_related_push_branch(self, cs):
493 remote = self._get_push_origin(cs)
494 try:
495 location = cs.get((b"remote", remote), b"url")
496 except KeyError:
497 return None
498
499 return git_url_to_bzr_url(location.decode('utf-8'), ref=self.ref)
500
501 def _get_related_merge_branch(self, cs):
502 remote = self._get_origin(cs)
503 try:
504 location = cs.get((b"remote", remote), b"url")
505 except KeyError:
506 return None
507
508 try:
509 ref = cs.get((b"branch", remote), b"merge")
510 except KeyError:
511 ref = self.ref
512
513 return git_url_to_bzr_url(location.decode('utf-8'), ref=ref)
514
467 def _get_parent_location(self):515 def _get_parent_location(self):
468 """See Branch.get_parent()."""516 """See Branch.get_parent()."""
469 # FIXME: Set "origin" url from .git/config ?
470 cs = self.repository._git.get_config_stack()517 cs = self.repository._git.get_config_stack()
471 try:518 return self._get_related_merge_branch(cs)
472 location = cs.get((b"remote", b'origin'), b"url")519
473 except KeyError:520 def _write_git_config(self, cs):
474 return None521 f = BytesIO()
475522 cs.write_to_file(f)
476 params = {}523 self.repository._git._put_named_file('config', f.getvalue())
477 try:
478 ref = cs.get((b"remote", b"origin"), b"merge")
479 except KeyError:
480 pass
481 else:
482 if ref != b'HEAD':
483 try:
484 params['branch'] = urlutils.escape(ref_to_branch_name(ref))
485 except ValueError:
486 params['ref'] = urlutils.quote_from_bytes(ref)
487
488 url = git_url_to_bzr_url(location.decode('utf-8'))
489 return urlutils.join_segment_parameters(url, params)
490524
491 def set_parent(self, location):525 def set_parent(self, location):
492 # FIXME: Set "origin" url in .git/config ?
493 cs = self.repository._git.get_config()526 cs = self.repository._git.get_config()
527 remote = self._get_origin(cs)
494 this_url = urlutils.split_segment_parameters(self.user_url)[0]528 this_url = urlutils.split_segment_parameters(self.user_url)[0]
495 target_url, target_params = urlutils.split_segment_parameters(location)529 target_url, branch, ref = bzr_url_to_git_url(location)
496 location = urlutils.relative_url(this_url, target_url)530 location = urlutils.relative_url(this_url, target_url)
497 cs.set((b"remote", b"origin"), b"url", location)531 cs.set((b"remote", remote), b"url", location)
498 if 'branch' in target_params:532 if branch:
499 cs.set((b"remote", b"origin"), b"merge",533 cs.set((b"branch", remote), b"merge", branch_name_to_ref(branch))
500 branch_name_to_ref(target_params['branch']))534 elif ref:
501 elif 'ref' in target_params:535 cs.set((b"branch", remote), b"merge", ref)
502 cs.set((b"remote", b"origin"), b"merge",
503 target_params['ref'])
504 else:536 else:
505 # TODO(jelmer): Maybe unset rather than setting to HEAD?537 # TODO(jelmer): Maybe unset rather than setting to HEAD?
506 cs.set((b"remote", b"origin"), b"merge", 'HEAD')538 cs.set((b"branch", remote), b"merge", b'HEAD')
507 f = BytesIO()539 self._write_git_config(cs)
508 cs.write_to_file(f)
509 self.repository._git._put_named_file('config', f.getvalue())
510540
511 def break_lock(self):541 def break_lock(self):
512 raise NotImplementedError(self.break_lock)542 raise NotImplementedError(self.break_lock)
@@ -720,7 +750,10 @@
720 def get_push_location(self):750 def get_push_location(self):
721 """See Branch.get_push_location."""751 """See Branch.get_push_location."""
722 push_loc = self.get_config_stack().get('push_location')752 push_loc = self.get_config_stack().get('push_location')
723 return push_loc753 if push_loc is not None:
754 return push_loc
755 cs = self.repository._git.get_config_stack()
756 return self._get_related_push_branch(cs)
724757
725 def set_push_location(self, location):758 def set_push_location(self, location):
726 """See Branch.set_push_location."""759 """See Branch.set_push_location."""
727760
=== modified file 'breezy/git/tests/test_urls.py'
--- breezy/git/tests/test_urls.py 2018-11-11 04:08:32 +0000
+++ breezy/git/tests/test_urls.py 2019-03-04 05:19:37 +0000
@@ -42,7 +42,26 @@
42 ('git+ssh://user@foo/bar/path'))42 ('git+ssh://user@foo/bar/path'))
4343
44 def test_path(self):44 def test_path(self):
45 self.assertEqual(45 self.assertEqual(git_url_to_bzr_url('/bar/path'), ('/bar/path'))
46 git_url_to_bzr_url(46
47 '/bar/path'),47 def test_with_ref(self):
48 ('/bar/path'))48 self.assertEqual(
49 git_url_to_bzr_url('foo:bar/path', ref=b'HEAD'),
50 'git+ssh://foo/bar/path')
51 self.assertEqual(
52 git_url_to_bzr_url('foo:bar/path', ref=b'refs/heads/blah'),
53 'git+ssh://foo/bar/path,branch=blah')
54 self.assertEqual(
55 git_url_to_bzr_url('foo:bar/path', ref=b'refs/tags/blah'),
56 'git+ssh://foo/bar/path,ref=refs%2Ftags%2Fblah')
57
58 def test_with_branch(self):
59 self.assertEqual(
60 git_url_to_bzr_url('foo:bar/path', branch=''),
61 'git+ssh://foo/bar/path')
62 self.assertEqual(
63 git_url_to_bzr_url('foo:bar/path', branch='foo/blah'),
64 'git+ssh://foo/bar/path,branch=foo%2Fblah')
65 self.assertEqual(
66 git_url_to_bzr_url('foo:bar/path', branch='blah'),
67 'git+ssh://foo/bar/path,branch=blah')
4968
=== modified file 'breezy/git/urls.py'
--- breezy/git/urls.py 2018-11-11 14:23:06 +0000
+++ breezy/git/urls.py 2019-03-04 05:19:37 +0000
@@ -18,7 +18,10 @@
1818
19from __future__ import absolute_import19from __future__ import absolute_import
2020
21from breezy.urlutils import URL, quote21from .. import urlutils
22from .refs import (
23 ref_to_branch_name,
24 )
2225
23from dulwich.client import parse_rsync_url26from dulwich.client import parse_rsync_url
2427
@@ -26,22 +29,46 @@
26KNOWN_GIT_SCHEMES = ['git+ssh', 'git', 'http', 'https', 'ftp']29KNOWN_GIT_SCHEMES = ['git+ssh', 'git', 'http', 'https', 'ftp']
2730
2831
29def git_url_to_bzr_url(location):32def git_url_to_bzr_url(location, branch=None, ref=None):
30 url = URL.from_string(location)33 if branch is not None and ref is not None:
31 if (url.scheme not in KNOWN_GIT_SCHEMES34 raise ValueError('only specify one of branch or ref')
32 and not url.scheme.startswith('chroot-')):35 url = urlutils.URL.from_string(location)
36 if (url.scheme not in KNOWN_GIT_SCHEMES and
37 not url.scheme.startswith('chroot-')):
33 try:38 try:
34 (username, host, path) = parse_rsync_url(location)39 (username, host, path) = parse_rsync_url(location)
35 except ValueError:40 except ValueError:
36 return location41 return location
37 else:42 else:
38 url = URL(43 url = urlutils.URL(
39 scheme='git+ssh',44 scheme='git+ssh',
40 quoted_user=(quote(username) if username else None),45 quoted_user=(urlutils.quote(username) if username else None),
41 quoted_password=None,46 quoted_password=None,
42 quoted_host=quote(host),47 quoted_host=urlutils.quote(host),
43 port=None,48 port=None,
44 quoted_path=quote(path, safe="/~"))49 quoted_path=urlutils.quote(path, safe="/~"))
45 return str(url)50 location = str(url)
46 else:51 if ref == b'HEAD':
47 return location52 ref = branch = None
53 if ref:
54 try:
55 branch = ref_to_branch_name(ref)
56 except ValueError:
57 branch = None
58 else:
59 ref = None
60 if ref or branch:
61 params = {}
62 if ref:
63 params['ref'] = urlutils.quote_from_bytes(ref, safe='')
64 if branch:
65 params['branch'] = urlutils.escape(branch, safe='')
66 location = urlutils.join_segment_parameters(location, params)
67 return location
68
69
70def bzr_url_to_git_url(location):
71 target_url, target_params = urlutils.split_segment_parameters(location)
72 branch = target_params.get('branch')
73 ref = target_params.get('ref')
74 return target_url, branch, ref
4875
=== modified file 'breezy/tests/per_branch/test_branch.py'
--- breezy/tests/per_branch/test_branch.py 2018-11-11 04:08:32 +0000
+++ breezy/tests/per_branch/test_branch.py 2019-03-04 05:19:37 +0000
@@ -164,7 +164,9 @@
164164
165 branch_b = wt_a.branch.controldir.sprout(165 branch_b = wt_a.branch.controldir.sprout(
166 'b', revision_id=rev1).open_branch()166 'b', revision_id=rev1).open_branch()
167 self.assertEqual(wt_a.branch.user_url, branch_b.get_parent())167 self.assertEqual(
168 urlutils.split_segment_parameters(wt_a.branch.user_url)[0],
169 urlutils.split_segment_parameters(branch_b.get_parent())[0])
168 return branch_b170 return branch_b
169171
170 def test_clone_branch_nickname(self):172 def test_clone_branch_nickname(self):
171173
=== modified file 'breezy/tests/per_branch/test_sprout.py'
--- breezy/tests/per_branch/test_sprout.py 2018-11-11 04:08:32 +0000
+++ breezy/tests/per_branch/test_sprout.py 2019-03-04 05:19:37 +0000
@@ -23,6 +23,7 @@
23 osutils,23 osutils,
24 revision as _mod_revision,24 revision as _mod_revision,
25 tests,25 tests,
26 urlutils,
26 )27 )
27from breezy.bzr import (28from breezy.bzr import (
28 branch as _mod_bzrbranch,29 branch as _mod_bzrbranch,
@@ -43,7 +44,9 @@
43 def test_sprout_branch_parent(self):44 def test_sprout_branch_parent(self):
44 source = self.make_branch('source')45 source = self.make_branch('source')
45 target = source.controldir.sprout(self.get_url('target')).open_branch()46 target = source.controldir.sprout(self.get_url('target')).open_branch()
46 self.assertEqual(source.user_url, target.get_parent())47 self.assertEqual(
48 urlutils.split_segment_parameters(source.user_url)[0],
49 urlutils.split_segment_parameters(target.get_parent())[0])
4750
48 def test_sprout_uses_bzrdir_branch_format(self):51 def test_sprout_uses_bzrdir_branch_format(self):
49 # branch.sprout(bzrdir) is defined as using the branch format selected52 # branch.sprout(bzrdir) is defined as using the branch format selected
5053
=== modified file 'breezy/urlutils.py'
--- breezy/urlutils.py 2018-11-12 01:41:38 +0000
+++ breezy/urlutils.py 2019-03-04 05:19:37 +0000
@@ -162,11 +162,11 @@
162unquote = urlparse.unquote162unquote = urlparse.unquote
163163
164164
165def escape(relpath):165def escape(relpath, safe='/~'):
166 """Escape relpath to be a valid url."""166 """Escape relpath to be a valid url."""
167 if not isinstance(relpath, str) and sys.version_info[0] == 2:167 if not isinstance(relpath, str) and sys.version_info[0] == 2:
168 relpath = relpath.encode('utf-8')168 relpath = relpath.encode('utf-8')
169 return quote(relpath, safe='/~')169 return quote(relpath, safe=safe)
170170
171171
172def file_relpath(base, path):172def file_relpath(base, path):

Subscribers

People subscribed via source and target branches