diff --git a/.gitignore b/.gitignore index 69fd43812..3a8687f6e 100644 --- a/.gitignore +++ b/.gitignore @@ -112,4 +112,5 @@ travis helm-chart/travis-binder.yaml # Federation data page -doc/federation/data-federation.txt \ No newline at end of file +doc/federation/data-federation.txt +.vscode/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 756dc1cda..adf703e2d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -108,7 +108,7 @@ every day development. * Start and stop minikube with `minikube start` and `minikube stop`. * Install JupyterHub in minikube with helm `./testing/minikube/install-hub` -* Setup docker to use the same docker daemon as your minikube cluster `eval $(minikube docker-env)` +* Setup `docker` to use the same Docker daemon as your minikube cluster `eval $(minikube docker-env)` * Start BinderHub `python3 -m binderhub -f testing/minikube/binderhub_config.py` * Visit your BinderHub at[http://localhost:8585](http://localhost:8585) @@ -209,7 +209,7 @@ sudo apt install socat eval $(minikube docker-env) ``` - This command sets up docker to use the same docker daemon as your minikube + This command sets up `docker` to use the same Docker daemon as your minikube cluster does. This means images you build are directly available to the cluster. Note: when you no longer wish to use the minikube host, you can undo this change by running: @@ -229,6 +229,26 @@ sudo apt install socat All features should work, including building and launching of repositories. +### Tip: Use local repo2docker version + +BinderHub runs repo2docker in a container. +For testing the combination of an unreleased repo2docker feature with BinderHub, you can use a locally build repo2docker image. +You can configure the image in the file `testing/minikube/binderhub_config.py` with the following line: + +```python +c.BinderHub.build_image = 'jupyter-repo2docker:my_image_tag' +``` + +**Important**: the image must be build using the same Docker daemon as the minikube cluster, otherwise you get an error _"Failed to pull image [...] repository does not exist or may require 'docker login'"_. + +### Tip: Enable debug logging + +In the file `testing/minikube/binderhub_config.py` add the following line: + +```python +c.BinderHub.debug = True +``` + ### Tip: Increase your GitHub API limit By default, GitHub has a limit of 60 API requests per hour. We recommend diff --git a/binderhub/app.py b/binderhub/app.py index b9747d8ef..c72030679 100644 --- a/binderhub/app.py +++ b/binderhub/app.py @@ -33,7 +33,7 @@ from .main import MainHandler, ParameterizedMainHandler, LegacyRedirectHandler from .repoproviders import (GitHubRepoProvider, GitRepoProvider, GitLabRepoProvider, GistRepoProvider, - ZenodoProvider) + ZenodoProvider, FigshareProvider) from .metrics import MetricsHandler from .utils import ByteSpecification, url_path_join @@ -379,6 +379,7 @@ def _add_slash(self, proposal): 'git': GitRepoProvider, 'gl': GitLabRepoProvider, 'zenodo': ZenodoProvider, + 'figshare': FigshareProvider, }, config=True, help=""" diff --git a/binderhub/event-schemas/launch.json b/binderhub/event-schemas/launch.json index 977dc1e26..b2eb48e17 100644 --- a/binderhub/event-schemas/launch.json +++ b/binderhub/event-schemas/launch.json @@ -11,7 +11,8 @@ "Gist", "GitLab", "Git", - "Zenodo" + "Zenodo", + "Figshare" ], "description": "Provider for the repository being launched" }, diff --git a/binderhub/main.py b/binderhub/main.py index 3e2033781..de1a1a711 100644 --- a/binderhub/main.py +++ b/binderhub/main.py @@ -15,7 +15,8 @@ "gist": "Gist", "gl": "GitLab", "git": "Git repo", - "zenodo": "Zenodo" + "zenodo": "Zenodo", + "figshare": "Figshare" } diff --git a/binderhub/repoproviders.py b/binderhub/repoproviders.py index fcf20a9fa..3f7b2bfc5 100644 --- a/binderhub/repoproviders.py +++ b/binderhub/repoproviders.py @@ -217,6 +217,39 @@ def get_build_slug(self): return "zenodo-{}".format(self.record_id) +class FigshareProvider(RepoProvider): + """Provide contents of a Figshare article + + Users must provide a spec consisting of the Figshare DOI. + """ + name = Unicode("Figshare") + url_regex = re.compile(r"(.*)/articles/([^/]+)/(\d+)(/)?(\d+)?") + + @gen.coroutine + def get_resolved_ref(self): + client = AsyncHTTPClient() + req = HTTPRequest("https://doi.org/{}".format(self.spec), + user_agent="BinderHub") + r = yield client.fetch(req) + + match = self.url_regex.match(r.effective_url) + article_id = match.groups()[2] + article_version = match.groups()[4] + if not article_version: + article_version = "1" + self.record_id = "{}.v{}".format(article_id, article_version) + + return self.record_id + + def get_repo_url(self): + # While called repo URL, the return value of this function is passed + # as argument to repo2docker, hence we return the spec as is. + return self.spec + + def get_build_slug(self): + return "figshare-{}".format(self.record_id) + + class GitRepoProvider(RepoProvider): """Bare bones git repo provider. diff --git a/binderhub/static/js/index.js b/binderhub/static/js/index.js index f5a9e6be7..2afac2a65 100644 --- a/binderhub/static/js/index.js +++ b/binderhub/static/js/index.js @@ -84,6 +84,11 @@ function updateRepoText() { $("#ref").prop("disabled", true); $("label[for=ref]").prop("disabled", true); } + else if (provider === "figshare") { + text = "Figshare DOI (10.6084/m9.figshare.9782777.v1)"; + $("#ref").prop("disabled", true); + $("label[for=ref]").prop("disabled", true); + } $("#repository").attr('placeholder', text); $("label[for=repository]").text(text); $("#ref").attr('placeholder', tag_text); @@ -107,7 +112,7 @@ function getBuildFormValues() { } var ref = $('#ref').val().trim() || 'master'; - if (providerPrefix === 'zenodo') { + if (providerPrefix === 'zenodo' || providerPrefix === 'figshare') { ref = ""; } var path = $('#filepath').val().trim(); diff --git a/binderhub/templates/index.html b/binderhub/templates/index.html index 4d888b631..96444265a 100644 --- a/binderhub/templates/index.html +++ b/binderhub/templates/index.html @@ -55,6 +55,7 @@

Build and launch a repository

+ diff --git a/binderhub/tests/test_repoproviders.py b/binderhub/tests/test_repoproviders.py index ee2a0f01f..cc921e705 100644 --- a/binderhub/tests/test_repoproviders.py +++ b/binderhub/tests/test_repoproviders.py @@ -6,7 +6,7 @@ from binderhub.repoproviders import ( tokenize_spec, strip_suffix, GitHubRepoProvider, GitRepoProvider, - GitLabRepoProvider, GistRepoProvider, ZenodoProvider + GitLabRepoProvider, GistRepoProvider, ZenodoProvider, FigshareProvider ) @@ -52,6 +52,21 @@ async def test_zenodo(): assert repo_url == spec +async def test_figshare(): + spec = '10.6084/m9.figshare.9782777.v1' + + provider = FigshareProvider(spec=spec) + + # have to resolve the ref first + ref = await provider.get_resolved_ref() + assert ref == '9782777.v1' + + slug = provider.get_build_slug() + assert slug == 'figshare-9782777.v1' + repo_url = provider.get_repo_url() + assert repo_url == spec + + @pytest.mark.github_api def test_github_ref(): provider = GitHubRepoProvider(spec='jupyterhub/zero-to-jupyterhub-k8s/v0.4')