def classpath(self, targets, classpath_prefix=None, classpath_product=None): """Builds a transitive classpath for the given targets. Optionally includes a classpath prefix or building from a non-default classpath product. :param targets: the targets for which to build the transitive classpath. :param classpath_prefix: optional additional entries to prepend to the classpath. :param classpath_product: an optional ClasspathProduct from which to build the classpath. if not specified, the runtime_classpath will be used. :return: a list of classpath strings. """ classpath = list(classpath_prefix) if classpath_prefix else [] classpath_product = classpath_product or self.context.products.get_data( 'runtime_classpath') closure = BuildGraph.closure(targets, bfs=True) classpath_for_targets = ClasspathUtil.classpath( closure, classpath_product, self.confs) classpath.extend(classpath_for_targets) return classpath
def classpath(self, targets, classpath_prefix=None, classpath_product=None, exclude_scopes=None, include_scopes=None): """Builds a transitive classpath for the given targets. Optionally includes a classpath prefix or building from a non-default classpath product. :param targets: the targets for which to build the transitive classpath. :param classpath_prefix: optional additional entries to prepend to the classpath. :param classpath_product: an optional ClasspathProduct from which to build the classpath. if not specified, the runtime_classpath will be used. :param :class:`pants.build_graph.target_scopes.Scope` exclude_scopes: Exclude targets which have at least one of these scopes on the classpath. :param :class:`pants.build_graph.target_scopes.Scope` include_scopes: Only include targets which have at least one of these scopes on the classpath. Defaults to Scopes.JVM_RUNTIME_SCOPES. :return: a list of classpath strings. """ include_scopes = Scopes.JVM_RUNTIME_SCOPES if include_scopes is None else include_scopes classpath_product = classpath_product or self.context.products.get_data('runtime_classpath') closure = BuildGraph.closure(targets, bfs=True, include_scopes=include_scopes, exclude_scopes=exclude_scopes, respect_intransitive=True) classpath_for_targets = ClasspathUtil.classpath(closure, classpath_product, self.confs) classpath = list(classpath_prefix or ()) classpath.extend(classpath_for_targets) return classpath
def _compute_classpath(runtime_classpath, targets): closure = BuildGraph.closure( targets, bfs=True, include_scopes=Scopes.JVM_RUNTIME_SCOPES, respect_intransitive=True ) classpath_for_targets = ClasspathUtil.classpath(closure, runtime_classpath) return classpath_for_targets
def execute(self): basedir = os.path.join(self.get_options().pants_distdir, self._output_folder) runtime_classpath = self.context.products.get_data('runtime_classpath') targets = self.context.targets() if self.get_options().manifest_jar_only: classpath = ClasspathUtil.classpath(targets, runtime_classpath) # Safely create e.g. dist/export-classpath/manifest.jar safe_classpath(classpath, basedir, "manifest.jar") else: ClasspathProducts.create_canonical_classpath( runtime_classpath, targets, basedir, save_classpath_file=True)
def _write_to_artifact_cache(self, vts, compile_context, get_update_artifact_cache_work): assert len(vts.targets) == 1 assert vts.targets[0] == compile_context.target # Noop if the target is uncacheable. if (compile_context.target.has_label('no_cache')): return vt = vts.versioned_targets[0] # Set up args to relativize analysis in the background. portable_analysis_file = self._portable_analysis_for_target( self._analysis_dir, compile_context.target) relativize_args_tuple = (compile_context.analysis_file, portable_analysis_file) # Collect the artifacts for this target. artifacts = [] # Intransitive classpath entries. target_classpath = ClasspathUtil.classpath( (compile_context.target,), self.context.products.get_data('runtime_classpath'), transitive=False) for entry in target_classpath: if ClasspathUtil.is_jar(entry): artifacts.append(entry) elif ClasspathUtil.is_dir(entry): for rel_file in ClasspathUtil.classpath_entries_contents([entry]): artifacts.append(os.path.join(entry, rel_file)) else: # non-jar and non-directory classpath entries should be ignored pass # Log file. log_file = self._capture_log_file(compile_context.target) if log_file and os.path.exists(log_file): artifacts.append(log_file) # Jar. artifacts.append(compile_context.jar_file) # Get the 'work' that will publish these artifacts to the cache. # NB: the portable analysis_file won't exist until we finish. vts_artifactfiles_pair = (vt, artifacts + [portable_analysis_file]) update_artifact_cache_work = get_update_artifact_cache_work([vts_artifactfiles_pair]) # And execute it. if update_artifact_cache_work: work_chain = [ Work(self._analysis_tools.relativize, [relativize_args_tuple], 'relativize'), update_artifact_cache_work ] self.context.submit_background_work_chain(work_chain, parent_workunit_name='cache')
def execute(self): basedir = os.path.join(self.get_options().pants_distdir, self._output_folder) runtime_classpath = self.context.products.get_data('runtime_classpath') targets = self.context.targets() if self.get_options().manifest_jar_only: classpath = ClasspathUtil.classpath(targets, runtime_classpath) # Safely create e.g. dist/export-classpath/manifest.jar safe_classpath(classpath, basedir, "manifest.jar") else: ClasspathProducts.create_canonical_classpath(runtime_classpath, targets, basedir, save_classpath_file=True)
def execute(self): if self.goal not in JvmPrepCommand.goals(): raise AssertionError( 'Got goal "{}". Expected goal to be one of {}'.format( self.goal, JvmPrepCommand.goals())) targets = self.context.targets(postorder=True, predicate=self.runnable_prep_cmd) compile_classpath = self.context.products.get_data('compile_classpath') classpath_products = self.context.products.get_data( 'runtime_classpath', compile_classpath.copy) with self.context.new_workunit(name='jvm_prep_command', labels=[WorkUnitLabel.PREP ]) as workunit: for target in targets: distribution = JvmPlatform.preferred_jvm_distribution( [target.platform]) executor = SubprocessExecutor(distribution) mainclass = target.payload.get_field_value('mainclass') args = target.payload.get_field_value('args', []) target_jvm_options = target.payload.get_field_value( 'jvm_options', []) cp = list( ClasspathUtil.classpath(target.closure(), classpath_products)) if not cp: raise TaskError( 'target {} has no classpath. (Add dependencies= parameter?' .format(target.address.spec)) self.context.log.info('Running prep command for {}'.format( target.address.spec)) returncode = distribution.execute_java( executor=executor, classpath=cp, main=mainclass, jvm_options=target_jvm_options, args=args, workunit_factory=self.context.new_workunit, workunit_name='run', workunit_labels=[WorkUnitLabel.PREP], ) workunit.set_outcome( WorkUnit.FAILURE if returncode else WorkUnit.SUCCESS) if returncode: raise TaskError( 'RunJvmPrepCommand failed to run {}'.format(mainclass))
def classpath(self, targets, classpath_prefix=None, classpath_product=None): """Builds a classpath for the current task and given targets, optionally including a classpath prefix or building from a non-default classpath product. :param targets: the targets for which to build the classpath. :param classpath_prefix: optional additional entries to prepend to the classpath. :param classpath_product: an optional ClasspathProduct from which to build the classpath. if not specified, the runtime_classpath will be used. :return: a list of classpath strings. """ classpath = list(classpath_prefix) if classpath_prefix else [] classpath_product = classpath_product or self.context.products.get_data('runtime_classpath') classpath_for_targets = ClasspathUtil.classpath(targets, classpath_product, self.confs) classpath.extend(classpath_for_targets) return classpath
def gen(): # Compute src -> target. if isinstance(target, JvmTarget): for src in target.sources_relative_to_buildroot(): yield os.path.join(self.buildroot, src) # TODO(Tejal Desai): pantsbuild/pants/65: Remove java_sources attribute for ScalaLibrary if isinstance(target, ScalaLibrary): for java_source in target.java_sources: for src in java_source.sources_relative_to_buildroot(): yield os.path.join(self.buildroot, src) # Compute classfile -> target and jar -> target. files = ClasspathUtil.classpath_contents((target,), self.runtime_classpath) # And jars; for binary deps, zinc doesn't emit precise deps (yet). cp_entries = ClasspathUtil.classpath((target,), self.runtime_classpath) jars = [cpe for cpe in cp_entries if ClasspathUtil.is_jar(cpe)] for coll in [files, jars]: for f in coll: yield f
def targets_by_file(self): """Returns a map from abs path of source, class or jar file to an OrderedSet of targets. The value is usually a singleton, because a source or class file belongs to a single target. However a single jar may be provided (transitively or intransitively) by multiple JarLibrary targets. But if there is a JarLibrary target that depends on a jar directly, then that "canonical" target will be the first one in the list of targets. """ targets_by_file = defaultdict(OrderedSet) runtime_classpath = self.context.products.get_data('runtime_classpath') # Compute src -> target. self.context.log.debug('Mapping sources...') buildroot = get_buildroot() # Look at all targets in-play for this pants run. Does not include synthetic targets, for target in self.context.targets(): if isinstance(target, JvmTarget): for src in target.sources_relative_to_buildroot(): targets_by_file[os.path.join(buildroot, src)].add(target) # TODO(Tejal Desai): pantsbuild/pants/65: Remove java_sources attribute for ScalaLibrary if isinstance(target, ScalaLibrary): for java_source in target.java_sources: for src in java_source.sources_relative_to_buildroot(): targets_by_file[os.path.join(buildroot, src)].add(target) # Compute classfile -> target and jar -> target. self.context.log.debug('Mapping classpath...') for target in self.context.targets(): # Classpath content. files = ClasspathUtil.classpath_contents((target, ), runtime_classpath, transitive=False) # And jars; for binary deps, zinc doesn't emit precise deps (yet). cp_entries = ClasspathUtil.classpath((target, ), runtime_classpath, transitive=False) jars = [cpe for cpe in cp_entries if ClasspathUtil.is_jar(cpe)] for coll in [files, jars]: for f in coll: targets_by_file[f].add(target) return targets_by_file
def gen(): # Compute src -> target. if isinstance(target, JvmTarget): for src in target.sources_relative_to_buildroot(): yield os.path.join(self.buildroot, src) # TODO(Tejal Desai): pantsbuild/pants/65: Remove java_sources attribute for ScalaLibrary if isinstance(target, ScalaLibrary): for java_source in target.java_sources: for src in java_source.sources_relative_to_buildroot(): yield os.path.join(self.buildroot, src) # Compute classfile -> target and jar -> target. files = ClasspathUtil.classpath_contents((target,), self.runtime_classpath) # And jars; for binary deps, zinc doesn't emit precise deps (yet). cp_entries = ClasspathUtil.classpath((target,), self.runtime_classpath) jars = [cpe for cpe in cp_entries if ClasspathUtil.is_jar(cpe)] for coll in [files, jars]: for f in coll: yield f
def classpath(self, targets, classpath_prefix=None, classpath_product=None): """Builds a transitive classpath for the given targets. Optionally includes a classpath prefix or building from a non-default classpath product. :param targets: the targets for which to build the transitive classpath. :param classpath_prefix: optional additional entries to prepend to the classpath. :param classpath_product: an optional ClasspathProduct from which to build the classpath. if not specified, the runtime_classpath will be used. :return: a list of classpath strings. """ classpath = list(classpath_prefix) if classpath_prefix else [] classpath_product = classpath_product or self.context.products.get_data('runtime_classpath') closure = OrderedSet() for target in targets: closure.update(target.closure(bfs=True)) classpath_for_targets = ClasspathUtil.classpath(closure, classpath_product, self.confs) classpath.extend(classpath_for_targets) return classpath
def targets_by_file(self): """Returns a map from abs path of source, class or jar file to an OrderedSet of targets. The value is usually a singleton, because a source or class file belongs to a single target. However a single jar may be provided (transitively or intransitively) by multiple JarLibrary targets. But if there is a JarLibrary target that depends on a jar directly, then that "canonical" target will be the first one in the list of targets. """ targets_by_file = defaultdict(OrderedSet) runtime_classpath = self.context.products.get_data('runtime_classpath') # Compute src -> target. self.context.log.debug('Mapping sources...') buildroot = get_buildroot() # Look at all targets in-play for this pants run. Does not include synthetic targets, for target in self.context.targets(): if isinstance(target, JvmTarget): for src in target.sources_relative_to_buildroot(): targets_by_file[os.path.join(buildroot, src)].add(target) # TODO(Tejal Desai): pantsbuild/pants/65: Remove java_sources attribute for ScalaLibrary if isinstance(target, ScalaLibrary): for java_source in target.java_sources: for src in java_source.sources_relative_to_buildroot(): targets_by_file[os.path.join(buildroot, src)].add(target) # Compute classfile -> target and jar -> target. self.context.log.debug('Mapping classpath...') for target in self.context.targets(): # Classpath content. files = ClasspathUtil.classpath_contents((target,), runtime_classpath, transitive=False) # And jars; for binary deps, zinc doesn't emit precise deps (yet). cp_entries = ClasspathUtil.classpath((target,), runtime_classpath, transitive=False) jars = [cpe for cpe in cp_entries if ClasspathUtil.is_jar(cpe)] for coll in [files, jars]: for f in coll: targets_by_file[f].add(target) return targets_by_file
def execute(self): if self.goal not in JvmPrepCommand.goals(): raise AssertionError('Got goal "{}". Expected goal to be one of {}'.format( self.goal, JvmPrepCommand.goals())) targets = self.context.targets(postorder=True, predicate=self.runnable_prep_cmd) compile_classpath = self.context.products.get_data('compile_classpath') classpath_products = self.context.products.get_data('runtime_classpath', compile_classpath.copy) with self.context.new_workunit(name='jvm_prep_command', labels=[WorkUnitLabel.PREP]) as workunit: for target in targets: distribution = JvmPlatform.preferred_jvm_distribution([target.platform]) executor = SubprocessExecutor(distribution) mainclass = target.payload.get_field_value('mainclass') args = target.payload.get_field_value('args', []) target_jvm_options = target.payload.get_field_value('jvm_options', []) cp = list(ClasspathUtil.classpath(target.closure(), classpath_products)) if not cp: raise TaskError('target {} has no classpath. (Add dependencies= parameter?' .format(target.address.spec)) self.context.log.info('Running prep command for {}'.format(target.address.spec)) returncode = distribution.execute_java( executor=executor, classpath=cp, main=mainclass, jvm_options=target_jvm_options, args=args, workunit_factory=self.context.new_workunit, workunit_name='run', workunit_labels=[WorkUnitLabel.PREP], ) workunit.set_outcome(WorkUnit.FAILURE if returncode else WorkUnit.SUCCESS) if returncode: raise TaskError('RunJvmPrepCommand failed to run {}'.format(mainclass))
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 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))