diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a88ef0d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: python +python: + - "2.7" + - "3.6" +install: + - make requirements +script: + - pylint src/run diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..87996fb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM antora/antora:latest + +# We content will be exposed on the standard HTTP port. +EXPOSE 80/tcp + +# Install git to clone the docs repo, apache to serve up the we content and +# python to process the playbooks. +RUN apk --no-cache add \ + git \ + apache2 \ + python \ + py-yaml \ + && mkdir /run/apache2 + +# Add a virtual host for Apache to serve requests on port 80. +COPY res/vhost.conf /etc/apache2/conf.d/ + +# Add in our new entry point. +COPY src/run /usr/local/bin +ENTRYPOINT ["/usr/local/bin/run"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..baefc34 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +DOCKER_IMAGE=spjmurray/couchbase-antora-preview +DOCKER_TAG=0.0.1 + +.PHONY: all +all: + docker build . -t ${DOCKER_IMAGE}:${DOCKER_TAG} + +.PHONY: requirements +requirements: + pip install -r requirements.txt diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..2b63be6 --- /dev/null +++ b/README.adoc @@ -0,0 +1,63 @@ += Couchbase Antora Preview + +https://travis-ci.org/spjmurray/couchbase-antora-preview[image:https://travis-ci.org/spjmurray/couchbase-antora-preview.png[]] + +Simple container which automates the installation of Antora, compilation of Couchbase +documentation for a single repository and display via a web server. + +== Installation + +=== Pre-requisites + +Ensure the following commands are installed and in your path: + +* make +* docker + +=== Creating the container image + +Simply (for Richard Smedley) run the following: + +[source,console] +---- +make +---- + +== Execution + +A typical execution of the container will look like the following: + +[source,console] +---- +docker run --rm -ti \ + --publish 8080:80 \ + --mount type=bind,source=/home/simon/go/src/github.com/couchbase/couchbase-operator,target=/src,readonly \ + spjmurray/couchbase-antora-preview:0.0.1 \ + master \ + docs/user +---- + +At present all arguments are required, however certain arguments may be modified to suit your particular Antora module. + +--rm:: +Removes the container once execution has terminated. + +-ti:: +Allocate a pseudo terminal and allow input. + +--publish 8080:80:: +Bind unprivileged port 8080 on the host system to port 80 on the container. + +--mount type=bind,source=/home/simon/go/src/github.com/couchbase/couchbase-operator,target=/src,readonly:: +Mounts your AsciiDoc repository to /src in the container. This must be a Git repository containing at least one Antora module. + +spjmurray/couchbase-antora-preview:0.0.1:: +This is the name of the container image to use. + +master:: +Argument passed to the container entry point. This selects the Git branch to generate static content from. + +docs/user:: +Argument passed to the container entry point. This selects the path to the Antora module (containing antora.yml). + +NOTE: The container runs in an interactive shell, to stop execution simply press `Ctl+C` diff --git a/pylintrc b/pylintrc new file mode 100644 index 0000000..0a23003 --- /dev/null +++ b/pylintrc @@ -0,0 +1,3 @@ +[MESSAGES CONTROL] +disable= + too-few-public-methods, diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1bfb73b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pylint +pyyaml diff --git a/res/vhost.conf b/res/vhost.conf new file mode 100644 index 0000000..4397d27 --- /dev/null +++ b/res/vhost.conf @@ -0,0 +1,8 @@ + + DocumentRoot "/antora/docs-site/public" + ServerName localhost + + + Require all granted + + diff --git a/src/run b/src/run new file mode 100755 index 0000000..b6d8793 --- /dev/null +++ b/src/run @@ -0,0 +1,134 @@ +#!/usr/bin/python + +"""placeholder""" + +import argparse +import logging +import os +import subprocess +import sys +import time +import yaml + +BASE_REPO = 'docs-site' +MODULE_REPO_PATH = '/src/' +PLAYBOOK_SRC = 'staging-antora-playbook.yml' +PLAYBOOK = 'anotora-preview-playbook.yml' +ANTORA_HOME = '/antora' + + +class Executor(object): + """ + Helper functions for execution of external commands + """ + + @staticmethod + def _execute(command, env): + """Execute a command returning the exit code and output""" + + logging.debug('Executing command: %s', ' '.join(command)) + proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + stdout, stderr = proc.communicate() + return proc.returncode, stdout, stderr + + @staticmethod + def execute(command, env=None): + """Execute a command saving the output to the debug logs""" + + returncode, stdout, stderr = Executor._execute(command, env=env) + logging.debug('stdout: \n%s', stdout) + logging.debug('stderr: \n%s', stderr) + if returncode != 0: + raise RuntimeError + return stdout, stderr + + +def init_logging(debug): + """Setup logging to stdout with nice formatting""" + + level = logging.INFO + if debug: + level = logging.DEBUG + + logging.getLogger().setLevel(level) + formatter = logging.Formatter(fmt='%(asctime)s.%(msecs)03d %(levelname)s %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter(formatter) + logging.getLogger().addHandler(handler) + + +def init_repo(args): + """Clone the most recent Couchbase docs repo, patch in our module, generate content""" + + logging.info('Cloning latest document repository ...') + os.chdir(ANTORA_HOME) + Executor.execute(['git', 'clone', 'https://github.com/couchbase/' + BASE_REPO]) + + logging.info('Creating site playbook ...') + os.chdir(ANTORA_HOME + '/' + BASE_REPO) + with open(PLAYBOOK_SRC) as filedesc: + playbook = yaml.load(filedesc.read()) + + playbook['site']['url'] = 'http://localhost' + playbook['content']['sources'] = [ + { + 'url': '.', + 'branches': 'HEAD', + 'start_path': 'home', + }, + { + 'url': MODULE_REPO_PATH, + 'branches': args.branch, + 'start_path': args.path, + } + ] + # Gets screwed up by read/dump :/ + del playbook['ui']['supplemental_files'] + + with open(PLAYBOOK, 'w') as filedesc: + filedesc.write(yaml.dump(playbook, default_flow_style=False)) + + logging.info("Generating static content ...") + os.chdir(ANTORA_HOME + '/' + BASE_REPO) + Executor.execute(['antora', PLAYBOOK]) + + +def init_httpd(): + """Start the HTTP daemon when the vhost directory is created""" + + logging.info('Starting webserver ...') + Executor.execute(['httpd', '-k', 'start']) + + +def init_slumber(): + """Sleep until we are killed""" + + logging.info('Serving content on http://localhost:8080, press Ctl+C to exit ...') + while True: + time.sleep(10) + + +def main(): + """Parse arguments, setup logging and run the main meat""" + + parser = argparse.ArgumentParser() + parser.add_argument('-d', '--debug', action='store_true', default=False) + parser.add_argument('branch') + parser.add_argument('path') + args = parser.parse_args() + + init_logging(debug=args.debug) + + try: + init_repo(args) + init_httpd() + init_slumber() + except KeyboardInterrupt: + logging.info('Caught interrupt exitting ...') + + +if __name__ == '__main__': + main() + +# vi: ts=4 et: