on master help sign in
Merge pull request #1 from replit/mc-masonstuff

build a binary for each language

commitbd47c67705348269524e83d77ace10efc36f0c97 authorMason Clayton <masongclayton@gmail.com> dateSat 20 Oct 2018, 01:05 (8 years ago) parent11abce958a3873
30 files changed+105−200
Dockerfile+23−8 Makefile+10−14 README.md+4−8 extract.sh+1−1 inject_launch.go+8 src/languages/R/main.go → languages/R/main.go+3−8 src/languages/lua/lua.c → languages/lua/lua.c src/languages/lua/main.go → languages/lua/main.go+8−12 src/languages/lua/pry.c → languages/lua/pry.c src/languages/lua/pry.h → languages/lua/pry.h src/languages/python2/main.go → languages/python2/main.go+2−4 src/languages/python2/pry_python2.c → languages/python2/pry_python2.c src/languages/python2/pry_python2.h → languages/python2/pry_python2.h src/languages/python3/main.go → languages/python3/main.go+2−4 src/languages/python3/pry_python3.c → languages/python3/pry_python3.c src/languages/python3/pry_python3.h → languages/python3/pry_python3.h src/languages/ruby/main.go → languages/ruby/main.go+1−4 src/languages/ruby/pry_ruby.c → languages/ruby/pry_ruby.c src/languages/ruby/pry_ruby.h → languages/ruby/pry_ruby.h src/languages/spidermonkey/main.go → languages/spidermonkey/main.go+8−15 src/languages/tcl/main.go → languages/tcl/main.go+7−9 src/languages/tcl/pry_tcl.c → languages/tcl/pry_tcl.c src/languages/tcl/pry_tcl.h → languages/tcl/pry_tcl.h src/linenoise-helper.c → linenoise/linenoise-helper.c+2−3 src/linenoise.c → linenoise/linenoise.c+1−1 src/linenoise.go → linenoise/linenoise.go+5−7 src/linenoise.h → linenoise/linenoise.h mk-deps.sh−22 src/language.go → utils/language.go+15−61 src/main.go → utils/utils.go+5−19
Dockerfile+23−8
@@ -1,17 +1,32 @@
11FROM ubuntu:bionic
22
33RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
4−build-essential wget golang python-dev python3-dev liblua5.2-dev \
5−ruby2.5-dev tcl-dev libnspr4-dev libffi-dev
4+ build-essential \
5+ wget \
6+ golang \
7+ python-dev \
8+ python3-dev \
9+ liblua5.2-dev \
10+ ruby2.5-dev \
11+ tcl-dev \
12+ libnspr4-dev \
13+ libffi-dev
614
7−RUN wget http://launchpadlibrarian.net/309343864/libmozjs185-dev_1.8.5-1.0.0+dfsg-7_amd64.deb && wget http://launchpadlibrarian.net/309343863/libmozjs185-1.0_1.8.5-1.0.0+dfsg-7_amd64.deb && dpkg -i libmozjs185*.deb && rm libmozjs185*.deb
15+RUN wget \
16+ http://launchpadlibrarian.net/309343864/libmozjs185-dev_1.8.5-1.0.0+dfsg-7_amd64.deb && \
17+ wget http://launchpadlibrarian.net/309343863/libmozjs185-1.0_1.8.5-1.0.0+dfsg-7_amd64.deb && \
18+ dpkg -i libmozjs185*.deb && rm libmozjs185*.deb
819
9−ADD . /prybar
10−RUN cd /prybar && make
20+RUN mkdir -p /gocode/src/github.com/replit/prybar
1121
12−WORKDIR /prybar
22+ENV GOPATH=/gocode
23+
24+ADD . /gocode/src/github.com/replit/prybar
25+
26+WORKDIR /gocode/src/github.com/replit/prybar
27+
28+RUN make prybar-python2 prybar-python3 prybar-ruby prybar-lua prybar-spidermonkey
1329
1430ENV LC_ALL=C.UTF-8
1531
16−ENTRYPOINT [ "/prybar/prybar" ]
17−CMD [ "-h" ]
32+CMD bash
Makefile+10−14
@@ -1,19 +1,15 @@
1−.PHONY: clean default
2−
3−default: prybar
1+LANGDIR := ./languages
2+LANGS := $(shell ls $(LANGDIR))
3+BINS := $(addprefix prybar-,$(LANGS))
44
5−deps.lst: mk-deps.sh
6− ./mk-deps.sh > deps.lst
7−
8−-include deps.lst
5+.PHONY: clean default
96
10−prybar: src/*.go $(plugins)
11− cd src && go build -o ../prybar
7+default: $(BINS)
128
13−plugins/%.so: src/languages/%/*.*
14− cd src/languages/$* && CGO_LDFLAGS_ALLOW=".*" go build -buildmode=plugin -o ../../../$@
9+prybar-%: ./languages/$(*) ./utils/* ./linenoise/* ./languages/$(*)/*
10+ cp inject_launch.go ./languages/$(*)/inject_launch.go
11+ CGO_LDFLAGS_ALLOW=".*" go build -o prybar-$(*) ./languages/$(*)
12+ rm ./languages/$(*)/inject_launch.go
1513
1614clean:
17− @rm deps.lst
18− @rm prybar
19− @rm plugins/*
15+ @rm ./prybar-*
README.md+4−8
@@ -1,6 +1,6 @@
11# ![Prybar](logo.svg)
22
3−Prybar is a universal interpreter front-end. Same interface, same REPL, different languages.
3+Prybar is a universal interpreter front-end. Same interface, same REPL, different languages.
44
55## Why
66
@@ -9,7 +9,7 @@ every language implements them differently. We wanted them to all behave the sam
99
1010## How it works
1111
12−Prybar, written in Golang, maintains a common command-line interface that calls into
12+Prybar, written in Golang, maintains a common command-line interface that calls into
1313a select language backend. The language backends are implemented using cgo and the langauge's C-bindings.
1414
1515## Usage
@@ -23,8 +23,6 @@ Usage of ./prybar:
2323 -e string
2424 expression to print
2525 -i interactive
26− -l string
27− langauge (default "python2")
2826 -ps1 string
2927 PS1 (default "--> ")
3028 -ps2 string
@@ -43,7 +41,7 @@ Usage of ./prybar:
4341
4442## Building
4543
46−Prybar uses a unix make file to build prybar along with plugins for the langage libraries `pkg-config` detects on your system.
44+Prybar uses a unix make file to build each Prybar binary with `pkg-config` to find language dependencies on your system.
4745
4846### Linux
4947
@@ -57,9 +55,7 @@ brew install go r ruby python python@2 lua spidermonkey
5755
5856## Docker
5957
60−The script `./extract.sh` can be used to compile all plugins and produce a tarball containing a `prybar` binary and supporting `plugin.so` files.
61−
62−
58+The script `./extract.sh` can be used to compile and produce a tarball containing all the Prybar binaries. Each binary will be named `prybar-<language>`. You can build all languages by running `make` in the repo's root or run `make prybar-<language>` to build a specific language.
6359
6460## License
6561
extract.sh+1−1
@@ -1,3 +1,3 @@
11#!/bin/sh
22docker build -t prybar .
3−docker run prybar tar -zc prybar plugins > prybar.tar.gz
3+docker run prybar bash -c 'tar -zc prybar-*' > prybar.tar.gz
inject_launch.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+ utils.DoCli(Instance)
8+}
src/languages/R/main.go → languages/R/main.gorenamed+3−8
@@ -37,12 +37,9 @@ import "C"
3737
3838import (
3939 "unsafe"
40− //"strings"
4140)
4241
43−
4442type R struct {
45−
4643}
4744
4845func (p R) Open() {
@@ -56,17 +53,15 @@ func (p R) Version() string {
5653func (p R) Eval(code string) {
5754 ccode := C.CString(code)
5855 defer C.free(unsafe.Pointer(ccode))
59− C.pry_eval(ccode)
56+ C.pry_eval(ccode)
6057}
6158
62−
6359func (p R) REPL() {
64− C.pry_repl();
60+ C.pry_repl()
6561}
6662
6763func (p R) Close() {
6864 C.Rf_endEmbeddedR(0)
6965}
7066
71−// exported
72−var Instance R
67+var Instance = R{}
src/languages/lua/lua.c → languages/lua/lua.crenamed

The content is the same.

src/languages/lua/main.go → languages/lua/main.gorenamed+8−12
@@ -16,14 +16,11 @@ int pmain (lua_State *L);
1616import "C"
1717
1818import (
19− "unsafe"
2019 "strings"
20+ "unsafe"
2121)
2222
23−
24−type Lua struct {
25−
26−}
23+type Lua struct{}
2724
2825func (p Lua) Open() {
2926 C.pry_init()
@@ -36,16 +33,16 @@ func (p Lua) Version() string {
3633func (p Lua) Eval(code string) {
3734 ccode := C.CString(code)
3835 defer C.free(unsafe.Pointer(ccode))
39− C.pry_eval(ccode);
36+ C.pry_eval(ccode)
4037}
4138
4239func (p Lua) EvalFile(file string, args []string) {
4340 cfile := C.CString(file)
4441 defer C.free(unsafe.Pointer(cfile))
45−
42+
4643 argv := C.CString(file + "\x00" + strings.Join(args, "\x00"))
4744 defer C.free(unsafe.Pointer(argv))
48− C.pry_eval_file(cfile, C.int(len(args) + 1), argv)
45+ C.pry_eval_file(cfile, C.int(len(args)+1), argv)
4946}
5047
5148func (p Lua) REPL() {
@@ -54,9 +51,8 @@ func (p Lua) REPL() {
5451 C.dotty(C.pry_L)
5552}
5653
57−func (p Lua) Close() {
58− C.lua_close(C.pry_L)
54+func (p Lua) Close() {
55+ C.lua_close(C.pry_L)
5956}
6057
61−// exported
62−var Instance Lua
58+var Instance = Lua{}
src/languages/lua/pry.c → languages/lua/pry.crenamed

The content is the same.

src/languages/lua/pry.h → languages/lua/pry.hrenamed

The content is the same.

src/languages/python2/main.go → languages/python2/main.gorenamed+2−4
@@ -11,8 +11,7 @@ import (
1111 "unsafe"
1212)
1313
14−type Python struct {
15−}
14+type Python struct{}
1615
1716func (p Python) Open() {
1817 C.Py_Initialize()
@@ -85,5 +84,4 @@ func (p Python) Close() {
8584 C.Py_Finalize()
8685}
8786
88−// exported
89−var Instance Python
87+var Instance = Python{}
src/languages/python2/pry_python2.c → languages/python2/pry_python2.crenamed

The content is the same.

src/languages/python2/pry_python2.h → languages/python2/pry_python2.hrenamed

The content is the same.

src/languages/python3/main.go → languages/python3/main.gorenamed+2−4
@@ -12,8 +12,7 @@ import (
1212 "unsafe"
1313)
1414
15−type Python struct {
16−}
15+type Python struct{}
1716
1817func (p Python) Open() {
1918 C.Py_Initialize()
@@ -80,5 +79,4 @@ func (p Python) Close() {
8079 C.Py_Finalize()
8180}
8281
83−// exported
84−var Instance Python
82+var Instance = Python{}
src/languages/python3/pry_python3.c → languages/python3/pry_python3.crenamed

The content is the same.

src/languages/python3/pry_python3.h → languages/python3/pry_python3.hrenamed

The content is the same.

src/languages/ruby/main.go → languages/ruby/main.gorenamed+1−4
@@ -10,7 +10,6 @@ import (
1010 "unsafe"
1111)
1212
13−/* */
1413type Ruby struct {
1514}
1615
@@ -42,10 +41,8 @@ func (p Ruby) EvalFile(file string, args []string) {
4241func (p Ruby) REPL() {
4342 p.Eval("require 'irb'\nbinding.irb")
4443}
45−
4644func (p Ruby) Close() {
4745 C.ruby_cleanup(0)
4846}
4947
50−// exported
51−var Instance Ruby
48+var Instance = Ruby{}
src/languages/ruby/pry_ruby.c → languages/ruby/pry_ruby.crenamed

The content is the same.

src/languages/ruby/pry_ruby.h → languages/ruby/pry_ruby.hrenamed

The content is the same.

src/languages/spidermonkey/main.go → languages/spidermonkey/main.gorenamed+8−15
@@ -1,6 +1,5 @@
11package main
22
3−
43/*
54#cgo pkg-config: mozjs185
65#include "jsapi.h"
@@ -66,30 +65,24 @@ import (
6665 "unsafe"
6766)
6867
68+type SpiderMonkey struct{}
6969
70−type Language struct {
71−
72−}
73−
74−func (p Language) Open() {
70+func (p SpiderMonkey) Open() {
7571 C.pry_open()
7672}
7773
78−func (p Language) Version() string {
74+func (p SpiderMonkey) Version() string {
7975 return C.GoString(C.JS_GetImplementationVersion())
80− //return "JS";
8176}
8277
83−func (p Language) Eval(code string) {
78+func (p SpiderMonkey) Eval(code string) {
8479 ccode := C.CString(code)
8580 defer C.free(unsafe.Pointer(ccode))
86− C.pry_eval(ccode)
81+ C.pry_eval(ccode)
8782}
8883
89−
90−func (p Language) Close() {
91− C.pry_close()
84+func (p SpiderMonkey) Close() {
85+ C.pry_close()
9286}
9387
94−// exported
95−var Instance Language
88+var Instance = SpiderMonkey{}
src/languages/tcl/main.go → languages/tcl/main.gorenamed+7−9
@@ -11,35 +11,33 @@ import (
1111 "unsafe"
1212)
1313
14−type Python struct {
15−}
14+type Tcl struct{}
1615
17−func (p Python) Open() {
16+func (p Tcl) Open() {
1817 C.pry_open()
1918}
2019
21−func (p Python) Version() string {
20+func (p Tcl) Version() string {
2221 cver := C.pry_version()
2322 ver := C.GoString(cver)
2423 C.free(unsafe.Pointer(cver))
2524 return "TCL " + ver
2625}
2726
28−func (p Python) Eval(code string) {
27+func (p Tcl) Eval(code string) {
2928 ccode := C.CString(code)
3029 defer C.free(unsafe.Pointer(ccode))
3130 C.pry_eval(ccode)
3231}
3332
34−func (p Python) EvalExpression(code string) string {
33+func (p Tcl) EvalExpression(code string) string {
3534 ccode := C.CString(code)
3635 defer C.free(unsafe.Pointer(ccode))
3736 return C.GoString(C.pry_eval(ccode))
3837}
3938
40−func (p Python) Close() {
39+func (p Tcl) Close() {
4140 C.pry_close()
4241}
4342
44−// exported
45−var Instance Python
43+var Instance = Tcl{}
src/languages/tcl/pry_tcl.c → languages/tcl/pry_tcl.crenamed

The content is the same.

src/languages/tcl/pry_tcl.h → languages/tcl/pry_tcl.hrenamed

The content is the same.

src/linenoise-helper.c → linenoise/linenoise-helper.crenamed+2−3
@@ -4,8 +4,7 @@
44void linenoiseCompletionStub(const char *, linenoiseCompletions *);
55void linenoiseHintsStub(const char *, int *color, int *bold);
66
7−
87void linenoise_setup() {
9− linenoiseSetCompletionCallback(linenoiseCompletionStub);
10− linenoiseSetHintsCallback(linenoiseHintsStub);
8+ linenoiseSetCompletionCallback(linenoiseCompletionStub);
9+ linenoiseSetHintsCallback(linenoiseHintsStub);
1110}
src/linenoise.c → linenoise/linenoise.crenamed+1−1
@@ -1198,4 +1198,4 @@ int linenoiseHistoryLoad(const char *filename) {
11981198 }
11991199 fclose(fp);
12001200 return 0;
1201−}
1201+}
src/linenoise.go → linenoise/linenoise.gorenamed+5−7
@@ -1,24 +1,23 @@
1−package main
1+package linenoise
22
33/*
4−#include <stdlib.h>
54#include <linenoise.h>
5+#include <stdlib.h>
66
7−void linenoise_setup();
7+void linenoise_setup();
88
99
1010*/
1111import "C"
1212
1313import (
14− "unsafe"
1514 "fmt"
15+ "unsafe"
1616)
1717
1818type Completer func(line string) []string
1919type Hinter func(line string) string
2020
21−
2221var completer Completer
2322var hinter Hinter
2423
@@ -52,7 +51,7 @@ func linenoiseHintsStub(input *C.char, color *C.int, bold *C.int) *C.char {
5251 return C.CString(hinter(C.GoString(input)))
5352}
5453
55−func Linenoise(prompt string) (string,error) {
54+func Linenoise(prompt string) (string, error) {
5655 C.linenoise_setup()
5756 cprompt := C.CString(prompt)
5857 defer C.free(unsafe.Pointer(cprompt))
@@ -78,4 +77,3 @@ func LinenoiseSetCompleter(newCompleter Completer) {
7877func LinenoiseSetHinter(newHinter Hinter) {
7978 hinter = newHinter
8079}
81−
src/linenoise.h → linenoise/linenoise.hrenamed

The content is the same.

mk-deps.shdeleted−22
@@ -1,22 +0,0 @@
1−#/bin/bash
2−
3−FOUND=""
4−check() {
5− pkg-config --exists $2
6− if [ $? -eq 0 ]; then
7− echo "Found plugin $1 => $2" 1>&2
8− FOUND="$FOUND plugins/$1.so"
9− else
10− echo "Couldnt find $1" 1>&2
11− fi
12−}
13−
14−for plugin in $(ls -1 src/languages/); do
15− PKG=$(grep cgo.*pkg-config src/languages/$plugin/main.go | cut -d ':' -f 2)
16− check $plugin $PKG
17−done
18−
19−
20−echo "plugins = $FOUND"
21−
22−
src/language.go → utils/language.gorenamed+15−61
@@ -1,12 +1,10 @@
1−package main
1+package utils
22
33import (
44 "fmt"
55 "io/ioutil"
6− "os"
7− "path/filepath"
8− "plugin"
9− "runtime"
6+
7+ "github.com/replit/prybar/linenoise"
108)
119
1210type PluginBase interface {
@@ -45,64 +43,20 @@ type PluginSetPrompts interface {
4543 SetPrompts(ps1, ps2 string)
4644}
4745
48−type Langauge struct {
46+type Language struct {
4947 ptr PluginBase
48+ ps1 string
5049}
5150
52−func finalizer(f *Langauge) {
53− fmt.Println("a finalizer has run.")
54−}
55−
56−func GetLanguage(name string) *Langauge {
57− base := "."
58− exe, err := os.Executable()
59− for {
60− o, err := os.Readlink(exe)
61− if err == nil {
62− exe = o
63− } else {
64− break
65− }
66− }
67−
68− base = filepath.Dir(exe)
69− plug, err := plugin.Open(base + "/plugins/" + name + ".so")
70−
71− if err != nil {
72− fmt.Println(err)
73− os.Exit(1)
74− }
75−
76− sym, err := plug.Lookup("Instance")
77− if err != nil {
78− fmt.Println(err)
79− os.Exit(1)
80− }
81−
82− var lang PluginBase
83− lang, ok := sym.(PluginBase)
84− if !ok {
85− fmt.Println("module did not export Language interface")
86− os.Exit(1)
87− }
88−
89− result := &Langauge{
90− ptr: lang,
91− }
92− lang.Open()
93− runtime.SetFinalizer(result, finalizer)
94− return result
95−}
96−
97−func (lang Langauge) Version() string {
51+func (lang Language) Version() string {
9852 return lang.ptr.Version()
9953}
10054
101−func (lang Langauge) Eval(code string) {
55+func (lang Language) Eval(code string) {
10256 lang.ptr.(PluginEval).Eval(code)
10357}
10458
105−func (lang Langauge) EvalAndTryToPrint(code string) {
59+func (lang Language) EvalAndTryToPrint(code string) {
10660 ee, ok := lang.ptr.(PluginEvalExpression)
10761 if ok {
10862 fmt.Println(ee.EvalExpression(code))
@@ -111,7 +65,7 @@ func (lang Langauge) EvalAndTryToPrint(code string) {
11165 }
11266}
11367
114−func (lang Langauge) REPLLikeEval(code string) {
68+func (lang Language) REPLLikeEval(code string) {
11569 rle, ok := lang.ptr.(PluginREPLLikeEval)
11670 if ok {
11771 rle.REPLLikeEval(code)
@@ -126,7 +80,7 @@ func (lang Langauge) REPLLikeEval(code string) {
12680 }
12781}
12882
129−func (lang Langauge) EvalFile(file string, args []string) {
83+func (lang Language) EvalFile(file string, args []string) {
13084 pef, ok := lang.ptr.(PluginEvalFile)
13185 if ok {
13286 pef.EvalFile(file, args)
@@ -139,7 +93,7 @@ func (lang Langauge) EvalFile(file string, args []string) {
13993 }
14094}
14195
142−func (lang Langauge) REPL() {
96+func (lang Language) REPL() {
14397 repl, ok := lang.ptr.(PluginREPL)
14498 if ok {
14599 repl.REPL()
@@ -148,18 +102,18 @@ func (lang Langauge) REPL() {
148102 }
149103}
150104
151−func (lang Langauge) InternalREPL() {
105+func (lang Language) InternalREPL() {
152106 for {
153− line, err := Linenoise(ps1)
107+ line, err := linenoise.Linenoise(lang.ps1)
154108 if err != nil {
155109 break
156110 }
157111 lang.REPLLikeEval(line)
158− LinenoiseHistoryAdd(line)
112+ linenoise.LinenoiseHistoryAdd(line)
159113 }
160114}
161115
162−func (lang Langauge) SetPrompts(ps1, ps2 string) {
116+func (lang Language) SetPrompts(ps1, ps2 string) {
163117 ee, ok := lang.ptr.(PluginSetPrompts)
164118 if ok {
165119 ee.SetPrompts(ps1, ps2)
src/main.go → utils/utils.gorenamed+5−19
@@ -1,16 +1,13 @@
1−package main
1+package utils
22
33import (
44 "flag"
55 "fmt"
66 "io"
77 "os"
8− "strings"
98 "syscall"
109)
1110
12−var ps1, ps2 string
13−
1411type Red struct {
1512 parent io.Writer
1613}
@@ -22,20 +19,14 @@ func (r *Red) Write(p []byte) (n int, err error) {
2219 return n, err
2320}
2421
25−func main() {
26− var language string
22+func DoCli(p PluginBase) {
2723 var interactive, ourInteractive bool
2824 var code string
2925 var quiet bool
3026 var exp string
3127 var colorizeStderr bool
28+ var ps1, ps2 string
3229
33− defaultLangague := os.Args[0]
34− if defaultLangague == "prybar" || strings.ContainsAny(defaultLangague, "./") {
35− defaultLangague = "python2"
36− }
37−
38− flag.StringVar(&language, "l", defaultLangague, "langauge")
3930 flag.StringVar(&code, "c", "", "code to run")
4031 flag.StringVar(&exp, "e", "", "expression to print")
4132
@@ -52,14 +43,9 @@ func main() {
5243
5344 args := flag.Args()
5445
55− switch language {
56− case "python":
57− language = "python3"
58− case "javascript":
59− language = "spidermonkey"
60− }
46+ p.Open()
47+ lang := &Language{ptr: p, ps1: ps1}
6148
62− lang := GetLanguage(language)
6349 if !quiet {
6450 fmt.Println(lang.Version())
6551 }