[elbe-devel] [PATCH 03/32] do and chroot in 'shellhelper.py'
dion at linutronix.de
dion at linutronix.de
Fri Jun 14 22:13:17 CEST 2019
From: Olivier Dion <dion at linutronix.de>
'do' and 'chroot', formerly 'ASCIIDocLog::do' and
'ASCIIDocLog::chroot', are now global functions.
* chroot
Is a wrapper around 'do' and simply put "chroot" in front of the
command to excute.
* do
Will call 'Popen' and redirect its outputs to 'log::filename'. This
is very _dangerous_ because it's not thread safe. This is how the
deprecated 'ASCIIDocLog::do' did.
The good way would be to redirect the outputs to some other logging
object, for example 'console'. Thus, the user could still see the
operation in real time from the SOAP server. And only when the
subprocess terminated, then its outputs is logged to 'log'.
This will still not be thread safe for the 'console' logging, but
that's ok. What's more important is to have correct log saved in a
file.
Commands are logged with their named wrapped at 70 characters,
followed by the outputs of the command wrapped by ">>>>>\n" and
"<<<<< errno" where 'errno' is the error number of the command.
** Example
command:
```````````````````````````````````````````````````````````````````
do("elbe --version; elbe initvm; cat /not/a/file/that/exists")
```````````````````````````````````````````````````````````````````
output:
```````````````````````````````````````````````````````````````````
$ elbe --version && elbe initvm && \
cat /not/a/file/that/exists
>>>>>
elbe v 8 debian 9.9
elbe initvm - no subcommand given
available subcommands are:
attach
create
stop
submit
start
ensure
cat: /not/a/file/that/exists: No such file or directory
<<<<< 1
```````````````````````````````````````````````````````````````````
* get_command_out
Work similary to 'do'.
Signed-off-by: Olivier Dion <dion at linutronix.de>
---
elbepack/shellhelper.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)
diff --git a/elbepack/shellhelper.py b/elbepack/shellhelper.py
index 8de9e8c2..a9361890 100644
--- a/elbepack/shellhelper.py
+++ b/elbepack/shellhelper.py
@@ -6,7 +6,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later
import os
+import textwrap
+
from subprocess import Popen, PIPE, STDOUT, call
+from elbepack.log import log
class CommandError(Exception):
@@ -84,3 +87,62 @@ def system_out_stderr(cmd, stdin=None, allow_fail=False, env_add=None):
raise CommandError(cmd, code)
return out, err
+
+
+cmd_header_wrap = textwrap.TextWrapper(width=70,
+ subsequent_indent=' ',
+ break_long_words=False,
+ break_on_hyphens=False)
+def wrap_cmd(cmd):
+ return ' \\\n'.join(cmd_header_wrap.wrap(cmd))
+
+
+# This is a hack for having async print of 'do' to the log.txt. This
+# is _not_ thread safe and should be replace with a pipe + buffering
+def do(cmd, allow_fail=False, stdin=None, env_add=None):
+ new_env = os.environ.copy()
+ if env_add:
+ new_env.update(env_add)
+
+ out = open(log.filename, "ab", 0)
+
+ out.write("\n$ %s\n>>>>>\n" % (wrap_cmd(cmd)))
+ os.fsync(out.fileno())
+
+ if stdin is None:
+ p = Popen(cmd, shell=True, stdout=out.fileno(), stderr=STDOUT, env=new_env)
+ else:
+ p = Popen(cmd, shell=True, stdin=PIPE, stdout=out.fileno(), stderr=STDOUT, env=new_env)
+
+ p.communicate(input=stdin)
+
+ out.write("<<<<< %s\n" % p.returncode)
+ if p.returncode and not allow_fail:
+ raise CommandError(cmd, p.returncode)
+
+def chroot(directory, cmd, **kwargs):
+ os.environ["LANG"] = "C"
+ os.environ["LANGUAGE"] = "C"
+ os.environ["LC_ALL"] = "C"
+ chcmd = 'chroot %s %s' % (directory, cmd)
+ do(chcmd, **kwargs)
+
+def flush_cmd(cmd, stderr, exitcode):
+ if stderr is None:
+ stderr = ""
+ msg = "$ %s\n>>>>>\n%s<<<<< %s" % (wrap_cmd(cmd), stderr, exitcode)
+ log.info(msg)
+
+def get_command_out(cmd, stdin=None, allow_fail=False, env_add={}):
+ new_env = os.environ.copy()
+ new_env.update(env_add)
+ if stdin is None:
+ p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, env=new_env)
+ else:
+ p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, env=new_env)
+ stdout, stderr = p.communicate(input=stdin)
+ exitcode = p.returncode
+ flush_cmd(cmd, stderr, exitcode)
+ if exitcode and not allow_fail:
+ raise CommandError(cmd, exitcode)
+ return stdout
--
2.11.0
More information about the elbe-devel
mailing list