Permalink
Browse files
Implement [ -t 1 ], which calls isatty() on a fd.
abuild uses this.
Also add the ability to return 2 for a usage error.
- Loading branch information...
Showing
with
40 additions
and
5 deletions.
-
+12
−0
core/expr_eval.py
-
+2
−2
core/id_kind.py
-
+10
−2
core/test_builtin.py
-
+4
−1
core/util.py
-
+12
−0
spec/builtin-test.test.sh
|
|
@@ -477,6 +477,7 @@ def Eval(self, node): |
|
|
|
|
|
# Now dispatch on arg type
|
|
|
arg_type = BOOL_OPS[op_id] # could be static in the LST?
|
|
|
|
|
|
if arg_type == OperandType.Path:
|
|
|
# Only use lstat if we're testing for a symlink.
|
|
|
if op_id in (Id.BoolUnary_h, Id.BoolUnary_L):
|
|
|
@@ -522,6 +523,17 @@ def Eval(self, node): |
|
|
|
|
|
raise NotImplementedError(op_id)
|
|
|
|
|
|
if arg_type == OperandType.Other:
|
|
|
if op_id == Id.BoolUnary_t:
|
|
|
try:
|
|
|
fd = int(s)
|
|
|
except ValueError:
|
|
|
# TODO: Need location information of [
|
|
|
e_die('Invalid file descriptor %r', s)
|
|
|
return os.isatty(fd)
|
|
|
|
|
|
raise NotImplementedError(op_id)
|
|
|
|
|
|
raise NotImplementedError(arg_type)
|
|
|
|
|
|
if node.tag == bool_expr_e.BoolBinary:
|
|
|
|
|
|
@@ -412,8 +412,8 @@ def _AddKinds(spec): |
|
|
|
|
|
# Shared between [[ and test/[.
|
|
|
_UNARY_STR_CHARS = 'zn' # -z -n
|
|
|
_UNARY_OTHER_CHARS = 'ovR' # -o is overloaded
|
|
|
_UNARY_PATH_CHARS = 'abcdefghLprsStuwxOGN' # -a is overloaded
|
|
|
_UNARY_OTHER_CHARS = 'otvR' # -o is overloaded
|
|
|
_UNARY_PATH_CHARS = 'abcdefghLprsSuwxOGN' # -a is overloaded
|
|
|
|
|
|
_BINARY_PATH = ['ef', 'nt', 'ot']
|
|
|
_BINARY_INT = ['eq', 'ne', 'gt', 'ge', 'lt', 'le']
|
|
|
|
|
|
@@ -1,4 +1,5 @@ |
|
|
#!/usr/bin/python
|
|
|
from __future__ import print_function
|
|
|
"""
|
|
|
test_builtin.py
|
|
|
"""
|
|
|
@@ -186,7 +187,14 @@ def Test(argv, need_right_bracket): |
|
|
word_ev = _WordEvaluator()
|
|
|
|
|
|
bool_ev = expr_eval.BoolEvaluator(mem, exec_opts, word_ev)
|
|
|
b = bool_ev.Eval(bool_node)
|
|
|
try:
|
|
|
b = bool_ev.Eval(bool_node)
|
|
|
except util.FatalRuntimeError as e:
|
|
|
# e.g. [ -t xxx ]
|
|
|
# TODO: Printing the location would be nice.
|
|
|
print('test: %s' % e.UserErrorString(), file=sys.stderr)
|
|
|
return 2
|
|
|
|
|
|
status = 0 if b else 1
|
|
|
return status
|
|
|
|
|
|
@@ -196,6 +204,6 @@ def Test(argv, need_right_bracket): |
|
|
e = _StringWordEmitter('-z X -o -z Y -a -z X'.split())
|
|
|
while True:
|
|
|
w = e.ReadWord(None)
|
|
|
print w
|
|
|
print(w)
|
|
|
if w.id == Id.Eof_Real:
|
|
|
break
|
|
|
@@ -74,7 +74,10 @@ class ParseError(_ErrorWithLocation): |
|
|
|
|
|
|
|
|
class FatalRuntimeError(_ErrorWithLocation):
|
|
|
"""Used in the evaluators."""
|
|
|
"""Used in the evaluators.
|
|
|
|
|
|
Also used in test builtin for invalid argument.
|
|
|
"""
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
@@ -220,3 +220,15 @@ dangling |
|
|
dangling
|
|
|
dangling is not file
|
|
|
## END
|
|
|
|
|
|
### -t 1 for stdout
|
|
|
# There isn't way to get a terminal in the test environment?
|
|
|
[ -t 1 ]
|
|
|
echo status=$?
|
|
|
## stdout: status=1
|
|
|
|
|
|
### [ -t invalid ]
|
|
|
[ -t invalid ]
|
|
|
echo status=$?
|
|
|
## stdout: status=2
|
|
|
## BUG bash stdout: status=1
|
0 comments on commit
fa7ea76