package main import ( "archive/zip" "bufio" "fmt" "io" "io/fs" "os" "path/filepath" "strings" ) // ---- Load ignore patterns ---- func loadIncludePatterns(file string) ([]string, error) { 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() } // ---- 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 for _, pat := range includes { p := filepath.ToSlash(filepath.Clean(pat)) // 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 } // ---- Zip the repo ---- func zipProject(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() err = filepath.WalkDir(srcDir, func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if d.IsDir() { return nil } relPath, _ := filepath.Rel(srcDir, path) if !shouldInclude(relPath, includes) { return nil // skip anything not explicitly included } file, err := os.Open(path) if err != nil { return err } defer file.Close() info, _ := file.Stat() header, _ := zip.FileInfoHeader(info) header.Name = relPath writer, err := archive.CreateHeader(header) if err != nil { return err } _, err = io.Copy(writer, file) fmt.Println("Added:", relPath) return err }) return err }