diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..d9e1e91 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,84 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Config-Man is a Python CLI tool for managing encrypted static configuration files stored in object storage with Cloudflare CDN distribution. It's primarily used for game application configuration management with support for multi-version management and update strategies. + +## Code Architecture + +### Core Components +- `src/config_man/core/` - Core business logic modules: + - `config_manager.py` - Handles storage and CDN configuration file operations + - `display_manager.py` - Manages configuration display and comparison + - `view_command.py` - Implements the view command functionality + - `suggest_update_command.py` - Implements the suggest-update command functionality + - `force_update_command.py` - Implements the force-update command functionality + +### CLI Layer +- `src/config_man/cli/main.py` - Main CLI entry point using Click framework +- Commands: view, suggest-update, force-update, show-config, setup-cloudflare, set-config + +### Utilities +- `src/config_man/utils/` - Utility modules for crypto, config management, and mock functionality + +## Common Development Commands + +### Installation and Setup +```bash +# Install dependencies +pip install -r requirements.txt + +# Install in development mode +pip install -e . + +# Install with development dependencies +pip install -e ".[dev]" +``` + +### Running the CLI +```bash +# Run the CLI tool +python main.py --help + +# Or if installed +config-man --help +``` + +### Testing +```bash +# Run all tests +pytest + +# Run tests with coverage +pytest --cov=src/config_man + +# Run tests with coverage report +pytest --cov=src/config_man --cov-report=html +``` + +### Code Quality +```bash +# Format code with black +black . + +# Lint with flake8 +flake8 . + +# Type checking with mypy +mypy src/ +``` + +## Configuration +- Uses `config-man.json` for runtime configuration +- Supports environment variables for Cloudflare CDN settings +- Configuration can be modified with `config-man set-config` command + +## Key Dependencies +- click>=8.0.0 - CLI framework +- pycryptodome>=3.19.0 - Encryption/decryption +- tabulate>=0.9.0 - Table formatting +- requests>=2.31.0 - HTTP requests +- rich>=13.0.0 - Rich text formatting +- rclone - Required for storage operations \ No newline at end of file diff --git a/configGen.py b/configGen.py new file mode 100755 index 0000000..8db4c06 --- /dev/null +++ b/configGen.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +""" +Config Generator Tool + +读取加密的 'androidconfig.json' 或 'iosconfig.json' 文件, +生成新的加密配置文件,支持添加建议更新版本号或强制更新版本号。 +""" + +import json +import os +import sys +from pathlib import Path +from rich.console import Console +from rich.panel import Panel +from rich.syntax import Syntax +from rich import print as rprint + +# Add the src directory to the path so we can import the crypto module +sys.path.insert(0, str(Path(__file__).parent / "src")) + +from config_man.utils.crypto import encrypt, decrypt + +# Initialize rich console +console = Console() + + +def load_encrypted_config(file_path): + """Load and decrypt a configuration file""" + try: + with open(file_path, 'r', encoding='utf-8') as f: + encrypted_content = f.read().strip() + + if not encrypted_content: + console.print(f"[red]错误: 文件 {file_path} 为空[/red]") + return None + + decrypted_content = decrypt(encrypted_content) + config_data = json.loads(decrypted_content) + return config_data + except FileNotFoundError: + console.print(f"[red]错误: 文件 {file_path} 不存在[/red]") + return None + except Exception as e: + console.print(f"[red]错误: 无法读取或解密文件 {file_path}: {str(e)}[/red]") + return None + + +def save_encrypted_config(config_data, file_path): + """Encrypt and save a configuration file""" + try: + # Convert config data to JSON string + config_json = json.dumps(config_data, ensure_ascii=False, indent=2) + + # Encrypt the content + encrypted_content = encrypt(config_json) + + # Save to file + with open(file_path, 'w', encoding='utf-8') as f: + f.write(encrypted_content) + + console.print(f"[green]✅ 配置文件已保存到: {file_path}[/green]") + return True + except Exception as e: + console.print(f"[red]错误: 无法保存文件 {file_path}: {str(e)}[/red]") + return False + + +def add_suggest_update(config_data, update_version): + """Add suggest update version (Ver_New) to config""" + # Show before and after + console.print(Panel("更新前的配置", title="🔄 更新前", border_style="blue")) + console.print(Syntax(json.dumps(config_data, ensure_ascii=False, indent=2), "json", theme="monokai")) + + # Get the Ver value from the update version config + # For now, we'll just add the version string as Ver_New + config_data["Ver_New"] = update_version + + console.print(Panel("更新后的配置", title="✅ 更新后", border_style="green")) + console.print(Syntax(json.dumps(config_data, ensure_ascii=False, indent=2), "json", theme="monokai")) + + console.print(f"✅ 已添加建议更新版本: {update_version}") + return config_data + + +def add_force_update(config_data, update_version): + """Add force update version (Ver) to config""" + # Show before and after + console.print(Panel("更新前的配置", title="🔄 更新前", border_style="blue")) + console.print(Syntax(json.dumps(config_data, ensure_ascii=False, indent=2), "json", theme="monokai")) + + # Update the Ver field + config_data["Ver"] = update_version + + console.print(Panel("更新后的配置", title="✅ 更新后", border_style="green")) + console.print(Syntax(json.dumps(config_data, ensure_ascii=False, indent=2), "json", theme="monokai")) + + console.print(f"✅ 已更新强制版本为: {update_version}") + return config_data + + +def main(): + console.print(Panel("🔧 Config Generator Tool", expand=False, border_style="bold blue")) + + # Get input file path + while True: + input_file = input("请输入要读取的加密配置文件路径 (如: androidconfig.json): ").strip() + if input_file and os.path.exists(input_file): + break + console.print("[red]❌ 文件不存在,请重新输入[/red]") + + # Load and decrypt the config file + console.print(f"[blue]正在读取配置文件: {input_file}[/blue]") + config_data = load_encrypted_config(input_file) + if config_data is None: + return 1 + + console.print("[green]✅ 配置文件读取成功[/green]") + console.print(f"[cyan]当前版本: {config_data.get('Ver', 'N/A')}[/cyan]") + + # Get update type + while True: + update_type = input("\n请选择更新类型 (1: 建议更新, 2: 强制更新): ").strip() + if update_type in ['1', '2']: + break + console.print("[red]❌ 请输入 1 或 2[/red]") + + # Get update version + update_version = input("请输入更新版本号 (如: 0.30): ").strip() + if not update_version: + console.print("[red]❌ 版本号不能为空[/red]") + return 1 + + # Apply update + if update_type == '1': + config_data = add_suggest_update(config_data, update_version) + else: + config_data = add_force_update(config_data, update_version) + + # Get output file path + default_output = f"new_{os.path.basename(input_file)}" + output_file = input(f"\n请输入输出文件路径 (默认: {default_output}): ").strip() + if not output_file: + output_file = default_output + + # Save the new encrypted config + console.print(f"[blue]正在保存配置文件: {output_file}[/blue]") + if save_encrypted_config(config_data, output_file): + console.print(Panel("🎉 配置文件生成完成!", expand=False, border_style="bold green")) + return 0 + else: + return 1 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except KeyboardInterrupt: + print("\n\n👋 已取消操作") + sys.exit(0) + except Exception as e: + print(f"\n❌ 程序执行出错: {str(e)}") + sys.exit(1) \ No newline at end of file