From cb95d2be09ce4880a8e3ae2d2bbbb86f755b7341 Mon Sep 17 00:00:00 2001 From: paugier Date: Mon, 5 Oct 2020 17:34:25 +0200 Subject: [PATCH 1/2] Add MercurialRepoProvider --- binderhub/app.py | 3 +- binderhub/event-schemas/launch.json | 3 +- binderhub/main.py | 1 + binderhub/repoproviders.py | 43 +++++++++++++++++++++++++++ binderhub/static/js/index.js | 4 +++ binderhub/templates/index.html | 1 + binderhub/tests/test_repoproviders.py | 28 ++++++++++++++++- 7 files changed, 80 insertions(+), 3 deletions(-) diff --git a/binderhub/app.py b/binderhub/app.py index 09f26ce4c..358c5347a 100755 --- a/binderhub/app.py +++ b/binderhub/app.py @@ -35,7 +35,7 @@ from .repoproviders import (GitHubRepoProvider, GitRepoProvider, GitLabRepoProvider, GistRepoProvider, ZenodoProvider, FigshareProvider, HydroshareProvider, - DataverseProvider) + DataverseProvider, MercurialRepoProvider) from .metrics import MetricsHandler from .utils import ByteSpecification, url_path_join @@ -420,6 +420,7 @@ def _add_slash(self, proposal): 'figshare': FigshareProvider, 'hydroshare': HydroshareProvider, 'dataverse': DataverseProvider, + 'hg': MercurialRepoProvider, }, config=True, help=""" diff --git a/binderhub/event-schemas/launch.json b/binderhub/event-schemas/launch.json index 7e8a22a1f..cefe809f8 100755 --- a/binderhub/event-schemas/launch.json +++ b/binderhub/event-schemas/launch.json @@ -14,7 +14,8 @@ "Zenodo", "Figshare", "Hydroshare", - "Dataverse" + "Dataverse", + "Mercurial" ], "description": "Provider for the repository being launched" }, diff --git a/binderhub/main.py b/binderhub/main.py index 329634238..7f837af8e 100755 --- a/binderhub/main.py +++ b/binderhub/main.py @@ -19,6 +19,7 @@ "figshare": "Figshare", "hydroshare": "Hydroshare", "dataverse": "Dataverse", + "hg": "Mercurial", } diff --git a/binderhub/repoproviders.py b/binderhub/repoproviders.py index 6a48a283e..4b10b190e 100755 --- a/binderhub/repoproviders.py +++ b/binderhub/repoproviders.py @@ -899,3 +899,46 @@ async def get_resolved_spec(self): def get_build_slug(self): return self.gist_id + + +class MercurialRepoProvider(GitRepoProvider): + """Bare bones Mercurial repo provider. + + Users must provide a spec of the following form. + + / + / + + eg: + https://foss.heptapod.net/pypy/pypy/release-pypy3.7-v7.3.2rc3 + https://foss.heptapod.net/graphics/plot-covid19-fr/8e29b5b0064d + + """ + + name = Unicode("Mercurial") + + @gen.coroutine + def get_resolved_ref(self): + if hasattr(self, 'resolved_ref'): + return self.resolved_ref + + try: + # Check if the reference is a valid SHA hash + self.sha1_validate(self.unresolved_ref) + except ValueError: + # The ref is a head/tag and we resolve it using `hg identify` + command = ["hg", "identify", self.repo, "-r", self.unresolved_ref, "-T", "{id}"] + result = subprocess.run(command, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if result.returncode: + raise RuntimeError("Unable to run hg identify to get the `resolved_ref`: {}".format(result.stderr)) + if not result.stdout: + raise ValueError("The specified branch, tag or commit SHA ('{}') was not found on the remote repository." + .format(self.unresolved_ref)) + resolved_ref = result.stdout.strip() + self.sha1_validate(resolved_ref) + self.resolved_ref = resolved_ref + else: + # The ref already was a valid SHA hash + self.resolved_ref = self.unresolved_ref + + return self.resolved_ref diff --git a/binderhub/static/js/index.js b/binderhub/static/js/index.js index 8f9878d17..265c205ec 100755 --- a/binderhub/static/js/index.js +++ b/binderhub/static/js/index.js @@ -99,6 +99,10 @@ function updateRepoText() { $("#ref").prop("disabled", true); $("label[for=ref]").prop("disabled", true); } + else if (provider === "hg") { + text = "Arbitrary Mercurial repository URL (http://hg.example.com/repo)"; + tag_text = "Mercurial branch, tag, topic or commit SHA"; + } $("#repository").attr('placeholder', text); $("label[for=repository]").text(text); $("#ref").attr('placeholder', tag_text); diff --git a/binderhub/templates/index.html b/binderhub/templates/index.html index 75f49d47a..f7c73c0d3 100755 --- a/binderhub/templates/index.html +++ b/binderhub/templates/index.html @@ -56,6 +56,7 @@

