OctoPrint update script now logs asynchronously

stdout and stderr of executed commands was previously only logged at
the very end, now gets logged when it is received.
This commit is contained in:
Gina Häußge 2015-07-03 14:00:01 +02:00
parent be8827b67c
commit a1735190d5

View file

@ -1,5 +1,5 @@
#!/bin/env python
from __future__ import absolute_import
from __future__ import absolute_import, print_function
__author__ = "Gina Haeussge <osd@foosel.net>"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
@ -7,9 +7,76 @@ __copyright__ = "Copyright (C) 2014 The OctoPrint Project - Released under terms
import errno
import subprocess
import sys
def _log_call(*lines):
_log(lines, prefix=">", stream="call")
def _log_stdout(*lines):
_log(lines, prefix=" ", stream="stdout")
def _log_stderr(*lines):
_log(lines, prefix=" ", stream="stderr")
def _log(lines, prefix=None, stream=None):
output_stream = sys.stdout
if stream == "stderr":
output_stream = sys.stderr
for line in lines:
print(u"{} {}".format(prefix, line.strip()), file=output_stream)
def _execute(command, **kwargs):
import sarge
if isinstance(command, (list, tuple)):
joined_command = " ".join(command)
else:
joined_command = command
_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:
_log_stderr(line)
all_stderr.append(line)
line = p.stdout.readline(timeout=0.5)
if line:
_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")
_log_stderr(*split_lines)
all_stderr += split_lines
stdout = p.stdout.text
if stdout:
split_lines = stdout.split("\n")
_log_stdout(*split_lines)
all_stdout += split_lines
return p.returncode, all_stdout, all_stderr
def _get_git_executables():
GITS = ["git"]
@ -18,7 +85,7 @@ def _get_git_executables():
return GITS
def _git(args, cwd, hide_stderr=False, verbose=False, git_executable=None):
def _git(args, cwd, verbose=False, git_executable=None):
if git_executable is not None:
commands = [git_executable]
else:
@ -26,10 +93,7 @@ def _git(args, cwd, hide_stderr=False, verbose=False, git_executable=None):
for c in commands:
try:
p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
stderr=(subprocess.PIPE if hide_stderr
else None))
break
return _execute([c] + args, cwd=cwd)
except EnvironmentError:
e = sys.exc_info()[1]
if e.errno == errno.ENOENT:
@ -43,37 +107,20 @@ def _git(args, cwd, hide_stderr=False, verbose=False, git_executable=None):
print("unable to find command, tried %s" % (commands,))
return None, None
stdout = p.communicate()[0].strip()
if sys.version >= '3':
stdout = stdout.decode()
if p.returncode != 0:
if verbose:
print("unable to run %s (error)" % args[0])
return p.returncode, stdout
def _python(args, cwd, python_executable, sudo=False):
command = [python_executable] + args
if sudo:
command = ["sudo"] + command
try:
p = subprocess.Popen(command, cwd=cwd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
return _execute(command, cwd=cwd)
except:
return None, None
stdout = p.communicate()[0].strip()
if sys.version >= "3":
stdout = stdout.decode()
return p.returncode, stdout
def update_source(git_executable, folder, target, force=False):
print(">>> Running: git diff --shortstat")
returncode, stdout = _git(["diff", "--shortstat"], folder, git_executable=git_executable)
returncode, stdout, stderr = _git(["diff", "--shortstat"], folder, git_executable=git_executable)
if returncode != 0:
raise RuntimeError("Could not update, \"git diff\" failed with returncode %d: %s" % (returncode, stdout))
if stdout and stdout.strip():
@ -84,7 +131,7 @@ def update_source(git_executable, folder, target, force=False):
patch = os.path.join(folder, "%s-preupdate.patch" % timestamp)
print(">>> Running: git diff and saving output to %s" % timestamp)
returncode, stdout = _git(["diff"], folder, git_executable=git_executable)
returncode, stdout, stderr = _git(["diff"], folder, git_executable=git_executable)
if returncode != 0:
raise RuntimeError("Could not update, installation directory was dirty and state could not be persisted as a patch to %s" % patch)
@ -92,43 +139,39 @@ def update_source(git_executable, folder, target, force=False):
f.write(stdout)
print(">>> Running: git reset --hard")
returncode, stdout = _git(["reset", "--hard"], folder, git_executable=git_executable)
returncode, stdout, stderr = _git(["reset", "--hard"], folder, git_executable=git_executable)
if returncode != 0:
raise RuntimeError("Could not update, \"git reset --hard\" failed with returncode %d: %s" % (returncode, stdout))
print(">>> Running: git pull")
returncode, stdout = _git(["pull"], folder, git_executable=git_executable)
returncode, stdout, stderr = _git(["pull"], folder, git_executable=git_executable)
if returncode != 0:
raise RuntimeError("Could not update, \"git pull\" failed with returncode %d: %s" % (returncode, stdout))
print(stdout)
if force:
reset_command = ["reset"]
reset_command += [target]
print(">>> Running: git %s" % " ".join(reset_command))
returncode, stdout = _git(reset_command, folder, git_executable=git_executable)
returncode, stdout, stderr = _git(reset_command, folder, git_executable=git_executable)
if returncode != 0:
raise RuntimeError("Error while updating, \"git %s\" failed with returncode %d: %s" % (" ".join(reset_command), returncode, stdout))
print(stdout)
def install_source(python_executable, folder, user=False, sudo=False):
print(">>> Running: python setup.py clean")
returncode, stdout = _python(["setup.py", "clean"], folder, python_executable)
returncode, stdout, stderr = _python(["setup.py", "clean"], folder, python_executable)
if returncode != 0:
print("\"python setup.py clean\" failed with returncode %d: %s" % (returncode, stdout))
print("Continuing anyways")
print(stdout)
print(">>> Running: python setup.py install")
args = ["setup.py", "install"]
if user:
args.append("--user")
returncode, stdout = _python(args, folder, python_executable, sudo=sudo)
returncode, stdout, stderr = _python(args, folder, python_executable, sudo=sudo)
if returncode != 0:
raise RuntimeError("Could not update, \"python setup.py install\" failed with returncode %d: %s" % (returncode, stdout))
print(stdout)
def parse_arguments():