diff mbox

[v2,08/10] autobuild-run: encapsulate subprocess calls

Message ID 1426693843-28792-9-git-send-email-dywi@mailerd.de
State Superseded
Headers show

Commit Message

André Erdmann March 18, 2015, 3:50 p.m. UTC
Preparation step for passing LANG to worker (sub-)processes,
allows to redirect stdin/stdout/stderr, which all default to devnull now
unless specified otherwise.
This makes the "yes"-pipe in "make oldconfig" redundant.

Signed-off-by: André Erdmann <dywi@mailerd.de>
---
 scripts/autobuild-run | 92 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 55 insertions(+), 37 deletions(-)

Comments

Samuel Martin April 12, 2015, 7:51 a.m. UTC | #1
Hi André, Thomas, all,

On Wed, Mar 18, 2015 at 4:50 PM, André Erdmann <dywi@mailerd.de> wrote:
> Preparation step for passing LANG to worker (sub-)processes,
> allows to redirect stdin/stdout/stderr, which all default to devnull now
> unless specified otherwise.
> This makes the "yes"-pipe in "make oldconfig" redundant.
>
> Signed-off-by: André Erdmann <dywi@mailerd.de>
[...]
>
>      return 0
> @@ -459,6 +480,7 @@ def gen_config(**kwargs):
>
>      idir = "instance-%d" % kwargs['instance']
>      log = kwargs['log']
> +    sysinfo = kwargs['sysinfo']
>
>      # We need the absolute path to use with O=, because the relative
>      # path to the output directory here is not relative to the
> @@ -493,10 +515,7 @@ def gen_config(**kwargs):
>      with open(os.path.join(outputdir, ".config"), "w+") as configf:
>          configf.writelines(configlines)
>
> -    devnull = open(os.devnull, "w")
> -
> -    ret = subprocess.call(["yes '' 2>/dev/null| make O=%s -C %s oldconfig" % \
> -                           (outputdir, srcdir)], shell=True, stdout=devnull, stderr=devnull)
> +    ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir, "oldconfig"])
Any reason to drop the yes pipe in the command?

>      if ret != 0:
>          log_write(log, "ERROR: cannot oldconfig")
>          return -1
> @@ -504,23 +523,20 @@ def gen_config(**kwargs):
>      # Now, generate the random selection of packages, and fixup
>      # things if needed.
>      while True:
> -        ret = subprocess.call(["make", "O=%s" % outputdir, "-C", srcdir,
> -                               "KCONFIG_PROBABILITY=%d" % randint(1,30), "randpackageconfig"],
> -                              stdout=devnull, stderr=devnull)
> +        ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir,
> +                               "KCONFIG_PROBABILITY=%d" % randint(1,30), "randpackageconfig"])
>          if ret != 0:
>              log_write(log, "ERROR: cannot generate random configuration")
>              return -1
>          if fixup_config(**kwargs):
>              break
>
> -    ret = subprocess.call(["yes '' 2>/dev/null| make O=%s -C %s oldconfig" % \
> -                           (outputdir, srcdir)], shell=True, stdout=devnull, stderr=devnull)
> +    ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir, "oldconfig"])
ditto

