##// END OF EJS Templates
remotenames: add new namespaces for remotebookmarks and remotebranches...
Pulkit Goyal -
r36079:382aefea default
parent child Browse files
Show More
@@ -1,150 +1,207 b''
1 # remotenames.py - extension to display remotenames
1 # remotenames.py - extension to display remotenames
2 #
2 #
3 # Copyright 2017 Augie Fackler <raf@durin42.com>
3 # Copyright 2017 Augie Fackler <raf@durin42.com>
4 # Copyright 2017 Sean Farley <sean@farley.io>
4 # Copyright 2017 Sean Farley <sean@farley.io>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 """ showing remotebookmarks and remotebranches in UI """
9 """ showing remotebookmarks and remotebranches in UI
10
11 By default both remotebookmarks and remotebranches are turned on. Config knob to
12 control the individually are as follows.
13
14 Config options to tweak the default behaviour:
15
16 remotenames.bookmarks
17 Boolean value to enable or disable showing of remotebookmarks
18
19 remotenames.branches
20 Boolean value to enable or disable showing of remotebranches
21 """
10
22
11 from __future__ import absolute_import
23 from __future__ import absolute_import
12
24
13 import UserDict
25 import UserDict
14
26
15 from mercurial.node import (
27 from mercurial.node import (
16 bin,
28 bin,
17 )
29 )
18 from mercurial import (
30 from mercurial import (
19 logexchange,
31 logexchange,
32 namespaces,
33 registrar,
20 )
34 )
21
35
22 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
36 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
23 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
37 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
24 # be specifying the version(s) of Mercurial they are tested with, or
38 # be specifying the version(s) of Mercurial they are tested with, or
25 # leave the attribute unspecified.
39 # leave the attribute unspecified.
26 testedwith = 'ships-with-hg-core'
40 testedwith = 'ships-with-hg-core'
27
41
42 configtable = {}
43 configitem = registrar.configitem(configtable)
44
45 configitem('remotenames', 'bookmarks',
46 default=True,
47 )
48 configitem('remotenames', 'branches',
49 default=True,
50 )
51
28 class lazyremotenamedict(UserDict.DictMixin):
52 class lazyremotenamedict(UserDict.DictMixin):
29 """
53 """
30 Read-only dict-like Class to lazily resolve remotename entries
54 Read-only dict-like Class to lazily resolve remotename entries
31
55
32 We are doing that because remotenames startup was slow.
56 We are doing that because remotenames startup was slow.
33 We lazily read the remotenames file once to figure out the potential entries
57 We lazily read the remotenames file once to figure out the potential entries
34 and store them in self.potentialentries. Then when asked to resolve an
58 and store them in self.potentialentries. Then when asked to resolve an
35 entry, if it is not in self.potentialentries, then it isn't there, if it
59 entry, if it is not in self.potentialentries, then it isn't there, if it
36 is in self.potentialentries we resolve it and store the result in
60 is in self.potentialentries we resolve it and store the result in
37 self.cache. We cannot be lazy is when asked all the entries (keys).
61 self.cache. We cannot be lazy is when asked all the entries (keys).
38 """
62 """
39 def __init__(self, kind, repo):
63 def __init__(self, kind, repo):
40 self.cache = {}
64 self.cache = {}
41 self.potentialentries = {}
65 self.potentialentries = {}
42 self._kind = kind # bookmarks or branches
66 self._kind = kind # bookmarks or branches
43 self._repo = repo
67 self._repo = repo
44 self.loaded = False
68 self.loaded = False
45
69
46 def _load(self):
70 def _load(self):
47 """ Read the remotenames file, store entries matching selected kind """
71 """ Read the remotenames file, store entries matching selected kind """
48 self.loaded = True
72 self.loaded = True
49 repo = self._repo
73 repo = self._repo
50 for node, rpath, rname in logexchange.readremotenamefile(repo,
74 for node, rpath, rname in logexchange.readremotenamefile(repo,
51 self._kind):
75 self._kind):
52 name = rpath + '/' + rname
76 name = rpath + '/' + rname
53 self.potentialentries[name] = (node, rpath, name)
77 self.potentialentries[name] = (node, rpath, name)
54
78
55 def _resolvedata(self, potentialentry):
79 def _resolvedata(self, potentialentry):
56 """ Check that the node for potentialentry exists and return it """
80 """ Check that the node for potentialentry exists and return it """
57 if not potentialentry in self.potentialentries:
81 if not potentialentry in self.potentialentries:
58 return None
82 return None
59 node, remote, name = self.potentialentries[potentialentry]
83 node, remote, name = self.potentialentries[potentialentry]
60 repo = self._repo
84 repo = self._repo
61 binnode = bin(node)
85 binnode = bin(node)
62 # if the node doesn't exist, skip it
86 # if the node doesn't exist, skip it
63 try:
87 try:
64 repo.changelog.rev(binnode)
88 repo.changelog.rev(binnode)
65 except LookupError:
89 except LookupError:
66 return None
90 return None
67 # Skip closed branches
91 # Skip closed branches
68 if (self._kind == 'branches' and repo[binnode].closesbranch()):
92 if (self._kind == 'branches' and repo[binnode].closesbranch()):
69 return None
93 return None
70 return [binnode]
94 return [binnode]
71
95
72 def __getitem__(self, key):
96 def __getitem__(self, key):
73 if not self.loaded:
97 if not self.loaded:
74 self._load()
98 self._load()
75 val = self._fetchandcache(key)
99 val = self._fetchandcache(key)
76 if val is not None:
100 if val is not None:
77 return val
101 return val
78 else:
102 else:
79 raise KeyError()
103 raise KeyError()
80
104
81 def _fetchandcache(self, key):
105 def _fetchandcache(self, key):
82 if key in self.cache:
106 if key in self.cache:
83 return self.cache[key]
107 return self.cache[key]
84 val = self._resolvedata(key)
108 val = self._resolvedata(key)
85 if val is not None:
109 if val is not None:
86 self.cache[key] = val
110 self.cache[key] = val
87 return val
111 return val
88 else:
112 else:
89 return None
113 return None
90
114
91 def keys(self):
115 def keys(self):
92 """ Get a list of bookmark or branch names """
116 """ Get a list of bookmark or branch names """
93 if not self.loaded:
117 if not self.loaded:
94 self._load()
118 self._load()
95 return self.potentialentries.keys()
119 return self.potentialentries.keys()
96
120
97 def iteritems(self):
121 def iteritems(self):
98 """ Iterate over (name, node) tuples """
122 """ Iterate over (name, node) tuples """
99
123
100 if not self.loaded:
124 if not self.loaded:
101 self._load()
125 self._load()
102
126
103 for k, vtup in self.potentialentries.iteritems():
127 for k, vtup in self.potentialentries.iteritems():
104 yield (k, [bin(vtup[0])])
128 yield (k, [bin(vtup[0])])
105
129
106 class remotenames(dict):
130 class remotenames(dict):
107 """
131 """
108 This class encapsulates all the remotenames state. It also contains
132 This class encapsulates all the remotenames state. It also contains
109 methods to access that state in convenient ways. Remotenames are lazy
133 methods to access that state in convenient ways. Remotenames are lazy
110 loaded. Whenever client code needs to ensure the freshest copy of
134 loaded. Whenever client code needs to ensure the freshest copy of
111 remotenames, use the `clearnames` method to force an eventual load.
135 remotenames, use the `clearnames` method to force an eventual load.
112 """
136 """
113
137
114 def __init__(self, repo, *args):
138 def __init__(self, repo, *args):
115 dict.__init__(self, *args)
139 dict.__init__(self, *args)
116 self._repo = repo
140 self._repo = repo
117 self.clearnames()
141 self.clearnames()
118
142
119 def clearnames(self):
143 def clearnames(self):
120 """ Clear all remote names state """
144 """ Clear all remote names state """
121 self['bookmarks'] = lazyremotenamedict("bookmarks", self._repo)
145 self['bookmarks'] = lazyremotenamedict("bookmarks", self._repo)
122 self['branches'] = lazyremotenamedict("branches", self._repo)
146 self['branches'] = lazyremotenamedict("branches", self._repo)
123 self._invalidatecache()
147 self._invalidatecache()
124
148
125 def _invalidatecache(self):
149 def _invalidatecache(self):
126 self._nodetobmarks = None
150 self._nodetobmarks = None
127 self._nodetobranch = None
151 self._nodetobranch = None
128
152
129 def bmarktonodes(self):
153 def bmarktonodes(self):
130 return self['bookmarks']
154 return self['bookmarks']
131
155
132 def nodetobmarks(self):
156 def nodetobmarks(self):
133 if not self._nodetobmarks:
157 if not self._nodetobmarks:
134 bmarktonodes = self.bmarktonodes()
158 bmarktonodes = self.bmarktonodes()
135 self._nodetobmarks = {}
159 self._nodetobmarks = {}
136 for name, node in bmarktonodes.iteritems():
160 for name, node in bmarktonodes.iteritems():
137 self._nodetobmarks.setdefault(node[0], []).append(name)
161 self._nodetobmarks.setdefault(node[0], []).append(name)
138 return self._nodetobmarks
162 return self._nodetobmarks
139
163
140 def branchtonodes(self):
164 def branchtonodes(self):
141 return self['branches']
165 return self['branches']
142
166
143 def nodetobranch(self):
167 def nodetobranch(self):
144 if not self._nodetobranch:
168 if not self._nodetobranch:
145 branchtonodes = self.branchtonodes()
169 branchtonodes = self.branchtonodes()
146 self._nodetobranch = {}
170 self._nodetobranch = {}
147 for name, nodes in branchtonodes.iteritems():
171 for name, nodes in branchtonodes.iteritems():
148 for node in nodes:
172 for node in nodes:
149 self._nodetobranch.setdefault(node, []).append(name)
173 self._nodetobranch.setdefault(node, []).append(name)
150 return self._nodetobranch
174 return self._nodetobranch
175
176 def reposetup(ui, repo):
177 if not repo.local():
178 return
179
180 repo._remotenames = remotenames(repo)
181 ns = namespaces.namespace
182
183 if ui.configbool('remotenames', 'bookmarks'):
184 remotebookmarkns = ns(
185 'remotebookmarks',
186 templatename='remotebookmarks',
187 logname='remote bookmark',
188 colorname='remotebookmark',
189 listnames=lambda repo: repo._remotenames.bmarktonodes().keys(),
190 namemap=lambda repo, name:
191 repo._remotenames.bmarktonodes().get(name, []),
192 nodemap=lambda repo, node:
193 repo._remotenames.nodetobmarks().get(node, []))
194 repo.names.addnamespace(remotebookmarkns)
195
196 if ui.configbool('remotenames', 'branches'):
197 remotebranchns = ns(
198 'remotebranches',
199 templatename='remotebranches',
200 logname='remote branch',
201 colorname='remotebranch',
202 listnames = lambda repo: repo._remotenames.branchtonodes().keys(),
203 namemap = lambda repo, name:
204 repo._remotenames.branchtonodes().get(name, []),
205 nodemap = lambda repo, node:
206 repo._remotenames.nodetobranch().get(node, []))
207 repo.names.addnamespace(remotebranchns)
@@ -1,108 +1,184 b''
1 Testing the functionality to pull remotenames
1 Testing the functionality to pull remotenames
2 =============================================
2 =============================================
3
3
4 $ cat >> $HGRCPATH << EOF
4 $ cat >> $HGRCPATH << EOF
5 > [alias]
5 > [alias]
6 > glog = log -G -T '{rev}:{node|short} {desc}'
6 > glog = log -G -T '{rev}:{node|short} {desc}'
7 > [experimental]
7 > [experimental]
8 > remotenames = True
8 > remotenames = True
9 > [extensions]
10 > remotenames =
11 > show =
9 > EOF
12 > EOF
10
13
11 Making a server repo
14 Making a server repo
12 --------------------
15 --------------------
13
16
14 $ hg init server
17 $ hg init server
15 $ cd server
18 $ cd server
16 $ for ch in a b c d e f g h; do
19 $ for ch in a b c d e f g h; do
17 > echo "foo" >> $ch
20 > echo "foo" >> $ch
18 > hg ci -Aqm "Added "$ch
21 > hg ci -Aqm "Added "$ch
19 > done
22 > done
20 $ hg glog
23 $ hg glog
21 @ 7:ec2426147f0e Added h
24 @ 7:ec2426147f0e Added h
22 |
25 |
23 o 6:87d6d6676308 Added g
26 o 6:87d6d6676308 Added g
24 |
27 |
25 o 5:825660c69f0c Added f
28 o 5:825660c69f0c Added f
26 |
29 |
27 o 4:aa98ab95a928 Added e
30 o 4:aa98ab95a928 Added e
28 |
31 |
29 o 3:62615734edd5 Added d
32 o 3:62615734edd5 Added d
30 |
33 |
31 o 2:28ad74487de9 Added c
34 o 2:28ad74487de9 Added c
32 |
35 |
33 o 1:29becc82797a Added b
36 o 1:29becc82797a Added b
34 |
37 |
35 o 0:18d04c59bb5d Added a
38 o 0:18d04c59bb5d Added a
36
39
37 $ hg bookmark -r 3 foo
40 $ hg bookmark -r 3 foo
38 $ hg bookmark -r 6 bar
41 $ hg bookmark -r 6 bar
39 $ hg up 4
42 $ hg up 4
40 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
43 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
41 $ hg branch wat
44 $ hg branch wat
42 marked working directory as branch wat
45 marked working directory as branch wat
43 (branches are permanent and global, did you want a bookmark?)
46 (branches are permanent and global, did you want a bookmark?)
44 $ echo foo >> bar
47 $ echo foo >> bar
45 $ hg ci -Aqm "added bar"
48 $ hg ci -Aqm "added bar"
46
49
47 Making a client repo
50 Making a client repo
48 --------------------
51 --------------------
49
52
50 $ cd ..
53 $ cd ..
51
54
52 $ hg clone server client
55 $ hg clone server client
53 updating to branch default
56 updating to branch default
54 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
55
58
56 $ cd client
59 $ cd client
57 $ cat .hg/logexchange/bookmarks
60 $ cat .hg/logexchange/bookmarks
58 0
61 0
59
62
60 87d6d66763085b629e6d7ed56778c79827273022\x00default\x00bar (esc)
63 87d6d66763085b629e6d7ed56778c79827273022\x00default\x00bar (esc)
61 62615734edd52f06b6fb9c2beb429e4fe30d57b8\x00default\x00foo (esc)
64 62615734edd52f06b6fb9c2beb429e4fe30d57b8\x00default\x00foo (esc)
62
65
63 $ cat .hg/logexchange/branches
66 $ cat .hg/logexchange/branches
64 0
67 0
65
68
66 ec2426147f0e39dbc9cef599b066be6035ce691d\x00default\x00default (esc)
69 ec2426147f0e39dbc9cef599b066be6035ce691d\x00default\x00default (esc)
67 3e1487808078543b0af6d10dadf5d46943578db0\x00default\x00wat (esc)
70 3e1487808078543b0af6d10dadf5d46943578db0\x00default\x00wat (esc)
68
71
72 $ hg show work
73 o 3e14 (wat) (default/wat) added bar
74 |
75 ~
76 @ ec24 (default/default) Added h
77 |
78 ~
79
80 $ hg update "default/wat"
81 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
82 $ hg identify
83 3e1487808078 (wat) tip
84
69 Making a new server
85 Making a new server
70 -------------------
86 -------------------
71
87
72 $ cd ..
88 $ cd ..
73 $ hg init server2
89 $ hg init server2
74 $ cd server2
90 $ cd server2
75 $ hg pull ../server/
91 $ hg pull ../server/
76 pulling from ../server/
92 pulling from ../server/
77 requesting all changes
93 requesting all changes
78 adding changesets
94 adding changesets
79 adding manifests
95 adding manifests
80 adding file changes
96 adding file changes
81 added 9 changesets with 9 changes to 9 files (+1 heads)
97 added 9 changesets with 9 changes to 9 files (+1 heads)
82 adding remote bookmark bar
98 adding remote bookmark bar
83 adding remote bookmark foo
99 adding remote bookmark foo
84 new changesets 18d04c59bb5d:3e1487808078
100 new changesets 18d04c59bb5d:3e1487808078
85 (run 'hg heads' to see heads)
101 (run 'hg heads' to see heads)
86
102
87 Pulling form the new server
103 Pulling form the new server
88 ---------------------------
104 ---------------------------
89 $ cd ../client/
105 $ cd ../client/
90 $ hg pull ../server2/
106 $ hg pull ../server2/
91 pulling from ../server2/
107 pulling from ../server2/
92 searching for changes
108 searching for changes
93 no changes found
109 no changes found
94 $ cat .hg/logexchange/bookmarks
110 $ cat .hg/logexchange/bookmarks
95 0
111 0
96
112
97 62615734edd52f06b6fb9c2beb429e4fe30d57b8\x00default\x00foo (esc)
113 62615734edd52f06b6fb9c2beb429e4fe30d57b8\x00default\x00foo (esc)
98 87d6d66763085b629e6d7ed56778c79827273022\x00default\x00bar (esc)
114 87d6d66763085b629e6d7ed56778c79827273022\x00default\x00bar (esc)
99 87d6d66763085b629e6d7ed56778c79827273022\x00$TESTTMP/server2\x00bar (esc)
115 87d6d66763085b629e6d7ed56778c79827273022\x00$TESTTMP/server2\x00bar (esc)
100 62615734edd52f06b6fb9c2beb429e4fe30d57b8\x00$TESTTMP/server2\x00foo (esc)
116 62615734edd52f06b6fb9c2beb429e4fe30d57b8\x00$TESTTMP/server2\x00foo (esc)
101
117
102 $ cat .hg/logexchange/branches
118 $ cat .hg/logexchange/branches
103 0
119 0
104
120
105 3e1487808078543b0af6d10dadf5d46943578db0\x00default\x00wat (esc)
121 3e1487808078543b0af6d10dadf5d46943578db0\x00default\x00wat (esc)
106 ec2426147f0e39dbc9cef599b066be6035ce691d\x00default\x00default (esc)
122 ec2426147f0e39dbc9cef599b066be6035ce691d\x00default\x00default (esc)
107 ec2426147f0e39dbc9cef599b066be6035ce691d\x00$TESTTMP/server2\x00default (esc)
123 ec2426147f0e39dbc9cef599b066be6035ce691d\x00$TESTTMP/server2\x00default (esc)
108 3e1487808078543b0af6d10dadf5d46943578db0\x00$TESTTMP/server2\x00wat (esc)
124 3e1487808078543b0af6d10dadf5d46943578db0\x00$TESTTMP/server2\x00wat (esc)
125
126 $ hg log -G
127 @ changeset: 8:3e1487808078
128 | branch: wat
129 | tag: tip
130 | remote branch:$TESTTMP/server2/wat
131 | remote branch:default/wat
132 | parent: 4:aa98ab95a928
133 | user: test
134 | date: Thu Jan 01 00:00:00 1970 +0000
135 | summary: added bar
136 |
137 | o changeset: 7:ec2426147f0e
138 | | remote branch:$TESTTMP/server2/default
139 | | remote branch:default/default
140 | | user: test
141 | | date: Thu Jan 01 00:00:00 1970 +0000
142 | | summary: Added h
143 | |
144 | o changeset: 6:87d6d6676308
145 | | bookmark: bar
146 | | remote bookmark:$TESTTMP/server2/bar
147 | | remote bookmark:default/bar
148 | | user: test
149 | | date: Thu Jan 01 00:00:00 1970 +0000
150 | | summary: Added g
151 | |
152 | o changeset: 5:825660c69f0c
153 |/ user: test
154 | date: Thu Jan 01 00:00:00 1970 +0000
155 | summary: Added f
156 |
157 o changeset: 4:aa98ab95a928
158 | user: test
159 | date: Thu Jan 01 00:00:00 1970 +0000
160 | summary: Added e
161 |
162 o changeset: 3:62615734edd5
163 | bookmark: foo
164 | remote bookmark:$TESTTMP/server2/foo
165 | remote bookmark:default/foo
166 | user: test
167 | date: Thu Jan 01 00:00:00 1970 +0000
168 | summary: Added d
169 |
170 o changeset: 2:28ad74487de9
171 | user: test
172 | date: Thu Jan 01 00:00:00 1970 +0000
173 | summary: Added c
174 |
175 o changeset: 1:29becc82797a
176 | user: test
177 | date: Thu Jan 01 00:00:00 1970 +0000
178 | summary: Added b
179 |
180 o changeset: 0:18d04c59bb5d
181 user: test
182 date: Thu Jan 01 00:00:00 1970 +0000
183 summary: Added a
184
General Comments 0
You need to be logged in to leave comments. Login now