From 42bbad443d78575f9839ddd0e1e1a67b29542c0e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Fri, 1 Apr 2022 17:47:10 -0500 Subject: [PATCH 1/3] chore(shortcuts): Clone create_repo_legacy May remove this later --- libvcs/shortcuts.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/libvcs/shortcuts.py b/libvcs/shortcuts.py index 8967ece1..37d9f8ef 100644 --- a/libvcs/shortcuts.py +++ b/libvcs/shortcuts.py @@ -87,3 +87,40 @@ def create_repo_from_pip_url( return SubversionRepo.from_pip_url(pip_url, **kwargs) else: raise InvalidPipURL(pip_url) + + +def create_repo_legacy( + url, vcs, progress_callback=None, *args, **kwargs +) -> Union[GitRepo, MercurialRepo, SubversionRepo]: + r"""Return a object representation of a VCS repository. + + Examples + -------- + >>> from libvcs.shortcuts import create_repo_legacy + >>> + >>> r = create_repo( + ... url='https://www.github.com/you/myrepo', + ... vcs='git', + ... repo_dir='/tmp/myrepo' + ... ) + + >>> r.update_repo() + |myrepo| (git) Repo directory for myrepo (git) does not exist @ \ + /tmp/myrepo + |myrepo| (git) Cloning. + |myrepo| (git) git clone https://www.github.com/tony/myrepo \ + /tmp/myrepo + Cloning into '/tmp/myrepo'... + Checking connectivity... done. + |myrepo| (git) git fetch + |myrepo| (git) git pull + Already up-to-date. + """ + if vcs == "git": + return GitRepo(url, progress_callback=progress_callback, *args, **kwargs) + elif vcs == "hg": + return MercurialRepo(url, progress_callback=progress_callback, *args, **kwargs) + elif vcs == "svn": + return SubversionRepo(url, progress_callback=progress_callback, *args, **kwargs) + else: + raise InvalidVCS("VCS %s is not a valid VCS" % vcs) From 13312514828eb7e4e0be6ecbcd4cf6445ccda216 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Fri, 1 Apr 2022 17:50:53 -0500 Subject: [PATCH 2/3] chore: Use create_repo_legacy --- README.md | 4 ++-- libvcs/shortcuts.py | 2 +- tests/test_base.py | 6 ++++-- tests/test_hg.py | 4 ++-- tests/test_shortcuts.py | 10 ++++++---- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c9ae7a59..44e6f182 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,10 @@ Create a [Repo](https://libvcs.git-pull.com/api.html#creating-a-repo-object) obj to inspect / checkout / update: ```python ->>> from libvcs.shortcuts import create_repo_from_pip_url, create_repo +>>> from libvcs.shortcuts import create_repo_from_pip_url, create_repo_legacy # repo is an object representation of a vcs repository. ->>> r = create_repo(url='https://www.github.com/vcs-python/libtmux', +>>> r = create_repo_legacy(url='https://www.github.com/vcs-python/libtmux', ... vcs='git', ... repo_dir='/tmp/libtmux') diff --git a/libvcs/shortcuts.py b/libvcs/shortcuts.py index 37d9f8ef..a8cbbf85 100644 --- a/libvcs/shortcuts.py +++ b/libvcs/shortcuts.py @@ -98,7 +98,7 @@ def create_repo_legacy( -------- >>> from libvcs.shortcuts import create_repo_legacy >>> - >>> r = create_repo( + >>> r = create_repo_legacy( ... url='https://www.github.com/you/myrepo', ... vcs='git', ... repo_dir='/tmp/myrepo' diff --git a/tests/test_base.py b/tests/test_base.py index 504454bb..06f23133 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -2,11 +2,13 @@ import pathlib from libvcs.base import BaseRepo, convert_pip_url -from libvcs.shortcuts import create_repo +from libvcs.shortcuts import create_repo_legacy def test_repr(): - repo = create_repo(url="file://path/to/myrepo", repo_dir="/hello/", vcs="git") + repo = create_repo_legacy( + url="file://path/to/myrepo", repo_dir="/hello/", vcs="git" + ) str_repo = str(repo) assert "GitRepo" in str_repo diff --git a/tests/test_hg.py b/tests/test_hg.py index 7d267f90..6f8b139d 100644 --- a/tests/test_hg.py +++ b/tests/test_hg.py @@ -5,7 +5,7 @@ import pytest -from libvcs.shortcuts import create_repo, create_repo_from_pip_url +from libvcs.shortcuts import create_repo_from_pip_url, create_repo_legacy from libvcs.util import run, which if not which("hg"): @@ -88,7 +88,7 @@ def test_vulnerability_2022_03_12_command_injection( random_dir = tmp_path / "random" random_dir.mkdir() monkeypatch.chdir(str(random_dir)) - mercurial_repo = create_repo( + mercurial_repo = create_repo_legacy( url="--config=alias.clone=!touch ./HELLO", vcs="hg", repo_dir="./" ) with pytest.raises(Exception): diff --git a/tests/test_shortcuts.py b/tests/test_shortcuts.py index 3b06f13c..25767fd8 100644 --- a/tests/test_shortcuts.py +++ b/tests/test_shortcuts.py @@ -4,7 +4,7 @@ from libvcs import GitRepo, MercurialRepo, SubversionRepo from libvcs.exc import InvalidPipURL, InvalidVCS -from libvcs.shortcuts import create_repo, create_repo_from_pip_url +from libvcs.shortcuts import create_repo_from_pip_url, create_repo_legacy @pytest.mark.parametrize( @@ -67,13 +67,15 @@ def test_create_repo_from_pip_url( ), ], ) -def test_create_repo(tmp_path: pathlib.Path, repo_dict, repo_class, raises_exception): +def test_create_repo_legacy( + tmp_path: pathlib.Path, repo_dict, repo_class, raises_exception +): # add parent_dir via fixture repo_dict["repo_dir"] = tmp_path / "repo_name" if raises_exception: with pytest.raises(raises_exception): - create_repo(**repo_dict) + create_repo_legacy(**repo_dict) else: - repo = create_repo(**repo_dict) + repo = create_repo_legacy(**repo_dict) assert isinstance(repo, repo_class) From 4c54b179cc73a2ace9db45b3d5a6e37f8e9d0053 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Fri, 1 Apr 2022 18:37:16 -0500 Subject: [PATCH 3/3] Commit progress --- libvcs/base.py | 3 +-- libvcs/git.py | 31 +++++++++++++++---------------- libvcs/hg.py | 1 + libvcs/shortcuts.py | 36 ++++++++++++++++++++++++++---------- libvcs/svn.py | 1 + 5 files changed, 44 insertions(+), 28 deletions(-) diff --git a/libvcs/base.py b/libvcs/base.py index aad3e64b..e35c2c2d 100644 --- a/libvcs/base.py +++ b/libvcs/base.py @@ -44,7 +44,7 @@ class BaseRepo(RepoLoggingAdapter): #: vcs app name, e.g. 'git' bin_name = "" - def __init__(self, url, repo_dir, progress_callback=None, *args, **kwargs): + def __init__(self, repo_dir, progress_callback=None, *args, **kwargs): """ Parameters ---------- @@ -58,7 +58,6 @@ def __init__(self, url, repo_dir, progress_callback=None, *args, **kwargs): >>> create_repo(..., progress_callback=progress_cb) """ self.progress_callback = progress_callback - self.url = url self.parent_dir = os.path.dirname(repo_dir) self.repo_name = os.path.basename(os.path.normpath(repo_dir)) self.path = repo_dir diff --git a/libvcs/git.py b/libvcs/git.py index e6f355bf..021022d6 100644 --- a/libvcs/git.py +++ b/libvcs/git.py @@ -134,17 +134,20 @@ class RemoteDict(TypedDict): RemotesArgs = Union[None, FullRemoteDict, Dict[str, str]] +class GitOptions(TypedDict): + remotes: RemotesArgs + + class GitRepo(BaseRepo): bin_name = "git" schemes = ("git", "git+http", "git+https", "git+ssh", "git+git", "git+file") - def __init__(self, url: str, repo_dir: str, remotes: RemotesArgs = None, **kwargs): + def __init__(self, repo_dir: str, options: GitOptions, *args, **kwargs): """A git repository. Parameters ---------- - url : str - URL of repo + options : FullRemoteDict tls_verify : bool Should certificate for https be checked (default False) @@ -190,20 +193,16 @@ def __init__(self, url: str, repo_dir: str, remotes: RemotesArgs = None, **kwarg if "tls_verify" not in kwargs: self.tls_verify = False - self._remotes: Union[FullRemoteDict, None] - - if remotes is None: - self._remotes: FullRemoteDict = {"origin": url} - elif isinstance(remotes, dict): - self._remotes: FullRemoteDict = remotes - for remote_name, url in remotes.items(): - if isinstance(str, dict): - remotes[remote_name] = { - "fetch": url, - "push": url, - } + self._remotes: FullRemoteDict = options["remotes"] + for remote_name, url in self._remotes.items(): + if isinstance(str, dict): + self._remotes[remote_name] = { + "fetch": url, + "push": url, + } - BaseRepo.__init__(self, url, repo_dir, **kwargs) + BaseRepo.__init__(self, repo_dir, options, *args, **kwargs) + self.url = self._remotes["origin"]["fetch"] @classmethod def from_pip_url(cls, pip_url, *args, **kwargs): diff --git a/libvcs/hg.py b/libvcs/hg.py index a62879ca..5c956fcb 100644 --- a/libvcs/hg.py +++ b/libvcs/hg.py @@ -22,6 +22,7 @@ class MercurialRepo(BaseRepo): def __init__(self, url, repo_dir, **kwargs): BaseRepo.__init__(self, url, repo_dir, **kwargs) + self.url = url def obtain(self, *args, **kwargs): self.ensure_dir() diff --git a/libvcs/shortcuts.py b/libvcs/shortcuts.py index a8cbbf85..e88790be 100644 --- a/libvcs/shortcuts.py +++ b/libvcs/shortcuts.py @@ -17,18 +17,32 @@ def create_repo( - url, vcs, progress_callback=None, *args, **kwargs + vcs: DEFAULT_VCS_LITERAL, + repo_dir: str, + options: Dict, + progress_callback=None, + *args, + **kwargs ) -> Union[GitRepo, MercurialRepo, SubversionRepo]: r"""Return a object representation of a VCS repository. + Parameters + ---------- + progress_callback : func + See :class:`libvcs.base.BaseRepo` + Examples -------- >>> from libvcs.shortcuts import create_repo >>> >>> r = create_repo( - ... url='https://www.github.com/you/myrepo', ... vcs='git', - ... repo_dir='/tmp/myrepo' + ... repo_dir='/tmp/myrepo', + ... options={ # VCS-specific params + ... 'remotes': { + ... 'origin': 'https://www.github.com/you/myrepo' + ... } + ... } ... ) >>> r.update_repo() @@ -43,13 +57,15 @@ def create_repo( |myrepo| (git) git pull Already up-to-date. """ - if vcs == "git": - return GitRepo(url, progress_callback=progress_callback, *args, **kwargs) - elif vcs == "hg": - return MercurialRepo(url, progress_callback=progress_callback, *args, **kwargs) - elif vcs == "svn": - return SubversionRepo(url, progress_callback=progress_callback, *args, **kwargs) - else: + try: + return DEFAULT_VCS_CLASS_MAP[vcs]( + repo_dir=repo_dir, + options=options, + progress_callback=progress_callback, + *args, + **kwargs + ) + except KeyError: raise InvalidVCS("VCS %s is not a valid VCS" % vcs) diff --git a/libvcs/svn.py b/libvcs/svn.py index 0f088a8b..b5372fc4 100644 --- a/libvcs/svn.py +++ b/libvcs/svn.py @@ -55,6 +55,7 @@ def __init__(self, url, repo_dir, **kwargs): self.svn_trust_cert = False self.rev = kwargs.get("rev") + self.url = url BaseRepo.__init__(self, url, repo_dir, **kwargs) def _user_pw_args(self):