>      if ret != 0:
>          log_write(log, "ERROR: cannot oldconfig")
>          return -1
>
> -    ret = subprocess.call(["make", "O=%s" % outputdir, "-C", srcdir, "savedefconfig"],
> -                          stdout=devnull, stderr=devnull)
> +    ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir, "savedefconfig"])
>      if ret != 0:
>          log_write(log, "ERROR: cannot savedefconfig")
>          return -1
[...]
> @@ -595,15 +613,14 @@ def send_results(result, **kwargs):
>          shutil.copyfile(os.path.join(outputdir, "legal-info", "manifest.csv"),
>                          os.path.join(resultdir, "licenses-manifest.csv"))
>
> -    subprocess.call(["git log master -n 1 --pretty=format:%%H > %s" % \
> +    sysinfo.run_cmd(["git log master -n 1 --pretty=format:%%H > %s" % \
>                       os.path.join(resultdir, "gitid")],
> -                    shell=True, cwd=srcdir)
> +                    shell=True, cwd=srcdir, stderr=None)
IIRC, stderr=None dumps the error output in the process error output,
so only available for the autobuilder owner.
So, how about log stderr in the log file using
sysinfo.run_cmd_get_output (stdout would be anyway redirected to
gitid, and stderr would be part of the log)?

>
>      def get_failure_reason():
>          # Output is a tuple (package, version), or None.
> -        lastlines = decode_bytes(subprocess.Popen(
> -            ["tail", "-n", "3", os.path.join(outputdir, "logfile")],
> -            stdout=subprocess.PIPE).communicate()[0]).splitlines()
> +        lastlines = sysinfo.run_cmd_get_stdout(
> +            ["tail", "-n", "3", os.path.join(outputdir, "logfile")])[1].splitlines()
>
>          regexp = re.compile(r'make: \*\*\* .*/(?:build|toolchain)/([^/]*)/')
>          for line in lastlines:
> @@ -618,9 +635,9 @@ def send_results(result, **kwargs):
>          """Save the last part of the build log, starting from the failed package"""
>
>          def extract_last_500_lines():
> -            subprocess.call(["tail -500 %s > %s" % \
> +            sysinfo.run_cmd(["tail -500 %s > %s" % \
>                               (os.path.join(outputdir, "logfile"), resultfile)],
> -                            shell=True)
> +                            shell=True, stderr=None)
ditto

>
>          reason = get_failure_reason()
>          if not reason:
> @@ -677,8 +694,8 @@ def send_results(result, **kwargs):
>
>      # Yes, shutil.make_archive() would be nice, but it doesn't exist
>      # in Python 2.6.
> -    ret = subprocess.call(["tar", "cjf", "results.tar.bz2", "results"],
> -                          cwd=outputdir, stdout=log, stderr=log)
> +    ret = sysinfo.run_cmd_write_to(
> +        log, ["tar", "cjf", "results.tar.bz2", "results"], cwd=outputdir)
>      if ret != 0:
>          log_write(log, "ERROR: could not make results tarball")
>          sys.exit(1)
> @@ -687,13 +704,14 @@ def send_results(result, **kwargs):
>          # Submit results. Yes, Python has some HTTP libraries, but
>          # none of the ones that are part of the standard library can
>          # upload a file without writing dozens of lines of code.
> -        ret = subprocess.call(["curl", "-u",
> -                               "%s:%s" % (kwargs['http_login'], kwargs['http_password']),
> -                               "-H", "Expect:",
> -                               "-F", "uploadedfile=@%s" % os.path.join(outputdir, "results.tar.bz2"),
> -                               "-F", "uploadsubmit=1",
> -                               "http://autobuild.buildroot.org/submit/"],
> -                              stdout=log, stderr=log)
> +        ret = sysinfo.run_cmd_write_to(
> +            log,
> +            ["curl", "-u",
> +             "%s:%s" % (kwargs['http_login'], kwargs['http_password']),
> +             "-H", "Expect:",
> +             "-F", "uploadedfile=@%s" % os.path.join(outputdir, "results.tar.bz2"),
> +             "-F", "uploadsubmit=1",
> +             "http://autobuild.buildroot.org/submit/"])
>          if ret != 0:
>              log_write(log, "INFO: results could not be submitted, %d" % ret)
>          else:
> --
> 2.3.2
>
> _______________________________________________
> buildroot mailing list
> buildroot@busybox.net
> http://lists.busybox.net/mailman/listinfo/buildroot

Regards,
André Erdmann April 14, 2015, 7:13 p.m. UTC | #2
Hi,

2015-04-12 9:51 GMT+02:00 Samuel Martin <s.martin49@gmail.com>:
> Hi André, Thomas, all,
>
> On Wed, Mar 18, 2015 at 4:50 PM, André Erdmann <dywi@mailerd.de> wrote:
>> Preparation step for passing LANG to worker (sub-)processes,
>> allows to redirect stdin/stdout/stderr, which all default to devnull now
>> unless specified otherwise.
>> This makes the "yes"-pipe in "make oldconfig" redundant.
>>
>> Signed-off-by: André Erdmann <dywi@mailerd.de>
> [...]
>>
>>      return 0
>> @@ -459,6 +480,7 @@ def gen_config(**kwargs):
>>
>>      idir = "instance-%d" % kwargs['instance']
>>      log = kwargs['log']
>> +    sysinfo = kwargs['sysinfo']
>>
>>      # We need the absolute path to use with O=, because the relative
>>      # path to the output directory here is not relative to the
>> @@ -493,10 +515,7 @@ def gen_config(**kwargs):
>>      with open(os.path.join(outputdir, ".config"), "w+") as configf:
>>          configf.writelines(configlines)
>>
>> -    devnull = open(os.devnull, "w")
>> -
>> -    ret = subprocess.call(["yes '' 2>/dev/null| make O=%s -C %s oldconfig" % \
>> -                           (outputdir, srcdir)], shell=True, stdout=devnull, stderr=devnull)
>> +    ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir, "oldconfig"])
> Any reason to drop the yes pipe in the command?
>

