gen_code.py 9.16 KB
Newer Older
wanliofficial's avatar
wanliofficial committed
1
<<<<<<< HEAD
wanli's avatar
wanli committed
2 3
from fs.copy import copy_fs
from jinja2 import Environment, FileSystemLoader
wanli's avatar
wanli committed
4
import json
wanli's avatar
wanli committed
5 6
import os
import re
wanliofficial's avatar
wanliofficial committed
7
=======
8
from fs.copy import copy_fs, copy_file
9
from jinja2 import Environment, FileSystemLoader
10
import fs
wanli's avatar
wanli committed
11
import json
12 13
import os
import re
wanli's avatar
wanli committed
14 15
import hashlib
import time
16
import shutil
wanliofficial's avatar
wanliofficial committed
17
>>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca
wanli's avatar
wanli committed
18

wanli's avatar
wanli committed
19 20 21 22 23 24
'''
流程:
一、将resources里面所有文件夹拷贝到当前目录下
二、解析json配置文件,遍历每一项生成/model/view/controller
三、自动运行项目
'''
wanli's avatar
wanli committed
25

wanliofficial's avatar
wanliofficial committed
26
<<<<<<< HEAD
wanli's avatar
wanli committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
# 将字符串首字母转换成大写字母
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)
wanli's avatar
wanli committed
56

wanliofficial's avatar
wanliofficial committed
57
=======
wanli's avatar
wanli committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
# 比较两个文件内容是否相同,这里没有使用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()

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
# 将字符串首字母转换成大写字母
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)
wanli's avatar
wanli committed
118

wanliofficial's avatar
wanliofficial committed
119
>>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca
wanli's avatar
wanli committed
120
def handleModel(config, application):
wanli's avatar
wanli committed
121 122
    # 将所有有默认值的字段分为一组,没有默认值的字段分为另一组
    # 生成模板代码时,无默认值的字段在前,有默认值的字段字在后
wanli's avatar
wanli committed
123 124 125 126 127 128 129
    # 收集表字段信息
    fields = []
    extend = False
    for m in config.get("model").get("fields"):
        fields.append(m.get("name"))
        extend = True
        print(m)
wanliofficial's avatar
wanliofficial committed
130 131 132 133 134 135
<<<<<<< HEAD

    target_file = os.sep.join(["models", "{}.py".format(config.get("name"))])
    handleRender(config, 'model.tpl', target_file, fields=fields, extend=extend, application=application)

=======
wanli's avatar
wanli committed
136

wanli's avatar
wanli committed
137 138
    target_file = os.sep.join(["models", "{}.py".format(config.get("name"))])
    handleRender(config, 'model.tpl', target_file, fields=fields, extend=extend, application=application)
wanli's avatar
wanli committed
139 140 141 142 143
    # 多次复制时,会报文件已存在错误,因此要先删除
    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)
wanli's avatar
wanli committed
144

wanliofficial's avatar
wanliofficial committed
145
>>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca
wanli's avatar
wanli committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
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)
wanliofficial's avatar
wanliofficial committed
161 162
<<<<<<< HEAD
=======
wanli's avatar
wanli committed
163

wanliofficial's avatar
wanliofficial committed
164
>>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca
wanli's avatar
wanli committed
165 166 167 168
    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))
    
wanliofficial's avatar
wanliofficial committed
169 170 171 172 173
<<<<<<< HEAD
    with open(target_file, 'w', encoding='utf-8') as f:
        f.write(content)

=======
wanli's avatar
wanli committed
174 175 176 177 178 179 180 181 182 183 184
    # 这里需要比较目标文件夹是否已经存在同名文件,如果存在,则需要比较两个文件内容是否一致
    # 如果不一致时,则需要给旧的文件打上时间戳,作为备份文件

    # 具体流程:
    # 先将原来文件重命名,然后新的内容写入到重命名的文件中
    # 最后比较两个文件内容是否一致,如果一致,则删除重命名的那个旧的备份文件

    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)
wanli's avatar
wanli committed
185 186
        if os.path.exists(tmp_file):
            os.remove(tmp_file)
wanli's avatar
wanli committed
187 188
        os.rename(target_file, tmp_file)

wanli's avatar
wanli committed
189 190 191
    with open(target_file, 'w', encoding='utf-8') as f:
        f.write(content)

wanli's avatar
wanli committed
192 193 194
    if cmp_file(tmp_file, target_file) == True:
        os.remove(tmp_file)

wanliofficial's avatar
wanliofficial committed
195
>>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca
wanli's avatar
wanli committed
196 197 198 199 200 201 202 203
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"))
wanli's avatar
wanli committed
204 205 206 207 208 209 210

def readConfig():
    result = {}
    with open("config.json", "r+") as f:
        result = json.loads(f.read())
    return result

wanliofficial's avatar
wanliofficial committed
211 212
<<<<<<< HEAD
=======
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
# 备份数据库,判断目标文件夹下是否有.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)

wanliofficial's avatar
wanliofficial committed
243
>>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca
wanli's avatar
wanli committed
244 245 246 247 248
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"])
wanliofficial's avatar
wanliofficial committed
249
<<<<<<< HEAD
wanli's avatar
wanli committed
250 251 252 253
    copyFiles(input_dir, output_dir)
    config = readConfig()
    # print(config)
    parseConfig(config)
wanliofficial's avatar
wanliofficial committed
254
=======
255
    backup_database()
256 257 258
    copyFiles(input_dir, output_dir)
    config = readConfig()
    parseConfig(config)
259
    restore_database()
wanliofficial's avatar
wanliofficial committed
260
>>>>>>> 735d39eb4d0c3134b62bf4fe1b7a2ca0ea8da1ca
wanli's avatar
wanli committed
261 262
    print("success ......")

wanli's avatar
wanli committed
263
if __name__ == "__main__":
wanli's avatar
wanli committed
264
    run()