commands.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. # Copyright (c) 2013 Intel Corporation
  2. #
  3. # Released under the MIT license (see COPYING.MIT)
  4. # DESCRIPTION
  5. # This module is mainly used by scripts/oe-selftest and modules under meta/oeqa/selftest
  6. # It provides a class and methods for running commands on the host in a convienent way for tests.
  7. import os
  8. import sys
  9. import signal
  10. import subprocess
  11. import threading
  12. import logging
  13. class Command(object):
  14. def __init__(self, command, bg=False, timeout=None, data=None, **options):
  15. self.defaultopts = {
  16. "stdout": subprocess.PIPE,
  17. "stderr": subprocess.STDOUT,
  18. "stdin": None,
  19. "shell": False,
  20. "bufsize": -1,
  21. }
  22. self.cmd = command
  23. self.bg = bg
  24. self.timeout = timeout
  25. self.data = data
  26. self.options = dict(self.defaultopts)
  27. if isinstance(self.cmd, basestring):
  28. self.options["shell"] = True
  29. if self.data:
  30. self.options['stdin'] = subprocess.PIPE
  31. self.options.update(options)
  32. self.status = None
  33. self.output = None
  34. self.error = None
  35. self.thread = None
  36. self.log = logging.getLogger("utils.commands")
  37. def run(self):
  38. self.process = subprocess.Popen(self.cmd, **self.options)
  39. def commThread():
  40. self.output, self.error = self.process.communicate(self.data)
  41. self.thread = threading.Thread(target=commThread)
  42. self.thread.start()
  43. self.log.debug("Running command '%s'" % self.cmd)
  44. if not self.bg:
  45. self.thread.join(self.timeout)
  46. self.stop()
  47. def stop(self):
  48. if self.thread.isAlive():
  49. self.process.terminate()
  50. # let's give it more time to terminate gracefully before killing it
  51. self.thread.join(5)
  52. if self.thread.isAlive():
  53. self.process.kill()
  54. self.thread.join()
  55. self.output = self.output.rstrip()
  56. self.status = self.process.poll()
  57. self.log.debug("Command '%s' returned %d as exit code." % (self.cmd, self.status))
  58. # logging the complete output is insane
  59. # bitbake -e output is really big
  60. # and makes the log file useless
  61. if self.status:
  62. lout = "\n".join(self.output.splitlines()[-20:])
  63. self.log.debug("Last 20 lines:\n%s" % lout)
  64. class Result(object):
  65. pass
  66. def runCmd(command, ignore_status=False, timeout=None, **options):
  67. result = Result()
  68. cmd = Command(command, timeout=timeout, **options)
  69. cmd.run()
  70. result.command = command
  71. result.status = cmd.status
  72. result.output = cmd.output
  73. result.pid = cmd.process.pid
  74. if result.status and not ignore_status:
  75. raise AssertionError("Command '%s' returned non-zero exit status %d:\n%s" % (command, result.status, result.output))
  76. return result
  77. def bitbake(command, ignore_status=False, timeout=None, **options):
  78. if isinstance(command, basestring):
  79. cmd = "bitbake " + command
  80. else:
  81. cmd = [ "bitbake" ] + command
  82. return runCmd(cmd, ignore_status, timeout, **options)
  83. def get_bb_env(target=None):
  84. if target:
  85. return runCmd("bitbake -e %s" % target).output
  86. else:
  87. return runCmd("bitbake -e").output
  88. def get_bb_var(var, target=None):
  89. val = None
  90. bbenv = get_bb_env(target)
  91. for line in bbenv.splitlines():
  92. if line.startswith(var + "="):
  93. val = line.split('=')[1]
  94. val = val.replace('\"','')
  95. break
  96. return val
  97. def get_test_layer():
  98. layers = get_bb_var("BBLAYERS").split()
  99. testlayer = None
  100. for l in layers:
  101. if "/meta-selftest" in l and os.path.isdir(l):
  102. testlayer = l
  103. break
  104. return testlayer