Exemple #1
0
    def do_build(self):
        apk_rollback_obj = utils.FileRollback()
        apk_rollback_obj.record_file(
            utils.flat_path(os.path.join(self.proj_parth, 'main.js')))
        # 编译creator工程
        if self.rebuild_creator:
            self.build_creator_proj()
            # 删除和替换资源
            self.op_creator_res()

        # 清理temp目录
        self.temp_dir = os.path.join(self.root_dir, 'temp')
        if os.path.isdir(self.temp_dir):
            shutil.rmtree(self.temp_dir)
        os.makedirs(self.temp_dir)

        # 创建mainfest的结构体
        self.gen_manifest_obj()

        # 更新资源目录
        self.update_resources()

        # 生成zip包
        self.write_zip_file()

        apk_rollback_obj.do_rollback()
        shutil.rmtree(self.temp_dir)

        Logging.debug_msg('热更包打包完成!\n')
        Logging.debug_msg('------------------------------------')
Exemple #2
0
    def _do_add_check_files(self, key, value):
        unix_key = key.replace('\\', '/')

        if unix_key not in self.check_files:
            self.check_files[unix_key] = value
        else:
            Logging.warn_msg("%s 冲突:%s 和 %s" % (unix_key, self.check_files[unix_key], value))
Exemple #3
0
 def _do_encrypt(self, src, dst_path):
     Logging.debug_msg('开始资源加密')
     sys.path.append(
         os.path.normpath(
             os.path.join(os.path.dirname(__file__), '../ResEncrypt')))
     from ResEncrypt import ResEncrypt
     encryptor = ResEncrypt(src, dst_path, False,
                            PackAPK.ASSETS_ENCRYPT_EXCLUDE_CFG, True, False)
     encryptor.do_encrypt()
     Logging.debug_msg('资源加密结束')
Exemple #4
0
def start(nameStr):
    Logging.debug_msg("\n")

    nameLst = []
    if nameStr == 'all' or nameStr == 'allmj' or nameStr == 'allpk':
        nameLst = getAllGames(nameStr)
    else:
        nameLst = nameStr.split(',')

    for name in nameLst:
        compress_imgs_in_path(name)
Exemple #5
0
def run_shell(cmd, cwd=None, quiet=False):
    if not quiet:
        Logging.log_msg('Running command: %s\n' % cmd)

    p = subprocess.Popen(cmd, shell=True, cwd=cwd)
    p.wait()

    if p.returncode:
        raise_known_error('Command %s failed' % cmd, p.returncode)

    return p.returncode
Exemple #6
0
 def write_zip_file(self):
     Logging.debug_msg('正在生成压缩包..')
     # 创建目录
     cur_time_str = datetime.datetime.fromtimestamp(
         time.time()).strftime('%Y%m%d_%H%M%S')
     zip_name = '%s_%s_%s_%s.zip' % (self.app_id, self.channel_id,
                                     self.batch_info['version'],
                                     cur_time_str)
     output_dir = os.path.join(self.root_dir, 'output', zip_name)
     utils.zip_folder(self.temp_dir, output_dir)
     Logging.debug_msg('压缩包生成完成 %s ' % output_dir)
