Example #1
0
 def test_nonexisting_command(self):
     cmdline = CommandLine('doesnotexist', [])
     iterable = iter(cmdline.execute())
     try:
         out, err = iterable.next()
         self.fail("Expected BuildError")
     except BuildError, e:
         self.failUnless("Error executing ['doesnotexist']" in str(e))
Example #2
0
 def test_nonexisting_command(self):
     cmdline = CommandLine('doesnotexist', [])
     iterable = iter(cmdline.execute())
     try:
         out, err = iterable.next()
         self.fail("Expected BuildError")
     except BuildError, e:
         self.failUnless("Error executing ['doesnotexist']" in str(e))
Example #3
0
    def test_timeout(self):
        script_file = self._create_file('test.py', content="""
import time
time.sleep(2.0)
print 'Done'
""")
        cmdline = CommandLine('python', [script_file])
        iterable = iter(cmdline.execute(timeout=.5))
        self.assertRaises(TimeoutError, iterable.next)
Example #4
0
    def test_timeout(self):
        script_file = self._create_file('test.py', content="""
import time
time.sleep(2.0)
print 'Done'
""")
        cmdline = CommandLine('python', [script_file])
        iterable = iter(cmdline.execute(timeout=.5))
        self.assertRaises(TimeoutError, iterable.next)
Example #5
0
    def test_timeout(self):
        script_file = self._create_file('test.py', content="""
import time
time.sleep(2.0)
print 'Done'
""")
        cmdline = CommandLine('python', [script_file])
        iterable = iter(cmdline.execute(timeout=.5))
        if os.name != "nt":
            # commandline timeout not implemented on windows. See #257
            self.assertRaises(TimeoutError, iterable.next)
Example #6
0
 def test_single_argument(self):
     cmdline = CommandLine(sys.executable, ['-V'])
     stdout = []
     stderr = []
     for out, err in cmdline.execute(timeout=5.0):
         if out is not None:
             stdout.append(out)
         if err is not None:
             stderr.append(err)
     py_version = '.'.join([str(v) for (v) in sys.version_info[:3]])
     self.assertEqual(['Python %s' % py_version], stderr)
     self.assertEqual([], stdout)
     self.assertEqual(0, cmdline.returncode)
Example #7
0
def distutils(ctxt,
              file_='setup.py',
              command='build',
              options=None,
              timeout=None):
    """Execute a ``distutils`` command.
    
    :param ctxt: the build context
    :type ctxt: `Context`
    :param file\_: name of the file defining the distutils setup
    :param command: the setup command to execute
    :param options: additional options to pass to the command
    :param timeout: the number of seconds before the external process should
                    be aborted (has same constraints as CommandLine)
    """
    if options:
        if isinstance(options, basestring):
            options = shlex.split(options)
    else:
        options = []

    if timeout:
        timeout = int(timeout)

    cmdline = CommandLine(_python_path(ctxt),
                          [ctxt.resolve(file_), command] + options,
                          cwd=ctxt.basedir)
    log_elem = xmlio.Fragment()
    error_logged = False
    for out, err in cmdline.execute(timeout):
        if out is not None:
            log.info(out)
            log_elem.append(xmlio.Element('message', level='info')[out])
        if err is not None:
            level = 'error'
            if err.startswith('warning: '):
                err = err[9:]
                level = 'warning'
                log.warning(err)
            elif err.startswith('error: '):
                ctxt.error(err[7:])
                error_logged = True
            else:
                log.error(err)
            log_elem.append(xmlio.Element('message', level=level)[err])
    ctxt.log(log_elem)

    if not error_logged and cmdline.returncode != 0:
        ctxt.error('distutils failed (%s)' % cmdline.returncode)
Example #8
0
    def test_single_argument(self):
        cmdline = CommandLine(sys.executable, ['-V'])
        stdout = []
        stderr = []
        for out, err in cmdline.execute(timeout=5.0):
            if out is not None:
                stdout.append(out)
            if err is not None:
                stderr.append(err)
        py_version = '.'.join([str(v) for (v) in sys.version_info[:3]]
                                                            ).rstrip('.0')

        self.assertEqual(['Python %s' % py_version], stderr)
        self.assertEqual([], stdout)
        self.assertEqual(0, cmdline.returncode)
