Merge pull request #43 from tripzero/master
[profile/ivi/automotive-message-broker.git] / tools / ambctl.py
1 #!/usr/bin/python
2
3 import argparse
4 import dbus
5 import sys
6 import json
7 import gobject
8 import fileinput
9 import termios, fcntl, os
10 import glib
11 import curses.ascii
12 import traceback
13
14 from dbus.mainloop.glib import DBusGMainLoop
15
16 class bcolors:
17                 HEADER = '\x1b[95m'
18                 OKBLUE = '\x1b[94m'
19                 OKGREEN = '\x1b[92m'
20                 WARNING = '\x1b[93m'
21                 FAIL = '\x1b[91m'
22                 ENDC = '\x1b[0m'
23                 GREEN = '\x1b[32m'
24                 WHITE = '\x1b[37m'
25                 BLUE = '\x1b[34m'
26
27 class Autocomplete:
28         class Cmd:
29                 name = ""
30                 description = ""
31                 def __init__(self, n, d):
32                         self.name = n
33                         self.description = d
34
35         commands = []
36         properties = []
37
38         def __init__(self):
39                 self.commands = []
40                 self.commands.append(Autocomplete.Cmd('help', 'Prints help data (also see COMMAND help)'))
41                 self.commands.append(Autocomplete.Cmd('list', 'List supported ObjectNames'))
42                 self.commands.append(Autocomplete.Cmd('get', 'Get properties from an ObjectName'))
43                 self.commands.append(Autocomplete.Cmd('listen', 'Listen for changes on an ObjectName'))
44                 self.commands.append(Autocomplete.Cmd('set', 'Set a property for an ObjectName'))
45                 self.commands.append(Autocomplete.Cmd('getHistory', 'Get logged data within a time range'))
46                 self.commands.append(Autocomplete.Cmd('plugin', 'enable, disable and get info on a plugin'))
47                 self.commands.append(Autocomplete.Cmd('quit', 'Exit ambctl'))
48
49                 bus = dbus.SystemBus()
50                 try:
51                         managerObject = bus.get_object("org.automotive.message.broker", "/");
52                         managerInterface = dbus.Interface(managerObject, "org.automotive.Manager")
53                         self.properties = managerInterface.List()
54                 except dbus.exceptions.DBusException, error:
55                         print error
56
57         def complete(self, partialString, commandsOnly = False):
58                 results = []
59
60                 sameString = ""
61
62                 for cmd in self.commands:
63                         if not (len(partialString)) or cmd.name.startswith(partialString):
64                                 results.append(cmd.name)
65
66                 if not commandsOnly:
67                         for property in self.properties:
68                                 if not(len(partialString)) or property.startswith(partialString):
69                                         results.append(str(property))
70
71                 if len(results) > 1 and len(results[0]) > 0:
72                         for i in range(len(results[0])):
73                                 for j in range(len(results[0])-i+1):
74                                         if j > len(sameString) and all(results[0][i:i+j] in x for x in results):
75                                                 sameString = results[0][i:i+j]
76                 elif len(results) == 1:
77                         sameString = results[0]
78
79                 return results, sameString
80
81
82 def help():
83                 help = ("Available commands:\n")
84                 autocomplete = Autocomplete()
85                 for cmd in autocomplete.commands:
86                         help += bcolors.HEADER + cmd.name + bcolors.WHITE
87                         for i in range(1, 15 - len(cmd.name)):
88                                 help += " "
89                         help += cmd.description + "\n"
90
91                 return help
92
93 def changed(interface, properties, invalidated):
94         print json.dumps(properties, indent=2)
95
96 def listPlugins():
97         list = []
98         for root, dirs, files in os.walk('@PLUGIN_SEGMENT_INSTALL_PATH@'):
99                 for file in files:
100                         fullpath = root + "/" + file;
101                         pluginFile = open(fullpath)
102                         data = json.load(pluginFile)
103                         data['segmentPath'] = fullpath
104                         pluginFile.close()
105                         list.append(data)
106         return list
107
108 def enablePlugin(pluginName, enabled):
109         list = listPlugins()
110
111         for plugin in list:
112                 if plugin["name"] == pluginName:
113                         try :
114                                 plugin["enabled"] = enabled
115                                 file = open(plugin["segmentPath"], 'rw+')
116                                 plugin.pop('segmentPath', None)
117                                 fixedData = json.dumps(plugin, separators=(', ', ' : '), indent=4)
118                                 fixedData = fixedData.replace('    ','\t');
119                                 file.truncate()
120                                 file.write(fixedData)
121                                 file.close()
122                                 return True
123                         except IOError, error:
124                                 print error
125                                 return False
126         return False
127 class Subscribe:
128         subscriptions = {}
129 def processCommand(command, commandArgs, noMain=True):
130
131         if command == 'help':
132                 print help()
133                 return 1
134
135         bus = dbus.SystemBus()
136
137         def getManager(bus):
138                 try:
139                         managerObject = bus.get_object("org.automotive.message.broker", "/");
140                         managerInterface = dbus.Interface(managerObject, "org.automotive.Manager")
141                         return managerInterface
142                 except:
143                         print "Error connecting to AMB.  is AMB running?"
144                         return None
145
146         if command == "list" :
147                 managerInterface = getManager(bus)
148                 supportedList = managerInterface.List()
149                 for objectName in supportedList:
150                         print objectName
151                 return 1
152         elif command == "get":
153                 if len(commandArgs) == 0:
154                         commandArgs = ['help']
155                 if commandArgs[0] == "help":
156                         print "ObjectName [ObjectName...]"
157                         return 1
158                 managerInterface = getManager(bus)
159                 for objectName in commandArgs:
160                         objects = managerInterface.FindObject(objectName)
161                         print objectName
162                         for o in objects:
163                                 propertiesInterface = dbus.Interface(bus.get_object("org.automotive.message.broker", o),"org.freedesktop.DBus.Properties")
164                                 print json.dumps(propertiesInterface.GetAll("org.automotive."+objectName), indent=2)
165                 return 1
166         elif command == "listen":
167                 off = False
168                 if len(commandArgs) == 0:
169                         commandArgs = ['help']
170                 if commandArgs[0] == "help":
171                         print "[help] [off] ObjectName [ObjectName...]"
172                         return 1
173                 elif commandArgs[0] == "off":
174                         off=True
175                         commandArgs=commandArgs[1:]
176                 managerInterface = getManager(bus)
177                 for objectName in commandArgs:
178                         objects = managerInterface.FindObject(objectName)
179                         for o in objects:
180                                 if off == False:
181                                         signalMatch = bus.add_signal_receiver(changed, dbus_interface="org.freedesktop.DBus.Properties", signal_name="PropertiesChanged", path=o)
182                                         Subscribe.subscriptions[o] = signalMatch
183                                 else:
184                                         try:
185                                                 signalMatch = Subscribe.subscriptions.get(o)
186                                                 signalMatch.remove()
187                                                 del Subscribe.subscriptions[o]
188                                         except KeyError:
189                                                 print "not lisenting to object at: ", o
190                                                 pass
191                 if not noMain == True:
192                         try:
193                                 main_loop = gobject.MainLoop(None, False)
194                                 main_loop.run()
195                         except KeyboardInterrupt:
196                                 return 1
197                         except:
198                                 traceback.print_stack()
199         elif command == "set":
200                 if len(commandArgs) == 0:
201                         commandArgs = ['help']
202                 if len(commandArgs) and commandArgs[0] == "help":
203                         print "ObjectName PropertyName VALUE [ZONE]"
204                         return 1
205                 if len(commandArgs) < 3:
206                         print "set requires more arguments (see set help)"
207                         return 1
208                 objectName = commandArgs[0]
209                 propertyName = commandArgs[1]
210                 value = commandArgs[2]
211                 zone = 0
212                 if len(commandArgs) == 4:
213                         zone = int(commandArgs[3])
214                 managerInterface = getManager(bus)
215                 object = managerInterface.FindObjectForZone(objectName, zone)
216                 propertiesInterface = dbus.Interface(bus.get_object("org.automotive.message.broker", object),"org.freedesktop.DBus.Properties")
217                 property = propertiesInterface.Get("org.automotive."+objectName, propertyName)
218                 if property.__class__ == dbus.Boolean:
219                         value = value.lower() == "true"
220                 realValue = property.__class__(value)
221                 propertiesInterface.Set("org.automotive."+objectName, propertyName, realValue)
222                 property = propertiesInterface.Get("org.automotive."+objectName, propertyName)
223                 if property == realValue:
224                         print propertyName + " = ", property
225                 else:
226                         print "Error setting property.  Expected value: ", realValue, " Received: ", property
227                 return 1
228         elif command == "getHistory":
229                 if len(commandArgs) == 0:
230                         commandArgs = ['help']
231                 if commandArgs[0] == "help":
232                         print "ObjectName [ZONE] [STARTTIME] [ENDTIME] "
233                         return 1
234                 if len(commandArgs) < 1:
235                         print "getHistory requires more arguments (see getHistory help)"
236                         return 1
237                 objectName = commandArgs[0]
238                 start = 1
239                 if len(commandArgs) >= 3:
240                         start = float(commandArgs[2])
241                 end = 9999999999
242                 if len(commandArgs) >= 4:
243                         end = float(commandArgs[3])
244                 zone = 0
245                 if len(commandArgs) >= 2:
246                         zone = int(commandArgs[1])
247                 managerInterface = getManager(bus)
248                 object = managerInterface.FindObjectForZone(objectName, zone);
249                 propertiesInterface = dbus.Interface(bus.get_object("org.automotive.message.broker", object),"org.automotive."+objectName)
250                 print json.dumps(propertiesInterface.GetHistory(start, end), indent=2)
251         elif command == "plugin":
252                 if len(commandArgs) == 0:
253                         commandArgs = ['help']
254                 if commandArgs[0] == 'help':
255                         print "[list] [pluginName] [on/off]"
256                         return 1
257                 elif commandArgs[0] == 'list':
258                         for plugin in listPlugins():
259                                 print plugin['name']
260                         return 1
261                 elif len(commandArgs) == 1:
262                         for plugin in listPlugins():
263                                 if plugin['name'] == commandArgs[0]:
264                                         print json.dumps(plugin, indent=4)
265                                         return 1
266                                 else:
267                                         print "name: " + plugin['name'] + "==?" + commandArgs[0]
268                         print "plugin not found: ", commandArgs[0]
269                         return 0
270                 else:
271                         if len(commandArgs) < 2:
272                                 return 1
273                         enArg = commandArgs[1]
274                         if not enArg == "on" and not enArg == "off":
275                                 print "please use 'on' or 'off' to enable/disable the plugin"
276                                 return 1
277                         plugin = commandArgs[0]
278                         enabled = enArg == "on"
279                         enStr = "disabled"
280                         if enablePlugin(plugin, enabled):
281                                 if enabled:
282                                         enStr = "enabled"
283                         else:
284                                 print "Error could not enable", plugin
285
286                         print plugin, enStr
287
288                         return 1
289
290         else:
291                 print "Invalid command"
292         return 1
293
294
295
296 parser = argparse.ArgumentParser(prog="ambctl", description='Automotive Message Broker DBus client tool', add_help=False)
297 parser.add_argument('command', metavar='COMMAND [help]', nargs='?', default='stdin', help='amb dbus command')
298 parser.add_argument('commandArgs', metavar='ARG', nargs='*',
299                         help='amb dbus command arguments')
300 parser.add_argument('-h', '--help', help='print help', action='store_true')
301
302 args = parser.parse_args()
303
304 if args.help:
305                 parser.print_help()
306                 print
307                 print help()
308                 sys.exit()
309
310 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
311
312 if args.command == "stdin":
313                 class Data:
314                                 history = []
315                                 line = ""
316                                 templine = ""
317                                 promptAmbctl = "[ambctl]"
318                                 promptEnd = "# "
319                                 fullprompt = promptAmbctl + promptEnd
320                                 curpos = 0
321                                 historypos = -1
322                                 autocomplete = Autocomplete()
323                                 def full_line_len(self):
324                                                 return len(self.fullprompt) + len(self.line)
325                                 def insert(self, str):
326                                                 if self.curpos == len(self.line):
327                                                                 self.line+=str
328                                                                 self.curpos = len(self.line)
329                                                 else:
330                                                                 self.line = self.line[:self.curpos] + str + self.line[self.curpos:]
331                                                                 self.curpos+=1
332                                 def arrow_back(self):
333                                                 if self.curpos > 0:
334                                                                 self.curpos-=1
335                                                                 return True
336                                                 return False
337
338                                 def arrow_forward(self):
339                                                 if self.curpos < len(self.line):
340                                                                 self.curpos+=1
341                                                                 return True
342                                                 return False
343
344                                 def back_space(self):
345                                                 if self.curpos > 0:
346                                                                 self.curpos-=1
347                                                                 self.line = self.line[:self.curpos] + self.line[self.curpos+1:]
348                                                                 return True
349                                                 return False
350                                 def delete(self):
351                                                 if self.curpos < len(self.line):
352                                                                 self.line = self.line[:self.curpos] + self.line[self.curpos+2:]
353                                                                 return True
354                                                 return False
355
356                                 def save_temp(self):
357                                                 if len(self.history)-1 == 0 or len(self.history)-1 != self.historypos:
358                                                                 return
359                                                 self.templine = self.line
360
361                                 def push(self):
362                                                 self.history.append(self.line)
363                                                 self.historypos = len(self.history)-1
364                                                 self.clear()
365
366                                 def set(self, str):
367                                                 self.line = str
368                                                 self.curpos = len(self.line)
369
370                                 def history_up(self):
371                                                 if self.historypos >= 0:
372                                                                 self.line = self.history[self.historypos]
373                                                                 if self.historypos != 0:
374                                                                                 self.historypos-=1
375                                                                 return True
376                                                 return False
377
378                                 def history_down(self):
379                                                 if self.historypos >= 0 and self.historypos < len(self.history)-1:
380                                                                 self.historypos+=1
381                                                                 self.line = self.history[self.historypos]
382
383                                                 else:
384                                                                 self.historypos = len(self.history)-1
385                                                                 self.set(self.templine)
386
387                                                 return True
388
389                                 def clear(self):
390                                                 self.set("")
391                                                 templist = ""
392
393                 def erase_line():
394                                 sys.stdout.write('\x1b[2K\x1b[80D')
395
396                 def cursor_left():
397                                 sys.stdout.write('\x1b[1D')
398
399                 def cursor_right():
400                                 sys.stdout.write('\x1b[1C')
401
402                 def display_prompt():
403                                 sys.stdout.write(bcolors.OKBLUE+Data.promptAmbctl+bcolors.WHITE+Data.promptEnd);
404
405                 def redraw(data):
406                                 erase_line()
407                                 display_prompt()
408                                 sys.stdout.write(data.line)
409                                 cursorpos = len(data.line) - data.curpos
410                                 for x in xrange(cursorpos):
411                                                 cursor_left()
412                                 sys.stdout.flush()
413
414                 def handle_keyboard(source, cond, data):
415                                                 str = source.read()
416                                                 #print "char: ", ord(str)
417
418                                                 if len(str) > 1:
419                                                         if ord(str[0]) == 27 and ord(str[1]) == 91 and ord(str[2]) == 68:
420                                                                 #left arrow
421                                                                 if data.arrow_back():
422                                                                         cursor_left()
423                                                                         sys.stdout.flush()
424                                                         elif ord(str[0]) == 27 and ord(str[1]) == 91 and ord(str[2]) == 67:
425                                                                 #right arrow
426                                                                 if data.arrow_forward():
427                                                                         cursor_right()
428                                                                         sys.stdout.flush()
429                                                         elif ord(str[0]) == 27 and ord(str[1]) == 91 and ord(str[2]) == 70:
430                                                                 #end
431                                                                 while data.arrow_forward():
432                                                                         cursor_right()
433                                                                 sys.stdout.flush()
434                                                         elif ord(str[0]) == 27 and ord(str[1]) == 91 and ord(str[2]) == 72: #home
435                                                                 while data.arrow_back():
436                                                                         cursor_left()
437                                                                 sys.stdout.flush()
438                                                         elif len(str) == 4 and ord(str[0]) == 27 and ord(str[1]) == 91 and ord(str[2]) == 51 and ord(str[3]) == 126:
439                                                                 #del
440                                                                 data.delete()
441                                                                 redraw(data)
442                                                         elif ord(str[0]) == 27 and ord(str[1]) == 91 and ord(str[2]) == 65:
443                                                                 #up arrow
444                                                                 data.save_temp()
445                                                                 data.history_up()
446                                                                 while data.arrow_forward():
447                                                                         cursor_right()
448                                                                 redraw(data)
449                                                         elif ord(str[0]) == 27 and ord(str[1]) == 91 and ord(str[2]) == 66:
450                                                                 #down arrow
451                                                                 data.history_down()
452                                                                 while data.arrow_forward():
453                                                                         cursor_right()
454                                                                 redraw(data)
455                                                 elif ord(str) == 10:
456                                                         #enter
457                                                         if data.line == "":
458                                                                 return True
459                                                         print ""
460                                                         words = data.line.split(' ')
461                                                         if words[0] == "quit":
462                                                                 termios.tcsetattr(fd, termios.TCSAFLUSH, old)
463                                                                 fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
464                                                                 sys.exit()
465                                                         try:
466                                                                 if len(words) > 1:
467                                                                         processCommand(words[0], words[1:])
468                                                                 else:
469                                                                         processCommand(words[0], [])
470                                                         except dbus.exceptions.DBusException, error:
471                                                                 print error
472                                                         except:
473                                                                 print "Error running command ", sys.exc_info()[0]
474                                                                 traceback.print_stack()
475                                                         data.push();
476                                                         data.clear()
477                                                         redraw(data)
478                                                 elif ord(str) == 127: #backspace
479                                                         data.back_space()
480                                                         redraw(data)
481                                                 elif ord(str) == 9:
482                                                         #tab
483                                                         #get last string:
484                                                         wordsList = data.line.split(' ')
485                                                         toComplete = wordsList[-1]
486                                                         results, samestring = data.autocomplete.complete(toComplete)
487                                                         if len(samestring) and len(samestring) > len(toComplete) and not (samestring == toComplete):
488                                                                 if len(wordsList) > 1:
489                                                                         data.line = ' '.join(wordsList[0:-1]) + ' ' + samestring
490                                                                 else:
491                                                                         data.line = samestring
492                                                                 while data.arrow_forward():
493                                                                         cursor_right()
494
495                                                         elif len(results) and not results[0] == toComplete:
496                                                                 print ''
497                                                                 print len(results), "results:"
498                                                                 if len(results) <= 3:
499                                                                         print ' '.join(results)
500                                                                 else:
501                                                                         longestLen = 0
502                                                                         for r in results:
503                                                                                 if len(r) > longestLen:
504                                                                                         longestLen = len(r)
505                                                                         i=0
506                                                                         while i < len(results) / 3:
507                                                                                 row = ""
508                                                                                 numCols = 3
509                                                                                 if len(results) < i+3:
510                                                                                         numCols = len(results) - i
511                                                                                 for n in xrange(numCols):
512                                                                                         row += results[i]
513                                                                                         for n in xrange((longestLen + 5) - len(results[i])):
514                                                                                                 row += ' '
515                                                                                         i += 1
516
517                                                                                 print row
518
519                                                         redraw(data)
520                                                 elif curses.ascii.isprint(ord(str)) or ord(str) == curses.ascii.SP: #regular text
521                                                         data.insert(str)
522                                                         redraw(data)
523
524                                                 return True
525                 print "@PROJECT_PRETTY_NAME@ @PROJECT_VERSION@"
526
527                 data = Data()
528                 fd = sys.stdin.fileno()
529                 old = termios.tcgetattr(fd)
530                 new = termios.tcgetattr(fd)
531                 new[3] = new[3] & ~termios.ICANON & ~termios.ECHO
532                 termios.tcsetattr(fd, termios.TCSANOW, new)
533
534                 oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
535                 fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
536
537                 io_stdin = glib.IOChannel(fd)
538                 io_stdin.add_watch(glib.IO_IN, handle_keyboard, data)
539
540                 try:
541                         erase_line()
542                         display_prompt()
543                         sys.stdout.flush()
544                         main_loop = gobject.MainLoop(None, False)
545                         main_loop.run()
546                 except KeyboardInterrupt:
547                         sys.exit()
548                 except:
549                         traceback.print_stack()
550                 finally:
551                         termios.tcsetattr(fd, termios.TCSAFLUSH, old)
552                         fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
553                         print ""
554                         sys.exit()
555
556 else:
557         try:
558                 processCommand(args.command, args.commandArgs, False)
559         except dbus.exceptions.DBusException, error:
560                 print error