Exemple #7
0
    def __init__(self, args):
        self.src_file = utils.flat_path(args.src_file)
        if not os.path.isfile(self.src_file):
            raise_known_error('文件 %s 不存在' % self.src_file, KnownError.ERROR_PATH_NOT_FOUND)

        if args.dst_file:
            self.dst_file = utils.flat_path(args.dst_file)
        else:
            name, ext = os.path.splitext(self.src_file)
            self.dst_file = '%s_new%s' % (name, ext)

        Logging.debug_msg("原始文件路径:%s" % self.src_file)
        Logging.debug_msg("输出文件路径:%s" % self.dst_file)
    def getCompileJsListByModule(self, module):
        jsList = []
        preList = []
        postList = []
        gameConfigPath = os.path.join(self.proj_path, "games", module,
                                      "wxpack.json")
        if os.path.exists(gameConfigPath):
            gameConfig = utils.parse_json(gameConfigPath)
            preposition = gameConfig.get("preposition", [])
            for preFile in preposition:
                jsList.append(preFile)
                preList.append(preFile)
            postposition = gameConfig.get("postposition", [])
            for postFile in postposition:
                postList.append(postFile)
        else:
            Logging.log_msg("wxpack.json 文件不存在 %s" % gameConfigPath)

        for parent, dirnames, filenames in os.walk(self.games_path):
            relpath = os.path.relpath(parent, os.path.join(parent, ".."))
            isSamePath = os.path.normpath(
                os.path.abspath(os.path.join(
                    parent, ".."))) == os.path.normpath(
                        os.path.abspath(self.games_path))
            if module == relpath and isSamePath == True:
                for p, dirname, filenames in os.walk(parent):
                    for filename in filenames:
                        token = filename.split(".")
                        if len(token) != 2 or filename.split(".")[1] != "js":
                            continue

                        filename = os.path.join(os.path.normpath(p), filename)
                        filename = os.path.relpath(filename, self.proj_path)
                        filename = filename.replace("\\", "/")

                        isPass = False
                        for postFile in postList:
                            if postFile == filename:
                                isPass = True
                        for preFile in preList:
                            if preFile == filename:
                                isPass = True
                        if 'manifest' in filename:
                            isPass = True

                        if isPass == False:
                            jsList.append(filename)
        for postFile in postList:
            jsList.append(postFile)
        return jsList
Exemple #9
0
def run_shell(cmd, cwd=None, quiet=False):
    if not quiet:
        cwd_info = ''
        if cwd:
            cwd_info = ' (cwd path : %s) ' % cwd
        Logging.log_msg('Running command%s: %s\n' % (cwd_info, cmd))

    p = subprocess.Popen(cmd, shell=True, cwd=cwd)
    p.wait()

    if p.returncode:
        raise_known_error('Command %s failed' % cmd, p.returncode)

    return p.returncode
Exemple #10
0
 def build_creator_proj(self):
     Logging.debug_msg('开始构建creator项目')
     try:
         if sys.platform == "win32":
             utils.run_shell(
                 'cd /d %s & CocosCreator.exe --path %s --build "platform=android;debug=false"'
                 % (self.creator_exe_path, self.creator_proj_path))
         else:
             creator_path = '/Applications/CocosCreator.app/Contents/MacOS'
             utils.run_shell(
                 'pushd "%s";CocosCreator --path %s --build "platform=android;debug=false";popd'
                 % (creator_path, self.creator_proj_path))
     except Exception as e:
         raise_known_error("Creator 项目命令行构建失败 msg=%s" % str(e))
     Logging.debug_msg('构建creator项目完成')
Exemple #11
0
def traverseDir(absDir):  #遍历当前目录以及递归的子目录,找到所有的png图片
    # test = "db://assets/resources/common/textures/bl_vip_10.png/bl_vip_10"
    # print(test.find("/common/"))
    count = 0
    compress_count = 0
    for (parent, dirs, files) in os.walk(absDir):
        for f in files:
            full_path = os.path.join(parent, f)
            rel_path = os.path.relpath(full_path, absDir)
            rel_path = rel_path.replace("\\", "/")
            ext = os.path.splitext(rel_path)[1]
            if ext == ".png":
                count += 1
                if needCompress(rel_path):
                    compress_count += 1
                    processPNG(full_path)
    Logging.debug_msg("Total image count : %d. Compress count : %d" %
                      (count, compress_count))
Exemple #12
0
    def build_apk_gradle(self, rollback_obj, cfg_dir, apk_cfg_info, apk_name):
        # 最终 apk 文件名格式为:GAMENAME_PKGNAME_APPID_CHANNELID_VERNAME_VERCODE.apk
        # Logging.debug_msg('修改apk文件名 game_name=%s pkg_name=%s app_id=%s channel_id=%s ver_name=%s ver_code=%s' % (game_name, pkg_name, app_id, channel_id, ver_name, ver_code))

        # 修改签名文件
        Logging.debug_msg('修改签名文件')
        self.setGradleConfig(rollback_obj, cfg_dir, apk_cfg_info, apk_name)
        try:
            if sys.platform == "win32":
                utils.run_shell(
                    'cd /d %s & set ANDROID_HOME="%s" & gradlew clean & gradlew aR --stacktrace'
                    % (self.proj_android_path, self.sdk_root))
            else:
                utils.run_shell(
                    'pushd "%s";export ANDROID_HOME="%s";./gradlew clean;./gradlew aR --stacktrace;popd'
                    % (self.proj_android_path, self.sdk_root))
        except Exception as e:
            raise_known_error("gradle 命令行打包失败 msg=%s" % str(e))

        Logging.debug_msg('gradle配置文件修改完成')