Example #9
0
    def test_multiple_arguments(self):
        script_file = self._create_file('test.py', content="""
import sys
for arg in sys.argv[1:]:
    print arg
""")
        cmdline = CommandLine('python', [script_file, 'foo', 'bar', 'baz'])
        stdout = []
        stderr = []
        for out, err in cmdline.execute(timeout=5.0):
            stdout.append(out)
            stderr.append(err)
        self.assertEqual(['foo', 'bar', 'baz'], stdout)
        self.assertEqual([None, None, None], stderr)
        self.assertEqual(0, cmdline.returncode)
Example #10
0
    def test_multiple_arguments(self):
        script_file = self._create_file('test.py', content="""
import sys
for arg in sys.argv[1:]:
    print arg
""")
        cmdline = CommandLine('python', [script_file, 'foo', 'bar', 'baz'])
        stdout = []
        stderr = []
        for out, err in cmdline.execute(timeout=5.0):
            stdout.append(out)
            stderr.append(err)
        self.assertEqual(['foo', 'bar', 'baz'], stdout)
        self.assertEqual([None, None, None], stderr)
        self.assertEqual(0, cmdline.returncode)
Example #11
0
def distutils(ctxt, file_='setup.py', command='build',
              options=None, timeout=None):
    """Execute a ``distutils`` command.
    
    :param ctxt: the build context
    :type ctxt: `Context`
    :param file\_: name of the file defining the distutils setup
    :param command: the setup command to execute
    :param options: additional options to pass to the command
    :param timeout: the number of seconds before the external process should
                    be aborted (has same constraints as CommandLine)
    """
    if options:
        if isinstance(options, basestring):
            options = shlex.split(options)
    else:
        options = []

    if timeout:
        timeout = int(timeout)

    cmdline = CommandLine(_python_path(ctxt),
                          [ctxt.resolve(file_), command] + options,
                          cwd=ctxt.basedir)
    log_elem = xmlio.Fragment()
    error_logged = False
    for out, err in cmdline.execute(timeout):
        if out is not None:
            log.info(out)
            log_elem.append(xmlio.Element('message', level='info')[out])
        if err is not None:
            level = 'error'
            if err.startswith('warning: '):
                err = err[9:]
                level = 'warning'
                log.warning(err)
            elif err.startswith('error: '):
                ctxt.error(err[7:])
                error_logged = True
            else:
                log.error(err)
            log_elem.append(xmlio.Element('message', level=level)[err])
    ctxt.log(log_elem)

    if not error_logged and cmdline.returncode != 0:
        ctxt.error('distutils failed (%s)' % cmdline.returncode)
Example #12
0
    def test_input_stream_as_string(self):
        script_file = self._create_file('test.py', content="""
import sys
data = sys.stdin.read()
if data == 'abcd':
    print>>sys.stdout, 'Thanks'
""")
        cmdline = CommandLine('python', [script_file], input='abcd')
        stdout = []
        stderr = []
        for out, err in cmdline.execute(timeout=5.0):
            stdout.append(out)
            stderr.append(err)
        py_version = '.'.join([str(v) for (v) in sys.version_info[:3]])
        self.assertEqual(['Thanks'], stdout)
        self.assertEqual([None], stderr)
        self.assertEqual(0, cmdline.returncode)
Example #13
0
    def test_input_stream_as_string(self):
        script_file = self._create_file('test.py', content="""
import sys
data = sys.stdin.read()
if data == 'abcd':
    print>>sys.stdout, 'Thanks'
""")
        cmdline = CommandLine('python', [script_file], input='abcd')
        stdout = []
        stderr = []
        for out, err in cmdline.execute(timeout=5.0):
            stdout.append(out)
            stderr.append(err)
        py_version = '.'.join([str(v) for (v) in sys.version_info[:3]])
        self.assertEqual(['Thanks'], stdout)
        self.assertEqual([None], stderr)
        self.assertEqual(0, cmdline.returncode)
Example #14
0
    def test_output_error_streams(self):
        script_file = self._create_file('test.py', content="""
import sys, time
print>>sys.stdout, 'Hello'
print>>sys.stdout, 'world!'
sys.stdout.flush()
time.sleep(.1)
print>>sys.stderr, 'Oops'
sys.stderr.flush()
""")
        cmdline = CommandLine('python', [script_file])
        stdout = []
        stderr = []
        for out, err in cmdline.execute(timeout=5.0):
            stdout.append(out)
            stderr.append(err)
        py_version = '.'.join([str(v) for (v) in sys.version_info[:3]])
        self.assertEqual(['Hello', 'world!', None], stdout)
        self.assertEqual(0, cmdline.returncode)
