on master help sign in
Ensure exit codes (where applicable) (#82)

* Ensure exit codes * cleanup a lil' * lock nix version to nix:2.3.16 * make some requested changes * save changes to utils.go

commita584d8e52bbff356140546fc6691f1d2c01a176e authorAllAwesome497 <47748690+AllAwesome497@users.noreply.github.com> dateTue 18 Jan 2022, 12:03 (5 years ago) parent02c7adf
19 files changed+111−54
.circleci/config.yml+1−1 languages/julia/main.go+4−3 languages/julia/pry.h+1−1 languages/lua/main.go+2−2 languages/lua/pry.c+1−1 languages/lua/pry.h+1−1 languages/nodejs/repl.js+23−14 languages/python2/main.go+9−2 languages/python2/pry_python2.c+2−2 languages/python2/pry_python2.h+1−1 languages/python3/main.go+14−3 languages/python3/pry_python3.c+26−11 languages/python3/pry_python3.h+4−2 languages/ruby/main.go+2−2 languages/ruby/pry_ruby.c+4−2 languages/ruby/pry_ruby.h+1−1 languages/tcl/main.go+5−1 utils/language.go+4−3 utils/utils.go+6−1
.circleci/config.yml+1−1
@@ -16,7 +16,7 @@ jobs:
1616 - run: make test-image
1717 nix_build:
1818 docker:
19− - image: nixos/nix
19+ - image: nixos/nix:2.3.16
2020 steps:
2121 - checkout
2222 - restore_cache:
languages/julia/main.go+4−3
@@ -37,10 +37,11 @@ func (p Julia) Eval(code string) {
3737 C.eval(cstr)
3838}
3939
40−func (p Julia) EvalFile(file string, args []string) {
40+func (p Julia) EvalFile(file string, args []string) int {
4141 cstr := C.CString(file)
42− C.eval_file(cstr)
43− C.free(unsafe.Pointer(cstr))
42+ defer C.free(unsafe.Pointer(cstr))
43+
44+ return int(C.eval_file(cstr))
4445}
4546
4647func (p Julia) REPL() {
languages/julia/pry.h+1−1
@@ -107,7 +107,7 @@ void cleanup() { jl_atexit_hook(0); }
107107
108108void eval(const char *str) { jl_eval_string(str); }
109109
110−void eval_file(const char *path) { exec_program(path); }
110+int eval_file(const char *path) { return exec_program(path); }
111111
112112void run_repl() { fancy_repl(); }
113113
languages/lua/main.go+2−2
@@ -49,11 +49,11 @@ func (p Lua) Eval(code string) {
4949 C.pry_eval(ccode)
5050}
5151
52−func (p Lua) EvalFile(file string) {
52+func (p Lua) EvalFile(file string, args []string) int {
5353 cfile := C.CString(file)
5454 defer C.free(unsafe.Pointer(cfile))
5555
56− C.pry_eval_file(cfile)
56+ return int(C.pry_eval_file(cfile))
5757}
5858
5959func (p Lua) REPL() {
languages/lua/pry.c+1−1
@@ -13,4 +13,4 @@ void pry_eval(const char *code) { dostring(pry_L, code, "<eval>"); }
1313
1414void pry_do_repl(void) { dotty(pry_L); }
1515
16−void pry_eval_file(char *file) { handle_script(pry_L, &file, 0); }
16+int pry_eval_file(char *file) { return handle_script(pry_L, &file, 0); }
languages/lua/pry.h+1−1
@@ -4,7 +4,7 @@ extern lua_State *pry_L;
44
55const char *pry_get_version(void);
66void pry_eval(const char *code);
7−void pry_eval_file(char *file);
7+int pry_eval_file(char *file);
88void pry_do_repl(void);
99
1010// from the lua repl lib (lua.c)
languages/nodejs/repl.js+23−14
@@ -1,6 +1,5 @@
11const repl = require('repl');
22const path = require('path');
3−const { isatty } = require('tty');
43const assets_dir =
54 process.env.PRYBAR_ASSETS_DIR || path.join(process.cwd(), 'prybar_assets');
65/**
@@ -13,7 +12,7 @@ const rl = require(path.join(assets_dir, 'nodejs', 'input-sync.js'));
1312const { runCode, runModule, getRepl } = require(path.join(
1413 assets_dir,
1514 'nodejs',
16− 'module-context-hook.js',
15+ 'module-context-hook.js'
1716));
1817
1918// imports to builtin modules don't get added to require.cache.
@@ -32,7 +31,7 @@ Error.prepareStackTrace = function prepareStackTrace(error, callSites) {
3231
3332 const idx = callSites.findIndex((frame) => frame.getFunctionName() === null);
3433 const domainIndex = callSites.findIndex(
35− (site) => site.getFileName() === 'domain.js',
34+ (site) => site.getFileName() === 'domain.js'
3635 );
3736
3837 if (domainIndex !== -1 && domainIndex < idx) {
@@ -43,7 +42,7 @@ Error.prepareStackTrace = function prepareStackTrace(error, callSites) {
4342 callSites.reverse();
4443
4544 const lowestPrybarFileIndex = callSites.findIndex((site) =>
46− prybarFilenames.includes(site.getFileName()),
45+ prybarFilenames.includes(site.getFileName())
4746 );
4847
4948 callSites = callSites.slice(0, lowestPrybarFileIndex);
@@ -68,18 +67,16 @@ if (!process.env.PRYBAR_QUIET) {
6867 console.log('Node ' + process.version + ' on ' + process.platform);
6968}
7069
71−const isTTY = isatty(process.stdin.fd);
72−
73−// Red errors (if stdout is a TTY)
70+// Red errors (if stderr is a TTY)
7471function logError(msg) {
75− if (isTTY) {
76− process.stdout.write(`\u001b[0m\u001b[31m${msg}\u001b[0m`);
72+ if (process.stderr.isTTY) {
73+ process.stderr.write(`\u001b[0m\u001b[31m${msg}\u001b[0m`);
7774 } else {
78− process.stdout.write(msg);
75+ process.stderr.write(msg);
7976 }
8077
8178 if (!msg.endsWith('\n')) {
82− process.stdout.write('\n');
79+ process.stderr.write('\n');
8380 }
8481}
8582
@@ -99,7 +96,7 @@ function resumeRepl() {
9996
10097// Clear the line if it has anything on it.
10198function clearLine() {
102− if (isTTY && r && r.line) r.clearLine();
99+ if (process.stdout.isTTY && r && r.line) r.clearLine();
103100}
104101
105102// Adapted from the internal node repl code just a lot simpler and adds
@@ -179,6 +176,10 @@ if (process.env.PRYBAR_CODE) {
179176 runCode(process.env.PRYBAR_CODE, isInterractive);
180177 } catch (err) {
181178 handleError(err);
179+
180+ if (!isInterractive) {
181+ process.exit(1);
182+ }
182183 }
183184
184185 if (isInterractive) {
@@ -189,18 +190,26 @@ if (process.env.PRYBAR_CODE) {
189190 console.log(runCode(process.env.PRYBAR_EXP, false));
190191 } catch (err) {
191192 handleError(err);
193+
194+ if (!isInterractive) {
195+ process.exit(1);
196+ }
192197 }
193198} else if (process.env.PRYBAR_FILE) {
194199 try {
195200 runModule(process.env.PRYBAR_FILE, isInterractive);
196201 } catch (err) {
197202 handleError(err);
203+
204+ if (!isInterractive) {
205+ process.exit(1);
206+ }
198207 }
199208
200209 if (isInterractive) {
201− if (isTTY) {
210+ if (process.stdout.isTTY && process.stdin.isTTY) {
202211 console.log(
203− '\u001b[0m\u001b[90mHint: hit control+c anytime to enter REPL.\u001b[0m',
212+ '\u001b[0m\u001b[90mHint: hit control+c anytime to enter REPL.\u001b[0m'
204213 );
205214 }
206215
languages/python2/main.go+9−2
@@ -38,7 +38,7 @@ func (p Python) EvalExpression(code string) string {
3838 return C.GoString(C.pry_eval(ccode, C.Py_eval_input))
3939}
4040
41−func (p Python) EvalFile(file string, args []string) {
41+func (p Python) EvalFile(file string, args []string) int {
4242 handle := C.stdin
4343 cfile := C.CString(file)
4444 defer C.free(unsafe.Pointer(cfile))
@@ -53,7 +53,14 @@ func (p Python) EvalFile(file string, args []string) {
5353
5454 argv := C.CString(file + "\x00" + strings.Join(args, "\x00"))
5555 defer C.free(unsafe.Pointer(argv))
56− C.pry_eval_file(handle, cfile, C.int(len(args)+1), argv)
56+ status := C.pry_eval_file(handle, cfile, C.int(len(args)+1), argv)
57+
58+ // if status is non-zero an error occured.
59+ if status != 0 {
60+ return 1
61+ }
62+
63+ return 0
5764}
5865
5966func (p Python) REPLLikeEval(code string) {
languages/python2/pry_python2.c+2−2
@@ -1,6 +1,6 @@
11#include "pry_python2.h"
22
3−void pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
3+int pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
44{
55 const char *xargv[argn + 1];
66 const char *ptr = argv;
@@ -11,7 +11,7 @@ void pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
1111 }
1212 xargv[argn] = NULL;
1313 PySys_SetArgvEx(argn, xargv, 1);
14− PyRun_AnyFile(f, file);
14+ return PyRun_AnyFile(f, file);
1515}
1616
1717const char *pry_eval(const char *code, int start)
languages/python2/pry_python2.h+1−1
@@ -1,5 +1,5 @@
11#include <Python.h>
22
3−void pry_eval_file(FILE *f, const char *file, int argn, const char *argv);
3+int pry_eval_file(FILE *f, const char *file, int argn, const char *argv);
44const char *pry_eval(const char *code, int start);
55void pry_set_prompts(const char *ps1, const char *ps2);
languages/python3/main.go+14−3
@@ -73,7 +73,7 @@ func (p Python) EvalExpression(code string) string {
7373 return C.GoString(C.pry_eval(ccode, C.Py_eval_input))
7474}
7575
76−func (p Python) EvalFile(file string, args []string) {
76+func (p Python) EvalFile(file string, args []string) int {
7777 handle := C.stdin
7878 cfile := C.CString(file)
7979 defer C.free(unsafe.Pointer(cfile))
@@ -88,7 +88,15 @@ func (p Python) EvalFile(file string, args []string) {
8888
8989 argv := C.CString(file + "\x00" + strings.Join(args, "\x00"))
9090 defer C.free(unsafe.Pointer(argv))
91− C.pry_eval_file(handle, cfile, C.int(len(args)+1), argv)
91+
92+ status := (C.pry_eval_file(handle, cfile, C.int(len(args)+1), argv))
93+
94+ // if status is non-zero an error occured.
95+ if status != 0 {
96+ return 1
97+ }
98+
99+ return 0
92100}
93101
94102func (p Python) REPLLikeEval(code string) {
@@ -104,7 +112,10 @@ func (p Python) loadModule(mod string) {
104112}
105113
106114func (p Python) REPL() {
107− C.pymain_run_interactive_hook()
115+ var exitCode C.int
116+ if C.pymain_run_interactive_hook(&exitCode) != 0 {
117+ os.Exit(int(exitCode))
118+ }
108119
109120 fn := C.CString("<stdin>")
110121 defer C.free(unsafe.Pointer(fn))
languages/python3/pry_python3.c+26−11
@@ -1,6 +1,6 @@
11#include "pry_python3.h"
22
3−void pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
3+int pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
44{
55 wchar_t *xargv[argn + 1];
66 const char *ptr = argv;
@@ -11,8 +11,8 @@ void pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
1111 }
1212 xargv[argn] = NULL;
1313 PySys_SetArgvEx(argn, xargv, 1);
14− PyRun_AnyFile(f, file);
1514
15+ return PyRun_AnyFile(f, file);
1616}
1717
1818const char *pry_eval(const char *code, int start)
@@ -71,34 +71,49 @@ void pry_set_prompts(const char *ps1, const char *ps2)
7171}
7272
7373//From python3 sourcecode
74−void pymain_run_interactive_hook(void)
74+int
75+pymain_run_interactive_hook(int *exitcode)
7576{
7677 PyObject *sys, *hook, *result;
7778 sys = PyImport_ImportModule("sys");
78− if (sys == NULL)
79− {
79+ if (sys == NULL) {
8080 goto error;
8181 }
8282
8383 hook = PyObject_GetAttrString(sys, "__interactivehook__");
8484 Py_DECREF(sys);
85− if (hook == NULL)
86− {
85+ if (hook == NULL) {
8786 PyErr_Clear();
88− return;
87+ return 0;
88+ }
89+
90+ if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) {
91+ goto error;
8992 }
9093
9194 result = _PyObject_CallNoArg(hook);
9295 Py_DECREF(hook);
93− if (result == NULL)
94− {
96+ if (result == NULL) {
9597 goto error;
9698 }
9799 Py_DECREF(result);
98100
99− return;
101+ return 0;
100102
101103error:
102104 PySys_WriteStderr("Failed calling sys.__interactivehook__\n");
105+ return pymain_err_print(exitcode);
106+}
107+
108+int
109+pymain_err_print(int *exitcode_p)
110+{
111+ int exitcode;
112+ if (_Py_HandleSystemExit(&exitcode)) {
113+ *exitcode_p = exitcode;
114+ return 1;
115+ }
116+
103117 PyErr_Print();
118+ return 0;
104119}
languages/python3/pry_python3.h+4−2
@@ -1,6 +1,8 @@
11#include <Python.h>
22
3−void pry_eval_file(FILE *f, const char *file, int argn, const char *argv);
3+int pry_eval_file(FILE *f, const char *file, int argn, const char *argv);
44const char *pry_eval(const char *code, int start);
55void pry_set_prompts(const char *ps1, const char *ps2);
6−void pymain_run_interactive_hook(void);
6+int pymain_run_interactive_hook(int *exitcode);
7+int pymain_err_print(int *exitcode_p);
8+PyAPI_FUNC(int) _Py_HandleSystemExit(int *exitcode_p);
languages/ruby/main.go+2−2
@@ -34,10 +34,10 @@ func (p Ruby) EvalExpression(code string) string {
3434 return C.GoString(res)
3535}
3636
37−func (p Ruby) EvalFile(file string, args []string) {
37+func (p Ruby) EvalFile(file string, args []string) int {
3838 cfile := C.CString(file)
3939 defer C.free(unsafe.Pointer(cfile))
40− C.pry_eval_file(cfile)
40+ return int(C.pry_eval_file(cfile))
4141}
4242
4343func (p Ruby) REPL() {
languages/ruby/pry_ruby.c+4−2
@@ -36,14 +36,16 @@ char *pry_eval(const char *code)
3636 }
3737}
3838
39−void pry_eval_file(const char *file)
39+int pry_eval_file(const char *file)
4040{
4141 char *options[] = {"ruby", file};
4242 void *node = ruby_options(2, options);
4343
44− int state;
44+ int state = 0;
4545 if (ruby_executable_node(node, &state))
4646 {
4747 state = ruby_exec_node(node);
4848 }
49+
50+ return state;
4951}
languages/ruby/pry_ruby.h+1−1
@@ -4,5 +4,5 @@
44void pry_open();
55const char *pry_ruby_version();
66char *pry_eval(const char *code);
7−void pry_eval_file(const char *file);
7+int pry_eval_file(const char *file);
88
languages/tcl/main.go+5−1
@@ -63,7 +63,7 @@ func (p *Tcl) eval(code string) string {
6363 return ""
6464}
6565
66−func (p *Tcl) EvalFile(file string, args []string) {
66+func (p *Tcl) EvalFile(file string, args []string) int {
6767 cfile := C.CString(file)
6868 defer C.free(unsafe.Pointer(cfile))
6969
@@ -72,7 +72,10 @@ func (p *Tcl) EvalFile(file string, args []string) {
7272 if status != C.TCL_OK {
7373 errstr := C.GoString(C.Tcl_GetStringResult(p.interp))
7474 fmt.Fprintf(os.Stderr, "error: %s\n", errstr)
75+ return int(status)
7576 }
77+
78+ return 0
7679}
7780
7881func (p *Tcl) Eval(code string) {
@@ -86,4 +89,5 @@ func (p *Tcl) EvalExpression(code string) string {
8689func (p *Tcl) Close() {
8790 C.Tcl_Finalize()
8891}
92+
8993var Instance = &Tcl{}
utils/language.go+4−3
@@ -25,7 +25,7 @@ type PluginEvalExpression interface {
2525
2626type PluginEvalFile interface {
2727 PluginBase
28− EvalFile(file string, args []string)
28+ EvalFile(file string, args []string) int
2929}
3030
3131type PluginREPL interface {
@@ -80,16 +80,17 @@ func (lang Language) REPLLikeEval(code string) {
8080 }
8181}
8282
83−func (lang Language) EvalFile(file string, args []string) {
83+func (lang Language) EvalFile(file string, args []string) int {
8484 pef, ok := lang.ptr.(PluginEvalFile)
8585 if ok {
86− pef.EvalFile(file, args)
86+ return pef.EvalFile(file, args)
8787 } else {
8888 dat, err := ioutil.ReadFile(file)
8989 if err != nil {
9090 panic(err)
9191 }
9292 lang.Eval(string(dat))
93+ return 0
9394 }
9495}
9596
utils/utils.go+6−1
@@ -58,12 +58,17 @@ func DoCli(p PluginBase) {
5858 if config.Exp != "" {
5959 lang.EvalAndTryToPrint(config.Exp)
6060 }
61+
6162 if len(config.Args) > 0 {
6263 if _, err := os.Stat(config.Args[0]); os.IsNotExist(err) {
6364 fmt.Println("No such file:", config.Args[0])
6465 os.Exit(2)
6566 } else {
66− lang.EvalFile(config.Args[0], config.Args[1:])
67+ exitCode := lang.EvalFile(config.Args[0], config.Args[1:])
68+ // TODO: Maybe log if exitCode is non-zero and interractive is true?
69+ if exitCode != 0 && !config.Interactive && !config.OurInteractive {
70+ os.Exit(exitCode)
71+ }
6772 }
6873 }
6974