Exemple #13
0
    def build_apk_gradle(self, rollback_obj, cfg_dir, apk_cfg_info, apk_name):
        # 最终 apk 文件名格式为:GAMENAME_PKGNAME_APPID_CHANNELID_VERNAME_VERCODE.apk
        # Logging.debug_msg('修改apk文件名 game_name=%s pkg_name=%s app_id=%s channel_id=%s ver_name=%s ver_code=%s' % (game_name, pkg_name, app_id, channel_id, ver_name, ver_code))

        # 修改签名文件
        Logging.debug_msg('修改签名文件')
        keystore_path = utils.flat_path(
            os.path.join(
                cfg_dir,
                apk_cfg_info[PackAPK.CFG_SIGN][PackAPK.CFG_SIGN_FILE]))
        keystore_pass = apk_cfg_info[PackAPK.CFG_SIGN][
            PackAPK.CFG_SIGN_PASSWORD]
        alias = apk_cfg_info[PackAPK.CFG_SIGN][PackAPK.CFG_SIGN_ALIAS]
        alias_pass = apk_cfg_info[PackAPK.CFG_SIGN][
            PackAPK.CFG_SIGN_ALIAS_PASSWORD]
        self._modify_gradle_config(rollback_obj, self.output_path, apk_name,
                                   keystore_path, keystore_pass, alias,
                                   alias_pass)

        gradle_cmd = "cd %s;gradle clean;gradle aR" % self.proj_androidStudio_path
        try:
            utils.run_shell(gradle_cmd)
        except:
            Logging.warn_msg('gradle 命令行打包失败')

        Logging.debug_msg('gradle配置文件修改完成')
Exemple #14
0
    def __init__(self, args):
        # 配置文件
        self.batch_cfg_file = utils.flat_path(args.proj_cfg)
        if not os.path.isfile(self.batch_cfg_file):
            raise_known_error("文件 %s 不存在" % self.batch_cfg_file,
                              KnownError.ERROR_PATH_NOT_FOUND)
        self.root_dir = os.path.dirname(self.batch_cfg_file)
        self.batch_info = self._parse_json(self.batch_cfg_file)
        if not self.batch_info:
            raise_known_error('解析文件 %s 失败' % self.batch_cfg_file,
                              KnownError.ERROR_PARSE_FILE)

        self.app_id = self.batch_info['appid']
        self.channel_id = self.batch_info['channel']
        self.proj_parth = utils.flat_path(
            os.path.join(self.root_dir, self.batch_info['proj_root']))
        self.pack_parth = utils.flat_path(
            os.path.join(self.root_dir, self.batch_info['pack_root']))
        # 是否需要重编creator
        self.rebuild_creator = args.rebuild_creator
        if self.rebuild_creator:
            # 检查Creator的安装目录
            self.creator_exe_path = utils.check_environment_variable(
                'CREATOR_PATH')
            if not os.path.isdir(self.creator_exe_path):
                raise_known_error("环境变量 CREATOR_PATH 未设置")
            self.creator_proj_path = utils.flat_path(
                os.path.join(self.proj_parth, '../../'))

        self.encrypt_res = args.encrypt_res

        Logging.debug_msg('是否重新编译creator工程 : %s' % self.rebuild_creator)
        Logging.debug_msg('是否加密图片资源 : %s' % self.encrypt_res)
        Logging.debug_msg('------------------------------------\n')
Exemple #15
0
    def op_creator_res(self):
        # 删除本地配置文件 CustomScript.js
        custom_file_path = utils.flat_path(
            os.path.join(self.proj_parth, 'src/assets/scripts'))
        self.del_js_file(custom_file_path, 'CustomScript')

        # #压缩图片资源
        # exclude_dict = {
        #     "exclude_files": [
        #         # "*_s9.png"
        #     ],
        # }
        # if not self.no_encrypt:
        #     pq = png_quant.PngQuant(self.res_root_path, exclude_dict)
        #     pq.compress_images_in_path()

        # 加密图片
        if self.encrypt_res:
            Logging.debug_msg('开始加密图片资源')
            res_root_path = utils.flat_path(
                os.path.join(self.proj_parth, 'res'))
            encrytPng.traverseDir(res_root_path)
            Logging.debug_msg('开始图片资源加密完成')
