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