on master help sign in
- Add exec-style languages

- Add NodeJS - Add static file packing framework - Refactor argument parsing

commite8e8b23444cea3834f786e948dabaed64974baab authorRob Blanckaert <basicer@basicer.com> dateTue 6 Nov 2018, 18:10 (8 years ago) parent4c14c51
13 files changed+174−62
.dockerignore+1−1 .gitignore+2−1 Dockerfile+1−1 Makefile+4−3 README.md+1−2 inject_launch.go → inject_claunch.go inject_elaunch.go+8 languages/nodejs/main.go+73 languages/nodejs/repl.js+8 languages/nodejs/version.js+1 scripts/gofiles.sh+30 scripts/inject.sh+10 utils/utils.go+35−54
.dockerignore+1−1
@@ -1,4 +1,4 @@
1−prybar
1+prybar-*
22plugins
33Dockerfile
44extract.sh
.gitignore+2−1
@@ -1,4 +1,5 @@
11plugins/
2−prybar
2+prybar-*
33deps.lst
44prybar.tar.gz
5+generated_*.go
Dockerfile+1−1
@@ -24,7 +24,7 @@ ENV GOPATH=/gocode
2424ADD . /gocode/src/github.com/replit/prybar
2525WORKDIR /gocode/src/github.com/replit/prybar
2626
27−RUN make prybar-python2 prybar-python3 prybar-ruby prybar-lua prybar-spidermonkey
27+RUN make prybar-python2 prybar-python3 prybar-ruby prybar-lua prybar-spidermonkey prybar-nodejs
2828RUN make test
2929
3030ENV LC_ALL=C.UTF-8
Makefile+4−3
@@ -7,12 +7,13 @@ BINS := $(addprefix prybar-,$(LANGS))
77all: $(BINS)
88
99prybar-%: ./languages/$(*) ./utils/* ./linenoise/* ./languages/$(*)/*
10− cp inject_launch.go ./languages/$(*)/inject_launch.go
10+ ./scripts/inject.sh $(*)
11+ go generate ./languages/$(*)/main.go
1112 CGO_LDFLAGS_ALLOW=".*" go build -o prybar-$(*) ./languages/$(*)
12− rm ./languages/$(*)/inject_launch.go
13+ rm ./languages/$(*)/generated_*.go
1314
1415test:
1516 ./run_tests
1617
1718clean:
18− @rm ./prybar-*
19+ @rm ./prybar-* ./languages/*/generated_*.go
README.md+1−2
@@ -15,8 +15,7 @@ a select language backend. The language backends are implemented using cgo and t
1515## Usage
1616
1717```
18−Usage of ./prybar:
19− -C colorize stderr
18+Usage of ./prybar-language:
2019 -I like -i, but never use language REPL
2120 -c string
2221 code to run
inject_launch.go → inject_claunch.gorenamed

The content is the same.

inject_elaunch.gonew file+8
@@ -0,0 +1,8 @@
1+// this file will be injected into a language's main package at build.
2+package main
3+
4+import "github.com/replit/prybar/utils"
5+
6+func main() {
7+ Execute(utils.ParseFlags())
8+}
languages/nodejs/main.gonew file+73
@@ -0,0 +1,73 @@
1+package main
2+
3+//go:generate ../../scripts/gofiles.sh generated_files.go
4+
5+import (
6+ "io/ioutil"
7+ "os"
8+ "os/exec"
9+ "syscall"
10+ "github.com/replit/prybar/utils"
11+)
12+
13+func findHelper(path string) string {
14+ bytes, err := File(path)
15+ if bytes != nil {
16+ f, err := ioutil.TempFile("", "prybar-nodejs-*.js")
17+ if err != nil {
18+ panic(err)
19+ }
20+
21+ if _, err = f.Write(bytes); err != nil {
22+ panic(err)
23+ }
24+ if err = f.Close(); err != nil {
25+ panic(err)
26+ }
27+ return f.Name()
28+ }
29+ if err != nil {
30+ panic(err)
31+ }
32+ return "./languages/nodejs/" + path + ".js"
33+}
34+
35+func Execute(config *utils.Config) {
36+ path, err := exec.LookPath("node")
37+
38+ if err != nil {
39+ panic(err)
40+ }
41+
42+ env := os.Environ()
43+ args := []string{"node"}
44+
45+ if !config.Quiet {
46+ args = append(args, "-r", findHelper("version"))
47+
48+ }
49+
50+ if config.Code != "" {
51+ args = append(args, "-e", config.Code)
52+ }
53+
54+ if config.Exp != "" {
55+ args = append(args, "-p", config.Exp)
56+ }
57+
58+ if config.Interactive {
59+ args = append(args, "-r", findHelper("repl"))
60+ }
61+
62+ if config.Ps1 != "" {
63+ env = append(env, "NODE_PROMPT="+config.Ps1)
64+ }
65+
66+ if config.Args != nil && len(config.Args) > 0 {
67+ args = append(args, config.Args...)
68+ } else if config.Exp == "" && config.Code == "" {
69+ args = append(args, "-e", "")
70+ }
71+
72+ syscall.Exec(path, args, env)
73+}
languages/nodejs/repl.jsnew file+8
@@ -0,0 +1,8 @@
1+var repl = require('repl');
2+var exit = require('async-exit-hook');
3+
4+
5+exit((reallyExit) => {
6+ let r = repl.start(process.env.NODE_PROMPT || '> ');
7+ r.on('exit', reallyExit);
8+});
languages/nodejs/version.jsnew file+1
@@ -0,0 +1 @@
1+console.log('Node ' + process.version + ' on ' + process.platform);
scripts/gofiles.shnew file+30
@@ -0,0 +1,30 @@
1+#!/bin/bash
2+
3+cat << EOF > $1
4+// generated by $0 $*; DO NOT EDIT
5+
6+package main
7+
8+import "encoding/base64"
9+
10+func File(name string) ([]byte, error) {
11+
12+ switch name {
13+
14+EOF
15+
16+for fn in $(ls *.js); do
17+
18+ echo " case \"$fn\":" >> $1
19+ echo " return base64.StdEncoding.DecodeString(\"$(base64 -i $fn | tr -d \\n)\")" >> $1
20+
21+done
22+
23+cat << EOF >> $1
24+
25+ }
26+ return nil, nil
27+}
28+EOF
29+
30+echo "Generated $(realpath $1)"
scripts/inject.shnew file+10
@@ -0,0 +1,10 @@
1+#!/bin/bash
2+
3+if grep "#cgo pkg-config" ./languages/$1/main.go; then
4+ cp inject_claunch.go ./languages/$1/generated_launch.go
5+else
6+ cp inject_elaunch.go ./languages/$1/generated_launch.go
7+fi
8+
9+
10+
utils/utils.go+35−54
@@ -3,88 +3,69 @@ package utils
33import (
44 "flag"
55 "fmt"
6− "io"
76 "os"
87 "runtime"
9− "syscall"
108)
119
12−type Red struct {
13− parent io.Writer
10+type Config struct {
11+ Code string
12+ Quiet bool
13+ Exp string
14+ Ps1, Ps2 string
15+ Args []string
16+ Interactive, OurInteractive bool
1417}
1518
16−func (r *Red) Write(p []byte) (n int, err error) {
17− r.parent.Write(([]byte("\033[31m")))
18− n, err = r.parent.Write(p)
19− r.parent.Write(([]byte("\033[0m")))
20− return n, err
21−}
19+func ParseFlags() *Config {
20+ config := &Config{}
2221
23−func DoCli(p PluginBase) {
24− var interactive, ourInteractive bool
25− var code string
26− var quiet bool
27− var exp string
28− var colorizeStderr bool
29− var ps1, ps2 string
22+ flag.StringVar(&config.Code, "c", "", "code to run")
23+ flag.StringVar(&config.Exp, "e", "", "expression to print")
3024
31− flag.StringVar(&code, "c", "", "code to run")
32− flag.StringVar(&exp, "e", "", "expression to print")
25+ flag.StringVar(&config.Ps1, "ps1", "--> ", "PS1")
26+ flag.StringVar(&config.Ps2, "ps2", "... ", "PS2")
3327
34− flag.StringVar(&ps1, "ps1", "--> ", "PS1")
35− flag.StringVar(&ps2, "ps2", "... ", "PS2")
28+ flag.BoolVar(&config.Interactive, "i", false, "interactive")
29+ flag.BoolVar(&config.OurInteractive, "I", false, "like -i, but never use language REPL")
30+ flag.BoolVar(&config.Quiet, "q", false, "quiet")
3631
37− flag.BoolVar(&interactive, "i", false, "interactive")
38− flag.BoolVar(&ourInteractive, "I", false, "like -i, but never use language REPL")
39− flag.BoolVar(&quiet, "q", false, "quiet")
32+ flag.Parse()
4033
41− flag.BoolVar(&colorizeStderr, "R", false, "color standard error red")
34+ config.Args = flag.Args()
35+ return config
36+}
4237
43− flag.Parse()
38+func DoCli(p PluginBase) {
4439
45− args := flag.Args()
40+ config := ParseFlags()
4641
4742 runtime.LockOSThread()
4843 p.Open()
49− lang := &Language{ptr: p, ps1: ps1}
44+ lang := &Language{ptr: p, ps1: config.Ps1}
5045
51− if !quiet {
46+ if !config.Quiet {
5247 fmt.Println(lang.Version())
5348 }
5449
55− if colorizeStderr {
56− var pipes [2]int
57− newStderr, err := syscall.Dup(2)
58− if err != nil {
59− panic(err)
60− }
61− syscall.Pipe(pipes[:])
62− syscall.Dup2(pipes[1], 2)
63− syscall.Close(pipes[1])
64− o := &Red{parent: os.NewFile(uintptr(newStderr), "o")}
65− i := os.NewFile(uintptr(pipes[0]), "i")
66− go io.Copy(o, i)
67− }
68−
69− if code != "" {
70− lang.Eval(code)
50+ if config.Code != "" {
51+ lang.Eval(config.Code)
7152 }
72− if exp != "" {
73− lang.EvalAndTryToPrint(exp)
53+ if config.Exp != "" {
54+ lang.EvalAndTryToPrint(config.Exp)
7455 }
75− if len(args) > 0 {
76− if _, err := os.Stat(args[0]); os.IsNotExist(err) {
77− fmt.Println("No such file:", args[0])
56+ if len(config.Args) > 0 {
57+ if _, err := os.Stat(config.Args[0]); os.IsNotExist(err) {
58+ fmt.Println("No such file:", config.Args[0])
7859 os.Exit(2)
7960 } else {
80− lang.EvalFile(args[0], args[1:])
61+ lang.EvalFile(config.Args[0], config.Args[1:])
8162 }
8263 }
8364
84− if interactive {
85− lang.SetPrompts(ps1, ps2)
65+ if config.Interactive {
66+ lang.SetPrompts(config.Ps1, config.Ps2)
8667 lang.REPL()
87− } else if ourInteractive {
68+ } else if config.OurInteractive {
8869 //LinenoiseSetCompleter(func(s string) []string {
8970 // return []string{s + "A", s + "B", s + "B"}
9071 //})