完成一个简易的全局skill、command管理器
This commit is contained in:
109
manager/internal/repo/git.go
Normal file
109
manager/internal/repo/git.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"skillmgr/internal/config"
|
||||
)
|
||||
|
||||
// URLToPathName 将 URL 转换为缓存目录名
|
||||
// 例如: https://github.com/user/repo.git -> github.com_user_repo
|
||||
func URLToPathName(url string) string {
|
||||
clean := strings.TrimPrefix(url, "https://")
|
||||
clean = strings.TrimPrefix(clean, "http://")
|
||||
clean = strings.TrimSuffix(clean, ".git")
|
||||
clean = strings.ReplaceAll(clean, "/", "_")
|
||||
return clean
|
||||
}
|
||||
|
||||
// CloneOrPull 克隆或更新仓库
|
||||
// 如果仓库不存在则 clone,存在则 pull
|
||||
func CloneOrPull(url, branch string) (string, error) {
|
||||
cachePath, err := config.GetCachePath()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
repoPath := filepath.Join(cachePath, URLToPathName(url))
|
||||
|
||||
// 检查是否已存在
|
||||
if _, err := os.Stat(filepath.Join(repoPath, ".git")); err == nil {
|
||||
// 已存在,执行 pull
|
||||
return repoPath, pullRepo(repoPath, branch)
|
||||
}
|
||||
|
||||
// 不存在,执行 clone
|
||||
return repoPath, cloneRepo(url, branch, repoPath)
|
||||
}
|
||||
|
||||
// cloneRepo 克隆仓库
|
||||
func cloneRepo(url, branch, dest string) error {
|
||||
args := []string{"clone", "--depth", "1"}
|
||||
if branch != "" {
|
||||
args = append(args, "--branch", branch)
|
||||
}
|
||||
args = append(args, url, dest)
|
||||
|
||||
cmd := exec.Command("git", args...)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("git clone 失败: %w\n%s", err, output)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// pullRepo 更新仓库
|
||||
func pullRepo(path, branch string) error {
|
||||
// 先 fetch
|
||||
fetchCmd := exec.Command("git", "-C", path, "fetch", "origin")
|
||||
if output, err := fetchCmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("git fetch 失败: %w\n%s", err, output)
|
||||
}
|
||||
|
||||
// 然后 pull
|
||||
pullArgs := []string{"-C", path, "pull", "origin"}
|
||||
if branch != "" {
|
||||
pullArgs = append(pullArgs, branch)
|
||||
}
|
||||
pullCmd := exec.Command("git", pullArgs...)
|
||||
output, err := pullCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("git pull 失败: %w\n%s", err, output)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetRepoPath 获取仓库缓存路径
|
||||
func GetRepoPath(url string) (string, error) {
|
||||
cachePath, err := config.GetCachePath()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(cachePath, URLToPathName(url)), nil
|
||||
}
|
||||
|
||||
// CloneTemporary 克隆临时仓库到临时目录
|
||||
// 返回临时目录路径和清理函数
|
||||
func CloneTemporary(url, branch string) (repoPath string, cleanup func(), err error) {
|
||||
// 创建临时目录
|
||||
tmpDir, err := os.MkdirTemp("", "skillmgr-temp-*")
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("创建临时目录失败: %w", err)
|
||||
}
|
||||
|
||||
cleanup = func() {
|
||||
os.RemoveAll(tmpDir)
|
||||
}
|
||||
|
||||
// 克隆到临时目录
|
||||
if err := cloneRepo(url, branch, tmpDir); err != nil {
|
||||
cleanup()
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return tmpDir, cleanup, nil
|
||||
}
|
||||
Reference in New Issue
Block a user