[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