From a8236c96a8f8482ba511d03e0f5141b1b19721ee Mon Sep 17 00:00:00 2001 From: Trevor Spreadbury Date: Wed, 20 Jul 2022 00:45:32 -0500 Subject: [PATCH 1/2] Create a RepoProvider that uses an API to proxy another RepoProvider ProxyRepoProvider queries an API endpoint on instantiation with the provided 'spec' as the resource id. The API must return both a 'provider' and an updated 'spec'. Attributes are then copied from the proper RepoProvider. The initializatin returns the proper RepoProvider and updated kwargs --- binderhub/app.py | 2 ++ binderhub/main.py | 1 + binderhub/repoproviders.py | 70 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/binderhub/app.py b/binderhub/app.py index 47198e60c..61de947f4 100644 --- a/binderhub/app.py +++ b/binderhub/app.py @@ -62,6 +62,7 @@ HydroshareProvider, RepoProvider, ZenodoProvider, + ProxyRepoProvider ) from .utils import ByteSpecification, url_path_join @@ -517,6 +518,7 @@ def _default_build_namespace(self): "figshare": FigshareProvider, "hydroshare": HydroshareProvider, "dataverse": DataverseProvider, + "proxy": ProxyRepoProvider, }, config=True, help=""" diff --git a/binderhub/main.py b/binderhub/main.py index 6d302972e..d2a3bf27d 100644 --- a/binderhub/main.py +++ b/binderhub/main.py @@ -21,6 +21,7 @@ "figshare": "Figshare", "hydroshare": "Hydroshare", "dataverse": "Dataverse", + "proxy": "Proxy" } diff --git a/binderhub/repoproviders.py b/binderhub/repoproviders.py index 256d4985d..786180bfd 100644 --- a/binderhub/repoproviders.py +++ b/binderhub/repoproviders.py @@ -1036,3 +1036,73 @@ async def get_resolved_spec(self): def get_build_slug(self): return self.gist_id + +class ProxyRepoProvider(RepoProvider): + """RepoProvider that acts as a proxy for another provider + + Uses an external API to determine desired provider and spec given + an input spec that acts as a repo id in the external API.""" + + name = Unicode("Proxy") + + display_name = "Proxy" + + api_url = Unicode( + config=True, + help="""The path to the external API + Requests to api_url/spec should return a json with a spec + field and a provider field that maps to one of the predefined + repoproviders. + """ + ) + + labels = { + "text": "URL to API endpoint returning project's spec and provider", + "tag_text": "Git ref (branch, tag, or commit)", + "ref_prop_disabled": True, + "label_prop_disabled": True, + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.provider, kwargs = self.resolve_provider(kwargs) + import inspect + for name, value in inspect.getmembers(self.provider(*args, **kwargs)): + if name in ["__dict__", "labels"]: + continue + try: + setattr(self, name, value) + except Exception as e: + self.log.debug(f"Error copying {e}") + self.log.debug(f"Copied attributes from {self.provider} instance") + + def resolve_provider(self, kwargs): + import requests + spec = kwargs["spec"] + # remove auto generated commit + spec = spec.split("/")[0] + project_url = f"{self.api_url}/{spec}" + self.log.debug(f"Fetching {project_url}") + project_metadata = requests.get(project_url).json() + try: + provider = project_metadata["provider"] + spec = project_metadata["spec"] + except AttributeError as e: + msg = f"""API endpoint {project_url} must return json with + 'provider' and 'spec' attributes""" + raise ValueError(msg) + providers = { + 'gh': GitHubRepoProvider, + 'gist': GistRepoProvider, + 'git': GitRepoProvider, + 'gl': GitLabRepoProvider, + 'zenodo': ZenodoProvider, + 'figshare': FigshareProvider, + 'hydroshare': HydroshareProvider, + 'dataverse': DataverseProvider, + } + provider_class = providers[provider] + self.log.debug(f"Using {provider} provider with spec {spec}") + kwargs["spec"] = spec + + return provider_class, kwargs \ No newline at end of file From 34312f87abd230d074f94615d12d04cfa46d4911 Mon Sep 17 00:00:00 2001 From: Trevor Spreadbury Date: Thu, 21 Jul 2022 08:21:48 -0500 Subject: [PATCH 2/2] add new provider prefix to ui, index javascript --- binderhub/event-schemas/launch.json | 3 ++- binderhub/static/js/index.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/binderhub/event-schemas/launch.json b/binderhub/event-schemas/launch.json index 16e277cf4..7323d8ace 100644 --- a/binderhub/event-schemas/launch.json +++ b/binderhub/event-schemas/launch.json @@ -14,7 +14,8 @@ "Zenodo", "Figshare", "Hydroshare", - "Dataverse" + "Dataverse", + "Proxy" ], "description": "Provider for the repository being launched" }, diff --git a/binderhub/static/js/index.js b/binderhub/static/js/index.js index 6d2673500..d85646034 100644 --- a/binderhub/static/js/index.js +++ b/binderhub/static/js/index.js @@ -114,7 +114,7 @@ function getBuildFormValues() { let ref = $('#ref').val().trim() || $("#ref").attr("placeholder"); if (providerPrefix === 'zenodo' || providerPrefix === 'figshare' || providerPrefix === 'dataverse' || - providerPrefix === 'hydroshare') { + providerPrefix === 'hydroshare' || providerPrefix === 'proxy') { ref = ""; } const path = $('#filepath').val().trim();