Exemple #16
0
    def __init__(self, args):
        self.batch_cfg_file = utils.flat_path(args.proj_cfg)
        if not os.path.isfile(self.batch_cfg_file):
            raise_known_error("文件 %s 不存在" % self.batch_cfg_file,
                              KnownError.ERROR_PATH_NOT_FOUND)
        self.no_rollback = args.no_rollback
        self.root_dir = os.path.dirname(self.batch_cfg_file)
        cur_time_str = datetime.datetime.fromtimestamp(
            time.time()).strftime('%Y%m%d_%H%M%S')
        self.output_path = os.path.join(self.root_dir, 'output', cur_time_str)
        #配置文件数据
        self.batch_info = self._parse_json(self.batch_cfg_file)
        if not self.batch_info:
            raise_known_error('解析文件 %s 失败' % self.batch_cfg_file,
                              KnownError.ERROR_PARSE_FILE)

        # 检查 android sdk 环境变量
        self.sdk_root = utils.flat_path(
            utils.check_environment_variable('ANDROID_SDK_ROOT'))

        self.build_result = {}
        cur_dir = os.path.dirname(__file__)
        self.proj_parth = utils.flat_path(
            os.path.join(cur_dir, '../../../jsb-default'))
        self.proj_android_path = utils.flat_path(
            os.path.join(self.proj_parth, 'project_android_20'))

        if not os.path.isdir(self.proj_android_path):
            raise_known_error("未找到 Android 工程文件夹 %s" % self.proj_android_path)

        self.android_manifest = os.path.join(
            self.proj_android_path, 'launcher/src/main/AndroidManifest.xml')

        self.java_files = []
        for parent, dirs, files in os.walk(
                utils.flat_path(
                    os.path.join(self.proj_android_path,
                                 'unityLibrary/src/main/java'))):
            for f in files:
                filename, ext = os.path.splitext(f)
                if ext.lower() == '.java':
                    self.java_files.append(os.path.join(parent, f))

        Logging.debug_msg('使用配置文件 : %s' % self.batch_cfg_file)
        Logging.debug_msg('是否禁用还原 : %s' % self.no_rollback)
        Logging.debug_msg('Android 工程路径 : %s' % self.proj_android_path)
        Logging.debug_msg('----------------\n')
Exemple #17
0
    def gen_manifest_obj(self):
        Logging.debug_msg('正在生成manifest结构..')
        self.manifest_obj = {}
        self.manifest_obj["version"] = self.batch_info['version']
        self.manifest_obj["packageUrl"] = ''
        self.manifest_obj["remoteManifestUrl"] = ''
        self.manifest_obj["remoteVersionUrl"] = ''
        hotUpdateUrl = self.batch_info['url']
        if len(hotUpdateUrl) > 1:
            self.manifest_obj["packageUrl"] = hotUpdateUrl + ''
            self.manifest_obj[
                "remoteManifestUrl"] = hotUpdateUrl + 'project.manifest'
            self.manifest_obj[
                "remoteVersionUrl"] = hotUpdateUrl + 'version.manifest'

        # 先创建version.manifest
        version_manifest = utils.flat_path(
            os.path.join(self.temp_dir, 'version.manifest'))
        file_m = open(version_manifest, "wb")
        file_m.writelines(json.dumps(self.manifest_obj))
        file_m.close()

        self.manifest_obj["searchPaths"] = []
        self.manifest_obj["assets"] = {}
