13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#!/usr/bin/env python
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)# found in the LICENSE file.
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"""Instruments classes and jar files.
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)This script corresponds to the 'emma_instr' action in the java build process.
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Depending on whether emma_instrument is set, the 'emma_instr' action will either
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)call one of the instrument commands, or the copy command.
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Possible commands are:
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)- instrument_jar: Accepts a jar and instruments it using emma.jar.
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- instrument_classes: Accepts a directory containing java classes and
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      instruments it using emma.jar.
1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- copy: Called when EMMA coverage is not enabled. This allows us to make
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      this a required step without necessarily instrumenting on every build.
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      Also removes any stale coverage files.
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"""
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import collections
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import json
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import os
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import shutil
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import sys
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import tempfile
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)from pylib.utils import command_option_parser
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)from util import build_utils
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)def _AddCommonOptions(option_parser):
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """Adds common options to |option_parser|."""
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  option_parser.add_option('--input-path',
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           help=('Path to input file(s). Either the classes '
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 'directory, or the path to a jar.'))
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  option_parser.add_option('--output-path',
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           help=('Path to output final file(s) to. Either the '
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 'final classes directory, or the directory in '
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 'which to place the instrumented/copied jar.'))
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  option_parser.add_option('--stamp', help='Path to touch when done.')
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  option_parser.add_option('--coverage-file',
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                           help='File to create with coverage metadata.')
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  option_parser.add_option('--sources-file',
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                           help='File to create with the list of sources.')
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)def _AddInstrumentOptions(option_parser):
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """Adds options related to instrumentation to |option_parser|."""
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  _AddCommonOptions(option_parser)
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  option_parser.add_option('--sources',
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           help='Space separated list of sources.')
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  option_parser.add_option('--src-root',
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           help='Root of the src repository.')
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  option_parser.add_option('--emma-jar',
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           help='Path to emma.jar.')
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  option_parser.add_option(
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      '--filter-string', default='',
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      help=('Filter string consisting of a list of inclusion/exclusion '
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            'patterns separated with whitespace and/or comma.'))
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)def _RunCopyCommand(_command, options, _, option_parser):
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  """Copies the jar from input to output locations.
6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  Also removes any old coverage/sources file.
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Args:
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    command: String indicating the command that was received to trigger
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        this function.
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    options: optparse options dictionary.
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    args: List of extra args from optparse.
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    option_parser: optparse.OptionParser object.
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Returns:
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    An exit code.
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if not (options.input_path and options.output_path and
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          options.coverage_file and options.sources_file):
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    option_parser.error('All arguments are required.')
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  coverage_file = os.path.join(os.path.dirname(options.output_path),
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                               options.coverage_file)
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  sources_file = os.path.join(os.path.dirname(options.output_path),
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                              options.sources_file)
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if os.path.exists(coverage_file):
9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    os.remove(coverage_file)
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if os.path.exists(sources_file):
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    os.remove(sources_file)
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if os.path.isdir(options.input_path):
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    shutil.rmtree(options.output_path, ignore_errors=True)
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    shutil.copytree(options.input_path, options.output_path)
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  else:
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    shutil.copy(options.input_path, options.output_path)
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if options.stamp:
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    build_utils.Touch(options.stamp)
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)def _CreateSourcesFile(sources_string, sources_file, src_root):
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """Adds all normalized source directories to |sources_file|.
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Args:
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    sources_string: String generated from gyp containing the list of sources.
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    sources_file: File into which to write the JSON list of sources.
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    src_root: Root which sources added to the file should be relative to.
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Returns:
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    An exit code.
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  src_root = os.path.abspath(src_root)
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  sources = build_utils.ParseGypList(sources_string)
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  relative_sources = []
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for s in sources:
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    abs_source = os.path.abspath(s)
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if abs_source[:len(src_root)] != src_root:
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      print ('Error: found source directory not under repository root: %s %s'
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)             % (abs_source, src_root))
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return 1
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    rel_source = os.path.relpath(abs_source, src_root)
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    relative_sources.append(rel_source)
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  with open(sources_file, 'w') as f:
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    json.dump(relative_sources, f)
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)def _RunInstrumentCommand(command, options, _, option_parser):
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """Instruments the classes/jar files using EMMA.
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Args:
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    command: 'instrument_jar' or 'instrument_classes'. This distinguishes
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        whether we copy the output from the created lib/ directory, or classes/
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        directory.
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    options: optparse options dictionary.
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    args: List of extra args from optparse.
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    option_parser: optparse.OptionParser object.
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Returns:
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    An exit code.
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if not (options.input_path and options.output_path and
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          options.coverage_file and options.sources_file and options.sources and
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          options.src_root and options.emma_jar):
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    option_parser.error('All arguments are required.')
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  coverage_file = os.path.join(os.path.dirname(options.output_path),
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                               options.coverage_file)
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  sources_file = os.path.join(os.path.dirname(options.output_path),
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                              options.sources_file)
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if os.path.exists(coverage_file):
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    os.remove(coverage_file)
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  temp_dir = tempfile.mkdtemp()
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  try:
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    cmd = ['java', '-cp', options.emma_jar,
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           'emma', 'instr',
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           '-ip', options.input_path,
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           '-ix', options.filter_string,
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           '-d', temp_dir,
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           '-out', coverage_file,
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           '-m', 'fullcopy']
166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    build_utils.CheckOutput(cmd)
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if command == 'instrument_jar':
1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      for jar in os.listdir(os.path.join(temp_dir, 'lib')):
1703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        shutil.copy(os.path.join(temp_dir, 'lib', jar),
1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    options.output_path)
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    else:  # 'instrument_classes'
1733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if os.path.isdir(options.output_path):
1743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        shutil.rmtree(options.output_path, ignore_errors=True)
1753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      shutil.copytree(os.path.join(temp_dir, 'classes'),
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                      options.output_path)
1773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  finally:
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    shutil.rmtree(temp_dir)
1793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  _CreateSourcesFile(options.sources, sources_file, options.src_root)
1813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if options.stamp:
1833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    build_utils.Touch(options.stamp)
1843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return 0
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)CommandFunctionTuple = collections.namedtuple(
1893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    'CommandFunctionTuple', ['add_options_func', 'run_command_func'])
1903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)VALID_COMMANDS = {
1913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    'copy': CommandFunctionTuple(_AddCommonOptions,
1923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 _RunCopyCommand),
1933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    'instrument_jar': CommandFunctionTuple(_AddInstrumentOptions,
1943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                           _RunInstrumentCommand),
1953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    'instrument_classes': CommandFunctionTuple(_AddInstrumentOptions,
1963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                               _RunInstrumentCommand),
1973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
20023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)def main():
2013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  option_parser = command_option_parser.CommandOptionParser(
2023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      commands_dict=VALID_COMMANDS)
2033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  command_option_parser.ParseAndExecute(option_parser)
2043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)if __name__ == '__main__':
20723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  sys.exit(main())
208