def main(args): argc = len(args) if argc == 2 and (args[1]=='--help' or args[1]=='-h'): print "%s <command> <version> <project_dir> <appid> <name> [options]" % os.path.basename(args[0]) print print "available commands: " print print " install install the app to itunes for testing on iphone" print " simulator build and run on the iphone simulator" print " distribute build final distribution bundle" sys.exit(1) print "[INFO] One moment, building ..." sys.stdout.flush() start_time = time.time() iphone_version = dequote(args[2].decode("utf-8")) iphonesim = os.path.abspath(os.path.join(template_dir,'iphonesim')) command = args[1].decode("utf-8") project_dir = os.path.expanduser(dequote(args[3].decode("utf-8"))) appid = dequote(args[4].decode("utf-8")) name = dequote(args[5].decode("utf-8")) target = 'Debug' deploytype = 'development' devicefamily = None debug = False simulator = False if command == 'distribute': appuuid = dequote(args[6].decode("utf-8")) dist_name = dequote(args[7].decode("utf-8")) output_dir = os.path.expanduser(dequote(args[8].decode("utf-8"))) if argc > 9: devicefamily = dequote(args[9].decode("utf-8")) target = 'Release' deploytype = 'production' elif command == 'simulator': deploytype = 'development' debug = True simulator = True if argc > 6: devicefamily = dequote(args[6].decode("utf-8")) elif command == 'install': appuuid = dequote(args[6].decode("utf-8")) dist_name = dequote(args[7].decode("utf-8")) if argc > 8: devicefamily = dequote(args[8].decode("utf-8")) deploytype = 'test' iphone_dir = os.path.abspath(os.path.join(project_dir,'build','iphone')) project_resources = os.path.join(project_dir,'Resources') app_name = name+'.app' app_folder_name = '%s-iphoneos' % target app_dir = os.path.abspath(os.path.join(iphone_dir,'build','%s-iphonesimulator'%target,name+'.app')) app_bundle_folder = os.path.abspath(os.path.join(iphone_dir,'build',app_folder_name)) app_bundle = os.path.join(app_bundle_folder,app_name) iphone_resources_dir = os.path.join(iphone_dir,'Resources') iphone_tmp_dir = os.path.join(iphone_dir,'tmp') # TODO: review this with new module SDK # in case the developer has their own modules we can pick them up project_module_dir = os.path.join(project_dir,"modules","iphone") if not os.path.exists(iphone_dir): print "Could not find directory: %s" % iphone_dir sys.exit(1) cwd = os.getcwd() app_js = os.path.join(project_dir,'Resources','app.js') if not os.path.exists(app_js): print "[ERROR] This project looks to not be ported to 0.9+." print "[ERROR] Your project is missing app.js. Please make sure to port your application to 0.9+ API" print "[ERROR] before continuing or choose a previous version of the SDK." sys.exit(1) tiapp_xml = os.path.join(project_dir,'tiapp.xml') if not os.path.exists(tiapp_xml): print "Missing tiapp.xml at %s" % tiapp_xml sys.exit(3) ti = TiAppXML(tiapp_xml) encrypt = False if ti.properties.has_key('encrypt'): encrypt = (ti.properties['encrypt']=='true') force_rebuild = True force_compile = False version_file = None log_id = None source_lib=os.path.join(template_dir,'libTiCore.a') target_lib=os.path.join(iphone_resources_dir,'libTiCore.a') lib_hash = None # for simulator, we only need to compile once so we check to # see if we've already compiled for the simulator for the # same version of titanium and if so, we don't need to rebuild if simulator: version_file = os.path.join(iphone_resources_dir,'.simulator') if os.path.exists(app_dir): if os.path.exists(version_file): line = open(version_file).read().strip() lines = line.split(",") v = lines[0] log_id = lines[1] if len(lines) > 2: lib_hash = lines[2] if iphone_version!=lines[3]: force_rebuild=True if lib_hash==None: force_rebuild = True else: if template_dir==v and force_rebuild==False: force_rebuild = False else: log_id = None if force_rebuild==False: if not os.path.exists(os.path.join(iphone_dir,'Classes','ApplicationRouting.h')): force_rebuild = True force_compile = True if force_rebuild==False and not os.path.exists(os.path.join(iphone_dir,'Classes','ApplicationRouting.m')): force_rebuild = True force_compile = True # if using custom modules, we have to force rebuild each time for now if force_rebuild==False and ti.properties.has_key('modules') and len(ti.properties['modules']) > 0: force_rebuild = True fd = open(source_lib,'rb') m = hashlib.md5() m.update(fd.read(1024)) # just read 1K, it's binary new_lib_hash = m.hexdigest() fd.close() if new_lib_hash!=lib_hash: force_rebuild=True lib_hash=new_lib_hash # only do this stuff when we're in a force rebuild which is either # non-simulator build or when we're simulator and it's the first time # or different version of titanium # if force_rebuild: print "[INFO] Performing full rebuild. This will take a little bit. Hold tight..." if os.path.exists(app_dir): shutil.rmtree(app_dir) # compile resources only if non-simulator (for speedups) compiler = Compiler(appid,project_dir,encrypt,debug) compiler.compile() # find the module directory relative to the root of the SDK tp_module_dir = os.path.abspath(os.path.join(template_dir,'..','..','..','..','modules','iphone')) tp_modules = [] tp_depends = [] def find_depends(config,depends): for line in open(config).readlines(): if line.find(':')!=-1: (token,value)=line.split(':') for entry in value.join(','): entry = entry.strip() try: depends.index(entry) except: depends.append(entry) for module in ti.properties['modules']: tp_name = module['name'].lower() tp_version = module['version'] tp_dir = os.path.join(tp_module_dir,tp_name,tp_version) if not os.path.exists(tp_dir): print "[ERROR] Third-party module: %s/%s detected in tiapp.xml but not found at %s" % (tp_name,tp_version,tp_dir) #sys.exit(1) tp_module = os.path.join(tp_dir,'lib%s.a' % tp_name) if not os.path.exists(tp_module): print "[ERROR] Third-party module: %s/%s missing library at %s" % (tp_name,tp_version,tp_module) #sys.exit(1) tp_config = os.path.join(tp_dir,'manifest') if not os.path.exists(tp_config): print "[ERROR] Third-party module: %s/%s missing manifest at %s" % (tp_name,tp_version,tp_config) find_depends(tp_config,tp_depends) tp_modules.append(tp_module) print "[INFO] Detected third-party module: %s/%s" % (tp_name,tp_version) # copy module resources img_dir = os.path.join(tp_dir,'assets','images') if os.path.exists(img_dir): dest_img_dir = os.path.join(iphone_tmp_dir,'modules',tp_name,'images') if os.path.exists(dest_img_dir): shutil.rmtree(dest_img_dir) os.makedirs(dest_img_dir) copy_module_resources(img_dir,dest_img_dir) # compiler dependencies dependscompiler = DependencyCompiler() dependscompiler.compile(template_dir,project_dir,tp_modules,tp_depends,simulator,iphone_version) # copy over main since it can change with each release main_template = codecs.open(os.path.join(template_dir,'main.m'),'r','utf-8','replace').read() main_template = main_template.replace('__PROJECT_NAME__',name) main_template = main_template.replace('__PROJECT_ID__',appid) main_template = main_template.replace('__DEPLOYTYPE__',deploytype) main_template = main_template.replace('__APP_ID__',appid) main_template = main_template.replace('__APP_ANALYTICS__',ti.properties['analytics']) main_template = main_template.replace('__APP_PUBLISHER__',ti.properties['publisher']) main_template = main_template.replace('__APP_URL__',ti.properties['url']) main_template = main_template.replace('__APP_NAME__',ti.properties['name']) main_template = main_template.replace('__APP_VERSION__',ti.properties['version']) main_template = main_template.replace('__APP_DESCRIPTION__',ti.properties['description']) main_template = main_template.replace('__APP_COPYRIGHT__',ti.properties['copyright']) main_template = main_template.replace('__APP_GUID__',ti.properties['guid']) if simulator: main_template = main_template.replace('__APP_RESOURCE_DIR__',os.path.abspath(app_dir)) else: main_template = main_template.replace('__APP_RESOURCE_DIR__','') # copy any module image directories for module in dependscompiler.modules: img_dir = os.path.abspath(os.path.join(template_dir,'modules',module.lower(),'images')) if os.path.exists(img_dir): dest_img_dir = os.path.join(iphone_tmp_dir,'modules',module.lower(),'images') if os.path.exists(dest_img_dir): shutil.rmtree(dest_img_dir) os.makedirs(dest_img_dir) copy_module_resources(img_dir,dest_img_dir) main_dest = codecs.open(os.path.join(iphone_dir,'main.m'),'w','utf-8','replace') main_dest.write(main_template.encode("utf-8")) main_dest.close() # attempt to use a slightly faster xcodeproject template when simulator which avoids # optimizing PNGs etc if simulator: xcodeproj = codecs.open(os.path.join(template_dir,'project_simulator.pbxproj'),'r','utf-8','replace').read() else: xcodeproj = codecs.open(os.path.join(template_dir,'project.pbxproj'),'r','utf-8','replace').read() xcodeproj = xcodeproj.replace('__PROJECT_NAME__',name) xcodeproj = xcodeproj.replace('__PROJECT_ID__',appid) xcode_dir = os.path.join(iphone_dir,name+'.xcodeproj') xcode_pbx = codecs.open(os.path.join(xcode_dir,'project.pbxproj'),'w','utf-8','replace') xcode_pbx.write(xcodeproj.encode("utf-8")) xcode_pbx.close() # attempt to only copy (this takes ~7sec) if its changed if not os.path.exists(target_lib) or os.path.getsize(source_lib)!=os.path.getsize(target_lib): shutil.copy(os.path.join(template_dir,'libTiCore.a'),os.path.join(iphone_resources_dir,'libTiCore.a')) # must copy the XIBs each time since they can change per SDK if devicefamily!=None: xib = 'MainWindow_%s.xib' % devicefamily else: xib = 'MainWindow_iphone.xib' s = os.path.join(template_dir,xib) t = os.path.join(iphone_resources_dir,'MainWindow.xib') shutil.copy(s,t) def is_adhoc(uuid): path = "~/Library/MobileDevice/Provisioning Profiles/%s.mobileprovision" % uuid f = os.path.expanduser(path) if os.path.exists(f): c = codecs.open(f,'r','utf-8','replace').read() return c.find("ProvisionedDevices")!=-1 return False def add_plist(dir): if not os.path.exists(dir): os.makedirs(dir) # write out the modules we're using in the APP for m in dependscompiler.required_modules: print "[INFO] Detected required module: Titanium.%s" % (m) if command == 'install': version = ti.properties['version'] # we want to make sure in debug mode the version always changes version = "%s.%d" % (version,time.time()) ti.properties['version']=version # write out the updated Info.plist infoplist_tmpl = os.path.join(iphone_dir,'Info.plist.template') infoplist = os.path.join(iphone_dir,'Info.plist') if devicefamily!=None: appicon = ti.generate_infoplist(infoplist,infoplist_tmpl,appid,devicefamily) else: appicon = ti.generate_infoplist(infoplist,infoplist_tmpl,appid,'iphone') # copy the app icon to the build resources iconf = os.path.join(iphone_tmp_dir,appicon) iconf_dest = os.path.join(dir,appicon) if os.path.exists(iconf): shutil.copy(iconf, iconf_dest) # update our simulator file with the current version if simulator: f = open(version_file,'w+') log_id = ti.properties['guid'] f.write("%s,%s,%s,%s" % (template_dir,log_id,lib_hash,iphone_version)) f.close() # copy in the default PNG default_png = os.path.join(project_resources,'iphone','Default.png') if os.path.exists(default_png): target_png = os.path.join(iphone_resources_dir,'Default.png') if os.path.exists(target_png): os.remove(target_png) shutil.copy(default_png,target_png) # copy in any resources in our module like icons if os.path.exists(project_module_dir): copy_module_resources(project_module_dir,iphone_tmp_dir) if force_rebuild: copy_module_resources(project_resources,iphone_tmp_dir) copy_module_resources(os.path.join(project_resources,'iphone'),iphone_tmp_dir) if os.path.exists(os.path.join(iphone_tmp_dir,'iphone')): shutil.rmtree(os.path.join(iphone_tmp_dir,'iphone')) try: os.chdir(iphone_dir) if force_rebuild: # write out plist add_plist(os.path.join(iphone_dir,'Resources')) print "[DEBUG] compile checkpoint: %0.2f seconds" % (time.time()-start_time) print "[INFO] Executing XCode build..." print "[BEGIN_VERBOSE] Executing XCode Compiler <span>[toggle output]</span>" elif simulator: print "[INFO] Detected pre-compiled app, will run in interpreted mode to speed launch" sys.stdout.flush() deploy_target = "IPHONEOS_DEPLOYMENT_TARGET=3.1" device_target = 'TARGETED_DEVICE_FAMILY=iPhone' # this is non-sensical, but you can't pass empty string if devicefamily!=None: if devicefamily == 'ipad': device_target=" TARGETED_DEVICE_FAMILY=iPad" deploy_target = "IPHONEOS_DEPLOYMENT_TARGET=3.2" if command == 'simulator': if force_rebuild: output = run.run([ "xcodebuild", "-configuration", "Debug", "-sdk", "iphonesimulator%s" % iphone_version, "WEB_SRC_ROOT=%s" % iphone_tmp_dir, "GCC_PREPROCESSOR_DEFINITIONS=__LOG__ID__=%s DEPLOYTYPE=development DEBUG=1" % log_id, deploy_target, device_target ]) print output print "[END_VERBOSE]" sys.stdout.flush() if os.path.exists(iphone_tmp_dir): shutil.rmtree(iphone_tmp_dir) if output.find("** BUILD FAILED **")!=-1 or output.find("ld returned 1")!=-1: print "[ERROR] Build Failed. Please see output for more details" sys.exit(1) # first make sure it's not running kill_simulator() # sometimes the simulator doesn't remove old log files # in which case we get our logging jacked - we need to remove # them before running the simulator def cleanup_app_logfiles(): def find_all_log_files(folder, fname): results = [] for root, dirs, files in os.walk(os.path.expanduser(folder)): for file in files: if fname==file: fullpath = os.path.join(root, file) results.append(fullpath) return results for f in find_all_log_files("~/Library/Application Support/iPhone Simulator",'%s.log' % log_id): print "[DEBUG] removing old log file: %s" % f sys.stdout.flush() os.remove(f) cleanup_app_logfiles() sim = None def handler(signum, frame): print "[INFO] Simulator is exiting" sys.stdout.flush() if not log == None: try: os.system("kill -2 %s" % str(log.pid)) except: pass if not sim == None and signum!=3: try: os.system("kill -3 %s" % str(sim.pid)) except: pass kill_simulator() sys.exit(0) signal.signal(signal.SIGHUP, handler) signal.signal(signal.SIGINT, handler) signal.signal(signal.SIGQUIT, handler) signal.signal(signal.SIGABRT, handler) signal.signal(signal.SIGTERM, handler) print "[INFO] Launching application in Simulator" sys.stdout.flush() sys.stderr.flush() # we have to do this in simulator *after* the potential compile since his screen # removes html, etc for module in os.listdir(os.path.join(template_dir,'modules')): img_dir = os.path.abspath(os.path.join(template_dir,'modules',module.lower(),'images')) if os.path.exists(img_dir): dest_img_dir = os.path.join(app_dir,'modules',module.lower(),'images') if os.path.exists(dest_img_dir): shutil.rmtree(dest_img_dir) os.makedirs(dest_img_dir) copy_module_resources(img_dir,dest_img_dir) copy_module_resources(project_resources,app_dir,True,True) copy_module_resources(os.path.join(project_resources,'iphone'),app_dir,True,True) if os.path.exists(os.path.join(app_dir,'iphone')): shutil.rmtree(os.path.join(app_dir,'iphone')) if os.path.exists(os.path.join(app_dir,'android')): shutil.rmtree(os.path.join(app_dir,'android')) # launch the simulator if devicefamily==None: sim = subprocess.Popen("\"%s\" launch \"%s\" %s iphone" % (iphonesim,app_dir,iphone_version),shell=True) else: sim = subprocess.Popen("\"%s\" launch \"%s\" %s %s" % (iphonesim,app_dir,iphone_version,devicefamily),shell=True) # activate the simulator window ass = os.path.join(template_dir,'iphone_sim_activate.scpt') cmd = "osascript \"%s\"" % ass os.system(cmd) end_time = time.time()-start_time print "[INFO] Launched application in Simulator (%0.2f seconds)" % end_time sys.stdout.flush() sys.stderr.flush() # give the simulator a bit to get started and up and running before # starting the logger time.sleep(2) logger = os.path.realpath(os.path.join(template_dir,'logger.py')) # start the logger log = subprocess.Popen([ logger, str(log_id)+'.log', iphone_version ]) os.waitpid(sim.pid,0) print "[INFO] Application has exited from Simulator" # in this case, the user has exited the simulator itself # and not clicked Stop Emulator from within Developer so we kill # our tail log process but let simulator keep running if not log == None: try: os.system("kill -2 %s" % str(log.pid)) except: pass sys.exit(0) elif command == 'install': # make sure it's clean if os.path.exists(app_bundle): shutil.rmtree(app_bundle) output = run.run(["xcodebuild", "-configuration", "Debug", "-sdk", "iphoneos%s" % iphone_version, "CODE_SIGN_ENTITLEMENTS=", "GCC_PREPROCESSOR_DEFINITIONS='DEPLOYTYPE=test'", "PROVISIONING_PROFILE[sdk=iphoneos*]=%s" % appuuid, "CODE_SIGN_IDENTITY[sdk=iphoneos*]=iPhone Developer: %s" % dist_name, deploy_target, device_target ]) shutil.rmtree(iphone_tmp_dir) if output.find("** BUILD FAILED **")!=-1: print "[ERROR] Build Failed. Please see output for more details" sys.exit(1) # look for a code signing error error = re.findall(r'Code Sign error:(.*)',output) if len(error) > 0: print "[ERROR] Code sign error: %s" % error[0].strip() sys.exit(1) print "[INFO] Installing application in iTunes ... one moment" sys.stdout.flush() # for install, launch itunes with the app cmd = "open -b com.apple.itunes \"%s\"" % app_bundle os.system(cmd) # now run our applescript to tell itunes to sync to get # the application on the phone ass = os.path.join(template_dir,'itunes_sync.scpt') cmd = "osascript \"%s\"" % ass os.system(cmd) print "[INFO] iTunes sync initiated" sys.stdout.flush() elif command == 'distribute': # make sure it's clean if os.path.exists(app_bundle): shutil.rmtree(app_bundle) # in this case, we have to do different things based on if it's # an ad-hoc distribution cert or not - in the case of non-adhoc # we don't use the entitlements file but in ad hoc we need to adhoc_line = "CODE_SIGN_ENTITLEMENTS=" deploytype = "production_adhoc" if not is_adhoc(appuuid): adhoc_line="CODE_SIGN_ENTITLEMENTS = Resources/Entitlements.plist" deploytype = "production" # build the final release distribution output = run.run(["xcodebuild", "-configuration", "Release", "-sdk", "iphoneos%s" % iphone_version, "%s" % adhoc_line, "GCC_PREPROCESSOR_DEFINITIONS='DEPLOYTYPE=%s'" % deploytype, "PROVISIONING_PROFILE[sdk=iphoneos*]=%s" % appuuid, "CODE_SIGN_IDENTITY[sdk=iphoneos*]=iPhone Distribution: %s" % dist_name, deploy_target, device_target ]) shutil.rmtree(iphone_tmp_dir) if output.find("** BUILD FAILED **")!=-1: print "[ERROR] Build Failed. Please see output for more details" sys.exit(1) # look for a code signing error error = re.findall(r'Code Sign error:(.*)',output) if len(error) > 0: print "[ERROR] Code sign error: %s" % error[0].strip() sys.exit(1) # switch to app_bundle for zip os.chdir(app_bundle_folder) # you *must* use ditto here or it won't upload to appstore os.system('ditto -ck --keepParent --sequesterRsrc "%s" "%s/%s.zip"' % (app_name,output_dir,app_name)) sys.exit(0) else: print "Unknown command: %s" % command sys.exit(2) finally: os.chdir(cwd)
def main(args): argc = len(args) if argc < 5 or (argc > 1 and args[1] == 'distribute' and argc!=9): print "%s <command> <version> <project_dir> <appid> <name> [uuid] [dist_name] [output_dir]" % os.path.basename(args[0]) print print "available commands: " print print " install install the app to itunes for testing on iphone" print " simulator build and run on the iphone simulator" print " distribute build final distribution bundle" sys.exit(1) print "[INFO] One moment, building ..." sys.stdout.flush() start_time = time.time() iphone_version = dequote(args[2].decode("utf-8")) simulator = os.path.abspath(os.path.join(template_dir,'iphonesim')) command = args[1].decode("utf-8") project_dir = os.path.expanduser(dequote(args[3].decode("utf-8"))) appid = dequote(args[4].decode("utf-8")) name = dequote(args[5].decode("utf-8")) target = 'Debug' deploytype = 'development' devicefamily = 'iphone' debug = False if command == 'distribute': appuuid = dequote(args[6].decode("utf-8")) dist_name = dequote(args[7].decode("utf-8")) output_dir = os.path.expanduser(dequote(args[8].decode("utf-8"))) target = 'Release' deploytype = 'production' elif command == 'simulator': deploytype = 'development' debug = True devicefamily = dequote(args[6].decode("utf-8")) elif command == 'install': appuuid = dequote(args[6].decode("utf-8")) dist_name = dequote(args[7].decode("utf-8")) deploytype = 'test' iphone_dir = os.path.abspath(os.path.join(project_dir,'build','iphone')) project_resources = os.path.join(project_dir,'Resources') app_name = name+'.app' app_folder_name = '%s-iphoneos' % target app_dir = os.path.abspath(os.path.join(iphone_dir,'build','%s-iphonesimulator'%target,name+'.app')) app_bundle_folder = os.path.abspath(os.path.join(iphone_dir,'build',app_folder_name)) app_bundle = os.path.join(app_bundle_folder,app_name) iphone_resources_dir = os.path.join(iphone_dir,'Resources') iphone_tmp_dir = os.path.join(iphone_dir,'tmp') if not os.path.exists(iphone_dir): print "Could not find directory: %s" % iphone_dir sys.exit(1) cwd = os.getcwd() app_js = os.path.join(project_dir,'Resources','app.js') if not os.path.exists(app_js): print "[ERROR] This project looks to not be ported to 0.9+." print "[ERROR] Your project is missing app.js. Please make sure to port your application to 0.9+ API" print "[ERROR] before continuing or choose a previous version of the SDK." sys.exit(1) tiapp_xml = os.path.join(project_dir,'tiapp.xml') if not os.path.exists(tiapp_xml): print "Missing tiapp.xml at %s" % tiapp_xml sys.exit(3) ti = TiAppXML(tiapp_xml) encrypt = False if ti.properties.has_key('encrypt'): encrypt = (ti.properties['encrypt']=='true') # compile resources compiler = Compiler(appid,project_dir,encrypt,debug) compiler.compile() # find the module directory relative to the root of the SDK tp_module_dir = os.path.abspath(os.path.join(template_dir,'..','..','..','..','modules','iphone')) tp_modules = [] for module in ti.properties['modules']: tp_name = module['name'].lower() tp_version = module['version'] tp_dir = os.path.join(tp_module_dir,tp_name,tp_version) if not os.path.exists(tp_dir): print "[ERROR] Third-party module: %s/%s detected in tiapp.xml but not found at %s" % (tp_name,tp_version,tp_dir) #sys.exit(1) tp_module = os.path.join(tp_dir,'lib%s.a' % tp_name) if not os.path.exists(tp_module): print "[ERROR] Third-party module: %s/%s missing library at %s" % (tp_name,tp_version,tp_module) #sys.exit(1) tp_modules.append(tp_module) print "[INFO] Detected third-party module: %s/%s" % (tp_name,tp_version) # copy module resources img_dir = os.path.join(tp_dir,'assets','images') if os.path.exists(img_dir): dest_img_dir = os.path.join(iphone_tmp_dir,'modules',tp_name,'images') if os.path.exists(dest_img_dir): shutil.rmtree(dest_img_dir) os.makedirs(dest_img_dir) copy_module_resources(img_dir,dest_img_dir) # compiler dependencies dependscompiler = DependencyCompiler() dependscompiler.compile(template_dir,project_dir,tp_modules) # copy any module image directories for module in dependscompiler.modules: img_dir = os.path.abspath(os.path.join(template_dir,'modules',module.lower(),'images')) if os.path.exists(img_dir): dest_img_dir = os.path.join(iphone_tmp_dir,'modules',module.lower(),'images') if os.path.exists(dest_img_dir): shutil.rmtree(dest_img_dir) os.makedirs(dest_img_dir) copy_module_resources(img_dir,dest_img_dir) # copy over main since it can change with each release main_template = codecs.open(os.path.join(template_dir,'main.m'),'r','utf-8','replace').read() main_template = main_template.replace('__PROJECT_NAME__',name) main_template = main_template.replace('__PROJECT_ID__',appid) main_template = main_template.replace('__DEPLOYTYPE__',deploytype) main_template = main_template.replace('__APP_ID__',appid) main_template = main_template.replace('__APP_ANALYTICS__',ti.properties['analytics']) main_template = main_template.replace('__APP_PUBLISHER__',ti.properties['publisher']) main_template = main_template.replace('__APP_URL__',ti.properties['url']) main_template = main_template.replace('__APP_NAME__',ti.properties['name']) main_template = main_template.replace('__APP_VERSION__',ti.properties['version']) main_template = main_template.replace('__APP_DESCRIPTION__',ti.properties['description']) main_template = main_template.replace('__APP_COPYRIGHT__',ti.properties['copyright']) main_template = main_template.replace('__APP_GUID__',ti.properties['guid']) main_dest = codecs.open(os.path.join(iphone_dir,'main.m'),'w','utf-8','replace') main_dest.write(main_template.encode("utf-8")) main_dest.close() # attempt to use a slightly faster xcodeproject template when simulator which avoids # optimizing PNGs etc if deploytype == 'simulator': xcodeproj = codecs.open(os.path.join(template_dir,'project_simulator.pbxproj'),'r','utf-8','replace').read() else: xcodeproj = codecs.open(os.path.join(template_dir,'project.pbxproj'),'r','utf-8','replace').read() xcodeproj = xcodeproj.replace('__PROJECT_NAME__',name) xcodeproj = xcodeproj.replace('__PROJECT_ID__',appid) xcode_dir = os.path.join(iphone_dir,name+'.xcodeproj') xcode_pbx = codecs.open(os.path.join(xcode_dir,'project.pbxproj'),'w','utf-8','replace') xcode_pbx.write(xcodeproj.encode("utf-8")) xcode_pbx.close() # copy in the default PNG default_png = os.path.join(project_resources,'iphone','Default.png') if os.path.exists(default_png): target_png = os.path.join(iphone_resources_dir,'Default.png') if os.path.exists(target_png): os.remove(target_png) shutil.copy(default_png,target_png) # TODO: review this with new module SDK # in case the developer has their own modules we can pick them up project_module_dir = os.path.join(project_dir,"modules","iphone") # copy in any resources in our module like icons if os.path.exists(project_module_dir): copy_module_resources(project_module_dir,iphone_tmp_dir) sys.stdout.flush() source_lib=os.path.join(template_dir,'libTiCore.a') target_lib=os.path.join(iphone_resources_dir,'libTiCore.a') # attempt to only copy (this takes ~7sec) if its changed if not os.path.exists(target_lib) or os.path.getsize(source_lib)!=os.path.getsize(target_lib): shutil.copy(os.path.join(template_dir,'libTiCore.a'),os.path.join(iphone_resources_dir,'libTiCore.a')) # must copy the XIBs each time since they can change per SDK xib = 'MainWindow_%s.xib' % devicefamily s = os.path.join(template_dir,xib) t = os.path.join(iphone_resources_dir,'MainWindow.xib') if not os.path.exists(t) or os.path.getsize(s)!=os.path.getsize(t): shutil.copy(s,t) def is_adhoc(uuid): path = "~/Library/MobileDevice/Provisioning Profiles/%s.mobileprovision" % uuid f = os.path.expanduser(path) if os.path.exists(f): c = codecs.open(f,'r','utf-8','replace').read() return c.find("ProvisionedDevices")!=-1 return False def add_plist(dir): if not os.path.exists(dir): os.makedirs(dir) # write out the modules we're using in the APP for m in dependscompiler.required_modules: print "[INFO] Detected required module: Titanium.%s" % (m) if command == 'install': version = ti.properties['version'] # we want to make sure in debug mode the version always changes version = "%s.%d" % (version,time.time()) ti.properties['version']=version # write out the updated Info.plist infoplist_tmpl = os.path.join(iphone_dir,'Info.plist.template') infoplist = os.path.join(iphone_dir,'Info.plist') appicon = ti.generate_infoplist(infoplist,infoplist_tmpl,appid,devicefamily) # copy the app icon to the build resources iconf = os.path.join(iphone_tmp_dir,appicon) iconf_dest = os.path.join(dir,appicon) if os.path.exists(iconf): shutil.copy(iconf, iconf_dest) try: os.chdir(iphone_dir) # write out plist add_plist(os.path.join(iphone_dir,'Resources')) print "[DEBUG] compile checkpoint: %0.2f seconds" % (time.time()-start_time) print "[INFO] Executing XCode build..." print "[BEGIN_VERBOSE] Executing XCode Compiler <span>[toggle output]</span>" sys.stdout.flush() if command == 'simulator': # first build it log_id = uuid.uuid4() # make sure it's clean if os.path.exists(app_dir): shutil.rmtree(app_dir) deploy_target = "IPHONEOS_DEPLOYMENT_TARGET=3.1" device_target = "TARGETED_DEVICE_FAMILY=iPhone" if devicefamily == 'ipad': iphone_version='3.2' device_target=" TARGETED_DEVICE_FAMILY=iPad" output = run.run([ "xcodebuild", "-configuration", "Debug", "-sdk", "iphonesimulator%s" % iphone_version, "WEB_SRC_ROOT=%s" % iphone_tmp_dir, "GCC_PREPROCESSOR_DEFINITIONS=__LOG__ID__=%s DEPLOYTYPE=development DEBUG=1" % log_id, deploy_target, device_target ]) print output print "[END_VERBOSE]" sys.stdout.flush() shutil.rmtree(iphone_tmp_dir) if output.find("** BUILD FAILED **")!=-1 or output.find("ld returned 1")!=-1: print "[ERROR] Build Failed. Please see output for more details" sys.exit(1) # first make sure it's not running kill_simulator() logger = os.path.realpath(os.path.join(template_dir,'logger.py')) # start the logger log = subprocess.Popen([ logger, str(log_id)+'.log', iphone_version ]) sim = None def handler(signum, frame): print "[INFO] Simulator is exiting" sys.stdout.flush() if not log == None: try: os.system("kill -2 %s" % str(log.pid)) except: pass if not sim == None and signum!=3: try: os.system("kill -3 %s" % str(sim.pid)) except: pass kill_simulator() sys.exit(0) signal.signal(signal.SIGHUP, handler) signal.signal(signal.SIGINT, handler) signal.signal(signal.SIGQUIT, handler) signal.signal(signal.SIGABRT, handler) signal.signal(signal.SIGTERM, handler) print "[INFO] Launching application in Simulator" sys.stdout.flush() sys.stderr.flush() # launch the simulator sim = subprocess.Popen("\"%s\" launch \"%s\" %s %s" % (simulator,app_dir,iphone_version,devicefamily),shell=True) # activate the simulator window ass = os.path.join(template_dir,'iphone_sim_activate.scpt') cmd = "osascript \"%s\"" % ass os.system(cmd) end_time = time.time()-start_time print "[INFO] Launched application in Simulator (%0.2f seconds)" % end_time sys.stdout.flush() sys.stderr.flush() os.waitpid(sim.pid,0) print "[INFO] Application has exited from Simulator" # in this case, the user has exited the simulator itself # and not clicked Stop Emulator from within Developer so we kill # our tail log process but let simulator keep running if not log == None: try: os.system("kill -2 %s" % str(log.pid)) except: pass sys.exit(0) elif command == 'install': # make sure it's clean if os.path.exists(app_bundle): shutil.rmtree(app_bundle) output = run.run(["xcodebuild", "-configuration", "Debug", "-sdk", "iphoneos%s" % iphone_version, "CODE_SIGN_ENTITLEMENTS=", "GCC_PREPROCESSOR_DEFINITIONS='DEPLOYTYPE=test'", "PROVISIONING_PROFILE[sdk=iphoneos*]=%s" % appuuid, "CODE_SIGN_IDENTITY[sdk=iphoneos*]=iPhone Developer: %s" % dist_name ]) shutil.rmtree(iphone_tmp_dir) if output.find("** BUILD FAILED **")!=-1: print "[ERROR] Build Failed. Please see output for more details" sys.exit(1) # look for a code signing error error = re.findall(r'Code Sign error:(.*)',output) if len(error) > 0: print "[ERROR] Code sign error: %s" % error[0].strip() sys.exit(1) print "[INFO] Installing application in iTunes ... one moment" sys.stdout.flush() # for install, launch itunes with the app cmd = "open -b com.apple.itunes \"%s\"" % app_bundle os.system(cmd) # now run our applescript to tell itunes to sync to get # the application on the phone ass = os.path.join(template_dir,'itunes_sync.scpt') cmd = "osascript \"%s\"" % ass os.system(cmd) print "[INFO] iTunes sync initiated" sys.stdout.flush() elif command == 'distribute': # make sure it's clean if os.path.exists(app_bundle): shutil.rmtree(app_bundle) # in this case, we have to do different things based on if it's # an ad-hoc distribution cert or not - in the case of non-adhoc # we don't use the entitlements file but in ad hoc we need to adhoc_line = "CODE_SIGN_ENTITLEMENTS=" deploytype = "production_adhoc" if not is_adhoc(appuuid): adhoc_line="CODE_SIGN_ENTITLEMENTS = Resources/Entitlements.plist" deploytype = "production" # build the final release distribution output = run.run(["xcodebuild", "-configuration", "Release", "-sdk", "iphoneos%s" % iphone_version, "%s" % adhoc_line, "GCC_PREPROCESSOR_DEFINITIONS='DEPLOYTYPE=%s'" % deploytype, "PROVISIONING_PROFILE[sdk=iphoneos*]=%s" % appuuid, "CODE_SIGN_IDENTITY[sdk=iphoneos*]=iPhone Distribution: %s" % dist_name ]) shutil.rmtree(iphone_tmp_dir) if output.find("** BUILD FAILED **")!=-1: print "[ERROR] Build Failed. Please see output for more details" sys.exit(1) # look for a code signing error error = re.findall(r'Code Sign error:(.*)',output) if len(error) > 0: print "[ERROR] Code sign error: %s" % error[0].strip() sys.exit(1) # switch to app_bundle for zip os.chdir(app_bundle_folder) # you *must* use ditto here or it won't upload to appstore os.system('ditto -ck --keepParent --sequesterRsrc "%s" "%s/%s.zip"' % (app_name,output_dir,app_name)) sys.exit(0) else: print "Unknown command: %s" % command sys.exit(2) finally: os.chdir(cwd)