diff --git a/Dockerfile b/Dockerfile index 496af2b..52f924e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -93,31 +93,14 @@ RUN printf '%s\n%s\n%s\n\n%s\n' \ '[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"' \ "$(cat /etc/bash.bashrc)" > /etc/bash.bashrc -# Create a shell wrapper that sources nvm before executing commands -RUN echo '#!/bin/bash' > /usr/local/bin/bash-with-nvm \ - && echo 'set -e' >> /usr/local/bin/bash-with-nvm \ - && echo 'export NVM_DIR="/usr/local/nvm"' >> /usr/local/bin/bash-with-nvm \ - && echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> /usr/local/bin/bash-with-nvm \ - && echo 'eval "$@"' >> /usr/local/bin/bash-with-nvm \ - && chmod +x /usr/local/bin/bash-with-nvm +# Copy nvm wrapper scripts from support directory +COPY image_support_files/bash-with-nvm /usr/local/bin/bash-with-nvm +COPY image_support_files/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh +RUN chmod +x /usr/local/bin/bash-with-nvm /usr/local/bin/docker-entrypoint.sh # Use wrapper for RUN commands to enable nvm SHELL ["/usr/local/bin/bash-with-nvm"] -# Create entrypoint wrapper for runtime nvm support (CI/CD workflows) -RUN echo '#!/bin/bash' > /usr/local/bin/docker-entrypoint.sh \ - && echo 'set -e' >> /usr/local/bin/docker-entrypoint.sh \ - && echo 'export NVM_DIR="/usr/local/nvm"' >> /usr/local/bin/docker-entrypoint.sh \ - && echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> /usr/local/bin/docker-entrypoint.sh \ - && echo '# If command is bash, source nvm in it' >> /usr/local/bin/docker-entrypoint.sh \ - && echo 'if [ "$1" = "bash" ] && [ "$2" = "-c" ]; then' >> /usr/local/bin/docker-entrypoint.sh \ - && echo ' shift 2' >> /usr/local/bin/docker-entrypoint.sh \ - && echo ' exec bash -c "source /etc/bash.bashrc && $*"' >> /usr/local/bin/docker-entrypoint.sh \ - && echo 'else' >> /usr/local/bin/docker-entrypoint.sh \ - && echo ' exec "$@"' >> /usr/local/bin/docker-entrypoint.sh \ - && echo 'fi' >> /usr/local/bin/docker-entrypoint.sh \ - && chmod +x /usr/local/bin/docker-entrypoint.sh - # Enable nvm for runtime bash commands (CI/CD workflows) ENV BASH_ENV=/etc/bash.bashrc diff --git a/image_support_files/README.md b/image_support_files/README.md new file mode 100644 index 0000000..e8c72eb --- /dev/null +++ b/image_support_files/README.md @@ -0,0 +1,90 @@ +# Image Support Files + +This directory contains helper scripts that are copied into the Docker image during build to enable NVM functionality. + +## Files + +### `bash-with-nvm` + +**Purpose**: Wrapper script for Dockerfile RUN commands + +**Usage**: Set as SHELL directive in Dockerfile +```dockerfile +SHELL ["/usr/local/bin/bash-with-nvm"] +``` + +**What it does**: +- Sources nvm before executing each Dockerfile RUN command +- Enables direct usage of `nvm` commands without manual sourcing +- Example: `RUN nvm install 18` works without `bash -c "source ..."` + +**Location in image**: `/usr/local/bin/bash-with-nvm` + +**How it works**: +1. Exports NVM_DIR environment variable +2. Sources `$NVM_DIR/nvm.sh` to load nvm functions +3. Executes the command passed to it via `eval "$@"` + +--- + +### `docker-entrypoint.sh` + +**Purpose**: ENTRYPOINT script for runtime nvm support + +**Usage**: Set as ENTRYPOINT in Dockerfile +```dockerfile +ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] +``` + +**What it does**: +- Makes nvm available in `docker run ... bash -c` commands +- Enables nvm in CI/CD workflow scripts +- Passes through non-bash commands unchanged + +**Location in image**: `/usr/local/bin/docker-entrypoint.sh` + +**How it works**: +1. Loads nvm in the entrypoint environment +2. Detects if command is `bash -c ...` +3. If yes: Injects `source /etc/bash.bashrc` before the user's command +4. If no: Executes command as-is with `exec "$@"` + +**Examples**: +- `docker run image bash -c "nvm install 18"` → nvm is available +- `docker run image node --version` → Passes through to node binary +- CI/CD: `run: nvm install 19` → Works automatically + +--- + +## Why These Scripts Are Needed + +**The Problem**: +- nvm is a bash function, not a binary executable +- It must be sourced into each shell session +- Docker RUN commands and `bash -c` don't automatically source it + +**The Solution**: +1. **bash-with-nvm**: Makes Dockerfile RUN commands work +2. **docker-entrypoint.sh**: Makes runtime `bash -c` commands work +3. **/etc/bash.bashrc** (configured in Dockerfile): Makes interactive shells work + +Together, these provide seamless nvm access in all contexts. + +--- + +## Maintenance + +**Modifying the scripts**: +1. Edit the file in this directory +2. Rebuild the Docker image +3. Test with both `docker build` and `docker run` scenarios + +**Testing checklist**: +- [ ] `RUN nvm install 18` works in Dockerfile +- [ ] `docker run image bash -c "nvm install 18"` works +- [ ] `docker run image node --version` still works (fallback) +- [ ] CI/CD workflows can use nvm commands + +**Debugging**: +- View script in running container: `docker run image cat /usr/local/bin/bash-with-nvm` +- Test entrypoint manually: `docker run --entrypoint /bin/bash image -c "nvm --version"` diff --git a/image_support_files/bash-with-nvm b/image_support_files/bash-with-nvm new file mode 100644 index 0000000..49280ab --- /dev/null +++ b/image_support_files/bash-with-nvm @@ -0,0 +1,9 @@ +#!/bin/bash +set -e + +# Load nvm before executing Dockerfile RUN commands +export NVM_DIR="/usr/local/nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + +# Execute the command passed to this wrapper +eval "$@" diff --git a/image_support_files/docker-entrypoint.sh b/image_support_files/docker-entrypoint.sh new file mode 100644 index 0000000..191aa5d --- /dev/null +++ b/image_support_files/docker-entrypoint.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +# Load nvm in the entrypoint environment +export NVM_DIR="/usr/local/nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + +# If command is bash -c, inject bashrc sourcing to make nvm available +if [ "$1" = "bash" ] && [ "$2" = "-c" ]; then + shift 2 + exec bash -c "source /etc/bash.bashrc && $*" +else + exec "$@" +fi