Example #15
0
    def test_output_error_streams(self):
        script_file = self._create_file('test.py', content="""
import sys, time
print>>sys.stdout, 'Hello'
print>>sys.stdout, 'world!'
sys.stdout.flush()
time.sleep(.1)
print>>sys.stderr, 'Oops'
sys.stderr.flush()
""")
        cmdline = CommandLine('python', [script_file])
        stdout = []
        stderr = []
        for out, err in cmdline.execute(timeout=5.0):
            stdout.append(out)
            stderr.append(err)
        py_version = '.'.join([str(v) for (v) in sys.version_info[:3]])
        self.assertEqual(['Hello', 'world!', None], stdout)
        self.assertEqual(0, cmdline.returncode)
Example #16
0
def execute(ctxt,
            executable=None,
            file_=None,
            input_=None,
            output=None,
            args=None,
            dir_=None,
            filter_=None):
    """Generic external program execution.
    
    This function is not itself bound to a recipe command, but rather used from
    other commands.
    
    :param ctxt: the build context
    :type ctxt: `Context`
    :param executable: name of the executable to run
    :param file\_: name of the script file, relative to the project directory,
                  that should be run
    :param input\_: name of the file containing the data that should be passed
                   to the shell script on its standard input stream
    :param output: name of the file to which the output of the script should be
                   written
    :param args: command-line arguments to pass to the script
    :param filter\_: function to filter out messages from the executable stdout
    """
    if args:
        if isinstance(args, basestring):
            args = shlex.split(args)
    else:
        args = []

    if dir_:

        def resolve(*args):
            return ctxt.resolve(dir_, *args)
    else:
        resolve = ctxt.resolve

    if file_ and os.path.isfile(resolve(file_)):
        file_ = resolve(file_)

    if executable is None:
        executable = file_
    elif file_:
        args[:0] = [file_]

    # Support important Windows CMD.EXE built-ins (and it does its own quoting)
    if os.name == 'nt' and executable.upper() in [
            'COPY', 'DIR', 'ECHO', 'ERASE', 'DEL', 'MKDIR', 'MD', 'MOVE',
            'RMDIR', 'RD', 'TYPE'
    ]:
        args = ['/C', executable] + [arg.strip('"') for arg in args]
        executable = os.environ['COMSPEC']

    if input_:
        input_file = file(resolve(input_), 'r')
    else:
        input_file = None

    if output:
        output_file = file(resolve(output), 'w')
    else:
        output_file = None

    if dir_ and os.path.isdir(ctxt.resolve(dir_)):
        dir_ = ctxt.resolve(dir_)
    else:
        dir_ = ctxt.basedir

    if not filter_:
        filter_ = lambda s: s

    try:
        cmdline = CommandLine(executable, args, input=input_file, cwd=dir_)
        log_elem = xmlio.Fragment()
        for out, err in cmdline.execute():
            if out is not None:
                log.info(out)
                info = filter_(out)
                if info:
                    log_elem.append(
                        xmlio.Element('message', level='info')[info.replace(
                            ctxt.basedir + os.sep,
                            '').replace(ctxt.basedir, '')])
                if output:
                    output_file.write(out + os.linesep)
            if err is not None:
                log.error(err)
                log_elem.append(
                    xmlio.Element('message', level='error')[err.replace(
                        ctxt.basedir + os.sep, '').replace(ctxt.basedir, '')])
                if output:
                    output_file.write(err + os.linesep)
        ctxt.log(log_elem)
    finally:
        if input_:
            input_file.close()
        if output:
            output_file.close()

    return cmdline.returncode
