feat: Phase 1 — 项目骨架搭建,集成 Gin、SQLite 和设置页面
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ReposHandler struct {
|
||||
db *sql.DB
|
||||
reposDir string
|
||||
}
|
||||
|
||||
func NewReposHandler(db *sql.DB, reposDir string) *ReposHandler {
|
||||
return &ReposHandler{db: db, reposDir: reposDir}
|
||||
}
|
||||
|
||||
func (h *ReposHandler) ListRepos(c *gin.Context) {
|
||||
rows, err := h.db.Query(`SELECT id, url, local_path, size_bytes, cloned_at, last_used FROM repositories ORDER BY last_used DESC`)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
var repos []gin.H
|
||||
for rows.Next() {
|
||||
var id int64
|
||||
var url, localPath string
|
||||
var sizeBytes int64
|
||||
var clonedAt, lastUsed string
|
||||
if rows.Scan(&id, &url, &localPath, &sizeBytes, &clonedAt, &lastUsed) == nil {
|
||||
repos = append(repos, gin.H{
|
||||
"id": id, "url": url, "local_path": localPath,
|
||||
"size_bytes": sizeBytes, "cloned_at": clonedAt, "last_used": lastUsed,
|
||||
})
|
||||
}
|
||||
}
|
||||
if repos == nil {
|
||||
repos = []gin.H{}
|
||||
}
|
||||
c.JSON(http.StatusOK, repos)
|
||||
}
|
||||
|
||||
func (h *ReposHandler) DeleteRepo(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var localPath string
|
||||
err := h.db.QueryRow(`SELECT local_path FROM repositories WHERE id = ?`, id).Scan(&localPath)
|
||||
if err == sql.ErrNoRows {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "repository not found"})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
// Remove from filesystem
|
||||
os.RemoveAll(localPath)
|
||||
// Remove from database
|
||||
h.db.Exec(`DELETE FROM analyses WHERE repo_id = ?`, id)
|
||||
h.db.Exec(`DELETE FROM repositories WHERE id = ?`, id)
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
func (h *ReposHandler) CleanupRepos(c *gin.Context) {
|
||||
// Get max age from settings
|
||||
var maxAgeDays string
|
||||
h.db.QueryRow(`SELECT value FROM settings WHERE key = 'cache.max_age_days'`).Scan(&maxAgeDays)
|
||||
if maxAgeDays == "" {
|
||||
maxAgeDays = "7"
|
||||
}
|
||||
// Find expired repos
|
||||
rows, err := h.db.Query(`SELECT id, local_path FROM repositories WHERE last_used < datetime('now', '-' || ? || ' days')`, maxAgeDays)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
var cleaned []int64
|
||||
for rows.Next() {
|
||||
var id int64
|
||||
var localPath string
|
||||
if rows.Scan(&id, &localPath) == nil {
|
||||
os.RemoveAll(localPath)
|
||||
h.db.Exec(`DELETE FROM analyses WHERE repo_id = ?`, id)
|
||||
h.db.Exec(`DELETE FROM repositories WHERE id = ?`, id)
|
||||
cleaned = append(cleaned, id)
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"cleaned": cleaned})
|
||||
}
|
||||
|
||||
// CloneRepo handles POST /api/repos — stub for Phase 2
|
||||
func (h *ReposHandler) CloneRepo(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "clone not implemented yet — coming in Phase 2"})
|
||||
}
|
||||
|
||||
// GetGraph handles GET /api/repos/:id/graph — stub for Phase 2
|
||||
func (h *ReposHandler) GetGraph(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "graph not implemented yet — coming in Phase 2"})
|
||||
}
|
||||
|
||||
// GetDiff handles GET /api/repos/:id/diff — stub for Phase 2
|
||||
func (h *ReposHandler) GetDiff(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, gin.H{"error": "diff not implemented yet — coming in Phase 2"})
|
||||
}
|
||||
|
||||
// dirSize returns the total size of a directory in bytes
|
||||
func dirSize(path string) int64 {
|
||||
var size int64
|
||||
filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
|
||||
if err != nil || info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
size += info.Size()
|
||||
return nil
|
||||
})
|
||||
return size
|
||||
}
|
||||
Reference in New Issue
Block a user