X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=tools%2Fexecutor.py;fp=tools%2Fexecutor.py;h=f2a428c249579e1f97966cf97a4e178ecba9ee1d;hb=4ded4f2a805e9447be90751d7d4fb7e11552e545;hp=0000000000000000000000000000000000000000;hpb=3b1226294aa9e47692e15279e669d159675deeb9;p=ta%2Fbuild-tools.git diff --git a/tools/executor.py b/tools/executor.py new file mode 100755 index 0000000..f2a428c --- /dev/null +++ b/tools/executor.py @@ -0,0 +1,107 @@ +# Copyright 2019 Nokia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import logging +import shlex +import subprocess + + +class ExecutionError(Exception): + def __init__(self, msg, result): + super(ExecutionError, self).__init__(msg) + self.result = result + + +class Result(object): + def __init__(self, status, stdout, stderr): + self.status = status + self.stdout = stdout + self.stderr = stderr + + @property + def str_status(self): + return 'Status:"{}"'.format(self.status) + + @property + def str_stdout(self): + return 'Stdout:"{}"'.format(self.stdout) + + @property + def str_stderr(self): + return 'Stderr:"{}"'.format(self.stderr) + + def __str__(self): + return '\n'.join([self.str_status, self.str_stdout, self.str_stderr]) + + +def run(*args, **kwargs): + return Executor().run(*args, **kwargs) + + +class Executor(object): + def __init__(self, shell=False, chdir=None): + self.shell = shell + self.chdir = chdir + + def run(self, cmd, raise_on_error=True, raise_on_stderr=True, retries=0): + result = self._run(cmd, retries) + if raise_on_error and result.status != 0: + raise ExecutionError('Command "{}" execution status NOT zero: {}'.format( + cmd, str(result)), result.status) + if raise_on_stderr and result.stderr: + raise ExecutionError('Command "{}" execution stderr not empty: {}'.format( + cmd, str(result)), result.status) + return result + + @staticmethod + def _log_result(result): + logging.debug('Result: %s', str(result)) + + def _run(self, cmd, retries): + logstr = 'Executing command: "{}"'.format(cmd) + cwd = os.getcwd() + if self.chdir is not None: + os.chdir(self.chdir) + logstr += ' in dir {}'.format(self.chdir) + logging.debug(logstr) + result = self._run_with_retries(cmd, retries) + if self.chdir is not None: + os.chdir(cwd) + return result + + def _run_with_retries(self, cmd, retries): + result = self._execute(cmd) + while result.status != 0 and retries > 0: + logging.debug('Retrying, retries left: %s', retries) + retries -= 1 + result = self._execute(cmd) + self._log_result(result) + if result.status == 0: + break + return result + + def _execute(self, cmd): + if not self.shell: + if isinstance(cmd, list): + cmd_args = cmd[:] + else: + cmd_args = shlex.split(cmd) + else: + cmd_args = cmd + process = subprocess.Popen(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + shell=self.shell) + stdout, stderr = process.communicate() + result = Result(process.returncode, stdout, stderr) + return result