#!/usr/bin/env python3 # -*- coding: utf-8 -*- r""" 补齐 `restore_p1.py` 恢复不到的那 16 个文件。 它们不是用 Write 工具写的,因此不在会话 jsonl 的 Write/Edit 记录里: * 12 个 Mapper 接口 —— 是当时用一句 bash 函数 `gen()` + heredoc 批量生成的 * 4 个 apibase 常量/POJO —— 是 `sed` 从老 `zteits-api` 复制改包名生成的 两种生成方式都是确定性的,本脚本按当时**一模一样**的规则重算: * Mapper:模板取自会话里那条 `gen()` 命令,`OrgMapper.java`(它是用 Write 写的、已被 restore_p1.py 恢复)用来交叉验证模板的最终形态(含当时补的 `sed '/^\*$/d'` 去掉多余星号行)。 * apibase:直接重放当时那条 `sed -e 's/com.zteits.clouds.api.apibase/…/g'`。 输出写到 tools/recover/out/,与其他恢复产物合并后再一起拷回源码树。 """ import os import re CLOUD = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) LEGACY = os.path.join(os.path.dirname(CLOUD), "zteits-clouds") STAGE = os.path.join(CLOUD, "tools/recover/out") SYS = "parking-module-system/src/main/java/com/zteits/parking/module/system" API = "parking-module-api/src/main/java/com/zteits/parking/module/api/apibase" # (包/DO 所在子包, 类名前缀, 中文描述, extra) —— 顺序与当时 gen() 的调用完全一致 # extra 是当时生成器的第 4 个参数,三个关联表被传成了 "*" / "'*'", # 落进 javadoc 就是一行多余的星号,随后由那条 `sed '/^\*$/d'` 删掉。 # 这里如实保留 extra,再在下面用等价的 sed 逻辑清掉,才能和当时的最终文件逐字节一致 # (extra 非空的那三个**没有**空行,extra 为空的那些有——这个差异肉眼看不出来, # 但对"恢复"来说必须还原)。 MAPPERS = [ ("user", "User", "用户", ""), ("permission", "Role", "角色", ""), ("permission", "Menu", "菜单", "*"), ("permission", "UserRole", "用户和角色的关联", "'*'"), ("permission", "RoleMenu", "角色和菜单的关联", "'*'"), ("dict", "DictType", "字典类型", ""), ("dict", "DictData", "字典数据", ""), ("oauth2", "OAuth2AccessToken", "OAuth2 访问令牌", ""), ("oauth2", "OAuth2RefreshToken", "OAuth2 刷新令牌", ""), ("oauth2", "OAuth2Client", "OAuth2 客户端", ""), ("logger", "LoginLog", "登录日志", ""), ("logger", "OperateLog", "操作日志", ""), ] MAPPER_TPL = """package com.zteits.parking.module.system.dal.mysql.{sub}; import com.zteits.parking.framework.mybatis.core.mapper.BaseMapperX; import com.zteits.parking.module.system.dal.dataobject.{sub}.{name}DO; import org.apache.ibatis.annotations.Mapper; /** * {desc} Mapper * * ⚠️ 每个 Mapper **必须**带 {{@link Mapper}} 注解: * `ParkingMybatisAutoConfiguration` 用的是 * `@MapperScan(value = "${{parking.info.base-package}}", annotationClass = Mapper.class)`, * 漏写注解不会被扫描到,报 "Invalid bound statement (not found)"。 {extra} * @author ZIEITS */ @Mapper public interface {name}Mapper extends BaseMapperX<{name}DO> {{ }} """ def drop_star_lines(text): """等价于当时的 `sed -e '/^\\*$/d' -e "/^'\\*'$/d"`:删掉整行只有 * 或 '*' 的行。""" return "".join( ln for ln in text.splitlines(keepends=True) if ln.rstrip("\n") not in ("*", "'*'") ) # sed 的目标:apibase 包名整体改名 APIBASE_FILES = [ "bean/BizResult.java", "bean/ResultBean.java", "bean/ErrorCode.java", "constants/ErrorType.java", ] OLD_PKG = "com.zteits.clouds.api.apibase" NEW_PKG = "com.zteits.parking.module.api.apibase" def write(rel, text): dst = os.path.join(STAGE, rel) os.makedirs(os.path.dirname(dst), exist_ok=True) # 保持与当时一致的 LF 结尾 + 文件末尾换行 with open(dst, "w", encoding="utf-8", newline="\n") as f: f.write(text) def main(): for sub, name, desc, extra in MAPPERS: text = MAPPER_TPL.format(sub=sub, name=name, desc=desc, extra=extra) write(f"{SYS}/dal/mysql/{sub}/{name}Mapper.java", drop_star_lines(text)) print(f"✔ 生成 {len(MAPPERS)} 个 Mapper 接口") # apibase:老源码存在才做,否则明确报错而不是产出空文件 src_root = os.path.join(LEGACY, "zteits-api/src/main/java/com/zteits/clouds/api/apibase") if not os.path.isdir(src_root): raise SystemExit(f"!! 老 apibase 目录不存在:{src_root}") for rel in APIBASE_FILES: src = os.path.join(src_root, rel) if not os.path.isfile(src): raise SystemExit(f"!! 老文件不存在:{src}") with open(src, encoding="utf-8", errors="surrogateescape") as f: text = f.read() text = text.replace(OLD_PKG, NEW_PKG) write(f"{API}/{rel}", text) print(f"✔ 由 {OLD_PKG} 重放改名生成 {len(APIBASE_FILES)} 个 apibase 文件") # 自检:新包名生效、老包名无残留 bad = [] for rel in APIBASE_FILES: text = open(os.path.join(STAGE, f"{API}/{rel}"), encoding="utf-8").read() if OLD_PKG in text: bad.append(rel) if rel == "constants/ErrorType.java": # 与当时那条 `grep -c '^ [A-Z_0-9]*('` 等价,用来对齐历史计数 142 n = sum(1 for ln in text.splitlines() if re.match(r"^ [A-Z_0-9]*\(", ln)) print(f" ErrorType 枚举值:{n}(当时记录为 142)") if bad: raise SystemExit(f"!! 仍有老包名残留:{bad}") if __name__ == "__main__": main()