comparison sat_frontends/jp/cmd_pubsub.py @ 2624:56f94936df1e

code style reformatting using black
author Goffi <goffi@goffi.org>
date Wed, 27 Jun 2018 20:14:46 +0200
parents 26edcf3a30eb
children 4b693ea24d5f
comparison
equal deleted inserted replaced
2623:49533de4540b 2624:56f94936df1e
36 36
37 __commands__ = ["Pubsub"] 37 __commands__ = ["Pubsub"]
38 38
39 PUBSUB_TMP_DIR = u"pubsub" 39 PUBSUB_TMP_DIR = u"pubsub"
40 PUBSUB_SCHEMA_TMP_DIR = PUBSUB_TMP_DIR + "_schema" 40 PUBSUB_SCHEMA_TMP_DIR = PUBSUB_TMP_DIR + "_schema"
41 ALLOWED_SUBSCRIPTIONS_OWNER = ('subscribed', 'pending', 'none') 41 ALLOWED_SUBSCRIPTIONS_OWNER = ("subscribed", "pending", "none")
42 42
43 # TODO: need to split this class in several modules, plugin should handle subcommands 43 # TODO: need to split this class in several modules, plugin should handle subcommands
44 44
45 45
46 class NodeInfo(base.CommandBase): 46 class NodeInfo(base.CommandBase):
47 47 def __init__(self, host):
48 def __init__(self, host): 48 base.CommandBase.__init__(
49 base.CommandBase.__init__(self, host, 'info', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'retrieve node configuration')) 49 self,
50 self.need_loop=True 50 host,
51 51 "info",
52 def add_parser_options(self): 52 use_output=C.OUTPUT_DICT,
53 self.parser.add_argument("-k", "--key", type=base.unicode_decoder, action='append', dest='keys', 53 use_pubsub=True,
54 help=_(u"data key to filter")) 54 pubsub_flags={C.NODE},
55 help=_(u"retrieve node configuration"),
56 )
57 self.need_loop = True
58
59 def add_parser_options(self):
60 self.parser.add_argument(
61 "-k",
62 "--key",
63 type=base.unicode_decoder,
64 action="append",
65 dest="keys",
66 help=_(u"data key to filter"),
67 )
55 68
56 def removePrefix(self, key): 69 def removePrefix(self, key):
57 return key[7:] if key.startswith(u"pubsub#") else key 70 return key[7:] if key.startswith(u"pubsub#") else key
58 71
59 def filterKey(self, key): 72 def filterKey(self, key):
60 return any((key == k or key == u'pubsub#' + k) for k in self.args.keys) 73 return any((key == k or key == u"pubsub#" + k) for k in self.args.keys)
61 74
62 def psNodeConfigurationGetCb(self, config_dict): 75 def psNodeConfigurationGetCb(self, config_dict):
63 key_filter = (lambda k: True) if not self.args.keys else self.filterKey 76 key_filter = (lambda k: True) if not self.args.keys else self.filterKey
64 config_dict = {self.removePrefix(k):v for k,v in config_dict.iteritems() if key_filter(k)} 77 config_dict = {
78 self.removePrefix(k): v for k, v in config_dict.iteritems() if key_filter(k)
79 }
65 self.output(config_dict) 80 self.output(config_dict)
66 self.host.quit() 81 self.host.quit()
67 82
68 def psNodeConfigurationGetEb(self, failure_): 83 def psNodeConfigurationGetEb(self, failure_):
69 self.disp(u"can't get node configuration: {reason}".format( 84 self.disp(
70 reason=failure_), error=True) 85 u"can't get node configuration: {reason}".format(reason=failure_), error=True
86 )
71 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 87 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
72 88
73 def start(self): 89 def start(self):
74 self.host.bridge.psNodeConfigurationGet( 90 self.host.bridge.psNodeConfigurationGet(
75 self.args.service, 91 self.args.service,
76 self.args.node, 92 self.args.node,
77 self.profile, 93 self.profile,
78 callback=self.psNodeConfigurationGetCb, 94 callback=self.psNodeConfigurationGetCb,
79 errback=self.psNodeConfigurationGetEb) 95 errback=self.psNodeConfigurationGetEb,
96 )
80 97
81 98
82 class NodeCreate(base.CommandBase): 99 class NodeCreate(base.CommandBase):
83 100 def __init__(self, host):
84 def __init__(self, host): 101 base.CommandBase.__init__(
85 base.CommandBase.__init__(self, host, 'create', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'create a node')) 102 self,
86 self.need_loop=True 103 host,
87 104 "create",
88 def add_parser_options(self): 105 use_output=C.OUTPUT_DICT,
89 self.parser.add_argument("-f", "--field", type=base.unicode_decoder, action='append', nargs=2, dest='fields', 106 use_pubsub=True,
90 default=[], metavar=(u"KEY", u"VALUE"), help=_(u"configuration field to set")) 107 pubsub_flags={C.NODE},
91 self.parser.add_argument("-F", "--full-prefix", action="store_true", help=_(u"don't prepend \"pubsub#\" prefix to field names")) 108 use_verbose=True,
109 help=_(u"create a node"),
110 )
111 self.need_loop = True
112
113 def add_parser_options(self):
114 self.parser.add_argument(
115 "-f",
116 "--field",
117 type=base.unicode_decoder,
118 action="append",
119 nargs=2,
120 dest="fields",
121 default=[],
122 metavar=(u"KEY", u"VALUE"),
123 help=_(u"configuration field to set"),
124 )
125 self.parser.add_argument(
126 "-F",
127 "--full-prefix",
128 action="store_true",
129 help=_(u'don\'t prepend "pubsub#" prefix to field names'),
130 )
92 131
93 def psNodeCreateCb(self, node_id): 132 def psNodeCreateCb(self, node_id):
94 if self.host.verbosity: 133 if self.host.verbosity:
95 announce = _(u'node created successfully: ') 134 announce = _(u"node created successfully: ")
96 else: 135 else:
97 announce = u'' 136 announce = u""
98 self.disp(announce + node_id) 137 self.disp(announce + node_id)
99 self.host.quit() 138 self.host.quit()
100 139
101 def psNodeCreateEb(self, failure_): 140 def psNodeCreateEb(self, failure_):
102 self.disp(u"can't create: {reason}".format( 141 self.disp(u"can't create: {reason}".format(reason=failure_), error=True)
103 reason=failure_), error=True)
104 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 142 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
105 143
106 def start(self): 144 def start(self):
107 if not self.args.full_prefix: 145 if not self.args.full_prefix:
108 options = {u'pubsub#' + k: v for k,v in self.args.fields} 146 options = {u"pubsub#" + k: v for k, v in self.args.fields}
109 else: 147 else:
110 options = dict(self.args.fields) 148 options = dict(self.args.fields)
111 self.host.bridge.psNodeCreate( 149 self.host.bridge.psNodeCreate(
112 self.args.service, 150 self.args.service,
113 self.args.node, 151 self.args.node,
114 options, 152 options,
115 self.profile, 153 self.profile,
116 callback=self.psNodeCreateCb, 154 callback=self.psNodeCreateCb,
117 errback=partial(self.errback, 155 errback=partial(
118 msg=_(u"can't create node: {}"), 156 self.errback,
119 exit_code=C.EXIT_BRIDGE_ERRBACK)) 157 msg=_(u"can't create node: {}"),
158 exit_code=C.EXIT_BRIDGE_ERRBACK,
159 ),
160 )
120 161
121 162
122 class NodeDelete(base.CommandBase): 163 class NodeDelete(base.CommandBase):
123 164 def __init__(self, host):
124 def __init__(self, host): 165 base.CommandBase.__init__(
125 base.CommandBase.__init__(self, host, 'delete', use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'delete a node')) 166 self,
126 self.need_loop=True 167 host,
127 168 "delete",
128 def add_parser_options(self): 169 use_pubsub=True,
129 self.parser.add_argument('-f', '--force', action='store_true', help=_(u'delete node without confirmation')) 170 pubsub_flags={C.NODE},
171 help=_(u"delete a node"),
172 )
173 self.need_loop = True
174
175 def add_parser_options(self):
176 self.parser.add_argument(
177 "-f",
178 "--force",
179 action="store_true",
180 help=_(u"delete node without confirmation"),
181 )
130 182
131 def psNodeDeleteCb(self): 183 def psNodeDeleteCb(self):
132 self.disp(_(u'node [{node}] deleted successfully').format(node=self.args.node)) 184 self.disp(_(u"node [{node}] deleted successfully").format(node=self.args.node))
133 self.host.quit() 185 self.host.quit()
134 186
135 def start(self): 187 def start(self):
136 if not self.args.force: 188 if not self.args.force:
137 if not self.args.service: 189 if not self.args.service:
138 message = _(u"Are you sure to delete pep node [{node_id}] ?").format( 190 message = _(u"Are you sure to delete pep node [{node_id}] ?").format(
139 node_id=self.args.node) 191 node_id=self.args.node
192 )
140 else: 193 else:
141 message = _(u"Are you sure to delete node [{node_id}] on service [{service}] ?").format( 194 message = _(
142 node_id=self.args.node, service=self.args.service) 195 u"Are you sure to delete node [{node_id}] on service [{service}] ?"
196 ).format(node_id=self.args.node, service=self.args.service)
143 self.host.confirmOrQuit(message, _(u"node deletion cancelled")) 197 self.host.confirmOrQuit(message, _(u"node deletion cancelled"))
144 198
145 self.host.bridge.psNodeDelete( 199 self.host.bridge.psNodeDelete(
146 self.args.service, 200 self.args.service,
147 self.args.node, 201 self.args.node,
148 self.profile, 202 self.profile,
149 callback=self.psNodeDeleteCb, 203 callback=self.psNodeDeleteCb,
150 errback=partial(self.errback, 204 errback=partial(
151 msg=_(u"can't delete node: {}"), 205 self.errback,
152 exit_code=C.EXIT_BRIDGE_ERRBACK)) 206 msg=_(u"can't delete node: {}"),
207 exit_code=C.EXIT_BRIDGE_ERRBACK,
208 ),
209 )
153 210
154 211
155 class NodeSet(base.CommandBase): 212 class NodeSet(base.CommandBase):
156 213 def __init__(self, host):
157 def __init__(self, host): 214 base.CommandBase.__init__(
158 base.CommandBase.__init__(self, host, 'set', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'set node configuration')) 215 self,
159 self.need_loop=True 216 host,
160 217 "set",
161 def add_parser_options(self): 218 use_output=C.OUTPUT_DICT,
162 self.parser.add_argument("-f", "--field", type=base.unicode_decoder, action='append', nargs=2, dest='fields', 219 use_pubsub=True,
163 required=True, metavar=(u"KEY", u"VALUE"), help=_(u"configuration field to set (required)")) 220 pubsub_flags={C.NODE},
221 use_verbose=True,
222 help=_(u"set node configuration"),
223 )
224 self.need_loop = True
225
226 def add_parser_options(self):
227 self.parser.add_argument(
228 "-f",
229 "--field",
230 type=base.unicode_decoder,
231 action="append",
232 nargs=2,
233 dest="fields",
234 required=True,
235 metavar=(u"KEY", u"VALUE"),
236 help=_(u"configuration field to set (required)"),
237 )
164 238
165 def psNodeConfigurationSetCb(self): 239 def psNodeConfigurationSetCb(self):
166 self.disp(_(u'node configuration successful'), 1) 240 self.disp(_(u"node configuration successful"), 1)
167 self.host.quit() 241 self.host.quit()
168 242
169 def psNodeConfigurationSetEb(self, failure_): 243 def psNodeConfigurationSetEb(self, failure_):
170 self.disp(u"can't set node configuration: {reason}".format( 244 self.disp(
171 reason=failure_), error=True) 245 u"can't set node configuration: {reason}".format(reason=failure_), error=True
246 )
172 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 247 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
173 248
174 def getKeyName(self, k): 249 def getKeyName(self, k):
175 if not k.startswith(u'pubsub#'): 250 if not k.startswith(u"pubsub#"):
176 return u'pubsub#' + k 251 return u"pubsub#" + k
177 else: 252 else:
178 return k 253 return k
179 254
180 def start(self): 255 def start(self):
181 self.host.bridge.psNodeConfigurationSet( 256 self.host.bridge.psNodeConfigurationSet(
182 self.args.service, 257 self.args.service,
183 self.args.node, 258 self.args.node,
184 {self.getKeyName(k): v for k,v in self.args.fields}, 259 {self.getKeyName(k): v for k, v in self.args.fields},
185 self.profile, 260 self.profile,
186 callback=self.psNodeConfigurationSetCb, 261 callback=self.psNodeConfigurationSetCb,
187 errback=self.psNodeConfigurationSetEb) 262 errback=self.psNodeConfigurationSetEb,
263 )
188 264
189 265
190 class NodeAffiliationsGet(base.CommandBase): 266 class NodeAffiliationsGet(base.CommandBase):
191 267 def __init__(self, host):
192 def __init__(self, host): 268 base.CommandBase.__init__(
193 base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'retrieve node affiliations (for node owner)')) 269 self,
194 self.need_loop=True 270 host,
271 "get",
272 use_output=C.OUTPUT_DICT,
273 use_pubsub=True,
274 pubsub_flags={C.NODE},
275 help=_(u"retrieve node affiliations (for node owner)"),
276 )
277 self.need_loop = True
195 278
196 def add_parser_options(self): 279 def add_parser_options(self):
197 pass 280 pass
198 281
199 def psNodeAffiliationsGetCb(self, affiliations): 282 def psNodeAffiliationsGetCb(self, affiliations):
200 self.output(affiliations) 283 self.output(affiliations)
201 self.host.quit() 284 self.host.quit()
202 285
203 def psNodeAffiliationsGetEb(self, failure_): 286 def psNodeAffiliationsGetEb(self, failure_):
204 self.disp(u"can't get node affiliations: {reason}".format( 287 self.disp(
205 reason=failure_), error=True) 288 u"can't get node affiliations: {reason}".format(reason=failure_), error=True
289 )
206 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 290 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
207 291
208 def start(self): 292 def start(self):
209 self.host.bridge.psNodeAffiliationsGet( 293 self.host.bridge.psNodeAffiliationsGet(
210 self.args.service, 294 self.args.service,
211 self.args.node, 295 self.args.node,
212 self.profile, 296 self.profile,
213 callback=self.psNodeAffiliationsGetCb, 297 callback=self.psNodeAffiliationsGetCb,
214 errback=self.psNodeAffiliationsGetEb) 298 errback=self.psNodeAffiliationsGetEb,
299 )
215 300
216 301
217 class NodeAffiliationsSet(base.CommandBase): 302 class NodeAffiliationsSet(base.CommandBase):
218 303 def __init__(self, host):
219 def __init__(self, host): 304 base.CommandBase.__init__(
220 base.CommandBase.__init__(self, host, 'set', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'set affiliations (for node owner)')) 305 self,
221 self.need_loop=True 306 host,
307 "set",
308 use_pubsub=True,
309 pubsub_flags={C.NODE},
310 use_verbose=True,
311 help=_(u"set affiliations (for node owner)"),
312 )
313 self.need_loop = True
222 314
223 def add_parser_options(self): 315 def add_parser_options(self):
224 # XXX: we use optional argument syntax for a required one because list of list of 2 elements 316 # XXX: we use optional argument syntax for a required one because list of list of 2 elements
225 # (uses to construct dicts) don't work with positional arguments 317 # (uses to construct dicts) don't work with positional arguments
226 self.parser.add_argument("-a", 318 self.parser.add_argument(
227 "--affiliation", 319 "-a",
228 dest="affiliations", 320 "--affiliation",
229 metavar=('JID', 'AFFILIATION'), 321 dest="affiliations",
230 required=True, 322 metavar=("JID", "AFFILIATION"),
231 type=base.unicode_decoder, 323 required=True,
232 action="append", 324 type=base.unicode_decoder,
233 nargs=2, 325 action="append",
234 help=_(u"entity/affiliation couple(s)")) 326 nargs=2,
327 help=_(u"entity/affiliation couple(s)"),
328 )
235 329
236 def psNodeAffiliationsSetCb(self): 330 def psNodeAffiliationsSetCb(self):
237 self.disp(_(u"affiliations have been set"), 1) 331 self.disp(_(u"affiliations have been set"), 1)
238 self.host.quit() 332 self.host.quit()
239 333
240 def psNodeAffiliationsSetEb(self, failure_): 334 def psNodeAffiliationsSetEb(self, failure_):
241 self.disp(u"can't set node affiliations: {reason}".format( 335 self.disp(
242 reason=failure_), error=True) 336 u"can't set node affiliations: {reason}".format(reason=failure_), error=True
337 )
243 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 338 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
244 339
245 def start(self): 340 def start(self):
246 affiliations = dict(self.args.affiliations) 341 affiliations = dict(self.args.affiliations)
247 self.host.bridge.psNodeAffiliationsSet( 342 self.host.bridge.psNodeAffiliationsSet(
248 self.args.service, 343 self.args.service,
249 self.args.node, 344 self.args.node,
250 affiliations, 345 affiliations,
251 self.profile, 346 self.profile,
252 callback=self.psNodeAffiliationsSetCb, 347 callback=self.psNodeAffiliationsSetCb,
253 errback=self.psNodeAffiliationsSetEb) 348 errback=self.psNodeAffiliationsSetEb,
349 )
254 350
255 351
256 class NodeAffiliations(base.CommandBase): 352 class NodeAffiliations(base.CommandBase):
257 subcommands = (NodeAffiliationsGet, NodeAffiliationsSet) 353 subcommands = (NodeAffiliationsGet, NodeAffiliationsSet)
258 354
259 def __init__(self, host): 355 def __init__(self, host):
260 super(NodeAffiliations, self).__init__(host, 'affiliations', use_profile=False, help=_(u'set or retrieve node affiliations')) 356 super(NodeAffiliations, self).__init__(
357 host,
358 "affiliations",
359 use_profile=False,
360 help=_(u"set or retrieve node affiliations"),
361 )
261 362
262 363
263 class NodeSubscriptionsGet(base.CommandBase): 364 class NodeSubscriptionsGet(base.CommandBase):
264 365 def __init__(self, host):
265 def __init__(self, host): 366 base.CommandBase.__init__(
266 base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_DICT, use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'retrieve node subscriptions (for node owner)')) 367 self,
267 self.need_loop=True 368 host,
369 "get",
370 use_output=C.OUTPUT_DICT,
371 use_pubsub=True,
372 pubsub_flags={C.NODE},
373 help=_(u"retrieve node subscriptions (for node owner)"),
374 )
375 self.need_loop = True
268 376
269 def add_parser_options(self): 377 def add_parser_options(self):
270 pass 378 pass
271 379
272 def psNodeSubscriptionsGetCb(self, subscriptions): 380 def psNodeSubscriptionsGetCb(self, subscriptions):
273 self.output(subscriptions) 381 self.output(subscriptions)
274 self.host.quit() 382 self.host.quit()
275 383
276 def psNodeSubscriptionsGetEb(self, failure_): 384 def psNodeSubscriptionsGetEb(self, failure_):
277 self.disp(u"can't get node subscriptions: {reason}".format( 385 self.disp(
278 reason=failure_), error=True) 386 u"can't get node subscriptions: {reason}".format(reason=failure_), error=True
387 )
279 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 388 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
280 389
281 def start(self): 390 def start(self):
282 self.host.bridge.psNodeSubscriptionsGet( 391 self.host.bridge.psNodeSubscriptionsGet(
283 self.args.service, 392 self.args.service,
284 self.args.node, 393 self.args.node,
285 self.profile, 394 self.profile,
286 callback=self.psNodeSubscriptionsGetCb, 395 callback=self.psNodeSubscriptionsGetCb,
287 errback=self.psNodeSubscriptionsGetEb) 396 errback=self.psNodeSubscriptionsGetEb,
397 )
288 398
289 399
290 class StoreSubscriptionAction(argparse.Action): 400 class StoreSubscriptionAction(argparse.Action):
291 """Action which handle subscription parameter for owner 401 """Action which handle subscription parameter for owner
292 402
299 while values: 409 while values:
300 jid_s = values.pop(0) 410 jid_s = values.pop(0)
301 try: 411 try:
302 subscription = values.pop(0) 412 subscription = values.pop(0)
303 except IndexError: 413 except IndexError:
304 subscription = 'subscribed' 414 subscription = "subscribed"
305 if subscription not in ALLOWED_SUBSCRIPTIONS_OWNER: 415 if subscription not in ALLOWED_SUBSCRIPTIONS_OWNER:
306 parser.error(_(u"subscription must be one of {}").format(u', '.join(ALLOWED_SUBSCRIPTIONS_OWNER))) 416 parser.error(
417 _(u"subscription must be one of {}").format(
418 u", ".join(ALLOWED_SUBSCRIPTIONS_OWNER)
419 )
420 )
307 dest_dict[jid_s] = subscription 421 dest_dict[jid_s] = subscription
308 422
309 423
310 class NodeSubscriptionsSet(base.CommandBase): 424 class NodeSubscriptionsSet(base.CommandBase):
311 425 def __init__(self, host):
312 def __init__(self, host): 426 base.CommandBase.__init__(
313 base.CommandBase.__init__(self, host, 'set', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'set/modify subscriptions (for node owner)')) 427 self,
314 self.need_loop=True 428 host,
429 "set",
430 use_pubsub=True,
431 pubsub_flags={C.NODE},
432 use_verbose=True,
433 help=_(u"set/modify subscriptions (for node owner)"),
434 )
435 self.need_loop = True
315 436
316 def add_parser_options(self): 437 def add_parser_options(self):
317 # XXX: we use optional argument syntax for a required one because list of list of 2 elements 438 # XXX: we use optional argument syntax for a required one because list of list of 2 elements
318 # (uses to construct dicts) don't work with positional arguments 439 # (uses to construct dicts) don't work with positional arguments
319 self.parser.add_argument("-S", 440 self.parser.add_argument(
320 "--subscription", 441 "-S",
321 dest="subscriptions", 442 "--subscription",
322 default={}, 443 dest="subscriptions",
323 nargs='+', 444 default={},
324 metavar=('JID [SUSBSCRIPTION]'), 445 nargs="+",
325 required=True, 446 metavar=("JID [SUSBSCRIPTION]"),
326 type=base.unicode_decoder, 447 required=True,
327 action=StoreSubscriptionAction, 448 type=base.unicode_decoder,
328 help=_(u"entity/subscription couple(s)")) 449 action=StoreSubscriptionAction,
450 help=_(u"entity/subscription couple(s)"),
451 )
329 452
330 def psNodeSubscriptionsSetCb(self): 453 def psNodeSubscriptionsSetCb(self):
331 self.disp(_(u"subscriptions have been set"), 1) 454 self.disp(_(u"subscriptions have been set"), 1)
332 self.host.quit() 455 self.host.quit()
333 456
334 def psNodeSubscriptionsSetEb(self, failure_): 457 def psNodeSubscriptionsSetEb(self, failure_):
335 self.disp(u"can't set node subscriptions: {reason}".format( 458 self.disp(
336 reason=failure_), error=True) 459 u"can't set node subscriptions: {reason}".format(reason=failure_), error=True
460 )
337 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 461 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
338 462
339 def start(self): 463 def start(self):
340 self.host.bridge.psNodeSubscriptionsSet( 464 self.host.bridge.psNodeSubscriptionsSet(
341 self.args.service, 465 self.args.service,
342 self.args.node, 466 self.args.node,
343 self.args.subscriptions, 467 self.args.subscriptions,
344 self.profile, 468 self.profile,
345 callback=self.psNodeSubscriptionsSetCb, 469 callback=self.psNodeSubscriptionsSetCb,
346 errback=self.psNodeSubscriptionsSetEb) 470 errback=self.psNodeSubscriptionsSetEb,
471 )
347 472
348 473
349 class NodeSubscriptions(base.CommandBase): 474 class NodeSubscriptions(base.CommandBase):
350 subcommands = (NodeSubscriptionsGet, NodeSubscriptionsSet) 475 subcommands = (NodeSubscriptionsGet, NodeSubscriptionsSet)
351 476
352 def __init__(self, host): 477 def __init__(self, host):
353 super(NodeSubscriptions, self).__init__(host, 'subscriptions', use_profile=False, help=_(u'get or modify node subscriptions')) 478 super(NodeSubscriptions, self).__init__(
479 host,
480 "subscriptions",
481 use_profile=False,
482 help=_(u"get or modify node subscriptions"),
483 )
354 484
355 485
356 class NodeSchemaSet(base.CommandBase): 486 class NodeSchemaSet(base.CommandBase):
357 487 def __init__(self, host):
358 def __init__(self, host): 488 base.CommandBase.__init__(
359 base.CommandBase.__init__(self, host, 'set', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'set/replace a schema')) 489 self,
360 self.need_loop = True 490 host,
361 491 "set",
362 def add_parser_options(self): 492 use_pubsub=True,
363 self.parser.add_argument('schema', help=_(u"schema to set (must be XML)")) 493 pubsub_flags={C.NODE},
494 use_verbose=True,
495 help=_(u"set/replace a schema"),
496 )
497 self.need_loop = True
498
499 def add_parser_options(self):
500 self.parser.add_argument("schema", help=_(u"schema to set (must be XML)"))
364 501
365 def psSchemaSetCb(self): 502 def psSchemaSetCb(self):
366 self.disp(_(u'schema has been set'), 1) 503 self.disp(_(u"schema has been set"), 1)
367 self.host.quit() 504 self.host.quit()
368 505
369 def start(self): 506 def start(self):
370 self.host.bridge.psSchemaSet( 507 self.host.bridge.psSchemaSet(
371 self.args.service, 508 self.args.service,
372 self.args.node, 509 self.args.node,
373 self.args.schema, 510 self.args.schema,
374 self.profile, 511 self.profile,
375 callback=self.psSchemaSetCb, 512 callback=self.psSchemaSetCb,
376 errback=partial(self.errback, 513 errback=partial(
377 msg=_(u"can't set schema: {}"), 514 self.errback,
378 exit_code=C.EXIT_BRIDGE_ERRBACK)) 515 msg=_(u"can't set schema: {}"),
516 exit_code=C.EXIT_BRIDGE_ERRBACK,
517 ),
518 )
379 519
380 520
381 class NodeSchemaEdit(base.CommandBase, common.BaseEdit): 521 class NodeSchemaEdit(base.CommandBase, common.BaseEdit):
382 use_items=False 522 use_items = False
383 523
384 def __init__(self, host): 524 def __init__(self, host):
385 base.CommandBase.__init__(self, host, 'edit', use_pubsub=True, pubsub_flags={C.NODE}, use_draft=True, use_verbose=True, help=_(u'edit a schema')) 525 base.CommandBase.__init__(
526 self,
527 host,
528 "edit",
529 use_pubsub=True,
530 pubsub_flags={C.NODE},
531 use_draft=True,
532 use_verbose=True,
533 help=_(u"edit a schema"),
534 )
386 common.BaseEdit.__init__(self, self.host, PUBSUB_SCHEMA_TMP_DIR) 535 common.BaseEdit.__init__(self, self.host, PUBSUB_SCHEMA_TMP_DIR)
387 self.need_loop=True 536 self.need_loop = True
388 537
389 def add_parser_options(self): 538 def add_parser_options(self):
390 pass 539 pass
391 540
392 def psSchemaSetCb(self): 541 def psSchemaSetCb(self):
393 self.disp(_(u'schema has been set'), 1) 542 self.disp(_(u"schema has been set"), 1)
394 self.host.quit() 543 self.host.quit()
395 544
396 def publish(self, schema): 545 def publish(self, schema):
397 self.host.bridge.psSchemaSet( 546 self.host.bridge.psSchemaSet(
398 self.args.service, 547 self.args.service,
399 self.args.node, 548 self.args.node,
400 schema, 549 schema,
401 self.profile, 550 self.profile,
402 callback=self.psSchemaSetCb, 551 callback=self.psSchemaSetCb,
403 errback=partial(self.errback, 552 errback=partial(
404 msg=_(u"can't set schema: {}"), 553 self.errback,
405 exit_code=C.EXIT_BRIDGE_ERRBACK)) 554 msg=_(u"can't set schema: {}"),
555 exit_code=C.EXIT_BRIDGE_ERRBACK,
556 ),
557 )
406 558
407 def psSchemaGetCb(self, schema): 559 def psSchemaGetCb(self, schema):
408 try: 560 try:
409 from lxml import etree 561 from lxml import etree
410 except ImportError: 562 except ImportError:
411 self.disp(u"lxml module must be installed to use edit, please install it with \"pip install lxml\"", error=True) 563 self.disp(
564 u'lxml module must be installed to use edit, please install it with "pip install lxml"',
565 error=True,
566 )
412 self.host.quit(1) 567 self.host.quit(1)
413 content_file_obj, content_file_path = self.getTmpFile() 568 content_file_obj, content_file_path = self.getTmpFile()
414 schema = schema.strip() 569 schema = schema.strip()
415 if schema: 570 if schema:
416 parser = etree.XMLParser(remove_blank_text=True) 571 parser = etree.XMLParser(remove_blank_text=True)
417 schema_elt = etree.fromstring(schema, parser) 572 schema_elt = etree.fromstring(schema, parser)
418 content_file_obj.write(etree.tostring(schema_elt, encoding="utf-8", pretty_print=True)) 573 content_file_obj.write(
574 etree.tostring(schema_elt, encoding="utf-8", pretty_print=True)
575 )
419 content_file_obj.seek(0) 576 content_file_obj.seek(0)
420 self.runEditor("pubsub_schema_editor_args", content_file_path, content_file_obj) 577 self.runEditor("pubsub_schema_editor_args", content_file_path, content_file_obj)
421 578
422 def start(self): 579 def start(self):
423 self.host.bridge.psSchemaGet( 580 self.host.bridge.psSchemaGet(
424 self.args.service, 581 self.args.service,
425 self.args.node, 582 self.args.node,
426 self.profile, 583 self.profile,
427 callback=self.psSchemaGetCb, 584 callback=self.psSchemaGetCb,
428 errback=partial(self.errback, 585 errback=partial(
429 msg=_(u"can't edit schema: {}"), 586 self.errback,
430 exit_code=C.EXIT_BRIDGE_ERRBACK)) 587 msg=_(u"can't edit schema: {}"),
588 exit_code=C.EXIT_BRIDGE_ERRBACK,
589 ),
590 )
431 591
432 592
433 class NodeSchemaGet(base.CommandBase): 593 class NodeSchemaGet(base.CommandBase):
434 594 def __init__(self, host):
435 def __init__(self, host): 595 base.CommandBase.__init__(
436 base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_XML, use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'get schema')) 596 self,
437 self.need_loop=True 597 host,
598 "get",
599 use_output=C.OUTPUT_XML,
600 use_pubsub=True,
601 pubsub_flags={C.NODE},
602 use_verbose=True,
603 help=_(u"get schema"),
604 )
605 self.need_loop = True
438 606
439 def add_parser_options(self): 607 def add_parser_options(self):
440 pass 608 pass
441 609
442 def psSchemaGetCb(self, schema): 610 def psSchemaGetCb(self, schema):
443 if not schema: 611 if not schema:
444 self.disp(_(u'no schema found'), 1) 612 self.disp(_(u"no schema found"), 1)
445 self.host.quit(1) 613 self.host.quit(1)
446 self.output(schema) 614 self.output(schema)
447 self.host.quit() 615 self.host.quit()
448 616
449 def start(self): 617 def start(self):
450 self.host.bridge.psSchemaGet( 618 self.host.bridge.psSchemaGet(
451 self.args.service, 619 self.args.service,
452 self.args.node, 620 self.args.node,
453 self.profile, 621 self.profile,
454 callback=self.psSchemaGetCb, 622 callback=self.psSchemaGetCb,
455 errback=partial(self.errback, 623 errback=partial(
456 msg=_(u"can't get schema: {}"), 624 self.errback,
457 exit_code=C.EXIT_BRIDGE_ERRBACK)) 625 msg=_(u"can't get schema: {}"),
626 exit_code=C.EXIT_BRIDGE_ERRBACK,
627 ),
628 )
458 629
459 630
460 class NodeSchema(base.CommandBase): 631 class NodeSchema(base.CommandBase):
461 subcommands = (NodeSchemaSet, NodeSchemaEdit, NodeSchemaGet) 632 subcommands = (NodeSchemaSet, NodeSchemaEdit, NodeSchemaGet)
462 633
463 def __init__(self, host): 634 def __init__(self, host):
464 super(NodeSchema, self).__init__(host, 'schema', use_profile=False, help=_(u"data schema manipulation")) 635 super(NodeSchema, self).__init__(
636 host, "schema", use_profile=False, help=_(u"data schema manipulation")
637 )
465 638
466 639
467 class Node(base.CommandBase): 640 class Node(base.CommandBase):
468 subcommands = (NodeInfo, NodeCreate, NodeDelete, NodeSet, NodeAffiliations, NodeSubscriptions, NodeSchema) 641 subcommands = (
469 642 NodeInfo,
470 def __init__(self, host): 643 NodeCreate,
471 super(Node, self).__init__(host, 'node', use_profile=False, help=_('node handling')) 644 NodeDelete,
645 NodeSet,
646 NodeAffiliations,
647 NodeSubscriptions,
648 NodeSchema,
649 )
650
651 def __init__(self, host):
652 super(Node, self).__init__(
653 host, "node", use_profile=False, help=_("node handling")
654 )
472 655
473 656
474 class Set(base.CommandBase): 657 class Set(base.CommandBase):
475 658 def __init__(self, host):
476 def __init__(self, host): 659 base.CommandBase.__init__(
477 base.CommandBase.__init__(self, host, 'set', use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'publish a new item or update an existing one')) 660 self,
478 self.need_loop=True 661 host,
479 662 "set",
480 def add_parser_options(self): 663 use_pubsub=True,
481 self.parser.add_argument("item", type=base.unicode_decoder, nargs='?', default=u'', help=_(u"id, URL of the item to update, keyword, or nothing for new item")) 664 pubsub_flags={C.NODE},
665 help=_(u"publish a new item or update an existing one"),
666 )
667 self.need_loop = True
668
669 def add_parser_options(self):
670 self.parser.add_argument(
671 "item",
672 type=base.unicode_decoder,
673 nargs="?",
674 default=u"",
675 help=_(u"id, URL of the item to update, keyword, or nothing for new item"),
676 )
482 677
483 def psItemsSendCb(self, published_id): 678 def psItemsSendCb(self, published_id):
484 if published_id: 679 if published_id:
485 self.disp(u"Item published at {pub_id}".format(pub_id=published_id)) 680 self.disp(u"Item published at {pub_id}".format(pub_id=published_id))
486 else: 681 else:
489 684
490 def start(self): 685 def start(self):
491 try: 686 try:
492 from lxml import etree 687 from lxml import etree
493 except ImportError: 688 except ImportError:
494 self.disp(u"lxml module must be installed to use edit, please install it with \"pip install lxml\"", error=True) 689 self.disp(
690 u'lxml module must be installed to use edit, please install it with "pip install lxml"',
691 error=True,
692 )
495 self.host.quit(1) 693 self.host.quit(1)
496 try: 694 try:
497 element = etree.parse(sys.stdin).getroot() 695 element = etree.parse(sys.stdin).getroot()
498 except Exception as e: 696 except Exception as e:
499 self.parser.error(_(u"Can't parse the payload XML in input: {msg}").format(msg=e)) 697 self.parser.error(
500 if element.tag in ('item', '{http://jabber.org/protocol/pubsub}item'): 698 _(u"Can't parse the payload XML in input: {msg}").format(msg=e)
699 )
700 if element.tag in ("item", "{http://jabber.org/protocol/pubsub}item"):
501 if len(element) > 1: 701 if len(element) > 1:
502 self.parser.error(_(u"<item> can only have one child element (the payload)")) 702 self.parser.error(
703 _(u"<item> can only have one child element (the payload)")
704 )
503 element = element[0] 705 element = element[0]
504 payload = etree.tostring(element, encoding='unicode') 706 payload = etree.tostring(element, encoding="unicode")
505 707
506 self.host.bridge.psItemSend(self.args.service, 708 self.host.bridge.psItemSend(
507 self.args.node, 709 self.args.service,
508 payload, 710 self.args.node,
509 self.args.item, 711 payload,
510 {}, 712 self.args.item,
511 self.profile, 713 {},
512 callback=self.psItemsSendCb, 714 self.profile,
513 errback=partial(self.errback, 715 callback=self.psItemsSendCb,
514 msg=_(u"can't send item: {}"), 716 errback=partial(
515 exit_code=C.EXIT_BRIDGE_ERRBACK)) 717 self.errback,
718 msg=_(u"can't send item: {}"),
719 exit_code=C.EXIT_BRIDGE_ERRBACK,
720 ),
721 )
516 722
517 723
518 class Get(base.CommandBase): 724 class Get(base.CommandBase):
519 725 def __init__(self, host):
520 def __init__(self, host): 726 base.CommandBase.__init__(
521 base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_LIST_XML, use_pubsub=True, pubsub_flags={C.NODE, C.MULTI_ITEMS}, help=_(u'get pubsub item(s)')) 727 self,
522 self.need_loop=True 728 host,
523 729 "get",
524 def add_parser_options(self): 730 use_output=C.OUTPUT_LIST_XML,
525 self.parser.add_argument("-S", "--sub-id", type=base.unicode_decoder, default=u'', 731 use_pubsub=True,
526 help=_(u"subscription id")) 732 pubsub_flags={C.NODE, C.MULTI_ITEMS},
527 # TODO: a key(s) argument to select keys to display 733 help=_(u"get pubsub item(s)"),
734 )
735 self.need_loop = True
736
737 def add_parser_options(self):
738 self.parser.add_argument(
739 "-S",
740 "--sub-id",
741 type=base.unicode_decoder,
742 default=u"",
743 help=_(u"subscription id"),
744 )
745 #  TODO: a key(s) argument to select keys to display
528 # TODO: add MAM filters 746 # TODO: add MAM filters
529
530 747
531 def psItemsGetCb(self, ps_result): 748 def psItemsGetCb(self, ps_result):
532 self.output(ps_result[0]) 749 self.output(ps_result[0])
533 self.host.quit(C.EXIT_OK) 750 self.host.quit(C.EXIT_OK)
534 751
535 def psItemsGetEb(self, failure_): 752 def psItemsGetEb(self, failure_):
536 self.disp(u"can't get pubsub items: {reason}".format( 753 self.disp(u"can't get pubsub items: {reason}".format(reason=failure_), error=True)
537 reason=failure_), error=True)
538 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 754 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
539 755
540 def start(self): 756 def start(self):
541 self.host.bridge.psItemsGet( 757 self.host.bridge.psItemsGet(
542 self.args.service, 758 self.args.service,
545 self.args.items, 761 self.args.items,
546 self.args.sub_id, 762 self.args.sub_id,
547 {}, 763 {},
548 self.profile, 764 self.profile,
549 callback=self.psItemsGetCb, 765 callback=self.psItemsGetCb,
550 errback=self.psItemsGetEb) 766 errback=self.psItemsGetEb,
767 )
768
551 769
552 class Delete(base.CommandBase): 770 class Delete(base.CommandBase):
553 771 def __init__(self, host):
554 def __init__(self, host): 772 base.CommandBase.__init__(
555 base.CommandBase.__init__(self, host, 'delete', use_pubsub=True, pubsub_flags={C.NODE, C.SINGLE_ITEM}, help=_(u'delete an item')) 773 self,
556 self.need_loop=True 774 host,
557 775 "delete",
558 def add_parser_options(self): 776 use_pubsub=True,
559 self.parser.add_argument("-f", "--force", action='store_true', help=_(u"delete without confirmation")) 777 pubsub_flags={C.NODE, C.SINGLE_ITEM},
560 self.parser.add_argument("-N", "--notify", action='store_true', help=_(u"notify deletion")) 778 help=_(u"delete an item"),
779 )
780 self.need_loop = True
781
782 def add_parser_options(self):
783 self.parser.add_argument(
784 "-f", "--force", action="store_true", help=_(u"delete without confirmation")
785 )
786 self.parser.add_argument(
787 "-N", "--notify", action="store_true", help=_(u"notify deletion")
788 )
561 789
562 def psItemsDeleteCb(self): 790 def psItemsDeleteCb(self):
563 self.disp(_(u'item {item_id} has been deleted').format(item_id=self.args.item)) 791 self.disp(_(u"item {item_id} has been deleted").format(item_id=self.args.item))
564 self.host.quit(C.EXIT_OK) 792 self.host.quit(C.EXIT_OK)
565 793
566 def start(self): 794 def start(self):
567 if not self.args.item: 795 if not self.args.item:
568 self.parser.error(_(u"You need to specify an item to delete")) 796 self.parser.error(_(u"You need to specify an item to delete"))
569 if not self.args.force: 797 if not self.args.force:
570 message = _(u"Are you sure to delete item {item_id} ?").format(item_id=self.args.item) 798 message = _(u"Are you sure to delete item {item_id} ?").format(
799 item_id=self.args.item
800 )
571 self.host.confirmOrQuit(message, _(u"item deletion cancelled")) 801 self.host.confirmOrQuit(message, _(u"item deletion cancelled"))
572 self.host.bridge.psRetractItem( 802 self.host.bridge.psRetractItem(
573 self.args.service, 803 self.args.service,
574 self.args.node, 804 self.args.node,
575 self.args.item, 805 self.args.item,
576 self.args.notify, 806 self.args.notify,
577 self.profile, 807 self.profile,
578 callback=self.psItemsDeleteCb, 808 callback=self.psItemsDeleteCb,
579 errback=partial(self.errback, 809 errback=partial(
580 msg=_(u"can't delete item: {}"), 810 self.errback,
581 exit_code=C.EXIT_BRIDGE_ERRBACK)) 811 msg=_(u"can't delete item: {}"),
812 exit_code=C.EXIT_BRIDGE_ERRBACK,
813 ),
814 )
582 815
583 816
584 class Edit(base.CommandBase, common.BaseEdit): 817 class Edit(base.CommandBase, common.BaseEdit):
585 818 def __init__(self, host):
586 def __init__(self, host): 819 base.CommandBase.__init__(
587 base.CommandBase.__init__(self, host, 'edit', use_verbose=True, use_pubsub=True, 820 self,
588 pubsub_flags={C.NODE, C.SINGLE_ITEM}, use_draft=True, help=_(u'edit an existing or new pubsub item')) 821 host,
822 "edit",
823 use_verbose=True,
824 use_pubsub=True,
825 pubsub_flags={C.NODE, C.SINGLE_ITEM},
826 use_draft=True,
827 help=_(u"edit an existing or new pubsub item"),
828 )
589 common.BaseEdit.__init__(self, self.host, PUBSUB_TMP_DIR) 829 common.BaseEdit.__init__(self, self.host, PUBSUB_TMP_DIR)
590 830
591 def add_parser_options(self): 831 def add_parser_options(self):
592 pass 832 pass
593 833
594 def edit(self, content_file_path, content_file_obj): 834 def edit(self, content_file_path, content_file_obj):
595 # we launch editor 835 # we launch editor
596 self.runEditor("pubsub_editor_args", content_file_path, content_file_obj) 836 self.runEditor("pubsub_editor_args", content_file_path, content_file_obj)
597 837
598 def publish(self, content): 838 def publish(self, content):
599 published_id = self.host.bridge.psItemSend(self.pubsub_service, self.pubsub_node, content, self.pubsub_item or '', {}, self.profile) 839 published_id = self.host.bridge.psItemSend(
840 self.pubsub_service,
841 self.pubsub_node,
842 content,
843 self.pubsub_item or "",
844 {},
845 self.profile,
846 )
600 if published_id: 847 if published_id:
601 self.disp(u"Item published at {pub_id}".format(pub_id=published_id)) 848 self.disp(u"Item published at {pub_id}".format(pub_id=published_id))
602 else: 849 else:
603 self.disp(u"Item published") 850 self.disp(u"Item published")
604 851
605 def getItemData(self, service, node, item): 852 def getItemData(self, service, node, item):
606 try: 853 try:
607 from lxml import etree 854 from lxml import etree
608 except ImportError: 855 except ImportError:
609 self.disp(u"lxml module must be installed to use edit, please install it with \"pip install lxml\"", error=True) 856 self.disp(
857 u'lxml module must be installed to use edit, please install it with "pip install lxml"',
858 error=True,
859 )
610 self.host.quit(1) 860 self.host.quit(1)
611 items = [item] if item is not None else [] 861 items = [item] if item is not None else []
612 item_raw = self.host.bridge.psItemsGet(service, node, 1, items, "", {}, self.profile)[0][0] 862 item_raw = self.host.bridge.psItemsGet(
863 service, node, 1, items, "", {}, self.profile
864 )[0][0]
613 parser = etree.XMLParser(remove_blank_text=True) 865 parser = etree.XMLParser(remove_blank_text=True)
614 item_elt = etree.fromstring(item_raw, parser) 866 item_elt = etree.fromstring(item_raw, parser)
615 item_id = item_elt.get('id') 867 item_id = item_elt.get("id")
616 try: 868 try:
617 payload = item_elt[0] 869 payload = item_elt[0]
618 except IndexError: 870 except IndexError:
619 self.disp(_(u'Item has not payload'), 1) 871 self.disp(_(u"Item has not payload"), 1)
620 return u'' 872 return u""
621 return etree.tostring(payload, encoding="unicode", pretty_print=True), item_id 873 return etree.tostring(payload, encoding="unicode", pretty_print=True), item_id
622 874
623 def start(self): 875 def start(self):
624 self.pubsub_service, self.pubsub_node, self.pubsub_item, content_file_path, content_file_obj = self.getItemPath() 876 self.pubsub_service, self.pubsub_node, self.pubsub_item, content_file_path, content_file_obj = (
877 self.getItemPath()
878 )
625 self.edit(content_file_path, content_file_obj) 879 self.edit(content_file_path, content_file_obj)
626 880
627 881
628 class Subscribe(base.CommandBase): 882 class Subscribe(base.CommandBase):
629 883 def __init__(self, host):
630 def __init__(self, host): 884 base.CommandBase.__init__(
631 base.CommandBase.__init__(self, host, 'subscribe', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'subscribe to a node')) 885 self,
632 self.need_loop=True 886 host,
887 "subscribe",
888 use_pubsub=True,
889 pubsub_flags={C.NODE},
890 use_verbose=True,
891 help=_(u"subscribe to a node"),
892 )
893 self.need_loop = True
633 894
634 def add_parser_options(self): 895 def add_parser_options(self):
635 pass 896 pass
636 897
637 def psSubscribeCb(self, sub_id): 898 def psSubscribeCb(self, sub_id):
638 self.disp(_(u'subscription done'), 1) 899 self.disp(_(u"subscription done"), 1)
639 if sub_id: 900 if sub_id:
640 self.disp(_(u'subscription id: {sub_id}').format(sub_id=sub_id)) 901 self.disp(_(u"subscription id: {sub_id}").format(sub_id=sub_id))
641 self.host.quit() 902 self.host.quit()
642 903
643 def start(self): 904 def start(self):
644 self.host.bridge.psSubscribe( 905 self.host.bridge.psSubscribe(
645 self.args.service, 906 self.args.service,
646 self.args.node, 907 self.args.node,
647 {}, 908 {},
648 self.profile, 909 self.profile,
649 callback=self.psSubscribeCb, 910 callback=self.psSubscribeCb,
650 errback=partial(self.errback, 911 errback=partial(
651 msg=_(u"can't subscribe to node: {}"), 912 self.errback,
652 exit_code=C.EXIT_BRIDGE_ERRBACK)) 913 msg=_(u"can't subscribe to node: {}"),
914 exit_code=C.EXIT_BRIDGE_ERRBACK,
915 ),
916 )
653 917
654 918
655 class Unsubscribe(base.CommandBase): 919 class Unsubscribe(base.CommandBase):
656 # TODO: voir pourquoi NodeNotFound sur subscribe juste après unsubscribe 920 # TODO: voir pourquoi NodeNotFound sur subscribe juste après unsubscribe
657 921
658 def __init__(self, host): 922 def __init__(self, host):
659 base.CommandBase.__init__(self, host, 'unsubscribe', use_pubsub=True, pubsub_flags={C.NODE}, use_verbose=True, help=_(u'unsubscribe from a node')) 923 base.CommandBase.__init__(
660 self.need_loop=True 924 self,
925 host,
926 "unsubscribe",
927 use_pubsub=True,
928 pubsub_flags={C.NODE},
929 use_verbose=True,
930 help=_(u"unsubscribe from a node"),
931 )
932 self.need_loop = True
661 933
662 def add_parser_options(self): 934 def add_parser_options(self):
663 pass 935 pass
664 936
665 def psUnsubscribeCb(self): 937 def psUnsubscribeCb(self):
666 self.disp(_(u'subscription removed'), 1) 938 self.disp(_(u"subscription removed"), 1)
667 self.host.quit() 939 self.host.quit()
668 940
669 def start(self): 941 def start(self):
670 self.host.bridge.psUnsubscribe( 942 self.host.bridge.psUnsubscribe(
671 self.args.service, 943 self.args.service,
672 self.args.node, 944 self.args.node,
673 self.profile, 945 self.profile,
674 callback=self.psUnsubscribeCb, 946 callback=self.psUnsubscribeCb,
675 errback=partial(self.errback, 947 errback=partial(
676 msg=_(u"can't unsubscribe from node: {}"), 948 self.errback,
677 exit_code=C.EXIT_BRIDGE_ERRBACK)) 949 msg=_(u"can't unsubscribe from node: {}"),
950 exit_code=C.EXIT_BRIDGE_ERRBACK,
951 ),
952 )
678 953
679 954
680 class Subscriptions(base.CommandBase): 955 class Subscriptions(base.CommandBase):
681 956 def __init__(self, host):
682 def __init__(self, host): 957 base.CommandBase.__init__(
683 base.CommandBase.__init__(self, host, 'subscriptions', use_output=C.OUTPUT_LIST_DICT, use_pubsub=True, help=_(u'retrieve all subscriptions on a service')) 958 self,
684 self.need_loop=True 959 host,
960 "subscriptions",
961 use_output=C.OUTPUT_LIST_DICT,
962 use_pubsub=True,
963 help=_(u"retrieve all subscriptions on a service"),
964 )
965 self.need_loop = True
685 966
686 def add_parser_options(self): 967 def add_parser_options(self):
687 pass 968 pass
688 969
689 def psSubscriptionsGetCb(self, subscriptions): 970 def psSubscriptionsGetCb(self, subscriptions):
694 self.host.bridge.psSubscriptionsGet( 975 self.host.bridge.psSubscriptionsGet(
695 self.args.service, 976 self.args.service,
696 self.args.node, 977 self.args.node,
697 self.profile, 978 self.profile,
698 callback=self.psSubscriptionsGetCb, 979 callback=self.psSubscriptionsGetCb,
699 errback=partial(self.errback, 980 errback=partial(
700 msg=_(u"can't retrieve subscriptions: {}"), 981 self.errback,
701 exit_code=C.EXIT_BRIDGE_ERRBACK)) 982 msg=_(u"can't retrieve subscriptions: {}"),
983 exit_code=C.EXIT_BRIDGE_ERRBACK,
984 ),
985 )
702 986
703 987
704 class Affiliations(base.CommandBase): 988 class Affiliations(base.CommandBase):
705 989 def __init__(self, host):
706 def __init__(self, host): 990 base.CommandBase.__init__(
707 base.CommandBase.__init__(self, host, 'affiliations', use_output=C.OUTPUT_DICT, use_pubsub=True, help=_(u'retrieve all affiliations on a service')) 991 self,
708 self.need_loop=True 992 host,
993 "affiliations",
994 use_output=C.OUTPUT_DICT,
995 use_pubsub=True,
996 help=_(u"retrieve all affiliations on a service"),
997 )
998 self.need_loop = True
709 999
710 def add_parser_options(self): 1000 def add_parser_options(self):
711 pass 1001 pass
712 1002
713 def psAffiliationsGetCb(self, affiliations): 1003 def psAffiliationsGetCb(self, affiliations):
714 self.output(affiliations) 1004 self.output(affiliations)
715 self.host.quit() 1005 self.host.quit()
716 1006
717 def psAffiliationsGetEb(self, failure_): 1007 def psAffiliationsGetEb(self, failure_):
718 self.disp(u"can't get node affiliations: {reason}".format( 1008 self.disp(
719 reason=failure_), error=True) 1009 u"can't get node affiliations: {reason}".format(reason=failure_), error=True
1010 )
720 self.host.quit(C.EXIT_BRIDGE_ERRBACK) 1011 self.host.quit(C.EXIT_BRIDGE_ERRBACK)
721 1012
722 def start(self): 1013 def start(self):
723 self.host.bridge.psAffiliationsGet( 1014 self.host.bridge.psAffiliationsGet(
724 self.args.service, 1015 self.args.service,
725 self.args.node, 1016 self.args.node,
726 self.profile, 1017 self.profile,
727 callback=self.psAffiliationsGetCb, 1018 callback=self.psAffiliationsGetCb,
728 errback=self.psAffiliationsGetEb) 1019 errback=self.psAffiliationsGetEb,
1020 )
729 1021
730 1022
731 class Search(base.CommandBase): 1023 class Search(base.CommandBase):
732 """this command to a search without using MAM, i.e. by checking every items if dound by itself, so it may be heavy in resources both for server and client""" 1024 """this command to a search without using MAM, i.e. by checking every items if dound by itself, so it may be heavy in resources both for server and client"""
1025
733 RE_FLAGS = re.MULTILINE | re.UNICODE 1026 RE_FLAGS = re.MULTILINE | re.UNICODE
734 EXEC_ACTIONS = (u'exec', u'external') 1027 EXEC_ACTIONS = (u"exec", u"external")
735 1028
736 def __init__(self, host): 1029 def __init__(self, host):
737 base.CommandBase.__init__(self, host, 'search', use_output=C.OUTPUT_XML, use_pubsub=True, pubsub_flags={C.MULTI_ITEMS, C.NO_MAX}, 1030 base.CommandBase.__init__(
738 use_verbose=True, help=_(u'search items corresponding to filters')) 1031 self,
739 self.need_loop=True 1032 host,
1033 "search",
1034 use_output=C.OUTPUT_XML,
1035 use_pubsub=True,
1036 pubsub_flags={C.MULTI_ITEMS, C.NO_MAX},
1037 use_verbose=True,
1038 help=_(u"search items corresponding to filters"),
1039 )
1040 self.need_loop = True
740 1041
741 @property 1042 @property
742 def etree(self): 1043 def etree(self):
743 """load lxml.etree only if needed""" 1044 """load lxml.etree only if needed"""
744 if self._etree is None: 1045 if self._etree is None:
745 from lxml import etree 1046 from lxml import etree
1047
746 self._etree = etree 1048 self._etree = etree
747 return self._etree 1049 return self._etree
748 1050
749 def filter_opt(self, value, type_): 1051 def filter_opt(self, value, type_):
750 value = base.unicode_decoder(value) 1052 value = base.unicode_decoder(value)
753 def filter_flag(self, value, type_): 1055 def filter_flag(self, value, type_):
754 value = C.bool(value) 1056 value = C.bool(value)
755 return (type_, value) 1057 return (type_, value)
756 1058
757 def add_parser_options(self): 1059 def add_parser_options(self):
758 self.parser.add_argument("-D", "--max-depth", type=int, default=0, help=_(u"maximum depth of recursion (will search linked nodes if > 0, default: 0)")) 1060 self.parser.add_argument(
759 self.parser.add_argument("-m", "--max", type=int, default=30, help=_(u"maximum number of items to get per node ({} to get all items, default: 30)".format(C.NO_LIMIT))) 1061 "-D",
760 self.parser.add_argument("-N", "--namespace", action='append', nargs=2, default=[], 1062 "--max-depth",
761 metavar="NAME NAMESPACE", help=_(u"namespace to use for xpath")) 1063 type=int,
1064 default=0,
1065 help=_(
1066 u"maximum depth of recursion (will search linked nodes if > 0, default: 0)"
1067 ),
1068 )
1069 self.parser.add_argument(
1070 "-m",
1071 "--max",
1072 type=int,
1073 default=30,
1074 help=_(
1075 u"maximum number of items to get per node ({} to get all items, default: 30)".format(
1076 C.NO_LIMIT
1077 )
1078 ),
1079 )
1080 self.parser.add_argument(
1081 "-N",
1082 "--namespace",
1083 action="append",
1084 nargs=2,
1085 default=[],
1086 metavar="NAME NAMESPACE",
1087 help=_(u"namespace to use for xpath"),
1088 )
762 1089
763 # filters 1090 # filters
764 filter_text = partial(self.filter_opt, type_=u'text') 1091 filter_text = partial(self.filter_opt, type_=u"text")
765 filter_re = partial(self.filter_opt, type_=u'regex') 1092 filter_re = partial(self.filter_opt, type_=u"regex")
766 filter_xpath = partial(self.filter_opt, type_=u'xpath') 1093 filter_xpath = partial(self.filter_opt, type_=u"xpath")
767 filter_python = partial(self.filter_opt, type_=u'python') 1094 filter_python = partial(self.filter_opt, type_=u"python")
768 filters = self.parser.add_argument_group(_(u'filters'), _(u'only items corresponding to following filters will be kept')) 1095 filters = self.parser.add_argument_group(
769 filters.add_argument("-t", "--text", 1096 _(u"filters"),
770 action='append', dest='filters', type=filter_text, 1097 _(u"only items corresponding to following filters will be kept"),
771 metavar='TEXT', 1098 )
772 help=_(u"full text filter, item must contain this string (XML included)")) 1099 filters.add_argument(
773 filters.add_argument("-r", "--regex", 1100 "-t",
774 action='append', dest='filters', type=filter_re, 1101 "--text",
775 metavar='EXPRESSION', 1102 action="append",
776 help=_(u"like --text but using a regular expression")) 1103 dest="filters",
777 filters.add_argument("-x", "--xpath", 1104 type=filter_text,
778 action='append', dest='filters', type=filter_xpath, 1105 metavar="TEXT",
779 metavar='XPATH', 1106 help=_(u"full text filter, item must contain this string (XML included)"),
780 help=_(u"filter items which has elements matching this xpath")) 1107 )
781 filters.add_argument("-P", "--python", 1108 filters.add_argument(
782 action='append', dest='filters', type=filter_python, 1109 "-r",
783 metavar='PYTHON_CODE', 1110 "--regex",
784 help=_(u'Python expression which much return a bool (True to keep item, False to reject it). "item" is raw text item, "item_xml" is lxml\'s etree.Element')) 1111 action="append",
1112 dest="filters",
1113 type=filter_re,
1114 metavar="EXPRESSION",
1115 help=_(u"like --text but using a regular expression"),
1116 )
1117 filters.add_argument(
1118 "-x",
1119 "--xpath",
1120 action="append",
1121 dest="filters",
1122 type=filter_xpath,
1123 metavar="XPATH",
1124 help=_(u"filter items which has elements matching this xpath"),
1125 )
1126 filters.add_argument(
1127 "-P",
1128 "--python",
1129 action="append",
1130 dest="filters",
1131 type=filter_python,
1132 metavar="PYTHON_CODE",
1133 help=_(
1134 u'Python expression which much return a bool (True to keep item, False to reject it). "item" is raw text item, "item_xml" is lxml\'s etree.Element'
1135 ),
1136 )
785 1137
786 # filters flags 1138 # filters flags
787 flag_case = partial(self.filter_flag, type_=u'ignore-case') 1139 flag_case = partial(self.filter_flag, type_=u"ignore-case")
788 flag_invert = partial(self.filter_flag, type_=u'invert') 1140 flag_invert = partial(self.filter_flag, type_=u"invert")
789 flag_dotall = partial(self.filter_flag, type_=u'dotall') 1141 flag_dotall = partial(self.filter_flag, type_=u"dotall")
790 flag_matching = partial(self.filter_flag, type_=u'only-matching') 1142 flag_matching = partial(self.filter_flag, type_=u"only-matching")
791 flags = self.parser.add_argument_group(_(u'filters flags'), _(u'filters modifiers (change behaviour of following filters)')) 1143 flags = self.parser.add_argument_group(
792 flags.add_argument("-C", "--ignore-case", 1144 _(u"filters flags"),
793 action='append', dest='filters', type=flag_case, 1145 _(u"filters modifiers (change behaviour of following filters)"),
794 const=('ignore-case', True), nargs='?', 1146 )
795 metavar='BOOLEAN', 1147 flags.add_argument(
796 help=_(u"(don't) ignore case in following filters (default: case sensitive)")) 1148 "-C",
797 flags.add_argument("-I", "--invert", 1149 "--ignore-case",
798 action='append', dest='filters', type=flag_invert, 1150 action="append",
799 const=('invert', True), nargs='?', 1151 dest="filters",
800 metavar='BOOLEAN', 1152 type=flag_case,
801 help=_(u"(don't) invert effect of following filters (default: don't invert)")) 1153 const=("ignore-case", True),
802 flags.add_argument("-A", "--dot-all", 1154 nargs="?",
803 action='append', dest='filters', type=flag_dotall, 1155 metavar="BOOLEAN",
804 const=('dotall', True), nargs='?', 1156 help=_(u"(don't) ignore case in following filters (default: case sensitive)"),
805 metavar='BOOLEAN', 1157 )
806 help=_(u"(don't) use DOTALL option for regex (default: don't use)")) 1158 flags.add_argument(
807 flags.add_argument("-o", "--only-matching", 1159 "-I",
808 action='append', dest='filters', type=flag_matching, 1160 "--invert",
809 const=('only-matching', True), nargs='?', 1161 action="append",
810 metavar='BOOLEAN', 1162 dest="filters",
811 help=_(u"keep only the matching part of the item")) 1163 type=flag_invert,
1164 const=("invert", True),
1165 nargs="?",
1166 metavar="BOOLEAN",
1167 help=_(u"(don't) invert effect of following filters (default: don't invert)"),
1168 )
1169 flags.add_argument(
1170 "-A",
1171 "--dot-all",
1172 action="append",
1173 dest="filters",
1174 type=flag_dotall,
1175 const=("dotall", True),
1176 nargs="?",
1177 metavar="BOOLEAN",
1178 help=_(u"(don't) use DOTALL option for regex (default: don't use)"),
1179 )
1180 flags.add_argument(
1181 "-o",
1182 "--only-matching",
1183 action="append",
1184 dest="filters",
1185 type=flag_matching,
1186 const=("only-matching", True),
1187 nargs="?",
1188 metavar="BOOLEAN",
1189 help=_(u"keep only the matching part of the item"),
1190 )
812 1191
813 # action 1192 # action
814 self.parser.add_argument("action", 1193 self.parser.add_argument(
815 default="print", 1194 "action",
816 nargs='?', 1195 default="print",
817 choices=('print', 'exec', 'external'), 1196 nargs="?",
818 help=_(u"action to do on found items (default: print)")) 1197 choices=("print", "exec", "external"),
1198 help=_(u"action to do on found items (default: print)"),
1199 )
819 self.parser.add_argument("command", nargs=argparse.REMAINDER) 1200 self.parser.add_argument("command", nargs=argparse.REMAINDER)
820 1201
821 def psItemsGetEb(self, failure_, service, node): 1202 def psItemsGetEb(self, failure_, service, node):
822 self.disp(u"can't get pubsub items at {service} (node: {node}): {reason}".format( 1203 self.disp(
823 service=service, 1204 u"can't get pubsub items at {service} (node: {node}): {reason}".format(
824 node=node, 1205 service=service, node=node, reason=failure_
825 reason=failure_), error=True) 1206 ),
1207 error=True,
1208 )
826 self.to_get -= 1 1209 self.to_get -= 1
827 1210
828 def getItems(self, depth, service, node, items): 1211 def getItems(self, depth, service, node, items):
829 search = partial(self.search, depth=depth) 1212 search = partial(self.search, depth=depth)
830 errback = partial(self.psItemsGetEb, service=service, node=node) 1213 errback = partial(self.psItemsGetEb, service=service, node=node)
835 items, 1218 items,
836 "", 1219 "",
837 {}, 1220 {},
838 self.profile, 1221 self.profile,
839 callback=search, 1222 callback=search,
840 errback=errback 1223 errback=errback,
841 ) 1224 )
842 self.to_get += 1 1225 self.to_get += 1
843 1226
844 def _checkPubsubURL(self, match, found_nodes): 1227 def _checkPubsubURL(self, match, found_nodes):
845 """check that the matched URL is an xmpp: one 1228 """check that the matched URL is an xmpp: one
846 1229
847 @param found_nodes(list[unicode]): found_nodes 1230 @param found_nodes(list[unicode]): found_nodes
848 this list will be filled while xmpp: URIs are discovered 1231 this list will be filled while xmpp: URIs are discovered
849 """ 1232 """
850 url = match.group(0) 1233 url = match.group(0)
851 if url.startswith(u'xmpp'): 1234 if url.startswith(u"xmpp"):
852 try: 1235 try:
853 url_data = uri.parseXMPPUri(url) 1236 url_data = uri.parseXMPPUri(url)
854 except ValueError: 1237 except ValueError:
855 return 1238 return
856 if url_data[u'type'] == u'pubsub': 1239 if url_data[u"type"] == u"pubsub":
857 found_node = {u'service': url_data[u'path'], 1240 found_node = {u"service": url_data[u"path"], u"node": url_data[u"node"]}
858 u'node': url_data[u'node']} 1241 if u"item" in url_data:
859 if u'item' in url_data: 1242 found_node[u"item"] = url_data[u"item"]
860 found_node[u'item'] = url_data[u'item']
861 found_nodes.append(found_node) 1243 found_nodes.append(found_node)
862 1244
863 def getSubNodes(self, item, depth): 1245 def getSubNodes(self, item, depth):
864 """look for pubsub URIs in item, and getItems on the linked nodes""" 1246 """look for pubsub URIs in item, and getItems on the linked nodes"""
865 found_nodes = [] 1247 found_nodes = []
866 checkURI = partial(self._checkPubsubURL, found_nodes=found_nodes) 1248 checkURI = partial(self._checkPubsubURL, found_nodes=found_nodes)
867 strings.RE_URL.sub(checkURI, item) 1249 strings.RE_URL.sub(checkURI, item)
868 for data in found_nodes: 1250 for data in found_nodes:
869 self.getItems(depth+1, 1251 self.getItems(
870 data[u'service'], 1252 depth + 1,
871 data[u'node'], 1253 data[u"service"],
872 [data[u'item']] if u'item' in data else [] 1254 data[u"node"],
873 ) 1255 [data[u"item"]] if u"item" in data else [],
1256 )
874 1257
875 def parseXml(self, item): 1258 def parseXml(self, item):
876 try: 1259 try:
877 return self.etree.fromstring(item) 1260 return self.etree.fromstring(item)
878 except self.etree.XMLSyntaxError: 1261 except self.etree.XMLSyntaxError:
879 self.disp(_(u"item doesn't looks like XML, you have probably used --only-matching somewhere before and we have no more XML"), error=True) 1262 self.disp(
1263 _(
1264 u"item doesn't looks like XML, you have probably used --only-matching somewhere before and we have no more XML"
1265 ),
1266 error=True,
1267 )
880 self.host.quit(C.EXIT_BAD_ARG) 1268 self.host.quit(C.EXIT_BAD_ARG)
881 1269
882 def filter(self, item): 1270 def filter(self, item):
883 """apply filters given on command line 1271 """apply filters given on command line
884 1272
895 for type_, value in self.args.filters: 1283 for type_, value in self.args.filters:
896 keep = True 1284 keep = True
897 1285
898 ## filters 1286 ## filters
899 1287
900 if type_ == u'text': 1288 if type_ == u"text":
901 if ignore_case: 1289 if ignore_case:
902 if value.lower() not in item.lower(): 1290 if value.lower() not in item.lower():
903 keep = False 1291 keep = False
904 else: 1292 else:
905 if value not in item: 1293 if value not in item:
906 keep = False 1294 keep = False
907 if keep and only_matching: 1295 if keep and only_matching:
908 # doesn't really make sens to keep a fixed string 1296 # doesn't really make sens to keep a fixed string
909 # so we raise an error 1297 # so we raise an error
910 self.host.disp(_(u"--only-matching used with fixed --text string, are you sure?"), error=True) 1298 self.host.disp(
1299 _(
1300 u"--only-matching used with fixed --text string, are you sure?"
1301 ),
1302 error=True,
1303 )
911 self.host.quit(C.EXIT_BAD_ARG) 1304 self.host.quit(C.EXIT_BAD_ARG)
912 elif type_ == u'regex': 1305 elif type_ == u"regex":
913 flags = self.RE_FLAGS 1306 flags = self.RE_FLAGS
914 if ignore_case: 1307 if ignore_case:
915 flags |= re.IGNORECASE 1308 flags |= re.IGNORECASE
916 if dotall: 1309 if dotall:
917 flags |= re.DOTALL 1310 flags |= re.DOTALL
918 match = re.search(value, item, flags) 1311 match = re.search(value, item, flags)
919 keep = match != None 1312 keep = match != None
920 if keep and only_matching: 1313 if keep and only_matching:
921 item = match.group() 1314 item = match.group()
922 item_xml = None 1315 item_xml = None
923 elif type_ == u'xpath': 1316 elif type_ == u"xpath":
924 if item_xml is None: 1317 if item_xml is None:
925 item_xml = self.parseXml(item) 1318 item_xml = self.parseXml(item)
926 try: 1319 try:
927 elts = item_xml.xpath(value, namespaces=self.args.namespace) 1320 elts = item_xml.xpath(value, namespaces=self.args.namespace)
928 except self.etree.XPathEvalError as e: 1321 except self.etree.XPathEvalError as e:
929 self.disp(_(u"can't use xpath: {reason}").format(reason=e), error=True) 1322 self.disp(
1323 _(u"can't use xpath: {reason}").format(reason=e), error=True
1324 )
930 self.host.quit(C.EXIT_BAD_ARG) 1325 self.host.quit(C.EXIT_BAD_ARG)
931 keep = bool(elts) 1326 keep = bool(elts)
932 if keep and only_matching: 1327 if keep and only_matching:
933 item_xml = elts[0] 1328 item_xml = elts[0]
934 try: 1329 try:
935 item = self.etree.tostring(item_xml, encoding='unicode') 1330 item = self.etree.tostring(item_xml, encoding="unicode")
936 except TypeError: 1331 except TypeError:
937 # we have a string only, not an element 1332 # we have a string only, not an element
938 item = unicode(item_xml) 1333 item = unicode(item_xml)
939 item_xml = None 1334 item_xml = None
940 elif type_ == u'python': 1335 elif type_ == u"python":
941 if item_xml is None: 1336 if item_xml is None:
942 item_xml = self.parseXml(item) 1337 item_xml = self.parseXml(item)
943 cmd_ns = {u'item': item, 1338 cmd_ns = {u"item": item, u"item_xml": item_xml}
944 u'item_xml': item_xml
945 }
946 try: 1339 try:
947 keep = eval(value, cmd_ns) 1340 keep = eval(value, cmd_ns)
948 except SyntaxError as e: 1341 except SyntaxError as e:
949 self.disp(unicode(e), error=True) 1342 self.disp(unicode(e), error=True)
950 self.host.quit(C.EXIT_BAD_ARG) 1343 self.host.quit(C.EXIT_BAD_ARG)
951 1344
952 ## flags 1345 ## flags
953 1346
954 elif type_ == u'ignore-case': 1347 elif type_ == u"ignore-case":
955 ignore_case = value 1348 ignore_case = value
956 elif type_ == u'invert': 1349 elif type_ == u"invert":
957 invert = value 1350 invert = value
958 # we need to continue, else loop would end here 1351 #  we need to continue, else loop would end here
959 continue 1352 continue
960 elif type_ == u'dotall': 1353 elif type_ == u"dotall":
961 dotall = value 1354 dotall = value
962 elif type_ == u'only-matching': 1355 elif type_ == u"only-matching":
963 only_matching = value 1356 only_matching = value
964 else: 1357 else:
965 raise exceptions.InternalError(_(u"unknown filter type {type}").format(type=type_)) 1358 raise exceptions.InternalError(
1359 _(u"unknown filter type {type}").format(type=type_)
1360 )
966 1361
967 if invert: 1362 if invert:
968 keep = not keep 1363 keep = not keep
969 if not keep: 1364 if not keep:
970 return False, item 1365 return False, item
975 """called when item has been kepts and the action need to be done 1370 """called when item has been kepts and the action need to be done
976 1371
977 @param item(unicode): accepted item 1372 @param item(unicode): accepted item
978 """ 1373 """
979 action = self.args.action 1374 action = self.args.action
980 if action == u'print' or self.host.verbosity > 0: 1375 if action == u"print" or self.host.verbosity > 0:
981 try: 1376 try:
982 self.output(item) 1377 self.output(item)
983 except self.etree.XMLSyntaxError: 1378 except self.etree.XMLSyntaxError:
984 # item is not valid XML, but a string 1379 # item is not valid XML, but a string
985 # can happen when --only-matching is used 1380 # can happen when --only-matching is used
986 self.disp(item) 1381 self.disp(item)
987 if action in self.EXEC_ACTIONS: 1382 if action in self.EXEC_ACTIONS:
988 item_elt = self.parseXml(item) 1383 item_elt = self.parseXml(item)
989 if action == u'exec': 1384 if action == u"exec":
990 use = {'service': metadata[u'service'], 1385 use = {
991 'node': metadata[u'node'], 1386 "service": metadata[u"service"],
992 'item': item_elt.get('id'), 1387 "node": metadata[u"node"],
993 'profile': self.profile 1388 "item": item_elt.get("id"),
994 } 1389 "profile": self.profile,
1390 }
995 # we need to send a copy of self.args.command 1391 # we need to send a copy of self.args.command
996 # else it would be modified 1392 # else it would be modified
997 parser_args, use_args = arg_tools.get_use_args(self.host, 1393 parser_args, use_args = arg_tools.get_use_args(
998 self.args.command, 1394 self.host, self.args.command, use, verbose=self.host.verbosity > 1
999 use, 1395 )
1000 verbose=self.host.verbosity > 1
1001 )
1002 cmd_args = sys.argv[0:1] + parser_args + use_args 1396 cmd_args = sys.argv[0:1] + parser_args + use_args
1003 else: 1397 else:
1004 cmd_args = self.args.command 1398 cmd_args = self.args.command
1005 1399
1006 1400 self.disp(
1007 self.disp(u'COMMAND: {command}'.format( 1401 u"COMMAND: {command}".format(
1008 command = u' '.join([arg_tools.escape(a) for a in cmd_args])), 2) 1402 command=u" ".join([arg_tools.escape(a) for a in cmd_args])
1009 if action == u'exec': 1403 ),
1404 2,
1405 )
1406 if action == u"exec":
1010 ret = subprocess.call(cmd_args) 1407 ret = subprocess.call(cmd_args)
1011 else: 1408 else:
1012 p = subprocess.Popen(cmd_args, stdin=subprocess.PIPE) 1409 p = subprocess.Popen(cmd_args, stdin=subprocess.PIPE)
1013 p.communicate(item.encode('utf-8')) 1410 p.communicate(item.encode("utf-8"))
1014 ret = p.wait() 1411 ret = p.wait()
1015 if ret != 0: 1412 if ret != 0:
1016 self.disp(A.color(C.A_FAILURE, _(u"executed command failed with exit code {code}").format(code=ret))) 1413 self.disp(
1414 A.color(
1415 C.A_FAILURE,
1416 _(u"executed command failed with exit code {code}").format(
1417 code=ret
1418 ),
1419 )
1420 )
1017 1421
1018 def search(self, items_data, depth): 1422 def search(self, items_data, depth):
1019 """callback of getItems 1423 """callback of getItems
1020 1424
1021 this method filters items, get sub nodes if needed, 1425 this method filters items, get sub nodes if needed,
1031 keep, item = self.filter(item) 1435 keep, item = self.filter(item)
1032 if not keep: 1436 if not keep:
1033 continue 1437 continue
1034 self.doItemAction(item, metadata) 1438 self.doItemAction(item, metadata)
1035 1439
1036 # we check if we got all getItems results 1440 #  we check if we got all getItems results
1037 self.to_get -= 1 1441 self.to_get -= 1
1038 if self.to_get == 0: 1442 if self.to_get == 0:
1039 # yes, we can quit 1443 # yes, we can quit
1040 self.host.quit() 1444 self.host.quit()
1041 assert self.to_get > 0 1445 assert self.to_get > 0
1042 1446
1043 def start(self): 1447 def start(self):
1044 if self.args.command: 1448 if self.args.command:
1045 if self.args.action not in self.EXEC_ACTIONS: 1449 if self.args.action not in self.EXEC_ACTIONS:
1046 self.parser.error(_(u"Command can only be used with {actions} actions").format( 1450 self.parser.error(
1047 actions=u', '.join(self.EXEC_ACTIONS))) 1451 _(u"Command can only be used with {actions} actions").format(
1452 actions=u", ".join(self.EXEC_ACTIONS)
1453 )
1454 )
1048 else: 1455 else:
1049 if self.args.action in self.EXEC_ACTIONS: 1456 if self.args.action in self.EXEC_ACTIONS:
1050 self.parser.error(_(u"you need to specify a command to execute")) 1457 self.parser.error(_(u"you need to specify a command to execute"))
1051 if not self.args.node: 1458 if not self.args.node:
1052 # TODO: handle get service affiliations when node is not set 1459 # TODO: handle get service affiliations when node is not set
1055 # when it reach 0 again, the command is finished 1462 # when it reach 0 again, the command is finished
1056 self.to_get = 0 1463 self.to_get = 0
1057 self._etree = None 1464 self._etree = None
1058 if self.args.filters is None: 1465 if self.args.filters is None:
1059 self.args.filters = [] 1466 self.args.filters = []
1060 self.args.namespace = dict(self.args.namespace + [('pubsub', "http://jabber.org/protocol/pubsub")]) 1467 self.args.namespace = dict(
1468 self.args.namespace + [("pubsub", "http://jabber.org/protocol/pubsub")]
1469 )
1061 self.getItems(0, self.args.service, self.args.node, self.args.items) 1470 self.getItems(0, self.args.service, self.args.node, self.args.items)
1062 1471
1063 1472
1064 class Uri(base.CommandBase): 1473 class Uri(base.CommandBase):
1065 1474 def __init__(self, host):
1066 def __init__(self, host): 1475 base.CommandBase.__init__(
1067 base.CommandBase.__init__(self, host, 'uri', use_profile=False, use_pubsub=True, pubsub_flags={C.NODE, C.SINGLE_ITEM}, help=_(u'build URI')) 1476 self,
1068 self.need_loop=True 1477 host,
1069 1478 "uri",
1070 def add_parser_options(self): 1479 use_profile=False,
1071 self.parser.add_argument("-p", "--profile", type=base.unicode_decoder, default=C.PROF_KEY_DEFAULT, help=_(u"profile (used when no server is specified)")) 1480 use_pubsub=True,
1481 pubsub_flags={C.NODE, C.SINGLE_ITEM},
1482 help=_(u"build URI"),
1483 )
1484 self.need_loop = True
1485
1486 def add_parser_options(self):
1487 self.parser.add_argument(
1488 "-p",
1489 "--profile",
1490 type=base.unicode_decoder,
1491 default=C.PROF_KEY_DEFAULT,
1492 help=_(u"profile (used when no server is specified)"),
1493 )
1072 1494
1073 def display_uri(self, jid_): 1495 def display_uri(self, jid_):
1074 uri_args = {} 1496 uri_args = {}
1075 if not self.args.service: 1497 if not self.args.service:
1076 self.args.service = jid.JID(jid_).bare 1498 self.args.service = jid.JID(jid_).bare
1077 1499
1078 for key in ('node', 'service', 'item'): 1500 for key in ("node", "service", "item"):
1079 value = getattr(self.args, key) 1501 value = getattr(self.args, key)
1080 if key == 'service': 1502 if key == "service":
1081 key = 'path' 1503 key = "path"
1082 if value: 1504 if value:
1083 uri_args[key] = value 1505 uri_args[key] = value
1084 self.disp(uri.buildXMPPUri(u'pubsub', **uri_args)) 1506 self.disp(uri.buildXMPPUri(u"pubsub", **uri_args))
1085 self.host.quit() 1507 self.host.quit()
1086 1508
1087 def start(self): 1509 def start(self):
1088 if not self.args.service: 1510 if not self.args.service:
1089 self.host.bridge.asyncGetParamA( 1511 self.host.bridge.asyncGetParamA(
1090 u'JabberID', 1512 u"JabberID",
1091 u'Connection', 1513 u"Connection",
1092 profile_key=self.args.profile, 1514 profile_key=self.args.profile,
1093 callback=self.display_uri, 1515 callback=self.display_uri,
1094 errback=partial(self.errback, 1516 errback=partial(
1095 msg=_(u"can't retrieve jid: {}"), 1517 self.errback,
1096 exit_code=C.EXIT_BRIDGE_ERRBACK)) 1518 msg=_(u"can't retrieve jid: {}"),
1519 exit_code=C.EXIT_BRIDGE_ERRBACK,
1520 ),
1521 )
1097 else: 1522 else:
1098 self.display_uri(None) 1523 self.display_uri(None)
1099 1524
1100 1525
1101 class HookCreate(base.CommandBase): 1526 class HookCreate(base.CommandBase):
1102 1527 def __init__(self, host):
1103 def __init__(self, host): 1528 base.CommandBase.__init__(
1104 base.CommandBase.__init__(self, host, 'create', use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'create a Pubsub hook')) 1529 self,
1105 self.need_loop=True 1530 host,
1106 1531 "create",
1107 def add_parser_options(self): 1532 use_pubsub=True,
1108 self.parser.add_argument('-t', '--type', default=u'python', choices=('python', 'python_file', 'python_code'), help=_(u"hook type")) 1533 pubsub_flags={C.NODE},
1109 self.parser.add_argument('-P', '--persistent', action='store_true', help=_(u"make hook persistent across restarts")) 1534 help=_(u"create a Pubsub hook"),
1110 self.parser.add_argument("hook_arg", type=base.unicode_decoder, help=_(u"argument of the hook (depend of the type)")) 1535 )
1536 self.need_loop = True
1537
1538 def add_parser_options(self):
1539 self.parser.add_argument(
1540 "-t",
1541 "--type",
1542 default=u"python",
1543 choices=("python", "python_file", "python_code"),
1544 help=_(u"hook type"),
1545 )
1546 self.parser.add_argument(
1547 "-P",
1548 "--persistent",
1549 action="store_true",
1550 help=_(u"make hook persistent across restarts"),
1551 )
1552 self.parser.add_argument(
1553 "hook_arg",
1554 type=base.unicode_decoder,
1555 help=_(u"argument of the hook (depend of the type)"),
1556 )
1111 1557
1112 @staticmethod 1558 @staticmethod
1113 def checkArgs(self): 1559 def checkArgs(self):
1114 if self.args.type == u'python_file': 1560 if self.args.type == u"python_file":
1115 self.args.hook_arg = os.path.abspath(self.args.hook_arg) 1561 self.args.hook_arg = os.path.abspath(self.args.hook_arg)
1116 if not os.path.isfile(self.args.hook_arg): 1562 if not os.path.isfile(self.args.hook_arg):
1117 self.parser.error(_(u"{path} is not a file").format(path=self.args.hook_arg)) 1563 self.parser.error(
1564 _(u"{path} is not a file").format(path=self.args.hook_arg)
1565 )
1118 1566
1119 def start(self): 1567 def start(self):
1120 self.checkArgs(self) 1568 self.checkArgs(self)
1121 self.host.bridge.psHookAdd( 1569 self.host.bridge.psHookAdd(
1122 self.args.service, 1570 self.args.service,
1124 self.args.type, 1572 self.args.type,
1125 self.args.hook_arg, 1573 self.args.hook_arg,
1126 self.args.persistent, 1574 self.args.persistent,
1127 self.profile, 1575 self.profile,
1128 callback=self.host.quit, 1576 callback=self.host.quit,
1129 errback=partial(self.errback, 1577 errback=partial(
1130 msg=_(u"can't create hook: {}"), 1578 self.errback,
1131 exit_code=C.EXIT_BRIDGE_ERRBACK)) 1579 msg=_(u"can't create hook: {}"),
1580 exit_code=C.EXIT_BRIDGE_ERRBACK,
1581 ),
1582 )
1132 1583
1133 1584
1134 class HookDelete(base.CommandBase): 1585 class HookDelete(base.CommandBase):
1135 1586 def __init__(self, host):
1136 def __init__(self, host): 1587 base.CommandBase.__init__(
1137 base.CommandBase.__init__(self, host, 'delete', use_pubsub=True, pubsub_flags={C.NODE}, help=_(u'delete a Pubsub hook')) 1588 self,
1138 self.need_loop=True 1589 host,
1139 1590 "delete",
1140 def add_parser_options(self): 1591 use_pubsub=True,
1141 self.parser.add_argument('-t', '--type', default=u'', choices=('', 'python', 'python_file', 'python_code'), help=_(u"hook type to remove, empty to remove all (default: remove all)")) 1592 pubsub_flags={C.NODE},
1142 self.parser.add_argument('-a', '--arg', dest='hook_arg', type=base.unicode_decoder, default=u'', help=_(u"argument of the hook to remove, empty to remove all (default: remove all)")) 1593 help=_(u"delete a Pubsub hook"),
1594 )
1595 self.need_loop = True
1596
1597 def add_parser_options(self):
1598 self.parser.add_argument(
1599 "-t",
1600 "--type",
1601 default=u"",
1602 choices=("", "python", "python_file", "python_code"),
1603 help=_(u"hook type to remove, empty to remove all (default: remove all)"),
1604 )
1605 self.parser.add_argument(
1606 "-a",
1607 "--arg",
1608 dest="hook_arg",
1609 type=base.unicode_decoder,
1610 default=u"",
1611 help=_(
1612 u"argument of the hook to remove, empty to remove all (default: remove all)"
1613 ),
1614 )
1143 1615
1144 def psHookRemoveCb(self, nb_deleted): 1616 def psHookRemoveCb(self, nb_deleted):
1145 self.disp(_(u'{nb_deleted} hook(s) have been deleted').format( 1617 self.disp(
1146 nb_deleted = nb_deleted)) 1618 _(u"{nb_deleted} hook(s) have been deleted").format(nb_deleted=nb_deleted)
1619 )
1147 self.host.quit() 1620 self.host.quit()
1148 1621
1149 def start(self): 1622 def start(self):
1150 HookCreate.checkArgs(self) 1623 HookCreate.checkArgs(self)
1151 self.host.bridge.psHookRemove( 1624 self.host.bridge.psHookRemove(
1153 self.args.node, 1626 self.args.node,
1154 self.args.type, 1627 self.args.type,
1155 self.args.hook_arg, 1628 self.args.hook_arg,
1156 self.profile, 1629 self.profile,
1157 callback=self.psHookRemoveCb, 1630 callback=self.psHookRemoveCb,
1158 errback=partial(self.errback, 1631 errback=partial(
1159 msg=_(u"can't delete hook: {}"), 1632 self.errback,
1160 exit_code=C.EXIT_BRIDGE_ERRBACK)) 1633 msg=_(u"can't delete hook: {}"),
1634 exit_code=C.EXIT_BRIDGE_ERRBACK,
1635 ),
1636 )
1161 1637
1162 1638
1163 class HookList(base.CommandBase): 1639 class HookList(base.CommandBase):
1164 1640 def __init__(self, host):
1165 def __init__(self, host): 1641 base.CommandBase.__init__(
1166 base.CommandBase.__init__(self, host, 'list', use_output=C.OUTPUT_LIST_DICT, help=_(u'list hooks of a profile')) 1642 self,
1643 host,
1644 "list",
1645 use_output=C.OUTPUT_LIST_DICT,
1646 help=_(u"list hooks of a profile"),
1647 )
1167 self.need_loop = True 1648 self.need_loop = True
1168 1649
1169 def add_parser_options(self): 1650 def add_parser_options(self):
1170 pass 1651 pass
1171 1652
1172 def psHookListCb(self, data): 1653 def psHookListCb(self, data):
1173 if not data: 1654 if not data:
1174 self.disp(_(u'No hook found.')) 1655 self.disp(_(u"No hook found."))
1175 self.output(data) 1656 self.output(data)
1176 self.host.quit() 1657 self.host.quit()
1177 1658
1178 def start(self): 1659 def start(self):
1179 self.host.bridge.psHookList( 1660 self.host.bridge.psHookList(
1180 self.profile, 1661 self.profile,
1181 callback=self.psHookListCb, 1662 callback=self.psHookListCb,
1182 errback=partial(self.errback, 1663 errback=partial(
1183 msg=_(u"can't list hooks: {}"), 1664 self.errback,
1184 exit_code=C.EXIT_BRIDGE_ERRBACK)) 1665 msg=_(u"can't list hooks: {}"),
1666 exit_code=C.EXIT_BRIDGE_ERRBACK,
1667 ),
1668 )
1185 1669
1186 1670
1187 class Hook(base.CommandBase): 1671 class Hook(base.CommandBase):
1188 subcommands = (HookCreate, HookDelete, HookList) 1672 subcommands = (HookCreate, HookDelete, HookList)
1189 1673
1190 def __init__(self, host): 1674 def __init__(self, host):
1191 super(Hook, self).__init__(host, 'hook', use_profile=False, use_verbose=True, help=_('trigger action on Pubsub notifications')) 1675 super(Hook, self).__init__(
1676 host,
1677 "hook",
1678 use_profile=False,
1679 use_verbose=True,
1680 help=_("trigger action on Pubsub notifications"),
1681 )
1192 1682
1193 1683
1194 class Pubsub(base.CommandBase): 1684 class Pubsub(base.CommandBase):
1195 subcommands = (Set, Get, Delete, Edit, Subscribe, Unsubscribe, Subscriptions, Node, Affiliations, Search, Hook, Uri) 1685 subcommands = (
1196 1686 Set,
1197 def __init__(self, host): 1687 Get,
1198 super(Pubsub, self).__init__(host, 'pubsub', use_profile=False, help=_('PubSub nodes/items management')) 1688 Delete,
1689 Edit,
1690 Subscribe,
1691 Unsubscribe,
1692 Subscriptions,
1693 Node,
1694 Affiliations,
1695 Search,
1696 Hook,
1697 Uri,
1698 )
1699
1700 def __init__(self, host):
1701 super(Pubsub, self).__init__(
1702 host, "pubsub", use_profile=False, help=_("PubSub nodes/items management")
1703 )