@@ -195,6 +195,10 @@ def is_pidfile(cls, exit_code: Optional[int]) -> bool:
195
195
DEFAULT_WAIT_TICK : float = 30.0
196
196
DEFAULT_WAIT_TICK_INCREASE : float = 1.0
197
197
198
+ # Defaults for GIT attempts and interval
199
+ DEFAULT_GIT_CLONE_ATTEMPTS : int = 3
200
+ DEFAULT_GIT_CLONE_INTERVAL : int = 10
201
+
198
202
# A stand-in variable for generic use.
199
203
T = TypeVar ('T' )
200
204
@@ -1777,7 +1781,7 @@ class RetryError(GeneralError):
1777
1781
""" Retries unsuccessful """
1778
1782
1779
1783
def __init__ (self , label : str , causes : list [Exception ]) -> None :
1780
- super ().__init__ (f"Retries of { label } unsuccessful." , causes )
1784
+ super ().__init__ (f"Retries of ' { label } ' unsuccessful." , causes )
1781
1785
1782
1786
1783
1787
# Step exceptions
@@ -4868,41 +4872,88 @@ def distgit_download(
4868
4872
4869
4873
4870
4874
def git_clone (
4875
+ * ,
4871
4876
url : str ,
4872
4877
destination : Path ,
4873
- common : Common ,
4874
- env : Optional [EnvironmentType ] = None ,
4875
4878
shallow : bool = False ,
4876
4879
can_change : bool = True ,
4877
- ) -> CommandOutput :
4878
- """
4879
- Git clone url to destination, retry without shallow if necessary
4880
+ env : Optional [EnvironmentType ] = None ,
4881
+ attempts : Optional [int ] = None ,
4882
+ interval : Optional [int ] = None ,
4883
+ timeout : Optional [int ] = None ,
4884
+ logger : tmt .log .Logger ) -> CommandOutput :
4885
+ """
4886
+ Clone git repository from provided url to the destination directory
4887
+
4888
+ :param url: Source URL of the git repository.
4889
+ :param destination: Full path to the destination directory.
4890
+ :param shallow: For ``shallow=True`` first try to clone repository
4891
+ using ``--depth=1`` option. If not successful clone repo with
4892
+ the whole history.
4893
+ :param can_change: URL can be modified with hardcoded rules. Use
4894
+ ``can_change=False`` to disable rewrite rules.
4895
+ :param env: Environment provided to the ``git clone`` process.
4896
+ :param attempts: Number of tries to call the function.
4897
+ :param interval: Amount of seconds to wait before a new try.
4898
+ :param timeout: Overall maximum time in seconds to clone the repo.
4899
+ :param logger: A Logger instance to be used for logging.
4900
+ :returns: Command output, bundled in a :py:class:`CommandOutput` tuple.
4901
+ """
4902
+
4903
+ def get_env (env : str , default_value : Optional [int ]) -> Optional [int ]:
4904
+ """ Check environment variable, convert to integer """
4905
+ value = os .getenv (env , None )
4906
+ if value is None :
4907
+ return default_value
4908
+ try :
4909
+ return int (value )
4910
+ except ValueError :
4911
+ raise GeneralError (f"Invalid '{ env } ' value, should be 'int', got '{ value } '." )
4880
4912
4881
- For shallow=True attempt to clone repository using --depth=1 option first.
4882
- If not successful attempt to clone whole repo.
4913
+ def clone_the_repo (
4914
+ url : str ,
4915
+ destination : Path ,
4916
+ shallow : bool = False ,
4917
+ env : Optional [EnvironmentType ] = None ,
4918
+ timeout : Optional [int ] = None ) -> CommandOutput :
4919
+ """ Clone the repo, handle history depth """
4883
4920
4884
- Common instance is used to run the command for appropriate logging.
4885
- Environment is updated by 'env' dictionary.
4921
+ depth = ['--depth=1' ] if shallow else []
4922
+ return Command ('git' , 'clone' , * depth , url , destination ).run (
4923
+ cwd = Path ('/' ), env = env , timeout = timeout , logger = logger )
4886
4924
4887
- Url can be modified with hardcode rules unless can_change=False is set.
4888
- """
4889
- depth = [ '--depth=1' ] if shallow else []
4925
+ timeout = timeout or get_env ( 'TMT_GIT_CLONE_TIMEOUT' , None )
4926
+ attempts = attempts or cast ( int , get_env ( 'TMT_GIT_CLONE_ATTEMPTS' , DEFAULT_GIT_CLONE_ATTEMPTS ))
4927
+ interval = interval or cast ( int , get_env ( 'TMT_GIT_CLONE_INTERVAL' , DEFAULT_GIT_CLONE_INTERVAL ))
4890
4928
4929
+ # Update url only once
4891
4930
if can_change :
4892
4931
url = clonable_git_url (url )
4893
- try :
4894
- return common .run (
4895
- Command (
4896
- 'git' , 'clone' ,
4897
- * depth ,
4898
- url , destination
4899
- ), env = env )
4900
- except RunError :
4901
- if not shallow :
4902
- # Do not retry if shallow was not used
4903
- raise
4904
- # Git server might not support shallow cloning, try again (do not modify url)
4905
- return git_clone (url , destination , common , env , shallow = False , can_change = False )
4932
+
4933
+ # Do an extra shallow clone first
4934
+ if shallow :
4935
+ try :
4936
+ return clone_the_repo (
4937
+ shallow = True ,
4938
+ url = url ,
4939
+ destination = destination ,
4940
+ env = env ,
4941
+ timeout = timeout )
4942
+ except RunError :
4943
+ logger .debug (f"Shallow clone of '{ url } ' failed, let's try with the full history." )
4944
+
4945
+ # Finish with whatever number attempts requested (deep)
4946
+ return retry (
4947
+ func = clone_the_repo ,
4948
+ attempts = attempts ,
4949
+ interval = interval ,
4950
+ label = f"git clone { url } { destination } " ,
4951
+ url = url ,
4952
+ destination = destination ,
4953
+ shallow = False ,
4954
+ env = env ,
4955
+ timeout = timeout ,
4956
+ logger = logger )
4906
4957
4907
4958
4908
4959
# ignore[type-arg]: base class is a generic class, but we cannot list its parameter type, because
0 commit comments