253 lines
8.6 KiB
Python
253 lines
8.6 KiB
Python
import click
|
||
import os
|
||
from ..core.view_command import ViewCommand
|
||
from ..core.suggest_update_command import SuggestUpdateCommand
|
||
from ..core.force_update_command import ForceUpdateCommand
|
||
from ..utils.mock_rclone import patch_rclone
|
||
from ..utils.config import config
|
||
|
||
|
||
@click.group()
|
||
@click.version_option(version="0.1.0")
|
||
def cli():
|
||
"""Config-Man CLI 工具
|
||
|
||
用于管理存储在对象存储中的加密静态资源配置文件。
|
||
支持多版本管理,通过Cloudflare CDN进行分发。
|
||
"""
|
||
pass
|
||
|
||
|
||
@cli.command()
|
||
@click.option('--version', required=True, help='版本号,格式为 0.29, 0.30, 0.31 等')
|
||
@click.option('--json', 'json_format', is_flag=True, help='以JSON格式输出')
|
||
@click.option('--storage-path', help='对象存储路径前缀(覆盖配置文件)')
|
||
@click.option('--cdn-url', help='CDN基础URL(覆盖配置文件)')
|
||
@click.option('--mock', is_flag=True, help='使用模拟环境进行测试')
|
||
def view(version, json_format, storage_path, cdn_url, mock):
|
||
"""查看配置文件
|
||
|
||
对比显示对象存储和CDN中的配置内容,支持 Android、iOS 和 RU 平台。
|
||
|
||
示例:
|
||
config-man view --version 0.30
|
||
config-man view --version 0.30 --json
|
||
config-man view --version 0.30 --mock
|
||
"""
|
||
try:
|
||
# 如果使用模拟环境,启用rclone模拟
|
||
if mock:
|
||
patch_rclone()
|
||
click.echo("使用模拟环境进行测试...")
|
||
else:
|
||
# 检查rclone是否可用
|
||
if not _check_rclone():
|
||
click.echo("错误: rclone 未安装或不可用。请先安装 rclone。")
|
||
return 1
|
||
|
||
# 创建查看命令处理器
|
||
view_cmd = ViewCommand(storage_path, cdn_url)
|
||
|
||
# 执行查看命令
|
||
success = view_cmd.execute(version, json_format)
|
||
|
||
return 0 if success else 1
|
||
|
||
except Exception as e:
|
||
click.echo(f"错误: {str(e)}")
|
||
return 1
|
||
|
||
|
||
@cli.command()
|
||
@click.option('--platform', required=True, type=click.Choice(['android', 'ios', 'ru']),
|
||
help='平台类型')
|
||
@click.option('--target-version', required=True, help='目标版本号')
|
||
@click.option('--update-version', required=True, help='更新版本号')
|
||
@click.option('--storage-path', help='对象存储路径前缀(覆盖配置文件)')
|
||
@click.option('--cdn-url', help='CDN基础URL(覆盖配置文件)')
|
||
@click.option('--mock', is_flag=True, help='使用模拟环境进行测试')
|
||
def suggest_update(platform, target_version, update_version, storage_path, cdn_url, mock):
|
||
"""建议更新
|
||
|
||
在目标版本的配置文件中添加 Ver_New 属性,提示用户有新版本可用。
|
||
|
||
示例:
|
||
config-man suggest-update --platform android --target-version 0.29 --update-version 0.30
|
||
config-man suggest-update --platform ios --target-version 0.29 --update-version 0.30 --mock
|
||
config-man suggest-update --platform ru --target-version 0.29 --update-version 0.30 --mock
|
||
"""
|
||
try:
|
||
# 如果使用模拟环境,启用rclone模拟
|
||
if mock:
|
||
patch_rclone()
|
||
click.echo("使用模拟环境进行测试...")
|
||
else:
|
||
# 检查rclone是否可用
|
||
if not _check_rclone():
|
||
click.echo("错误: rclone 未安装或不可用。请先安装 rclone。")
|
||
return 1
|
||
|
||
# 创建建议更新命令处理器
|
||
suggest_cmd = SuggestUpdateCommand(storage_path, cdn_url)
|
||
|
||
# 执行建议更新命令
|
||
success = suggest_cmd.execute(platform, target_version, update_version)
|
||
|
||
return 0 if success else 1
|
||
|
||
except Exception as e:
|
||
click.echo(f"错误: {str(e)}")
|
||
return 1
|
||
|
||
|
||
@cli.command()
|
||
@click.option('--platform', required=True, type=click.Choice(['android', 'ios', 'ru']),
|
||
help='平台类型')
|
||
@click.option('--target-version', required=True, help='目标版本号')
|
||
@click.option('--update-version', required=True, help='更新版本号')
|
||
@click.option('--storage-path', help='对象存储路径前缀(覆盖配置文件)')
|
||
@click.option('--cdn-url', help='CDN基础URL(覆盖配置文件)')
|
||
@click.option('--mock', is_flag=True, help='使用模拟环境进行测试')
|
||
def force_update(platform, target_version, update_version, storage_path, cdn_url, mock):
|
||
"""强制更新
|
||
|
||
直接更新目标版本的 Ver 属性,强制用户升级到新版本。
|
||
|
||
示例:
|
||
config-man force-update --platform ios --target-version 0.29 --update-version 0.30
|
||
config-man force-update --platform android --target-version 0.29 --update-version 0.30 --mock
|
||
config-man force-update --platform ru --target-version 0.29 --update-version 0.30 --mock
|
||
"""
|
||
try:
|
||
# 如果使用模拟环境,启用rclone模拟
|
||
if mock:
|
||
patch_rclone()
|
||
click.echo("使用模拟环境进行测试...")
|
||
else:
|
||
# 检查rclone是否可用
|
||
if not _check_rclone():
|
||
click.echo("错误: rclone 未安装或不可用。请先安装 rclone。")
|
||
return 1
|
||
|
||
# 创建强制更新命令处理器
|
||
force_cmd = ForceUpdateCommand(storage_path, cdn_url)
|
||
|
||
# 执行强制更新命令
|
||
success = force_cmd.execute(platform, target_version, update_version)
|
||
|
||
return 0 if success else 1
|
||
|
||
except Exception as e:
|
||
click.echo(f"错误: {str(e)}")
|
||
return 1
|
||
|
||
|
||
@cli.command()
|
||
def show_config():
|
||
"""显示当前配置
|
||
|
||
显示当前加载的配置信息。
|
||
"""
|
||
import json
|
||
from rich.console import Console
|
||
from rich.panel import Panel
|
||
|
||
console = Console()
|
||
|
||
# 获取所有配置
|
||
all_config = {
|
||
"storage": config.get_storage_config(),
|
||
"cdn": config.get_cdn_config(),
|
||
"crypto": config.get_crypto_config(),
|
||
"display": config.get_display_config(),
|
||
"logging": config.get_logging_config()
|
||
}
|
||
|
||
# 格式化输出
|
||
config_json = json.dumps(all_config, indent=2, ensure_ascii=False)
|
||
panel = Panel(
|
||
config_json,
|
||
title="当前配置",
|
||
border_style="blue"
|
||
)
|
||
console.print(panel)
|
||
|
||
# 显示配置文件路径
|
||
console.print(f"\n配置文件路径: {config.config_file}")
|
||
|
||
|
||
@cli.command()
|
||
@click.option('--api-token', required=True, help='Cloudflare API Token')
|
||
@click.option('--zone-id', required=True, help='Cloudflare Zone ID')
|
||
def setup_cloudflare(api_token, zone_id):
|
||
"""设置Cloudflare CDN配置
|
||
|
||
设置Cloudflare API Token和Zone ID。
|
||
|
||
示例:
|
||
config-man setup-cloudflare --api-token your_api_token --zone-id your_zone_id
|
||
"""
|
||
try:
|
||
# 设置Cloudflare配置
|
||
config.set('cdn.cloudflare.api_token', api_token)
|
||
config.set('cdn.cloudflare.zone_id', zone_id)
|
||
config.save()
|
||
|
||
click.echo("✅ Cloudflare配置已更新")
|
||
click.echo(f" API Token: {api_token[:10]}...")
|
||
click.echo(f" Zone ID: {zone_id}")
|
||
click.echo("\n💡 提示: 配置已保存到配置文件,无需重复设置环境变量")
|
||
|
||
except Exception as e:
|
||
click.echo(f"❌ 设置Cloudflare配置失败: {e}")
|
||
return 1
|
||
|
||
|
||
@cli.command()
|
||
@click.option('--key', required=True, help='配置键,如 storage.path')
|
||
@click.option('--value', required=True, help='配置值')
|
||
def set_config(key, value):
|
||
"""设置配置值
|
||
|
||
设置指定的配置值并保存到配置文件。
|
||
|
||
示例:
|
||
config-man set-config --key storage.path --value custom_path
|
||
config-man set-config --key cdn.base_url --value https://cdn.example.com
|
||
config-man set-config --key cdn.cloudflare.api_token --value your_api_token
|
||
config-man set-config --key cdn.cloudflare.zone_id --value your_zone_id
|
||
"""
|
||
try:
|
||
# 尝试转换数值类型
|
||
if value.isdigit():
|
||
value = int(value)
|
||
elif value.lower() in ('true', 'false'):
|
||
value = value.lower() == 'true'
|
||
|
||
config.set(key, value)
|
||
config.save()
|
||
click.echo(f"✅ 配置已更新: {key} = {value}")
|
||
except Exception as e:
|
||
click.echo(f"❌ 设置配置失败: {e}")
|
||
return 1
|
||
|
||
|
||
def _check_rclone():
|
||
"""检查rclone是否可用"""
|
||
import subprocess
|
||
try:
|
||
result = subprocess.run(['rclone', 'version'],
|
||
capture_output=True, text=True, timeout=5)
|
||
return result.returncode == 0
|
||
except (subprocess.TimeoutExpired, FileNotFoundError):
|
||
return False
|
||
|
||
|
||
def main():
|
||
"""主函数"""
|
||
cli()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|