New helper CommandlineCaller

Wraps sarge and allows asynchronous execution of commands incl. logging
to provided logging methods for stdout, stderr and command calls.

Refactored PipCaller to utilized that.
This commit is contained in:
Gina Häußge 2015-07-03 13:56:31 +02:00
parent 5674de9c2f
commit 6f24a2b6c5
2 changed files with 93 additions and 52 deletions

View file

@ -0,0 +1,87 @@
# coding=utf-8
from __future__ import absolute_import
__author__ = "Gina Häußge <osd@foosel.net>"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
__copyright__ = "Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License"
import sarge
import logging
class CommandlineError(Exception):
def __init__(self, returncode, stdout, stderr):
self.returncode = returncode
self.stdout = stdout
self.stderr = stderr
class CommandlineCaller(object):
def __init__(self):
self._logger = logging.getLogger(__name__)
self.on_log_call = lambda *args, **kwargs: None
self.on_log_stdout = lambda *args, **kwargs: None
self.on_log_stderr = lambda *args, **kwargs: None
def checked_call(self, command, **kwargs):
returncode, stdout, stderr = self.call(command, **kwargs)
if returncode != 0:
raise CommandlineError(returncode, stdout, stderr)
return returncode, stdout, stderr
def call(self, command, **kwargs):
if isinstance(command, (list, tuple)):
joined_command = " ".join(command)
else:
joined_command = command
self._logger.debug(u"Calling: {}".format(joined_command))
self.on_log_call(joined_command)
kwargs.update(dict(async=True, stdout=sarge.Capture(), stderr=sarge.Capture()))
p = sarge.run(command, **kwargs)
p.wait_events()
all_stdout = []
all_stderr = []
try:
while p.returncode is None:
line = p.stderr.readline(timeout=0.5)
if line:
self._log_stderr(line)
all_stderr.append(line)
line = p.stdout.readline(timeout=0.5)
if line:
self._log_stdout(line)
all_stdout.append(line)
p.commands[0].poll()
finally:
p.close()
stderr = p.stderr.text
if stderr:
split_lines = stderr.split("\n")
self._log_stderr(*split_lines)
all_stderr += split_lines
stdout = p.stdout.text
if stdout:
split_lines = stdout.split("\n")
self._log_stdout(*split_lines)
all_stdout += split_lines
return p.returncode, all_stdout, all_stderr
def _log_stdout(self, *lines):
self.on_log_stdout(*lines)
def _log_stderr(self, *lines):
self.on_log_stderr(*lines)

View file

@ -3,19 +3,22 @@ from __future__ import absolute_import
__author__ = "Gina Häußge <osd@foosel.net>"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
__copyright__ = "Copyright (C) 2014 The OctoPrint Project - Released under terms of the AGPLv3 License"
__copyright__ = "Copyright (C) 2015 The OctoPrint Project - Released under terms of the AGPLv3 License"
import sarge
import sys
import logging
from .commandline import CommandlineCaller
class UnknownPip(Exception):
pass
class PipCaller(object):
class PipCaller(CommandlineCaller):
def __init__(self, configured=None):
CommandlineCaller.__init__(self)
self._logger = logging.getLogger(__name__)
self._configured = configured
@ -26,9 +29,6 @@ class PipCaller(object):
self._command, self._version = self._find_pip()
self.refresh = False
self.on_log_call = lambda *args, **kwargs: None
self.on_log_stdout = lambda *args, **kwargs: None
self.on_log_stderr = lambda *args, **kwargs: None
def __le__(self, other):
return self.version is not None and self.version <= other
@ -63,47 +63,7 @@ class PipCaller(object):
raise UnknownPip()
command = [self._command] + list(args)
joined_command = " ".join(command)
self._logger.debug(u"Calling: {}".format(joined_command))
self.on_log_call(joined_command)
p = sarge.run(command, async=True, stdout=sarge.Capture(), stderr=sarge.Capture())
p.wait_events()
all_stdout = []
all_stderr = []
try:
while p.returncode is None:
line = p.stderr.readline(timeout=0.5)
if line:
self._log_stderr(line)
all_stderr.append(line)
line = p.stdout.readline(timeout=0.5)
if line:
self._log_stdout(line)
all_stdout.append(line)
p.commands[0].poll()
finally:
p.close()
stderr = p.stderr.text
if stderr:
split_lines = stderr.split("\n")
self._log_stderr(*split_lines)
all_stderr += split_lines
stdout = p.stdout.text
if stdout:
split_lines = stdout.split("\n")
self._log_stdout(*split_lines)
all_stdout += split_lines
return p.returncode, all_stdout, all_stderr
return self.call(command)
def _find_pip(self):
pip_command = self._configured
@ -170,9 +130,3 @@ class PipCaller(object):
self._logger.info("Found pip at {}, version is {}".format(pip_command, version_segment))
return pip_command, pip_version
def _log_stdout(self, *lines):
self.on_log_stdout(*lines)
def _log_stderr(self, *lines):
self.on_log_stderr(*lines)