aboutsummaryrefslogtreecommitdiffstats
path: root/lib/python2.7/site-packages/autobuilder/lib/buildsteps.py
blob: 8e3707f2e0f700cd02d6813cb92e7e0ea4a8866e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
'''
Created on Feb 15, 2016

__author__ = "Anibal (alimon) Limon"
__copyright__ = "Copyright 2016, Intel Corp."
__credits__ = ["Anibal Limon"]
__license__ = "GPL"
__version__ = "2.0"
__maintainer__ = "Anibal Limon"
__email__ = "anibal.limon@linux.intel.com"
'''

import os
import re


from buildbot.steps.shell import ShellCommand
from buildbot.process.buildstep import LogLineObserver
from buildbot.status.results import SUCCESS

from lib.ABTools import save_error_report

DEFAULT_SHELL = 'bash'

class ShellCommandCleanEnv(ShellCommand):
    def __init__(self, factory, argdict=None, **kwargs):
        shell = DEFAULT_SHELL
        if 'SHELL' in kwargs:
            shell = kwargs['SHELL']
            del kwargs['SHELL']

        if 'PENV' in kwargs:
            preserve_env = kwargs['PENV']
            del kwargs['PENV']
        else:
            preserve_env = ['HOME', 'PWD', 'PATH',
                            'http_proxy', 'https_proxy',
                            'ftp_proxy', 'no_proxy', 'GIT_PROXY_COMMAND']

        env_command = self._get_env_cleaned_command(shell, preserve_env)
        self.command = "%s \'%s\'" % (env_command, self.command)
        ShellCommand.__init__(self, **kwargs)

    def _get_env_cleaned_command(self, shell, preserve_env):
        pe_cmd = ''
        for pe in preserve_env:
            pe_cmd += "%s=\"$%s\" " % (pe, pe)

        return "env -i %s %s -c " % (pe_cmd, shell)

class BitbakeLogLineObserver(LogLineObserver):
    """
        Search in the stdio bitbake log for exception/errors, identify
        if the error is a recipe/task one if not turn on the flag of
        bitbake error/exception and save the log.
    """

    rexp_error = re.compile("^ERROR: .*$")

    # recipe task errors regex'es
    rexp_pnpv_error = re.compile("^ERROR: (?P<pnpv>.*) do_(?P<task>.*):.*$")
    rexp_task_error = re.compile("^ERROR: Task .*$")
    rexp_log_error = re.compile("^ERROR: Logfile of failure stored in: "\
            "(?P<path>.*)$")

    def _handleError(self, line):
        if not hasattr(self.step, 'errors'):
            self.step.errors = {}
            self.step.errors['bitbake'] = False
            self.step.errors['log'] = []

        # save all the log for be able to get report variables like
        # machine, target, distro, etc
        self.step.errors['log'].append(line)

        # discard line that are not errors and line that
        # is recipe task errors
        if (not self.rexp_error.match(line)) or \
                self.rexp_pnpv_error.match(line) or \
                self.rexp_task_error.match(line) or \
                self.rexp_log_error.match(line):
            return

        # if not match recipe task type is a bitbake exception/error
        self.step.errors['bitbake'] = True

    def outLineReceived(self, line):
        self._handleError(line)

    def errLineReceived(self, line):
        self._handleError(line)

class BitbakeShellCommand(ShellCommand):
    def __init__(self, factory, argdict=None, **kwargs):
        super(BitbakeShellCommand, self).__init__(**kwargs)

        self.stdio_observer = BitbakeLogLineObserver()
        self.addLogObserver('stdio', self.stdio_observer)

    def _get_variables(self, log):
        vrs = {}

        rexp = re.compile("^(.*)=.*\"(.*)\"$")
        for line in log:
            m = rexp.match(line)
            if m:
                vrs[m.group(1).rstrip()] = m.group(2)

        return vrs

    def _createBitbakeErrorReport(self, log):
        vrs = self._get_variables(log)

        report = {}
        report['machine'] = vrs.get('MACHINE', 'unknown_{0}'.format('MACHINE'))
        report['build_sys'] = vrs.get('BUILD_SYS', 'unknown_{0}'.format('BUILD_SYS'))
        report['nativelsb'] = vrs.get('NATIVELSBSTRING', 'unknown_{0}'.format('NATIVELSBSTRING'))
        report['distro'] = vrs.get('DISTRO', 'unknown_{0}'.format('DISTRO'))
        report['target_sys'] = vrs.get('TARGET_SYS', 'unknown_{0}'.format('TARGET_SYS'))

        report['component'] = 'bitbake'
        try:
            branch = self.getProperty('branch')
            revision = self.getProperty('got_revision')
            if not revision:
                revision = self.getProperty('got_revision_oecore')
        except:
            branch = "unknown_branch"
            revision = "unknown_revision"
        report['branch_commit'] = branch + ': ' + revision

        failure = {}
        failure['package'] = "bitbake-%s" % vrs.get('BB_VERSION', 'unknown_{0}'.format('BB_VERSION'))
        if 'bitbake-selftest' in self.command:
            report['error_type'] = 'bitbake-selftest'
            failure['task'] = self.command[self.command.find('bitbake-selftest'):]
        else:
            report['error_type'] = 'core'
            failure['task'] = self.command[self.command.find('bitbake'):]

        failure['log'] = "\n".join(log)

        report['failures'] = [failure]

        return report

    def commandComplete(self, cmd):
        if cmd.didFail():
            if hasattr(self, 'errors') and self.errors['bitbake']:
                buildername = self.getProperty('buildername')
                buildnumber = self.getProperty('buildnumber')

                report = self._createBitbakeErrorReport(self.errors['log'])
                save_error_report(buildername, buildnumber, report, 'bitbake')

    def skipStep(self, reason):
        self.command = "echo '%s'" % reason
        self.description = ["%s" % reason]