more edits

This commit is contained in:
Anthony Scopatz 2016-09-06 00:44:16 -04:00
parent 7958e66b2c
commit e728fdf7fa
2 changed files with 137 additions and 52 deletions

View file

@ -367,7 +367,7 @@ def no_pg_xonsh_preexec_fn():
signal.signal(signal.SIGTSTP, default_signal_pauser)
class SubprocCmd:
class SubprocSpec:
"""A container for specifiying how a subprocess command should be
executed.
"""
@ -560,16 +560,16 @@ class SubprocCmd:
was recieved.
"""
# modifications that do not alter cmds may come before creating instance
p = kls(cmd, cls=cls, **kwargs)
spec = kls(cmd, cls=cls, **kwargs)
# modifications that alter cmds must come after creating instance
self.redirect_leading()
self.redirect_trailing()
self.resolve_alias()
self.resolve_binary_loc()
self.resolve_auto_cd()
self.resolve_executable_commands()
self.resolve_alias_cls()
return p
spec.redirect_leading()
spec.redirect_trailing()
spec.resolve_alias()
spec.resolve_binary_loc()
sped.resolve_auto_cd()
spec.resolve_executable_commands()
spec.resolve_alias_cls()
return spec
def redirect_leading(self):
"""Manage leading redirects such as with '< input.txt COMMAND'. """
@ -664,7 +664,7 @@ def stdout_capture_kinds():
return frozenset(['stdout', 'object'])
def _update_last_subproc(last, captured=False)
def _update_last_spec(last, captured=False)
env = builtins.__xonsh_env__
# set standard in
if (last.stdin is not None and captured == 'object' and
@ -704,32 +704,32 @@ def _update_last_subproc(last, captured=False)
last.captured_stderr = last.stderr
def cmds_to_subprocs(cmds, captured=False):
"""Converts a list of cmds to a list of SubprocCmd objects that are
def cmds_to_specs(cmds, captured=False):
"""Converts a list of cmds to a list of SubprocSpec objects that are
ready to be executed.
"""
# first build the subprocs independently and separate from the redirects
subprocs = []
specs = []
redirects = []
for cmd in cmds:
if isinstance(cmd, str):
redirects.append(cmd)
else:
subproc = SubprocCmd.build(cmd)
subprocs.append(subproc)
spec = SubprocSpec.build(cmd)
spes.append(spec)
# now modify the subprocs based on the redirects.
for i, redirect in enumerate(redirects):
if redirect == '|':
r, w = os.pipe()
subprocs[i].stdout = w
subprocs[i + 1].stdin = r
specs[i].stdout = w
specs[i + 1].stdin = r
elif redirect == '&' and i == len(redirects) - 1:
subprocs[-1].background = True
specs[-1].background = True
else:
raise XonshError('unrecognized redirect {0!r}'.format(redirect))
# Apply boundry conditions
_update_last_subproc(subproc[-1], captured=captured)
return subprocs
_update_last_spec(spec[-1], captured=captured)
return specs
def _should_set_title(captured=False):
@ -754,22 +754,22 @@ def run_subproc(cmds, captured=False):
Lastly, the captured argument affects only the last real command.
"""
env = builtins.__xonsh_env__
subprocs = cmds_to_subprocs(cmds, captured=captured)
specs = cmds_to_specs(cmds, captured=captured)
procs = []
proc = pipeline_group = None
for subproc in subprocs:
for spec in specs:
starttime = time.time()
proc = subproc.run(pipeline_group=pipeline_group)
proc = spec.run(pipeline_group=pipeline_group)
procs.append(proc)
if ON_POSIX and pipeline_group is None and \
subproc.cls is subprocess.Popen:
pipeline_group = prev_proc.pid
spec.cls is subprocess.Popen:
pipeline_group = proc.pid
if not subproc.is_proxy:
add_job({
'cmds': cmds,
'pids': [i.pid for i in procs],
'obj': proc,
'bg': subproc.background
'bg': spec.background
})
procinfo = {}
if _should_set_title(captured=captured):

View file

@ -552,31 +552,41 @@ def _wcode_to_popen(code):
raise ValueError("Invalid os.wait code: {}".format(code))
_CCTuple = collections.namedtuple("_CCTuple", ["stdin", "stdout", "stderr",
"pid", "returncode", "args", "alias", "stdin_redirect",
"stdout_redirect", "stderr_redirect", "timestamp",
"executed_cmd"])
class Command:
"""Represents a subprocess-mode command."""
attrnames = ("stdin", "stdout", "stderr", "pid", "returncode", "args",
"alias", "stdin_redirect", "stdout_redirect",
"stderr_redirect", "timestamp", "executed_cmd")
class CompletedCommand(_CCTuple):
"""Represents a completed subprocess-mode command."""
def __init__(self, spec, proc, timestamp):
"""
Parameters
----------
spec : SubprocSpec
Process sepcification
proc : Popen-like
Process object.
"""
self.proc = proc
self.spec = spec
self.timestamp = timestamp
def __bool__(self):
return self.returncode == 0
def __iter__(self):
if not self.stdout:
proc = self.proc
stdout = proc.stdout
if not stdout:
if not proc.poll():
proc.wait()
self.endtime()
raise StopIteration()
pre = self.stdout
post = None
while post != '':
pre, sep, post = pre.partition('\n')
# this line may be optional since we use universal newlines.
pre = pre[:-1] if pre and pre[-1] == '\r' else pre
yield pre
pre = post
while not proc.poll():
yield from stdout.readlines(1024)
self.endtime()
yield from stdout.readlines()
def itercheck(self):
yield from self
@ -586,31 +596,106 @@ class CompletedCommand(_CCTuple):
raise XonshCalledProcessError(self.returncode, self.executed_cmd,
self.stdout, self.stderr, self)
def endtime(self):
"""Sets the closing timestamp if it hasn't been already."""
if self.timestamp[1] is None:
self.timestamp[1] = time.time()
#
# Properties
#
@propertybh
def stdin(self):
"""Process stdin."""
return self.proc.stdin
@property
def inp(self):
"""Creates normalized input string from args."""
return ' '.join(self.args)
@property
def out(self):
"""Alias to stdout."""
return self.stdout
def stdout(self):
"""Process stdout."""
return self.proc.stdout
out = stdout
@property
def err(self):
"""Alias to stderr."""
return self.stderr
def stderr(self):
"""Process stderr."""
return self.proc.stderr
err = stdout
@property
def pid(self):
"""Process identifier."""
return self.proc.pid
@property
def returncode(self):
"""Process return code, waits until command is completed."""
proc = self.proc
if proc.returncode is None:
proc.wait()
self.endtime()
return proc.returncode
rtn = returncode
@property
def rtn(self):
"""Alias to return code."""
return self.returncode
@property
def args(self):
"""Arguments to the process."""
return self.spec.args
CompletedCommand.__new__.__defaults__ = (None,) * len(CompletedCommand._fields)
@property
def rtn(self):
"""Alias to return code."""
return self.returncode
@property
def alias(self):
"""Alias the process used."""
return self.spec.alias
@property
def stdin_redirect(self):
"""Redirection used for stdin."""
stdin = self.spec.stdin
name = getattr(stdin, 'name', '<stdin>')
mode = getattr(stdin, 'mode', 'r')
return [name, mode]
@property
def sdtout_redirect(self):
"""Redirection used for stdout."""
stdout = self.spec.stdout
name = getattr(stdout, 'name', '<stdout>')
mode = getattr(stdout, 'mode', 'a')
return [name, mode]
@property
def stderr_redirect(self):
"""Redirection used for stderr."""
stderr = self.spec.stderr
name = getattr(stderr, 'name', '<stderr>')
mode = getattr(stderr, 'mode', 'r')
return [name, mode]
@propery
def executed_cmd(self):
"""The resolve and executed command."""
return self.spec.cmd
class HiddenCompletedCommand(CompletedCommand):
class HiddenCommand(Command):
def __repr__(self):
return ''