diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..27b5685 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,20 @@ +# Git属性配置 +*.md text eol=lf +*.sh text eol=lf +*.py text eol=lf + +# 二进制文件 +*.pdf binary +*.doc binary +*.docx binary +*.zip binary +*.png binary +*.jpg binary + +# 自动检测换行符 +* text=auto + +# 排除文件 +.gitignore export-ignore +.gitattributes export-ignore +README.md export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae8b541 --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +# 临时文件 +*.tmp +*.log +*.bak +*.swp +*.swo + +# 系统文件 +.DS_Store +Thumbs.db +desktop.ini + +# 编辑器文件 +.vscode/ +.idea/ +*.code-workspace + +# 环境配置 +.env +.env.local +.env.development +.env.production +*.key +*.pem +*.cert + +# 依赖文件 +node_modules/ +__pycache__/ +*.pyc +*.pyo + +# 构建输出 +dist/ +build/ +target/ +*.exe +*.dll + +# 日志文件 +logs/ +*.log + +# 备份文件 +*.backup +*.old +*~ + +# 大文件 +*.zip +*.rar +*.7z +*.tar.gz + +# 数据文件 +*.db +*.sqlite +*.sqlite3 + +# 小说项目特定 +backups/ +temp/ +drafts/ \ No newline at end of file diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..ecb2e5b --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,355 @@ +# 《末日重生》项目定时同步系统安装指南 + +## 🎯 系统概述 + +为《末日重生-开局囤货十亿物资》项目提供完整的Git版本管理和定时同步系统,包含: + +- 🔄 **自动提交**:检测更改并自动提交 +- 🏷️ **版本标签**:自动创建语义化版本标签 +- 📦 **定时备份**:按计划备份项目数据 +- 📊 **状态报告**:生成详细的项目状态报告 +- ⏰ **Cron定时任务**:自动执行所有任务 +- 📈 **健康监控**:监控系统运行状态 + +## 📁 已创建的文件结构 + +``` +末日重生_囤货/ +├── .gitattributes # Git文件属性配置 +├── .gitignore # Git忽略文件配置 +├── tools/ +│ ├── git_version_manager.sh # Git版本管理主脚本 +│ └── schedule_manager.py # 定时任务管理系统 +├── config/ +│ └── cron_schedule.json # 定时任务配置 +├── backups/ # 备份文件存储 +├── logs/ # 系统日志文件 +├── progress/ # 进度报告文件 +└── INSTALL.md # 本安装指南 +``` + +## 🚀 快速安装 + +### 方法一:一键安装(推荐) + +```bash +cd /root/.openclaw/workspace/projects/末日重生_囤货 + +# 1. 测试系统健康 +./tools/schedule_manager.py health + +# 2. 安装Cron定时任务 +./tools/schedule_manager.py install + +# 3. 显示系统仪表板 +./tools/schedule_manager.py dashboard +``` + +### 方法二:手动安装 + +```bash +# 1. 设置脚本权限 +chmod +x tools/git_version_manager.sh +chmod +x tools/schedule_manager.py + +# 2. 创建必要的目录 +mkdir -p backups logs progress + +# 3. 测试Git版本管理 +./tools/git_version_manager.sh status + +# 4. 手动创建Cron任务 +echo "*/30 * * * * cd $(pwd) && ./tools/git_version_manager.sh commit" | crontab - +``` + +## 🔧 配置说明 + +### 定时任务配置(config/cron_schedule.json) + +```json +{ + "定时同步配置": { + "自动提交": { + "启用": true, + "间隔": "30分钟" + }, + "版本标签": { + "启用": true, + "触发条件": "每10次提交自动创建标签" + }, + "远程同步": { + "启用": true, + "间隔": "1小时" + }, + "自动备份": { + "启用": true, + "时间": "每日凌晨3点" + } + } +} +``` + +### Git版本管理配置 + +系统会自动跟踪: +- 章节数量变化 +- 字数统计 +- 提交历史 +- 版本标签 +- 同步状态 + +## 📊 系统功能 + +### 1. 自动提交(每30分钟) +- 检测未提交的更改 +- 自动添加所有更改 +- 生成包含时间戳的提交信息 +- 自动提交到本地仓库 + +### 2. 版本标签管理 +- 每10次提交自动创建新版本 +- 语义化版本号(v1.0.0格式) +- 包含章节和字数信息的标签描述 +- 标签同步到远程仓库 + +### 3. 定时备份(每天凌晨3点) +- **完整备份**:包含所有项目文件 +- **章节备份**:仅备份章节内容 +- **Git包备份**:可移植的Git仓库 +- **自动清理**:保留7天内的备份 + +### 4. 状态报告(每天凌晨1点) +- 章节统计和字数统计 +- Git提交历史和版本信息 +- 番茄平台适配情况 +- 系统健康状态检查 + +### 5. 远程同步(每1小时) +- 自动拉取远程最新更改 +- 推送本地提交到Gitea +- 同步版本标签 +- 失败重试机制 + +## 🖥️ 使用方法 + +### 命令行工具 + +```bash +# 1. 显示系统仪表板 +./tools/schedule_manager.py dashboard + +# 2. 执行自动提交 +./tools/git_version_manager.sh commit + +# 3. 创建版本标签 +./tools/git_version_manager.sh tag + +# 4. 同步到远程仓库 +./tools/git_version_manager.sh sync + +# 5. 创建备份 +./tools/schedule_manager.py backup --type full + +# 6. 生成状态报告 +./tools/git_version_manager.sh report + +# 7. 检查系统健康 +./tools/schedule_manager.py health + +# 8. 显示交互式菜单 +./tools/git_version_manager.sh menu +``` + +### 一键全流程 + +```bash +# 执行完整的版本管理流程 +./tools/git_version_manager.sh workflow +``` + +这将依次执行: +1. 检查Git状态 +2. 自动提交更改 +3. 创建版本标签(如果需要) +4. 同步到远程仓库 +5. 生成状态报告 + +## 📋 定时任务列表 + +安装后系统会自动配置以下定时任务: + +| 任务 | 时间 | 描述 | +|------|------|------| +| 自动提交 | 每30分钟 | 检测并提交未提交的更改 | +| 状态报告 | 每天01:00 | 生成项目状态报告 | +| 项目备份 | 每天03:00 | 创建项目备份文件 | +| 健康检查 | 每小时 | 检查系统健康状态 | + +## 🛠️ 维护和管理 + +### 查看Cron任务 + +```bash +crontab -l +``` + +### 查看系统日志 + +```bash +# 查看Git版本管理日志 +tail -f logs/git_version.log + +# 查看定时任务日志 +tail -f /tmp/末日重生_*.log + +# 查看备份目录 +ls -la backups/ +``` + +### 手动执行任务 + +```bash +# 手动触发自动提交 +./tools/git_version_manager.sh commit + +# 手动创建备份 +./tools/schedule_manager.py backup + +# 手动生成报告 +./tools/git_version_manager.sh report +``` + +## 🔍 监控和告警 + +### 系统健康检查 + +系统会自动监控: +- ✅ Git仓库状态 +- ✅ 磁盘空间使用 +- ✅ 项目目录完整性 +- ✅ 网络连接状态 +- ✅ 任务执行状态 + +### 日志文件位置 + +``` +末日重生_囤货/logs/ +├── git_version.log # Git版本管理日志 +├── schedule_YYYYMM.log # 定时任务日志 +└── monitor_YYYYMMDD.json # 监控数据 + +/tmp/ +├── 末日重生_自动提交.log # 自动提交日志 +├── 末日重生_报告生成.log # 报告生成日志 +├── 末日重生_备份.log # 备份任务日志 +└── 末日重生_健康检查.log # 健康检查日志 +``` + +## 🚨 故障排除 + +### 常见问题 + +1. **Cron任务未执行** + ```bash + # 检查Cron服务状态 + systemctl status cron + + # 重新安装Cron任务 + ./tools/schedule_manager.py install + ``` + +2. **Git同步失败** + ```bash + # 检查网络连接 + ping gitea.nevadalice.top:226 + + # 手动同步 + ./tools/git_version_manager.sh sync --force + ``` + +3. **备份失败** + ```bash + # 检查磁盘空间 + df -h + + # 手动创建备份 + ./tools/schedule_manager.py backup --type chapters + ``` + +### 日志分析 + +```bash +# 查看错误日志 +grep -i "error\|fatal\|failed" logs/git_version.log + +# 查看最近活动 +tail -100 /tmp/末日重生_自动提交.log + +# 检查任务执行时间 +grep "开始\|完成\|成功\|失败" logs/git_version.log | tail -20 +``` + +## 📞 技术支持 + +### 紧急恢复 + +1. **恢复最新备份** + ```bash + # 找到最新的备份文件 + ls -t backups/*.tar.gz | head -1 + + # 恢复备份 + tar -xzf 最新备份文件.tar.gz -C 目标目录 + ``` + +2. **重新初始化系统** + ```bash + # 移除现有配置 + crontab -r + + # 重新安装 + ./tools/schedule_manager.py install + ``` + +### 联系信息 + +- **项目名称**:《末日重生-开局囤货十亿物资》 +- **作者**:唐天洛 +- **Gitea仓库**:https://gitea.nevadalice.top:226/liyuchen/novel-doomsday-resurgence +- **创建时间**:2026年3月30日 + +## 🎉 安装完成 + +系统已成功安装!你现在拥有: + +1. ✅ **自动版本管理**:每30分钟自动提交更改 +2. ✅ **定时备份**:每天凌晨3点自动备份 +3. ✅ **状态报告**:每天凌晨1点生成报告 +4. ✅ **远程同步**:自动同步到Gitea仓库 +5. ✅ **健康监控**:系统健康状态实时监控 + +### 下一步建议 + +1. **立即测试系统** + ```bash + ./tools/git_version_manager.sh workflow + ``` + +2. **查看系统状态** + ```bash + ./tools/schedule_manager.py dashboard + ``` + +3. **开始创作** + - 在 `chapters/` 目录下继续写第25章 + - 系统会自动跟踪和备份你的创作 + - 定期查看状态报告了解进度 + +4. **监控维护** + - 定期检查系统日志 + - 确保备份文件正常创建 + - 关注番茄平台更新要求 + +--- + +**系统状态**:✅ 安装完成 | **版本**:v1.0.0 | **最后更新**:2026-03-30 \ No newline at end of file diff --git a/chapters/test_chapter.md b/chapters/test_chapter.md new file mode 100644 index 0000000..d6c4ed3 --- /dev/null +++ b/chapters/test_chapter.md @@ -0,0 +1,3 @@ +# 测试章节 2026-03-30 13:07:45 +这是一个测试章节,用于验证定时同步系统。 +系统应该能自动检测并提交这个更改。 diff --git a/config/cron_schedule.json b/config/cron_schedule.json new file mode 100644 index 0000000..804ef81 --- /dev/null +++ b/config/cron_schedule.json @@ -0,0 +1,117 @@ +{ + "定时同步配置": { + "自动提交": { + "启用": true, + "间隔": "30分钟", + "条件": "检测到未提交的更改", + "提交信息模板": "定时更新: {date} {time}" + }, + "版本标签": { + "启用": true, + "触发条件": "每10次提交自动创建标签", + "标签格式": "v{大版本}.{中版本}.{小版本}", + "里程碑章节": [5, 10, 20, 50, 100] + }, + "远程同步": { + "启用": true, + "间隔": "1小时", + "重试次数": 3, + "重试间隔": "5分钟", + "强制推送": false + }, + "自动备份": { + "启用": true, + "类型": ["章节备份", "Git包备份"], + "时间": "每日凌晨3点", + "保留天数": 7, + "存储位置": "项目目录/backups/" + }, + "状态报告": { + "启用": true, + "生成时间": "每日凌晨1点", + "报告内容": ["章节统计", "字数统计", "版本信息", "健康检查"], + "存储位置": "项目目录/progress/status_report_YYYYMMDD.md" + }, + "通知提醒": { + "启用": false, + "方式": "日志文件", + "成功通知": true, + "失败通知": true, + "日志路径": "项目目录/logs/git_version.log" + } + }, + "番茄平台适配": { + "字数检查": { + "启用": true, + "标准字数": 2500, + "最小字数": 2000, + "最大字数": 3500, + "预警阈值": 80 + }, + "更新频率": { + "日更目标": 4000, + "章节目标": 1, + "提醒时间": "每日20:00", + "进度跟踪": true + }, + "听书优化": { + "对话占比检查": true, + "最小占比": 30, + "段落长度检查": true, + "最大段落行数": 5 + } + }, + "Git工作流": { + "分支策略": { + "主分支": "master", + "开发分支": "develop", + "功能分支": "feature/*", + "发布分支": "release/*", + "修复分支": "hotfix/*" + }, + "提交规范": { + "类型": ["feat", "fix", "docs", "style", "refactor", "test", "chore"], + "范围": ["chapters", "outlines", "assets", "tools", "config"], + "描述": "简洁描述更改内容", + "正文": "详细说明更改原因和影响", + "脚注": "关联Issue或任务" + }, + "标签策略": { + "版本格式": "语义化版本 (SemVer)", + "预发布标签": "alpha, beta, rc", + "构建元数据": "build metadata", + "里程碑标签": "milestone-*" + } + }, + "监控告警": { + "磁盘空间": { + "启用": true, + "阈值": "90%", + "检查间隔": "每日" + }, + "网络连接": { + "启用": true, + "检查地址": "gitea.nevadalice.top:226", + "超时时间": 10 + }, + "任务执行": { + "启用": true, + "超时时间": 300, + "重试机制": true, + "失败通知": true + }, + "性能监控": { + "启用": false, + "内存监控": true, + "CPU监控": true, + "磁盘IO监控": false + } + }, + "配置说明": { + "最后更新": "2026-03-30", + "配置版本": "1.0.0", + "适用项目": "《末日重生-开局囤货十亿物资》", + "作者": "唐天洛", + "备注": "定时同步系统配置,如需修改请谨慎操作" + } +} \ No newline at end of file diff --git a/config/version_config.json b/config/version_config.json new file mode 100644 index 0000000..fc560b1 --- /dev/null +++ b/config/version_config.json @@ -0,0 +1,16 @@ +{ + "auto_commit": true, + "commit_pattern": "更新: {date} {time}", + "commit_threshold": 3, + "auto_tag": true, + "tag_pattern": "v{version}", + "tag_milestones": [5, 10, 20, 50, 100], + "sync_enabled": true, + "sync_schedule": "*/30 * * * *", + "backup_enabled": true, + "backup_retention": 7, + "notifications": { + "on_success": true, + "on_failure": true + } +} diff --git a/tools/git_version_manager.sh b/tools/git_version_manager.sh new file mode 100755 index 0000000..98c8995 --- /dev/null +++ b/tools/git_version_manager.sh @@ -0,0 +1,626 @@ +#!/bin/bash +# 《末日重生》项目Git版本管理脚本 +# 提供自动提交、版本标签、定时同步功能 + +PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +LOG_FILE="$PROJECT_DIR/logs/git_version.log" +CONFIG_FILE="$PROJECT_DIR/config/version_config.json" + +# 颜色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 初始化日志和配置 +init() { + mkdir -p "$(dirname "$LOG_FILE")" + mkdir -p "$(dirname "$CONFIG_FILE")" + + if [ ! -f "$CONFIG_FILE" ]; then + cat > "$CONFIG_FILE" << EOF +{ + "auto_commit": true, + "commit_pattern": "更新: {date} {time}", + "commit_threshold": 3, + "auto_tag": true, + "tag_pattern": "v{version}", + "tag_milestones": [5, 10, 20, 50, 100], + "sync_enabled": true, + "sync_schedule": "*/30 * * * *", + "backup_enabled": true, + "backup_retention": 7, + "notifications": { + "on_success": true, + "on_failure": true + } +} +EOF + fi +} + +# 日志函数 +log() { + local level="$1" + local message="$2" + local timestamp=$(date '+%Y-%m-%d %H:%M:%S') + + case $level in + "INFO") color=$GREEN ;; + "WARN") color=$YELLOW ;; + "ERROR") color=$RED ;; + *) color=$NC ;; + esac + + echo -e "${color}[$timestamp] [$level] $message${NC}" + echo "[$timestamp] [$level] $message" >> "$LOG_FILE" +} + +# 检查Git状态 +check_git_status() { + log "INFO" "检查Git状态..." + + cd "$PROJECT_DIR" + + # 检查是否有未提交的更改 + if [ -n "$(git status --porcelain)" ]; then + changed_files=$(git status --porcelain | wc -l) + log "INFO" "检测到 $changed_files 个未提交的文件" + + # 显示更改摘要 + echo "📝 更改摘要:" + git status --short + echo "" + + return 0 # 有更改 + else + log "INFO" "没有未提交的更改" + return 1 # 没有更改 + fi +} + +# 自动提交更改 +auto_commit() { + local message="$1" + + if [ -z "$message" ]; then + local current_date=$(date '+%Y年%m月%d日') + local current_time=$(date '+%H:%M:%S') + message="更新: $current_date $current_time" + fi + + log "INFO" "自动提交更改: $message" + + cd "$PROJECT_DIR" + + # 添加所有更改 + git add . + + # 提交 + if git commit -m "$message" > /dev/null 2>&1; then + local commit_hash=$(git rev-parse --short HEAD) + log "INFO" "✅ 提交成功 (commit: $commit_hash)" + echo "提交信息: $message" + echo "提交哈希: $commit_hash" + return 0 + else + log "ERROR" "❌ 提交失败" + return 1 + fi +} + +# 创建版本标签 +create_version_tag() { + local tag_name="$1" + local tag_message="$2" + + if [ -z "$tag_name" ]; then + # 自动生成标签名 + local current_version=$(git tag | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1) + + if [ -z "$current_version" ]; then + current_version="v0.0.0" + fi + + # 递增版本号 + local major=$(echo "$current_version" | cut -d. -f1 | tr -d 'v') + local minor=$(echo "$current_version" | cut -d. -f2) + local patch=$(echo "$current_version" | cut -d. -f3) + + patch=$((patch + 1)) + + # 每10个小版本升级一个中版本 + if [ $patch -ge 10 ]; then + patch=0 + minor=$((minor + 1)) + fi + + # 每10个中版本升级一个大版本 + if [ $minor -ge 10 ]; then + minor=0 + major=$((major + 1)) + fi + + tag_name="v${major}.${minor}.${patch}" + fi + + if [ -z "$tag_message" ]; then + local chapter_count=$(find "$PROJECT_DIR/chapters" -name "*.md" | wc -l) + local total_words=0 + + for chapter in "$PROJECT_DIR/chapters"/*.md; do + if [ -f "$chapter" ]; then + words=$(wc -w < "$chapter" 2>/dev/null || echo 0) + total_words=$((total_words + words)) + fi + done + + tag_message="版本 ${tag_name} | 章节: ${chapter_count}章 | 字数: ${total_words}字" + fi + + log "INFO" "创建版本标签: $tag_name" + + if git tag -a "$tag_name" -m "$tag_message" > /dev/null 2>&1; then + log "INFO" "✅ 标签创建成功: $tag_name" + echo "标签名称: $tag_name" + echo "标签描述: $tag_message" + return 0 + else + log "ERROR" "❌ 标签创建失败" + return 1 + fi +} + +# 同步到远程仓库 +sync_to_remote() { + local force="$1" + + log "INFO" "同步到远程仓库..." + + cd "$PROJECT_DIR" + + # 检查远程仓库 + if ! git remote get-url origin > /dev/null 2>&1; then + log "ERROR" "❌ 未配置远程仓库" + return 1 + fi + + # 获取远程仓库信息 + local remote_url=$(git remote get-url origin) + log "INFO" "远程仓库: $(echo $remote_url | sed 's|https://.*@||')" + + # 拉取最新更改 + log "INFO" "拉取远程更改..." + if ! git pull --rebase origin master 2>&1 | grep -q "Already up to date"; then + log "INFO" "✅ 已更新本地仓库" + fi + + # 推送更改 + log "INFO" "推送到远程仓库..." + if [ "$force" = "true" ]; then + if git push origin master --tags --force 2>&1; then + log "INFO" "✅ 强制推送成功" + else + log "ERROR" "❌ 推送失败" + return 1 + fi + else + if git push origin master --tags 2>&1; then + log "INFO" "✅ 推送成功" + else + log "WARN" "⚠️ 推送失败,尝试强制推送..." + if git push origin master --tags --force 2>&1; then + log "INFO" "✅ 强制推送成功" + else + log "ERROR" "❌ 强制推送失败" + return 1 + fi + fi + fi + + # 显示同步结果 + local current_branch=$(git branch --show-current) + local latest_commit=$(git log -1 --format="%h - %s" 2>/dev/null) + local tag_count=$(git tag | wc -l) + + echo "" + echo "📊 同步完成报告" + echo "├─ 分支: $current_branch" + echo "├─ 最新提交: $latest_commit" + echo "├─ 版本标签: $tag_count 个" + echo "└─ 远程仓库: $(echo $remote_url | sed 's|https://.*@||')" + + return 0 +} + +# 自动备份 +create_backup() { + local backup_type="$1" + + log "INFO" "创建项目备份..." + + local backup_dir="$PROJECT_DIR/backups" + local timestamp=$(date '+%Y%m%d_%H%M%S') + + mkdir -p "$backup_dir" + + case $backup_type in + "full") + # 完整备份 + local backup_file="$backup_dir/full_backup_$timestamp.tar.gz" + tar -czf "$backup_file" -C "$PROJECT_DIR" . + log "INFO" "✅ 完整备份创建: $(basename $backup_file)" + ;; + "git") + # Git包备份 + local backup_file="$backup_dir/git_bundle_$timestamp.bundle" + git bundle create "$backup_file" --all + log "INFO" "✅ Git包备份创建: $(basename $backup_file)" + ;; + "chapters") + # 章节备份 + local backup_file="$backup_dir/chapters_$timestamp.tar.gz" + tar -czf "$backup_file" -C "$PROJECT_DIR" chapters/ + log "INFO" "✅ 章节备份创建: $(basename $backup_file)" + ;; + *) + # 默认备份 + local backup_file="$backup_dir/backup_$timestamp.tar.gz" + tar -czf "$backup_file" -C "$PROJECT_DIR" chapters/ outlines/ assets/ + log "INFO" "✅ 默认备份创建: $(basename $backup_file)" + ;; + esac + + # 清理旧备份 + local retention_days=7 + find "$backup_dir" -name "*.tar.gz" -mtime +$retention_days -delete 2>/dev/null + find "$backup_dir" -name "*.bundle" -mtime +$retention_days -delete 2>/dev/null + + echo "备份文件: $backup_file" + echo "备份大小: $(du -h "$backup_file" | cut -f1)" + + return 0 +} + +# 项目状态报告 +generate_status_report() { + log "INFO" "生成项目状态报告..." + + cd "$PROJECT_DIR" + + local report_file="$PROJECT_DIR/progress/status_report_$(date '+%Y%m%d').md" + mkdir -p "$(dirname "$report_file")" + + # 收集数据 + local chapter_count=$(find chapters -name "*.md" | wc -l) + local total_words=0 + local latest_chapter="" + local latest_chapter_time="" + + for chapter in chapters/*.md; do + if [ -f "$chapter" ]; then + words=$(wc -w < "$chapter" 2>/dev/null || echo 0) + total_words=$((total_words + words)) + + # 找到最新章节 + chapter_time=$(stat -c %Y "$chapter" 2>/dev/null || echo 0) + if [ -z "$latest_chapter_time" ] || [ $chapter_time -gt $latest_chapter_time ]; then + latest_chapter_time=$chapter_time + latest_chapter=$(basename "$chapter" .md) + fi + fi + done + + local commit_count=$(git rev-list --count HEAD 2>/dev/null || echo 0) + local latest_commit=$(git log -1 --format="%h - %s (%ad)" --date=short 2>/dev/null || echo "无") + local tag_count=$(git tag | wc -l) + local latest_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "无") + + # 生成报告 + cat > "$report_file" << EOF +# 《末日重生》项目状态报告 + +## 报告时间 +$(date '+%Y年%m月%d日 %H:%M:%S') + +## 创作进度 +- **总章节**: ${chapter_count} 章 +- **总字数**: ${total_words} 字 +- **最新章节**: ${latest_chapter} +- **平均每章字数**: $((total_words / chapter_count)) 字 + +## 版本管理 +- **提交次数**: ${commit_count} 次 +- **最新提交**: ${latest_commit} +- **版本标签**: ${tag_count} 个 +- **最新版本**: ${latest_tag} + +## 番茄平台适配 +### 字数要求 +- 标准章节字数: 2500-3500字 +- 当前平均: $((total_words / chapter_count)) 字 +- 状态: $(if [ $((total_words / chapter_count)) -ge 2000 ] && [ $((total_words / chapter_count)) -le 3500 ]; then echo "✅ 符合标准"; else echo "⚠️ 需要调整"; fi) + +### 更新要求 +- 日更全勤要求: 4000字/天 +- 当前总字数: ${total_words} 字 +- 相当于: $((total_words / 4000)) 天的全勤更新量 + +## Git状态 +\`\`\`bash +$(git status --short 2>/dev/null || echo "无未提交更改") +\`\`\` + +## 下一步计划 +1. [ ] 继续创作第 $(($chapter_count + 1)) 章 +2. [ ] 检查并优化现有章节 +3. [ ] 更新项目大纲和设定 +4. [ ] 同步到远程仓库 + +## 健康检查 +- [$(if [ $chapter_count -gt 0 ]; then echo "x"; else echo " "; fi)] 章节文件正常 +- [$(if [ -d ".git" ]; then echo "x"; else echo " "; fi)] Git仓库正常 +- [$(if git remote get-url origin >/dev/null 2>&1; then echo "x"; else echo " "; fi)] 远程仓库配置 +- [$(if [ -f "$report_file" ]; then echo "x"; else echo " "; fi)] 报告生成正常 + +--- +*报告自动生成于 $(date '+%Y-%m-%d %H:%M:%S')* +EOF + + log "INFO" "✅ 状态报告生成: $(basename $report_file)" + echo "报告文件: $report_file" + + return 0 +} + +# 定时同步任务 +setup_cron_job() { + local schedule="$1" + + if [ -z "$schedule" ]; then + schedule="*/30 * * * *" # 每30分钟 + fi + + log "INFO" "设置定时同步任务: $schedule" + + # 创建定时任务脚本 + local cron_script="/tmp/末日重生_定时同步.sh" + + cat > "$cron_script" << 'CRON_EOF' +#!/bin/bash +# 《末日重生》定时同步脚本 + +PROJECT_DIR="/root/.openclaw/workspace/projects/末日重生_囤货" +LOG_FILE="/tmp/末日重生_同步日志.log" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE" +} + +log "INFO" "开始定时同步任务" + +cd "$PROJECT_DIR" + +# 检查是否有未提交的更改 +if [ -n "$(git status --porcelain)" ]; then + log "INFO" "检测到未提交的更改,自动提交..." + + # 自动提交 + commit_message="定时更新: $(date '+%Y年%m月%d日 %H:%M:%S')" + git add . + if git commit -m "$commit_message" >/dev/null 2>&1; then + commit_hash=$(git rev-parse --short HEAD) + log "INFO" "✅ 自动提交成功: $commit_hash" + else + log "ERROR" "❌ 自动提交失败" + fi +fi + +# 同步到远程 +log "INFO" "同步到远程仓库..." +if git pull --rebase origin master >/dev/null 2>&1 && git push origin master >/dev/null 2>&1; then + log "INFO" "✅ 同步成功" +else + log "WARN" "⚠️ 同步失败,下次重试" +fi + +# 创建每日备份(只在特定时间) +if [ "$(date '+%H')" = "03" ]; then # 凌晨3点 + log "INFO" "创建每日备份..." + tar -czf "/tmp/末日重生_备份_$(date '+%Y%m%d').tar.gz" -C "$PROJECT_DIR" . + log "INFO" "✅ 备份创建完成" +fi + +log "INFO" "定时同步任务完成" +CRON_EOF + + chmod +x "$cron_script" + + # 添加cron任务 + (crontab -l 2>/dev/null | grep -v "$cron_script"; echo "$schedule $cron_script") | crontab - + + log "INFO" "✅ 定时任务设置完成" + echo "定时任务: $schedule" + echo "任务脚本: $cron_script" + + return 0 +} + +# 主菜单 +show_menu() { + echo "" + echo "📚 《末日重生》项目版本管理系统" + echo "=================================" + echo "" + echo "1. 🔍 检查项目状态" + echo "2. 📝 自动提交更改" + echo "3. 🏷️ 创建版本标签" + echo "4. 🔄 同步到远程仓库" + echo "5. 💾 创建项目备份" + echo "6. 📊 生成状态报告" + echo "7. ⏰ 设置定时同步" + echo "8. 🚀 一键全流程" + echo "9. 📋 显示帮助" + echo "0. ❌ 退出" + echo "" + echo "=================================" +} + +# 一键全流程 +full_workflow() { + log "INFO" "开始一键全流程..." + + echo "🚀 执行一键全流程" + echo "----------------" + + # 1. 检查状态 + if check_git_status; then + echo "✅ 步骤1: 检查状态完成" + else + echo "ℹ️ 步骤1: 无未提交更改" + fi + + # 2. 自动提交 + if auto_commit "一键更新: $(date '+%Y年%m月%d日 %H:%M:%S')"; then + echo "✅ 步骤2: 自动提交完成" + else + echo "⚠️ 步骤2: 提交跳过" + fi + + # 3. 检查是否需要创建标签 + local commit_count=$(git rev-list --count HEAD 2>/dev/null || echo 0) + if [ $((commit_count % 10)) -eq 0 ]; then + if create_version_tag; then + echo "✅ 步骤3: 版本标签创建" + else + echo "⚠️ 步骤3: 标签跳过" + fi + fi + + # 4. 同步到远程 + if sync_to_remote; then + echo "✅ 步骤4: 远程同步完成" + else + echo "❌ 步骤4: 同步失败" + fi + + # 5. 生成报告 + if generate_status_report; then + echo "✅ 步骤5: 状态报告生成" + fi + + log "INFO" "一键全流程完成" + echo "🎉 全流程执行完毕!" +} + +# 显示帮助 +show_help() { + echo "" + echo "📖 《末日重生》Git版本管理工具使用说明" + echo "========================================" + echo "" + echo "主要功能:" + echo " 🔍 检查状态 - 检查Git状态和未提交更改" + echo " 📝 自动提交 - 自动提交所有更改到本地仓库" + echo " 🏷️ 版本标签 - 创建版本标签,记录重要里程碑" + echo " 🔄 远程同步 - 同步到Gitea远程仓库" + echo " 💾 项目备份 - 创建项目备份文件" + echo " 📊 状态报告 - 生成详细的项目状态报告" + echo " ⏰ 定时同步 - 设置定时自动同步任务" + echo " 🚀 一键流程 - 执行完整的版本管理流程" + echo "" + echo "使用方式:" + echo " ./git_version_manager.sh [选项]" + echo "" + echo "选项:" + echo " status 检查项目状态" + echo " commit 自动提交更改" + echo " tag 创建版本标签" + echo " sync 同步到远程" + echo " backup 创建备份" + echo " report 生成报告" + echo " cron 设置定时任务" + echo " workflow 执行一键流程" + echo " menu 显示交互菜单" + echo " help 显示帮助" + echo "" + echo "示例:" + echo " ./git_version_manager.sh status" + echo " ./git_version_manager.sh workflow" + echo " ./git_version_manager.sh menu" + echo "" +} + +# 主函数 +main() { + init + + case "$1" in + "status") + check_git_status + ;; + "commit") + auto_commit "$2" + ;; + "tag") + create_version_tag "$2" "$3" + ;; + "sync") + sync_to_remote "$2" + ;; + "backup") + create_backup "$2" + ;; + "report") + generate_status_report + ;; + "cron") + setup_cron_job "$2" + ;; + "workflow"|"auto") + full_workflow + ;; + "menu") + while true; do + show_menu + echo "请选择操作 (0-9): " + read choice + + case $choice in + 1) check_git_status ;; + 2) auto_commit ;; + 3) create_version_tag ;; + 4) sync_to_remote ;; + 5) create_backup ;; + 6) generate_status_report ;; + 7) setup_cron_job ;; + 8) full_workflow ;; + 9) show_help ;; + 0) + echo "再见!" + exit 0 + ;; + *) + echo "❌ 无效选择" + ;; + esac + + echo "" + echo "按回车键继续..." + read + done + ;; + "help"|"--help"|"-h") + show_help + ;; + *) + echo "使用: $0 [命令]" + echo "可用命令: status, commit, tag, sync, backup, report, cron, workflow, menu, help" + exit 1 + ;; + esac +} + +# 运行主函数 +main "$@" \ No newline at end of file diff --git a/tools/schedule_manager.py b/tools/schedule_manager.py new file mode 100755 index 0000000..b5ba6f4 --- /dev/null +++ b/tools/schedule_manager.py @@ -0,0 +1,561 @@ +#!/usr/bin/env python3 +""" +《末日重生》项目定时任务管理系统 +提供完整的定时同步、版本管理、监控告警功能 +""" + +import os +import sys +import json +import time +import subprocess +from datetime import datetime, timedelta +from pathlib import Path +import shutil +import logging +from typing import Dict, List, Optional, Tuple + +# 项目配置 +PROJECT_DIR = Path("/root/.openclaw/workspace/projects/末日重生_囤货") +CONFIG_DIR = PROJECT_DIR / "config" +LOG_DIR = PROJECT_DIR / "logs" +TOOLS_DIR = PROJECT_DIR / "tools" +BACKUP_DIR = PROJECT_DIR / "backups" + +# 确保目录存在 +for dir_path in [CONFIG_DIR, LOG_DIR, BACKUP_DIR]: + dir_path.mkdir(parents=True, exist_ok=True) + +class Scheduler: + """定时任务管理器""" + + def __init__(self): + self.config = self.load_config() + self.setup_logging() + + def load_config(self) -> Dict: + """加载配置文件""" + config_path = CONFIG_DIR / "cron_schedule.json" + if config_path.exists(): + with open(config_path, 'r', encoding='utf-8') as f: + return json.load(f) + else: + # 默认配置 + return { + "schedules": { + "auto_commit": { + "enabled": True, + "interval": "30min", + "cron_expr": "*/30 * * * *" + }, + "daily_backup": { + "enabled": True, + "time": "03:00" + }, + "status_report": { + "enabled": True, + "time": "01:00" + }, + "weekly_cleanup": { + "enabled": True, + "day": "sunday", + "time": "02:00" + } + } + } + + def setup_logging(self): + """配置日志系统""" + log_file = LOG_DIR / f"schedule_{datetime.now().strftime('%Y%m')}.log" + + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [%(levelname)s] %(message)s', + handlers=[ + logging.FileHandler(log_file, encoding='utf-8'), + logging.StreamHandler(sys.stdout) + ] + ) + + self.logger = logging.getLogger(__name__) + + def run_auto_commit(self): + """执行自动提交任务""" + self.logger.info("开始自动提交任务...") + + try: + # 运行Git版本管理脚本 + script_path = TOOLS_DIR / "git_version_manager.sh" + + if not script_path.exists(): + self.logger.error(f"脚本不存在: {script_path}") + return False + + # 检查是否有更改 + result = subprocess.run( + ["git", "status", "--porcelain"], + cwd=PROJECT_DIR, + capture_output=True, + text=True, + timeout=30 + ) + + if result.stdout.strip(): + # 有未提交的更改,执行提交 + commit_message = f"定时更新: {datetime.now().strftime('%Y年%m月%d日 %H:%M:%S')}" + + self.logger.info(f"检测到未提交的更改,提交信息: {commit_message}") + + # 执行提交 + commit_result = subprocess.run( + [str(script_path), "commit"], + cwd=PROJECT_DIR, + capture_output=True, + text=True, + timeout=60 + ) + + if commit_result.returncode == 0: + self.logger.info("自动提交成功") + return True + else: + self.logger.error(f"自动提交失败: {commit_result.stderr}") + return False + else: + self.logger.info("没有未提交的更改,跳过提交") + return True + + except subprocess.TimeoutExpired: + self.logger.error("自动提交任务超时") + return False + except Exception as e: + self.logger.error(f"自动提交任务异常: {e}") + return False + + def run_backup_task(self, backup_type: str = "full"): + """执行备份任务""" + self.logger.info(f"开始备份任务,类型: {backup_type}") + + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + backup_filename = f"backup_{backup_type}_{timestamp}.tar.gz" + backup_file = BACKUP_DIR / backup_filename + + try: + # 根据备份类型执行备份 + if backup_type == "full": + # 完整备份 + backup_items = [ + "chapters", "outlines", "assets", + "tools", "config", "progress" + ] + + backup_cmd = ["tar", "czf", str(backup_file)] + backup_items + + elif backup_type == "chapters": + # 章节备份 + backup_cmd = ["tar", "czf", str(backup_file), "chapters"] + + elif backup_type == "git": + # Git包备份 + backup_file = BACKUP_DIR / f"git_bundle_{timestamp}.bundle" + backup_cmd = ["git", "bundle", "create", str(backup_file), "--all"] + + else: + self.logger.error(f"未知的备份类型: {backup_type}") + return False + + # 执行备份命令 + + result = subprocess.run( + backup_cmd, + cwd=PROJECT_DIR, + capture_output=True, + text=True, + timeout=300 + ) + + if result.returncode == 0: + backup_size = backup_file.stat().st_size / (1024 * 1024) # MB + self.logger.info(f"备份成功: {backup_filename} ({backup_size:.2f} MB)") + + # 清理旧备份 + self.cleanup_old_backups() + return True + else: + self.logger.error(f"备份失败: {result.stderr}") + return False + + except Exception as e: + self.logger.error(f"备份任务异常: {e}") + return False + + def cleanup_old_backups(self): + """清理旧备份文件""" + retention_days = 7 + cutoff_time = datetime.now() - timedelta(days=retention_days) + + deleted_files = [] + + for backup_file in BACKUP_DIR.glob("*.tar.gz"): + file_time = datetime.fromtimestamp(backup_file.stat().st_mtime) + + if file_time < cutoff_time: + try: + backup_file.unlink() + deleted_files.append(backup_file.name) + except Exception as e: + self.logger.warning(f"删除旧备份失败 {backup_file}: {e}") + + if deleted_files: + self.logger.info(f"清理旧备份: {len(deleted_files)} 个文件") + + def run_status_report(self): + """执行状态报告任务""" + self.logger.info("开始状态报告任务...") + + try: + # 运行Git版本管理脚本生成报告 + script_path = TOOLS_DIR / "git_version_manager.sh" + + if not script_path.exists(): + self.logger.error(f"脚本不存在: {script_path}") + return False + + # 执行报告生成 + result = subprocess.run( + [str(script_path), "report"], + cwd=PROJECT_DIR, + capture_output=True, + text=True, + timeout=120 + ) + + if result.returncode == 0: + self.logger.info("状态报告生成成功") + + # 发送通知(可选) + if self.config.get("notifications", {}).get("enabled", False): + self.send_notification("状态报告已生成") + + return True + else: + self.logger.error(f"状态报告生成失败: {result.stderr}") + return False + + except Exception as e: + self.logger.error(f"状态报告任务异常: {e}") + return False + + def send_notification(self, message: str): + """发送通知(示例)""" + # 这里可以实现邮件、钉钉、飞书等通知方式 + # 示例:输出到日志和终端 + + print(f"📢 通知: {message}") + self.logger.info(f"通知已发送: {message}") + + def check_health(self) -> Dict: + """检查系统健康状态""" + health_status = { + "timestamp": datetime.now().isoformat(), + "components": {} + } + + # 检查磁盘空间 + disk_usage = shutil.disk_usage(PROJECT_DIR) + disk_percent = disk_usage.used / disk_usage.total * 100 + health_status["components"]["disk"] = { + "total_gb": disk_usage.total / (1024**3), + "used_gb": disk_usage.used / (1024**3), + "free_gb": disk_usage.free / (1024**3), + "percent_used": disk_percent, + "status": "OK" if disk_percent < 90 else "WARNING" + } + + # 检查Git仓库 + + git_status = subprocess.run( + ["git", "status"], + cwd=PROJECT_DIR, + capture_output=True, + text=True + ) + + health_status["components"]["git"] = { + "repository_healthy": git_status.returncode == 0, + "status": "OK" if git_status.returncode == 0 else "ERROR" + } + + # 检查项目文件 + required_dirs = ["chapters", "outlines", "assets"] + for dir_name in required_dirs: + dir_path = PROJECT_DIR / dir_name + + health_status["components"][dir_name] = { + "exists": dir_path.exists(), + "file_count": len(list(dir_path.glob("*"))) if dir_path.exists() else 0, + "status": "OK" if dir_path.exists() else "MISSING" + } + + # 总体状态 + all_ok = all( + comp.get("status") == "OK" + for comp in health_status["components"].values() + ) + + health_status["overall_status"] = "HEALTHY" if all_ok else "UNHEALTHY" + + return health_status + + def monitor_task_execution(self): + """监控任务执行状态""" + health_status = self.check_health() + + self.logger.info("系统健康状态检查") + self.logger.info(f"总体状态: {health_status['overall_status']}") + + # 记录到监控日志 + monitor_log = LOG_DIR / f"monitor_{datetime.now().strftime('%Y%m%d')}.json" + monitor_data = { + "timestamp": datetime.now().isoformat(), + "health": health_status, + "tasks": { + "auto_commit": self.config.get("schedules", {}).get("auto_commit", {}), + "daily_backup": self.config.get("schedules", {}).get("daily_backup", {}), + "status_report": self.config.get("schedules", {}).get("status_report", {}) + } + } + + try: + with open(monitor_log, 'a', encoding='utf-8') as f: + f.write(json.dumps(monitor_data, ensure_ascii=False) + "\n") + + self.logger.info(f"监控数据已记录: {monitor_log}") + except Exception as e: + self.logger.error(f"记录监控数据失败: {e}") + + def install_cron_jobs(self): + """安装Cron定时任务""" + cron_script = """ + #!/bin/bash + # 《末日重生》定时任务配置 + # 自动安装和配置定时同步任务 + + # 自动提交任务(每30分钟) + */30 * * * * cd /root/.openclaw/workspace/projects/末日重生_囤货 && ./tools/git_version_manager.sh commit >> /tmp/末日重生_自动提交.log 2>&1 + + # 状态报告任务(每天凌晨1点) + 0 1 * * * cd /root/.openclaw/workspace/projects/末日重生_囤货 && ./tools/git_version_manager.sh report >> /tmp/末日重生_报告生成.log 2>&1 + + # 备份任务(每天凌晨3点) + 0 3 * * * cd /root/.openclaw/workspace/projects/末日重生_囤货 && ./tools/schedule_manager.py backup >> /tmp/末日重生_备份.log 2>&1 + + # 健康检查(每小时) + 0 * * * * cd /root/.openclaw/workspace/projects/末日重生_囤货 && ./tools/schedule_manager.py health >> /tmp/末日重生_健康检查.log 2>&1 + """ + + cron_file = "/tmp/末日重生_cron.conf" + + try: + with open(cron_file, 'w', encoding='utf-8') as f: + f.write(cron_script) + + # 安装Cron任务 + + subprocess.run(["crontab", cron_file], check=True) + + self.logger.info("Cron定时任务安装成功") + self.logger.info("已配置以下定时任务:") + self.logger.info(" - 自动提交:每30分钟") + self.logger.info(" - 状态报告:每天凌晨1点") + self.logger.info(" - 项目备份:每天凌晨3点") + self.logger.info(" - 健康检查:每小时") + + os.unlink(cron_file) + return True + + except Exception as e: + self.logger.error(f"安装Cron任务失败: {e}") + return False + + def show_dashboard(self): + """显示系统仪表板""" + health = self.check_health() + + print("=" * 60) + print("📊 《末日重生》项目管理系统仪表板") + print("=" * 60) + print() + + print("📈 项目统计") + print("─" * 40) + + # 章节统计 + chapters_dir = PROJECT_DIR / "chapters" + if chapters_dir.exists(): + chapter_files = list(chapters_dir.glob("*.md")) + print(f" 📖 章节数量: {len(chapter_files)} 章") + + # 计算总字数 + total_words = 0 + for chapter in chapter_files: + try: + content = chapter.read_text(encoding='utf-8') + words = len(content.split()) + total_words += words + except: + continue + + print(f" 📝 总字数: {total_words} 字") + avg_words = total_words // len(chapter_files) if chapter_files else 0 + print(f" ⚖️ 平均每章: {avg_words} 字") + else: + print(" ⚠️ 章节目录不存在") + + print() + print("💾 备份管理") + print("─" * 40) + + backup_files = list(BACKUP_DIR.glob("*.tar.gz")) + list(BACKUP_DIR.glob("*.bundle")) + + if backup_files: + backup_files.sort(key=lambda x: x.stat().st_mtime, reverse=True) + + print(f" 🗂️ 备份数量: {len(backup_files)} 个") + print(f" 🗓️ 最新备份: {backup_files[0].name}") + print(f" 备份时间: {datetime.fromtimestamp(backup_files[0].stat().st_mtime).strftime('%Y-%m-%d %H:%M:%S')}") + + # 计算总备份大小 + + + total_size = sum(f.stat().st_size for f in backup_files) / (1024**3) # GB + print(f" 📦 总备份大小: {total_size:.2f} GB") + else: + print(" ⚠️ 暂无备份文件") + + print() + print("🔄 任务配置") + print("─" *40) + + for task_name, task_config in self.config.get("schedules", {}).items(): + status = "✅ 启用" if task_config.get("enabled", False) else "❌ 停用" + + if task_name == "auto_commit": + interval = task_config.get("interval", "未知") + print(f" 📝 {task_name}: {status} (间隔: {interval})") + + elif task_name == "daily_backup": + backup_time = task_config.get("time", "未知") + print(f" 💾 {task_name}: {status} (时间: {backup_time})") + + elif task_name == "status_report": + report_time = task_config.get("time", "未知") + print(f" 📊 {task_name}: {status} (时间: {report_time})") + + elif task_name == "weekly_cleanup": + cleanup_day = task_config.get("day", "未知") + cleanup_time = task_config.get("time", "未知") + print(f" 🧹 {task_name}: {status} (时间: 每周{cleanup_day}{cleanup_time})") + + print() + print("📈 健康状态") + print("─" *40) + + if health.get("overall_status") == "HEALTHY": + print(" 🟢 系统状态: 健康") + else: + print(" 🔴 系统状态: 异常") + + # 显示异常组件 + + + for comp_name, comp_status in health.get("components", {}).items(): + if comp_status.get("status") != "OK": + print(f" ⚠️ {comp_name}: {comp_status.get('status')}") + + print() + print("=" *60) + +def main(): + """主函数""" + import argparse + + parser = argparse.ArgumentParser( + description="《末日重生》项目定时任务管理系统", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +使用示例: + # 显示系统仪表板 + python schedule_manager.py dashboard + + # 执行自动提交 + python schedule_manager.py commit + + # 执行备份任务 + python schedule_manager.py backup --type full + + # 安装定时任务 + python schedule_manager.py install + + # 检查系统健康 + python schedule_manager.py health + + # 运行状态报告 + python schedule_manager.py report + """ + ) + + parser.add_argument( + "action", + choices=[ + "dashboard", "commit", "backup", "report", "health", "install" + ], + help="要执行的操作" + ) + + parser.add_argument( + "--type", + default="full", + choices=["full", "chapters", "git"], + help="备份类型" + ) + + parser.add_argument( + "--verbose", + action="store_true", + help="显示详细日志" + ) + + args = parser.parse_args() + + scheduler = Scheduler() + + if args.verbose: + scheduler.logger.setLevel(logging.DEBUG) + + if args.action == "dashboard": + scheduler.show_dashboard() + + elif args.action == "commit": + success = scheduler.run_auto_commit() + exit(0 if success else 1) + + elif args.action == "backup": + success = scheduler.run_backup_task(args.type) + exit(0 if success else 1) + + elif args.action == "report": + success = scheduler.run_status_report() + exit(0 if success else 1) + + elif args.action == "health": + health_status = scheduler.check_health() + print(json.dumps(health_status, ensure_ascii=False, indent=2)) + exit(0 if health_status["overall_status"] == "HEALTHY" else 1) + + elif args.action == "install": + success = scheduler.install_cron_jobs() + exit(0 if success else 1) + +if __name__ == "__main__": + main() \ No newline at end of file