<<<<<<< HEAD from fs.copy import copy_fs from jinja2 import Environment, FileSystemLoader import json import os import re ======= from fs.copy import copy_fs, copy_file from jinja2 import Environment, FileSystemLoader import fs import json import os import re import hashlib import time import shutil >>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca ''' 流程: 一、将resources里面所有文件夹拷贝到当前目录下 二、解析json配置文件,遍历每一项生成/model/view/controller 三、自动运行项目 ''' <<<<<<< HEAD # 将字符串首字母转换成大写字母 def convertFirstLetterUpper(text_str): # return text_str.capitalize() # print("////////////////////>>>>", text_str) return re.sub("([a-zA-Z])", lambda x: x.groups()[0].upper(), text_str, 1) # ROOT = os.path.abspath(os.getcwd()) jinja_env = Environment(loader=FileSystemLoader(os.path.join(os.getcwd(), 'templates'))) jinja_env.filters['letterUpper'] = convertFirstLetterUpper input_dir = None output_dir = None def copyFiles(src_dir, dst_dir): copy_fs(src_dir, dst_dir) def handleResources(config): # 处理路由页面 # 遍历config文件,收集所有的action和name,action和name的首字母必须大写 # 然后才生成路由配置页面 target_file = os.sep.join(["views", "__init__.py"]) handleRender(config, 'router.tpl', target_file) def handleSignal(config): # 生成信号槽模块 target_file = os.sep.join(["application", "signal_manager.py"]) handleRender(config, 'signal_manager.tpl', target_file) target_file = os.sep.join(["controllers", "__init__.py"]) handleRender(config, 'signal_manager_init.tpl', target_file) ======= # 比较两个文件内容是否相同,这里没有使用md5内容摘要算法,MD5算法的缺点是,针对大文件,计算耗时。虽然咱们这里不存在大文件,但是条条大路通罗马嘛,试试其他方法也挺好。 def cmp_file(file1, file2): f1 = os.stat(file1) f2 = os.stat(file2) if f1.st_size != f2.st_size: return False buf_size = 8 * 1024 with open(file1, "rb") as fp1, open(file2, "rb") as fp2: while True: buf1 = fp1.read(buf_size) buf2 = fp2.read(buf_size) if buf1 != buf2: return False # 这里表示文件读完了 if not buf1 or not buf2: return True def cmp_md5(contnet1, content2): m1 = hashlib.md5() m1.update(bytearray(contnet1, 'utf-8')) m2 = hashlib.md5() m2.update(bytearray(content2, 'utf-8')) return m1.hexdigest() == m2.hexdigest() # 将字符串首字母转换成大写字母 def convertFirstLetterUpper(text_str): # return text_str.capitalize() # print("////////////////////>>>>", text_str) return re.sub("([a-zA-Z])", lambda x: x.groups()[0].upper(), text_str, 1) # ROOT = os.path.abspath(os.getcwd()) jinja_env = Environment(loader=FileSystemLoader(os.path.join(os.getcwd(), 'templates'))) jinja_env.filters['letterUpper'] = convertFirstLetterUpper input_dir = None output_dir = None def copyFiles(src_dir, dst_dir): copy_fs(src_dir, dst_dir) def handleResources(config): # 处理路由页面 # 遍历config文件,收集所有的action和name,action和name的首字母必须大写 # 然后才生成路由配置页面 target_file = os.sep.join(["views", "__init__.py"]) handleRender(config, 'router.tpl', target_file) def handleSignal(config): # 生成信号槽模块 target_file = os.sep.join(["application", "signal_manager.py"]) handleRender(config, 'signal_manager.tpl', target_file) target_file = os.sep.join(["controllers", "__init__.py"]) handleRender(config, 'signal_manager_init.tpl', target_file) >>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca def handleModel(config, application): # 将所有有默认值的字段分为一组,没有默认值的字段分为另一组 # 生成模板代码时,无默认值的字段在前,有默认值的字段字在后 # 收集表字段信息 fields = [] extend = False for m in config.get("model").get("fields"): fields.append(m.get("name")) extend = True print(m) <<<<<<< HEAD target_file = os.sep.join(["models", "{}.py".format(config.get("name"))]) handleRender(config, 'model.tpl', target_file, fields=fields, extend=extend, application=application) ======= target_file = os.sep.join(["models", "{}.py".format(config.get("name"))]) handleRender(config, 'model.tpl', target_file, fields=fields, extend=extend, application=application) # 多次复制时,会报文件已存在错误,因此要先删除 target_file = os.sep.join(["models", "base.py"]) if os.path.exists(target_file): os.remove(target_file) handleRender(config, 'base.tpl', target_file, application=application) >>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca def handleView(config): target_file = os.sep.join(["views", "{}.py".format(config.get("name"))]) handleRender(config, 'view.tpl', target_file) def handleController(config): # 根据模型字段自动从models列表中取出file name信息和class name信息 target_file = os.sep.join(["controllers", "{}.py".format(config.get("name"))]) handleRender(config, 'controller.tpl', target_file) def handleRender(result, tpl, target_file, **kwargs): global output_dir # print("=========>", result.get("name"), "{}.py".format(result.get("name"))) jinja_tpl = jinja_env.get_template(tpl) content = jinja_tpl.render({ "config": result, **kwargs }) # print("############", output_dir) <<<<<<< HEAD ======= >>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca target_file = os.sep.join([output_dir, target_file]) if not os.path.exists(os.path.dirname(target_file)): os.makedirs(os.path.dirname(target_file)) <<<<<<< HEAD with open(target_file, 'w', encoding='utf-8') as f: f.write(content) ======= # 这里需要比较目标文件夹是否已经存在同名文件,如果存在,则需要比较两个文件内容是否一致 # 如果不一致时,则需要给旧的文件打上时间戳,作为备份文件 # 具体流程: # 先将原来文件重命名,然后新的内容写入到重命名的文件中 # 最后比较两个文件内容是否一致,如果一致,则删除重命名的那个旧的备份文件 tmp_file = "" if os.path.exists(target_file) and os.stat(target_file).st_size > 0: n, e = os.path.splitext(target_file) tmp_file = "{}.{}{}".format(n, time.strftime("%Y%m%d%H%M%S", time.localtime()), e) if os.path.exists(tmp_file): os.remove(tmp_file) os.rename(target_file, tmp_file) with open(target_file, 'w', encoding='utf-8') as f: f.write(content) if cmp_file(tmp_file, target_file) == True: os.remove(tmp_file) >>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca def parseConfig(config): # 解析配置文件 for cfg in config.get("apis"): handleModel(cfg, config.get("application")) handleView(cfg) handleController(cfg) handleResources(config.get("apis")) handleSignal(config.get("apis")) def readConfig(): result = {} with open("config.json", "r+") as f: result = json.loads(f.read()) return result <<<<<<< HEAD ======= # 备份数据库,判断目标文件夹下是否有.db文件,有的话,先备份到临时目录,待文件复制完成后,再放回原来位置 def backup_database(): global output_dir target_dir = os.sep.join([os.path.dirname(output_dir), "tmp"]) if not os.path.exists(target_dir): os.makedirs(target_dir) home_fs = fs.open_fs(output_dir) for file in home_fs.glob('*.db', namespaces=['details']): # print(file.path, os.path.normpath(os.sep.join([output_dir, file.path]))) # copyFiles(os.path.normpath(os.sep.join([output_dir, file.path])), target_dir) shutil.copy(os.path.normpath(os.sep.join([output_dir, file.path])), target_dir) # 恢复数据库,代码生成完成后,需要把之前复制的数据库文件,恢复到原来位置 def restore_database(): global output_dir target_dir = os.sep.join([os.path.dirname(output_dir), "tmp"]) if not os.path.exists(target_dir): return home_fs = fs.open_fs(target_dir) for file in home_fs.glob('*.db', namespaces=['details']): # copyFiles(os.path.normpath(os.sep.join([target_dir, file.path])), output_dir) shutil.copy(os.path.normpath(os.sep.join([target_dir, file.path])), output_dir) home_fs = fs.open_fs(target_dir) home_fs.removetree("/") if home_fs.exists("/"): os.removedirs(target_dir) >>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca def run(): global input_dir global output_dir input_dir = os.sep.join([os.getcwd(), "resources"]) output_dir = os.sep.join([os.getcwd(), "build_out"]) <<<<<<< HEAD copyFiles(input_dir, output_dir) config = readConfig() # print(config) parseConfig(config) ======= backup_database() copyFiles(input_dir, output_dir) config = readConfig() parseConfig(config) restore_database() >>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca print("success ......") if __name__ == "__main__": run()