Bundle Puppeteer Dependency
This commit is contained in:
104
internal/dependencies.go
Normal file
104
internal/dependencies.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/sha256"
|
||||
_ "embed"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:embed assets/node_modules.tar.gz
|
||||
var embeddedNodeModules []byte
|
||||
|
||||
// ensureEmbeddedNodeModules extracts the bundled Node.js dependencies into a
|
||||
// deterministic cache directory derived from the archive hash and returns the
|
||||
// path that contains the resulting node_modules directory.
|
||||
func ensureEmbeddedNodeModules() (string, error) {
|
||||
if len(embeddedNodeModules) == 0 {
|
||||
return "", errors.New("no embedded node modules archive available")
|
||||
}
|
||||
|
||||
sum := sha256.Sum256(embeddedNodeModules)
|
||||
hashPrefix := hex.EncodeToString(sum[:8])
|
||||
|
||||
cacheRoot, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
cacheRoot = os.TempDir()
|
||||
}
|
||||
baseDir := filepath.Join(cacheRoot, "streamed-tui", "node_modules", hashPrefix)
|
||||
|
||||
marker := filepath.Join(baseDir, ".complete")
|
||||
if _, err := os.Stat(marker); err == nil {
|
||||
return baseDir, nil
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(baseDir); err != nil {
|
||||
return "", fmt.Errorf("failed to clear embedded node cache: %w", err)
|
||||
}
|
||||
if err := os.MkdirAll(baseDir, 0o755); err != nil {
|
||||
return "", fmt.Errorf("failed to create embedded node cache: %w", err)
|
||||
}
|
||||
|
||||
if err := untarGzip(bytes.NewReader(embeddedNodeModules), baseDir); err != nil {
|
||||
return "", fmt.Errorf("failed to extract embedded node modules: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(marker, []byte(time.Now().Format(time.RFC3339)), 0o644); err != nil {
|
||||
return "", fmt.Errorf("failed to mark embedded node modules ready: %w", err)
|
||||
}
|
||||
|
||||
return baseDir, nil
|
||||
}
|
||||
|
||||
func untarGzip(r io.Reader, dest string) error {
|
||||
gz, err := gzip.NewReader(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gz.Close()
|
||||
|
||||
tr := tar.NewReader(gz)
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
target := filepath.Join(dest, hdr.Name)
|
||||
switch hdr.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.MkdirAll(target, os.FileMode(hdr.Mode)); err != nil {
|
||||
return err
|
||||
}
|
||||
case tar.TypeReg:
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(hdr.Mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.Copy(f, tr); err != nil {
|
||||
f.Close()
|
||||
return err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
// Ignore unsupported entries to keep extraction simple.
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user