Skip to content

Commit

Permalink
Implement [ -t 1 ], which calls isatty() on a fd.
Browse files Browse the repository at this point in the history
abuild uses this.

Also add the ability to return 2 for a usage error.
  • Loading branch information
Andy Chu committed Jan 8, 2018
1 parent 5ea4327 commit fa7ea76
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 5 deletions.
12 changes: 12 additions & 0 deletions core/expr_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions core/id_kind.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down
12 changes: 10 additions & 2 deletions core/test_builtin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/python
from __future__ import print_function
"""
test_builtin.py
"""
Expand Down Expand Up @@ -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

Expand All @@ -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
5 changes: 4 additions & 1 deletion core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
12 changes: 12 additions & 0 deletions spec/builtin-test.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

Please sign in to comment.