def test_path_globs_to_digest_entries(rule_runner: RuleRunner) -> None: setup_fs_test_tar(rule_runner) def get_entries(globs: Iterable[str]) -> Set[Union[FileEntry, Directory]]: return set(rule_runner.request(DigestEntries, [PathGlobs(globs)])) assert get_entries(["4.txt", "a/4.txt.ln"]) == { FileEntry( "4.txt", FileDigest("ab929fcd5594037960792ea0b98caf5fdaf6b60645e4ef248c28db74260f393e", 5), ), FileEntry( "a/4.txt.ln", FileDigest("ab929fcd5594037960792ea0b98caf5fdaf6b60645e4ef248c28db74260f393e", 5), ), } assert get_entries(["c.ln/../3.txt"]) == { FileEntry( "c.ln/../3.txt", FileDigest("f6936912184481f5edd4c304ce27c5a1a827804fc7f329f43d273b8621870776", 6), ) } # Directories are empty. assert get_entries(["a/b"]) == {Directory("a/b")} assert get_entries(["c.ln"]) == {Directory("c.ln")}
async def render_war_deployment_descriptor( request: RenderWarDeploymentDescriptorRequest, ) -> RenderedWarDeploymentDescriptor: descriptor_sources = await Get( HydratedSources, HydrateSourcesRequest(request.descriptor), ) descriptor_sources_entries = await Get(DigestEntries, Digest, descriptor_sources.snapshot.digest) if len(descriptor_sources_entries) != 1: raise AssertionError( f"Expected `descriptor` field for {request.descriptor.address} to only refer to one file." ) descriptor_entry = descriptor_sources_entries[0] if not isinstance(descriptor_entry, FileEntry): raise AssertionError( f"Expected `descriptor` field for {request.descriptor.address} to produce a file." ) descriptor_digest = await Get( Digest, CreateDigest([ FileEntry("__war__/WEB-INF/web.xml", descriptor_entry.file_digest) ]), ) return RenderedWarDeploymentDescriptor(descriptor_digest)
async def package_debian_package(field_set: DebianPackageFieldSet, tar_binary_path: TarBinary) -> BuiltPackage: dpkg_deb_path = await Get( BinaryPaths, BinaryPathRequest( binary_name="dpkg-deb", search_path=["/usr/bin"], ), ) if not dpkg_deb_path.first_path: raise OSError( f"Could not find the `{dpkg_deb_path.binary_name}` program in `/usr/bin`." ) hydrated_sources = await Get(HydratedSources, HydrateSourcesRequest(field_set.sources_dir)) # Since all the sources are coming only from a single directory, it is # safe to pick an arbitrary file and get its root directory name. # Validation of the resolved files has been called on the target, so it is known that # snapshot.files isn't empty. sources_directory_name = PurePath( hydrated_sources.snapshot.files[0]).parts[0] result = await Get( ProcessResult, Process( argv=( dpkg_deb_path.first_path.path, "--build", sources_directory_name, ), description="Create a Debian package from the produced packages.", input_digest=hydrated_sources.snapshot.digest, # dpkg-deb produces a file with the same name as the input directory output_files=(f"{sources_directory_name}.deb", ), env={"PATH": str(PurePath(tar_binary_path.path).parent)}, ), ) # The output Debian package file needs to be renamed to match the output_path field. output_filename = field_set.output_path.value_or_default( file_ending="deb", ) digest_entries = await Get(DigestEntries, Digest, result.output_digest) assert len(digest_entries) == 1 result_file_entry = digest_entries[0] assert isinstance(result_file_entry, FileEntry) new_file = FileEntry(output_filename, result_file_entry.file_digest) final_result = await Get(Digest, CreateDigest([new_file])) return BuiltPackage(final_result, artifacts=(BuiltPackageArtifact(output_filename), ))
def test_digest_entries_handles_empty_directory(rule_runner: RuleRunner) -> None: digest = rule_runner.request( Digest, [CreateDigest([Directory("a/b"), FileContent("a/foo.txt", b"four\n")])] ) entries = rule_runner.request(DigestEntries, [digest]) assert entries == DigestEntries( [ Directory("a/b"), FileEntry( "a/foo.txt", FileDigest("ab929fcd5594037960792ea0b98caf5fdaf6b60645e4ef248c28db74260f393e", 5), ), ] )
async def handle_bsp_scalac_options_request( request: HandleScalacOptionsRequest, build_root: BuildRoot, workspace: Workspace, ) -> HandleScalacOptionsResult: bsp_target = await Get(BSPBuildTargetInternal, BuildTargetIdentifier, request.bsp_target_id) targets = await Get( Targets, AddressSpecs, bsp_target.specs.address_specs, ) coarsened_targets = await Get(CoarsenedTargets, Addresses(tgt.address for tgt in targets)) resolve = await Get(CoursierResolveKey, CoarsenedTargets, coarsened_targets) lockfile = await Get(CoursierResolvedLockfile, CoursierResolveKey, resolve) resolve_digest = await Get( Digest, CreateDigest([ FileEntry(entry.file_name, entry.file_digest) for entry in lockfile.entries ]), ) resolve_digest = await Get( Digest, AddPrefix(resolve_digest, f"jvm/resolves/{resolve.name}/lib")) workspace.write_digest(resolve_digest, path_prefix=".pants.d/bsp") classpath = [ build_root.pathlib_path.joinpath( f".pants.d/bsp/jvm/resolves/{resolve.name}/lib/{entry.file_name}"). as_uri() for entry in lockfile.entries ] return HandleScalacOptionsResult( ScalacOptionsItem( target=request.bsp_target_id, options=(), classpath=tuple(classpath), class_directory=build_root.pathlib_path.joinpath( f".pants.d/bsp/jvm/resolves/{resolve.name}/classes").as_uri(), ))
async def _hydrate_asset_source( request: GenerateSourcesRequest) -> GeneratedSources: target = request.protocol_target source_field = target[AssetSourceField] if isinstance(source_field.value, str): return GeneratedSources(request.protocol_sources) http_source = source_field.value file_digest = FileDigest(http_source.sha256, http_source.len) # NB: This just has to run, we don't actually need the result because we know the Digest's # FileEntry metadata. await Get(Digest, DownloadFile(http_source.url, file_digest)) snapshot = await Get( Snapshot, CreateDigest([ FileEntry( path=source_field.file_path, file_digest=file_digest, ) ]), ) return GeneratedSources(snapshot)
async def package_war( field_set: PackageWarFileFieldSet, bash: BashBinary, zip: ZipBinary, ) -> BuiltPackage: classpath = await Get(Classpath, DependenciesRequest(field_set.dependencies)) all_jar_files_digest = await Get(Digest, MergeDigests(classpath.digests())) prefixed_jars_digest, content, descriptor, input_setup_digest = await MultiGet( Get(Digest, AddPrefix(all_jar_files_digest, "__war__/WEB-INF/lib")), Get(RenderedWarContent, RenderWarContentRequest(field_set.content)), Get( RenderedWarDeploymentDescriptor, RenderWarDeploymentDescriptorRequest(field_set.descriptor, field_set.address), ), Get( Digest, CreateDigest([ FileContent( "make_war.sh", textwrap.dedent(f"""\ cd __war__ {zip.path} ../output.war -r . """).encode(), is_executable=True, ), Directory("__war__/WEB-INF/classes"), Directory("__war__/WEB-INF/lib"), ]), ), ) input_digest = await Get( Digest, MergeDigests([ prefixed_jars_digest, descriptor.digest, content.digest, input_setup_digest, ]), ) result = await Get( ProcessResult, Process( [bash.path, "make_war.sh"], input_digest=input_digest, output_files=("output.war", ), description=f"Assemble WAR file for {field_set.address}", ), ) output_entries = await Get(DigestEntries, Digest, result.output_digest) if len(output_entries) != 1: raise AssertionError("No output from war assembly step.") output_entry = output_entries[0] if not isinstance(output_entry, FileEntry): raise AssertionError("Unexpected digest entry") output_filename = PurePath( field_set.output_path.value_or_default(file_ending="war")) package_digest = await Get( Digest, CreateDigest( [FileEntry(str(output_filename), output_entry.file_digest)])) artifact = BuiltPackageArtifact(relpath=str(output_filename)) return BuiltPackage(digest=package_digest, artifacts=(artifact, ))
async def scala_bsp_dependency_modules( request: ScalaBSPDependencyModulesRequest, build_root: BuildRoot, ) -> BSPDependencyModulesResult: coarsened_targets = await Get( CoarsenedTargets, Addresses([fs.address for fs in request.field_sets])) resolve = await Get(CoursierResolveKey, CoarsenedTargets, coarsened_targets) lockfile = await Get(CoursierResolvedLockfile, CoursierResolveKey, resolve) # TODO: Can this use ClasspathEntryRequest? transitive_targets = await Get( TransitiveTargets, TransitiveTargetsRequest(roots=[ tgt.address for coarsened_target in coarsened_targets for tgt in coarsened_target.members ]), ) artifact_requirements = [ ArtifactRequirement.from_jvm_artifact_target(tgt) for tgt in transitive_targets.closure if JvmArtifactFieldSet.is_applicable(tgt) ] applicable_lockfile_entries: set[CoursierLockfileEntry] = set() for artifact_requirement in artifact_requirements: entry = get_entry_for_coord(lockfile, artifact_requirement.coordinate) if not entry: _logger.warning( f"No lockfile entry for {artifact_requirement.coordinate} in resolve {resolve.name}." ) continue applicable_lockfile_entries.add(entry) resolve_digest = await Get( Digest, CreateDigest([ FileEntry(entry.file_name, entry.file_digest) for entry in applicable_lockfile_entries ]), ) resolve_digest = await Get( Digest, AddPrefix(resolve_digest, f"jvm/resolves/{resolve.name}/lib")) modules = [ DependencyModule( name=f"{entry.coord.group}:{entry.coord.artifact}", version=entry.coord.version, data=MavenDependencyModule( organization=entry.coord.group, name=entry.coord.artifact, version=entry.coord.version, scope=None, artifacts=(MavenDependencyModuleArtifact( uri=build_root.pathlib_path.joinpath( f".pants.d/bsp/jvm/resolves/{resolve.name}/lib/{entry.file_name}" ).as_uri()), ), ), ) for entry in applicable_lockfile_entries ] return BSPDependencyModulesResult( modules=tuple(modules), digest=resolve_digest, )