mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 16:34:47 +01:00
more edits
This commit is contained in:
parent
7958e66b2c
commit
e728fdf7fa
2 changed files with 137 additions and 52 deletions
|
@ -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):
|
||||
|
|
135
xonsh/proc.py
135
xonsh/proc.py
|
@ -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 ''
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue