shell_command: add ability to cancel a running process
Also adds an indefinite timeout if the timeout is specified as "None". Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
3d1faebf15
commit
6905515f3d
|
@ -19,6 +19,7 @@ class ShellCommand:
|
||||||
cmd = os.path.expanduser(cmd)
|
cmd = os.path.expanduser(cmd)
|
||||||
self.command = shlex.split(cmd)
|
self.command = shlex.split(cmd)
|
||||||
self.partial_output = b""
|
self.partial_output = b""
|
||||||
|
self.cancelled = False
|
||||||
|
|
||||||
def _process_output(self, fd, events):
|
def _process_output(self, fd, events):
|
||||||
if events & IOLoop.ERROR:
|
if events & IOLoop.ERROR:
|
||||||
|
@ -40,7 +41,14 @@ class ShellCommand:
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception("Error writing command output")
|
logging.exception("Error writing command output")
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
self.cancelled = True
|
||||||
|
|
||||||
async def run(self, timeout=2., verbose=True):
|
async def run(self, timeout=2., verbose=True):
|
||||||
|
fd = None
|
||||||
|
if timeout is None:
|
||||||
|
# Never timeout
|
||||||
|
timeout = 9999999999999999.
|
||||||
if not timeout or self.output_cb is None:
|
if not timeout or self.output_cb is None:
|
||||||
# Fire and forget commands cannot be verbose as we can't
|
# Fire and forget commands cannot be verbose as we can't
|
||||||
# clean up after the process terminates
|
# clean up after the process terminates
|
||||||
|
@ -58,7 +66,7 @@ class ShellCommand:
|
||||||
fd, self._process_output, IOLoop.READ | IOLoop.ERROR)
|
fd, self._process_output, IOLoop.READ | IOLoop.ERROR)
|
||||||
elif not timeout:
|
elif not timeout:
|
||||||
# fire and forget, return from execution
|
# fire and forget, return from execution
|
||||||
return
|
return True
|
||||||
sleeptime = 0
|
sleeptime = 0
|
||||||
complete = False
|
complete = False
|
||||||
while sleeptime < timeout:
|
while sleeptime < timeout:
|
||||||
|
@ -67,6 +75,8 @@ class ShellCommand:
|
||||||
if proc.poll() is not None:
|
if proc.poll() is not None:
|
||||||
complete = True
|
complete = True
|
||||||
break
|
break
|
||||||
|
if self.cancelled:
|
||||||
|
break
|
||||||
if not complete:
|
if not complete:
|
||||||
proc.terminate()
|
proc.terminate()
|
||||||
if verbose:
|
if verbose:
|
||||||
|
@ -75,10 +85,13 @@ class ShellCommand:
|
||||||
self.partial_output = b""
|
self.partial_output = b""
|
||||||
if complete:
|
if complete:
|
||||||
msg = f"Command ({self.name}) finished"
|
msg = f"Command ({self.name}) finished"
|
||||||
|
elif self.cancelled:
|
||||||
|
msg = f"Command ({self.name}) cancelled"
|
||||||
else:
|
else:
|
||||||
msg = f"Command ({self.name}) timed out"
|
msg = f"Command ({self.name}) timed out"
|
||||||
logging.info(msg)
|
logging.info(msg)
|
||||||
self.io_loop.remove_handler(fd)
|
self.io_loop.remove_handler(fd)
|
||||||
|
return complete
|
||||||
|
|
||||||
class ShellCommandFactory:
|
class ShellCommandFactory:
|
||||||
def build_shell_command(self, cmd, callback):
|
def build_shell_command(self, cmd, callback):
|
||||||
|
|
Loading…
Reference in New Issue