Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 2 additions & 106 deletions internal/analyze/zip.go
Original file line number Diff line number Diff line change
@@ -1,111 +1,7 @@
package analyze

import (
"archive/zip"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
)
import "github.com/supermodeltools/cli/internal/archive"

// skipDirs are directory names that should never be included in the archive.
var skipDirs = map[string]bool{
".git": true,
"node_modules": true,
"vendor": true,
"__pycache__": true,
".venv": true,
"venv": true,
"dist": true,
"build": true,
"target": true,
".next": true,
".nuxt": true,
"coverage": true,
".terraform": true,
".tox": true,
}

// createZip archives the repository at dir into a temporary ZIP file and
// returns its path. The caller is responsible for removing the file.
//
// Strategy: use git archive when inside a Git repo (respects .gitignore,
// deterministic output). Falls back to a manual directory walk otherwise.
func createZip(dir string) (string, error) {
f, err := os.CreateTemp("", "supermodel-*.zip")
if err != nil {
return "", fmt.Errorf("create temp file: %w", err)
}
dest := f.Name()
f.Close()

if isGitRepo(dir) {
if err := gitArchive(dir, dest); err == nil {
return dest, nil
}
}

if err := walkZip(dir, dest); err != nil {
os.Remove(dest)
return "", err
}
return dest, nil
}

func isGitRepo(dir string) bool {
cmd := exec.Command("git", "-C", dir, "rev-parse", "--git-dir")
cmd.Stdout = io.Discard
cmd.Stderr = io.Discard
return cmd.Run() == nil
}

func gitArchive(dir, dest string) error {
cmd := exec.Command("git", "-C", dir, "archive", "--format=zip", "-o", dest, "HEAD")
cmd.Stderr = os.Stderr
return cmd.Run()
}

// walkZip creates a ZIP of dir, excluding skipDirs, hidden files, and
// files larger than 10 MB.
func walkZip(dir, dest string) error {
out, err := os.Create(dest)
if err != nil {
return err
}
defer out.Close()

zw := zip.NewWriter(out)
defer zw.Close()

return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
rel, err := filepath.Rel(dir, path)
if err != nil {
return err
}
if info.IsDir() {
if skipDirs[info.Name()] {
return filepath.SkipDir
}
return nil
}
if strings.HasPrefix(info.Name(), ".") || info.Size() > 10<<20 {
return nil
}
w, err := zw.Create(filepath.ToSlash(rel))
if err != nil {
return err
}
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(w, f)
return err
})
return archive.CreateZip(dir)
}
10 changes: 6 additions & 4 deletions internal/analyze/zip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"path/filepath"
"strings"
"testing"

"github.com/supermodeltools/cli/internal/archive"
)

func TestIsGitRepo_WithDotGit(t *testing.T) {
Expand All @@ -17,7 +19,7 @@ func TestIsGitRepo_WithDotGit(t *testing.T) {
// isGitRepo uses `git rev-parse --git-dir` which needs an actual git repo;
// fall back to checking directory creation only — the factory version
// (os.Stat) is simpler, but here we just ensure non-git dir returns false.
if isGitRepo(t.TempDir()) {
if archive.IsGitRepo(t.TempDir()) {
t.Error("empty temp dir should not be a git repo")
}
}
Expand All @@ -29,7 +31,7 @@ func TestWalkZip_IncludesFiles(t *testing.T) {
}

dest := filepath.Join(t.TempDir(), "out.zip")
if err := walkZip(src, dest); err != nil {
if err := archive.WalkZip(src, dest); err != nil {
t.Fatalf("walkZip: %v", err)
}
entries := readZipEntries(t, dest)
Expand All @@ -48,7 +50,7 @@ func TestWalkZip_SkipsHiddenFiles(t *testing.T) {
}

dest := filepath.Join(t.TempDir(), "out.zip")
if err := walkZip(src, dest); err != nil {
if err := archive.WalkZip(src, dest); err != nil {
t.Fatal(err)
}
entries := readZipEntries(t, dest)
Expand All @@ -74,7 +76,7 @@ func TestWalkZip_SkipsSkipDirs(t *testing.T) {
}

dest := filepath.Join(t.TempDir(), "out.zip")
if err := walkZip(src, dest); err != nil {
if err := archive.WalkZip(src, dest); err != nil {
t.Fatal(err)
}
entries := readZipEntries(t, dest)
Expand Down
108 changes: 2 additions & 106 deletions internal/archdocs/zip.go
Original file line number Diff line number Diff line change
@@ -1,111 +1,7 @@
package archdocs

import (
"archive/zip"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
)
import "github.com/supermodeltools/cli/internal/archive"

// skipDirs are directory names that should never be included in the archive.
var skipDirs = map[string]bool{
".git": true,
"node_modules": true,
"vendor": true,
"__pycache__": true,
".venv": true,
"venv": true,
"dist": true,
"build": true,
"target": true,
".next": true,
".nuxt": true,
"coverage": true,
".terraform": true,
".tox": true,
}

// createZip archives the repository at dir into a temporary ZIP file and
// returns its path. The caller is responsible for removing the file.
//
// Strategy: use git archive when inside a Git repo (respects .gitignore,
// deterministic output). Falls back to a manual directory walk otherwise.
func createZip(dir string) (string, error) {
f, err := os.CreateTemp("", "supermodel-*.zip")
if err != nil {
return "", fmt.Errorf("create temp file: %w", err)
}
dest := f.Name()
f.Close()

if isGitRepo(dir) {
if err := gitArchive(dir, dest); err == nil {
return dest, nil
}
}

if err := walkZip(dir, dest); err != nil {
os.Remove(dest)
return "", err
}
return dest, nil
}

func isGitRepo(dir string) bool {
cmd := exec.Command("git", "-C", dir, "rev-parse", "--git-dir")
cmd.Stdout = io.Discard
cmd.Stderr = io.Discard
return cmd.Run() == nil
}

func gitArchive(dir, dest string) error {
cmd := exec.Command("git", "-C", dir, "archive", "--format=zip", "-o", dest, "HEAD")
cmd.Stderr = os.Stderr
return cmd.Run()
}

// walkZip creates a ZIP of dir, excluding skipDirs, hidden files, and
// files larger than 10 MB.
func walkZip(dir, dest string) error {
out, err := os.Create(dest)
if err != nil {
return err
}
defer out.Close()

zw := zip.NewWriter(out)
defer zw.Close()

return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
rel, err := filepath.Rel(dir, path)
if err != nil {
return err
}
if info.IsDir() {
if skipDirs[info.Name()] {
return filepath.SkipDir
}
return nil
}
if strings.HasPrefix(info.Name(), ".") || info.Size() > 10<<20 {
return nil
}
w, err := zw.Create(filepath.ToSlash(rel))
if err != nil {
return err
}
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(w, f)
return err
})
return archive.CreateZip(dir)
}
Loading
Loading