# -*- coding: utf-8 -*- # Copyright 2016 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Functions and classes for formatting buildbot stage annotations.""" from __future__ import print_function import abc import itertools import json import six class Annotation(object): """Formatted annotation for buildbot.""" def __init__(self, name, args): """Initialize instance. Args: name: Annotation name. args: A sequence of string arguments. """ self.name = name self.args = args def __str__(self): inner_text = '@'.join( _EscapeArgText(text) for text in itertools.chain([self.name], self.args) ) return '@@@%s@@@' % (inner_text,) @property def human_friendly(self): """Human-friendly format.""" if self.args: return '%s: %s' % (self.name, '; '.join(self.args)) else: return self.name @six.add_metaclass(abc.ABCMeta) class _NamedAnnotation(Annotation): """Abstract subclass for creating named annotations. Concrete subclasses should define the ANNOTATION_NAME class attribute. """ def __init__(self, *args): super(_NamedAnnotation, self).__init__(self.ANNOTATION_NAME, args) @abc.abstractproperty def ANNOTATION_NAME(self): raise NotImplementedError() class StepLink(_NamedAnnotation): """STEP_LINK annotation.""" ANNOTATION_NAME = 'STEP_LINK' # Some callers pass in text/url by kwarg. We leave the full signature here # so the API is a bit cleaner/more obvious. # pylint: disable=useless-super-delegation def __init__(self, text, url): super(StepLink, self).__init__(text, url) class StepText(_NamedAnnotation): """STEP_TEXT annotation.""" ANNOTATION_NAME = 'STEP_TEXT' class StepWarnings(_NamedAnnotation): """STEP_WARNINGS annotation.""" ANNOTATION_NAME = 'STEP_WARNINGS' class StepFailure(_NamedAnnotation): """STEP_FAILURE annotation.""" ANNOTATION_NAME = 'STEP_FAILURE' class BuildStep(_NamedAnnotation): """BUILD_STEP annotation.""" ANNOTATION_NAME = 'BUILD_STEP' class SetBuildProperty(_NamedAnnotation): """SET_BUILD_PROPERTY annotation.""" ANNOTATION_NAME = 'SET_BUILD_PROPERTY' def __init__(self, name, value): super(SetBuildProperty, self).__init__(name, json.dumps(value)) class SetEmailNotifyProperty(_NamedAnnotation): """SET_BUILD_PROPERTY annotation for email_notify.""" ANNOTATION_NAME = 'SET_BUILD_PROPERTY' def __init__(self, name, value): super(SetEmailNotifyProperty, self).__init__(name, json.dumps(value)) def __str__(self): inner_text = '@'.join( text for text in itertools.chain([self.name], self.args)) return '@@@%s@@@' % (inner_text) def _EscapeArgText(text): """Escape annotation argument text. Args: text: String to escape. """ return text.replace('@', '-AT-')