package git import ( "bytes" "context" "fmt" "io" "os/exec" "regexp" ) var ValidRef = regexp.MustCompile(`^[A-Za-z0-9._/-]+$`) var ErrInvalidRef = fmt.Errorf("Invalid ref.") // verifies if a reference (hash) exists. Will error if not. func RefExists(ctx context.Context, repoPath, ref string) error { if !ValidRef.MatchString(ref) { return ErrInvalidRef } cmd := exec.CommandContext(ctx, "git", "rev-parse", "--verify", "--quiet", ref+"^{commit}") cmd.Dir = repoPath if err := cmd.Run(); err != nil { return fmt.Errorf("ref %q not found: %w", ref, err) } return nil } // uses git's `git archive --format=zip` to create a zip archive and streams it. func ZipStream(ctx context.Context, repoPath, ref string, w io.Writer) error { if !ValidRef.MatchString(ref) { return ErrInvalidRef } cmd := exec.CommandContext(ctx, "git", "archive", "--format=zip", "--", ref+"^{commit}") cmd.Dir = repoPath // repo itself cmd.Stdout = w // could be the http writer var stderr bytes.Buffer cmd.Stderr = &stderr if err := cmd.Run(); err != nil { return fmt.Errorf("git archive failed: %w: %s", err, stderr.String()) } return nil }