Example #17
0
def execute(ctxt, executable=None, file_=None, input_=None, output=None,
            args=None, dir_=None, filter_=None):
    """Generic external program execution.
    
    This function is not itself bound to a recipe command, but rather used from
    other commands.
    
    :param ctxt: the build context
    :type ctxt: `Context`
    :param executable: name of the executable to run
    :param file\_: name of the script file, relative to the project directory,
                  that should be run
    :param input\_: name of the file containing the data that should be passed
                   to the shell script on its standard input stream
    :param output: name of the file to which the output of the script should be
                   written
    :param args: command-line arguments to pass to the script
    :param filter\_: function to filter out messages from the executable stdout
    """
    if args:
        if isinstance(args, basestring):
            args = shlex.split(args)
    else:
        args = []

    if dir_:
        def resolve(*args):
            return ctxt.resolve(dir_, *args)
    else:
        resolve = ctxt.resolve

    if file_ and os.path.isfile(resolve(file_)):
        file_ = resolve(file_)

    if executable is None:
        executable = file_
    elif file_:
        args[:0] = [file_]

    # Support important Windows CMD.EXE built-ins (and it does its own quoting)
    if os.name == 'nt' and executable.upper() in ['COPY', 'DIR', 'ECHO',
                'ERASE', 'DEL', 'MKDIR', 'MD', 'MOVE', 'RMDIR', 'RD', 'TYPE']:
        args = ['/C', executable] + [arg.strip('"') for arg in args]
        executable = os.environ['COMSPEC']

    if input_:
        input_file = file(resolve(input_), 'r')
    else:
        input_file = None

    if output:
        output_file = file(resolve(output), 'w')
    else:
        output_file = None

    if dir_ and os.path.isdir(ctxt.resolve(dir_)):
        dir_ = ctxt.resolve(dir_)
    else:
        dir_ = ctxt.basedir
        
    if not filter_:
        filter_=lambda s: s

    try:
        cmdline = CommandLine(executable, args, input=input_file,
                              cwd=dir_)
        log_elem = xmlio.Fragment()
        for out, err in cmdline.execute():
            if out is not None:
                log.info(out)
                info = filter_(out)
                if info:
                    log_elem.append(xmlio.Element('message', level='info')[
                        info.replace(ctxt.basedir + os.sep, '')
                            .replace(ctxt.basedir, '')
                ])
                if output:
                    output_file.write(out + os.linesep)
            if err is not None:
                log.error(err)
                log_elem.append(xmlio.Element('message', level='error')[
                    err.replace(ctxt.basedir + os.sep, '')
                       .replace(ctxt.basedir, '')
                ])
                if output:
                    output_file.write(err + os.linesep)
        ctxt.log(log_elem)
    finally:
        if input_:
            input_file.close()
        if output:
            output_file.close()

    return cmdline.returncode
Example #18
0
def ant(ctxt, file_=None, target=None, keep_going=False, args=None):
    """Run an Ant build.
    
    :param ctxt: the build context
    :type ctxt: `Context`
    :param file\_: name of the Ant build file
    :param target: name of the target that should be executed (optional)
    :param keep_going: whether Ant should keep going when errors are encountered
    :param args: additional arguments to pass to Ant
    """
    executable = 'ant'
    ant_home = ctxt.config.get_dirpath('ant.home')
    if ant_home:
        executable = os.path.join(ant_home, 'bin', 'ant')

    java_home = ctxt.config.get_dirpath('java.home')
    if java_home:
        os.environ['JAVA_HOME'] = java_home

    logfile = tempfile.NamedTemporaryFile(prefix='ant_log', suffix='.xml')
    logfile.close()
    if args:
        args = shlex.split(args)
    else:
        args = []
    args += ['-noinput', '-listener', 'org.apache.tools.ant.XmlLogger',
             '-Dant.XmlLogger.stylesheet.uri', '""',
             '-DXmlLogger.file', logfile.name]
    if file_:
        args += ['-buildfile', ctxt.resolve(file_)]
    if keep_going:
        args.append('-keep-going')
    if target:
        args.append(target)

    cmdline = CommandLine(executable, args, cwd=ctxt.basedir)
    for out, err in cmdline.execute():
        if out is not None:
            log.info(out)
        if err is not None:
            log.error(err)

    error_logged = False
    log_elem = xmlio.Fragment()
    try:
        xml_log = xmlio.parse(file(logfile.name, 'r'))
        def collect_log_messages(node):
            for child in node.children():
                if child.name == 'message':
                    if child.attr['priority'] == 'debug':
                        continue
                    log_elem.append(xmlio.Element('message',
                                                  level=child.attr['priority'])[
                        child.gettext().replace(ctxt.basedir + os.sep, '')
                                       .replace(ctxt.basedir, '')
                    ])
                else:
                    collect_log_messages(child)
        collect_log_messages(xml_log)

        if 'error' in xml_log.attr:
            ctxt.error(xml_log.attr['error'])
            error_logged = True

    except xmlio.ParseError, e:
        log.warning('Error parsing Ant XML log file (%s)', e)
