├── .sphinx-server.yml ├── .travis.yml ├── Dockerfile ├── LICENCE ├── README.md ├── requirements.txt └── server.py /.sphinx-server.yml: -------------------------------------------------------------------------------- 1 | # Set autobuild to false if you do not want to enable compilation when a file changes. 2 | # This will enable http authentication if credentials section is filled. 3 | autobuild: true 4 | 5 | # Add files and folders you want autobuild watcher to ignore on changes. 6 | ignore: 7 | - .git 8 | 9 | # Add a username and a password if you want to enable http authentication. 10 | # This will not work if autobuild is enabled. 11 | credentials: 12 | username: ~ 13 | password: ~ 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | services: 4 | - docker 5 | 6 | sudo: true 7 | 8 | install: 9 | - docker build -t server-image . 10 | 11 | script: 12 | - mkdir documentation && cd documentation 13 | - docker run -itd -v "$(pwd)":/web -p 8000:8000 --name sphinx-server server-image 14 | - docker ps | grep -q sphinx-server 15 | - docker exec -it sphinx-server sphinx-quickstart -q -p test -a tester -v 0.1 16 | - docker exec -it sphinx-server make html 17 | - curl -O http://localhost:8000/index.html 18 | - grep -q "Welcome to test’s documentation!" index.html 19 | - docker exec -it sphinx-server plantuml -version 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8.0-alpine3.10 2 | 3 | MAINTAINER Loïc Pauletto 4 | MAINTAINER Quentin de Longraye 5 | 6 | COPY ./requirements.txt requirements.txt 7 | 8 | RUN apk add --no-cache --virtual --update py3-pip make wget ca-certificates ttf-dejavu openjdk8-jre graphviz \ 9 | && pip install --upgrade pip \ 10 | && pip install --no-cache-dir -r requirements.txt 11 | 12 | RUN wget http://downloads.sourceforge.net/project/plantuml/plantuml.jar -P /opt/ \ 13 | && echo -e '#!/bin/sh -e\njava -jar /opt/plantuml.jar "$@"' > /usr/local/bin/plantuml \ 14 | && chmod +x /usr/local/bin/plantuml 15 | 16 | COPY ./server.py /opt/sphinx-server/ 17 | COPY ./.sphinx-server.yml /opt/sphinx-server/ 18 | 19 | WORKDIR /web 20 | 21 | EXPOSE 8000 35729 22 | 23 | CMD ["python", "/opt/sphinx-server/server.py"] 24 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 dLdL 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sphinx-Server 2 | 3 | Sphinx-Server allows you to build *Sphinx documentation* using a Docker 4 | image based on Alpine. 5 | 6 | [![Build Status](https://travis-ci.org/dldl/sphinx-server.svg?branch=master)](https://travis-ci.org/dldl/sphinx-server) 7 | [![Docker pulls](https://img.shields.io/docker/pulls/dldl/sphinx-server.svg)](https://hub.docker.com/r/dldl/sphinx-server/) 8 | [![Docker layers](https://images.microbadger.com/badges/image/dldl/sphinx-server.svg)](https://microbadger.com/images/dldl/sphinx-server) 9 | [![Docker automated build](https://img.shields.io/docker/automated/dldl/sphinx-server.svg)](https://hub.docker.com/r/dldl/sphinx-server/) 10 | 11 | **Functionnalities:** 12 | 13 | - *Sphinx documentation* served by a python server 14 | - UML support with *PlantUML* 15 | - `dot` support with *Graphviz* 16 | - *Autobuild* with sphinx-autobuild 17 | - HTTP *authentication* 18 | 19 | **Limitations:** 20 | 21 | - This image is not bundled with LaTeX but you can generate *.tex* files and 22 | compile them outside of the container 23 | 24 | ## Installation 25 | 26 | ### With Docker Hub 27 | 28 | Pull the image from Docker Hub using: 29 | 30 | ```sh 31 | docker pull dldl/sphinx-server 32 | ``` 33 | 34 | If you only want to compile files without using the server, you can use the 35 | following command (for example) at the root of your documentation: 36 | 37 | ```sh 38 | docker run -t -v "$(pwd)":/web dldl/sphinx-server make html 39 | ``` 40 | 41 | ### From source 42 | 43 | Clone this repository on your computer and build the image using the following 44 | command: 45 | 46 | ```sh 47 | docker build -t dldl/sphinx-server . 48 | ``` 49 | 50 | ## Usage 51 | 52 | You may add a *.sphinx-server.yml* file at the root of your project 53 | documentation if you want to use a custom configuration. You can see the default 54 | *.sphinx-server.yml* in this repository that will be used if you don't add 55 | yours. 56 | 57 | ### Container creation 58 | 59 | **Without autobuild (production mode):** 60 | 61 | If you want to enable HTTP authentication, just add a *.sphinx-server.yml* file 62 | at the root of your project documentation and add a `credentials` section. You 63 | also need to set `autobuild` to false. 64 | 65 | Run the following command at the root of your documentation: 66 | 67 | ```sh 68 | docker run -itd -v "$(pwd)":/web -p 8000:8000 --name sphinx-server dldl/sphinx-server 69 | ``` 70 | 71 | **With autobuild enabled:** 72 | 73 | Autobuild is enabled by default. You may add folders and files to the `ignore` list. 74 | 75 | Run the following command at the root of your documentation: 76 | 77 | ```sh 78 | docker run -itd -v "$(pwd)":/web -u $(id -u):$(id -g) -p 8000:8000 --name sphinx-server dldl/sphinx-server 79 | ``` 80 | 81 | The web server will be listening on port `8000`. 82 | All the files in the current directory will be mounted in the container. 83 | 84 | ### Interacting with the server 85 | 86 | - To stop the server, use `docker stop sphinx-server` 87 | - To start the server, use `docker start sphinx-server` 88 | - To remove the server, use `docker rm -v sphinx-server` 89 | 90 | You can use the following command to open a shell into the container: 91 | 92 | ```sh 93 | docker exec -it sphinx-server /bin/sh 94 | ``` 95 | 96 | You can then run commands like `make html` to build the documentation. 97 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | livereload==2.6.1 2 | Sphinx==2.2.1 3 | sphinx-autobuild==0.7.1 4 | sphinx-rtd-theme==0.4.3 5 | sphinxcontrib-plantuml==0.17.1 -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import sphinx_autobuild 2 | import os 3 | import sys 4 | from contextlib import contextmanager 5 | import base64 6 | from livereload import Server 7 | import http.server 8 | import http.server 9 | import socketserver 10 | import yaml 11 | 12 | 13 | class AuthHandler(http.server.SimpleHTTPRequestHandler): 14 | """ 15 | Authentication handler used to support HTTP authentication 16 | """ 17 | def do_HEAD(self): 18 | self.send_response(200) 19 | self.send_header('Content-type', 'text/html') 20 | self.end_headers() 21 | 22 | def do_AUTHHEAD(self): 23 | self.send_response(401) 24 | self.send_header('WWW-Authenticate', 'Basic realm=\"Restricted area\"') 25 | self.send_header('Content-type', 'text/html') 26 | self.end_headers() 27 | 28 | def do_GET(self): 29 | global key 30 | if self.headers.get('Authorization') is None: 31 | self.do_AUTHHEAD() 32 | self.wfile.write('Credentials required.'.encode('utf-8')) 33 | pass 34 | elif self.headers.get('Authorization') == 'Basic ' + key.decode('utf-8'): 35 | http.server.SimpleHTTPRequestHandler.do_GET(self) 36 | pass 37 | else: 38 | self.do_AUTHHEAD() 39 | self.wfile.write('Credentials required.'.encode('utf-8')) 40 | pass 41 | 42 | ''' 43 | This function is used to simulate the manipulation of the stack (like pushd and popd in BASH) 44 | and change the folder with the usage of the context manager 45 | ''' 46 | @contextmanager 47 | def pushd(new_dir): 48 | previous_dir = os.getcwd() 49 | os.chdir(new_dir) 50 | yield 51 | os.chdir(previous_dir) 52 | 53 | 54 | if __name__ == '__main__': 55 | 56 | key = '' 57 | config_file = '.sphinx-server.yml' 58 | install_folder = '/opt/sphinx-server/' 59 | build_folder = os.path.realpath('_build/html') 60 | source_folder = os.path.realpath('.') 61 | configuration = None 62 | 63 | with open(install_folder + config_file, 'r') as config_stream: 64 | configuration = yaml.safe_load(config_stream) 65 | 66 | if os.path.isfile(source_folder + '/' + config_file): 67 | with open(source_folder + '/' + config_file, "r") as custom_stream: 68 | configuration.update(yaml.safe_load(custom_stream)) 69 | 70 | if not os.path.exists(build_folder): 71 | os.makedirs(build_folder) 72 | 73 | if configuration.get('autobuild'): 74 | 75 | ignored_files = [] 76 | for path in configuration.get('ignore'): 77 | ignored_files.append(os.path.realpath(path)) 78 | 79 | builder = sphinx_autobuild.SphinxBuilder( 80 | outdir=build_folder, 81 | args=['-b', 'html', source_folder, build_folder]+sys.argv[1:], 82 | ignored=ignored_files 83 | ) 84 | 85 | server = Server(watcher=sphinx_autobuild.LivereloadWatchdogWatcher()) 86 | server.watch(source_folder, builder) 87 | server.watch(build_folder) 88 | 89 | builder.build() 90 | 91 | server.serve(port=8000, host='0.0.0.0', root=build_folder) 92 | else: 93 | # Building once when server starts 94 | builder = sphinx_autobuild.SphinxBuilder(outdir=build_folder, args=['-b', 'html', source_folder, build_folder]+sys.argv[1:]) 95 | builder.build() 96 | 97 | sys.argv = ['nouser', '8000'] 98 | 99 | if configuration.get('credentials')['username'] is not None: 100 | auth = configuration.get('credentials')['username'] + ':' + configuration.get('credentials')['password'] 101 | key = base64.b64encode(auth.encode('utf-8')) 102 | 103 | with pushd(build_folder): 104 | http.server.test(AuthHandler, http.server.HTTPServer) 105 | else: 106 | with pushd(build_folder): 107 | Handler = http.server.SimpleHTTPRequestHandler 108 | httpd = socketserver.TCPServer(('', 8000), Handler) 109 | httpd.serve_forever() 110 | --------------------------------------------------------------------------------