3fe0d59558
Change-Id: Ie7a359b6028dafc706c2213b8745e45c9bf414a2
207 lines
7.4 KiB
Python
207 lines
7.4 KiB
Python
# Copyright 2014 Huawei Technologies Co. Ltd
|
|
#
|
|
# 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.
|
|
|
|
"""Module to get the progress when found match with a line of the log."""
|
|
import logging
|
|
import re
|
|
|
|
from abc import ABCMeta
|
|
|
|
from compass.utils import util
|
|
|
|
|
|
class ProgressCalculator(object):
|
|
"""base class to generate progress."""
|
|
|
|
__metaclass__ = ABCMeta
|
|
|
|
@classmethod
|
|
def update_progress(
|
|
cls, progress_data, message,
|
|
severity, log_history
|
|
):
|
|
"""Update progress with the given progress_data, message and severity.
|
|
|
|
:param progress_data: installing progress.
|
|
:type progress_data: float between 0 to 1.
|
|
:param message: installing progress message.
|
|
:param severity: installing message severity.
|
|
:param progress: :class:`Progress` instance to update
|
|
"""
|
|
# the progress is only updated when the new progress
|
|
# is greater than the stored progress or the progress
|
|
# to update is the same but the message is different.
|
|
if (
|
|
progress_data > log_history['percentage'] or (
|
|
progress_data == log_history['percentage'] and
|
|
message != log_history['message']
|
|
)
|
|
):
|
|
log_history['percentage'] = progress_data
|
|
if message:
|
|
log_history['message'] = message
|
|
if severity:
|
|
log_history['severity'] = severity
|
|
logging.debug('update progress to %s', log_history)
|
|
else:
|
|
logging.debug('ignore update progress %s to %s',
|
|
progress_data, log_history)
|
|
|
|
def update(self, message, severity, log_history):
|
|
"""vritual method to update progress by message and severity.
|
|
|
|
:param message: installing message.
|
|
:param severity: installing severity.
|
|
"""
|
|
raise NotImplementedError(str(self))
|
|
|
|
def __repr__(self):
|
|
return self.__class__.__name__
|
|
|
|
|
|
class IncrementalProgress(ProgressCalculator):
|
|
"""Class to increment the progress."""
|
|
|
|
def __init__(self, min_progress,
|
|
max_progress, incremental_ratio):
|
|
super(IncrementalProgress, self).__init__()
|
|
if not 0.0 <= min_progress <= max_progress <= 1.0:
|
|
raise IndexError(
|
|
'%s restriction is not mat: 0.0 <= min_progress(%s)'
|
|
' <= max_progress(%s) <= 1.0' % (
|
|
self.__class__.__name__, min_progress, max_progress))
|
|
|
|
if not 0.0 <= incremental_ratio <= 1.0:
|
|
raise IndexError(
|
|
'%s restriction is not mat: '
|
|
'0.0 <= incremental_ratio(%s) <= 1.0' % (
|
|
self.__class__.__name__, incremental_ratio))
|
|
|
|
self.min_progress_ = min_progress
|
|
self.max_progress_ = max_progress
|
|
self.incremental_progress_ = (
|
|
incremental_ratio * (max_progress - min_progress))
|
|
|
|
def __str__(self):
|
|
return '%s[%s:%s:%s]' % (
|
|
self.__class__.__name__,
|
|
self.min_progress_,
|
|
self.max_progress_,
|
|
self.incremental_progress_
|
|
)
|
|
|
|
def update(self, message, severity, log_history):
|
|
"""update progress from message and severity."""
|
|
progress_data = max(
|
|
self.min_progress_,
|
|
min(
|
|
self.max_progress_,
|
|
log_history['percentage'] + self.incremental_progress_
|
|
)
|
|
)
|
|
self.update_progress(progress_data,
|
|
message, severity, log_history)
|
|
|
|
|
|
class RelativeProgress(ProgressCalculator):
|
|
"""class to update progress to the given relative progress."""
|
|
|
|
def __init__(self, progress):
|
|
super(RelativeProgress, self).__init__()
|
|
if not 0.0 <= progress <= 1.0:
|
|
raise IndexError(
|
|
'%s restriction is not mat: 0.0 <= progress(%s) <= 1.0' % (
|
|
self.__class__.__name__, progress))
|
|
|
|
self.progress_ = progress
|
|
|
|
def __str__(self):
|
|
return '%s[%s]' % (self.__class__.__name__, self.progress_)
|
|
|
|
def update(self, message, severity, log_history):
|
|
"""update progress from message and severity."""
|
|
self.update_progress(
|
|
self.progress_, message, severity, log_history)
|
|
|
|
|
|
class SameProgress(ProgressCalculator):
|
|
"""class to update message and severity for progress."""
|
|
|
|
def update(self, message, severity, log_history):
|
|
"""update progress from the message and severity."""
|
|
self.update_progress(log_history['percentage'], message,
|
|
severity, log_history)
|
|
|
|
|
|
class LineMatcher(object):
|
|
"""Progress matcher for each line."""
|
|
|
|
def __init__(self, pattern, progress=None,
|
|
message_template='', severity=None,
|
|
unmatch_sameline_next_matcher_name='',
|
|
unmatch_nextline_next_matcher_name='',
|
|
match_sameline_next_matcher_name='',
|
|
match_nextline_next_matcher_name=''):
|
|
self.regex_ = re.compile(pattern)
|
|
if not progress:
|
|
self.progress_ = SameProgress()
|
|
elif isinstance(progress, ProgressCalculator):
|
|
self.progress_ = progress
|
|
elif util.is_instance(progress, [int, float]):
|
|
self.progress_ = RelativeProgress(progress)
|
|
else:
|
|
raise TypeError(
|
|
'progress unsupport type %s: %s' % (
|
|
type(progress), progress))
|
|
|
|
self.message_template_ = message_template
|
|
self.severity_ = severity
|
|
self.unmatch_sameline_ = unmatch_sameline_next_matcher_name
|
|
self.unmatch_nextline_ = unmatch_nextline_next_matcher_name
|
|
self.match_sameline_ = match_sameline_next_matcher_name
|
|
self.match_nextline_ = match_nextline_next_matcher_name
|
|
|
|
def __repr__(self):
|
|
return '%r[pattern:%r, message_template:%r, severity:%r]' % (
|
|
self.__class__.__name__, self.regex_.pattern,
|
|
self.message_template_, self.severity_)
|
|
|
|
def update_progress(self, line, log_history):
|
|
"""Update progress by the line.
|
|
|
|
:param line: one line in log file to indicate the installing progress.
|
|
.. note::
|
|
The line may be partial if the latest line of the log file is
|
|
not the whole line. But the whole line may be resent
|
|
in the next run.
|
|
:param progress: the :class:`Progress` instance to update.
|
|
"""
|
|
mat = self.regex_.search(line)
|
|
if not mat:
|
|
return (
|
|
self.unmatch_sameline_,
|
|
self.unmatch_nextline_)
|
|
|
|
try:
|
|
message = self.message_template_ % mat.groupdict()
|
|
except Exception as error:
|
|
logging.error('failed to get message %s %% %s in line matcher %s',
|
|
self.message_template_, mat.groupdict(), self)
|
|
raise error
|
|
|
|
self.progress_.update(message, self.severity_, log_history)
|
|
return (
|
|
self.match_sameline_,
|
|
self.match_nextline_)
|