supabase-cli/pkg/function/bundle.go

71 lines
1.8 KiB
Go

package function
import (
"context"
"fmt"
"io"
"io/fs"
"os"
"os/exec"
"path/filepath"
"github.com/andybalholm/brotli"
"github.com/go-errors/errors"
)
type nativeBundler struct {
tempDir string
fsys fs.FS
}
func NewNativeBundler(tempDir string, fsys fs.FS) EszipBundler {
return &nativeBundler{
tempDir: tempDir,
fsys: fsys,
}
}
// Use a package private variable to allow testing without gosec complaining about G204
var edgeRuntimeBin = "edge-runtime"
func (b *nativeBundler) Bundle(ctx context.Context, entrypoint string, importMap string, staticFiles []string, output io.Writer) error {
slug := filepath.Base(filepath.Dir(entrypoint))
outputPath := filepath.Join(b.tempDir, slug+".eszip")
// TODO: make edge runtime write to stdout
args := []string{"bundle", "--entrypoint", entrypoint, "--output", outputPath}
if len(importMap) > 0 {
args = append(args, "--import-map", importMap)
}
for _, staticFile := range staticFiles {
args = append(args, "--static", staticFile)
}
cmd := exec.CommandContext(ctx, edgeRuntimeBin, args...)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
if err := cmd.Run(); err != nil {
return errors.Errorf("failed to bundle function: %w", err)
}
defer os.Remove(outputPath)
// Compress the output
eszipBytes, err := b.fsys.Open(outputPath)
if err != nil {
return errors.Errorf("failed to open eszip: %w", err)
}
defer eszipBytes.Close()
return Compress(eszipBytes, output)
}
const compressedEszipMagicID = "EZBR"
func Compress(r io.Reader, w io.Writer) error {
if _, err := fmt.Fprint(w, compressedEszipMagicID); err != nil {
return errors.Errorf("failed to append magic id: %w", err)
}
brw := brotli.NewWriter(w)
defer brw.Close()
if _, err := io.Copy(brw, r); err != nil {
return errors.Errorf("failed to compress eszip: %w", err)
}
return nil
}