Build and launch a repository

+ diff --git a/binderhub/tests/test_repoproviders.py b/binderhub/tests/test_repoproviders.py index 223a339c4..f0c33df06 100755 --- a/binderhub/tests/test_repoproviders.py +++ b/binderhub/tests/test_repoproviders.py @@ -7,7 +7,7 @@ from binderhub.repoproviders import ( tokenize_spec, strip_suffix, GitHubRepoProvider, GitRepoProvider, GitLabRepoProvider, GistRepoProvider, ZenodoProvider, FigshareProvider, - HydroshareProvider, DataverseProvider + HydroshareProvider, DataverseProvider, MercurialRepoProvider ) @@ -404,3 +404,29 @@ def test_gist_secret(): provider = GistRepoProvider(spec=spec, allow_secret_gist=True) assert IOLoop().run_sync(provider.get_resolved_ref) is not None + + +@pytest.mark.parametrize('url,unresolved_ref,resolved_ref', [ + ['https://foss.heptapod.net/graphics/plot-covid19-fr', + '3f1209cb613a', + '3f1209cb613a1286e555d8cabe722c1be2a6f123'], + ['https://foss.heptapod.net/pypy/pypy', + 'release-pypy3.7-v7.3.2rc3', + '87875bf2dfd8fe682a49e010f6636a871b1308e6'] +]) +def test_mercurial_ref(url, unresolved_ref, resolved_ref): + spec = '{}/{}'.format( + quote(url, safe=''), + quote(unresolved_ref) + ) + provider = MercurialRepoProvider(spec=spec) + slug = provider.get_build_slug() + assert slug == url + full_url = provider.get_repo_url() + assert full_url == url + ref = IOLoop().run_sync(provider.get_resolved_ref) + assert ref == resolved_ref + ref_url = IOLoop().run_sync(provider.get_resolved_ref_url) + assert ref_url == full_url + resolved_spec = IOLoop().run_sync(provider.get_resolved_spec) + assert resolved_spec == quote(url, safe='') + f'/{resolved_ref}' From eb4890ec50fdca3f8ba552313d7e9e4c252c7b2b Mon Sep 17 00:00:00 2001 From: paugier Date: Mon, 5 Oct 2020 17:37:25 +0200 Subject: [PATCH 2/2] doc for MercurialRepoProvider --- doc/developer/repoproviders.rst | 2 ++ doc/reference/repoproviders.rst | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/doc/developer/repoproviders.rst b/doc/developer/repoproviders.rst index 2b58a41ac..e5a040997 100755 --- a/doc/developer/repoproviders.rst +++ b/doc/developer/repoproviders.rst @@ -38,6 +38,8 @@ Currently supported providers, their prefixes and specs are: +------------+--------------------+-------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ | Git | ``git`` | ``/`` | A generic repository provider for URLs that point directly to a git repository. | +------------+--------------------+-------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | Mercurial | ``hg`` | ``/`` | A generic repository provider for URLs that point directly to a Mercurial repository. | + +------------+--------------------+-------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ Adding a new repository provider ================================ diff --git a/doc/reference/repoproviders.rst b/doc/reference/repoproviders.rst index d0f5ca37c..b6b46ddf8 100755 --- a/doc/reference/repoproviders.rst +++ b/doc/reference/repoproviders.rst @@ -71,3 +71,10 @@ Module: :mod:`binderhub.repoproviders` .. autoconfigurable:: GitRepoProvider :members: + + +:class:`MercurialRepoProvider` +--------------------------- + +.. autoconfigurable:: MercurialRepoProvider + :members: