CD86
CD86

Reputation: 1079

Literate programming setup of Docker programming environment with org-mode in Emacs

I put together a small example of how I manage my development environment with Docker from within Emacs. The idea is, rather than having multiple files in folders that interrelate to each other and thus make it hard to track transitional changes, to have one org-file and just tangle the individual files and even execute some of the source code blocks within the org file for convenience with the use of some Emacs packages. Below I try to describe my reasoning and I am grateful for advise on how to streamline things and also alternatives to my approach. Maybe though it can also prove helpful for others who aim for similar workflows. Can I improve something, by following best practices and the likes? I am particularly concerned about the local-file variable that defines the docker-image name on a per-file basis and which I need to read out in several places in a quite cumbersome way

  # -*- image_name: "test_env"; -*-


    * Environment
      :PROPERTIES:
      :header-args: :results output :mkdirp yes
      :END:

    ** requirements.txt
        #+BEGIN_SRC conf :tangle requirements.txt
        numpy
        #+END_SRC

    ** Start docker
    #+BEGIN_SRC sh :dir "/sudo::"
    sudo service docker start
        #+END_SRC

    ** Dockerfile
    Use [ob-docker-build][1] to build the docker images upon pressing C-c C-c. The image
    name is grabbed from the file-local variable at the top of this file. This file
    can also be tangled to disk.

    #+BEGIN_SRC docker-build :dir "." :tag (symbol-value 'image_name) :tangle Dockerfile
    FROM python:3.8-slim-buster

    ENV VIRTUAL_ENV=/opt/venv
    RUN python3 -m venv $VIRTUAL_ENV
    # Make sure we use the virtualenv:
    ENV PATH="$VIRTUAL_ENV/bin:$PATH"

    COPY requirements.txt .
    RUN pip install --quiet --no-cache-dir -r requirements.txt
    WORKDIR /app
    # just for keeping the container running
    CMD tail -f /dev/null
    #+END_SRC

    ** run_docker.sh
    This script can either be tangled to disk or is executed automatically by
    org-sbe in the python application below

    #+HEADER: :var image_name=(symbol-value 'image_name)
    #+name: run_docker
    #+BEGIN_SRC bash :tangle run_docker.sh :tangle-mode (identity #o755) :results output
    #!/bin/bash

    SBX_DIR=$(realpath $(dirname $0))

    # generate some id for the container
    CONTAINER_NAME=$(uuidgen | md5sum | awk '{ print $1 }' | cut -c -12)

    if [ $# -eq 0 ]; then
        ARGS=$SHELL
    else
        ARGS=$@
    fi

    DOCKER="docker run"

    DOCKER_ARGS=(
        --name "$CONTAINER_NAME"
        -v $HOME:$HOME
        -v "$SBX_DIR":"$SBX_DIR"
        --rm
        --user $(id -u):$(id -g)
        -w $SBX_DIR
        -itd ${image_name}
        $ARGS
    )

    $DOCKER ${DOCKER_ARGS[@]}
    #+END_SRC

    ** python
    Use the [docker-tramp][1] package to attach to a running container. C-c C-c on the
    block below causes the run-docker src-block to be executed. The resulting ID of
    the container is then used here to attach to this running instance

    #+BEGIN_SRC python :dir (concat "/docker:" (org-sbe run_docker) ":") :results output
    print('hello')
    #+END_SRC

What is taking precedence here?

# -*- foo: "one"; -*-

#+PROPERTY: header-args :var foo=two
#+PROPERTY: foo=three


* first
:PROPERTIES:
:foo: four
:END:
** second
:PROPERTIES:
:foo: five
:END:
#+HEADER: foo=(symbol-value 'foo)
#+BEGIN_SRC bash :var foo=(org-macro--get-property "foo" "")
echo $foo
#+END_SRC

Upvotes: 5

Views: 1352

Answers (1)

mankoff
mankoff

Reputation: 2301

Re:

I am particularly concerned about the local-file variable that defines the docker-image name on a per-file basis and which I need to read out in several places in a quite cumbersome way

You can define a property and access in text and in header args:

:PROPERTIES:
:foo:  bar
:END:

You can access the foo property like this: {{{property(foo)}}}.

And you can access it in header args like this:

#+BEGIN_SRC bash :var foo=(org-macro--get-property "foo" "")
echo $foo # prints bar
#+END_SRC

Upvotes: 3

Related Questions