Skip to content
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

Better git handling #192

Merged
merged 5 commits into from
Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions poetry/core/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ def create_dependency(
branch=constraint.get("branch", None),
tag=constraint.get("tag", None),
rev=constraint.get("rev", None),
directory=constraint.get("subdirectory", None),
groups=groups,
optional=optional,
develop=constraint.get("develop", False),
Expand Down
4 changes: 4 additions & 0 deletions poetry/core/json/schemas/poetry-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,10 @@
"type": "string",
"description": "The revision to checkout."
},
"subdirectory": {
"type": "string",
"description": "The relative path to the directory where the package is located."
},
"python": {
"type": "string",
"description": "The python versions for which the dependency should be installed."
Expand Down
11 changes: 9 additions & 2 deletions poetry/core/packages/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def __init__(
source_url: Optional[str] = None,
source_reference: Optional[str] = None,
source_resolved_reference: Optional[str] = None,
source_subdirectory: Optional[str] = None,
):
from poetry.core.version.markers import AnyMarker

Expand All @@ -50,6 +51,7 @@ def __init__(
source_url=source_url,
source_reference=source_reference,
source_resolved_reference=source_resolved_reference,
source_subdirectory=source_subdirectory,
features=extras,
)

Expand Down Expand Up @@ -435,7 +437,7 @@ def create_from_pep_508(
from .vcs_dependency import VCSDependency

# Removing comments
parts = name.split("#", 1)
parts = name.split(" #", 1)
name = parts[0].strip()
if len(parts) > 1:
rest = parts[1]
Expand Down Expand Up @@ -497,7 +499,12 @@ def create_from_pep_508(
if link.scheme.startswith("git+"):
url = ParsedUrl.parse(link.url)
dep = VCSDependency(
name, "git", url.url, rev=url.rev, extras=req.extras
name,
"git",
url.url,
rev=url.rev,
directory=url.subdirectory,
extras=req.extras,
)
elif link.scheme == "git":
dep = VCSDependency(
Expand Down
3 changes: 3 additions & 0 deletions poetry/core/packages/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def __init__(
source_url: Optional[str] = None,
source_reference: Optional[str] = None,
source_resolved_reference: Optional[str] = None,
source_subdirectory: Optional[str] = None,
features: Optional[List[str]] = None,
develop: bool = False,
) -> None:
Expand All @@ -66,6 +67,7 @@ def __init__(
source_url=source_url,
source_reference=source_reference,
source_resolved_reference=source_resolved_reference,
source_subdirectory=source_subdirectory,
features=features,
)

Expand Down Expand Up @@ -468,6 +470,7 @@ def to_dependency(
self.source_url,
rev=self.source_reference,
resolved_rev=self.source_resolved_reference,
directory=self.source_subdirectory,
groups=list(self._dependency_groups.keys()),
optional=self.optional,
develop=self.develop,
Expand Down
18 changes: 18 additions & 0 deletions poetry/core/packages/specification.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def __init__(
source_url: Optional[str] = None,
source_reference: Optional[str] = None,
source_resolved_reference: Optional[str] = None,
source_subdirectory: Optional[str] = None,
features: Optional[List[str]] = None,
):
from poetry.core.utils.helpers import canonicalize_name
Expand All @@ -21,6 +22,7 @@ def __init__(
self._source_url = source_url
self._source_reference = source_reference
self._source_resolved_reference = source_resolved_reference
self._source_subdirectory = source_subdirectory

if not features:
features = []
Expand Down Expand Up @@ -60,6 +62,10 @@ def source_reference(self) -> Optional[str]:
def source_resolved_reference(self) -> Optional[str]:
return self._source_resolved_reference

@property
def source_subdirectory(self) -> Optional[str]:
return self._source_subdirectory

@property
def features(self) -> FrozenSet[str]:
return self._features
Expand All @@ -76,6 +82,18 @@ def is_same_package_as(self, other: "PackageSpecification") -> bool:
if self._source_url != other.source_url:
return False

# We check the resolved reference first:
# if they match we assume equality regardless
# of their source reference.
# This is important when comparing a resolved branch VCS
# dependency to a direct commit reference VCS dependency
if (
self._source_resolved_reference
and other.source_resolved_reference
and self._source_resolved_reference == other.source_resolved_reference
):
return True

if self._source_reference or other.source_reference:
# special handling for packages with references
if not self._source_reference or not other.source_reference:
Expand Down
24 changes: 16 additions & 8 deletions poetry/core/packages/vcs_dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def __init__(
tag: Optional[str] = None,
rev: Optional[str] = None,
resolved_rev: Optional[str] = None,
directory: Optional[str] = None,
groups: Optional[List[str]] = None,
optional: bool = False,
develop: bool = False,
Expand All @@ -33,13 +34,10 @@ def __init__(
self._vcs = vcs
self._source = source

if not any([branch, tag, rev]):
# If nothing has been specified, we assume master
branch = "master"

self._branch = branch
self._tag = tag
self._rev = rev
self._directory = directory
self._develop = develop

super(VCSDependency, self).__init__(
Expand All @@ -52,6 +50,7 @@ def __init__(
source_url=self._source,
source_reference=branch or tag or rev,
source_resolved_reference=resolved_rev,
source_subdirectory=directory,
extras=extras,
)

Expand All @@ -75,6 +74,10 @@ def tag(self) -> Optional[str]:
def rev(self) -> Optional[str]:
return self._rev

@property
def directory(self) -> Optional[str]:
return self._directory

@property
def develop(self) -> bool:
return self._develop
Expand Down Expand Up @@ -108,11 +111,15 @@ def base_pep_508_name(self) -> str:
requirement += "[{}]".format(",".join(self.extras))

if parsed_url.protocol is not None:
requirement += " @ {}+{}@{}".format(self._vcs, self._source, self.reference)
requirement += " @ {}+{}".format(self._vcs, self._source)
else:
requirement += " @ {}+ssh://{}@{}".format(
self._vcs, parsed_url.format(), self.reference
)
requirement += " @ {}+ssh://{}".format(self._vcs, parsed_url.format())

if self.reference:
requirement += f"@{self.reference}"

if self._directory:
requirement += f"#subdirectory{self._directory}"

return requirement

Expand All @@ -131,6 +138,7 @@ def with_constraint(self, constraint: "BaseConstraint") -> "VCSDependency":
tag=self._tag,
rev=self._rev,
resolved_rev=self._source_resolved_reference,
directory=self.directory,
optional=self.is_optional(),
groups=list(self._groups),
develop=self._develop,
Expand Down
71 changes: 55 additions & 16 deletions poetry/core/vcs/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"port": r"\d+",
"path": r"[\w~.\-/\\]+",
"name": r"[\w~.\-]+",
"rev": r"[^@#]+",
"rev": r"[^@#]+?",
"subdir": r"[\w\-/\\]+",
}

PATTERNS = [
Expand All @@ -26,14 +27,21 @@
r"(:(?P<port>{port}))?"
r"(?P<pathname>[:/\\]({path}[/\\])?"
r"((?P<name>{name}?)(\.git|[/\\])?)?)"
r"([@#](?P<rev>{rev}))?"
r"(?:"
r"#egg=?.+"
r"|"
r"#(?:egg=.+?&subdirectory=|subdirectory=)(?P<subdirectory>{subdir})"
r"|"
r"[@#](?P<rev>{rev})(?:[&#](?:egg=.+?|(?:egg=.+?&subdirectory=|subdirectory=)(?P<rev_subdirectory>{subdir})))?"
r")?"
r"$".format(
user=pattern_formats["user"],
resource=pattern_formats["resource"],
port=pattern_formats["port"],
path=pattern_formats["path"],
name=pattern_formats["name"],
rev=pattern_formats["rev"],
subdir=pattern_formats["subdir"],
)
),
re.compile(
Expand All @@ -44,7 +52,13 @@
r"(:(?P<port>{port}))?"
r"(?P<pathname>({path})"
r"(?P<name>{name})(\.git|/)?)"
r"([@#](?P<rev>{rev}))?"
r"(?:"
r"#egg=?.+"
r"|"
r"#(?:egg=.+?&subdirectory=|subdirectory=)(?P<subdirectory>{subdir})"
r"|"
r"[@#](?P<rev>{rev})(?:[&#](?:egg=.+?|(?:egg=.+?&subdirectory=|subdirectory=)(?P<rev_subdirectory>{subdir})))?"
r")?"
r"$".format(
protocol=pattern_formats["protocol"],
user=pattern_formats["user"],
Expand All @@ -53,6 +67,7 @@
path=pattern_formats["path"],
name=pattern_formats["name"],
rev=pattern_formats["rev"],
subdir=pattern_formats["subdir"],
)
),
re.compile(
Expand All @@ -61,14 +76,21 @@
r"(:(?P<port>{port}))?"
r"(?P<pathname>([:/]{path}/)"
r"(?P<name>{name})(\.git|/)?)"
r"([@#](?P<rev>{rev}))?"
r"(?:"
r"#egg=.+?"
r"|"
r"#(?:egg=.+?&subdirectory=|subdirectory=)(?P<subdirectory>{subdir})"
r"|"
r"[@#](?P<rev>{rev})(?:[&#](?:egg=.+?&subdirectory=|subdirectory=)(?P<rev_subdirectory>{subdir}))?"
r")?"
r"$".format(
user=pattern_formats["user"],
resource=pattern_formats["resource"],
port=pattern_formats["port"],
path=pattern_formats["path"],
name=pattern_formats["name"],
rev=pattern_formats["rev"],
subdir=pattern_formats["subdir"],
)
),
re.compile(
Expand All @@ -77,13 +99,20 @@
r"[:/]{{1,2}}"
r"(?P<pathname>({path})"
r"(?P<name>{name})(\.git|/)?)"
r"([@#](?P<rev>{rev}))?"
r"(?:"
r"#egg=?.+"
r"|"
r"#(?:egg=.+?&subdirectory=|subdirectory=)(?P<subdirectory>{subdir})"
r"|"
r"[@#](?P<rev>{rev})(?:[&#](?:egg=.+?|(?:egg=.+?&subdirectory=|subdirectory=)(?P<rev_subdirectory>{subdir})))?"
r")?"
r"$".format(
user=pattern_formats["user"],
resource=pattern_formats["resource"],
path=pattern_formats["path"],
name=pattern_formats["name"],
rev=pattern_formats["rev"],
subdir=pattern_formats["subdir"],
)
),
]
Expand All @@ -99,6 +128,7 @@ def __init__(
port: Optional[str],
name: Optional[str],
rev: Optional[str],
subdirectory: Optional[str] = None,
):
self.protocol = protocol
self.resource = resource
Expand All @@ -107,6 +137,7 @@ def __init__(
self.port = port
self.name = name
self.rev = rev
self.subdirectory = subdirectory

@classmethod
def parse(cls, url: str) -> "ParsedUrl":
Expand All @@ -122,6 +153,7 @@ def parse(cls, url: str) -> "ParsedUrl":
groups.get("port"),
groups.get("name"),
groups.get("rev"),
groups.get("rev_subdirectory") or groups.get("subdirectory"),
)

raise ValueError('Invalid git url "{}"'.format(url))
Expand All @@ -143,7 +175,7 @@ def __str__(self) -> str:
return self.format()


GitUrl = namedtuple("GitUrl", ["url", "revision"])
GitUrl = namedtuple("GitUrl", ["url", "revision", "subdirectory"])


class GitConfig:
Expand Down Expand Up @@ -183,6 +215,11 @@ def normalize_url(cls, url: str) -> GitUrl:
if parsed.rev:
formatted = re.sub(r"[#@]{}$".format(parsed.rev), "", formatted)

if parsed.subdirectory:
formatted = re.sub(
r"[#&]subdirectory={}$".format(parsed.subdirectory), "", formatted
)

altered = parsed.format() != formatted

if altered:
Expand All @@ -197,7 +234,9 @@ def normalize_url(cls, url: str) -> GitUrl:
else:
normalized = parsed.format()

return GitUrl(re.sub(r"#[^#]*$", "", normalized), parsed.rev)
return GitUrl(
re.sub(r"#[^#]*$", "", normalized), parsed.rev, parsed.subdirectory
)

@property
def config(self) -> GitConfig:
Expand Down Expand Up @@ -228,14 +267,6 @@ def rev_parse(self, rev: str, folder: Optional[Path] = None) -> str:
if folder is None and self._work_dir:
folder = self._work_dir

if folder:
args += [
"--git-dir",
(folder / ".git").as_posix(),
"--work-tree",
folder.as_posix(),
]

# We need "^0" (an alternative to "^{commit}") to ensure that the
# commit SHA of the commit the tag points to is returned, even in
# the case of annotated tags.
Expand All @@ -246,7 +277,15 @@ def rev_parse(self, rev: str, folder: Optional[Path] = None) -> str:
# they should not be escaped.
args += ["rev-parse", rev + "^0"]

return self.run(*args)
return self.run(*args, folder=folder)

def get_current_branch(self, folder: Optional[Path] = None) -> str:
if folder is None and self._work_dir:
folder = self._work_dir

output = self.run("symbolic-ref", "--short", "HEAD", folder=folder)

return output.strip()

def get_ignored_files(self, folder: Optional[Path] = None) -> list:
args = []
Expand Down
2 changes: 1 addition & 1 deletion tests/masonry/builders/test_sdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def test_convert_dependencies():
"A>=1.0,<2.0",
"B>=1.0,<1.1",
"C==1.2.3",
"D @ git+https://github.com/sdispater/d.git@master",
"D @ git+https://github.com/sdispater/d.git",
"E>=1.0,<2.0",
"F>=1.0,<2.0,!=1.3",
]
Expand Down
Loading