Exemple #18
0
    def update_resources(self):
        Logging.debug_msg('正在拷贝资源到tmp目录..')
        # 拷贝资源到tmp目录
        for res in self.batch_info['include']:
            if not res:
                continue
            copy_cfg = {'from': res, 'to': res, 'exclude': ['**/.DS_Store']}
            excopy.copy_files_with_config(copy_cfg, self.proj_parth,
                                          self.temp_dir)

        # 先删除CfgPackage.js或CfgPackage.jsc
        scripts_path = utils.flat_path(
            os.path.join(self.temp_dir, 'src/assets/scripts'))
        self.del_js_file(scripts_path, 'CfgPackage')
        self.del_js_file(scripts_path, 'manifest')

        # 替换CfgPackage.js文件
        pack_cfg_path = utils.flat_path(
            os.path.join(self.pack_parth, self.app_id, self.channel_id))
        copy_cfg = {
            'from': 'cfg',
            'to': 'src/assets/scripts',
            'exclude': ['**/.DS_Store']
        }
        excopy.copy_files_with_config(copy_cfg, pack_cfg_path, self.temp_dir)

        Logging.debug_msg('正在生成资源列表的md5信息..')
        # 生成资源列表的md5信息
        assetsObj = self.manifest_obj['assets']
        self.get_file_path_md5(self.temp_dir, assetsObj)

        # 替换掉文件 manifest.js
        tmp_str = "(function() { window.CustomManifestAssets = holdString})();"
        tmp_str = tmp_str.replace("holdString", json.dumps(assetsObj))
        src_path = utils.flat_path(os.path.join(self.temp_dir, 'src'))
        manifest_js_path = utils.flat_path(
            os.path.join(src_path, 'assets/scripts/manifest.js'))
        file_m = open(manifest_js_path, "wb")
        file_m.writelines(tmp_str)
        file_m.close()

        # 重新计算manifest.js的md5值
        rel_path = 'src/assets/scripts/manifest.js'
        assetsObj[rel_path] = {
            'size': os.path.getsize(manifest_js_path),
            'md5': self.get_file_md5(manifest_js_path)
        }

        Logging.debug_msg('生成project.manifest文件..')
        # 创建project.manifest
        version_manifest = utils.flat_path(
            os.path.join(self.temp_dir, 'project.manifest'))
        file_m = open(version_manifest, "wb")
        file_m.writelines(json.dumps(self.manifest_obj))
        file_m.close()
Exemple #19
0
def needCompress(key):
    global PngMap
    # folder, basename = os.path.split(key)
    # pattern = r"([a-f0-9\-]+)\.[a-f0-9\-]{5}\.png"
    # m = re.match(pattern, basename)
    # if not m:
    #     Logging.warn_msg("The file path %s is not in right format." % key)
    #     return False
    #
    # checkKey = os.path.join(folder, "%s.png" % m.group(1))
    checkKey = key.replace('\\', '/')
    if PngMap.has_key(checkKey):
        srcPath = os.path.dirname(PngMap[checkKey])
        srcPath = srcPath.lstrip("db://assets/")
        base, ext = os.path.splitext(srcPath)
        if (ext == ".plist"):
            srcPath = base + '.png'

        # 检查不需要压缩的文件夹
        unDirs = Uncompress.get('dirs', [])
        for d in unDirs:
            if srcPath.startswith(d):
                Logging.warn_msg("%s in uncompress dir : %s" % (key, d))
                return False

        # 检查不需要压缩的文件
        unFiles = Uncompress.get('files', [])
        for f in unFiles:
            if srcPath == f:
                Logging.warn_msg("%s is uncompress file %s" % (key, f))
                return False

        Logging.debug_msg("Compress image : %s (%s)" % (key, srcPath))
        return True
    else:
        Logging.warn_msg("%s is not found in PngMap.json" % checkKey)
        return False
Exemple #20
0
 def build_creator_proj(self):
     Logging.debug_msg('开始构建creator项目')
     Logging.debug_msg(self.creator_proj_parth)
     creator_exe_path = utils.check_environment_variable('CREATOR_PATH')
     try:
         if sys.platform == "win32":
             utils.run_shell(
                 'cd /d %s & CocosCreator.exe --path %s --build "platform=wechatgame;debug=false"'
                 % (creator_exe_path, self.creator_proj_parth))
         else:
             creator_path = '/Applications/CocosCreator.app/Contents/MacOS/'
             utils.run_shell(
                 '%sCocosCreator --path %s --build "platform=wechatgame;debug=false"'
                 % (creator_path, self.creator_proj_parth))
     except Exception as e:
         raise_known_error("Creator 项目命令行构建失败 msg=%s" % str(e))
     Logging.debug_msg('构建creator项目完成')
