feat(controller): added copy by server only currently
This commit is contained in:
@@ -8,92 +8,155 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
socketio "github.com/googollee/go-socket.io"
|
||||
)
|
||||
|
||||
// ---- Load ignore patterns ----
|
||||
func loadIncludePatterns(file string) ([]string, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var patterns []string
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
patterns = append(patterns, filepath.ToSlash(filepath.Clean(line)))
|
||||
}
|
||||
return patterns, scanner.Err()
|
||||
var patterns []string
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
patterns = append(patterns, filepath.ToSlash(filepath.Clean(line)))
|
||||
}
|
||||
return patterns, scanner.Err()
|
||||
}
|
||||
|
||||
// ---- Simple matcher ----
|
||||
// (Later swap for github.com/sabhiram/go-gitignore lib for proper rules)
|
||||
func shouldInclude(path string, includes []string) bool {
|
||||
cleanPath := filepath.ToSlash(filepath.Clean(path)) // normalize to forward slashes
|
||||
cleanPath := filepath.ToSlash(filepath.Clean(path)) // normalize to forward slashes
|
||||
|
||||
for _, pat := range includes {
|
||||
p := filepath.ToSlash(filepath.Clean(pat))
|
||||
for _, pat := range includes {
|
||||
p := filepath.ToSlash(filepath.Clean(pat))
|
||||
|
||||
// exact match (file or folder)
|
||||
if cleanPath == p {
|
||||
return true
|
||||
}
|
||||
// exact match (file or folder)
|
||||
if cleanPath == p {
|
||||
return true
|
||||
}
|
||||
|
||||
// if p is a folder, include all paths under it
|
||||
if strings.HasPrefix(cleanPath, p+"/") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
// if p is a folder, include all paths under it
|
||||
if strings.HasPrefix(cleanPath, p+"/") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ---- Zip the repo ----
|
||||
func zipProject(srcDir, zipFile string, includes []string) error {
|
||||
outFile, err := os.Create(zipFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outFile.Close()
|
||||
func zipProject(server *socketio.Server, srcDir, zipFile string, includes []string) error {
|
||||
outFile, err := os.Create(zipFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
archive := zip.NewWriter(outFile)
|
||||
defer archive.Close()
|
||||
archive := zip.NewWriter(outFile)
|
||||
defer archive.Close()
|
||||
|
||||
err = filepath.WalkDir(srcDir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
err = filepath.WalkDir(srcDir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
server.BroadcastToRoom("/", "build", "buildlogs", fmt.Sprintf("❌ Error walking %s: %v", path, err))
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
relPath, _ := filepath.Rel(srcDir, path)
|
||||
if !shouldInclude(relPath, includes) {
|
||||
return nil // skip anything not explicitly included
|
||||
}
|
||||
relPath, _ := filepath.Rel(srcDir, path)
|
||||
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
// only include files matching your patterns
|
||||
if !shouldInclude(relPath, includes) {
|
||||
return nil
|
||||
}
|
||||
|
||||
info, _ := file.Stat()
|
||||
header, _ := zip.FileInfoHeader(info)
|
||||
header.Name = relPath
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
server.BroadcastToRoom("/", "build", "buildlogs", fmt.Sprintf("❌ Could not open: %s", relPath))
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
writer, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(writer, file)
|
||||
fmt.Println("Added:", relPath)
|
||||
return err
|
||||
})
|
||||
info, _ := file.Stat()
|
||||
header, _ := zip.FileInfoHeader(info)
|
||||
header.Name = relPath
|
||||
|
||||
return err
|
||||
writer, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
server.BroadcastToRoom("/", "build", "buildlogs", fmt.Sprintf("❌ Could not add header for: %s", relPath))
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := io.Copy(writer, file); err != nil {
|
||||
server.BroadcastToRoom("/", "build", "buildlogs", fmt.Sprintf("❌ Error zipping: %s", relPath))
|
||||
return err
|
||||
}
|
||||
|
||||
// ✅ Send progress back to clients
|
||||
server.BroadcastToRoom("/", "build", "buildlogs", fmt.Sprintf("📦 Added: %s", relPath))
|
||||
return nil
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
server.BroadcastToRoom("/", "build", "buildlogs", fmt.Sprintf("✅ Archive created: %s", zipFile))
|
||||
doCleanup(server, filepath.Dir(zipFile))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func doCleanup(server *socketio.Server, dir string) {
|
||||
// read max builds from env
|
||||
maxStr := os.Getenv("MAX_BUILDS")
|
||||
if maxStr == "" {
|
||||
return
|
||||
}
|
||||
maxBuilds, err := strconv.Atoi(maxStr)
|
||||
if err != nil || maxBuilds <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var files []os.FileInfo
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() && strings.HasSuffix(e.Name(), ".zip") {
|
||||
info, err := e.Info()
|
||||
if err == nil {
|
||||
files = append(files, info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by modification time newest → oldest
|
||||
sort.Slice(files, func(i, j int) bool {
|
||||
return files[i].ModTime().After(files[j].ModTime())
|
||||
})
|
||||
|
||||
// Delete extras
|
||||
if len(files) > maxBuilds {
|
||||
for _, f := range files[maxBuilds:] {
|
||||
toDelete := filepath.Join(dir, f.Name())
|
||||
if err := os.Remove(toDelete); err == nil {
|
||||
server.BroadcastToRoom("/", "build", "buildlogs",
|
||||
fmt.Sprintf("🧹 Removed old build: %s", f.Name()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user