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
This commit is contained in:
AllAwesome497 2022-01-18 12:03:34 -06:00 committed by GitHub
parent 02c7adf7b1
commit a584d8e52b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 112 additions and 55 deletions

View File

@ -16,7 +16,7 @@ jobs:
- run: make test-image - run: make test-image
nix_build: nix_build:
docker: docker:
- image: nixos/nix - image: nixos/nix:2.3.16
steps: steps:
- checkout - checkout
- restore_cache: - restore_cache:

View File

@ -37,10 +37,11 @@ func (p Julia) Eval(code string) {
C.eval(cstr) C.eval(cstr)
} }
func (p Julia) EvalFile(file string, args []string) { func (p Julia) EvalFile(file string, args []string) int {
cstr := C.CString(file) cstr := C.CString(file)
C.eval_file(cstr) defer C.free(unsafe.Pointer(cstr))
C.free(unsafe.Pointer(cstr))
return int(C.eval_file(cstr))
} }
func (p Julia) REPL() { func (p Julia) REPL() {

View File

@ -107,7 +107,7 @@ void cleanup() { jl_atexit_hook(0); }
void eval(const char *str) { jl_eval_string(str); } void eval(const char *str) { jl_eval_string(str); }
void eval_file(const char *path) { exec_program(path); } int eval_file(const char *path) { return exec_program(path); }
void run_repl() { fancy_repl(); } void run_repl() { fancy_repl(); }

View File

@ -49,11 +49,11 @@ func (p Lua) Eval(code string) {
C.pry_eval(ccode) C.pry_eval(ccode)
} }
func (p Lua) EvalFile(file string) { func (p Lua) EvalFile(file string, args []string) int {
cfile := C.CString(file) cfile := C.CString(file)
defer C.free(unsafe.Pointer(cfile)) defer C.free(unsafe.Pointer(cfile))
C.pry_eval_file(cfile) return int(C.pry_eval_file(cfile))
} }
func (p Lua) REPL() { func (p Lua) REPL() {

View File

@ -13,4 +13,4 @@ void pry_eval(const char *code) { dostring(pry_L, code, "<eval>"); }
void pry_do_repl(void) { dotty(pry_L); } void pry_do_repl(void) { dotty(pry_L); }
void pry_eval_file(char *file) { handle_script(pry_L, &file, 0); } int pry_eval_file(char *file) { return handle_script(pry_L, &file, 0); }

View File

@ -4,7 +4,7 @@ extern lua_State *pry_L;
const char *pry_get_version(void); const char *pry_get_version(void);
void pry_eval(const char *code); void pry_eval(const char *code);
void pry_eval_file(char *file); int pry_eval_file(char *file);
void pry_do_repl(void); void pry_do_repl(void);
// from the lua repl lib (lua.c) // from the lua repl lib (lua.c)

View File

@ -1,6 +1,5 @@
const repl = require('repl'); const repl = require('repl');
const path = require('path'); const path = require('path');
const { isatty } = require('tty');
const assets_dir = const assets_dir =
process.env.PRYBAR_ASSETS_DIR || path.join(process.cwd(), 'prybar_assets'); process.env.PRYBAR_ASSETS_DIR || path.join(process.cwd(), 'prybar_assets');
/** /**
@ -13,7 +12,7 @@ const rl = require(path.join(assets_dir, 'nodejs', 'input-sync.js'));
const { runCode, runModule, getRepl } = require(path.join( const { runCode, runModule, getRepl } = require(path.join(
assets_dir, assets_dir,
'nodejs', 'nodejs',
'module-context-hook.js', 'module-context-hook.js'
)); ));
// imports to builtin modules don't get added to require.cache. // imports to builtin modules don't get added to require.cache.
@ -32,7 +31,7 @@ Error.prepareStackTrace = function prepareStackTrace(error, callSites) {
const idx = callSites.findIndex((frame) => frame.getFunctionName() === null); const idx = callSites.findIndex((frame) => frame.getFunctionName() === null);
const domainIndex = callSites.findIndex( const domainIndex = callSites.findIndex(
(site) => site.getFileName() === 'domain.js', (site) => site.getFileName() === 'domain.js'
); );
if (domainIndex !== -1 && domainIndex < idx) { if (domainIndex !== -1 && domainIndex < idx) {
@ -43,7 +42,7 @@ Error.prepareStackTrace = function prepareStackTrace(error, callSites) {
callSites.reverse(); callSites.reverse();
const lowestPrybarFileIndex = callSites.findIndex((site) => const lowestPrybarFileIndex = callSites.findIndex((site) =>
prybarFilenames.includes(site.getFileName()), prybarFilenames.includes(site.getFileName())
); );
callSites = callSites.slice(0, lowestPrybarFileIndex); callSites = callSites.slice(0, lowestPrybarFileIndex);
@ -68,18 +67,16 @@ if (!process.env.PRYBAR_QUIET) {
console.log('Node ' + process.version + ' on ' + process.platform); console.log('Node ' + process.version + ' on ' + process.platform);
} }
const isTTY = isatty(process.stdin.fd); // Red errors (if stderr is a TTY)
// Red errors (if stdout is a TTY)
function logError(msg) { function logError(msg) {
if (isTTY) { if (process.stderr.isTTY) {
process.stdout.write(`\u001b[0m\u001b[31m${msg}\u001b[0m`); process.stderr.write(`\u001b[0m\u001b[31m${msg}\u001b[0m`);
} else { } else {
process.stdout.write(msg); process.stderr.write(msg);
} }
if (!msg.endsWith('\n')) { if (!msg.endsWith('\n')) {
process.stdout.write('\n'); process.stderr.write('\n');
} }
} }
@ -99,7 +96,7 @@ function resumeRepl() {
// Clear the line if it has anything on it. // Clear the line if it has anything on it.
function clearLine() { function clearLine() {
if (isTTY && r && r.line) r.clearLine(); if (process.stdout.isTTY && r && r.line) r.clearLine();
} }
// Adapted from the internal node repl code just a lot simpler and adds // Adapted from the internal node repl code just a lot simpler and adds
@ -179,6 +176,10 @@ if (process.env.PRYBAR_CODE) {
runCode(process.env.PRYBAR_CODE, isInterractive); runCode(process.env.PRYBAR_CODE, isInterractive);
} catch (err) { } catch (err) {
handleError(err); handleError(err);
if (!isInterractive) {
process.exit(1);
}
} }
if (isInterractive) { if (isInterractive) {
@ -189,18 +190,26 @@ if (process.env.PRYBAR_CODE) {
console.log(runCode(process.env.PRYBAR_EXP, false)); console.log(runCode(process.env.PRYBAR_EXP, false));
} catch (err) { } catch (err) {
handleError(err); handleError(err);
if (!isInterractive) {
process.exit(1);
}
} }
} else if (process.env.PRYBAR_FILE) { } else if (process.env.PRYBAR_FILE) {
try { try {
runModule(process.env.PRYBAR_FILE, isInterractive); runModule(process.env.PRYBAR_FILE, isInterractive);
} catch (err) { } catch (err) {
handleError(err); handleError(err);
if (!isInterractive) {
process.exit(1);
}
} }
if (isInterractive) { if (isInterractive) {
if (isTTY) { if (process.stdout.isTTY && process.stdin.isTTY) {
console.log( console.log(
'\u001b[0m\u001b[90mHint: hit control+c anytime to enter REPL.\u001b[0m', '\u001b[0m\u001b[90mHint: hit control+c anytime to enter REPL.\u001b[0m'
); );
} }

View File

@ -38,7 +38,7 @@ func (p Python) EvalExpression(code string) string {
return C.GoString(C.pry_eval(ccode, C.Py_eval_input)) return C.GoString(C.pry_eval(ccode, C.Py_eval_input))
} }
func (p Python) EvalFile(file string, args []string) { func (p Python) EvalFile(file string, args []string) int {
handle := C.stdin handle := C.stdin
cfile := C.CString(file) cfile := C.CString(file)
defer C.free(unsafe.Pointer(cfile)) defer C.free(unsafe.Pointer(cfile))
@ -53,7 +53,14 @@ func (p Python) EvalFile(file string, args []string) {
argv := C.CString(file + "\x00" + strings.Join(args, "\x00")) argv := C.CString(file + "\x00" + strings.Join(args, "\x00"))
defer C.free(unsafe.Pointer(argv)) defer C.free(unsafe.Pointer(argv))
C.pry_eval_file(handle, cfile, C.int(len(args)+1), argv) status := C.pry_eval_file(handle, cfile, C.int(len(args)+1), argv)
// if status is non-zero an error occured.
if status != 0 {
return 1
}
return 0
} }
func (p Python) REPLLikeEval(code string) { func (p Python) REPLLikeEval(code string) {

View File

@ -1,6 +1,6 @@
#include "pry_python2.h" #include "pry_python2.h"
void pry_eval_file(FILE *f, const char *file, int argn, const char *argv) int pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
{ {
const char *xargv[argn + 1]; const char *xargv[argn + 1];
const char *ptr = argv; const char *ptr = argv;
@ -11,7 +11,7 @@ void pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
} }
xargv[argn] = NULL; xargv[argn] = NULL;
PySys_SetArgvEx(argn, xargv, 1); PySys_SetArgvEx(argn, xargv, 1);
PyRun_AnyFile(f, file); return PyRun_AnyFile(f, file);
} }
const char *pry_eval(const char *code, int start) const char *pry_eval(const char *code, int start)

View File

@ -1,5 +1,5 @@
#include <Python.h> #include <Python.h>
void pry_eval_file(FILE *f, const char *file, int argn, const char *argv); int pry_eval_file(FILE *f, const char *file, int argn, const char *argv);
const char *pry_eval(const char *code, int start); const char *pry_eval(const char *code, int start);
void pry_set_prompts(const char *ps1, const char *ps2); void pry_set_prompts(const char *ps1, const char *ps2);

View File

@ -73,7 +73,7 @@ func (p Python) EvalExpression(code string) string {
return C.GoString(C.pry_eval(ccode, C.Py_eval_input)) return C.GoString(C.pry_eval(ccode, C.Py_eval_input))
} }
func (p Python) EvalFile(file string, args []string) { func (p Python) EvalFile(file string, args []string) int {
handle := C.stdin handle := C.stdin
cfile := C.CString(file) cfile := C.CString(file)
defer C.free(unsafe.Pointer(cfile)) defer C.free(unsafe.Pointer(cfile))
@ -88,7 +88,15 @@ func (p Python) EvalFile(file string, args []string) {
argv := C.CString(file + "\x00" + strings.Join(args, "\x00")) argv := C.CString(file + "\x00" + strings.Join(args, "\x00"))
defer C.free(unsafe.Pointer(argv)) defer C.free(unsafe.Pointer(argv))
C.pry_eval_file(handle, cfile, C.int(len(args)+1), argv)
status := (C.pry_eval_file(handle, cfile, C.int(len(args)+1), argv))
// if status is non-zero an error occured.
if status != 0 {
return 1
}
return 0
} }
func (p Python) REPLLikeEval(code string) { func (p Python) REPLLikeEval(code string) {
@ -104,7 +112,10 @@ func (p Python) loadModule(mod string) {
} }
func (p Python) REPL() { func (p Python) REPL() {
C.pymain_run_interactive_hook() var exitCode C.int
if C.pymain_run_interactive_hook(&exitCode) != 0 {
os.Exit(int(exitCode))
}
fn := C.CString("<stdin>") fn := C.CString("<stdin>")
defer C.free(unsafe.Pointer(fn)) defer C.free(unsafe.Pointer(fn))

View File

@ -1,6 +1,6 @@
#include "pry_python3.h" #include "pry_python3.h"
void pry_eval_file(FILE *f, const char *file, int argn, const char *argv) int pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
{ {
wchar_t *xargv[argn + 1]; wchar_t *xargv[argn + 1];
const char *ptr = argv; const char *ptr = argv;
@ -11,8 +11,8 @@ void pry_eval_file(FILE *f, const char *file, int argn, const char *argv)
} }
xargv[argn] = NULL; xargv[argn] = NULL;
PySys_SetArgvEx(argn, xargv, 1); PySys_SetArgvEx(argn, xargv, 1);
PyRun_AnyFile(f, file);
return PyRun_AnyFile(f, file);
} }
const char *pry_eval(const char *code, int start) const char *pry_eval(const char *code, int start)
@ -71,34 +71,49 @@ void pry_set_prompts(const char *ps1, const char *ps2)
} }
//From python3 sourcecode //From python3 sourcecode
void pymain_run_interactive_hook(void) int
pymain_run_interactive_hook(int *exitcode)
{ {
PyObject *sys, *hook, *result; PyObject *sys, *hook, *result;
sys = PyImport_ImportModule("sys"); sys = PyImport_ImportModule("sys");
if (sys == NULL) if (sys == NULL) {
{
goto error; goto error;
} }
hook = PyObject_GetAttrString(sys, "__interactivehook__"); hook = PyObject_GetAttrString(sys, "__interactivehook__");
Py_DECREF(sys); Py_DECREF(sys);
if (hook == NULL) if (hook == NULL) {
{
PyErr_Clear(); PyErr_Clear();
return; return 0;
}
if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) {
goto error;
} }
result = _PyObject_CallNoArg(hook); result = _PyObject_CallNoArg(hook);
Py_DECREF(hook); Py_DECREF(hook);
if (result == NULL) if (result == NULL) {
{
goto error; goto error;
} }
Py_DECREF(result); Py_DECREF(result);
return; return 0;
error: error:
PySys_WriteStderr("Failed calling sys.__interactivehook__\n"); PySys_WriteStderr("Failed calling sys.__interactivehook__\n");
PyErr_Print(); return pymain_err_print(exitcode);
}
int
pymain_err_print(int *exitcode_p)
{
int exitcode;
if (_Py_HandleSystemExit(&exitcode)) {
*exitcode_p = exitcode;
return 1;
}
PyErr_Print();
return 0;
} }

View File

@ -1,6 +1,8 @@
#include <Python.h> #include <Python.h>
void pry_eval_file(FILE *f, const char *file, int argn, const char *argv); int pry_eval_file(FILE *f, const char *file, int argn, const char *argv);
const char *pry_eval(const char *code, int start); const char *pry_eval(const char *code, int start);
void pry_set_prompts(const char *ps1, const char *ps2); void pry_set_prompts(const char *ps1, const char *ps2);
void pymain_run_interactive_hook(void); int pymain_run_interactive_hook(int *exitcode);
int pymain_err_print(int *exitcode_p);
PyAPI_FUNC(int) _Py_HandleSystemExit(int *exitcode_p);

View File

@ -34,10 +34,10 @@ func (p Ruby) EvalExpression(code string) string {
return C.GoString(res) return C.GoString(res)
} }
func (p Ruby) EvalFile(file string, args []string) { func (p Ruby) EvalFile(file string, args []string) int {
cfile := C.CString(file) cfile := C.CString(file)
defer C.free(unsafe.Pointer(cfile)) defer C.free(unsafe.Pointer(cfile))
C.pry_eval_file(cfile) return int(C.pry_eval_file(cfile))
} }
func (p Ruby) REPL() { func (p Ruby) REPL() {

View File

@ -36,14 +36,16 @@ char *pry_eval(const char *code)
} }
} }
void pry_eval_file(const char *file) int pry_eval_file(const char *file)
{ {
char *options[] = {"ruby", file}; char *options[] = {"ruby", file};
void *node = ruby_options(2, options); void *node = ruby_options(2, options);
int state; int state = 0;
if (ruby_executable_node(node, &state)) if (ruby_executable_node(node, &state))
{ {
state = ruby_exec_node(node); state = ruby_exec_node(node);
} }
return state;
} }

View File

@ -4,5 +4,5 @@
void pry_open(); void pry_open();
const char *pry_ruby_version(); const char *pry_ruby_version();
char *pry_eval(const char *code); char *pry_eval(const char *code);
void pry_eval_file(const char *file); int pry_eval_file(const char *file);

View File

@ -63,7 +63,7 @@ func (p *Tcl) eval(code string) string {
return "" return ""
} }
func (p *Tcl) EvalFile(file string, args []string) { func (p *Tcl) EvalFile(file string, args []string) int {
cfile := C.CString(file) cfile := C.CString(file)
defer C.free(unsafe.Pointer(cfile)) defer C.free(unsafe.Pointer(cfile))
@ -72,7 +72,10 @@ func (p *Tcl) EvalFile(file string, args []string) {
if status != C.TCL_OK { if status != C.TCL_OK {
errstr := C.GoString(C.Tcl_GetStringResult(p.interp)) errstr := C.GoString(C.Tcl_GetStringResult(p.interp))
fmt.Fprintf(os.Stderr, "error: %s\n", errstr) fmt.Fprintf(os.Stderr, "error: %s\n", errstr)
return int(status)
} }
return 0
} }
func (p *Tcl) Eval(code string) { func (p *Tcl) Eval(code string) {
@ -86,4 +89,5 @@ func (p *Tcl) EvalExpression(code string) string {
func (p *Tcl) Close() { func (p *Tcl) Close() {
C.Tcl_Finalize() C.Tcl_Finalize()
} }
var Instance = &Tcl{} var Instance = &Tcl{}

View File

@ -25,7 +25,7 @@ type PluginEvalExpression interface {
type PluginEvalFile interface { type PluginEvalFile interface {
PluginBase PluginBase
EvalFile(file string, args []string) EvalFile(file string, args []string) int
} }
type PluginREPL interface { type PluginREPL interface {
@ -80,16 +80,17 @@ func (lang Language) REPLLikeEval(code string) {
} }
} }
func (lang Language) EvalFile(file string, args []string) { func (lang Language) EvalFile(file string, args []string) int {
pef, ok := lang.ptr.(PluginEvalFile) pef, ok := lang.ptr.(PluginEvalFile)
if ok { if ok {
pef.EvalFile(file, args) return pef.EvalFile(file, args)
} else { } else {
dat, err := ioutil.ReadFile(file) dat, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
panic(err) panic(err)
} }
lang.Eval(string(dat)) lang.Eval(string(dat))
return 0
} }
} }

View File

@ -58,12 +58,17 @@ func DoCli(p PluginBase) {
if config.Exp != "" { if config.Exp != "" {
lang.EvalAndTryToPrint(config.Exp) lang.EvalAndTryToPrint(config.Exp)
} }
if len(config.Args) > 0 { if len(config.Args) > 0 {
if _, err := os.Stat(config.Args[0]); os.IsNotExist(err) { if _, err := os.Stat(config.Args[0]); os.IsNotExist(err) {
fmt.Println("No such file:", config.Args[0]) fmt.Println("No such file:", config.Args[0])
os.Exit(2) os.Exit(2)
} else { } else {
lang.EvalFile(config.Args[0], config.Args[1:]) exitCode := lang.EvalFile(config.Args[0], config.Args[1:])
// TODO: Maybe log if exitCode is non-zero and interractive is true?
if exitCode != 0 && !config.Interactive && !config.OurInteractive {
os.Exit(exitCode)
}
} }
} }