Example #19
0
def gcov(ctxt, include=None, exclude=None, prefix=None, root=""):
    """Run ``gcov`` to extract coverage data where available.
    
    :param ctxt: the build context
    :type ctxt: `Context`
    :param include: patterns of files and directories to include
    :param exclude: patterns of files and directories that should be excluded
    :param prefix: optional prefix name that is added to object files by the
                   build system
    :param root: optional root path in which the build system puts the object
                 files
    """
    file_re = re.compile(r'^File (?:\'|\`)(?P<file>[^\']+)\'\s*$')
    lines_re = re.compile(r'^Lines executed:(?P<cov>\d+\.\d+)\% of (?P<num>\d+)\s*$')

    files = []
    for filename in FileSet(ctxt.basedir, include, exclude):
        if os.path.splitext(filename)[1] in ('.c', '.cpp', '.cc', '.cxx'):
            files.append(filename)

    coverage = xmlio.Fragment()
    log_elem = xmlio.Fragment()
    def info (msg):
        log.info (msg)
        log_elem.append (xmlio.Element ('message', level='info')[msg])
    def warning (msg):
        log.warning (msg)
        log_elem.append (xmlio.Element ('message', level='warning')[msg])
    def error (msg):
        log.error (msg)
        log_elem.append (xmlio.Element ('message', level='error')[msg])

    for srcfile in files:
        # Determine the coverage for each source file by looking for a .gcno
        # and .gcda pair
        info ("Getting coverage info for %s" % srcfile)
        filepath, filename = os.path.split(srcfile)
        stem = os.path.splitext(filename)[0]
        if prefix is not None:
            stem = prefix + '-' + stem

        objfile = os.path.join (root, filepath, stem + '.o')
        if not os.path.isfile(ctxt.resolve(objfile)):
            warning ('No object file found for %s at %s' % (srcfile, objfile))
            continue
        if not os.path.isfile (ctxt.resolve (os.path.join (root, filepath, stem + '.gcno'))):
            warning ('No .gcno file found for %s at %s' % (srcfile, os.path.join (root, filepath, stem + '.gcno')))
            continue
        if not os.path.isfile (ctxt.resolve (os.path.join (root, filepath, stem + '.gcda'))):
            warning ('No .gcda file found for %s at %s' % (srcfile, os.path.join (root, filepath, stem + '.gcda')))
            continue

        num_lines, num_covered = 0, 0
        skip_block = False
        cmd = CommandLine('gcov', ['-b', '-n', '-o', objfile, srcfile],
                          cwd=ctxt.basedir)
        for out, err in cmd.execute():
            if out == '': # catch blank lines, reset the block state...
                skip_block = False
            elif out and not skip_block:
                # Check for a file name
                match = file_re.match(out)
                if match:
                    if os.path.isabs(match.group('file')):
                        skip_block = True
                        continue
                else:
                    # check for a "Lines executed" message
                    match = lines_re.match(out)
                    if match:
                        lines = float(match.group('num'))
                        cov = float(match.group('cov'))
                        num_covered += int(lines * cov / 100)
                        num_lines += int(lines)
        if cmd.returncode != 0:
            continue

        module = xmlio.Element('coverage', name=os.path.basename(srcfile),
                                file=srcfile.replace(os.sep, '/'),
                                lines=num_lines, percentage=0)
        if num_lines:
            percent = int(round(num_covered * 100 / num_lines))
            module.attr['percentage'] = percent
        coverage.append(module)

    ctxt.report('coverage', coverage)
    ctxt.log (log_elem)
