def test_resolve_with_transitive_deps(rule_runner: RuleRunner) -> None: junit_coord = Coordinate(group="junit", artifact="junit", version="4.13.2") resolved_lockfile = rule_runner.request( CoursierResolvedLockfile, [ ArtifactRequirements([junit_coord]), ], ) assert resolved_lockfile == CoursierResolvedLockfile(entries=( CoursierLockfileEntry( coord=junit_coord, file_name="junit-4.13.2.jar", direct_dependencies=Coordinates([HAMCREST_COORD]), dependencies=Coordinates([HAMCREST_COORD]), file_digest=FileDigest( fingerprint= "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3", serialized_bytes_length=384581, ), ), CoursierLockfileEntry( coord=HAMCREST_COORD, file_name="hamcrest-core-1.3.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", serialized_bytes_length=45024, ), ), ))
def test_fetch_one_coord_with_mismatched_coord( rule_runner: RuleRunner) -> None: """This test demonstrates that fetch_one_coord is picky about inexact coordinates. Even though the expected jar was downloaded, the coordinate in the lockfile entry was inexact, meaning it wasn't an exact string match for the coordinate fetched and reported by Coursier, which is exact. This shouldn't happen in practice, because these lockfile entries are ultimately derived from Coursier reports which always give exact coordinate strings. """ expected_exception_msg = ( r'Coursier resolved coord.*?"org.hamcrest:hamcrest-core:1.3".*?' r'does not match requested coord.*?"org.hamcrest:hamcrest-core:1.3\+".*?' ) lockfile_entry = CoursierLockfileEntry( coord=Coordinate(group="org.hamcrest", artifact="hamcrest-core", version="1.3+"), file_name="hamcrest-core-1.3.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", serialized_bytes_length=45024, ), ) with pytest.raises(ExecutionError, match=expected_exception_msg): rule_runner.request(ClasspathEntry, [lockfile_entry])
def test_fetch_one_coord_with_transitive_deps(rule_runner: RuleRunner) -> None: junit_coord = Coordinate(group="junit", artifact="junit", version="4.13.2") classpath_entry = rule_runner.request( ClasspathEntry, [ CoursierLockfileEntry( coord=junit_coord, file_name="junit-4.13.2.jar", direct_dependencies=Coordinates([HAMCREST_COORD]), dependencies=Coordinates([HAMCREST_COORD]), file_digest=FileDigest( fingerprint= "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3", serialized_bytes_length=384581, ), ) ], ) assert classpath_entry.filenames == ("junit-4.13.2.jar", ) file_digest = rule_runner.request( FileDigest, [ExtractFileDigest(classpath_entry.digest, "junit-4.13.2.jar")]) assert file_digest == FileDigest( fingerprint= "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3", serialized_bytes_length=384581, )
def test_resolve_with_inexact_coord(rule_runner: RuleRunner) -> None: resolved_lockfile = rule_runner.request( CoursierResolvedLockfile, [ # Note the open-ended coordinate here. We will still resolve this for the user, but the result # will be exact and pinned. As noted above, this is an especially brittle unit test, but version # 4.8 was chosen because it has multiple patch versions and no new versions have been uploaded # to 4.8.x in over a decade. ArtifactRequirements( [Coordinate(group="junit", artifact="junit", version="4.8+")]), ], ) assert resolved_lockfile == CoursierResolvedLockfile( entries=(CoursierLockfileEntry( coord=Coordinate(group="junit", artifact="junit", version="4.8.2"), file_name="junit-4.8.2.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "a2aa2c3bb2b72da76c3e6a71531f1eefdc350494819baf2b1d80d7146e020f9e", serialized_bytes_length=237344, ), ), ))
def test_fetch_one_coord_with_no_deps(rule_runner: RuleRunner) -> None: classpath_entry = rule_runner.request( ClasspathEntry, [ CoursierLockfileEntry( coord=HAMCREST_COORD, file_name="hamcrest-core-1.3.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", serialized_bytes_length=45024, ), ) ], ) assert classpath_entry.filenames == ("hamcrest-core-1.3.jar", ) file_digest = rule_runner.request( FileDigest, [ExtractFileDigest(classpath_entry.digest, "hamcrest-core-1.3.jar")]) assert file_digest == FileDigest( fingerprint= "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", serialized_bytes_length=45024, )
def test_compile_with_maven_deps(rule_runner: RuleRunner) -> None: resolved_joda_lockfile = CoursierResolvedLockfile( entries=(CoursierLockfileEntry( coord=Coordinate( group="joda-time", artifact="joda-time", version="2.10.10"), file_name="joda-time-2.10.10.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "dd8e7c92185a678d1b7b933f31209b6203c8ffa91e9880475a1be0346b9617e3", serialized_bytes_length=644419, ), ), )) rule_runner.write_files({ "BUILD": dedent("""\ jvm_artifact( name = "joda-time_joda-time", group = "joda-time", artifact = "joda-time", version = "2.10.10", ) java_sources( name = 'main', dependencies = [ ':joda-time_joda-time', ] ) """), "coursier_resolve.lockfile": resolved_joda_lockfile.to_json().decode("utf-8"), "Example.java": dedent(""" package org.pantsbuild.example; import org.joda.time.DateTime; public class Example { public static void main(String[] args) { DateTime dt = new DateTime(); System.out.println(dt.getYear()); } } """), }) request = CompileJavaSourceRequest( component=expect_single_expanded_coarsened_target( rule_runner, Address(spec_path="", target_name="main")), resolve=make_resolve(rule_runner), ) compiled_classfiles = rule_runner.request(ClasspathEntry, [request]) classpath = rule_runner.request(RenderedClasspath, [compiled_classfiles.digest]) assert classpath.content == { ".Example.java.main.jar": {"org/pantsbuild/example/Example.class"} }
def test_compile_with_maven_deps(rule_runner: RuleRunner) -> None: resolved_joda_lockfile = CoursierResolvedLockfile( entries=(CoursierLockfileEntry( coord=Coordinate( group="joda-time", artifact="joda-time", version="2.10.10"), file_name="joda-time-2.10.10.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "dd8e7c92185a678d1b7b933f31209b6203c8ffa91e9880475a1be0346b9617e3", serialized_bytes_length=644419, ), ), )) rule_runner.write_files({ "BUILD": dedent("""\ jvm_artifact( name = "joda-time_joda-time", group = "joda-time", artifact = "joda-time", version = "2.10.10", ) scala_sources( name = 'main', dependencies = [":joda-time_joda-time"], ) """), "coursier_resolve.lockfile": resolved_joda_lockfile.to_json().decode("utf-8"), "Example.scala": dedent(""" package org.pantsbuild.example import org.joda.time.DateTime object Main { def main(args: Array[String]): Unit = { val dt = new DateTime() println(dt.getYear) } } """), }) request = CompileScalaSourceRequest( component=expect_single_expanded_coarsened_target( rule_runner, Address(spec_path="", target_name="main")), resolve=make_resolve(rule_runner), ) compiled_classfiles = rule_runner.request(ClasspathEntry, [request]) classpath = rule_runner.request(RenderedClasspath, [compiled_classfiles.digest]) assert classpath.content == { ".Example.scala.main.jar": { "META-INF/MANIFEST.MF", "org/pantsbuild/example/Main$.class", "org/pantsbuild/example/Main.class", } }
def test_resolve_with_no_deps(rule_runner: RuleRunner) -> None: resolved_lockfile = rule_runner.request( CoursierResolvedLockfile, [ArtifactRequirements([HAMCREST_COORD])], ) assert resolved_lockfile == CoursierResolvedLockfile( entries=(CoursierLockfileEntry( coord=HAMCREST_COORD, file_name="hamcrest-core-1.3.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", serialized_bytes_length=45024, ), ), ))
def test_coursier_resolve_updates_bogus_lockfile( rule_runner: RuleRunner) -> None: rule_runner.write_files({ "BUILD": dedent("""\ java_sources( name = 'here_to_provide_dependencies', dependencies = [ ':org.hamcrest_hamcrest-core', ], sources = ["*.txt"], ) jvm_artifact( name = 'org.hamcrest_hamcrest-core', group = 'org.hamcrest', artifact = 'hamcrest-core', version = "1.3", ) coursier_lockfile( name = 'example-lockfile', ) """), "coursier_resolve.lockfile": "]bad json[", }) result = rule_runner.run_goal_rule(CoursierResolve, args=ARGS, env_inherit=PYTHON_BOOTSTRAP_ENV) assert result.exit_code == 0 assert result.stderr == "Updated lockfile at: coursier_resolve.lockfile\n" expected_lockfile = CoursierResolvedLockfile(entries=(CoursierLockfileEntry( coord=HAMCREST_COORD, file_name="hamcrest-core-1.3.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", serialized_bytes_length=45024, ), ), )) assert (Path(rule_runner.build_root, "coursier_resolve.lockfile").read_bytes() == expected_lockfile.to_json())
def test_fetch_one_coord_with_bad_fingerprint(rule_runner: RuleRunner) -> None: expected_exception_msg = ( r".*?CoursierError:.*?Coursier fetch for .*?hamcrest.*? succeeded.*?" r"66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9.*?" r"did not match.*?ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" ) lockfile_entry = CoursierLockfileEntry( coord=HAMCREST_COORD, file_name="hamcrest-core-1.3.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", serialized_bytes_length=45024, ), ) with pytest.raises(ExecutionError, match=expected_exception_msg): rule_runner.request(ClasspathEntry, [lockfile_entry])
def lockfile() -> CoursierResolvedLockfile: # Calculate transitive deps transitive_ = {(i, k) for i, j in direct.items() for k in j} while True: old_len = len(transitive_) transitive_ |= {(i, k) for i, j in transitive_ for k in direct[j]} if old_len == len(transitive_): break transitive = DefaultDict(set) for (i, j) in transitive_: transitive[i].add(j) entries = (CoursierLockfileEntry( coord=coord, file_name=f"{coord.artifact}.jar", direct_dependencies=Coordinates(direct[coord]), dependencies=Coordinates(transitive[coord]), file_digest=mock.Mock(), ) for coord in direct) return CoursierResolvedLockfile(entries=tuple(entries))
def test_coursier_resolve_noop_does_not_touch_lockfile( rule_runner: RuleRunner) -> None: expected_lockfile = CoursierResolvedLockfile(entries=(CoursierLockfileEntry( coord=HAMCREST_COORD, file_name="hamcrest-core-1.3.jar", direct_dependencies=Coordinates([]), dependencies=Coordinates([]), file_digest=FileDigest( fingerprint= "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", serialized_bytes_length=45024, ), ), )) rule_runner.write_files({ "BUILD": dedent("""\ jvm_artifact( name = 'org.hamcrest_hamcrest-core', group = 'org.hamcrest', artifact = 'hamcrest-core', version = "1.3", ) coursier_lockfile( name = 'example-lockfile', requirements = [ ':org.hamcrest_hamcrest-core', ], sources = [ "coursier_resolve.lockfile", ], ) """), "coursier_resolve.lockfile": expected_lockfile.to_json().decode("utf-8"), }) result = rule_runner.run_goal_rule(CoursierResolve, args=["::"]) assert result.exit_code == 0 assert result.stderr == ""
# CoursierResolvedLockfile, # [ # MavenRequirements.create_from_maven_coordinates_fields( # fields=(), # additional_requirements=["junit:junit:4.13.2"], # ) # ], # ) # The `repr` of the resulting lockfile object can be directly copied # into code to get the following: JUNIT4_RESOLVED_LOCKFILE = CoursierResolvedLockfile(entries=( CoursierLockfileEntry( coord=Coordinate(group="junit", artifact="junit", version="4.13.2"), file_name="junit-4.13.2.jar", direct_dependencies=Coordinates([ Coordinate( group="org.hamcrest", artifact="hamcrest-core", version="1.3") ]), dependencies=Coordinates([ Coordinate( group="org.hamcrest", artifact="hamcrest-core", version="1.3") ]), file_digest=FileDigest( fingerprint= "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3", serialized_bytes_length=384581, ), ), CoursierLockfileEntry( coord=Coordinate( group="org.hamcrest", artifact="hamcrest-core", version="1.3"), file_name="hamcrest-core-1.3.jar",
async def setup_jdk(coursier: Coursier, javac: JavacSubsystem, bash: BashBinary) -> JdkSetup: nailgun = await Get( ResolvedClasspathEntry, CoursierLockfileEntry( coord=Coordinate.from_coord_str( "com.martiansoftware:nailgun-server:0.9.1"), file_name="nailgun-server-0.9.1.jar", direct_dependencies=Coordinates(), dependencies=Coordinates(), file_digest=FileDigest( fingerprint= "4518faa6bf4bd26fccdc4d85e1625dc679381a08d56872d8ad12151dda9cef25", serialized_bytes_length=32927, ), ), ) if javac.options.jdk == "system": coursier_jdk_option = "--system-jvm" else: coursier_jdk_option = f"--jvm={javac.options.jdk}" java_home_command = f"{coursier.coursier.exe} java-home {coursier_jdk_option}" java_version_result = await Get( FallibleProcessResult, Process( argv=( bash.path, "-c", f"$({java_home_command})/bin/java -version", ), input_digest=coursier.digest, description=f"Ensure download of JDK {coursier_jdk_option}.", cache_scope=ProcessCacheScope.PER_RESTART_SUCCESSFUL, ), ) if java_version_result.exit_code != 0: raise ValueError( f"Failed to locate Java for JDK `{javac.options.jdk}`:\n" f"{java_version_result.stderr.decode('utf-8')}") java_version = java_version_result.stdout.decode("utf-8").strip() # TODO: Locate `ln`. jdk_preparation_script = textwrap.dedent(f"""\ # pants javac script using Coursier {coursier_jdk_option}. `java -version`: {java_version}" set -eu /bin/ln -s "$({java_home_command})" "{JdkSetup.java_home}" exec "$@" """) jdk_preparation_script_digest = await Get( Digest, CreateDigest([ FileContent( JdkSetup.jdk_preparation_script, jdk_preparation_script.encode("utf-8"), is_executable=True, ), ]), ) return JdkSetup( digest=await Get( Digest, MergeDigests([ coursier.digest, jdk_preparation_script_digest, nailgun.digest, ]), ), nailgun_jar=nailgun.file_name, )