Skip to content

Commit 2b0723c

Browse files
authored
Dulwich upgrade (#10674)
1 parent 8a1b011 commit 2b0723c

File tree

6 files changed

+116
-88
lines changed

6 files changed

+116
-88
lines changed

poetry.lock

Lines changed: 38 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ dependencies = [
88
"build (>=1.2.1,<2.0.0)",
99
"cachecontrol[filecache] (>=0.14.0,<0.15.0)",
1010
"cleo (>=2.1.0,<3.0.0)",
11-
"dulwich (>=0.24.0,<0.25.0)",
11+
"dulwich (>=0.25.0,<0.26.0)",
1212
"fastjsonschema (>=2.18.0,<3.0.0)",
1313
"installer (>=0.7.0,<0.8.0)",
1414
"keyring (>=25.1.0,<26.0.0)",

src/poetry/vcs/git/backend.py

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
from dulwich.errors import NotGitRepository
2121
from dulwich.file import FileLocked
2222
from dulwich.index import IndexEntry
23-
from dulwich.refs import ANNOTATED_TAG_SUFFIX
23+
from dulwich.objects import ObjectID
24+
from dulwich.protocol import PEELED_TAG_SUFFIX
25+
from dulwich.refs import Ref
2426
from dulwich.repo import Repo
2527

2628
from poetry.console.exceptions import PoetryRuntimeError
@@ -76,18 +78,18 @@ def is_revision_sha(revision: str | None) -> bool:
7678
return re.match(r"^\b[0-9a-f]{5,40}\b$", revision or "") is not None
7779

7880

79-
def annotated_tag(ref: str | bytes) -> bytes:
81+
def peeled_tag(ref: str | bytes) -> Ref:
8082
if isinstance(ref, str):
8183
ref = ref.encode("utf-8")
82-
return ref + ANNOTATED_TAG_SUFFIX
84+
return Ref(ref + PEELED_TAG_SUFFIX)
8385

8486

8587
@dataclasses.dataclass
8688
class GitRefSpec:
8789
branch: str | None = None
8890
revision: str | None = None
8991
tag: str | None = None
90-
ref: bytes = dataclasses.field(default_factory=lambda: b"HEAD")
92+
ref: Ref = dataclasses.field(default_factory=lambda: Ref(b"HEAD"))
9193

9294
def resolve(self, remote_refs: FetchPackResult, repo: Repo) -> None:
9395
"""
@@ -104,7 +106,7 @@ def _normalise(self, remote_refs: FetchPackResult, repo: Repo) -> None:
104106
"""
105107
if self.revision:
106108
ref = f"refs/tags/{self.revision}".encode()
107-
if ref in remote_refs.refs or annotated_tag(ref) in remote_refs.refs:
109+
if ref in remote_refs.refs or peeled_tag(ref) in remote_refs.refs:
108110
# this is a tag, incorrectly specified as a revision, tags take priority
109111
self.tag = self.revision
110112
self.revision = None
@@ -120,7 +122,7 @@ def _normalise(self, remote_refs: FetchPackResult, repo: Repo) -> None:
120122
and f"refs/heads/{self.branch}".encode() not in remote_refs.refs
121123
and (
122124
f"refs/tags/{self.branch}".encode() in remote_refs.refs
123-
or annotated_tag(f"refs/tags/{self.branch}") in remote_refs.refs
125+
or peeled_tag(f"refs/tags/{self.branch}") in remote_refs.refs
124126
)
125127
):
126128
# this is a tag incorrectly specified as a branch
@@ -131,7 +133,7 @@ def _normalise(self, remote_refs: FetchPackResult, repo: Repo) -> None:
131133
# revision is a short sha, resolve to full sha
132134
short_sha = self.revision.encode("utf-8")
133135
for sha in remote_refs.refs.values():
134-
if sha.startswith(short_sha):
136+
if sha is not None and sha.startswith(short_sha):
135137
self.revision = sha.decode("utf-8")
136138
return
137139

@@ -145,24 +147,25 @@ def _set_head(self, remote_refs: FetchPackResult) -> None:
145147
Internal helper method to populate ref and set it's sha as the remote's head
146148
and default ref.
147149
"""
148-
self.ref = remote_refs.symrefs[b"HEAD"]
150+
self.ref = remote_refs.symrefs[Ref(b"HEAD")]
149151

152+
head: ObjectID | None
150153
if self.revision:
151-
head = self.revision.encode("utf-8")
154+
head = ObjectID(self.revision.encode("utf-8"))
152155
else:
153156
if self.tag:
154-
ref = f"refs/tags/{self.tag}".encode()
155-
annotated = annotated_tag(ref)
156-
self.ref = annotated if annotated in remote_refs.refs else ref
157+
ref = Ref(f"refs/tags/{self.tag}".encode())
158+
peeled = peeled_tag(ref)
159+
self.ref = peeled if peeled in remote_refs.refs else ref
157160
elif self.branch:
158161
self.ref = (
159-
self.branch.encode("utf-8")
162+
Ref(self.branch.encode("utf-8"))
160163
if self.is_ref
161-
else f"refs/heads/{self.branch}".encode()
164+
else Ref(f"refs/heads/{self.branch}".encode())
162165
)
163166
head = remote_refs.refs[self.ref]
164167

165-
remote_refs.refs[self.ref] = remote_refs.refs[b"HEAD"] = head
168+
remote_refs.refs[self.ref] = remote_refs.refs[Ref(b"HEAD")] = head
166169

167170
@property
168171
def key(self) -> str:
@@ -216,7 +219,7 @@ def get_remote_url(repo: Repo, remote: str = "origin") -> str:
216219
@staticmethod
217220
def get_revision(repo: Repo) -> str:
218221
with repo:
219-
return repo.get_peeled(b"HEAD").decode("utf-8")
222+
return repo.get_peeled(Ref(b"HEAD")).decode("utf-8")
220223

221224
@classmethod
222225
def info(cls, repo: Repo | Path) -> GitRepoLocalInfo:
@@ -234,21 +237,24 @@ def _fetch_remote_refs(cls, url: str, local: Repo) -> FetchPackResult:
234237
client: GitClient
235238
path: str
236239

237-
kwargs: dict[str, str] = {}
238240
credentials = get_default_authenticator().get_credentials_for_git_url(url=url)
239241

242+
username = None
243+
password = None
240244
if credentials.password and credentials.username:
241245
# we do this conditionally as otherwise, dulwich might complain if these
242246
# parameters are passed in for an ssh url
243-
kwargs["username"] = credentials.username
244-
kwargs["password"] = credentials.password
247+
username = credentials.username
248+
password = credentials.password
245249

246250
config = local.get_config_stack()
247-
client, path = get_transport_and_path(url, config=config, **kwargs)
251+
client, path = get_transport_and_path(
252+
url, config=config, username=username, password=password
253+
)
248254

249255
with local:
250256
result: FetchPackResult = client.fetch(
251-
path,
257+
path.encode(),
252258
local,
253259
determine_wants=local.object_store.determine_wants_all,
254260
)
@@ -335,7 +341,9 @@ def _clone(cls, url: str, refspec: GitRefSpec, target: Path) -> Repo:
335341

336342
try:
337343
# ensure local HEAD matches remote
338-
local.refs[b"HEAD"] = remote_refs.refs[b"HEAD"]
344+
ref = remote_refs.refs[Ref(b"HEAD")]
345+
if ref is not None:
346+
local.refs[Ref(b"HEAD")] = ref
339347
except ValueError:
340348
raise PoetryRuntimeError.create(
341349
reason=f"<error>Failed to clone {url} at '{refspec.key}', verify ref exists on remote.</>",
@@ -349,30 +357,36 @@ def _clone(cls, url: str, refspec: GitRefSpec, target: Path) -> Repo:
349357

350358
if refspec.is_ref:
351359
# set ref to current HEAD
352-
local.refs[refspec.ref] = local.refs[b"HEAD"]
360+
local.refs[refspec.ref] = local.refs[Ref(b"HEAD")]
353361

354362
for base, prefix in {
355-
(b"refs/remotes/origin", b"refs/heads/"),
356-
(b"refs/tags", b"refs/tags"),
363+
(Ref(b"refs/remotes/origin"), b"refs/heads/"),
364+
(Ref(b"refs/tags"), b"refs/tags"),
357365
}:
358366
try:
359367
local.refs.import_refs(
360368
base=base,
361369
other={
362-
n[len(prefix) :]: v
370+
Ref(n[len(prefix) :]): v
363371
for (n, v) in remote_refs.refs.items()
364-
if n.startswith(prefix) and not n.endswith(ANNOTATED_TAG_SUFFIX)
372+
if n.startswith(prefix)
373+
and not n.endswith(PEELED_TAG_SUFFIX)
374+
and v is not None
365375
},
366376
)
367377
except FileLocked as e:
368378

369-
def to_str(path: bytes) -> str:
370-
return path.decode().replace(os.sep * 2, os.sep)
379+
def to_str(path: bytes | str) -> str:
380+
if isinstance(path, bytes):
381+
path = path.decode()
382+
return path.replace(os.sep * 2, os.sep)
371383

372384
raise PoetryRuntimeError.create(
385+
# <https://github.com/jelmer/dulwich/pull/2045> should clean up the
386+
# ignore.
373387
reason=(
374388
f"<error>Failed to clone {url} at '{refspec.key}',"
375-
f" unable to acquire file lock for {to_str(e.filename)}.</>"
389+
f" unable to acquire file lock for {to_str(e.filename)}.</>" # type: ignore[arg-type]
376390
),
377391
info=[
378392
ERROR_MESSAGE_NOTE,
@@ -519,7 +533,9 @@ def clone(
519533

520534
with current_repo:
521535
# we use peeled sha here to ensure tags are resolved consistently
522-
current_sha = current_repo.get_peeled(b"HEAD").decode("utf-8")
536+
current_sha = current_repo.get_peeled(Ref(b"HEAD")).decode(
537+
"utf-8"
538+
)
523539
except (NotGitRepository, AssertionError, KeyError):
524540
# something is wrong with the current checkout, clean it
525541
remove_directory(target, force=True)

0 commit comments

Comments
 (0)