##// END OF EJS Templates
exthelper: update the examples to be python3 complaint...
Matt Harbison -
r46544:bd22900e default
parent child Browse files
Show More
@@ -1,311 +1,311 b''
1 # Copyright 2012 Logilab SA <contact@logilab.fr>
1 # Copyright 2012 Logilab SA <contact@logilab.fr>
2 # Pierre-Yves David <pierre-yves.david@ens-lyon.org>
2 # Pierre-Yves David <pierre-yves.david@ens-lyon.org>
3 # Octobus <contact@octobus.net>
3 # Octobus <contact@octobus.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 #####################################################################
8 #####################################################################
9 ### Extension helper ###
9 ### Extension helper ###
10 #####################################################################
10 #####################################################################
11
11
12 from __future__ import absolute_import
12 from __future__ import absolute_import
13
13
14 from . import (
14 from . import (
15 commands,
15 commands,
16 error,
16 error,
17 extensions,
17 extensions,
18 pycompat,
18 pycompat,
19 registrar,
19 registrar,
20 )
20 )
21
21
22 from hgdemandimport import tracing
22 from hgdemandimport import tracing
23
23
24
24
25 class exthelper(object):
25 class exthelper(object):
26 """Helper for modular extension setup
26 """Helper for modular extension setup
27
27
28 A single helper should be instantiated for each module of an
28 A single helper should be instantiated for each module of an
29 extension, where a command or function needs to be wrapped, or a
29 extension, where a command or function needs to be wrapped, or a
30 command, extension hook, fileset, revset or template needs to be
30 command, extension hook, fileset, revset or template needs to be
31 registered. Helper methods are then used as decorators for
31 registered. Helper methods are then used as decorators for
32 these various purposes. If an extension spans multiple modules,
32 these various purposes. If an extension spans multiple modules,
33 all helper instances should be merged in the main module.
33 all helper instances should be merged in the main module.
34
34
35 All decorators return the original function and may be chained.
35 All decorators return the original function and may be chained.
36
36
37 Aside from the helper functions with examples below, several
37 Aside from the helper functions with examples below, several
38 registrar method aliases are available for adding commands,
38 registrar method aliases are available for adding commands,
39 configitems, filesets, revsets, and templates. Simply decorate
39 configitems, filesets, revsets, and templates. Simply decorate
40 the appropriate methods, and assign the corresponding exthelper
40 the appropriate methods, and assign the corresponding exthelper
41 variable to a module level variable of the extension. The
41 variable to a module level variable of the extension. The
42 extension loading mechanism will handle the rest.
42 extension loading mechanism will handle the rest.
43
43
44 example::
44 example::
45
45
46 # ext.py
46 # ext.py
47 eh = exthelper.exthelper()
47 eh = exthelper.exthelper()
48
48
49 # As needed:
49 # As needed:
50 cmdtable = eh.cmdtable
50 cmdtable = eh.cmdtable
51 configtable = eh.configtable
51 configtable = eh.configtable
52 filesetpredicate = eh.filesetpredicate
52 filesetpredicate = eh.filesetpredicate
53 revsetpredicate = eh.revsetpredicate
53 revsetpredicate = eh.revsetpredicate
54 templatekeyword = eh.templatekeyword
54 templatekeyword = eh.templatekeyword
55
55
56 @eh.command('mynewcommand',
56 @eh.command(b'mynewcommand',
57 [('r', 'rev', [], _('operate on these revisions'))],
57 [(b'r', b'rev', [], _(b'operate on these revisions'))],
58 _('-r REV...'),
58 _(b'-r REV...'),
59 helpcategory=command.CATEGORY_XXX)
59 helpcategory=command.CATEGORY_XXX)
60 def newcommand(ui, repo, *revs, **opts):
60 def newcommand(ui, repo, *revs, **opts):
61 # implementation goes here
61 # implementation goes here
62
62
63 eh.configitem('experimental', 'foo',
63 eh.configitem(b'experimental', b'foo',
64 default=False,
64 default=False,
65 )
65 )
66
66
67 @eh.filesetpredicate('lfs()')
67 @eh.filesetpredicate(b'lfs()')
68 def filesetbabar(mctx, x):
68 def filesetbabar(mctx, x):
69 return mctx.predicate(...)
69 return mctx.predicate(...)
70
70
71 @eh.revsetpredicate('hidden')
71 @eh.revsetpredicate(b'hidden')
72 def revsetbabar(repo, subset, x):
72 def revsetbabar(repo, subset, x):
73 args = revset.getargs(x, 0, 0, 'babar accept no argument')
73 args = revset.getargs(x, 0, 0, b'babar accept no argument')
74 return [r for r in subset if 'babar' in repo[r].description()]
74 return [r for r in subset if b'babar' in repo[r].description()]
75
75
76 @eh.templatekeyword('babar')
76 @eh.templatekeyword(b'babar')
77 def kwbabar(ctx):
77 def kwbabar(ctx):
78 return 'babar'
78 return b'babar'
79 """
79 """
80
80
81 def __init__(self):
81 def __init__(self):
82 self._uipopulatecallables = []
82 self._uipopulatecallables = []
83 self._uicallables = []
83 self._uicallables = []
84 self._extcallables = []
84 self._extcallables = []
85 self._repocallables = []
85 self._repocallables = []
86 self._commandwrappers = []
86 self._commandwrappers = []
87 self._extcommandwrappers = []
87 self._extcommandwrappers = []
88 self._functionwrappers = []
88 self._functionwrappers = []
89 self.cmdtable = {}
89 self.cmdtable = {}
90 self.command = registrar.command(self.cmdtable)
90 self.command = registrar.command(self.cmdtable)
91 self.configtable = {}
91 self.configtable = {}
92 self.configitem = registrar.configitem(self.configtable)
92 self.configitem = registrar.configitem(self.configtable)
93 self.filesetpredicate = registrar.filesetpredicate()
93 self.filesetpredicate = registrar.filesetpredicate()
94 self.revsetpredicate = registrar.revsetpredicate()
94 self.revsetpredicate = registrar.revsetpredicate()
95 self.templatekeyword = registrar.templatekeyword()
95 self.templatekeyword = registrar.templatekeyword()
96
96
97 def merge(self, other):
97 def merge(self, other):
98 self._uicallables.extend(other._uicallables)
98 self._uicallables.extend(other._uicallables)
99 self._uipopulatecallables.extend(other._uipopulatecallables)
99 self._uipopulatecallables.extend(other._uipopulatecallables)
100 self._extcallables.extend(other._extcallables)
100 self._extcallables.extend(other._extcallables)
101 self._repocallables.extend(other._repocallables)
101 self._repocallables.extend(other._repocallables)
102 self.filesetpredicate._merge(other.filesetpredicate)
102 self.filesetpredicate._merge(other.filesetpredicate)
103 self.revsetpredicate._merge(other.revsetpredicate)
103 self.revsetpredicate._merge(other.revsetpredicate)
104 self.templatekeyword._merge(other.templatekeyword)
104 self.templatekeyword._merge(other.templatekeyword)
105 self._commandwrappers.extend(other._commandwrappers)
105 self._commandwrappers.extend(other._commandwrappers)
106 self._extcommandwrappers.extend(other._extcommandwrappers)
106 self._extcommandwrappers.extend(other._extcommandwrappers)
107 self._functionwrappers.extend(other._functionwrappers)
107 self._functionwrappers.extend(other._functionwrappers)
108 self.cmdtable.update(other.cmdtable)
108 self.cmdtable.update(other.cmdtable)
109 for section, items in pycompat.iteritems(other.configtable):
109 for section, items in pycompat.iteritems(other.configtable):
110 if section in self.configtable:
110 if section in self.configtable:
111 self.configtable[section].update(items)
111 self.configtable[section].update(items)
112 else:
112 else:
113 self.configtable[section] = items
113 self.configtable[section] = items
114
114
115 def finaluisetup(self, ui):
115 def finaluisetup(self, ui):
116 """Method to be used as the extension uisetup
116 """Method to be used as the extension uisetup
117
117
118 The following operations belong here:
118 The following operations belong here:
119
119
120 - Changes to ui.__class__ . The ui object that will be used to run the
120 - Changes to ui.__class__ . The ui object that will be used to run the
121 command has not yet been created. Changes made here will affect ui
121 command has not yet been created. Changes made here will affect ui
122 objects created after this, and in particular the ui that will be
122 objects created after this, and in particular the ui that will be
123 passed to runcommand
123 passed to runcommand
124 - Command wraps (extensions.wrapcommand)
124 - Command wraps (extensions.wrapcommand)
125 - Changes that need to be visible to other extensions: because
125 - Changes that need to be visible to other extensions: because
126 initialization occurs in phases (all extensions run uisetup, then all
126 initialization occurs in phases (all extensions run uisetup, then all
127 run extsetup), a change made here will be visible to other extensions
127 run extsetup), a change made here will be visible to other extensions
128 during extsetup
128 during extsetup
129 - Monkeypatch or wrap function (extensions.wrapfunction) of dispatch
129 - Monkeypatch or wrap function (extensions.wrapfunction) of dispatch
130 module members
130 module members
131 - Setup of pre-* and post-* hooks
131 - Setup of pre-* and post-* hooks
132 - pushkey setup
132 - pushkey setup
133 """
133 """
134 for command, wrapper, opts in self._commandwrappers:
134 for command, wrapper, opts in self._commandwrappers:
135 entry = extensions.wrapcommand(commands.table, command, wrapper)
135 entry = extensions.wrapcommand(commands.table, command, wrapper)
136 if opts:
136 if opts:
137 for opt in opts:
137 for opt in opts:
138 entry[1].append(opt)
138 entry[1].append(opt)
139 for cont, funcname, wrapper in self._functionwrappers:
139 for cont, funcname, wrapper in self._functionwrappers:
140 extensions.wrapfunction(cont, funcname, wrapper)
140 extensions.wrapfunction(cont, funcname, wrapper)
141 for c in self._uicallables:
141 for c in self._uicallables:
142 with tracing.log('finaluisetup: %s', repr(c)):
142 with tracing.log('finaluisetup: %s', repr(c)):
143 c(ui)
143 c(ui)
144
144
145 def finaluipopulate(self, ui):
145 def finaluipopulate(self, ui):
146 """Method to be used as the extension uipopulate
146 """Method to be used as the extension uipopulate
147
147
148 This is called once per ui instance to:
148 This is called once per ui instance to:
149
149
150 - Set up additional ui members
150 - Set up additional ui members
151 - Update configuration by ``ui.setconfig()``
151 - Update configuration by ``ui.setconfig()``
152 - Extend the class dynamically
152 - Extend the class dynamically
153 """
153 """
154 for c in self._uipopulatecallables:
154 for c in self._uipopulatecallables:
155 c(ui)
155 c(ui)
156
156
157 def finalextsetup(self, ui):
157 def finalextsetup(self, ui):
158 """Method to be used as a the extension extsetup
158 """Method to be used as a the extension extsetup
159
159
160 The following operations belong here:
160 The following operations belong here:
161
161
162 - Changes depending on the status of other extensions. (if
162 - Changes depending on the status of other extensions. (if
163 extensions.find('mq'))
163 extensions.find(b'mq'))
164 - Add a global option to all commands
164 - Add a global option to all commands
165 """
165 """
166 knownexts = {}
166 knownexts = {}
167
167
168 for ext, command, wrapper, opts in self._extcommandwrappers:
168 for ext, command, wrapper, opts in self._extcommandwrappers:
169 if ext not in knownexts:
169 if ext not in knownexts:
170 try:
170 try:
171 e = extensions.find(ext)
171 e = extensions.find(ext)
172 except KeyError:
172 except KeyError:
173 # Extension isn't enabled, so don't bother trying to wrap
173 # Extension isn't enabled, so don't bother trying to wrap
174 # it.
174 # it.
175 continue
175 continue
176 knownexts[ext] = e.cmdtable
176 knownexts[ext] = e.cmdtable
177 entry = extensions.wrapcommand(knownexts[ext], command, wrapper)
177 entry = extensions.wrapcommand(knownexts[ext], command, wrapper)
178 if opts:
178 if opts:
179 for opt in opts:
179 for opt in opts:
180 entry[1].append(opt)
180 entry[1].append(opt)
181
181
182 for c in self._extcallables:
182 for c in self._extcallables:
183 with tracing.log('finalextsetup: %s', repr(c)):
183 with tracing.log('finalextsetup: %s', repr(c)):
184 c(ui)
184 c(ui)
185
185
186 def finalreposetup(self, ui, repo):
186 def finalreposetup(self, ui, repo):
187 """Method to be used as the extension reposetup
187 """Method to be used as the extension reposetup
188
188
189 The following operations belong here:
189 The following operations belong here:
190
190
191 - All hooks but pre-* and post-*
191 - All hooks but pre-* and post-*
192 - Modify configuration variables
192 - Modify configuration variables
193 - Changes to repo.__class__, repo.dirstate.__class__
193 - Changes to repo.__class__, repo.dirstate.__class__
194 """
194 """
195 for c in self._repocallables:
195 for c in self._repocallables:
196 with tracing.log('finalreposetup: %s', repr(c)):
196 with tracing.log('finalreposetup: %s', repr(c)):
197 c(ui, repo)
197 c(ui, repo)
198
198
199 def uisetup(self, call):
199 def uisetup(self, call):
200 """Decorated function will be executed during uisetup
200 """Decorated function will be executed during uisetup
201
201
202 example::
202 example::
203
203
204 @eh.uisetup
204 @eh.uisetup
205 def setupbabar(ui):
205 def setupbabar(ui):
206 print 'this is uisetup!'
206 print('this is uisetup!')
207 """
207 """
208 self._uicallables.append(call)
208 self._uicallables.append(call)
209 return call
209 return call
210
210
211 def uipopulate(self, call):
211 def uipopulate(self, call):
212 """Decorated function will be executed during uipopulate
212 """Decorated function will be executed during uipopulate
213
213
214 example::
214 example::
215
215
216 @eh.uipopulate
216 @eh.uipopulate
217 def setupfoo(ui):
217 def setupfoo(ui):
218 print 'this is uipopulate!'
218 print('this is uipopulate!')
219 """
219 """
220 self._uipopulatecallables.append(call)
220 self._uipopulatecallables.append(call)
221 return call
221 return call
222
222
223 def extsetup(self, call):
223 def extsetup(self, call):
224 """Decorated function will be executed during extsetup
224 """Decorated function will be executed during extsetup
225
225
226 example::
226 example::
227
227
228 @eh.extsetup
228 @eh.extsetup
229 def setupcelestine(ui):
229 def setupcelestine(ui):
230 print 'this is extsetup!'
230 print('this is extsetup!')
231 """
231 """
232 self._extcallables.append(call)
232 self._extcallables.append(call)
233 return call
233 return call
234
234
235 def reposetup(self, call):
235 def reposetup(self, call):
236 """Decorated function will be executed during reposetup
236 """Decorated function will be executed during reposetup
237
237
238 example::
238 example::
239
239
240 @eh.reposetup
240 @eh.reposetup
241 def setupzephir(ui, repo):
241 def setupzephir(ui, repo):
242 print 'this is reposetup!'
242 print('this is reposetup!')
243 """
243 """
244 self._repocallables.append(call)
244 self._repocallables.append(call)
245 return call
245 return call
246
246
247 def wrapcommand(self, command, extension=None, opts=None):
247 def wrapcommand(self, command, extension=None, opts=None):
248 """Decorated function is a command wrapper
248 """Decorated function is a command wrapper
249
249
250 The name of the command must be given as the decorator argument.
250 The name of the command must be given as the decorator argument.
251 The wrapping is installed during `uisetup`.
251 The wrapping is installed during `uisetup`.
252
252
253 If the second option `extension` argument is provided, the wrapping
253 If the second option `extension` argument is provided, the wrapping
254 will be applied in the extension commandtable. This argument must be a
254 will be applied in the extension commandtable. This argument must be a
255 string that will be searched using `extension.find` if not found and
255 string that will be searched using `extension.find` if not found and
256 Abort error is raised. If the wrapping applies to an extension, it is
256 Abort error is raised. If the wrapping applies to an extension, it is
257 installed during `extsetup`.
257 installed during `extsetup`.
258
258
259 example::
259 example::
260
260
261 @eh.wrapcommand('summary')
261 @eh.wrapcommand(b'summary')
262 def wrapsummary(orig, ui, repo, *args, **kwargs):
262 def wrapsummary(orig, ui, repo, *args, **kwargs):
263 ui.note('Barry!')
263 ui.note(b'Barry!')
264 return orig(ui, repo, *args, **kwargs)
264 return orig(ui, repo, *args, **kwargs)
265
265
266 The `opts` argument allows specifying a list of tuples for additional
266 The `opts` argument allows specifying a list of tuples for additional
267 arguments for the command. See ``mercurial.fancyopts.fancyopts()`` for
267 arguments for the command. See ``mercurial.fancyopts.fancyopts()`` for
268 the format of the tuple.
268 the format of the tuple.
269
269
270 """
270 """
271 if opts is None:
271 if opts is None:
272 opts = []
272 opts = []
273 else:
273 else:
274 for opt in opts:
274 for opt in opts:
275 if not isinstance(opt, tuple):
275 if not isinstance(opt, tuple):
276 raise error.ProgrammingError(b'opts must be list of tuples')
276 raise error.ProgrammingError(b'opts must be list of tuples')
277 if len(opt) not in (4, 5):
277 if len(opt) not in (4, 5):
278 msg = b'each opt tuple must contain 4 or 5 values'
278 msg = b'each opt tuple must contain 4 or 5 values'
279 raise error.ProgrammingError(msg)
279 raise error.ProgrammingError(msg)
280
280
281 def dec(wrapper):
281 def dec(wrapper):
282 if extension is None:
282 if extension is None:
283 self._commandwrappers.append((command, wrapper, opts))
283 self._commandwrappers.append((command, wrapper, opts))
284 else:
284 else:
285 self._extcommandwrappers.append(
285 self._extcommandwrappers.append(
286 (extension, command, wrapper, opts)
286 (extension, command, wrapper, opts)
287 )
287 )
288 return wrapper
288 return wrapper
289
289
290 return dec
290 return dec
291
291
292 def wrapfunction(self, container, funcname):
292 def wrapfunction(self, container, funcname):
293 """Decorated function is a function wrapper
293 """Decorated function is a function wrapper
294
294
295 This function takes two arguments, the container and the name of the
295 This function takes two arguments, the container and the name of the
296 function to wrap. The wrapping is performed during `uisetup`.
296 function to wrap. The wrapping is performed during `uisetup`.
297 (there is no extension support)
297 (there is no extension support)
298
298
299 example::
299 example::
300
300
301 @eh.function(discovery, 'checkheads')
301 @eh.function(discovery, b'checkheads')
302 def wrapfunction(orig, *args, **kwargs):
302 def wrapfunction(orig, *args, **kwargs):
303 ui.note('His head smashed in and his heart cut out')
303 ui.note(b'His head smashed in and his heart cut out')
304 return orig(*args, **kwargs)
304 return orig(*args, **kwargs)
305 """
305 """
306
306
307 def dec(wrapper):
307 def dec(wrapper):
308 self._functionwrappers.append((container, funcname, wrapper))
308 self._functionwrappers.append((container, funcname, wrapper))
309 return wrapper
309 return wrapper
310
310
311 return dec
311 return dec
General Comments 0
You need to be logged in to leave comments. Login now