It's not needed anymore: SystemInfo::run_cmd() redirects stdin to
/dev/null, so this command reads as "make ... oldconfig < /dev/null",
which behaves identical to "yes '' | make ... oldconfig".

>>      if ret != 0:
>>          log_write(log, "ERROR: cannot oldconfig")
>>          return -1
>> @@ -504,23 +523,20 @@ def gen_config(**kwargs):
>>      # Now, generate the random selection of packages, and fixup
>>      # things if needed.
>>      while True:
>> -        ret = subprocess.call(["make", "O=%s" % outputdir, "-C", srcdir,
>> -                               "KCONFIG_PROBABILITY=%d" % randint(1,30), "randpackageconfig"],
>> -                              stdout=devnull, stderr=devnull)
>> +        ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir,
>> +                               "KCONFIG_PROBABILITY=%d" % randint(1,30), "randpackageconfig"])
>>          if ret != 0:
>>              log_write(log, "ERROR: cannot generate random configuration")
>>              return -1
>>          if fixup_config(**kwargs):
>>              break
>>
>> -    ret = subprocess.call(["yes '' 2>/dev/null| make O=%s -C %s oldconfig" % \
>> -                           (outputdir, srcdir)], shell=True, stdout=devnull, stderr=devnull)
>> +    ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir, "oldconfig"])
> ditto
>
>>      if ret != 0:
>>          log_write(log, "ERROR: cannot oldconfig")
>>          return -1
>>
>> -    ret = subprocess.call(["make", "O=%s" % outputdir, "-C", srcdir, "savedefconfig"],
>> -                          stdout=devnull, stderr=devnull)
>> +    ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir, "savedefconfig"])
>>      if ret != 0:
>>          log_write(log, "ERROR: cannot savedefconfig")
>>          return -1
> [...]
>> @@ -595,15 +613,14 @@ def send_results(result, **kwargs):
>>          shutil.copyfile(os.path.join(outputdir, "legal-info", "manifest.csv"),
>>                          os.path.join(resultdir, "licenses-manifest.csv"))
>>
>> -    subprocess.call(["git log master -n 1 --pretty=format:%%H > %s" % \
>> +    sysinfo.run_cmd(["git log master -n 1 --pretty=format:%%H > %s" % \
>>                       os.path.join(resultdir, "gitid")],
>> -                    shell=True, cwd=srcdir)
>> +                    shell=True, cwd=srcdir, stderr=None)
> IIRC, stderr=None dumps the error output in the process error output,
> so only available for the autobuilder owner.
> So, how about log stderr in the log file using
> sysinfo.run_cmd_get_output (stdout would be anyway redirected to
> gitid, and stderr would be part of the log)?
>

Sure! But I'd rather do that in a follow-up patch since this one tries
to keep the functional changes at a minimum, except for the
stdin-/dev/null redirection. (The "git log" command used to write to
console before this series, same applies to the "tar" command below.)

>>
>>      def get_failure_reason():
>>          # Output is a tuple (package, version), or None.
>> -        lastlines = decode_bytes(subprocess.Popen(
>> -            ["tail", "-n", "3", os.path.join(outputdir, "logfile")],
>> -            stdout=subprocess.PIPE).communicate()[0]).splitlines()
>> +        lastlines = sysinfo.run_cmd_get_stdout(
>> +            ["tail", "-n", "3", os.path.join(outputdir, "logfile")])[1].splitlines()
>>
>>          regexp = re.compile(r'make: \*\*\* .*/(?:build|toolchain)/([^/]*)/')
>>          for line in lastlines:
>> @@ -618,9 +635,9 @@ def send_results(result, **kwargs):
>>          """Save the last part of the build log, starting from the failed package"""
>>
>>          def extract_last_500_lines():
>> -            subprocess.call(["tail -500 %s > %s" % \
>> +            sysinfo.run_cmd(["tail -500 %s > %s" % \
>>                               (os.path.join(outputdir, "logfile"), resultfile)],
>> -                            shell=True)
>> +                            shell=True, stderr=None)
> ditto
>
>>
>>          reason = get_failure_reason()
>>          if not reason:
>> @@ -677,8 +694,8 @@ def send_results(result, **kwargs):
>>
>>      # Yes, shutil.make_archive() would be nice, but it doesn't exist
>>      # in Python 2.6.
>> -    ret = subprocess.call(["tar", "cjf", "results.tar.bz2", "results"],
>> -                          cwd=outputdir, stdout=log, stderr=log)
>> +    ret = sysinfo.run_cmd_write_to(
>> +        log, ["tar", "cjf", "results.tar.bz2", "results"], cwd=outputdir)
>>      if ret != 0:
>>          log_write(log, "ERROR: could not make results tarball")
>>          sys.exit(1)
>> @@ -687,13 +704,14 @@ def send_results(result, **kwargs):
>>          # Submit results. Yes, Python has some HTTP libraries, but
>>          # none of the ones that are part of the standard library can
>>          # upload a file without writing dozens of lines of code.
>> -        ret = subprocess.call(["curl", "-u",
>> -                               "%s:%s" % (kwargs['http_login'], kwargs['http_password']),
>> -                               "-H", "Expect:",
>> -                               "-F", "uploadedfile=@%s" % os.path.join(outputdir, "results.tar.bz2"),
>> -                               "-F", "uploadsubmit=1",
>> -                               "http://autobuild.buildroot.org/submit/"],
>> -                              stdout=log, stderr=log)
>> +        ret = sysinfo.run_cmd_write_to(
>> +            log,
>> +            ["curl", "-u",
>> +             "%s:%s" % (kwargs['http_login'], kwargs['http_password']),
>> +             "-H", "Expect:",
>> +             "-F", "uploadedfile=@%s" % os.path.join(outputdir, "results.tar.bz2"),
>> +             "-F", "uploadsubmit=1",
>> +             "http://autobuild.buildroot.org/submit/"])
>>          if ret != 0:
>>              log_write(log, "INFO: results could not be submitted, %d" % ret)
>>          else:
>> --
>> 2.3.2
>>
diff mbox

Patch

diff --git a/scripts/autobuild-run b/scripts/autobuild-run
index 409570d..0ee6d57 100755
--- a/scripts/autobuild-run
+++ b/scripts/autobuild-run
@@ -172,6 +172,7 @@  class SystemInfo:
         self.needed_progs = list(self.__class__.DEFAULT_NEEDED_PROGS)
         self.optional_progs = list(self.__class__.DEFAULT_OPTIONAL_PROGS)
         self.progs = {}
+        self.devnull = open(os.devnull, "w")
 
     def find_prog(self, name, flags=os.X_OK, env=os.environ):
         if not name or name[0] == os.sep: raise ValueError(name)
@@ -203,10 +204,8 @@  class SystemInfo:
         have_it = self.find_prog(prog)
         # java[c] needs special care
         if have_it and prog in ('java', 'javac'):
-            with open(os.devnull, "w") as devnull:
-                if subprocess.call("%s -version | grep gcj" % prog, shell=True,
-                                   stdout=devnull, stderr=devnull) != 1:
-                    have_it = False
+            if self.run_cmd("%s -version | grep gcj" % prog, shell=True) != 1:
+                have_it = False
         # --
         self.progs[prog] = have_it
         return have_it
@@ -231,6 +230,27 @@  class SystemInfo:
 
         return not missing_requirements
 
+    def popen(self, cmdv, **kwargs):
+        kwargs.setdefault('stdin', self.devnull)
+        kwargs.setdefault('stdout', self.devnull)
+        kwargs.setdefault('stderr', self.devnull)
+        return subprocess.Popen(cmdv, **kwargs)
+
+    def run_cmd(self, cmdv, **kwargs):
+        proc = self.popen(cmdv, **kwargs)
+        proc.communicate()
+        return proc.poll()
+
+    def run_cmd_write_to(self, outstream, cmdv, **kwargs):
+        kwargs.update(stdout=outstream, stderr=outstream)
+        return self.run_cmd(cmdv, **kwargs)
+
+    def run_cmd_get_stdout(self, cmdv, **kwargs):
+        proc = self.popen(cmdv, stdout=subprocess.PIPE, **kwargs)
+        stdout_data, _ = proc.communicate()
+        return (proc.poll(), decode_bytes(stdout_data) if stdout_data else None)
+
+
 def get_toolchain_configs():
     """Fetch and return the possible toolchain configurations
 
@@ -274,6 +294,7 @@  def prepare_build(**kwargs):
 
     idir = "instance-%d" % kwargs['instance']
     log = kwargs['log']
+    sysinfo = kwargs['sysinfo']
 
     log_write(log, "INFO: preparing a new build")
 
@@ -298,15 +319,15 @@  def prepare_build(**kwargs):
     # didn't exist already.
     srcdir = os.path.join(idir, "buildroot")
     if not os.path.exists(srcdir):
-        ret = subprocess.call(["git", "clone", "git://git.busybox.net/buildroot", srcdir],
-                              stdout=log, stderr=log)
+        ret = sysinfo.run_cmd_write_to(
+            log, ["git", "clone", "git://git.busybox.net/buildroot", srcdir])
         if ret != 0:
             log_write(log, "ERROR: could not clone Buildroot sources")
             return -1
 
     # Update the Buildroot sources.
     abssrcdir = os.path.abspath(srcdir)
-    ret = subprocess.call(["git", "pull"], cwd=abssrcdir, stdout=log, stderr=log)
+    ret = sysinfo.run_cmd_write_to(log, ["git", "pull"],  cwd=abssrcdir)
     if ret != 0:
         log_write(log, "ERROR: could not pull Buildroot sources")
         return -1
@@ -315,7 +336,7 @@  def prepare_build(**kwargs):
     outputdir = os.path.join(idir, "output")
     if os.path.exists(outputdir):
         # shutil.rmtree doesn't remove write-protected files
-        subprocess.call(["rm", "-rf", outputdir])
+        sysinfo.run_cmd(["rm", "-rf", outputdir])
     os.mkdir(outputdir)
 
     return 0
@@ -459,6 +480,7 @@  def gen_config(**kwargs):
 
     idir = "instance-%d" % kwargs['instance']
     log = kwargs['log']
+    sysinfo = kwargs['sysinfo']
 
     # We need the absolute path to use with O=, because the relative
     # path to the output directory here is not relative to the
@@ -493,10 +515,7 @@  def gen_config(**kwargs):
     with open(os.path.join(outputdir, ".config"), "w+") as configf:
         configf.writelines(configlines)
 
-    devnull = open(os.devnull, "w")
-
-    ret = subprocess.call(["yes '' 2>/dev/null| make O=%s -C %s oldconfig" % \
-                           (outputdir, srcdir)], shell=True, stdout=devnull, stderr=devnull)
+    ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir, "oldconfig"])
     if ret != 0:
         log_write(log, "ERROR: cannot oldconfig")
         return -1
@@ -504,23 +523,20 @@  def gen_config(**kwargs):
     # Now, generate the random selection of packages, and fixup
     # things if needed.
     while True:
-        ret = subprocess.call(["make", "O=%s" % outputdir, "-C", srcdir,
-                               "KCONFIG_PROBABILITY=%d" % randint(1,30), "randpackageconfig"],
-                              stdout=devnull, stderr=devnull)
+        ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir,
+                               "KCONFIG_PROBABILITY=%d" % randint(1,30), "randpackageconfig"])
         if ret != 0:
             log_write(log, "ERROR: cannot generate random configuration")
             return -1
         if fixup_config(**kwargs):
             break
 
-    ret = subprocess.call(["yes '' 2>/dev/null| make O=%s -C %s oldconfig" % \
-                           (outputdir, srcdir)], shell=True, stdout=devnull, stderr=devnull)
+    ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir, "oldconfig"])
     if ret != 0:
         log_write(log, "ERROR: cannot oldconfig")
         return -1
 
-    ret = subprocess.call(["make", "O=%s" % outputdir, "-C", srcdir, "savedefconfig"],
-                          stdout=devnull, stderr=devnull)
+    ret = sysinfo.run_cmd(["make", "O=%s" % outputdir, "-C", srcdir, "savedefconfig"])
     if ret != 0:
         log_write(log, "ERROR: cannot savedefconfig")
         return -1
@@ -532,6 +548,7 @@  def do_build(**kwargs):
 
     idir = "instance-%d" % kwargs['instance']
     log = kwargs['log']
+    sysinfo = kwargs['sysinfo']
 
     # We need the absolute path to use with O=, because the relative
     # path to the output directory here is not relative to the
@@ -547,7 +564,7 @@  def do_build(**kwargs):
             "-C", srcdir, "BR2_DL_DIR=%s" % dldir,
             "BR2_JLEVEL=%s" % kwargs['njobs']] \
           + kwargs['make_opts'].split()
-    sub = subprocess.Popen(cmd, stdout=f, stderr=f)
+    sub = sysinfo.popen(cmd, stdout=f, stderr=f)
     kwargs['buildpid'][kwargs['instance']] = sub.pid
     ret = sub.wait()
     kwargs['buildpid'][kwargs['instance']] = 0
@@ -560,7 +577,7 @@  def do_build(**kwargs):
     if ret != 0:
         log_write(log, "INFO: build failed")
         return -1
-    ret = subprocess.call(["make", "O=%s" % outputdir, "-C", srcdir], stdout=f, stderr=f)
+    ret = sysinfo.run_cmd_write_to(f, ["make", "O=%s" % outputdir, "-C", srcdir])
     if ret != 0:
         log_write(log, "INFO: build failed during legal-info")
         return -1
@@ -577,6 +594,7 @@  def send_results(result, **kwargs):
 
     idir = "instance-%d" % kwargs['instance']
     log = kwargs['log']
+    sysinfo = kwargs['sysinfo']
 
     outputdir = os.path.abspath(os.path.join(idir, "output"))
     srcdir = os.path.join(idir, "buildroot")
@@ -595,15 +613,14 @@  def send_results(result, **kwargs):
         shutil.copyfile(os.path.join(outputdir, "legal-info", "manifest.csv"),
                         os.path.join(resultdir, "licenses-manifest.csv"))
 
-    subprocess.call(["git log master -n 1 --pretty=format:%%H > %s" % \
+    sysinfo.run_cmd(["git log master -n 1 --pretty=format:%%H > %s" % \
                      os.path.join(resultdir, "gitid")],
-                    shell=True, cwd=srcdir)
+                    shell=True, cwd=srcdir, stderr=None)
 
     def get_failure_reason():
         # Output is a tuple (package, version), or None.
-        lastlines = decode_bytes(subprocess.Popen(
-            ["tail", "-n", "3", os.path.join(outputdir, "logfile")],
-            stdout=subprocess.PIPE).communicate()[0]).splitlines()
+        lastlines = sysinfo.run_cmd_get_stdout(
+            ["tail", "-n", "3", os.path.join(outputdir, "logfile")])[1].splitlines()
 
         regexp = re.compile(r'make: \*\*\* .*/(?:build|toolchain)/([^/]*)/')
         for line in lastlines:
@@ -618,9 +635,9 @@  def send_results(result, **kwargs):
         """Save the last part of the build log, starting from the failed package"""
 
         def extract_last_500_lines():
-            subprocess.call(["tail -500 %s > %s" % \
+            sysinfo.run_cmd(["tail -500 %s > %s" % \
                              (os.path.join(outputdir, "logfile"), resultfile)],
-                            shell=True)
+                            shell=True, stderr=None)
 
         reason = get_failure_reason()
         if not reason:
@@ -677,8 +694,8 @@  def send_results(result, **kwargs):
 
     # Yes, shutil.make_archive() would be nice, but it doesn't exist
     # in Python 2.6.
-    ret = subprocess.call(["tar", "cjf", "results.tar.bz2", "results"],
-                          cwd=outputdir, stdout=log, stderr=log)
+    ret = sysinfo.run_cmd_write_to(
+        log, ["tar", "cjf", "results.tar.bz2", "results"], cwd=outputdir)
     if ret != 0:
         log_write(log, "ERROR: could not make results tarball")
         sys.exit(1)
@@ -687,13 +704,14 @@  def send_results(result, **kwargs):
         # Submit results. Yes, Python has some HTTP libraries, but
         # none of the ones that are part of the standard library can
         # upload a file without writing dozens of lines of code.
-        ret = subprocess.call(["curl", "-u",
-                               "%s:%s" % (kwargs['http_login'], kwargs['http_password']),
-                               "-H", "Expect:",
-                               "-F", "uploadedfile=@%s" % os.path.join(outputdir, "results.tar.bz2"),
-                               "-F", "uploadsubmit=1",
-                               "http://autobuild.buildroot.org/submit/"],
-                              stdout=log, stderr=log)
+        ret = sysinfo.run_cmd_write_to(
+            log,
+            ["curl", "-u",
+             "%s:%s" % (kwargs['http_login'], kwargs['http_password']),
+             "-H", "Expect:",
+             "-F", "uploadedfile=@%s" % os.path.join(outputdir, "results.tar.bz2"),
+             "-F", "uploadsubmit=1",
+             "http://autobuild.buildroot.org/submit/"])
         if ret != 0:
             log_write(log, "INFO: results could not be submitted, %d" % ret)
         else: