utils.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. # ex:ts=4:sw=4:sts=4:et
  2. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  3. #
  4. # utils: common methods used by the patchtest framework
  5. #
  6. # Copyright (C) 2016 Intel Corporation
  7. #
  8. # SPDX-License-Identifier: GPL-2.0-only
  9. #
  10. import os
  11. import subprocess
  12. import logging
  13. import sys
  14. import re
  15. import mailbox
  16. class CmdException(Exception):
  17. """ Simple exception class where its attributes are the ones passed when instantiated """
  18. def __init__(self, cmd):
  19. self._cmd = cmd
  20. def __getattr__(self, name):
  21. value = None
  22. if self._cmd.has_key(name):
  23. value = self._cmd[name]
  24. return value
  25. def exec_cmd(cmd, cwd, ignore_error=False, input=None, strip=True, updateenv={}):
  26. """
  27. Input:
  28. cmd: dict containing the following keys:
  29. cmd : the command itself as an array of strings
  30. ignore_error: if False, no exception is raised
  31. strip: indicates if strip is done on the output (stdout and stderr)
  32. input: input data to the command (stdin)
  33. updateenv: environment variables to be appended to the current
  34. process environment variables
  35. NOTE: keys 'ignore_error' and 'input' are optional; if not included,
  36. the defaults are the ones specify in the arguments
  37. cwd: directory where commands are executed
  38. ignore_error: raise CmdException if command fails to execute and
  39. this value is False
  40. input: input data (stdin) for the command
  41. Output: dict containing the following keys:
  42. cmd: the same as input
  43. ignore_error: the same as input
  44. strip: the same as input
  45. input: the same as input
  46. stdout: Standard output after command's execution
  47. stderr: Standard error after command's execution
  48. returncode: Return code after command's execution
  49. """
  50. cmddefaults = {
  51. 'cmd':'',
  52. 'ignore_error':ignore_error,
  53. 'strip':strip,
  54. 'input':input,
  55. 'updateenv':updateenv,
  56. }
  57. # update input values if necessary
  58. cmddefaults.update(cmd)
  59. _cmd = cmddefaults
  60. if not _cmd['cmd']:
  61. raise CmdException({'cmd':None, 'stderr':'no command given'})
  62. # update the environment
  63. env = os.environ
  64. env.update(_cmd['updateenv'])
  65. _command = [e for e in _cmd['cmd']]
  66. p = subprocess.Popen(_command,
  67. stdin=subprocess.PIPE,
  68. stdout=subprocess.PIPE,
  69. stderr=subprocess.PIPE,
  70. universal_newlines=True,
  71. cwd=cwd,
  72. env=env)
  73. # execute the command and strip output
  74. (_stdout, _stderr) = p.communicate(_cmd['input'])
  75. if _cmd['strip']:
  76. _stdout, _stderr = map(str.strip, [_stdout, _stderr])
  77. # generate the result
  78. result = _cmd
  79. result.update({'cmd':_command,'stdout':_stdout,'stderr':_stderr,'returncode':p.returncode})
  80. # launch exception if necessary
  81. if not _cmd['ignore_error'] and p.returncode:
  82. raise CmdException(result)
  83. return result
  84. def exec_cmds(cmds, cwd):
  85. """ Executes commands
  86. Input:
  87. cmds: Array of commands
  88. cwd: directory where commands are executed
  89. Output: Array of output commands
  90. """
  91. results = []
  92. _cmds = cmds
  93. for cmd in _cmds:
  94. result = exec_cmd(cmd, cwd)
  95. results.append(result)
  96. return results
  97. def logger_create(name):
  98. logger = logging.getLogger(name)
  99. loggerhandler = logging.StreamHandler()
  100. loggerhandler.setFormatter(logging.Formatter("%(message)s"))
  101. logger.addHandler(loggerhandler)
  102. logger.setLevel(logging.INFO)
  103. return logger
  104. def get_subject_prefix(path):
  105. prefix = ""
  106. mbox = mailbox.mbox(path)
  107. if len(mbox):
  108. subject = mbox[0]['subject']
  109. if subject:
  110. pattern = re.compile("(\[.*\])", re.DOTALL)
  111. match = pattern.search(subject)
  112. if match:
  113. prefix = match.group(1)
  114. return prefix
  115. def valid_branch(branch):
  116. """ Check if branch is valid name """
  117. lbranch = branch.lower()
  118. invalid = lbranch.startswith('patch') or \
  119. lbranch.startswith('rfc') or \
  120. lbranch.startswith('resend') or \
  121. re.search('^v\d+', lbranch) or \
  122. re.search('^\d+/\d+', lbranch)
  123. return not invalid
  124. def get_branch(path):
  125. """ Get the branch name from mbox """
  126. fullprefix = get_subject_prefix(path)
  127. branch, branches, valid_branches = None, [], []
  128. if fullprefix:
  129. prefix = fullprefix.strip('[]')
  130. branches = [ b.strip() for b in prefix.split(',')]
  131. valid_branches = [b for b in branches if valid_branch(b)]
  132. if len(valid_branches):
  133. branch = valid_branches[0]
  134. return branch