Exemple #21
0
    def build_creator_proj(self):
        Logging.debug_msg('开始构建creator项目')
        Logging.debug_msg(self.creator_proj_path)
        try:
            # 删除之前构建生成的文件夹
            if os.path.isdir(self.proj_parth):
                shutil.rmtree(self.proj_parth)

            json_file = os.path.join(self.creator_proj_path,
                                     "settings/wechatgame.json")
            loads = self.readJson(json_file)
            loads["startSceneAssetBundle"] = False

            self.writeJson(json_file, loads)

            # https://docs.cocos.com/creator/manual/en/publish/publish-in-command-line.html
            buildoptions = ";".join([
                "platform=wechatgame", "buildPath=build", "debug=false",
                "sourceMaps=false", "md5Cache=true",
                "mainCompressionType=merge_all_json", "mainIsRemote=false"
            ])
            paramFmt = '--path {path} --build "{options}"'
            params = paramFmt.format(path=self.creator_proj_path,
                                     options=buildoptions)

            if sys.platform == "win32":
                creator_exe_path = utils.check_environment_variable(
                    'CREATOR_PATH')
                cmdline = 'cd /d "%s" & CocosCreator.exe %s' % (
                    creator_exe_path, params)
                utils.run_shell(cmdline)
            else:
                creator_path = '/Applications/CocosCreator/Creator/2.4.3/CocosCreator.app/Contents/MacOS/CocosCreator'
                utils.run_shell('%s %s' % (creator_path, params))

        except Exception as e:
            raise_known_error("Creator 项目命令行构建失败 msg=%s" % str(e))
        Logging.debug_msg('构建creator项目完成')
Exemple #22
0
def start(absDir, pngMapPath):  #遍历当前目录以及递归的子目录,找到所有的png图片
    global ext_path
    global PngMap
    global Uncompress

    Logging.debug_msg("----- Handle image compress begin. ----")
    if utils.os_is_win32():
        ext_path = utils.flat_path(
            os.path.join(os.path.dirname(__file__),
                         "../../png_quant/bin/win32/pngquant"))
    else:
        ext_path = utils.flat_path(
            os.path.join(os.path.dirname(__file__),
                         "../../png_quant/bin/mac/pngquant"))
    Logging.debug_msg("Tool path : " + ext_path)
    absDir = utils.flat_path(absDir)
    Logging.debug_msg("Handle images path : " + absDir)
    Logging.debug_msg("PngMap.json path : " + pngMapPath)
    try:
        f = open(pngMapPath)
        PngMap = json.load(f)
        f.close()
    except:
        pass

    #print(PngMap['res/raw-assets/6a/6a811324-26ea-4e78-b238-4509160c26ad.png'])
    json_file = utils.flat_path(
        os.path.join(os.path.dirname(__file__), "uncompress.json"))
    Logging.debug_msg("uncompress.json path :" + json_file)
    try:
        f = open(json_file)
        Uncompress = json.load(f)
        f.close()
    except:
        pass

    traverseDir(absDir)

    Logging.debug_msg("----- Handle image compress end. ----")
Exemple #23
0
    def do_build(self):
        #各个渠道的打包
        for app_id in self.batch_info.keys():
            app_id = utils.non_unicode_str(app_id)
            channels = self.batch_info[app_id]
            for channel_id in channels:
                Logging.debug_msg('----------------')
                apk_rollback_obj = utils.FileRollback()
                try:
                    channel_str = self.get_string(channel_id)
                    self.build_result['%s_%s' % (app_id, channel_str)] = ''
                    self.build_one_apk(app_id, channel_str, apk_rollback_obj)
                except:
                    Logging.warn_msg('打包失败')
                finally:
                    Logging.debug_msg('finally :')
                    if not self.no_rollback:
                        apk_rollback_obj.do_rollback()
                Logging.debug_msg('----------------\n')

        Logging.debug_msg('\n打包结果汇总 :')
        for key in self.build_result.keys():
            ids = key.split('_')
            value = self.build_result[key]
            if value and os.path.isfile(utils.get_sys_encode_str(value)):
                Logging.debug_msg(
                    'APP_ID : %s, CHANNEL_ID : %s。打包成功。apk 路径 : %s' %
                    (ids[0], ids[1], value))
            else:
                Logging.debug_msg('APP_ID : %s, CHANNEL_ID : %s。打包失败。' %
                                  (ids[0], ids[1]))
        #打开目录
        os.system("start explorer %s" % self.output_path)