#!/bin/env python import pycurl, StringIO, urllib import json, hashlib, types import os,sys, datetime BASE = "http://ide.srobo.org/fw" fdev = os.path.expanduser ("~/.sr/fwman-dev" ) if os.path.exists( fdev ): f = open(fdev, "r") BASE = f.read().strip() f.close() # Display this warning to try and reduce fail sys.stderr.write("*" * 40 + "\n") sys.stderr.write(" WARNING: fwman running in debug mode.\n") sys.stderr.write(" WARNING: fwman is using %s as base URL.\n" % BASE) sys.stderr.write("*" * 40 + "\n") class FwHandler: def __getattr__(self,name): def fn(**args): c = pycurl.Curl() c.setopt( pycurl.URL, "%s/%s" % (BASE, name) ) # POST data data = [] for varname, val in args.iteritems(): if type(val) == types.TupleType and val[0] == "file": """It's a filename, so tell pycurl""" f = [pycurl.FORM_FILE, val[1]] data.append( (varname, tuple(f) ) ) else: data.append( (varname, val) ) c.setopt( pycurl.HTTPPOST, data ) out = StringIO.StringIO() c.setopt(pycurl.WRITEFUNCTION, out.write) c.perform() c.close() r = json.read( out.getvalue() ) return r return fn class FwClient: def __init__(self): self.h = FwHandler() def get_devices(self): return self.h.devices()["devices"] def req_version(self,device, desc, revision): r = self.h.req_version( device = device, desc = desc, revision = revision ) if r.has_key( "ERROR" ): print "Failure: %s" % r["ERROR"] return False return r["version"] def upload(self,device,version,fname): r = self.h.upload( device = device, version = version, firmware = ("file", fname) ) if r.has_key( "ERROR" ): print "Failure: %s" % r["ERROR"] return False h = hashlib.sha1() f = open(fname,"r") while True: "Hash the file" d = f.read(4096) if not d: break h.update( d ) if r["sha1"] != h.hexdigest(): print "ERROR: Hashes don't match" def info(self,device,version): r = self.h.info( device = device, version = version ) if r.has_key( "ERROR" ): print "Failure: %s" % r["ERROR"] return False return r def images(self, device): r = self.h.images( device = device ) if r.has_key( "ERROR" ): print "Failure: %s" % r["ERROR"] return False return r if __name__ == "__main__": if len(sys.argv) < 2: print "fwman: The Student Robotics firmware management CLI" print "Usage: fwman COMMAND ..." print "Where COMMAND can be:" print "\treq_version DEV - Request a new version number to build with." print "\tupload DEV VERSION FILE - Upload the given " print "\tdownload DEV VERSION FILE - Download firmware image into FILE" print print "\tlog DEV VERSION - Show the log for the given firmware VERSION." print "\tlistdev - List the devices the server manages" print print "\tstate DEV [VERSION]" print "Common args:" print " - DEV: The device name." print " - VERSION: A firmware version number." print " - FILE: A file path." sys.exit(0) cmd = sys.argv[1] client = FwClient() if cmd == "listdev": for d in client.get_devices(): print d elif cmd == "req_version": if len(sys.argv) < 3: print "Usage: fwman req_version DEV" sys.exit(1) device = sys.argv[2] #TODO: launch editor v = client.req_version( device, "jamjamjam", "svn:3" ) print v elif cmd == "upload": if len(sys.argv) < 5: print "Usage: fwman upload DEV VERSION FNAME" sys.exit(1) device, version, fname = sys.argv[2:5] #TODO: Poke around in the binary for the version number client.upload( device, version, fname ) elif cmd == "state": if len(sys.argv) == 3: device = sys.argv[2] for state, images in client.images(device).iteritems(): if "tg_flash" not in state: if len(images) is not 0: print "%s: %s" % (state, ", ".join([str(x) for x in images])) elif len(sys.argv) == 4: device, version = sys.argv[2:5] print client.info( device, version )["state"] else: print "Usage: fwman state DEV [VERSION]" sys.exit(1) elif cmd == "info": if len(sys.argv) < 4: print "Usage: fwman info DEV VERSION" sys.exit(1) device, version = sys.argv[2:4] r = client.info( device, version ) print "State: %s" % r["state"] if r.has_key("size"): print "Size: %i" % r["size"] print "SHA1: %s" % r["sha1"] print print "%s" % r["desc"] elif cmd == "log": if len(sys.argv) < 4: print "Usage: fwman log DEV VERSION" sys.exit(1) device, version = sys.argv[2:4] r = client.info( device, version ) for entry in r["log"]: print "Date: %s" % datetime.datetime.fromtimestamp(entry["time"]) print "State: %s" % entry["state"] print print entry["message"] print "-" * 80 elif cmd == "download": if len(sys.argv) < 5: print "Usage: fwman download DEV VERSION FILE" sys.exit(1) device, version, file = sys.argv[2:5] args = { "device" : device, "version": version } u = urllib.urlopen( "%s/get" % BASE, data = urllib.urlencode( [(x,args[x]) for x in args.keys()] ) ) f = open( file, "w" ) while True: d = u.read(4096) if not d: break f.write(d)