-
-
Notifications
You must be signed in to change notification settings - Fork 636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[internal] Refactor jvm_artifact
usage
#13890
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,7 @@ | |
) | ||
from pants.engine.process import BashBinary, Process, ProcessResult | ||
from pants.engine.rules import Get, MultiGet, collect_rules, rule | ||
from pants.engine.target import InvalidTargetException, Target, Targets | ||
from pants.engine.target import Target, Targets | ||
from pants.engine.unions import UnionRule | ||
from pants.jvm.compile import ( | ||
ClasspathEntry, | ||
|
@@ -136,46 +136,22 @@ class ArtifactRequirement: | |
@classmethod | ||
def from_jvm_artifact_target(cls, target: Target) -> ArtifactRequirement: | ||
if not JvmArtifactFieldSet.is_applicable(target): | ||
raise CoursierError( | ||
raise AssertionError( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This represents a programmer error. |
||
"`ArtifactRequirement.from_jvm_artifact_target()` only works on targets with " | ||
"`JvmArtifactFieldSet` fields present." | ||
) | ||
|
||
group = target[JvmArtifactGroupField].value | ||
if not group: | ||
raise InvalidTargetException( | ||
f"The `group` field of {target.alias} target {target.address} must be set." | ||
) | ||
|
||
artifact = target[JvmArtifactArtifactField].value | ||
if not artifact: | ||
raise InvalidTargetException( | ||
f"The `artifact` field of {target.alias} target {target.address} must be set." | ||
) | ||
|
||
version = target[JvmArtifactVersionField].value | ||
if not version: | ||
raise InvalidTargetException( | ||
f"The `version` field of {target.alias} target {target.address} must be set." | ||
) | ||
Comment on lines
-144
to
-160
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Target API already was checking that it's not |
||
|
||
url = target[JvmArtifactUrlField].value | ||
jar_ = target[JvmArtifactJarSourceField] | ||
jar = jar_ if jar_.value else None | ||
|
||
if url and url.startswith("file:"): | ||
raise CoursierError( | ||
"Pants does not support `file:` URLS. Instead, use the `jar` field to specify the " | ||
"relative path to the local jar file." | ||
) | ||
|
||
if url and jar: | ||
raise CoursierError( | ||
"You cannot specify both a `url` and `jar` for the same `jvm_artifact`." | ||
) | ||
Comment on lines
-172
to
-175
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now done with the Target API via The downside is that this is less reslient to creating a new |
||
|
||
return ArtifactRequirement( | ||
coordinate=Coordinate(group=group, artifact=artifact, version=version), url=url, jar=jar | ||
coordinate=Coordinate( | ||
group=target[JvmArtifactGroupField].value, | ||
artifact=target[JvmArtifactArtifactField].value, | ||
version=target[JvmArtifactVersionField].value, | ||
), | ||
url=target[JvmArtifactUrlField].value, | ||
jar=( | ||
target[JvmArtifactJarSourceField] | ||
if target[JvmArtifactJarSourceField].value | ||
else None | ||
), | ||
) | ||
|
||
def to_coord_str(self, versioned: bool = True) -> str: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,17 +4,49 @@ | |
from __future__ import annotations | ||
|
||
from abc import ABCMeta | ||
from typing import Optional | ||
|
||
from pants.engine.addresses import Address | ||
from pants.engine.target import ( | ||
COMMON_TARGET_FIELDS, | ||
FieldSet, | ||
InvalidFieldException, | ||
InvalidTargetException, | ||
SingleSourceField, | ||
StringField, | ||
StringSequenceField, | ||
Target, | ||
) | ||
from pants.util.docutil import git_url | ||
|
||
# ----------------------------------------------------------------------------------------------- | ||
# Generic resolve support fields | ||
# ----------------------------------------------------------------------------------------------- | ||
Comment on lines
+22
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section is moved, unmodified, from below. I'll need it in a followup PR defined here so that I can subclass it lower in the file. |
||
|
||
|
||
class JvmCompatibleResolvesField(StringSequenceField): | ||
alias = "compatible_resolves" | ||
required = False | ||
help = ( | ||
"The set of resolve names that this target is compatible with.\n\n" | ||
"Each name must be defined as a resolve in `[jvm].resolves`.\n\n" | ||
"Any targets which depend on one another must have at least one compatible resolve in " | ||
"common. Which resolves are actually used in a build is calculated based on a target's " | ||
"dependees." | ||
) | ||
|
||
|
||
class JvmResolveField(StringField): | ||
alias = "resolve" | ||
required = False | ||
help = ( | ||
"The name of the resolve to use when building this target.\n\n" | ||
"Each name must be defined as a resolve in `[jvm].resolves`.\n\n" | ||
"If not supplied, the default resolve will be used. Otherwise, one resolve that is " | ||
"compatible with all dependency targets will be used." | ||
) | ||
|
||
|
||
# ----------------------------------------------------------------------------------------------- | ||
# `jvm_artifact` targets | ||
# ----------------------------------------------------------------------------------------------- | ||
|
@@ -27,6 +59,7 @@ | |
class JvmArtifactGroupField(StringField): | ||
alias = "group" | ||
required = True | ||
value: str | ||
help = ( | ||
"The 'group' part of a Maven-compatible coordinate to a third-party JAR artifact.\n\n" | ||
"For the JAR coordinate `com.google.guava:guava:30.1.1-jre`, the group is " | ||
|
@@ -37,6 +70,7 @@ class JvmArtifactGroupField(StringField): | |
class JvmArtifactArtifactField(StringField): | ||
alias = "artifact" | ||
required = True | ||
value: str | ||
help = ( | ||
"The 'artifact' part of a Maven-compatible coordinate to a third-party JAR artifact.\n\n" | ||
"For the JAR coordinate `com.google.guava:guava:30.1.1-jre`, the artifact is `guava`." | ||
|
@@ -46,6 +80,7 @@ class JvmArtifactArtifactField(StringField): | |
class JvmArtifactVersionField(StringField): | ||
alias = "version" | ||
required = True | ||
value: str | ||
help = ( | ||
"The 'version' part of a Maven-compatible coordinate to a third-party JAR artifact.\n\n" | ||
"For the JAR coordinate `com.google.guava:guava:30.1.1-jre`, the version is `30.1.1-jre`." | ||
|
@@ -76,6 +111,17 @@ class JvmArtifactJarSourceField(SingleSourceField): | |
"Use the `url` field for remote artifacts." | ||
) | ||
|
||
@classmethod | ||
def compute_value(cls, raw_value: Optional[str], address: Address) -> Optional[str]: | ||
value_or_default = super().compute_value(raw_value, address) | ||
if value_or_default and value_or_default.startswith("file:"): | ||
raise InvalidFieldException( | ||
f"The `{cls.alias}` field does not support `file:` URLS, but the target " | ||
f"{address} sets the field to `{value_or_default}`.\n\n" | ||
"Instead, use the `jar` field to specify the relative path to the local jar file." | ||
) | ||
return value_or_default | ||
|
||
|
||
class JvmArtifactPackagesField(StringSequenceField): | ||
alias = "packages" | ||
|
@@ -109,7 +155,6 @@ class JvmProvidesTypesField(StringSequenceField): | |
|
||
|
||
class JvmArtifactFieldSet(FieldSet): | ||
|
||
group: JvmArtifactGroupField | ||
artifact: JvmArtifactArtifactField | ||
version: JvmArtifactVersionField | ||
|
@@ -137,6 +182,13 @@ class JvmArtifactTarget(Target): | |
"That is, an artifact identified by its `group`, `artifact`, and `version` components." | ||
) | ||
|
||
def validate(self) -> None: | ||
if self[JvmArtifactJarSourceField].value and self[JvmArtifactUrlField].value: | ||
raise InvalidTargetException( | ||
f"You cannot specify both the `url` and `jar` fields, but both were set on the " | ||
f"`{self.alias}` target {self.address}." | ||
) | ||
|
||
|
||
# ----------------------------------------------------------------------------------------------- | ||
# JUnit test support field(s) | ||
|
@@ -145,31 +197,3 @@ class JvmArtifactTarget(Target): | |
|
||
class JunitTestSourceField(SingleSourceField, metaclass=ABCMeta): | ||
"""A marker that indicates that a source field represents a JUnit test.""" | ||
|
||
|
||
# ----------------------------------------------------------------------------------------------- | ||
# Generic resolve support fields | ||
# ----------------------------------------------------------------------------------------------- | ||
|
||
|
||
class JvmCompatibleResolvesField(StringSequenceField): | ||
alias = "compatible_resolves" | ||
required = False | ||
help = ( | ||
"The set of resolve names that this target is compatible with.\n\n" | ||
"Each name must be defined as a resolve in `[jvm].resolves`.\n\n" | ||
"Any targets which depend on one another must have at least one compatible resolve in " | ||
"common. Which resolves are actually used in a build is calculated based on a target's " | ||
"dependees." | ||
) | ||
|
||
|
||
class JvmResolveField(StringField): | ||
alias = "resolve" | ||
required = False | ||
help = ( | ||
"The name of the resolve to use when building this target.\n\n" | ||
"Each name must be defined as a resolve in `[jvm].resolves`.\n\n" | ||
"If not supplied, the default resolve will be used. Otherwise, one resolve that is " | ||
"compatible with all dependency targets will be used." | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were duplicating the two
if
statement bodies. I inverted the conditional to make this all shorter and simpler.