From 7f0d0325c7e2a262819b5a642401586dd91baabe Mon Sep 17 00:00:00 2001 From: Paul Reynolds Date: Wed, 26 Aug 2015 16:52:27 -0400 Subject: [PATCH] Reintroduced Clean plugin. Refactored Mac and iOS Compile plugin The Clean plugin required updating to the 'cocos' namespace. The execution dependency on dist was removed (since that's an optional plugin). The Clean now does the clean with xcodebuild so there's a connection with the Compile plugin class to access the same build environment variables. Tested compile, run, and clean commands on Mac and iOS --- bin/cocos2d.ini | 2 +- plugins/plugin_clean.py | 141 ++++++++-- plugins/project_compile/project_compile.py | 304 +++++++++------------ 3 files changed, 258 insertions(+), 189 deletions(-) diff --git a/bin/cocos2d.ini b/bin/cocos2d.ini index f81c541a..5c7d34fc 100644 --- a/bin/cocos2d.ini +++ b/bin/cocos2d.ini @@ -28,7 +28,7 @@ framework.CCPluginFramework #plugin_version.CCPluginVersion #plugin_install.CCPluginInstall #plugin_update.CCPluginUpdate -#plugin_clean.CCPluginClean +plugin_clean.CCPluginClean #plugin_dist.CCPluginDist #plugin_test.CCPluginTest # To add a new plugin add it's classname here diff --git a/plugins/plugin_clean.py b/plugins/plugin_clean.py index 319d495f..32eff144 100644 --- a/plugins/plugin_clean.py +++ b/plugins/plugin_clean.py @@ -1,24 +1,24 @@ #!/usr/bin/python # ---------------------------------------------------------------------------- -# cocos2d "clean" plugin -# -# Author: Luis Parravicini +# cocos "clean" plugin # # License: MIT # ---------------------------------------------------------------------------- ''' -"clean" plugin for cocos2d command line tool +"clean" plugin for cocos command line tool ''' __docformat__ = 'restructuredtext' import os +import re import shutil +import cocos +import cocos_project +from MultiLanguage import MultiLanguage +from project_compile import CCPluginCompile -import cocos2d -from plugin_dist import CCPluginDist - -class CCPluginClean(cocos2d.CCPlugin): +class CCPluginClean(cocos.CCPlugin): """ cleans a project """ @@ -31,35 +31,138 @@ def plugin_name(): def brief_description(): return "removes files produced by compilation" - def clean_android(self): + def _add_custom_options(self, parser): + self.ccompile._add_custom_options(parser) + + def _check_custom_options(self, args): + self.ccompile._check_custom_options(args) + + def clean_android(self, dependencies): if not self._platforms.is_android_active(): return project_dir = self._platforms.project_path() - cocos2d.Logging.info("cleaning native") + cocos.Logging.info("cleaning native") obj_path = os.path.join(project_dir, 'obj') self._rmdir(obj_path) - cocos2d.Logging.info("cleaning java") + cocos.Logging.info("cleaning java") self._run_cmd("cd \"%s\" && ant clean" % project_dir) - def clean_ios(self): + def clean_win32(self, dependencies): + if not self._platforms.is_win32_active(): + return + cocos.Logging.info("Clean not supported for this platform yet.") + + def clean_web(self,dependencies): + if not self._platforms.is_web_active(): + return + cocos.Logging.info("Clean not supported for this platform yet.") + + def clean_linux(self,dependencies): + if not self._platforms.is_linux_active(): + return + cocos.Logging.info("Clean not supported for this platform yet.") + + def clean_wp8(self,dependencies): + if not self._platforms.is_wp8_active(): + return + cocos.Logging.info("Clean not supported for this platform yet.") + + def clean_wp8_1(self,dependencies): + if not self._platforms.is_wp8_active(): + return + cocos.Logging.info("Clean not supported for this platform yet.") + + def clean_metro(self,dependencies): + if not self._platforms.is_wp8_active(): + return + cocos.Logging.info("Clean not supported for this platform yet.") + + def clean_ios(self, dependencies): if not self._platforms.is_ios_active(): return - project_dir = self._platforms.project_path() + + self.ccompile.setup_ios_mac_build_vars() + output_dir = self.ccompile._output_dir + target_name = self.ccompile.target_name + mode = self.ccompile._mode + use_sdk = self.ccompile.use_sdk + xcodeproj_path = self.ccompile.xcodeproj_path + target_app_dir = os.path.join(output_dir, "%s.app" % target_name) + + cocos.Logging.info("Cleaning iOS " + target_name) + + command = ' '.join([ + "xcodebuild clean", + "-project", + "\"%s\"" % xcodeproj_path, + "-configuration", + "%s" % 'Debug' if mode == 'debug' else 'Release', + "-target", + "\"%s\"" % target_name, + "%s" % "-arch i386" if use_sdk == 'iphonesimulator' else '', + "-sdk", + "%s" % use_sdk, + "CONFIGURATION_BUILD_DIR=\"%s\"" % (output_dir), + "%s" % "VALID_ARCHS=\"i386\"" if use_sdk == 'iphonesimulator' else '' + ]) + + self._run_cmd(command) + + cocos.Logging.info("Removing " + target_app_dir) + self._rmdir(target_app_dir) + + def clean_mac(self, dependencies): + if not self._platforms.is_mac_active(): + return + + self.ccompile.setup_ios_mac_build_vars() + output_dir = self.ccompile._output_dir + target_name = self.ccompile.target_name + mode = self.ccompile._mode + xcodeproj_path = self.ccompile.xcodeproj_path + target_app_dir = os.path.join(output_dir, "%s.app" % target_name) + + cocos.Logging.info("Cleaning Mac " + target_name) + + command = ' '.join([ + "xcodebuild clean", + "-project", + "\"%s\"" % xcodeproj_path, + "-configuration", + "%s" % 'Debug' if mode == 'debug' else 'Release', + "-target", + "\"%s\"" % target_name, + "CONFIGURATION_BUILD_DIR=\"%s\"" % (output_dir) + ]) + + self._run_cmd(command) + + cocos.Logging.info("Removing " + target_app_dir) + self._rmdir(target_app_dir) - cocos2d.Logging.info("removing intermediate files") - self._run_cmd("cd \"%s\" && xcodebuild clean" % project_dir) - self._rmdir(CCPluginDist.target_path(project_dir)) def _rmdir(self, path): if os.path.exists(path): try: shutil.rmtree(path) except OSError as e: - raise cocos2d.CCPluginError("Error removing directory: " + str(e.args)) + raise cocos.CCPluginError("Error removing directory: " + str(e.args)) def run(self, argv, dependencies): + self.ccompile = CCPluginCompile() + self.ccompile.parse_args(argv) + self.parse_args(argv) - self.clean_android() - self.clean_ios() + + self.clean_android(dependencies) + self.clean_ios(dependencies) + self.clean_mac(dependencies) + + self.clean_win32(dependencies) + self.clean_web(dependencies) + self.clean_linux(dependencies) + self.clean_wp8(dependencies) + self.clean_wp8_1(dependencies) + self.clean_metro(dependencies) diff --git a/plugins/project_compile/project_compile.py b/plugins/project_compile/project_compile.py index 767744ec..4f3b6bfc 100644 --- a/plugins/project_compile/project_compile.py +++ b/plugins/project_compile/project_compile.py @@ -505,7 +505,8 @@ def build_android(self): cocos.Logging.info(MultiLanguage.get_string('COMPILE_INFO_BUILD_SUCCEED')) - def check_ios_mac_build_depends(self): + + def setup_ios_mac_build_vars(self): version = cocos.get_xcode_version() if version <= '5': @@ -517,13 +518,14 @@ def check_ios_mac_build_depends(self): xcodeproj_name = cfg_obj.proj_file name = os.path.basename(xcodeproj_name) else: - name, xcodeproj_name = self.checkFileByExtention(".xcodeproj", self._platforms.project_path()) + name, xcodeproj_name = self.checkFileByExtension(".xcodeproj", self._platforms.project_path()) if not xcodeproj_name: message = MultiLanguage.get_string('COMPILE_ERROR_XCODEPROJ_NOT_FOUND') raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) self.project_name = name self.xcodeproj_name = xcodeproj_name + self._setup_ios_mac_xcode_target() def _remove_res(self, target_path): build_cfg_dir = self._build_cfg_path() @@ -616,79 +618,16 @@ def build_ios(self): raise cocos.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_BUILD_ON_MAC'), cocos.CCPluginError.ERROR_WRONG_ARGS) - if self._sign_id is not None: - cocos.Logging.info(MultiLanguage.get_string('COMPILE_INFO_IOS_SIGN_FMT', self._sign_id)) - self.use_sdk = 'iphoneos' - else: - self.use_sdk = 'iphonesimulator' - - self.check_ios_mac_build_depends() - - ios_project_dir = self._platforms.project_path() + self.setup_ios_mac_build_vars() output_dir = self._output_dir - projectPath = os.path.join(ios_project_dir, self.xcodeproj_name) - pbxprojectPath = os.path.join(projectPath, "project.pbxproj") - - f = file(pbxprojectPath) - contents = f.read() - - section = re.search(r"Begin PBXProject section.*End PBXProject section", contents, re.S) - - if section is None: - message = MultiLanguage.get_string('COMPILE_ERROR_NO_IOS_TARGET') - raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) - - targets = re.search(r"targets = (.*);", section.group(), re.S) - if targets is None: - message = MultiLanguage.get_string('COMPILE_ERROR_NO_IOS_TARGET') - raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) - - targetName = None - if self.xcode_target_name is not None: - targetName = self.xcode_target_name - else: - cfg_obj = self._platforms.get_current_config() - if cfg_obj.target_name is not None: - targetName = cfg_obj.target_name - else: - names = re.split("\*", targets.group()) - for name in names: - if "iOS" in name or "-mobile" in name: - targetName = str.strip(name) - break - - if targetName is None: - message = MultiLanguage.get_string('COMPILE_ERROR_NO_IOS_TARGET') - raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) - if os.path.isdir(output_dir): - target_app_dir = os.path.join(output_dir, "%s.app" % targetName) + target_app_dir = os.path.join(output_dir, "%s.app" % self.target_name) if os.path.isdir(target_app_dir): shutil.rmtree(target_app_dir) # is script project, check whether compile scripts or not - need_reset_dir = False - if self._project._is_script_project(): - script_src_dir = os.path.join(self._project.get_project_dir(), "src") - - if self._project._is_js_project() and self._compile_script: - # backup the source scripts - self.backup_dir(script_src_dir) - self.compile_js_scripts(script_src_dir, script_src_dir) - - # js project need compile the js files in engine - engine_js_dir = self.get_engine_js_dir() - if engine_js_dir is not None: - self.backup_dir(engine_js_dir) - self.compile_js_scripts(engine_js_dir, engine_js_dir) - need_reset_dir = True - - if self._project._is_lua_project() and self._lua_encrypt: - # on iOS, only invoke luacompile when lua encrypt is specified - self.backup_dir(script_src_dir) - self.compile_lua_scripts(script_src_dir, script_src_dir, False) - need_reset_dir = True + need_reset_dir = self._script_cleanup_check() try: cocos.Logging.info(MultiLanguage.get_string('COMPILE_INFO_BUILDING')) @@ -696,11 +635,11 @@ def build_ios(self): command = ' '.join([ "xcodebuild", "-project", - "\"%s\"" % projectPath, + "\"%s\"" % self.xcodeproj_path, "-configuration", "%s" % 'Debug' if self._mode == 'debug' else 'Release', "-target", - "\"%s\"" % targetName, + "\"%s\"" % self.target_name, "%s" % "-arch i386" if self.use_sdk == 'iphonesimulator' else '', "-sdk", "%s" % self.use_sdk, @@ -716,19 +655,19 @@ def build_ios(self): filelist = os.listdir(output_dir) for filename in filelist: - name, extention = os.path.splitext(filename) - if extention == '.a': + name, extension = os.path.splitext(filename) + if extension == '.a': filename = os.path.join(output_dir, filename) os.remove(filename) - self._iosapp_path = os.path.join(output_dir, "%s.app" % targetName) + self._iosapp_path = os.path.join(output_dir, "%s.app" % self.target_name) if self._no_res: self._remove_res(self._iosapp_path) if self._sign_id is not None: # generate the ipa - app_path = os.path.join(output_dir, "%s.app" % targetName) - ipa_path = os.path.join(output_dir, "%s.ipa" % targetName) + app_path = os.path.join(output_dir, "%s.app" % target_name) + ipa_path = os.path.join(output_dir, "%s.ipa" % target_name) ipa_cmd = "xcrun -sdk %s PackageApplication -v \"%s\" -o \"%s\"" % (self.use_sdk, app_path, ipa_path) self._run_cmd(ipa_cmd) @@ -738,14 +677,7 @@ def build_ios(self): cocos.CCPluginError.ERROR_BUILD_FAILED) finally: # is script project & need reset dirs - if need_reset_dir: - script_src_dir = os.path.join(self._project.get_project_dir(), "src") - self.reset_backup_dir(script_src_dir) - - if self._project._is_js_project(): - engine_js_dir = self.get_engine_js_dir() - if engine_js_dir is not None: - self.reset_backup_dir(engine_js_dir) + if need_reset_dir: self._script_project_cleanup() def build_mac(self): if not self._platforms.is_mac_active(): @@ -755,56 +687,69 @@ def build_mac(self): raise cocos.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_BUILD_ON_MAC'), cocos.CCPluginError.ERROR_WRONG_ARGS) - self.check_ios_mac_build_depends() - - mac_project_dir = self._platforms.project_path() + self.setup_ios_mac_build_vars() output_dir = self._output_dir + + # I commented this out because it was blowing away the resource files + # inside the app package that were not getting put back in on rebuilds + # ml-preynolds@github.com - projectPath = os.path.join(mac_project_dir, self.xcodeproj_name) - pbxprojectPath = os.path.join(projectPath, "project.pbxproj") + #if os.path.isdir(self._output_dir): + # target_app_dir = os.path.join(self._output_dir, "%s.app" % self.target_name) + # if os.path.isdir(target_app_dir): + # shutil.rmtree(target_app_dir) - f = file(pbxprojectPath) - contents = f.read() + need_reset_dir = self._script_cleanup_check() - section = re.search( - r"Begin PBXProject section.*End PBXProject section", - contents, - re.S - ) + try: + cocos.Logging.info(MultiLanguage.get_string('COMPILE_INFO_BUILDING')) - if section is None: - message = MultiLanguage.get_string('COMPILE_ERROR_NO_MAC_TARGET') - raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) + command = ' '.join([ + "xcodebuild", + "-project", + "\"%s\"" % self.xcodeproj_path, + "-configuration", + "%s" % 'Debug' if self._mode == 'debug' else 'Release', + "-target", + "\"%s\"" % self.target_name, + "CONFIGURATION_BUILD_DIR=\"%s\"" % (output_dir) + ]) - targets = re.search(r"targets = (.*);", section.group(), re.S) - if targets is None: - message = MultiLanguage.get_string('COMPILE_ERROR_NO_MAC_TARGET') - raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) + self._run_cmd(command) - targetName = None - if self.xcode_target_name is not None: - targetName = self.xcode_target_name - else: - cfg_obj = self._platforms.get_current_config() - if cfg_obj.target_name is not None: - targetName = cfg_obj.target_name - else: - names = re.split("\*", targets.group()) - for name in names: - if "Mac" in name or "-desktop" in name: - targetName = str.strip(name) - break + # cleaning up residual libs + filelist = os.listdir(output_dir) + for filename in filelist: + name, extension = os.path.splitext(filename) + if extension == '.a': + filename = os.path.join(output_dir, filename) + os.remove(filename) - if targetName is None: - message = MultiLanguage.get_string('COMPILE_ERROR_NO_MAC_TARGET') - raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) + # run command uses this var + self._macapp_path = os.path.join(output_dir, "%s.app" % self.target_name) - if os.path.isdir(output_dir): - target_app_dir = os.path.join(output_dir, "%s.app" % targetName) - if os.path.isdir(target_app_dir): - shutil.rmtree(target_app_dir) + if self._no_res: + resource_path = os.path.join(self._macapp_path, "Contents", "Resources") + self._remove_res(resource_path) - # is script project, check whether compile scripts or not + cocos.Logging.info(MultiLanguage.get_string('COMPILE_INFO_BUILD_SUCCEED')) + except: + raise cocos.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_BUILD_FAILED'), + cocos.CCPluginError.ERROR_BUILD_FAILED) + finally: + # is script project & need reset dirs + if need_reset_dir: self._script_cleanup() + + def _script_project_cleanup(self): + script_src_dir = os.path.join(self._project.get_project_dir(), "src") + self.reset_backup_dir(script_src_dir) + + if self._project._is_js_project(): + engine_js_dir = self.get_engine_js_dir() + if engine_js_dir is not None: + self.reset_backup_dir(engine_js_dir) + + def _script_cleanup_check(self): need_reset_dir = False if self._project._is_script_project(): script_src_dir = os.path.join(self._project.get_project_dir(), "src") @@ -821,55 +766,76 @@ def build_mac(self): self.compile_js_scripts(engine_js_dir, engine_js_dir) need_reset_dir = True - if self._project._is_lua_project() and (self._lua_encrypt or self._compile_script): + if self._project._is_lua_project() and self._lua_encrypt: # on iOS, only invoke luacompile when lua encrypt is specified self.backup_dir(script_src_dir) - self.compile_lua_scripts(script_src_dir, script_src_dir) + self.compile_lua_scripts(script_src_dir, script_src_dir, False) need_reset_dir = True + return need_reset_dir - try: - cocos.Logging.info(MultiLanguage.get_string('COMPILE_INFO_BUILDING')) + # digs into a xcode project to extract the target name + # also sets the xcodeproj_path which is the full path to the project file + def _setup_ios_mac_xcode_target(self): + self.xcodeproj_path = os.path.join(self._platforms.project_path(), self.xcodeproj_name) + pbxprojectPath = os.path.join(self.xcodeproj_path, "project.pbxproj") - command = ' '.join([ - "xcodebuild", - "-project", - "\"%s\"" % projectPath, - "-configuration", - "%s" % 'Debug' if self._mode == 'debug' else 'Release', - "-target", - "\"%s\"" % targetName, - "CONFIGURATION_BUILD_DIR=\"%s\"" % (output_dir) - ]) + if self._platforms.is_ios_active(): + if self._sign_id is not None: + cocos.Logging.info(MultiLanguage.get_string('COMPILE_INFO_IOS_SIGN_FMT', self._sign_id)) + self.use_sdk = 'iphoneos' + else: + self.use_sdk = 'iphonesimulator' - self._run_cmd(command) + f = file(pbxprojectPath) + contents = f.read() - self.target_name = targetName - filelist = os.listdir(output_dir) - for filename in filelist: - name, extention = os.path.splitext(filename) - if extention == '.a': - filename = os.path.join(output_dir, filename) - os.remove(filename) + section = re.search( + r"Begin PBXProject section.*End PBXProject section", + contents, + re.S + ) - self._macapp_path = os.path.join(output_dir, "%s.app" % targetName) - if self._no_res: - resource_path = os.path.join(self._macapp_path, "Contents", "Resources") - self._remove_res(resource_path) + if section is None: + message = MultiLanguage.get_string('COMPILE_ERROR_NO_MAC_TARGET') + if self._platforms.is_ios_active(): + message = MultiLanguage.get_string('COMPILE_ERROR_NO_IOS_TARGET') + raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) - cocos.Logging.info(MultiLanguage.get_string('COMPILE_INFO_BUILD_SUCCEED')) - except: - raise cocos.CCPluginError(MultiLanguage.get_string('COMPILE_ERROR_BUILD_FAILED'), - cocos.CCPluginError.ERROR_BUILD_FAILED) - finally: - # is script project & need reset dirs - if need_reset_dir: - script_src_dir = os.path.join(self._project.get_project_dir(), "src") - self.reset_backup_dir(script_src_dir) + targets = re.search(r"targets = (.*);", section.group(), re.S) + if targets is None: + message = MultiLanguage.get_string('COMPILE_ERROR_NO_MAC_TARGET') + if self._platforms.is_ios_active(): + message = MultiLanguage.get_string('COMPILE_ERROR_NO_IOS_TARGET') + raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) + + target_name = None + if self.xcode_target_name is not None: + target_name = self.xcode_target_name + else: + cfg_obj = self._platforms.get_current_config() + if cfg_obj.target_name is not None: + target_name = cfg_obj.target_name + else: + names = re.split("\*", targets.group()) + if self._platforms.is_mac_active(): + for name in names: + if "Mac" in name or "-desktop" in name: + target_name = str.strip(name) + break + elif self._platforms.is_ios_active(): + for name in names: + if "iOS" in name or "-mobile" in name: + target_name = str.strip(name) + break + + if target_name is None: + message = MultiLanguage.get_string('COMPILE_ERROR_NO_MAC_TARGET') + if self._platforms.is_ios_active(): + message = MultiLanguage.get_string('COMPILE_ERROR_NO_IOS_TARGET') + raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PARSE_FILE) + + self.target_name = target_name - if self._project._is_js_project(): - engine_js_dir = self.get_engine_js_dir() - if engine_js_dir is not None: - self.reset_backup_dir(engine_js_dir) def _get_required_vs_version(self, proj_file): # get the VS version required by the project @@ -1095,7 +1061,7 @@ def build_win32(self): else: name = cfg_obj.project_name else: - name, sln_name = self.checkFileByExtention(".sln", win32_projectdir) + name, sln_name = self.checkFileByExtension(".sln", win32_projectdir) if not sln_name: message = MultiLanguage.get_string('COMPILE_ERROR_SLN_NOT_FOUND') raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PATH_NOT_FOUND) @@ -1405,7 +1371,7 @@ def build_wp8(self): else: name = cfg_obj.project_name else: - name, sln_name = self.checkFileByExtention(".sln", sln_path) + name, sln_name = self.checkFileByExtension(".sln", sln_path) if not sln_name: message = MultiLanguage.get_string('COMPILE_ERROR_SLN_NOT_FOUND') raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PATH_NOT_FOUND) @@ -1466,7 +1432,7 @@ def build_wp8_1(self): else: name = cfg_obj.project_name else: - name, sln_name = self.checkFileByExtention(".sln", wp8_1_projectdir) + name, sln_name = self.checkFileByExtension(".sln", wp8_1_projectdir) if not sln_name: message = MultiLanguage.get_string('COMPILE_ERROR_SLN_NOT_FOUND') raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PATH_NOT_FOUND) @@ -1500,7 +1466,7 @@ def build_metro(self): else: name = cfg_obj.project_name else: - name, sln_name = self.checkFileByExtention(".sln", metro_projectdir) + name, sln_name = self.checkFileByExtension(".sln", metro_projectdir) if not sln_name: message = MultiLanguage.get_string('COMPILE_ERROR_SLN_NOT_FOUND') raise cocos.CCPluginError(message, cocos.CCPluginError.ERROR_PATH_NOT_FOUND) @@ -1512,11 +1478,11 @@ def build_metro(self): build_mode = 'Debug' if self._is_debug_mode() else 'Release' self.build_vs_project(projectPath, self.project_name, build_mode) - def checkFileByExtention(self, ext, path): + def checkFileByExtension(self, ext, path): filelist = os.listdir(path) for fullname in filelist: - name, extention = os.path.splitext(fullname) - if extention == ext: + name, extension = os.path.splitext(fullname) + if extension == ext: return name, fullname return (None, None)