OK, more fixes

This commit is contained in:
Anthony Scopatz 2016-11-21 20:50:21 -05:00
parent 35d95b593d
commit 1887864528
3 changed files with 50 additions and 20 deletions

View file

@ -301,13 +301,13 @@ def _dh_create_parser(p=None):
return p
def _dh_main_action(ns, hist=None):
def _dh_main_action(ns, hist=None, stdout=None, stderr=None):
hd = HistoryDiffer(ns.a, ns.b, reopen=ns.reopen, verbose=ns.verbose)
print_color(hd.format())
print_color(hd.format(), file=stdout)
def diff_history_main(args=None, stdin=None):
def diff_history_main(args=None, stdin=None, stdout=None, stderr=None):
"""Main entry point for history diff'ing"""
parser = _dh_create_parser()
ns = parser.parse_args(args)
_dh_main_action(ns)
_dh_main_action(ns, stdout=stdout)

View file

@ -443,7 +443,7 @@ def _hist_get(session='session', *, slices=None, datetime_format=None,
return cmds
def _hist_show(ns, *args, **kwargs):
def _hist_show(ns, hist=None, stdout=None, stderr=None):
"""Show the requested portion of shell history.
Accepts same parameters with `_hist_get`.
"""
@ -454,24 +454,24 @@ def _hist_show(ns, *args, **kwargs):
end_time=ns.end_time,
datetime_format=ns.datetime_format)
except ValueError as err:
print("history: error: {}".format(err), file=sys.stderr)
print("history: error: {}".format(err), file=stderr)
return
if ns.reverse:
commands = reversed(list(commands))
if not ns.numerate and not ns.timestamp:
for c, _, _ in commands:
print(c)
print(c, file=stdout)
elif not ns.timestamp:
for c, _, i in commands:
print('{}: {}'.format(i, c))
print('{}: {}'.format(i, c), file=stdout)
elif not ns.numerate:
for c, ts, _ in commands:
dt = datetime.datetime.fromtimestamp(ts).ctime()
print('({}) {}'.format(dt, c))
print('({}) {}'.format(dt, c), file=stdout)
else:
for c, ts, i in commands:
dt = datetime.datetime.fromtimestamp(ts).ctime()
print('{}:({}) {}'.format(i, dt, c))
print('{}:({}) {}'.format(i, dt, c), file=stdout)
# Interface to History
@ -689,7 +689,7 @@ class History(object):
'you can create new though.')
def _hist_info(ns, hist):
def _hist_info(ns, hist, stdout, stderr):
"""Display information about the shell history."""
data = collections.OrderedDict()
data['sessionid'] = str(hist.sessionid)
@ -699,10 +699,10 @@ def _hist_info(ns, hist):
data['bufferlength'] = len(hist.buffer)
if ns.json:
s = json.dumps(data)
print(s)
print(s, file=stdout)
else:
lines = ['{0}: {1}'.format(k, v) for k, v in data.items()]
print('\n'.join(lines))
print('\n'.join(lines), file=stdout)
def _hist_gc(ns, hist):
@ -726,12 +726,12 @@ def _HIST_SESSIONS():
def _HIST_MAIN_ACTIONS():
return {
'show': _hist_show,
'id': lambda ns, hist: print(hist.sessionid),
'file': lambda ns, hist: print(hist.filename),
'id': lambda ns, hist, stdout, stderr: print(hist.sessionid, file=stdout),
'file': lambda ns, hist, stdout, stderr: print(hist.filename, file=stdout),
'info': _hist_info,
'diff': _dh_main_action,
'gc': _hist_gc,
}
}
def _hist_parse_args(args):
@ -759,9 +759,9 @@ def _hist_parse_args(args):
return ns
def history_main(args=None, stdin=None):
def history_main(args=None, stdin=None, stdout=None, stderr=None):
"""This is the history command entry point."""
hist = builtins.__xonsh_history__
ns = _hist_parse_args(args)
if ns:
_HIST_MAIN_ACTIONS[ns.action](ns, hist)
_HIST_MAIN_ACTIONS[ns.action](ns, hist, stdout, stderr)

View file

@ -491,6 +491,18 @@ def safe_flush(handle):
return status
def still_writable(fd):
"""Determines whether a file descriptior is still writable by trying to
write an empty string and seeing if it fails.
"""
try:
os.write(fd, b'')
status = True
except OSError:
status = False
return status
class PopenThread(threading.Thread):
"""A thread for running and managing subprocess. This allows reading
from the stdin, stdout, and stderr streams in a non-blocking fashion.
@ -1010,8 +1022,11 @@ class FileThreadDispatcher:
extra sure the string was written.
"""
h = self.handle
r = h.write(s)
safe_flush(h)
try:
r = h.write(s)
h.flush()
except OSError:
r = None
return r
@property
@ -1286,6 +1301,21 @@ class ProcProxyThread(threading.Thread):
r = self.f(self.args, sp_stdin, sp_stdout, sp_stderr, spec)
except SystemExit as e:
r = e.code if isinstance(e.code, int) else int(bool(e.code))
except OSError as e:
status = still_writable(self.c2pwrite) and \
still_writable(self.errwrite)
if status:
# stdout and stderr are still writable, so error must
# come from function itself.
print_exception()
r = 1
else:
# stdout and stderr are no longer writable, so error must
# come from the fact that the next process in the pipeline
# has closed the other side of the pipe. The function then
# attempted to write to this side of the pipe anyway. This
# is not truly an error and we should exit gracefully.
r = 0
except Exception:
print_exception()
r = 1