def test_get_internal_classpath_entries_for_targets(self): b = self.make_target('b', JvmTarget) a = self.make_target('a', JvmTarget, dependencies=[b]) classpath_product = ClasspathProducts(self.pants_workdir) # This artifact classpath entry should be ignored. example_jar_path = self._example_jar_path() self.add_jar_classpath_element_for_path(classpath_product, a, example_jar_path) classpath_product.add_for_target( b, [('default', self.path('b/loose/classes/dir'))]) classpath_product.add_for_target( a, [('default', self.path('a/loose/classes/dir')), ('default', self.path('an/internally/generated.jar'))]) classpath = classpath_product.get_internal_classpath_entries_for_targets( a.closure(bfs=True)) self.assertEqual( [('default', ClasspathEntry(self.path('a/loose/classes/dir'))), ('default', ClasspathEntry(self.path('an/internally/generated.jar'))), ('default', ClasspathEntry(self.path('b/loose/classes/dir')))], classpath)
def test_classpath_by_targets(self): b = self.make_target('b', JvmTarget) a = self.make_target('a', JvmTarget, dependencies=[b], excludes=[Exclude('com.example', 'lib')]) classpath_products = ClasspathProducts(self.pants_workdir) path1 = self._path('jar/path1') path2 = self._path('jar/path2') path3 = os.path.join(self.pants_workdir, 'jar/path3') resolved_jar = ResolvedJar(M2Coordinate(org='com.example', name='lib', rev='1.0'), cache_path='somewhere', pants_path=path3) classpath_products.add_for_target(a, [('default', path1)]) classpath_products.add_for_target(a, [('non-default', path2)]) classpath_products.add_for_target(b, [('default', path2)]) classpath_products.add_jars_for_targets([b], 'default', [resolved_jar]) classpath_products.add_excludes_for_targets([a]) # (a, path2) filtered because of conf # (b, path3) filtered because of excludes self.assertEqual( OrderedDict([(a, [ClasspathEntry(path1)]), (b, [ClasspathEntry(path2)])]), ClasspathUtil.classpath_by_targets(a.closure(bfs=True), classpath_products))
def test_get_product_target_mappings_for_targets_intransitive(self): b = self.make_target('b', JvmTarget, excludes=[Exclude('com.example', 'lib')]) a = self.make_target('a', JvmTarget, dependencies=[b]) classpath_product = ClasspathProducts(self.pants_workdir) example_jar_path = self._example_jar_path() resolved_jar = self.add_jar_classpath_element_for_path( classpath_product, a, example_jar_path) classpath_product.add_for_target( b, [('default', self.path('b/loose/classes/dir'))]) classpath_product.add_for_target( a, [('default', self.path('a/loose/classes/dir')), ('default', self.path('an/internally/generated.jar'))]) classpath_target_tuples = classpath_product.get_product_target_mappings_for_targets( [a]) self.assertEqual([ (('default', ArtifactClasspathEntry(example_jar_path, resolved_jar.coordinate, resolved_jar.cache_path)), a), (('default', ClasspathEntry(self.path('a/loose/classes/dir'))), a), (('default', ClasspathEntry(self.path('an/internally/generated.jar'))), a) ], classpath_target_tuples)
def create_compile_context(self, target, target_workdir): return CompileContext( target, os.path.join(target_workdir, 'z.analysis'), ClasspathEntry(os.path.join(target_workdir, 'classes')), ClasspathEntry(os.path.join(target_workdir, 'z.jar')), os.path.join(target_workdir, 'logs'), os.path.join(target_workdir, 'zinc_args'), self._compute_sources_for_target(target))
def create_compile_context(self, target, target_workdir): return CompileContext(target=target, analysis_file=os.path.join(target_workdir, 'z.analysis'), classes_dir=ClasspathEntry(os.path.join(target_workdir, 'classes')), jar_file=ClasspathEntry(os.path.join(target_workdir, 'z.jar')), log_dir=os.path.join(target_workdir, 'logs'), args_file=os.path.join(target_workdir, 'zinc_args'), post_compile_merge_dir=os.path.join(target_workdir, 'post_compile_merge_dir'), sources=self._compute_sources_for_target(target))
def _default_work_for_vts(self, vts, ctx, input_classpath_product_key, counter, all_compile_contexts, output_classpath_product): progress_message = ctx.target.address.spec # Double check the cache before beginning compilation hit_cache = self.check_cache(vts, counter) if not hit_cache: # Compute the compile classpath for this target. dependency_cp_entries = self._zinc.compile_classpath_entries( input_classpath_product_key, ctx.target, extra_cp_entries=self._extra_compile_time_classpath, ) upstream_analysis = dict( self._upstream_analysis(all_compile_contexts, dependency_cp_entries)) is_incremental = self.should_compile_incrementally(vts, ctx) if not is_incremental: # Purge existing analysis file in non-incremental mode. safe_delete(ctx.analysis_file) # Work around https://github.com/pantsbuild/pants/issues/3670 safe_rmtree(ctx.classes_dir.path) dep_context = DependencyContext.global_instance() tgt, = vts.targets compiler_option_sets = dep_context.defaulted_property( tgt, 'compiler_option_sets') zinc_file_manager = dep_context.defaulted_property( tgt, 'zinc_file_manager') with Timer() as timer: directory_digest = self._compile_vts( vts, ctx, upstream_analysis, dependency_cp_entries, progress_message, tgt.platform, compiler_option_sets, zinc_file_manager, counter) ctx.classes_dir = ClasspathEntry(ctx.classes_dir.path, directory_digest) self._record_target_stats(tgt, len(dependency_cp_entries), len(ctx.sources), timer.elapsed, is_incremental, 'compile') # Write any additional resources for this target to the target workdir. self.write_extra_resources(ctx) # Jar the compiled output. self._create_context_jar(ctx) # Update the products with the latest classes. output_classpath_product.add_for_target( ctx.target, [(conf, self._classpath_for_context(ctx)) for conf in self._confs], ) self.register_extra_products_from_contexts([ctx.target], all_compile_contexts)
def compile_compiler_bridge(self, context): """Compile the compiler bridge to be used by zinc, using our scala bootstrapper. It will compile and cache the jar, and materialize it if not already there. :param context: The context of the task trying to compile the bridge. This is mostly needed to use its scheduler to create digests of the relevant jars. :return: The absolute path to the compiled scala-compiler-bridge jar. """ bridge_jar_name = 'scala-compiler-bridge.jar' bridge_jar = os.path.join(self._compiler_bridge_cache_dir, bridge_jar_name) global_bridge_cache_dir = os.path.join( self._zinc_factory.get_options().pants_bootstrapdir, fast_relpath(self._compiler_bridge_cache_dir, self._workdir())) globally_cached_bridge_jar = os.path.join(global_bridge_cache_dir, bridge_jar_name) # Workaround to avoid recompiling the bridge for every integration test # We check the bootstrapdir (.cache) for the bridge. # If it exists, we make a copy to the buildroot. # # TODO Remove when action caches are implemented. if os.path.exists(globally_cached_bridge_jar): # Cache the bridge jar under buildroot, to allow snapshotting safe_mkdir( self._relative_to_buildroot(self._compiler_bridge_cache_dir)) safe_hardlink_or_copy(globally_cached_bridge_jar, bridge_jar) if not os.path.exists(bridge_jar): res = self._run_bootstrapper(bridge_jar, context) context._scheduler.materialize_directories( (DirectoryToMaterialize(get_buildroot(), res.output_directory_digest), )) # For the workaround above to work, we need to store a copy of the bridge in # the bootstrapdir cache (.cache). safe_mkdir(global_bridge_cache_dir) safe_hardlink_or_copy(bridge_jar, globally_cached_bridge_jar) return ClasspathEntry(bridge_jar, res.output_directory_digest) else: bridge_jar_snapshot = context._scheduler.capture_snapshots( (PathGlobsAndRoot( PathGlobs((self._relative_to_buildroot(bridge_jar), )), text_type(get_buildroot())), ))[0] bridge_jar_digest = bridge_jar_snapshot.directory_digest return ClasspathEntry(bridge_jar, bridge_jar_digest)
def _snapshotted_classpath(self, results_dir): relpath = fast_relpath(results_dir, get_buildroot()) classes_dir_snapshot, = self.context._scheduler.capture_snapshots([ PathGlobsAndRoot( PathGlobs([relpath]), get_buildroot(), Digest.load(relpath), ), ]) return ClasspathEntry(results_dir, classes_dir_snapshot.directory_digest)
def extra_compile_classpath_iter(): for conf in self._confs: for jar in self.extra_compile_time_classpath_elements(): if isinstance(jar, string_types): # Backwards compatibility deprecated_conditional( lambda: True, "1.12.0.dev0", "Extra compile classpath auto-promotion from string to ClasspathEntry", ) jar = ClasspathEntry(jar) yield (conf, jar)
def _compiler_plugins_cp_entries(self): """Any additional global compiletime classpath entries for compiler plugins.""" java_options_src = Java.global_instance() scala_options_src = ScalaPlatform.global_instance() def cp(instance, toolname): scope = instance.options_scope return instance.tool_classpath_from_products(self._products, toolname, scope=scope) classpaths = (cp(java_options_src, 'javac-plugin-dep') + cp(scala_options_src, 'scalac-plugin-dep')) return [(conf, ClasspathEntry(jar)) for conf in self.DEFAULT_CONFS for jar in classpaths]
def _set_directory_digest_for_compile_context(self, directory_digest, target, compile_contexts): cc = self.select_runtime_context(compile_contexts[target]) new_classpath_entry = ClasspathEntry(cc.classes_dir.path, directory_digest) cc.classes_dir = new_classpath_entry
def _set_directory_digest_for_compile_context(self, ctx, directory_digest): if self.get_options().use_classpath_jars: ctx.jar_file = ClasspathEntry(ctx.jar_file.path, directory_digest) else: ctx.classes_dir = ClasspathEntry(ctx.classes_dir.path, directory_digest)