refactor(nvm): Move wrapper scripts to image_support_files directory

Improved code organization and maintainability:
- Created image_support_files/ directory for Docker helper scripts
- Moved bash-with-nvm and docker-entrypoint.sh to support directory
- Added comprehensive README.md documenting each script's purpose
- Updated Dockerfile to COPY from organized directory structure

Benefits:
- Cleaner repository structure
- Scripts are now version-controlled files (not echo chains)
- Easier to read, modify, and maintain
- Self-documented with in-directory README

No functional changes - all nvm functionality remains identical.
This commit is contained in:
2025-10-26 10:38:59 +00:00
parent 3aea4a70ee
commit bb8d623c95
4 changed files with 117 additions and 21 deletions

View File

@@ -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

View File

@@ -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"`

View File

@@ -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 "$@"

View File

@@ -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