Example #20
0
def ant(ctxt, file_=None, target=None, keep_going=False, args=None):
    """Run an Ant build.
    
    :param ctxt: the build context
    :type ctxt: `Context`
    :param file\_: name of the Ant build file
    :param target: name of the target that should be executed (optional)
    :param keep_going: whether Ant should keep going when errors are encountered
    :param args: additional arguments to pass to Ant
    """
    executable = 'ant'
    ant_home = ctxt.config.get_dirpath('ant.home')
    if ant_home:
        executable = os.path.join(ant_home, 'bin', 'ant')

    java_home = ctxt.config.get_dirpath('java.home')
    if java_home:
        os.environ['JAVA_HOME'] = java_home

    logfile = tempfile.NamedTemporaryFile(prefix='ant_log', suffix='.xml')
    logfile.close()
    if args:
        args = shlex.split(args)
    else:
        args = []
    args += [
        '-noinput', '-listener', 'org.apache.tools.ant.XmlLogger',
        '-Dant.XmlLogger.stylesheet.uri', '""', '-DXmlLogger.file',
        logfile.name
    ]
    if file_:
        args += ['-buildfile', ctxt.resolve(file_)]
    if keep_going:
        args.append('-keep-going')
    if target:
        args.append(target)

    shell = False
    if os.name == 'nt':
        # Need to execute ant.bat through a shell on Windows
        shell = True

    cmdline = CommandLine(executable, args, cwd=ctxt.basedir, shell=shell)
    for out, err in cmdline.execute():
        if out is not None:
            log.info(out)
        if err is not None:
            log.error(err)

    error_logged = False
    log_elem = xmlio.Fragment()
    try:
        xml_log = xmlio.parse(file(logfile.name, 'r'))

        def collect_log_messages(node):
            for child in node.children():
                if child.name == 'message':
                    if child.attr['priority'] == 'debug':
                        continue
                    log_elem.append(
                        xmlio.Element('message', level=child.attr['priority'])
                        [child.gettext().replace(ctxt.basedir + os.sep,
                                                 '').replace(ctxt.basedir,
                                                             '')])
                else:
                    collect_log_messages(child)

        collect_log_messages(xml_log)

        if 'error' in xml_log.attr:
            ctxt.error(xml_log.attr['error'])
            error_logged = True

    except xmlio.ParseError, e:
        log.warning('Error parsing Ant XML log file (%s)', e)
Example #21
0
def gcov(ctxt, include=None, exclude=None, prefix=None, root="", dir_=None):
    """Run ``gcov`` to extract coverage data where available.

    :param ctxt: the build context
    :type ctxt: `Context`
    :param include: patterns of files and directories to include
    :param exclude: patterns of files and directories that should be excluded
    :param prefix: optional prefix name that is added to object files by the
                   build system
    :param root: optional root path in which the build system puts the object
                 files
    :param dir_: optional base dir path, usefull when you have source in a
                 subdirectory of your repository
    """
    file_re = re.compile(r"^File (?:\'|\`)(?P<file>[^\']+)\'\s*$")
    lines_re = re.compile(r"^Lines executed:(?P<cov>\d+\.\d+)\% of (?P<num>\d+)\s*$")

    # basedir will be a path relative to the context
    # resolve will be a function for resolving file's paths
    if dir_:
        # The base dir should finish in /
        # this is used to create the path of the files
        basedir = dir_
        if basedir.rfind("/") != len(basedir) - 1:
            basedir += "/"

        def resolve(*args):
            return ctxt.resolve(dir_, *args)

    else:
        basedir = ""
        resolve = ctxt.resolve

    files = []
    if dir_ and os.path.isdir(ctxt.resolve(dir_)):
        dir_ = ctxt.resolve(dir_)
    else:
        dir_ = ctxt.basedir
    for filename in FileSet(dir_, include, exclude):
        if os.path.splitext(filename)[1] in (".c", ".cpp", ".cc", ".cxx"):
            files.append(filename)

    coverage = xmlio.Fragment()
    log_elem = xmlio.Fragment()

    def info(msg):
        log.info(msg)
        log_elem.append(xmlio.Element("message", level="info")[msg])

    def warning(msg):
        log.warning(msg)
        log_elem.append(xmlio.Element("message", level="warning")[msg])

    def error(msg):
        log.error(msg)
        log_elem.append(xmlio.Element("message", level="error")[msg])

    for srcfile in files:
        # Determine the coverage for each source file by looking for a .gcno
        # and .gcda pair
        info("Getting coverage info for %s" % srcfile)
        filepath, filename = os.path.split(srcfile)
        stem = os.path.splitext(filename)[0]
        if prefix is not None:
            stem = prefix + "-" + stem

        objfile = os.path.join(root, filepath, stem + ".o")
        if not os.path.isfile(resolve(objfile)):
            warning("No object file found for %s at %s" % (srcfile, objfile))
            continue
        if not os.path.isfile(resolve(os.path.join(root, filepath, stem + ".gcno"))):
            warning("No .gcno file found for %s at %s" % (srcfile, os.path.join(root, filepath, stem + ".gcno")))
            continue
        if not os.path.isfile(resolve(os.path.join(root, filepath, stem + ".gcda"))):
            warning("No .gcda file found for %s at %s" % (srcfile, os.path.join(root, filepath, stem + ".gcda")))
            continue

        num_lines, num_covered = 0, 0
        skip_block = False
        cmd = CommandLine("gcov", ["-b", "-n", "-o", objfile, srcfile], cwd=dir_)
        for out, err in cmd.execute():
            info(out)
            if out == "":  # catch blank lines, reset the block state...
                skip_block = False
            elif out and not skip_block:
                # Check for a file name
                match = file_re.match(out)
                if match:
                    # if the file is inside our ctxt.resolve(dir_)...
                    if match.group("file").find(dir_) != 0:
                        skip_block = True
                        continue
                else:
                    # check for a "Lines executed" message
                    match = lines_re.match(out)
                    if match:
                        lines = float(match.group("num"))
                        cov = float(match.group("cov"))
                        num_covered += int(lines * cov / 100)
                        num_lines += int(lines)
        if cmd.returncode != 0:
            continue

        module = xmlio.Element(
            "coverage",
            name=os.path.basename(srcfile),
            file=(basedir + srcfile).replace(os.sep, "/"),
            lines=num_lines,
            percentage=0,
        )
        if num_lines:
            percent = int(round(num_covered * 100 / num_lines))
            module.attr["percentage"] = percent
        coverage.append(module)

    ctxt.report("coverage", coverage)
    ctxt.log(log_elem)
