"""'Git type Path Source."""from__future__importannotationsimportloggingimportshutilimportsubprocessimporttempfilefrompathlibimportPathfromtypingimportAnyfrom.sourceimportSourceLOGGER=logging.getLogger(__name__)
[docs]classGit(Source):"""Git Path Source. The Git path source can be tasked with cloning a remote repository and pointing to a specific module folder (or the root). """
[docs]def__init__(self,*,arguments:dict[str,str]|None=None,location:str="",uri:str="",**kwargs:Any,)->None:"""Git Path Source. Args: arguments: A reference can be passed along via the arguments so that a specific version of the repository is cloned. **commit**, **tag**, **branch** are all valid keys with respective output location: The relative location to the root of the repository where the module resides. Leaving this as an empty string, ``/``, or ``./`` will have runway look in the root folder. uri: The uniform resource identifier that targets the remote git repository **kwargs: Arbitrary keyword arguments. """self.args=argumentsor{}self.uri=uriself.location=locationsuper().__init__(**kwargs)
[docs]deffetch(self)->Path:"""Retrieve the git repository from it's remote location."""fromgit.repoimportReporef=self.__determine_git_ref()dir_name="_".join([self.sanitize_git_path(self.uri),ref])cached_dir_path=self.cache_dir/dir_nameifcached_dir_path.exists():returncached_dir_pathwithtempfile.TemporaryDirectory()astmpdirname:tmp_repo_path=Path(tmpdirname)/dir_namewithRepo.clone_from(self.uri,str(tmp_repo_path))asrepo:repo.head.set_reference(ref)repo.head.reset(index=True,working_tree=True)shutil.move(str(tmp_repo_path),self.cache_dir)returncached_dir_path
def__git_ls_remote(self,ref:str)->str:"""List remote repositories based on uri and ref received. Keyword Args: ref (str): The git reference value """cmd=["git","ls-remote",self.uri,ref]LOGGER.debug("getting commit ID from repo: %s"," ".join(cmd))ls_remote_output=subprocess.check_output(cmd)ifb"\t"inls_remote_output:commit_id=ls_remote_output.split(b"\t",maxsplit=1)[0].decode()LOGGER.debug("matching commit id found: %s",commit_id)returncommit_idraiseValueError(f'Ref "{ref}" not found for repo {self.uri}.')def__determine_git_ls_remote_ref(self)->str:"""Determine remote ref, defaulting to HEAD unless a branch is found."""ref="HEAD"ifself.args.get("branch"):ref=f"refs/heads/{self.args['branch']}"returnrefdef__determine_git_ref(self)->str:"""Determine the git reference code."""ref_config_keys=sum(bool(self.args.get(i))foriin["commit","tag","branch"])ifref_config_keys>1:raiseValueError("Fetching remote git sources failed: conflicting revisions ""(e.g. 'commit', 'tag', 'branch') specified for a package source")ifself.args.get("commit"):returnself.args["commit"]ifself.args.get("tag"):returnself.args["tag"]returnself.__git_ls_remote(self.__determine_git_ls_remote_ref())
[docs]@classmethoddefsanitize_git_path(cls,path:str)->str:"""Sanitize the git path for folder/file assignment. Keyword Args: path: The path string to be sanitized """dir_name=pathsplit=path.split("//")domain=split[len(split)-1]ifdomain.endswith(".git"):dir_name=domain[:-4]returncls.sanitize_directory_path(dir_name)