def instrument(self, targets, tests, compute_junit_classpath, execute_java_for_targets): instrumentation_classpath = self.initialize_instrument_classpath( targets) junit_classpath = compute_junit_classpath() cobertura_cp = self._settings.tool_classpath('cobertura-instrument') aux_classpath = os.pathsep.join( relativize_paths(junit_classpath, get_buildroot())) safe_delete(self._coverage_datafile) files_to_instrument = [] for target in targets: if self.is_coverage_target(target): paths = instrumentation_classpath.get_for_target(target) for (name, path) in paths: files_to_instrument.append(path) if len(files_to_instrument) > 0: self._nothing_to_instrument = False unique_files = list(set(files_to_instrument)) relativize_paths(unique_files, self._settings.workdir) args = [ '--basedir', self._settings.workdir, '--datafile', self._coverage_datafile, ] # apply class incl/excl filters if len(self._include_classes) > 0: for pattern in self._include_classes: args += ["--includeClasses", pattern] else: args += ["--includeClasses", '.*'] # default to instrumenting all classes for pattern in self._exclude_classes: args += ["--excludeClasses", pattern] with temporary_file() as tmp_file: tmp_file.write("\n".join(unique_files)) tmp_file.flush() args += ["--listOfFilesToInstrument", tmp_file.name] main = 'net.sourceforge.cobertura.instrument.InstrumentMain' self._context.log.debug( "executing cobertura instrumentation with the following args: {}" .format(args)) result = execute_java_for_targets( targets, classpath=cobertura_cp, main=main, jvm_options=self._coverage_jvm_options, args=args, workunit_factory=self._context.new_workunit, workunit_name='cobertura-instrument') if result != 0: raise TaskError("java {0} ... exited non-zero ({1})" " 'failed to instrument'".format( main, result))
def instrument(self, targets, compute_junit_classpath, execute_java_for_targets): # Setup an instrumentation classpath based on the existing runtime classpath. runtime_classpath = self._context.products.get_data('runtime_classpath') instrumentation_classpath = self._context.products.safe_create_data('instrument_classpath', runtime_classpath.copy) self.initialize_instrument_classpath(targets, instrumentation_classpath) cobertura_cp = self._settings.tool_classpath('cobertura-instrument') safe_delete(self._coverage_datafile) files_to_instrument = [] for target in targets: if self.is_coverage_target(target): paths = instrumentation_classpath.get_for_target(target) for (name, path) in paths: files_to_instrument.append(path) if len(files_to_instrument) > 0: self._nothing_to_instrument = False unique_files = list(set(files_to_instrument)) relativize_paths(unique_files, self._settings.workdir) args = [ '--basedir', self._settings.workdir, '--datafile', self._coverage_datafile, ] # apply class incl/excl filters if len(self._include_classes) > 0: for pattern in self._include_classes: args += ["--includeClasses", pattern] else: args += ["--includeClasses", '.*'] # default to instrumenting all classes for pattern in self._exclude_classes: args += ["--excludeClasses", pattern] with temporary_file() as tmp_file: tmp_file.write("\n".join(unique_files)) tmp_file.flush() args += ["--listOfFilesToInstrument", tmp_file.name] main = 'net.sourceforge.cobertura.instrument.InstrumentMain' self._context.log.debug( "executing cobertura instrumentation with the following args: {}".format(args)) result = execute_java_for_targets(targets, classpath=cobertura_cp, main=main, jvm_options=self._coverage_jvm_options, args=args, workunit_factory=self._context.new_workunit, workunit_name='cobertura-instrument') if result != 0: raise TaskError("java {0} ... exited non-zero ({1})" " 'failed to instrument'".format(main, result))
def instrument(self, targets, tests, compute_junit_classpath, execute_java_for_targets): instrumentation_classpath = self.initialize_instrument_classpath(targets) junit_classpath = compute_junit_classpath() cobertura_cp = self._settings.tool_classpath("cobertura-instrument") aux_classpath = os.pathsep.join(relativize_paths(junit_classpath, get_buildroot())) safe_delete(self._coverage_datafile) files_to_instrument = [] for target in targets: if self.is_coverage_target(target): paths = instrumentation_classpath.get_for_target(target) for (name, path) in paths: files_to_instrument.append(path) if len(files_to_instrument) > 0: self._nothing_to_instrument = False unique_files = list(set(files_to_instrument)) relativize_paths(unique_files, self._settings.workdir) args = ["--basedir", self._settings.workdir, "--datafile", self._coverage_datafile] # apply class incl/excl filters if len(self._include_classes) > 0: for pattern in self._include_classes: args += ["--includeClasses", pattern] else: args += ["--includeClasses", ".*"] # default to instrumenting all classes for pattern in self._exclude_classes: args += ["--excludeClasses", pattern] with temporary_file() as tmp_file: tmp_file.write("\n".join(unique_files)) tmp_file.flush() args += ["--listOfFilesToInstrument", tmp_file.name] main = "net.sourceforge.cobertura.instrument.InstrumentMain" self._context.log.debug("executing cobertura instrumentation with the following args: {}".format(args)) result = execute_java_for_targets( targets, classpath=cobertura_cp, main=main, jvm_options=self._coverage_jvm_options, args=args, workunit_factory=self._context.new_workunit, workunit_name="cobertura-instrument", ) if result != 0: raise TaskError("java {0} ... exited non-zero ({1})" " 'failed to instrument'".format(main, result))
def _test_canonical_classpath_helper(self, classpath_products, targets, libs_dir, expected_canonical_classpath, expected_classspath_files, excludes=None): """ Helper method to call `create_canonical_classpath` and verify generated canonical classpath. :param ClasspathProducts classpath_products: Classpath products. :param list targets: List of targets to generate canonical classpath from. :param string libs_dir: Directory where canonical classpath are to be generated. :param list expected_canonical_classpath: List of canonical classpath relative to a base directory. :param dict expected_classspath_files: A dict of classpath.txt path to its expected content. """ canonical_classpath = ClasspathProducts.create_canonical_classpath( classpath_products, targets, libs_dir, save_classpath_file=True, internal_classpath_only=False, excludes=excludes) # check canonical path returned self.assertEquals(expected_canonical_classpath, relativize_paths(canonical_classpath, libs_dir)) # check canonical path created contain the exact set of files, no more, no less self.assertTrue(contains_exact_files(libs_dir, expected_canonical_classpath + expected_classspath_files.keys())) # check the content of classpath.txt for classpath_file in expected_classspath_files: self.assertTrue(check_file_content(os.path.join(libs_dir, classpath_file), expected_classspath_files[classpath_file]))
def test_relativize_paths(self): build_root = "/build-root" jar_outside_build_root = os.path.join("/outside-build-root", "bar.jar") classpath = [os.path.join(build_root, "foo.jar"), jar_outside_build_root] relativized_classpath = relativize_paths(classpath, build_root) jar_relpath = os.path.relpath(jar_outside_build_root, build_root) self.assertEquals(["foo.jar", jar_relpath], relativized_classpath)
def compile(self, args, classpath, sources, classes_output_dir, analysis_file): relative_classpath = relativize_paths(classpath, self._buildroot) jmake_classpath = self.tool_classpath(self._jmake_bootstrap_key) args = [ '-classpath', ':'.join(relative_classpath + [self._classes_dir]), '-d', self._classes_dir, '-pdb', analysis_file, '-pdb-text-format', ] compiler_classpath = self.tool_classpath(self._compiler_bootstrap_key) args.extend([ '-jcpath', ':'.join(compiler_classpath), '-jcmainclass', 'com.twitter.common.tools.Compiler', ]) args.extend(map(lambda arg: '-C%s' % arg, self._javac_opts)) args.extend(self._args) args.extend(sources) result = self.runjava(classpath=jmake_classpath, main=JavaCompile._JMAKE_MAIN, jvm_options=self._jvm_options, args=args, workunit_name='jmake', workunit_labels=[WorkUnit.COMPILER]) if result: default_message = 'Unexpected error - JMake returned %d' % result raise TaskError(_JMAKE_ERROR_CODES.get(result, default_message))
def _test_canonical_classpath_helper(self, classpath_products, targets, expected_canonical_classpath, expected_classspath_files, use_target_id): """ Helper method to call `create_canonical_classpath` and verify generated canonical classpath. :param ClasspathProducts classpath_products: Classpath products. :param list targets: List of targets to generate canonical classpath from. :param list expected_canonical_classpath: List of canonical classpath relative to a base directory. :param dict expected_classspath_files: A dict of classpath.txt path to its expected content. """ with temporary_dir() as base_dir: canonical_classpath = ClasspathUtil.create_canonical_classpath( classpath_products, targets, base_dir, save_classpath_file=True, use_target_id=use_target_id) # check canonical path returned self.assertEquals(expected_canonical_classpath, relativize_paths(canonical_classpath, base_dir)) # check canonical path created contain the exact set of files, no more, no less self.assertTrue( contains_exact_files( base_dir, expected_canonical_classpath + expected_classspath_files.keys())) # check the content of classpath.txt for classpath_file in expected_classspath_files: self.assertTrue( check_file_content( os.path.join(base_dir, classpath_file), expected_classspath_files[classpath_file]))
def test_relativize_paths(self): build_root = '/build-root' jar_outside_build_root = os.path.join('/outside-build-root', 'bar.jar') classpath = [os.path.join(build_root, 'foo.jar'), jar_outside_build_root] relativized_classpath = relativize_paths(classpath, build_root) jar_relpath = os.path.relpath(jar_outside_build_root, build_root) self.assertEquals(['foo.jar', jar_relpath], relativized_classpath)
def test_relativize_paths(self) -> None: build_root = "/build-root" jar_outside_build_root = os.path.join("/outside-build-root", "bar.jar") classpath = [os.path.join(build_root, "foo.jar"), jar_outside_build_root] relativized_classpath = relativize_paths(classpath, build_root) jar_relpath = os.path.relpath(jar_outside_build_root, build_root) self.assertEqual(["foo.jar", jar_relpath], relativized_classpath)
def compile(self, args, classpath, sources, classes_output_dir, analysis_file): relative_classpath = relativize_paths(classpath, self._buildroot) jmake_classpath = self.tool_classpath(self._jmake_bootstrap_key) args = [ '-classpath', ':'.join(relative_classpath + [self._classes_dir]), '-d', self._classes_dir, '-pdb', analysis_file, '-pdb-text-format', ] compiler_classpath = self.tool_classpath( self._compiler_bootstrap_key) args.extend([ '-jcpath', ':'.join(compiler_classpath), '-jcmainclass', 'com.twitter.common.tools.Compiler', ]) args.extend(map(lambda arg: '-C%s' % arg, self._javac_opts)) args.extend(self._args) args.extend(sources) result = self.runjava(classpath=jmake_classpath, main=JavaCompile._JMAKE_MAIN, jvm_options=self._jvm_options, args=args, workunit_name='jmake', workunit_labels=[WorkUnit.COMPILER]) if result: default_message = 'Unexpected error - JMake returned %d' % result raise TaskError(_JMAKE_ERROR_CODES.get(result, default_message))
def _test_canonical_classpath_helper(self, classpath_products, targets, expected_canonical_classpath, expected_classspath_files, use_target_id): """ Helper method to call `create_canonical_classpath` and verify generated canonical classpath. :param ClasspathProducts classpath_products: Classpath products. :param list targets: List of targets to generate canonical classpath from. :param list expected_canonical_classpath: List of canonical classpath relative to a base directory. :param dict expected_classspath_files: A dict of classpath.txt path to its expected content. """ with temporary_dir() as base_dir: canonical_classpath = ClasspathUtil.create_canonical_classpath(classpath_products, targets, base_dir, save_classpath_file=True, use_target_id=use_target_id) # check canonical path returned self.assertEquals(expected_canonical_classpath, relativize_paths(canonical_classpath, base_dir)) # check canonical path created contain the exact set of files, no more, no less self.assertTrue(contains_exact_files(base_dir, expected_canonical_classpath + expected_classspath_files.keys())) # check the content of classpath.txt for classpath_file in expected_classspath_files: self.assertTrue(check_file_content(os.path.join(base_dir, classpath_file), expected_classspath_files[classpath_file]))
def compile(self, args, classpath, sources, classes_output_dir, upstream_analysis, analysis_file, log_file, settings): relative_classpath = relativize_paths(classpath, self._buildroot) jmake_classpath = self.tool_classpath('jmake') args = [ '-classpath', ':'.join(relative_classpath), '-d', classes_output_dir, '-pdb', analysis_file, '-pdb-text-format', ] # TODO: This file should always exist for modern jmake installs; this check should # be removed via a Task-level identity bump after: # https://github.com/pantsbuild/pants/issues/1351 if os.path.exists(self._depfile): args.extend(['-depfile', self._depfile]) compiler_classpath = self.tool_classpath('java-compiler') args.extend([ '-jcpath', ':'.join(compiler_classpath), '-jcmainclass', 'org.pantsbuild.tools.compiler.Compiler', ]) if not self.get_options().colors: filtered_args = filter(lambda arg: not arg == '-C-Tcolor', self._args) else: filtered_args = self._args args.extend(filtered_args) args.extend(settings.args) if '-C-source' in args: raise TaskError("Define a [jvm-platform] with the desired 'source' level instead of " "supplying one via 'args'.") if '-C-target' in args: raise TaskError("Define a [jvm-platform] with the desired 'target' level instead of " "supplying one via 'args'.") source_level = settings.source_level target_level = settings.target_level if source_level: args.extend(['-C-source', '-C{0}'.format(source_level)]) if target_level: args.extend(['-C-target', '-C{0}'.format(target_level)]) args.append('-C-Tdependencyfile') args.append('-C{}'.format(self._depfile)) jvm_options = list(self._jvm_options) args.extend(sources) result = self.runjava(classpath=jmake_classpath, main=JmakeCompile._JMAKE_MAIN, jvm_options=jvm_options, args=args, workunit_name='jmake', workunit_labels=[WorkUnitLabel.COMPILER]) if result: default_message = 'Unexpected error - JMake returned {}'.format(result) raise TaskError(_JMAKE_ERROR_CODES.get(result, default_message))
def instrument(self, targets, tests, compute_junit_classpath): junit_classpath = compute_junit_classpath() cobertura_cp = self._task_exports.tool_classpath('cobertura-instrument') aux_classpath = os.pathsep.join(relativize_paths(junit_classpath, get_buildroot())) safe_delete(self._coverage_datafile) classes_by_target = self._context.products.get_data('classes_by_target') for target in targets: if self.is_coverage_target(target): classes_by_rootdir = classes_by_target.get(target) if classes_by_rootdir: for root, products in classes_by_rootdir.rel_paths(): self._rootdirs[root].update(products) # Cobertura uses regular expressions for filters, and even then there are still problems # with filtering. It turned out to be easier to just select which classes to instrument # by filtering them here. # TODO(ji): Investigate again how we can use cobertura's own filtering mechanisms. if self._coverage_filters: for basedir, classes in self._rootdirs.items(): updated_classes = [] for cls in classes: does_match = False for positive_filter in self._include_filters: if fnmatch.fnmatchcase(_classfile_to_classname(cls), positive_filter): does_match = True for negative_filter in self._exclude_filters: if fnmatch.fnmatchcase(_classfile_to_classname(cls), negative_filter): does_match = False if does_match: updated_classes.append(cls) self._rootdirs[basedir] = updated_classes for basedir, classes in self._rootdirs.items(): if not classes: continue # No point in running instrumentation if there is nothing to instrument! self._nothing_to_instrument = False args = [ '--basedir', basedir, '--datafile', self._coverage_datafile, '--auxClasspath', aux_classpath, ] with temporary_file_path(cleanup=False) as instrumented_classes_file: with file(instrumented_classes_file, 'wb') as icf: icf.write(('\n'.join(classes) + '\n').encode('utf-8')) self._context.log.debug('instrumented classes in {0}'.format(instrumented_classes_file)) args.append('--listOfFilesToInstrument') args.append(instrumented_classes_file) main = 'net.sourceforge.cobertura.instrument.InstrumentMain' execute_java = self.preferred_jvm_distribution_for_targets(targets).execute_java result = execute_java(classpath=cobertura_cp, main=main, jvm_options=self._coverage_jvm_options, args=args, workunit_factory=self._context.new_workunit, workunit_name='cobertura-instrument') if result != 0: raise TaskError("java {0} ... exited non-zero ({1})" " 'failed to instrument'".format(main, result))
def _create_command(self, classpath, main, jvm_options, args, cwd=None): cmd = [self._distribution.java] cmd.extend(jvm_options) if cwd: classpath = relativize_paths(classpath, cwd) cmd.extend(['-cp', os.pathsep.join(classpath), main]) cmd.extend(args) return cmd
def instrument(self, targets, tests, compute_junit_classpath): junit_classpath = compute_junit_classpath() cobertura_cp = self._task_exports.tool_classpath('cobertura-instrument') aux_classpath = os.pathsep.join(relativize_paths(junit_classpath, get_buildroot())) safe_delete(self._coverage_datafile) classes_by_target = self._context.products.get_data('classes_by_target') for target in targets: if self.is_coverage_target(target): classes_by_rootdir = classes_by_target.get(target) if classes_by_rootdir: for root, products in classes_by_rootdir.rel_paths(): self._rootdirs[root].update(products) # Cobertura uses regular expressions for filters, and even then there are still problems # with filtering. It turned out to be easier to just select which classes to instrument # by filtering them here. # TODO(ji): Investigate again how we can use cobertura's own filtering mechanisms. if self._coverage_filters: for basedir, classes in self._rootdirs.items(): updated_classes = [] for cls in classes: does_match = False for positive_filter in self._include_filters: if fnmatch.fnmatchcase(_classfile_to_classname(cls), positive_filter): does_match = True for negative_filter in self._exclude_filters: if fnmatch.fnmatchcase(_classfile_to_classname(cls), negative_filter): does_match = False if does_match: updated_classes.append(cls) self._rootdirs[basedir] = updated_classes for basedir, classes in self._rootdirs.items(): if not classes: continue # No point in running instrumentation if there is nothing to instrument! self._nothing_to_instrument = False args = [ '--basedir', basedir, '--datafile', self._coverage_datafile, '--auxClasspath', aux_classpath, ] with temporary_file_path(cleanup=False) as instrumented_classes_file: with file(instrumented_classes_file, 'wb') as icf: icf.write(('\n'.join(classes) + '\n').encode('utf-8')) self._context.log.debug('instrumented classes in {0}'.format(instrumented_classes_file)) args.append('--listOfFilesToInstrument') args.append(instrumented_classes_file) main = 'net.sourceforge.cobertura.instrument.InstrumentMain' result = execute_java(classpath=cobertura_cp, main=main, jvm_options=self._coverage_jvm_options, args=args, workunit_factory=self._context.new_workunit, workunit_name='cobertura-instrument') if result != 0: raise TaskError("java {0} ... exited non-zero ({1})" " 'failed to instrument'".format(main, result))
def compile(self, args, classpath, sources, classes_output_dir, upstream_analysis, analysis_file, log_file, settings): # We add compiler_classpath to ensure the scala-library jar is on the classpath. # TODO: This also adds the compiler jar to the classpath, which compiled code shouldn't # usually need. Be more selective? # TODO(John Sirois): Do we need to do this at all? If adding scala-library to the classpath is # only intended to allow target authors to omit a scala-library dependency, then ScalaLibrary # already overrides traversable_dependency_specs to achieve the same end; arguably at a more # appropriate level and certainly at a more appropriate granularity. relativized_classpath = relativize_paths(self.compiler_classpath() + classpath, get_buildroot()) zinc_args = [] zinc_args.extend([ '-log-level', self.get_options().level, '-analysis-cache', analysis_file, '-classpath', ':'.join(relativized_classpath), '-d', classes_output_dir ]) if not self.get_options().colors: zinc_args.append('-no-color') if not self.get_options().name_hashing: zinc_args.append('-no-name-hashing') if log_file: zinc_args.extend(['-capture-log', log_file]) zinc_args.extend(['-compiler-interface', self.tool_jar('compiler-interface')]) zinc_args.extend(['-sbt-interface', self.tool_jar('sbt-interface')]) zinc_args.extend(['-scala-path', ':'.join(self.compiler_classpath())]) zinc_args += self.plugin_args() if upstream_analysis: zinc_args.extend(['-analysis-map', ','.join('{}:{}'.format(*kv) for kv in upstream_analysis.items())]) zinc_args += args zinc_args.extend([ '-C-source', '-C{}'.format(settings.source_level), '-C-target', '-C{}'.format(settings.target_level), ]) zinc_args.extend(settings.args) jvm_options = list(self._jvm_options) zinc_args.extend(sources) self.log_zinc_file(analysis_file) if self.runjava(classpath=self.zinc_classpath(), main=self._ZINC_MAIN, jvm_options=jvm_options, args=zinc_args, workunit_name='zinc', workunit_labels=[WorkUnitLabel.COMPILER]): raise TaskError('Zinc compile failed.')
def compile(self, args, classpath, sources, classes_output_dir, upstream_analysis, analysis_file, log_file): # We add compiler_classpath to ensure the scala-library jar is on the classpath. # TODO: This also adds the compiler jar to the classpath, which compiled code shouldn't # usually need. Be more selective? # TODO(John Sirois): Do we need to do this at all? If adding scala-library to the classpath is # only intended to allow target authors to omit a scala-library dependency, then ScalaLibrary # already overrides traversable_dependency_specs to achieve the same end; arguably at a more # appropriate level and certainly at a more appropriate granularity. relativized_classpath = relativize_paths(self.compiler_classpath() + classpath, get_buildroot()) zinc_args = [] zinc_args.extend( [ "-log-level", self.get_options().level, "-analysis-cache", analysis_file, "-classpath", ":".join(relativized_classpath), "-d", classes_output_dir, ] ) if not self.get_options().colors: zinc_args.append("-no-color") if not self.get_options().name_hashing: zinc_args.append("-no-name-hashing") if log_file: zinc_args.extend(["-capture-log", log_file]) zinc_args.extend(["-compiler-interface", self.tool_jar("compiler-interface")]) zinc_args.extend(["-sbt-interface", self.tool_jar("sbt-interface")]) zinc_args.extend(["-scala-path", ":".join(self.compiler_classpath())]) zinc_args += self.plugin_args() if upstream_analysis: zinc_args.extend(["-analysis-map", ",".join("{}:{}".format(*kv) for kv in upstream_analysis.items())]) zinc_args += args zinc_args.extend(sources) self.log_zinc_file(analysis_file) if self.runjava( classpath=self.zinc_classpath(), main=self._ZINC_MAIN, jvm_options=self._jvm_options, args=zinc_args, workunit_name="zinc", workunit_labels=[WorkUnit.COMPILER], ): raise TaskError("Zinc compile failed.")
def instrument(self, targets, tests, compute_junit_classpath): instrumentation_classpath = self.initialize_instrument_classpath( targets) junit_classpath = compute_junit_classpath() cobertura_cp = self._task_exports.tool_classpath( 'cobertura-instrument') aux_classpath = os.pathsep.join( relativize_paths(junit_classpath, get_buildroot())) safe_delete(self._coverage_datafile) files_to_instrument = [] for target in targets: if self.is_coverage_target(target): paths = instrumentation_classpath.get_for_target(target, False) for (name, path) in paths: files_to_instrument.append(path) if len(files_to_instrument) > 0: self._nothing_to_instrument = False args = [ '--datafile', self._coverage_datafile, '--auxClasspath', aux_classpath, ] # apply class incl/excl filters if len(self._include_classes) > 0: for pattern in self._include_classes: args += ["--includeClasses", pattern] else: args += ["--includeClasses", '.*'] # default to instrumenting all classes for pattern in self._exclude_classes: args += ["--excludeClasses", pattern] args += files_to_instrument main = 'net.sourceforge.cobertura.instrument.InstrumentMain' self._context.log.debug( "executing cobertura instrumentation with the following args: {}" .format(args)) execute_java = self.preferred_jvm_distribution_for_targets( targets).execute_java result = execute_java( classpath=cobertura_cp, main=main, jvm_options=self._coverage_jvm_options, args=args, workunit_factory=self._context.new_workunit, workunit_name='cobertura-instrument') if result != 0: raise TaskError("java {0} ... exited non-zero ({1})" " 'failed to instrument'".format( main, result))
def compile(self, args, classpath, sources, classes_output_dir, upstream_analysis, analysis_file, log_file): # We add compiler_classpath to ensure the scala-library jar is on the classpath. # TODO: This also adds the compiler jar to the classpath, which compiled code shouldn't # usually need. Be more selective? # TODO(John Sirois): Do we need to do this at all? If adding scala-library to the classpath is # only intended to allow target authors to omit a scala-library dependency, then ScalaLibrary # already overrides traversable_dependency_specs to achieve the same end; arguably at a more # appropriate level and certainly at a more appropriate granularity. relativized_classpath = relativize_paths( self.compiler_classpath() + classpath, get_buildroot()) zinc_args = [] zinc_args.extend([ '-log-level', self.get_options().level, '-analysis-cache', analysis_file, '-classpath', ':'.join(relativized_classpath), '-d', classes_output_dir ]) if not self.get_options().colors: zinc_args.append('-no-color') if not self.get_options().name_hashing: zinc_args.append('-no-name-hashing') if log_file: zinc_args.extend(['-capture-log', log_file]) zinc_args.extend( ['-compiler-interface', self.tool_jar('compiler-interface')]) zinc_args.extend(['-sbt-interface', self.tool_jar('sbt-interface')]) zinc_args.extend(['-scala-path', ':'.join(self.compiler_classpath())]) zinc_args += self.plugin_args() if upstream_analysis: zinc_args.extend([ '-analysis-map', ','.join('{}:{}'.format(*kv) for kv in upstream_analysis.items()) ]) zinc_args += args zinc_args.extend(sources) self.log_zinc_file(analysis_file) if self.runjava(classpath=self.zinc_classpath(), main=self._ZINC_MAIN, jvm_options=self._jvm_options, args=zinc_args, workunit_name='zinc', workunit_labels=[WorkUnit.COMPILER]): raise TaskError('Zinc compile failed.')
def compile(self, args, classpath, sources, classes_output_dir, upstream_analysis, analysis_file): relative_classpath = relativize_paths(classpath, self._buildroot) jmake_classpath = self.tool_classpath('jmake') args = [ '-classpath', ':'.join(relative_classpath), '-d', classes_output_dir, '-pdb', analysis_file, '-pdb-text-format', ] # TODO: This file should always exist for modern jmake installs; this check should # be removed via a Task-level identity bump after: # https://github.com/pantsbuild/pants/issues/1351 if os.path.exists(self._depfile): args.extend(['-depfile', self._depfile]) compiler_classpath = self.tool_classpath('java-compiler') args.extend([ '-jcpath', ':'.join(compiler_classpath), '-jcmainclass', 'com.twitter.common.tools.Compiler', ]) if self.get_options().source: args.extend(['-C-source', '-C{0}'.format(self.get_options().source)]) if self.get_options().target: args.extend(['-C-target', '-C{0}'.format(self.get_options().target)]) if '-C-source' in self._args: raise TaskError("Set the source Java version with the 'source' option, not in 'args'.") if '-C-target' in self._args: raise TaskError("Set the target JVM version with the 'target' option, not in 'args'.") if not self.get_options().colors: filtered_args = filter(lambda arg: not arg == '-C-Tcolor', self._args) else: filtered_args = self._args args.extend(filtered_args) args.append('-C-Tdependencyfile') args.append('-C{}'.format(self._depfile)) args.extend(sources) result = self.runjava(classpath=jmake_classpath, main=JavaCompile._JMAKE_MAIN, jvm_options=self._jvm_options, args=args, workunit_name='jmake', workunit_labels=[WorkUnit.COMPILER]) if result: default_message = 'Unexpected error - JMake returned {}'.format(result) raise TaskError(_JMAKE_ERROR_CODES.get(result, default_message))
def compile(self, args, classpath, sources, classes_output_dir, analysis_file): relative_classpath = relativize_paths(classpath, self._buildroot) jmake_classpath = self.tool_classpath('jmake') args = [ '-classpath', ':'.join(relative_classpath + [self._classes_dir]), '-d', self._classes_dir, '-pdb', analysis_file, '-pdb-text-format', ] compiler_classpath = self.tool_classpath('java-compiler') args.extend([ '-jcpath', ':'.join(compiler_classpath), '-jcmainclass', 'com.twitter.common.tools.Compiler', ]) if self.get_options().source: args.extend( ['-C-source', '-C{0}'.format(self.get_options().source)]) if self.get_options().target: args.extend( ['-C-target', '-C{0}'.format(self.get_options().target)]) if '-C-source' in self._args: raise TaskError( "Set the source Java version with the 'source' option, not in 'args'." ) if '-C-target' in self._args: raise TaskError( "Set the target JVM version with the 'target' option, not in 'args'." ) args.extend(self._args) args.extend(sources) result = self.runjava(classpath=jmake_classpath, main=JavaCompile._JMAKE_MAIN, jvm_options=self._jvm_options, args=args, workunit_name='jmake', workunit_labels=[WorkUnit.COMPILER]) if result: default_message = 'Unexpected error - JMake returned %d' % result raise TaskError(_JMAKE_ERROR_CODES.get(result, default_message))
def _get_compile_args(opts, classpath, sources, output_dir, analysis_file, upstream_analysis_files): args = list(opts) # Make a copy if upstream_analysis_files: args.extend( ['-analysis-map', ','.join(['%s:%s' % kv for kv in upstream_analysis_files.items()])]) relative_classpath = relativize_paths(classpath, get_buildroot()) args.extend([ '-analysis-cache', analysis_file, '-classpath', ':'.join(relative_classpath), '-d', output_dir ]) args.extend(sources) return args
def _get_compile_args(opts, classpath, sources, output_dir, analysis_file, upstream_analysis_files): args = list(opts) # Make a copy if upstream_analysis_files: args.extend([ '-analysis-map', ','.join( ['%s:%s' % kv for kv in upstream_analysis_files.items()]) ]) relative_classpath = relativize_paths(classpath, get_buildroot()) args.extend([ '-analysis-cache', analysis_file, '-classpath', ':'.join(relative_classpath), '-d', output_dir ]) args.extend(sources) return args
def compile(self, args, classpath, sources, classes_output_dir, analysis_file): relative_classpath = relativize_paths(classpath, self._buildroot) jmake_classpath = self.tool_classpath('jmake') args = [ '-classpath', ':'.join(relative_classpath + [self._classes_dir]), '-d', self._classes_dir, '-pdb', analysis_file, '-pdb-text-format', '-depfile', self._depfile ] compiler_classpath = self.tool_classpath('java-compiler') args.extend([ '-jcpath', ':'.join(compiler_classpath), '-jcmainclass', 'com.twitter.common.tools.Compiler', ]) if self.get_options().source: args.extend(['-C-source', '-C{0}'.format(self.get_options().source)]) if self.get_options().target: args.extend(['-C-target', '-C{0}'.format(self.get_options().target)]) if '-C-source' in self._args: raise TaskError("Set the source Java version with the 'source' option, not in 'args'.") if '-C-target' in self._args: raise TaskError("Set the target JVM version with the 'target' option, not in 'args'.") if not self.get_options().colors: filtered_args = filter(lambda arg: not arg == '-C-Tcolor', self._args) else: filtered_args = self._args args.extend(filtered_args) args.append('-C-Tdependencyfile') args.append('-C{}'.format(self._depfile)) args.extend(sources) result = self.runjava(classpath=jmake_classpath, main=JavaCompile._JMAKE_MAIN, jvm_options=self._jvm_options, args=args, workunit_name='jmake', workunit_labels=[WorkUnit.COMPILER]) if result: default_message = 'Unexpected error - JMake returned %d' % result raise TaskError(_JMAKE_ERROR_CODES.get(result, default_message))
def instrument(self, targets, tests, compute_junit_classpath, execute_java_for_targets): instrumentation_classpath = self.initialize_instrument_classpath(targets) junit_classpath = compute_junit_classpath() cobertura_cp = self._settings.tool_classpath('cobertura-instrument') aux_classpath = os.pathsep.join(relativize_paths(junit_classpath, get_buildroot())) safe_delete(self._coverage_datafile) files_to_instrument = [] for target in targets: if self.is_coverage_target(target): paths = instrumentation_classpath.get_for_target(target, False) for (name, path) in paths: files_to_instrument.append(path) if len(files_to_instrument) > 0: self._nothing_to_instrument = False args = [ '--datafile', self._coverage_datafile, '--auxClasspath', aux_classpath, ] # apply class incl/excl filters if len(self._include_classes) > 0: for pattern in self._include_classes: args += ["--includeClasses", pattern] else: args += ["--includeClasses", '.*'] # default to instrumenting all classes for pattern in self._exclude_classes: args += ["--excludeClasses", pattern] args += files_to_instrument main = 'net.sourceforge.cobertura.instrument.InstrumentMain' self._context.log.debug( "executing cobertura instrumentation with the following args: {}".format(args)) result = execute_java_for_targets(targets, classpath=cobertura_cp, main=main, jvm_options=self._coverage_jvm_options, args=args, workunit_factory=self._context.new_workunit, workunit_name='cobertura-instrument') if result != 0: raise TaskError("java {0} ... exited non-zero ({1})" " 'failed to instrument'".format(main, result))
def instrument(self, output_dir): for datafile in self._iter_datafiles(output_dir): os.unlink(datafile) self._canonical_datafile = os.path.join( output_dir, '{}.canonical'.format(self._DATAFILE_NAME)) # It's conceivable we'll be executing a test that has no source file dependencies; ie: we'll # never generate a canonical coverage datafile below. Create an empty one here to allow the # test run to proceeed normally. touch(self._canonical_datafile) # Setup an instrumentation classpath based on the existing runtime classpath. runtime_classpath = self._context.products.get_data( 'runtime_classpath') instrumentation_classpath = self._context.products.safe_create_data( 'instrument_classpath', runtime_classpath.copy) self.initialize_instrument_classpath(output_dir, self._settings, self._targets, instrumentation_classpath) cobertura_cp = self._settings.tool_classpath('cobertura-instrument') files_to_instrument = [] for target in self._targets: if Cobertura.is_coverage_target(target): paths = instrumentation_classpath.get_for_target(target) for (name, path) in paths: files_to_instrument.append(path) if len(files_to_instrument) > 0: unique_files = list(set(files_to_instrument)) relativize_paths(unique_files, self._settings.workdir) args = [ '--basedir', self._settings.workdir, '--datafile', self._canonical_datafile, ] if self._include_user_classpath: closure = BuildGraph.closure( self._targets, bfs=True, include_scopes=Scopes.JVM_TEST_SCOPES, respect_intransitive=True) aux_classpath = safe_classpath(ClasspathUtil.classpath( closure, runtime_classpath), synthetic_jar_dir=None) args.append('--auxClasspath') args.extend(aux_classpath) # apply class incl/excl filters if len(self._include_classes) > 0: for pattern in self._include_classes: args += ["--includeClasses", pattern] else: args += ["--includeClasses", '.*'] # default to instrumenting all classes for pattern in self._exclude_classes: args += ["--excludeClasses", pattern] with temporary_file(binary_mode=False) as tmp_file: tmp_file.write("\n".join(unique_files)) tmp_file.flush() args += ["--listOfFilesToInstrument", tmp_file.name] main = 'net.sourceforge.cobertura.instrument.InstrumentMain' self._settings.log.debug( "executing cobertura instrumentation with the following args: {}" .format(args)) result = self._execute_java( classpath=cobertura_cp, main=main, jvm_options=self._settings.coverage_jvm_options, args=args, workunit_factory=self._context.new_workunit, workunit_name='cobertura-instrument') if result != 0: raise TaskError("java {0} ... exited non-zero ({1})" " 'failed to instrument'".format( main, result))
def _create_command(self, classpath, main, jvm_options, args, cwd=None): cwd = cwd or self._buildroot relative_classpath = relativize_paths(classpath, cwd) return super(SubprocessExecutor, self)._create_command(relative_classpath, main, jvm_options, args, cwd=cwd)
def compile(self, args, classpath, sources, classes_output_dir, upstream_analysis, analysis_file, log_file, settings): relative_classpath = relativize_paths(classpath, self._buildroot) jmake_classpath = self.tool_classpath('jmake') args = [ '-classpath', ':'.join(relative_classpath), '-d', classes_output_dir, '-pdb', analysis_file, '-pdb-text-format', ] # TODO: This file should always exist for modern jmake installs; this check should # be removed via a Task-level identity bump after: # https://github.com/pantsbuild/pants/issues/1351 if os.path.exists(self._depfile): args.extend(['-depfile', self._depfile]) compiler_classpath = self.tool_classpath('java-compiler') args.extend([ '-jcpath', ':'.join(compiler_classpath), '-jcmainclass', 'org.pantsbuild.tools.compiler.Compiler', ]) if not self.get_options().colors: filtered_args = filter(lambda arg: not arg == '-C-Tcolor', self._args) else: filtered_args = self._args args.extend(filtered_args) args.extend(settings.args) if '-C-source' in args: raise TaskError("Set the source Java version with the 'source' or with the jvm platform, not " "in 'args'.") if '-C-target' in args: raise TaskError("Set the target JVM version with the 'target' option or with the jvm " "platform, not in 'args'.") if self.get_options().source or self.get_options().target: self.context.log.warn('--compile-java-source and --compile-java-target trample and override ' 'target jvm platform settings, and probably should not be used except ' 'for testing.') source_level = self.get_options().source or settings.source_level target_level = self.get_options().target or settings.target_level if source_level: args.extend(['-C-source', '-C{0}'.format(source_level)]) if target_level: args.extend(['-C-target', '-C{0}'.format(target_level)]) args.append('-C-Tdependencyfile') args.append('-C{}'.format(self._depfile)) jvm_options = list(self._jvm_options) args.extend(sources) result = self.runjava(classpath=jmake_classpath, main=JmakeCompile._JMAKE_MAIN, jvm_options=jvm_options, args=args, workunit_name='jmake', workunit_labels=[WorkUnitLabel.COMPILER]) if result: default_message = 'Unexpected error - JMake returned {}'.format(result) raise TaskError(_JMAKE_ERROR_CODES.get(result, default_message))
def instrument(self, output_dir): for datafile in self._iter_datafiles(output_dir): os.unlink(datafile) self._canonical_datafile = os.path.join(output_dir, '{}.canonical'.format(self._DATAFILE_NAME)) # It's conceivable we'll be executing a test that has no source file dependencies; ie: we'll # never generate a canonical coverage datafile below. Create an empty one here to allow the # test run to proceeed normally. touch(self._canonical_datafile) # Setup an instrumentation classpath based on the existing runtime classpath. runtime_classpath = self._context.products.get_data('runtime_classpath') instrumentation_classpath = self._context.products.safe_create_data('instrument_classpath', runtime_classpath.copy) self.initialize_instrument_classpath(output_dir, self._settings, self._targets, instrumentation_classpath) cobertura_cp = self._settings.tool_classpath('cobertura-instrument') files_to_instrument = [] for target in self._targets: if Cobertura.is_coverage_target(target): paths = instrumentation_classpath.get_for_target(target) for (name, path) in paths: files_to_instrument.append(path) if len(files_to_instrument) > 0: unique_files = list(set(files_to_instrument)) relativize_paths(unique_files, self._settings.workdir) args = [ '--basedir', self._settings.workdir, '--datafile', self._canonical_datafile, ] if self._include_user_classpath: closure = BuildGraph.closure(self._targets, bfs=True, include_scopes=Scopes.JVM_TEST_SCOPES, respect_intransitive=True) aux_classpath = safe_classpath( ClasspathUtil.classpath(closure, runtime_classpath), synthetic_jar_dir=None) args.append('--auxClasspath') args.extend(aux_classpath) # apply class incl/excl filters if len(self._include_classes) > 0: for pattern in self._include_classes: args += ["--includeClasses", pattern] else: args += ["--includeClasses", '.*'] # default to instrumenting all classes for pattern in self._exclude_classes: args += ["--excludeClasses", pattern] with temporary_file() as tmp_file: tmp_file.write("\n".join(unique_files)) tmp_file.flush() args += ["--listOfFilesToInstrument", tmp_file.name] main = 'net.sourceforge.cobertura.instrument.InstrumentMain' self._settings.log.debug( "executing cobertura instrumentation with the following args: {}".format(args)) result = self._execute_java(classpath=cobertura_cp, main=main, jvm_options=self._settings.coverage_jvm_options, args=args, workunit_factory=self._context.new_workunit, workunit_name='cobertura-instrument') if result != 0: raise TaskError("java {0} ... exited non-zero ({1})" " 'failed to instrument'".format(main, result))
def compile(self, args, classpath, sources, classes_output_dir, upstream_analysis, analysis_file, log_file, settings): relative_classpath = relativize_paths(classpath, self._buildroot) jmake_classpath = self.tool_classpath('jmake') args = [ '-classpath', ':'.join(relative_classpath), '-d', classes_output_dir, '-pdb', analysis_file, '-pdb-text-format', ] # TODO: This file should always exist for modern jmake installs; this check should # be removed via a Task-level identity bump after: # https://github.com/pantsbuild/pants/issues/1351 if os.path.exists(self._depfile): args.extend(['-depfile', self._depfile]) compiler_classpath = self.tool_classpath('java-compiler') args.extend([ '-jcpath', ':'.join(compiler_classpath), '-jcmainclass', 'org.pantsbuild.tools.compiler.Compiler', ]) if not self.get_options().colors: filtered_args = filter(lambda arg: not arg == '-C-Tcolor', self._args) else: filtered_args = self._args args.extend(filtered_args) args.extend(settings.args) if '-C-source' in args: raise TaskError( "Set the source Java version with the 'source' or with the jvm platform, not " "in 'args'.") if '-C-target' in args: raise TaskError( "Set the target JVM version with the 'target' option or with the jvm " "platform, not in 'args'.") if self.get_options().source or self.get_options().target: self.context.log.warn( '--compile-java-source and --compile-java-target trample and override ' 'target jvm platform settings, and probably should not be used except ' 'for testing.') source_level = self.get_options().source or settings.source_level target_level = self.get_options().target or settings.target_level if source_level: args.extend(['-C-source', '-C{0}'.format(source_level)]) if target_level: args.extend(['-C-target', '-C{0}'.format(target_level)]) args.append('-C-Tdependencyfile') args.append('-C{}'.format(self._depfile)) jvm_options = list(self._jvm_options) args.extend(sources) result = self.runjava(classpath=jmake_classpath, main=JmakeCompile._JMAKE_MAIN, jvm_options=jvm_options, args=args, workunit_name='jmake', workunit_labels=[WorkUnitLabel.COMPILER]) if result: default_message = 'Unexpected error - JMake returned {}'.format( result) raise TaskError(_JMAKE_ERROR_CODES.get(result, default_message))
def _create_command(self, classpath, main, jvm_options, args): relative_classpath = relativize_paths(classpath, self._buildroot) log.debug('The length of the the classpath is: %s' % len(relative_classpath)) return super(SubprocessExecutor, self)._create_command(relative_classpath, main, jvm_options, args)
def relativize_classpath(classpath): return relativize_paths(classpath, get_buildroot())
def _create_command(self, classpath, main, jvm_options, args): relative_classpath = relativize_paths(classpath, self._buildroot) return super(SubprocessExecutor, self)._create_command(relative_classpath, main, jvm_options, args)