Edgewall Software

source: trunk/bitten/build/phptools.py @ 1001

Last change on this file since 1001 was 910, checked in by osimons, 13 years ago

Updated copyright to 2010.

  • Property svn:eol-style set to native
File size: 6.3 KB
CovLine 
1# -*- coding: UTF-8 -*-
2#
3# Copyright (C) 2007-2010 Edgewall Software
4# Copyright (C) 2007 Wei Zhuo <weizhuo@gmail.com>
5# All rights reserved.
6#
7# This software is licensed as described in the file COPYING, which
8# you should have received as part of this distribution. The terms
9# are also available at http://bitten.edgewall.org/wiki/License.
10
111"Recipe commands for tools commonly used in PHP projects."
12
113import logging
114import os
115import shlex
16
117from bitten.util import xmlio
118from bitten.build import shtools
19
120log = logging.getLogger('bitten.build.phptools')
21
122def phing(ctxt, file_=None, target=None, executable=None, args=None):
23    """Run a phing build"""
024    if args:
025        args = shlex.split(args)
026    else:
027        args = []
028    args += ['-logger', 'phing.listener.DefaultLogger',
029             '-buildfile', ctxt.resolve(file_ or 'build.xml')]
030    if target:
031        args.append(target)
32
033    returncode = shtools.execute(ctxt, file_=executable or 'phing', args=args)
034    if returncode != 0:
035        ctxt.error('Phing failed (%s)' % returncode)
36
137def phpunit(ctxt, file_=None):
38    """Extract test results from a PHPUnit XML report."""
239    assert file_, 'Missing required attribute "file"'
40
141    def _process_testsuite(testsuite, results, parent_file=''):
542        for testcase in testsuite.children():
343            if testcase.name == 'testsuite':
044                _process_testsuite(testcase, results,
045                        parent_file=testcase.attr.get('file', parent_file))
046                continue
347            test = xmlio.Element('test')
348            test.attr['fixture'] = testsuite.attr['name']
349            test.attr['name'] = testcase.attr['name']
350            test.attr['duration'] = testcase.attr['time']
351            result = list(testcase.children())
352            if result:
153                test.append(xmlio.Element('traceback')[
154                    result[0].gettext()
155                ])
156                test.attr['status'] = result[0].name
157            else:
258                test.attr['status'] = 'success'
359            if 'file' in testsuite.attr or parent_file:
360                testfile = os.path.realpath(
361                                    testsuite.attr.get('file', parent_file))
362                if testfile.startswith(ctxt.basedir):
063                    testfile = testfile[len(ctxt.basedir) + 1:]
364                testfile = testfile.replace(os.sep, '/')
365                test.attr['file'] = testfile
366            results.append(test)
67
168    try:
169        total, failed = 0, 0
170        results = xmlio.Fragment()
171        fileobj = file(ctxt.resolve(file_), 'r')
172        try:
373            for testsuite in xmlio.parse(fileobj).children('testsuite'):
274                total += int(testsuite.attr['tests'])
275                failed += int(testsuite.attr['failures']) + \
276                            int(testsuite.attr['errors'])
77
278                _process_testsuite(testsuite, results)
279        finally:
180            fileobj.close()
181        if failed:
182            ctxt.error('%d of %d test%s failed' % (failed, total,
183                        total != 1 and 's' or ''))
184        ctxt.report('test', results)
085    except IOError, e:
086        ctxt.log('Error opening PHPUnit results file (%s)' % e)
087    except xmlio.ParseError, e:
088        ctxt.log('Error parsing PHPUnit results file (%s)' % e)
89
190def coverage(ctxt, file_=None):
91    """Extract data from Phing or PHPUnit code coverage report."""
392    assert file_, 'Missing required attribute "file"'
93
294    def _process_phing_coverage(ctxt, element, coverage):
495        for cls in element.children('class'):
396            statements = float(cls.attr['statementcount'])
397            covered = float(cls.attr['statementscovered'])
398            if statements:
299                percentage = covered / statements * 100
2100            else:
1101                percentage = 100
3102            class_coverage = xmlio.Element('coverage',
3103                name=cls.attr['name'],
3104                lines=int(statements),
3105                percentage=percentage
3106            )
3107            source = list(cls.children())[0]
3108            if 'sourcefile' in source.attr:
3109                sourcefile = os.path.realpath(source.attr['sourcefile'])
3110                if sourcefile.startswith(ctxt.basedir):
0111                    sourcefile = sourcefile[len(ctxt.basedir) + 1:]
3112                sourcefile = sourcefile.replace(os.sep, '/')
3113                class_coverage.attr['file'] = sourcefile
3114            coverage.append(class_coverage)
115
2116    def _process_phpunit_coverage(ctxt, element, coverage):
7117        for cls in element._node.getElementsByTagName('class'):
6118            sourcefile = cls.parentNode.getAttribute('name')
6119            if not os.path.isabs(sourcefile):
1120                sourcefile = os.path.join(ctxt.basedir, sourcefile)
6121            if sourcefile.startswith(ctxt.basedir):
6122                loc, ncloc = 0, 0.0
41123                for line in cls.parentNode.getElementsByTagName('line'):
35124                    if str(line.getAttribute('type')) == 'stmt':
27125                        loc += 1
27126                        if int(line.getAttribute('count')) == 0:
23127                            ncloc += 1
6128                if loc > 0:
6129                    percentage = 100 - (ncloc / loc * 100)
6130                else:
0131                    percentage = 100
132
6133                if sourcefile.startswith(ctxt.basedir):
6134                    sourcefile = sourcefile[len(ctxt.basedir) + 1:]
6135                class_coverage = xmlio.Element('coverage',
6136                                    name=cls.getAttribute('name'),
6137                                    lines=int(loc),
6138                                    percentage=int(percentage),
6139                                    file=sourcefile.replace(os.sep, '/'))
6140                coverage.append(class_coverage)
141
2142    try:
2143        summary_file = file(ctxt.resolve(file_), 'r')
2144        summary = xmlio.parse(summary_file)
2145        coverage = xmlio.Fragment()
2146        try:
4147            for element in summary.children():
2148                if element.name == 'package':
1149                    _process_phing_coverage(ctxt, element, coverage)
1150                elif element.name == 'project':
1151                    _process_phpunit_coverage(ctxt, element, coverage)
1152        finally:
2153            summary_file.close()
2154        ctxt.report('coverage', coverage)
0155    except IOError, e:
0156        ctxt.log('Error opening coverage summary file (%s)' % e)
0157    except xmlio.ParseError, e:
0158        ctxt.log('Error parsing coverage summary file (%s)' % e)
Note: See TracBrowser for help on using the repository browser.