New command: datasette package - packages a docker container

Example usage:

    datasette package fivethirtyeight.db \
        --tag fivethirtyeight \
        --metadata=538-metadata.json

This will create a temporary directory, generate a Dockerfile, copy in the
SQLite database and metadata file, then build that as a new docker image and
tag that in your local Docker repository as fivethirtyeight:latest.

You can then run the image like so:

    docker run -p 8006:8001 fivethirtyeight

This will expose port 8001 in the container (the default) as port 8006 on your
host.

Closes #67
pull/81/head
Simon Willison 2017-11-13 08:13:38 -08:00
rodzic 3ef35ca8b4
commit 4143e3b45c
2 zmienionych plików z 65 dodań i 26 usunięć

Wyświetl plik

@ -1,13 +1,13 @@
import click import click
from click_default_group import DefaultGroup from click_default_group import DefaultGroup
import json import json
import os
import shutil import shutil
from subprocess import call from subprocess import call
import sys import sys
import tempfile
from .app import Datasette from .app import Datasette
from .utils import make_dockerfile from .utils import (
temporary_docker_directory,
)
@click.group(cls=DefaultGroup, default='serve', default_if_no_args=True) @click.group(cls=DefaultGroup, default='serve', default_if_no_args=True)
@ -46,28 +46,39 @@ def publish(files, name, metadata):
) )
click.echo('Follow the instructions at https://zeit.co/now#whats-now', err=True) click.echo('Follow the instructions at https://zeit.co/now#whats-now', err=True)
sys.exit(1) sys.exit(1)
tmp = tempfile.TemporaryDirectory()
# We create a datasette folder in there to get a nicer now deploy name with temporary_docker_directory(files, name, metadata):
datasette_dir = os.path.join(tmp.name, name)
os.mkdir(datasette_dir)
saved_cwd = os.getcwd()
file_paths = [
os.path.join(saved_cwd, name)
for name in files
]
file_names = [os.path.split(f)[-1] for f in files]
try:
dockerfile = make_dockerfile(file_names, metadata and 'metadata.json')
os.chdir(datasette_dir)
open('Dockerfile', 'w').write(dockerfile)
if metadata:
open('metadata.json', 'w').write(metadata.read())
for path, filename in zip(file_paths, file_names):
os.link(path, os.path.join(datasette_dir, filename))
call('now') call('now')
finally:
tmp.cleanup()
os.chdir(saved_cwd) @cli.command()
@click.argument('files', type=click.Path(exists=True), nargs=-1, required=True)
@click.option(
'-t', '--tag',
help='Name for the resulting Docker container, can optionally use name:tag format'
)
@click.option(
'-m', '--metadata', type=click.File(mode='r'),
help='Path to JSON file containing metadata to publish'
)
def package(files, tag, metadata):
"Package specified SQLite files into a new datasette Docker container"
if not shutil.which('docker'):
click.secho(
' The package command requires "docker" to be installed and configured ',
bg='red',
fg='white',
bold=True,
err=True,
)
sys.exit(1)
with temporary_docker_directory(files, 'datasette', metadata):
args = ['docker', 'build']
if tag:
args.append('-t')
args.append(tag)
args.append('.')
call(args)
@cli.command() @cli.command()

Wyświetl plik

@ -1,8 +1,10 @@
from contextlib import contextmanager from contextlib import contextmanager
import base64 import base64
import json import json
import os
import re import re
import sqlite3 import sqlite3
import tempfile
import time import time
import urllib import urllib
@ -140,9 +142,35 @@ COPY . /app
WORKDIR /app WORKDIR /app
RUN pip install https://static.simonwillison.net/static/2017/datasette-0.6-py3-none-any.whl RUN pip install https://static.simonwillison.net/static/2017/datasette-0.6-py3-none-any.whl
RUN datasette build {} --inspect-file inspect-data.json RUN datasette build {} --inspect-file inspect-data.json
EXPOSE 8006 EXPOSE 8001
CMD ["datasette", "serve", {}, "--port", "8006", "--inspect-file", "inspect-data.json"{}]'''.format( CMD ["datasette", "serve", {}, "--port", "8001", "--inspect-file", "inspect-data.json"{}]'''.format(
' '.join(files), ' '.join(files),
'"' + '", "'.join(files) + '"', '"' + '", "'.join(files) + '"',
metadata_file and ', "--metadata", "{}"'.format(metadata_file) or '', metadata_file and ', "--metadata", "{}"'.format(metadata_file) or '',
).strip() ).strip()
@contextmanager
def temporary_docker_directory(files, name, metadata):
tmp = tempfile.TemporaryDirectory()
# We create a datasette folder in there to get a nicer now deploy name
datasette_dir = os.path.join(tmp.name, name)
os.mkdir(datasette_dir)
saved_cwd = os.getcwd()
file_paths = [
os.path.join(saved_cwd, name)
for name in files
]
file_names = [os.path.split(f)[-1] for f in files]
try:
dockerfile = make_dockerfile(file_names, metadata and 'metadata.json')
os.chdir(datasette_dir)
open('Dockerfile', 'w').write(dockerfile)
if metadata:
open('metadata.json', 'w').write(metadata.read())
for path, filename in zip(file_paths, file_names):
os.link(path, os.path.join(datasette_dir, filename))
yield
finally:
tmp.cleanup()
os.chdir(saved_cwd)