Files
QuickGit/quickgit/remote_manager.py

236 lines
8.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
远程仓库管理模块 - 处理GitHub和Gitea远程仓库的管理
"""
from .utils import CommandExecutor, OutputFormatter, InputValidator
from .config import Config
class RemoteManager:
"""远程仓库管理器"""
def __init__(self):
self.executor = CommandExecutor()
def get_remotes(self) -> list[str]:
"""
获取所有远程仓库
Returns:
远程仓库列表
"""
success, output = self.executor.run("git remote", show_output=False)
if success and output.strip():
return [r.strip() for r in output.strip().split('\n') if r.strip()]
return []
def show_remotes(self):
"""显示所有远程仓库"""
from .utils import Colors
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
print(f"{Colors.BRIGHT_CYAN}>> 远程仓库列表:{Colors.ENDC}")
self.executor.run("git remote -v", show_output=True)
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
def add_github_remote(self, repo_name: str = "") -> bool:
"""
添加GitHub远程仓库
Args:
repo_name: 仓库名(如果为空则提示用户输入)
Returns:
是否成功
"""
if not repo_name:
from .utils import Colors
repo_name = InputValidator.get_input(f"{Colors.BRIGHT_CYAN}>> 请输入GitHub仓库名: {Colors.ENDC}")
remote_url = f"git@github.com:{Config.GITHUB_USER}/{repo_name}.git"
return self._add_remote("github", remote_url)
def add_gitea_remote(self, user: str = "", repo_name: str = "") -> bool:
"""
添加Gitea远程仓库
Args:
user: Gitea用户名如果为空则提示用户输入
repo_name: 仓库名(如果为空则提示用户输入)
Returns:
是否成功
"""
from .utils import Colors
if not user:
user = InputValidator.get_input(f"{Colors.BRIGHT_CYAN}>> 请输入Gitea用户名: {Colors.ENDC}")
if not repo_name:
repo_name = InputValidator.get_input(f"{Colors.BRIGHT_CYAN}>> 请输入Gitea仓库名: {Colors.ENDC}")
remote_url = f"ssh://git@{Config.GITEA_HOST}:{Config.GITEA_PORT}/{user}/{repo_name}.git"
return self._add_remote("gitea", remote_url)
def _add_remote(self, name: str, url: str) -> bool:
"""
添加远程仓库
Args:
name: 远程仓库名称
url: 远程仓库URL
Returns:
是否成功
"""
# 检查remote是否已存在
remotes = self.get_remotes()
if name in remotes:
if InputValidator.confirm(f"远程仓库 '{name}' 已存在,是否覆盖?", default=False):
self.executor.run(f"git remote remove {name}", show_output=False)
else:
return False
success, _ = self.executor.run(f'git remote add {name} {url}', show_output=False)
if success:
OutputFormatter.success(f"{name.capitalize()}远程仓库已添加: {url}")
else:
OutputFormatter.error(f"{name.capitalize()}远程仓库添加失败")
return success
def remove_remote(self, name: str = "") -> bool:
"""
删除远程仓库
Args:
name: 远程仓库名(如果为空则提示用户选择)
Returns:
是否成功
"""
from .utils import Colors
remotes = self.get_remotes()
if not remotes:
OutputFormatter.warning("没有配置远程仓库")
return False
if not name:
# 让用户选择要删除的远程仓库
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
print(f"{Colors.BRIGHT_YELLOW}>> 当前远程仓库:{Colors.ENDC}")
for idx, remote in enumerate(remotes, 1):
OutputFormatter.menu_item(idx, remote)
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
choice = InputValidator.get_choice(
f"{Colors.BRIGHT_CYAN}>> 请选择要删除的远程仓库 [1-{len(remotes)}]: {Colors.ENDC}",
range(1, len(remotes) + 1)
)
name = remotes[choice - 1]
if not InputValidator.confirm(f"确认删除远程仓库 '{name}'?", default=False):
return False
success, _ = self.executor.run(f"git remote remove {name}", show_output=False)
if success:
OutputFormatter.success(f"远程仓库 '{name}' 已删除")
else:
OutputFormatter.error("删除失败")
return success
def configure_remotes_interactive(self):
"""交互式配置远程仓库"""
from .utils import Colors
print(f"\n{Colors.BRIGHT_MAGENTA}>> 配置远程仓库{Colors.ENDC}")
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
OutputFormatter.menu_item(1, "GitHub")
OutputFormatter.menu_item(2, "Gitea")
OutputFormatter.menu_item(3, "两者都配置")
OutputFormatter.menu_item(4, "跳过")
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
choice = InputValidator.get_choice(
f"{Colors.BRIGHT_CYAN}>> 请选择 [1-4]: {Colors.ENDC}",
range(1, 5)
)
if choice == 1:
self.add_github_remote()
elif choice == 2:
self.add_gitea_remote()
elif choice == 3:
self.add_github_remote()
self.add_gitea_remote()
else:
OutputFormatter.info("跳过远程仓库配置")
def select_remote_for_push(self) -> list[str]:
"""
选择要推送的远程仓库
Returns:
选中的远程仓库列表
"""
from .utils import Colors
remotes = self.get_remotes()
if not remotes:
OutputFormatter.warning("没有配置远程仓库")
return []
print(f"\n{Colors.BRIGHT_YELLOW}>> 可用的远程仓库:{Colors.ENDC}")
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
for idx, remote in enumerate(remotes, 1):
OutputFormatter.menu_item(idx, remote)
OutputFormatter.menu_item(len(remotes) + 1, "全部推送")
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
choice = InputValidator.get_choice(
f"{Colors.BRIGHT_CYAN}>> 请选择 [1-{len(remotes) + 1}]: {Colors.ENDC}",
range(1, len(remotes) + 2)
)
if choice == len(remotes) + 1:
return remotes
else:
return [remotes[choice - 1]]
def select_remote_for_pull(self) -> str:
"""
选择要拉取的远程仓库
Returns:
选中的远程仓库名,如果没有配置则返回空字符串
"""
from .utils import Colors
remotes = self.get_remotes()
if not remotes:
OutputFormatter.warning("没有配置远程仓库")
return ""
print(f"\n{Colors.BRIGHT_YELLOW}>> 可用的远程仓库:{Colors.ENDC}")
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
for idx, remote in enumerate(remotes, 1):
OutputFormatter.menu_item(idx, remote)
print(f"{Colors.CYAN}{'-' * 60}{Colors.ENDC}")
choice = InputValidator.get_choice(
f"{Colors.BRIGHT_CYAN}>> 请选择 [1-{len(remotes)}]: {Colors.ENDC}",
range(1, len(remotes) + 1)
)
return remotes[choice - 1]
choice = InputValidator.get_choice(
f"\n请选择要拉取的远程仓库 [1-{len(remotes)}]: ",
range(1, len(remotes) + 1)
)
return remotes[choice - 1]