Skip to content

Commit

Permalink
playground/server: add server that will generate wasm bundles on demand
Browse files Browse the repository at this point in the history
  • Loading branch information
d4l3k committed Sep 21, 2018
1 parent c7fcb2d commit 752e5be
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 43 deletions.
30 changes: 18 additions & 12 deletions generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import (
type Generator struct {
contexts []pryContext
debug bool
Build build.Context
}

func NewGenerator(debug bool) *Generator {
return &Generator{
debug: debug,
Build: build.Default,
}
}

Expand All @@ -40,9 +42,9 @@ func (g Generator) Debug(templ string, k ...interface{}) {

// ExecuteGoCmd runs the 'go' command with certain parameters.
func (g *Generator) ExecuteGoCmd(ctx context.Context, args []string, env []string) error {
binary, lookErr := exec.LookPath("go")
if lookErr != nil {
panic(lookErr)
binary, err := exec.LookPath("go")
if err != nil {
return err
}

cmd := exec.CommandContext(ctx, binary, args...)
Expand Down Expand Up @@ -77,22 +79,26 @@ func (g *Generator) InjectPry(filePath string) (string, error) {
importStr := imp.Path.Value[1 : len(imp.Path.Value)-1]
if importStr != "../pry" {
dir := filepath.Dir(filePath)
pkg, err := build.Import(importStr, dir, build.AllowBinary)
pkg, err := g.Build.Import(importStr, dir, build.AllowBinary)
if err != nil {
panic(err)
return "", err
}
importName := pkg.Name
if imp.Name != nil {
importName = imp.Name.Name
}
pkgAst, err := parser.ParseDir(fset, pkg.Dir, nil, parser.ParseComments)
if err != nil {
panic(err)
return "", err
}
pair := "\"" + importName + "\": pry.Package{Name: \"" + pkg.Name + "\", Functions: map[string]interface{}{"
added := make(map[string]bool)
for _, nPkg := range pkgAst {
pair += g.GetExports(importName, nPkg, added)
exports, err := g.GetExports(importName, nPkg, added)
if err != nil {
return "", err
}
pair += exports
}
pair += "}}, "
packagePairs = append(packagePairs, pair)
Expand Down Expand Up @@ -167,19 +173,19 @@ func (g *Generator) InjectPry(filePath string) (string, error) {
}

// GetExports returns a string of gocode that represents the exports (constants/functions) of an ast.Package.
func (g *Generator) GetExports(importName string, pkg *ast.Package, added map[string]bool) string {
func (g *Generator) GetExports(importName string, pkg *ast.Package, added map[string]bool) (string, error) {
if pkg.Name == "main" {
return ""
return "", nil
}
vars := ""
for name, file := range pkg.Files {
if strings.HasSuffix(name, "_test.go") {
continue
}

match, err := build.Default.MatchFile(path.Dir(name), path.Base(name))
match, err := g.Build.MatchFile(path.Dir(name), path.Base(name))
if err != nil {
panic(err)
return "", err
}
if !match {
continue
Expand Down Expand Up @@ -261,7 +267,7 @@ func (g *Generator) GetExports(importName string, pkg *ast.Package, added map[st
}
}
}
return vars
return vars, nil
}

// GenerateFile generates a injected file.
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func main() {
}()

if err := run(); err != nil {
log.Fatal("%+v", err)
log.Fatalf("%+v", err)
}
}

Expand Down
5 changes: 2 additions & 3 deletions playground/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ wasm_exec.js
node_modules/
*.wasm
*.gopry
main.go
stdlib.go
server
bundles/
playground
14 changes: 2 additions & 12 deletions playground/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
FROM golang:alpine as base

WORKDIR /go/src/app
COPY . .

RUN go get -d -v ./...
RUN go install -v ./...

RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o server ./server

FROM scratch
COPY --from=base /go/src/app/ /
COPY . /

EXPOSE 8080
CMD ["/server"]
CMD ["/playground"]

15 changes: 8 additions & 7 deletions playground/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
build: wasm_exec.js
yarn install
go install -v ..
go-pry -generate="main.go" -i="fmt,log,math" -e='log.Println("Hello world!")'
GOOS=js GOARCH=wasm go build -v -ldflags "-s -w" -o main.wasm main.go
go-pry -generate="stdlib.go" -i="$(shell tr '\n' ',' < packages.txt)" -e='log.Println("Hello world!")'
GOOS=js GOARCH=wasm go build -v -ldflags "-s -w" -o stdlib.wasm stdlib.go
mkdir -p bundles
go-pry -generate="bundles/main.go" -i="fmt,log,math" -e='log.Println("Hello world!")'
GOOS=js GOARCH=wasm go build -v -ldflags "-s -w" -o bundles/main.wasm bundles/main.go
go-pry -generate="bundles/stdlib.go" -i="$(shell tr '\n' ',' < packages.txt)" -e='log.Println("Hello world!")'
GOOS=js GOARCH=wasm go build -v -ldflags "-s -w" -o bundles/stdlib.wasm bundles/stdlib.go
CGO_ENABLED=0 go build -ldflags "-s -w" -o playground ./server

.PHONY: run
run:
RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o server ./server
./server
run: build
./playground

wasm_exec.js: $(shell go env GOROOT)/misc/wasm/wasm_exec.js
cp $< .
Expand Down
4 changes: 2 additions & 2 deletions playground/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ <h2>go-pry import bundles</h2>
<ul>
<li><a href="/">just fmt,log,math</a></li>
<li>
<a href="/?file=stdlib.wasm">full standard library</a>
<a href="/?file=bundles/stdlib.wasm">full standard library</a>
(~37MB, will take longer to load)
</li>
</ul>
Expand All @@ -76,7 +76,7 @@ <h2>go-pry import bundles</h2>
<script>

const file = (new URL(document.location)).searchParams.get('file')
const wasm = fetch(file || "main.wasm")
const wasm = fetch(file || "bundles/main.wasm")

document.fonts.ready.then(() => {
const term = new Terminal({
Expand Down
9 changes: 4 additions & 5 deletions playground/now.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
{
"name": "go-pry",
"type": "static",
"type": "docker",
"alias": "gopry.rice.sh",
"files": [
"index.html",
"node_modules",
"wasm_exec.js",
"main.wasm",
".main.gopry",
"stdlib.wasm",
".stdlib.gopry"
"bundles",
"playground",
"Dockerfile"
],
"public": true
}
Expand Down
125 changes: 125 additions & 0 deletions playground/server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package main

import (
"crypto/sha256"
"encoding/hex"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"sort"
"strings"

"github.com/d4l3k/go-pry/generate"
"github.com/gorilla/mux"
"github.com/pkg/errors"
)

var bind = flag.String("bind", ":8080", "address to bind to")

func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}

func pkgHash(pkgs []string) string {
hash := sha256.Sum256([]byte(strings.Join(pkgs, ",")))
return hex.EncodeToString(hash[:])
}

func normalizePackages(packages string) []string {
var pkgs []string
for _, pkg := range strings.Split(strings.ToLower(packages), ",") {
pkg = strings.TrimSpace(pkg)
if len(pkg) == 0 {
continue
}
pkgs = append(pkgs, pkg)
}
sort.Strings(pkgs)
return pkgs
}

func generateBundle(w http.ResponseWriter, r *http.Request, packages string) (retErr error) {
pkgs := normalizePackages(packages)
hash := pkgHash(pkgs)
path := filepath.Join("bundles", hash+".wasm")
goPath := filepath.Join("bundles", hash+".go")
_, err := os.Stat(path)
if err == nil {
http.ServeFile(w, r, path)
return nil
} else if !os.IsNotExist(err) {
return err
}

dir, err := ioutil.TempDir("", "pry-playground-gopath")
if err != nil {
return err
}
defer func() {
if err := os.RemoveAll(dir); err != nil {
if retErr == nil {
retErr = err
}
}
}()

env := []string{
fmt.Sprintf("GOPATH=%s", dir),
}

g := generate.NewGenerator(false)
g.Build.GOPATH = dir
g.Build.CgoEnabled = false

for _, pkg := range append([]string{"github.com/d4l3k/go-pry/pry"}, pkgs...) {
if err := g.ExecuteGoCmd(r.Context(), []string{
"get",
pkg,
}, env); err != nil {
return errors.Wrapf(err, "error go get %q", pkg)
}
}

if err := g.GenerateFile(pkgs, "", goPath); err != nil {
return errors.Wrap(err, "GenerateFile")
}

if err := g.ExecuteGoCmd(r.Context(), []string{
"build",
"-ldflags",
"-s -w",
"-o",
path,
goPath,
}, append([]string{
"GOOS=js",
"GOARCH=wasm",
}, env...)); err != nil {
return errors.Wrapf(err, "go build")
}

http.ServeFile(w, r, path)
return nil
}

func run() error {
log.SetFlags(log.Flags() | log.Lshortfile)

router := mux.NewRouter()
router.PathPrefix("/wasm/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pkgs := strings.Join(strings.Split(r.URL.Path, "/")[2:], "/")
if err := generateBundle(w, r, pkgs); err != nil {
http.Error(w, fmt.Sprintf("%+v", err), http.StatusInternalServerError)
}
})
router.NotFoundHandler = http.FileServer(http.Dir("."))

log.Printf("Listening %s...", *bind)
return http.ListenAndServe(*bind, router)
}
2 changes: 1 addition & 1 deletion pry/io_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func readFile(path string) ([]byte, error) {
path = filepath.Base(path)
path = filepath.Join("bundles", filepath.Base(path))

r, w := io.Pipe()
var respCB js.Callback
Expand Down

0 comments on commit 752e5be

Please sign in to comment.