#!/usr/bin/python # create new project by cocos-console # compile, deploy project and run # perpose: for autotest cocos2d-console command. # now support: mac- mac/ios/android # will add: window-android,linux-android import os import subprocess import sys import json import time import socket import smtplib from email.mime.text import MIMEText from os.path import join, getsize # default console_param. console_param = '[console run]' # get param from commit. if os.environ.has_key('payload'): payload_str = os.environ['payload'] payload = json.loads(payload_str) if payload.has_key('console'): console_param = payload['console'] console_param = console_param[1:len(console_param)-1] print 'console_param:',console_param console_param_arr = console_param.split(' ') # enum command type class ENUM_PARAM: new = 0 compile = 1 deploy = 2 run = 3 # partition different level LEVEL_COCOS = { ENUM_PARAM.new : 1, ENUM_PARAM.compile : 2, ENUM_PARAM.deploy : 4, ENUM_PARAM.run : 8 } # level's cocos command COCOS_CMD = { ENUM_PARAM.new:'new', ENUM_PARAM.compile:'compile', ENUM_PARAM.deploy:'deploy', ENUM_PARAM.run:'run' } # set cocos_param for run different command cocos_param = 0 for level in LEVEL_COCOS: if console_param_arr.count(COCOS_CMD[level]): cocos_param = cocos_param + LEVEL_COCOS[level] if cocos_param < LEVEL_COCOS[ENUM_PARAM.new]: cocos_param = LEVEL_COCOS[ENUM_PARAM.new] print 'cocos_param:', cocos_param # project types project_types = ['cpp', 'lua'] # project suffix PROJ_SUFFIX = 'Proj' # different phone platform phonePlats = ['mac','ios','android'] # need use console's position, perhaps should be set an env-param cocos_console_dir = 'tools/cocos2d-console/bin/' # now cocos2d-console suport different run on Platforms, e.g: only run android on win runSupport = { 'darwin' : {'mac':1,'ios':1,'android':1}, 'win' : {'mac':0,'ios':0,'android':1}, 'linux' : {'mac':0,'ios':0,'android':1} } # get current running system curPlat = sys.platform if curPlat.find('linux') >= 0: curPlat = 'linux' elif curPlat.find('darwin') >= 0: curPlat = 'darwin' else: curPlat = 'win' print 'current platform is:', curPlat # delete project.(will use different system command to delete.just mac now.) def clean_project(): print 'delete older project.' for proj in project_types: cmd = 'rm -rf '+proj+PROJ_SUFFIX os.system(cmd) # file path.(for add console listen command.) FILE_PATH = '/Classes/AppDelegate.cpp' FILE_DIR = { 'cpp':'', 'lua':'/frameworks/runtime-src' } PARSE_WORD = 'director->setDisplayStats(true);' CONSOLE_COMMAND = 'director->getConsole()->listenOnTCP(5678);' # add console listenOnTCP to AppDelegate.cpp. def addConsoleListenOnTCP(name): filePath = name+PROJ_SUFFIX+FILE_DIR[name]+FILE_PATH print 'filePath:',filePath strCont = '' if os.path.isfile(filePath): file_object = open(filePath, 'r') strLine = file_object.readline() while strLine: strCont = strCont + strLine if strLine.find(PARSE_WORD) > -1: print 'add console listenOnTCP command.' strCont = strCont+'\n\t' + CONSOLE_COMMAND + '\n' strLine = file_object.readline() file_object.close() file_object = open(filePath, 'w') file_object.write(strCont) file_object.close() time.sleep(2) else: print 'file is not exist.' # console result, for record result console_result = 'the result of cocos-console-test is:\n\r' # get current android devices count. def getAndroidDevices(): cmd = 'adb devices' info_devices = os.popen(cmd).read() arrDevices = info_devices.split('\n') del arrDevices[0] count = 0 for device in arrDevices: # e.g: emulator-5554 device, contains 'device', so, min length is len('device') if len(device) > len('device') and (device.find('device') >= 0): count += 1 return count # close running app or exe by using console command. IP_PHONE = { 'mac':'localhost', 'ios':'localhost' } PORT = 5678 def close_proj(proj, phone): print 'close running project' # connect socket strClose = 'close ' + proj + ' on ' + phone if IP_PHONE.has_key(phone): soc = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) print proj, phone, IP_PHONE[phone] try: soc.connect((IP_PHONE[phone], PORT)) cmd = 'director end\r\n' print 'cmd close:', cmd soc.send(cmd) time.sleep(2) strClose = strClose + ' success.' except Exception, e: print 'socket is not connect.' strClose = strClose + ' failed.' + ' socket is not connect.' else: strClose = strClose + ' failed.' + ' no ' +phone+ ' type.' time.sleep(2) return strClose # appendToResult def appendToResult(content): global console_result console_result = console_result + content # if any error ANY_ERROR_IN_RUN = 0 # excute cocos command def cocos_project(level): global ANY_ERROR_IN_RUN print 'will excute cocos_command: ', COCOS_CMD[level], level appendToResult('will excute ' + COCOS_CMD[level] + ' command:'+"\n\r\t") for proj in project_types: print 'proj: ', proj if level == ENUM_PARAM.new: cmd = './'+cocos_console_dir+'cocos new -l '+proj+' '+proj+PROJ_SUFFIX print proj,'cmd:',cmd info_create = os.system(cmd) #call cmd on win is diff if info_create == 0: time.sleep(12) addConsoleListenOnTCP(proj) print 'create project',proj,' is:', not info_create ANY_ERROR_IN_RUN = ANY_ERROR_IN_RUN + info_create appendToResult(' '+cmd +': ' + str(not info_create) + ".\n\r\t") else: for phone in phonePlats: print 'platform is: ', phone cmd = './'+cocos_console_dir+'cocos '+COCOS_CMD[level]+' -s '+proj+PROJ_SUFFIX+' -p '+phone print 'cmd:',cmd info_cmd = '' if level == ENUM_PARAM.compile: if runSupport[curPlat][phone]: info_cmd = os.system(cmd) print 'info '+COCOS_CMD[level]+':', not info_cmd appendToResult(' '+cmd +': ' + str(not info_cmd) + ".\n\r\t") else: if runSupport[curPlat][phone]: print 'in desploy or run:', phone, getAndroidDevices() if phone == 'android' and getAndroidDevices() == 0: strInfo = 'no android device, please checkout the device is running ok.' print strInfo # appendToResult(' '+strInfo+"\n\r\t") else: info_cmd = os.system(cmd) print 'info '+COCOS_CMD[level]+':', not info_cmd if level == ENUM_PARAM.run: time.sleep(20) strClose = close_proj(proj, phone) appendToResult(' '+strClose+"\n\r\t") appendToResult(' '+cmd +': ' + str(not info_cmd) + ".\n\r\t") # build and run according to params of provided.(lv_ignore: e.g:ignore new) def build_run(lv_ignore): print 'will build and run, in function build_run' for level in LEVEL_COCOS: print 'level:', level, cocos_param, LEVEL_COCOS[level] if cocos_param >= LEVEL_COCOS[level] and level > lv_ignore: if level == ENUM_PARAM.new: clean_project() cocos_project(level) # android simulator name. ANDROID_SIMULATOR_NAME = 'console-test' # start android simulator if no android devices connected. def start_android_simulator(): print 'in function start_android_simulator.' if getAndroidDevices() > 0: print 'already connected android device.' return if cocos_param >= LEVEL_COCOS[ENUM_PARAM.deploy]: cmd_start = [ 'emulator -avd '+ANDROID_SIMULATOR_NAME ] # print 'cmd_start:', cmd_start # info_start = subprocess.Popen(cmd_start, stdin=subprocess.PIPE, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # print 'start an android simulator:', not info_start # send email EMAIL_KEYS={ 0:'EMAIL_HOST', 1:'EMAIL_USER', 2:'EMAIL_PWD', 3:'EMAIL_POSTFIX', 4:'EMAIL_LIST', 5:'NEED_SEND_EMAIL' } OBJ_EMAIL_INFO = {} print 'will get env info.' for key in EMAIL_KEYS: if os.environ.has_key(EMAIL_KEYS[key]): OBJ_EMAIL_INFO[EMAIL_KEYS[key]] = os.environ[EMAIL_KEYS[key]] if key == 4: # string to list by ' ', for separate users. OBJ_EMAIL_INFO[EMAIL_KEYS[4]] = OBJ_EMAIL_INFO[EMAIL_KEYS[4]].split(' ') print 'will send email.', OBJ_EMAIL_INFO def send_mail(to_list,sub,title,content): mail_user = OBJ_EMAIL_INFO[ EMAIL_KEYS[1] ] mail_postfix = OBJ_EMAIL_INFO[ EMAIL_KEYS[3] ] mail_host = OBJ_EMAIL_INFO[ EMAIL_KEYS[0] ] mail_pass = OBJ_EMAIL_INFO[ EMAIL_KEYS[2] ] me = mail_user+"<"+mail_user+"@"+mail_postfix+">" msg = MIMEText(content,_subtype='plain',_charset='gb2312') msg['Subject'] = sub msg['From'] = me msg['To'] = " ".join(to_list) print 'to users:', msg['To'] msg['Content'] = 'test' try: s = smtplib.SMTP() s.connect(mail_host) s.login(mail_user,mail_pass) s.sendmail(me, to_list, str(msg)) print 'info:', me, to_list, str(msg) s.close() appendToResult( 'send email true:' + str(msg) ) return True except Exception, e: appendToResult( 'send email false:' + str(e) ) print str(e) return False def sendEmail(msg): send_mail(OBJ_EMAIL_INFO[EMAIL_KEYS[4]], "cocos-console-test result", 'for error.', msg) # get package size def getdirsize(dir): size = 0L for root, dirs, files in os.walk(dir): size += sum([getsize(join(root, name)) for name in files]) return size APP_FILE_DIR = { 'cpp':'bin/debug/', 'lua':'runtime/' } APP_FILE_SUFFIX = { 'mac':'.app', 'ios':'.app', 'android':'-debug-unaligned.apk' } def getPackageSize(): for proj in project_types: for phone in phonePlats: # if runSupport[curPlat][phone]: package_path = './'+proj+PROJ_SUFFIX+'/'+APP_FILE_DIR[proj]+phone+'/'+proj+PROJ_SUFFIX+APP_FILE_SUFFIX[phone] print 'package_path', package_path package_size = 0 if os.path.isfile(package_path): package_size = os.path.getsize(package_path); else: package_size = getdirsize(package_path); strSize = 'size of '+proj+PROJ_SUFFIX+' '+phone+' is:'+str(package_size/(1024))+'KB'+'\n\t' print 'strSize:', strSize appendToResult(strSize) def main(): print 'in main:' # start_android_simulator() print 'will build_run:' build_run(-1) print 'ANY_ERROR_IN_RUN:', ANY_ERROR_IN_RUN print 'end build run. and get package size.' getPackageSize() print 'will send email:' print 'console_result:', console_result if OBJ_EMAIL_INFO[ EMAIL_KEYS[5] ] or ANY_ERROR_IN_RUN: sendEmail(console_result) # -------------- main -------------- if __name__ == '__main__': sys_ret = 0 try: sys_ret = main() except: traceback.print_exc() sys_ret = 1 finally: sys.exit(sys_ret)