Skip to content

Commit d303d93

Browse files
author
Andy C
committed
[main] --eval stops on normal errors
AND when $? is non-zero after evaluating a file. (This matters only for OSH.) [doc/ref] Document --eval Improve osh --help and ysh --help.
1 parent a54e666 commit d303d93

9 files changed

+156
-39
lines changed

core/main_loop.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ def EvalFile(
446446
cmd_ev, # type: cmd_eval.CommandEvaluator
447447
lang, # type: str
448448
):
449-
# type: (...) -> bool
449+
# type: (...) -> Tuple[bool, int]
450450
"""Evaluate a disk file, for --eval --eval-pure
451451
452452
Copied and adapted from the 'source' builtin in builtin/meta_oils.py.
@@ -463,7 +463,7 @@ def EvalFile(
463463
except (IOError, OSError) as e:
464464
print_stderr("%s: Couldn't open %r for --eval: %s" %
465465
(lang, fs_path, posix.strerror(e.errno)))
466-
return False
466+
return False, -1
467467

468468
line_reader = reader.FileLineReader(f, cmd_ev.arena)
469469
c_parser = parse_ctx.MakeOshParser(line_reader)
@@ -477,8 +477,8 @@ def EvalFile(
477477
src = source.MainFile(fs_path)
478478
with alloc.ctx_SourceCode(cmd_ev.arena, src):
479479
# May raise util.UserExit
480-
was_parsed, unused = Batch2(cmd_ev, c_parser, cmd_ev.errfmt)
480+
was_parsed, status = Batch2(cmd_ev, c_parser, cmd_ev.errfmt)
481481
if not was_parsed:
482-
return False
482+
return False, -1
483483

484-
return True
484+
return True, status

core/shell.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -962,15 +962,22 @@ def Main(
962962
for path, is_pure in attrs.eval_flags:
963963
# TODO: respect is_pure
964964
try:
965-
ok = main_loop.EvalFile(path, fd_state, parse_ctx, cmd_ev, lang)
965+
ok, status = main_loop.EvalFile(path, fd_state, parse_ctx, cmd_ev,
966+
lang)
966967
except util.UserExit as e:
967968
# Doesn't seem like we need this, and verbose_errexit isn't the right option
968969
#if exec_opts.verbose_errexit():
969970
# print-stderr('oils: --eval exit')
970971
return e.status
971-
if not ok: # parse error or I/O error was already printed
972+
973+
# I/O error opening file, parse error. Message was # already printed.
974+
if not ok:
972975
return 1
973976

977+
# Runtime error
978+
if status != 0:
979+
return status
980+
974981
#
975982
# Is the shell interactive?
976983
#

core/util.py

+4
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ def HelpFlag(loader, topic_id, f):
160160
# Note: could assert this in C++ too
161161
assert found, 'Missing %s' % topic_id
162162

163+
found = PrintEmbeddedHelp(loader, 'shell-flags', f)
164+
# Note: could assert this in C++ too
165+
assert found, 'Missing %s' % topic_id
166+
163167

164168
def VersionFlag(loader, f):
165169
# type: (pyutil._ResourceLoader, mylib.Writer) -> None

doc/ref/chap-front-end.md

+53-24
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ This chapter describes command line usage and lexing.
3131
```
3232
bin/oils-for-unix is an executable that contains OSH, YSH, and more.
3333
34-
Usage: oils-for-unix MAIN_NAME ARG*
35-
MAIN_NAME ARG*
34+
Usage:
35+
oils-for-unix MAIN_NAME ARG*
36+
MAIN_NAME ARG*
3637
3738
It behaves like busybox. The command name can be passed as the first argument:
3839
@@ -54,25 +55,16 @@ behave like that command:
5455
```
5556
bin/osh is compatible with POSIX shell, bash, and other shells.
5657
57-
Usage: osh FLAG* SCRIPT ARG*
58-
osh FLAG* -c COMMAND ARG*
59-
osh FLAG*
60-
61-
The command line accepted by `bin/osh` is compatible with /bin/sh and bash.
58+
Usage:
59+
osh FLAG* SCRIPT ARG*
60+
osh FLAG* -c COMMAND ARG*
61+
osh FLAG*
6262
63+
Examples:
6364
osh -c 'echo hi'
6465
osh myscript.sh
6566
echo 'echo hi' | osh
6667
67-
It also has a few enhancements:
68-
69-
osh -n -c 'hello' # pretty-print the AST
70-
osh --ast-format text -n -c 'hello' # print it full
71-
72-
osh accepts POSIX sh flags, with these additions:
73-
74-
-n parse the program but don't execute it. Print the AST.
75-
--ast-format what format the AST should be in
7668
```
7769

7870
<h3 id="ysh-usage" class="ysh-topic" oils-embed="1">
@@ -84,23 +76,47 @@ osh accepts POSIX sh flags, with these additions:
8476
```
8577
bin/ysh is the shell with data tYpes, influenced by pYthon, JavaScript, ...
8678
87-
Usage: ysh FLAG* SCRIPT ARG*
88-
ysh FLAG* -c COMMAND ARG*
89-
ysh FLAG*
79+
Usage:
80+
ysh FLAG* SCRIPT ARG*
81+
ysh FLAG* -c COMMAND ARG*
82+
ysh FLAG*
9083
9184
Examples:
92-
9385
ysh -c 'echo hi'
9486
ysh myscript.ysh
9587
echo 'echo hi' | ysh
9688
97-
bin/ysh is the same as bin/osh with a the ysh:all option group set. So bin/ysh
98-
also accepts shell flags. Examples:
89+
Note that bin/ysh is the same as bin/osh with the ysh:all option group set:
90+
osh -o ysh:all -c 'echo hi' # Same as YSH
91+
```
92+
93+
<h3 id="shell-flags" oils-embed="1">
94+
shell-flags
95+
</h3>
9996

97+
```
98+
osh and ysh accept standard POSIX shell flags, like:
99+
100+
bin/osh -o errexit -c 'false'
100101
bin/ysh -n myfile.ysh
101102
bin/ysh +o errexit -c 'false; echo ok'
102-
```
103103
104+
They also accept these flags:
105+
106+
-n Parse the program but don't execute it. Print the AST.
107+
--ast-format FMT The format for the AST (text|text-abbrev)
108+
--eval FILE Evaluate the given file, similar to the 'source' builtin.
109+
Specify it multiple times to run multiple files. The
110+
shell stops on normal errors, as well as when $? is
111+
non-zero after evaluating a file (even if errexit is
112+
off).
113+
--tool Run a tool instead of the shell (cat-em|syntax-tree)
114+
115+
Examples:
116+
117+
osh -n -c 'hello' # pretty-print the AST
118+
ysh --ast-format text -n -c 'hello' # print it full
119+
```
104120

105121
<h3 id="config" class="osh-ysh-topic">config</h3>
106122

@@ -123,7 +139,10 @@ Pass --norc to disable the startup directory.
123139

124140
<h3 id="startup" class="osh-ysh-topic">startup</h3>
125141

126-
History is read?
142+
TODO:
143+
144+
1. History is read
145+
1. ...
127146

128147
<h3 id="line-editing" class="osh-ysh-topic">line-editing</h3>
129148

@@ -302,6 +321,16 @@ Print files embedded in the `oils-for-unix` binary to stdout. Example:
302321

303322
osh --tool cat-em stdlib/math.ysh stdlib/other.ysh
304323

324+
### syntax-tree
325+
326+
Print the syntax tree in a debug format.
327+
328+
osh --tool syntax-tree stdlib/ysh/math.ysh
329+
330+
The `-n` flag is a shortcut:
331+
332+
osh -n stdlib/ysh/math.ysh
333+
305334

306335
## Help Chapters
307336

doc/ref/toc-osh.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ X [Unsupported] enable
9191
</h2>
9292

9393
```chapter-links-front-end
94-
[Usage] oils-usage osh-usage config
95-
startup line-editing exit-codes
94+
[Usage] oils-usage osh-usage shell-flags
95+
config startup line-editing
96+
exit-codes
9697
[Lexing] comment # line-continuation \ ascii-whitespace [ \t\r\n]
9798
```
9899

doc/ref/toc-ysh.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,12 @@ X [External Lang] BEGIN END when (awk)
220220
</h2>
221221

222222
```chapter-links-front-end
223-
[Usage] oils-usage ysh-usage
224-
[Lexing] ascii-whitespace [ \t\r\n]
225-
doc-comment ### multiline-command ...
226-
[Tools] cat-em
223+
[Usage] oils-usage ysh-usage shell-flags
224+
config startup line-editing
225+
exit-codes
226+
[Lexing] comment # line-continuation \ ascii-whitespace [ \t\r\n]
227+
[Lexing] doc-comment ### multiline-command ...
228+
[Tools] cat-em syntax-tree
227229
```
228230

229231
<h2 id="cmd-lang">

spec/hay.test.sh

+46-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## oils_failures_allowed: 4
1+
## oils_failures_allowed: 5
22

33
# Hay: Hay Ain't YAML
44

@@ -811,3 +811,48 @@ json write (_hay().children[0].attrs)
811811
}
812812
## END
813813

814+
815+
#### Using Hay with --eval flags
816+
shopt --set ysh:all
817+
818+
echo 'hay define Package' >pre.ysh
819+
820+
echo '
821+
Package cpython {
822+
version = "3.12"
823+
url = "https://python.org/"
824+
if (false) {
825+
proc build {
826+
echo $version
827+
}
828+
}
829+
}
830+
' >def.hay
831+
832+
# TODO:
833+
# - nullify_fields=true - well some of them aren't fields
834+
# - nullify=true
835+
# - errors='null'
836+
# - on_error=null
837+
# - drop_with='error' drop_with='null'
838+
# - degrade_to_null=true
839+
# - replace_with_null=true
840+
# - null_replace=true
841+
# - null_replacer=true # replacer can be a function?
842+
# - errors=false # too vague?
843+
#
844+
# JavaScript has a second "replacer" arg, which can be a function, or an array
845+
# I guess you can specify replacer=null
846+
847+
echo 'json write (_hay())' > post.ysh
848+
849+
... $[ENV.SH] -o ysh:all
850+
--eval pre.ysh
851+
--eval def.hay
852+
--eval post.ysh
853+
-c ''
854+
;
855+
856+
## STDOUT:
857+
a
858+
## END

spec/sh-usage.test.sh

+29
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,32 @@ $SH --login -c 'exit 0'
9292
## OK dash status: 2
9393
## OK mksh status: 1
9494

95+
96+
#### osh --eval
97+
case $SH in bash|dash|mksh|zsh) exit ;; esac
98+
99+
echo 'echo one "$@"' > one.sh
100+
echo 'echo fail "$@"; ( exit 42 )' > fail.sh
101+
102+
$SH --eval one.sh \
103+
-c 'echo flag -c "$@"' dummy x y z
104+
echo
105+
106+
# Even though errexit is off, the shell exits if the last status of an --eval
107+
# file was non-zero.
108+
109+
$SH --eval one.sh --eval fail.sh \
110+
-c 'echo flag -c "$@"' dummy x y z
111+
echo status=$?
112+
113+
## STDOUT:
114+
one x y z
115+
flag -c x y z
116+
117+
one x y z
118+
fail x y z
119+
status=42
120+
## END
121+
122+
## N-I bash/dash/mksh/zsh STDOUT:
123+
## END

spec/ysh-usage.test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ echo 'echo flag --eval; false; echo bye' >bad.ysh
8282

8383
$[ENV.SH] --eval bad.ysh -c 'echo flag -c'
8484

85+
## status: 1
8586
## STDOUT:
8687
flag --eval
87-
flag -c
8888
## END
8989

9090
#### ysh --eval exit status

0 commit comments

Comments
 (0)