From 67fc9c5720ed1fcd62b116481f70d4e80b403a22 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Wed, 29 Jan 2020 14:46:43 -0800 Subject: [PATCH] --port argument for datasette package, plus tests - closes #661 From pull request #663 --- datasette/cli.py | 5 ++++ datasette/utils/__init__.py | 8 +++-- docs/datasette-package-help.txt | 1 + docs/publish.rst | 4 +++ tests/conftest.py | 2 ++ tests/test_package.py | 53 +++++++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 tests/test_package.py diff --git a/datasette/cli.py b/datasette/cli.py index b71275d5..67d00fbb 100644 --- a/datasette/cli.py +++ b/datasette/cli.py @@ -167,6 +167,9 @@ def plugins(all, plugins_dir): ) @click.option("--spatialite", is_flag=True, help="Enable SpatialLite extension") @click.option("--version-note", help="Additional note to show on /-/versions") +@click.option( + "-p", "--port", default=8001, help="Port to run the server on, defaults to 8001", +) @click.option("--title", help="Title for metadata") @click.option("--license", help="License label for metadata") @click.option("--license_url", help="License URL for metadata") @@ -186,6 +189,7 @@ def package( install, spatialite, version_note, + port, **extra_metadata ): "Package specified SQLite files into a new datasette Docker container" @@ -211,6 +215,7 @@ def package( spatialite, version_note, extra_metadata, + port=port, ): args = ["docker", "build"] if tag: diff --git a/datasette/utils/__init__.py b/datasette/utils/__init__.py index ab5f995b..a8db83a7 100644 --- a/datasette/utils/__init__.py +++ b/datasette/utils/__init__.py @@ -275,6 +275,7 @@ def make_dockerfile( spatialite, version_note, environment_variables=None, + port=8001, ): cmd = ["datasette", "serve", "--host", "0.0.0.0"] for filename in files: @@ -313,8 +314,8 @@ WORKDIR /app {environment_variables} RUN pip install -U {install_from} RUN datasette inspect {files} --inspect-file inspect-data.json -ENV PORT 8001 -EXPOSE 8001 +ENV PORT {port} +EXPOSE {port} CMD {cmd}""".format( environment_variables="\n".join( [ @@ -326,6 +327,7 @@ CMD {cmd}""".format( cmd=cmd, install_from=" ".join(install), spatialite_extras=SPATIALITE_DOCKERFILE_EXTRAS if spatialite else "", + port=port, ).strip() @@ -344,6 +346,7 @@ def temporary_docker_directory( version_note, extra_metadata=None, environment_variables=None, + port=8001, ): extra_metadata = extra_metadata or {} tmp = tempfile.TemporaryDirectory() @@ -373,6 +376,7 @@ def temporary_docker_directory( spatialite, version_note, environment_variables, + port=port, ) os.chdir(datasette_dir) if metadata_content: diff --git a/docs/datasette-package-help.txt b/docs/datasette-package-help.txt index 92ef09b9..1f1fab85 100644 --- a/docs/datasette-package-help.txt +++ b/docs/datasette-package-help.txt @@ -16,6 +16,7 @@ Options: --install TEXT Additional packages (e.g. plugins) to install --spatialite Enable SpatialLite extension --version-note TEXT Additional note to show on /-/versions + -p, --port INTEGER Port to run the server on, defaults to 8001 --title TEXT Title for metadata --license TEXT License label for metadata --license_url TEXT License URL for metadata diff --git a/docs/publish.rst b/docs/publish.rst index 0a22648f..cb51c75e 100644 --- a/docs/publish.rst +++ b/docs/publish.rst @@ -152,6 +152,10 @@ You can now run the resulting container like so:: This exposes port 8001 inside the container as port 8081 on your host machine, so you can access the application at ``http://localhost:8081/`` +You can customize the port that is exposed by the countainer using the ``--port`` option: + + datasette package mydatabase.db --port 8080 + A full list of options can be seen by running ``datasette package --help``: .. literalinclude:: datasette-package-help.txt diff --git a/tests/conftest.py b/tests/conftest.py index aaa8f735..a19ad18d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -20,6 +20,8 @@ def pytest_collection_modifyitems(items): move_to_front(items, "test_inspect_cli") move_to_front(items, "test_inspect_cli_writes_to_file") move_to_front(items, "test_spatialite_error_if_attempt_to_open_spatialite") + move_to_front(items, "test_package") + move_to_front(items, "test_package_with_port") def move_to_front(items, test_name): diff --git a/tests/test_package.py b/tests/test_package.py new file mode 100644 index 00000000..f0cbe88f --- /dev/null +++ b/tests/test_package.py @@ -0,0 +1,53 @@ +from click.testing import CliRunner +from datasette import cli +from unittest import mock +import pathlib +import json + + +class CaptureDockerfile: + def __call__(self, _): + self.captured = (pathlib.Path() / "Dockerfile").read_text() + + +EXPECTED_DOCKERFILE = """ +FROM python:3.8 +COPY . /app +WORKDIR /app + + +RUN pip install -U datasette +RUN datasette inspect test.db --inspect-file inspect-data.json +ENV PORT {port} +EXPOSE {port} +CMD datasette serve --host 0.0.0.0 -i test.db --cors --inspect-file inspect-data.json --port $PORT +""".strip() + + +@mock.patch("shutil.which") +@mock.patch("datasette.cli.call") +def test_package(mock_call, mock_which): + mock_which.return_value = True + runner = CliRunner() + capture = CaptureDockerfile() + mock_call.side_effect = capture + with runner.isolated_filesystem(): + open("test.db", "w").write("data") + result = runner.invoke(cli.cli, ["package", "test.db"]) + assert 0 == result.exit_code + mock_call.assert_has_calls([mock.call(["docker", "build", "."])]) + assert EXPECTED_DOCKERFILE.format(port=8001) == capture.captured + + +@mock.patch("shutil.which") +@mock.patch("datasette.cli.call") +def test_package_with_port(mock_call, mock_which): + mock_which.return_value = True + capture = CaptureDockerfile() + mock_call.side_effect = capture + runner = CliRunner() + with runner.isolated_filesystem(): + open("test.db", "w").write("data") + result = runner.invoke(cli.cli, ["package", "test.db", "-p", "8080"]) + assert 0 == result.exit_code + assert EXPECTED_DOCKERFILE.format(port=8080) == capture.captured