diff --git a/containers/base/Containerfile b/containers/base/Containerfile index 1df7208..444d842 100644 --- a/containers/base/Containerfile +++ b/containers/base/Containerfile @@ -150,6 +150,10 @@ RUN echo "$DEV_USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers \ ENV VOLS_DIR="/vols" RUN mkdir -m 755 $VOLS_DIR +# Create directory to hold volume initialization data +ENV VOLS_INIT_DIR="$VOLS_DIR/.init" +RUN mkdir -m 755 $VOLS_INIT_DIR + # Make a directory for shell config ENV SHELL_CONFIG_DIR="$VOLS_DIR/shell" RUN mkdir -m 755 $SHELL_CONFIG_DIR \ diff --git a/containers/emacs/Containerfile b/containers/emacs/Containerfile index 6350d34..95025a9 100644 --- a/containers/emacs/Containerfile +++ b/containers/emacs/Containerfile @@ -63,11 +63,8 @@ RUN curl -fL -o $FD_FILE "$FD_URL" \ && dpkg -i $FD_FILE \ && rm -f $FD_FILE -# Switch to non-root user -USER $DEV_USER -WORKDIR $DEV_USER_HOME -# Doom Emacs variables +# Doom Emacs variables from the cache image ARG DE_EMACS_DIR="/vols/emacs.d" ARG DE_DOOM_DIR="/vols/doom.d" @@ -75,21 +72,38 @@ ARG DE_DOOM_DIR="/vols/doom.d" # organization. Copying those symlinks will break them, unless the absolute # paths stay the same. That is to say, $DE_EMACS_DIR must equal # $EMACS_CONFIG_DIR, etc. -ENV EMACS_CONFIG_DIR="$DE_EMACS_DIR" -ENV DOOM_CONFIG_DIR="$DE_DOOM_DIR" +ENV EMACS_CONFIG_DIR=$DE_EMACS_DIR +ENV DOOM_CONFIG_DIR=$DE_DOOM_DIR # Make blank directories to ensure permissions are set correctly -RUN sudo mkdir -m 755 $EMACS_CONFIG_DIR $DOOM_CONFIG_DIR \ - && sudo chown $DEV_USER:$DEV_USER $EMACS_CONFIG_DIR $DOOM_CONFIG_DIR +RUN mkdir -m 755 $EMACS_CONFIG_DIR $DOOM_CONFIG_DIR \ + && chown $DEV_USER:$DEV_USER $EMACS_CONFIG_DIR $DOOM_CONFIG_DIR + +# Add Doom executables to PATH +ENV PATH=$EMACS_CONFIG_DIR/bin:$PATH + +# Set environment variables used by Doom +ENV EMACSDIR=$EMACS_CONFIG_DIR +ENV DOOMDIR=$DOOM_CONFIG_DIR + +# Tarballs which will be made to initialize Emacs volumes +ENV EMACS_CONFIG_TARBALL="$VOLS_INIT_DIR/emacs.d.tar.gz" +ENV DOOM_CONFIG_TARBALL="$VOLS_INIT_DIR/doom.d.tar.gz" + +# Create tarballs for the Emacs Doom config files +RUN --mount=type=bind,from=doom-cache,src=$DE_EMACS_DIR,dst=$EMACS_CONFIG_DIR \ + tar -C $EMACS_CONFIG_DIR --create -z -f $EMACS_CONFIG_TARBALL . +RUN --mount=type=bind,from=doom-cache,src=$DE_DOOM_DIR,dst=$DOOM_CONFIG_DIR \ + tar -C $DOOM_CONFIG_DIR --create -z -f $DOOM_CONFIG_TARBALL . + +# Switch to non-root user +USER $DEV_USER +WORKDIR $DEV_USER_HOME # Add links to the home directory RUN ln -s $EMACS_CONFIG_DIR $DEV_USER_HOME/.emacs.d \ && ln -s $DOOM_CONFIG_DIR $DEV_USER_HOME/.doom.d -# Copy files from the build layer -COPY --from=doom-cache --chown=$DEV_USER:$DEV_USER $DE_EMACS_DIR $EMACS_CONFIG_DIR -COPY --from=doom-cache --chown=$DEV_USER:$DEV_USER $DE_DOOM_DIR $DOOM_CONFIG_DIR - # Doom font variables ARG DE_NERDFONT_URL="https://raw.githubusercontent.com/rainstormstudio/nerd-icons.el/main/fonts/NFM.ttf" ARG DE_NERDFONT_FILE="$DEV_USER_HOME/.local/share/fonts/NFM.ttf" @@ -99,20 +113,6 @@ RUN mkdir -p $(dirname $DE_NERDFONT_FILE) \ && curl -fL -o $DE_NERDFONT_FILE "$DE_NERDFONT_URL" \ && fc-cache -f -# Add Doom executables to PATH -ENV PATH=$EMACS_CONFIG_DIR/bin:$PATH - -# Set environment variables used by Doom -ENV EMACSDIR=$DE_EMACS_DIR -ENV DOOMDIR=$DE_DOOM_DIR - -# Build the VTerm module. We must locate the exact build directory because it's -# name depends on the Emacs version, e.g., `build-28.1`, etc. -RUN VTERM_BUILD_DIR=$(fd -uu -p "build-[0-9.]+/vterm$" $EMACS_CONFIG_DIR) \ - && cd $VTERM_BUILD_DIR \ - && cmake -S . -B build \ - && cmake --build build - # Add VTerm integration to Bash config RUN { \ echo; \ @@ -124,11 +124,14 @@ RUN { \ echo "fi"; \ } >> $DEV_USER_HOME/.bashrc +# Copy entry point for config initialization +COPY emacs_init.sh $ENTRYPOINT_DIR/80_emacs_init.sh + # Persistent storage for the Emacs and Doom config directories. These # directories will be initialized with the Doom files from above. VOLUME ["$EMACS_CONFIG_DIR", "$DOOM_CONFIG_DIR"] -# Copy the Emacs shim for the entry point +# Copy the Emacs shim for the default command COPY emacs_shim.sh /emacs_shim.sh # Launch Emacs by default diff --git a/containers/emacs/doom_cache/Containerfile b/containers/emacs/doom_cache/Containerfile index 7ecade0..d797908 100644 --- a/containers/emacs/doom_cache/Containerfile +++ b/containers/emacs/doom_cache/Containerfile @@ -61,3 +61,18 @@ RUN mkdir -p $DE_DOOM_DIR \ && cp $DE_EMACS_DIR/static/packages.example.el $DE_DOOM_DIR/packages.el \ && sed -e "s/[(]\?evil/;;&/" -e "s/;;\([(]\?vterm\)/\1/" -i $DE_DOOM_DIR/init.el \ && doom install --force --verbose --no-config --no-env --no-hooks + +# Install dependencies for building VTerm +RUN apt-get update \ + && apt-get install -y \ + build-essential \ + cmake \ + libtool-bin \ + && rm -rf /var/lib/apt/lists/* + +# Build the VTerm module. We must locate the exact build directory because it's +# name depends on the Emacs version, e.g., `build-28.1`, etc. +RUN VTERM_BUILD_DIR=$(find "$DE_EMACS_DIR" -path "*/build-[0-9.]*/vterm") \ + && cd $VTERM_BUILD_DIR \ + && cmake -S . -B build \ + && cmake --build build diff --git a/containers/emacs/emacs_init.sh b/containers/emacs/emacs_init.sh new file mode 100755 index 0000000..6b80702 --- /dev/null +++ b/containers/emacs/emacs_init.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Copyright (c) 2023 Tim Perkins + +set -o errexit +set -o nounset +set -o pipefail +IFS=$'\n\t' + +# This should never happen, but check anyway +if [ -z "${EMACS_CONFIG_DIR:-}" -o -z "${EMACS_CONFIG_TARBALL:-}" \ + -o -z "${DOOM_CONFIG_DIR:-}" -o -z "${DOOM_CONFIG_TARBALL:-}" ]; then + echo "ERROR: Essential Emacs variables are not defined!" >&2 + exit 1 +fi + +is_empty_dir() { + find "$1" -maxdepth 0 -type d -empty | grep -q . +} + +if is_empty_dir $EMACS_CONFIG_DIR; then + echo "Initializing Emacs config: $EMACS_CONFIG_DIR" + tar -C $EMACS_CONFIG_DIR --extract -f $EMACS_CONFIG_TARBALL +fi + +if is_empty_dir $DOOM_CONFIG_DIR; then + echo "Initializing Doom config: $DOOM_CONFIG_DIR" + tar -C $DOOM_CONFIG_DIR --extract -f $DOOM_CONFIG_TARBALL +fi + +exec "$@" diff --git a/containers/run.sh b/containers/run.sh index f90feda..3b27d71 100755 --- a/containers/run.sh +++ b/containers/run.sh @@ -13,8 +13,6 @@ DEFAULT_TARGET_TAG="main" # The names of the volumes SHELL_CONFIG_VOL="shell-config" -EMACS_CONFIG_VOL="emacs-config" -DOOM_CONFIG_VOL="doom-config" # The default projects directory DEFAULT_PROJECTS_DIR="$HOME/Projects" @@ -141,7 +139,7 @@ EMACS_CONFIG_DIR=$(get_from_env "$IMAGE_ENV" "EMACS_CONFIG_DIR" || true) DOOM_CONFIG_DIR=$(get_from_env "$IMAGE_ENV" "DOOM_CONFIG_DIR" || true) # Check for volumes, create them if necessary -vols=($SHELL_CONFIG_VOL $EMACS_CONFIG_VOL $DOOM_CONFIG_VOL) +vols=($SHELL_CONFIG_VOL) for vol in "${vols[@]}"; do if ! docker volume ls -q | grep -q $vol; then echo "Creating volume: $vol" >&2 @@ -157,6 +155,9 @@ ensure_exists f 644 $HOME/.gitconfig ensure_exists d 700 $HOME/.xpra ensure_exists f 600 $HOME/.claude.json ensure_exists d 700 $HOME/.claude +ensure_exists d 700 $HOME/.taughz +ensure_exists d 700 $HOME/.taughz/emacs.d +ensure_exists d 700 $HOME/.taughz/doom.d # Get the user data ready passwd_ent=$(getent passwd $(id -u)) @@ -214,8 +215,8 @@ SHELL_FLAGS=( emacs_flags=() if [ -n "$EMACS_CONFIG_DIR" -a -n "$DOOM_CONFIG_DIR" ]; then - emacs_flags+=(--mount "type=volume,src=$EMACS_CONFIG_VOL,dst=$EMACS_CONFIG_DIR") - emacs_flags+=(--mount "type=volume,src=$DOOM_CONFIG_VOL,dst=$DOOM_CONFIG_DIR") + emacs_flags+=(--mount "type=bind,src=$HOME/.taughz/emacs.d,dst=$EMACS_CONFIG_DIR") + emacs_flags+=(--mount "type=bind,src=$HOME/.taughz/doom.d,dst=$DOOM_CONFIG_DIR") fi projects_flags=()