2020from dulwich .errors import NotGitRepository
2121from dulwich .file import FileLocked
2222from 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
2426from dulwich .repo import Repo
2527
2628from 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
8688class 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