3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
21 class ExecutionError(Exception):
22 def __init__(self, msg, result):
23 super(ExecutionError, self).__init__(msg)
28 def __init__(self, status, stdout, stderr):
35 return 'Status:"{}"'.format(self.status)
39 return 'Stdout:"{}"'.format(self.stdout)
43 return 'Stderr:"{}"'.format(self.stderr)
46 return '\n'.join([self.str_status, self.str_stdout, self.str_stderr])
49 def run(*args, **kwargs):
50 return Executor().run(*args, **kwargs)
53 class Executor(object):
54 def __init__(self, shell=False, chdir=None):
58 def run(self, cmd, raise_on_error=True, raise_on_stderr=True, retries=0):
59 result = self._run(cmd, retries)
60 if raise_on_error and result.status != 0:
61 raise ExecutionError('Command "{}" execution status NOT zero: {}'.format(
62 cmd, str(result)), result.status)
63 if raise_on_stderr and result.stderr:
64 raise ExecutionError('Command "{}" execution stderr not empty: {}'.format(
65 cmd, str(result)), result.status)
69 def _log_result(result):
70 logging.debug('Result: %s', str(result))
72 def _run(self, cmd, retries):
73 logstr = 'Executing command: "{}"'.format(cmd)
75 if self.chdir is not None:
77 logstr += ' in dir {}'.format(self.chdir)
79 result = self._run_with_retries(cmd, retries)
80 if self.chdir is not None:
84 def _run_with_retries(self, cmd, retries):
85 result = self._execute(cmd)
86 while result.status != 0 and retries > 0:
87 logging.debug('Retrying, retries left: %s', retries)
89 result = self._execute(cmd)
90 self._log_result(result)
91 if result.status == 0:
95 def _execute(self, cmd):
97 if isinstance(cmd, list):
100 cmd_args = shlex.split(cmd)
103 process = subprocess.Popen(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
105 stdout, stderr = process.communicate()
106 result = Result(process.returncode, stdout, stderr)