Example #22
0
def execute(
    ctxt, executable=None, file_=None, input_=None, output=None, args=None, dir_=None, filter_=None, timeout=None
):
    """Generic external program execution.
    
    This function is not itself bound to a recipe command, but rather used from
    other commands.
    
    :param ctxt: the build context
    :type ctxt: `Context`
    :param executable: name of the executable to run
    :param file\_: name of the script file, relative to the project directory,
                  that should be run
    :param input\_: name of the file containing the data that should be passed
                   to the shell script on its standard input stream
    :param output: name of the file to which the output of the script should be
                   written
    :param args: command-line arguments to pass to the script
    :param dir\_: directory to change to before executing the command
    :param filter\_: function to filter out messages from the executable stdout
    :param timeout: the number of seconds before the external process should
                    be aborted (has same constraints as CommandLine)
    """
    if args:
        if isinstance(args, basestring):
            args = shlex.split(args)
    else:
        args = []

    if dir_:

        def resolve(*args):
            return ctxt.resolve(dir_, *args)

    else:
        resolve = ctxt.resolve

    if file_ and os.path.isfile(resolve(file_)):
        file_ = resolve(file_)

    shell = False

    if file_ and os.name == "nt":
        # Need to execute script files through a shell on Windows
        shell = True

    if executable is None:
        executable = file_
    elif file_:
        args[:0] = [file_]

    # Support important Windows CMD.EXE built-ins (and it does its own quoting)
    if os.name == "nt" and executable.upper() in [
        "COPY",
        "DIR",
        "ECHO",
        "ERASE",
        "DEL",
        "MKDIR",
        "MD",
        "MOVE",
        "RMDIR",
        "RD",
        "TYPE",
    ]:
        shell = True

    if input_:
        input_file = codecs.open(resolve(input_), "r", "utf-8")
    else:
        input_file = None

    if output:
        output_file = codecs.open(resolve(output), "w", "utf-8")
    else:
        output_file = None

    if dir_ and os.path.isdir(ctxt.resolve(dir_)):
        dir_ = ctxt.resolve(dir_)
    else:
        dir_ = ctxt.basedir

    if not filter_:
        filter_ = lambda s: s

    if timeout:
        timeout = int(timeout)

    try:
        cmdline = CommandLine(executable, args, input=input_file, cwd=dir_, shell=shell)
        log_elem = xmlio.Fragment()
        for out, err in cmdline.execute(timeout=timeout):
            if out is not None:
                log.info(out)
                info = filter_(out)
                if info:
                    log_elem.append(
                        xmlio.Element("message", level="info")[
                            info.replace(ctxt.basedir + os.sep, "").replace(ctxt.basedir, "")
                        ]
                    )
                if output:
                    output_file.write(out + os.linesep)
            if err is not None:
                log.error(err)
                log_elem.append(
                    xmlio.Element("message", level="error")[
                        err.replace(ctxt.basedir + os.sep, "").replace(ctxt.basedir, "")
                    ]
                )
                if output:
                    output_file.write(err + os.linesep)
        ctxt.log(log_elem)
    finally:
        if input_:
            input_file.close()
        if output:
            output_file.close()

    return cmdline.returncode