Skip to content

Commit

Permalink
Merge pull request #143 from nmfs-opensci/dev
Browse files Browse the repository at this point in the history
Use scripts instead of ONBUILD
  • Loading branch information
eeholmes authored Nov 5, 2024
2 parents adffffa + d4b3732 commit b3a167e
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 101 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ on:
- 'appendix'
- 'desktop.sh'
- 'rocker.sh'
- 'scripts/**'
- '.github/workflows/build-dev.yaml'

jobs:
Expand Down
111 changes: 10 additions & 101 deletions appendix
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
USER root

# Clean up extra files in ${REPO_DIR}
RUN rm -rf ${REPO_DIR}/book ${REPO_DIR}/docs

# repo2docker does not set this. This is the default env in repo2docker type images
ENV CONDA_ENV=notebook
# Tell applications where to open desktop apps - this allows notebooks to pop open GUIs
Expand Down Expand Up @@ -38,113 +41,19 @@ RUN mandb
RUN cp ${REPO_DIR}/custom_jupyter_server_config.json ${NB_PYTHON_PREFIX}/etc/jupyter/jupyter_server_config.d/
RUN cp ${REPO_DIR}/custom_jupyter_server_config.json ${NB_PYTHON_PREFIX}/etc/jupyter/jupyter_notebook_config.d/

# Clean up extra files in ${REPO_DIR}
RUN rm -rf ${REPO_DIR}/book ${REPO_DIR}/docs
# Copy scripts into /pyrocket_scripts directory in the image
RUN mkdir -p /pyrocket_scripts && cp -r ${REPO_DIR}/scripts/* /pyrocket_scripts/

# Set ownership to root and permissions to 755
RUN chown -R root:staff /pyrocket_scripts && \
chmod -R 775 /pyrocket_scripts

###################
# Set up behavior for child dockerfiles
# Convert NB_USER to ENV (from ARG) so that it passes to the child dockerfile
ENV NB_USER=${NB_USER}

## ONBUILD section. These commands are run in child Dockerfiles. These are run right after the FROM image is loaded

ONBUILD RUN echo "py-rocket-base: looking for configuration files to use"

ONBUILD USER ${NB_USER}

# ${REPO_DIR} is owned by ${NB_USER}
# Copy the child repo files into childimage so they are available to scripts
ONBUILD COPY --chown=${NB_USER}:${NB_USER} . ${REPO_DIR}/childimage

# The Desktop and apt.txt installs need to be root
ONBUILD USER root

# Copy Desktop files into ${REPO_DIR}/Desktop if they exist. start will copy to Application dir and Desktop
# Will not fail if Desktop dir exists but is empty
ONBUILD RUN echo "Checking for 'Desktop directory'..." \
; cd "${REPO_DIR}/childimage/" \
; if test -d Desktop ; then \
mkdir -p "${REPO_DIR}/Desktop" && \
cp -r Desktop/* "${REPO_DIR}/Desktop/" 2>/dev/null && \
chmod +x "${REPO_DIR}/desktop.sh" ; \
fi \
; "${REPO_DIR}/desktop.sh"

# Install apt packages specified in a apt.txt file if it exists.
# blank lines and comments are supported in apt.txt
ONBUILD RUN echo "Checking for 'apt.txt'..." \
; cd "${REPO_DIR}/childimage/" \
; if test -f "apt.txt" ; then \
package_list=$(grep -v '^\s*#' apt.txt | grep -v '^\s*$' | sed 's/\r//g; s/#.*//; s/^[[:space:]]*//; s/[[:space:]]*$//' | awk '{$1=$1};1') \
&& apt-get update --fix-missing > /dev/null \
&& apt-get install --yes --no-install-recommends $package_list \
&& apt-get autoremove --purge \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
; fi

ONBUILD USER ${NB_USER}

# Add the conda environment
# sometimes package solving will get rid of pip installed packages. Make sure jupyter-remote-desktop-proxy does not disappear
ONBUILD RUN echo "Checking for 'conda-lock.yml' or 'environment.yml'..." \
; cd "${REPO_DIR}/childimage/" \
; if test -f "conda-lock.yml" ; then echo "Using conda-lock.yml" & \
conda-lock install --name ${CONDA_ENV} \
&& pip install --no-deps jupyter-remote-desktop-proxy \
; elif test -f "environment.yml" ; then echo "Using environment.yml" & \
mamba env update --name ${CONDA_ENV} -f environment.yml \
&& pip install --no-deps jupyter-remote-desktop-proxy \
; fi \
&& mamba clean -yaf \
&& find ${CONDA_DIR} -follow -type f -name '*.a' -delete \
&& find ${CONDA_DIR} -follow -type f -name '*.js.map' -delete \
; if ls ${NB_PYTHON_PREFIX}/lib/python*/site-packages/bokeh/server/static > /dev/null 2>&1; then \
find ${NB_PYTHON_PREFIX}/lib/python*/site-packages/bokeh/server/static -follow -type f -name '*.js' ! -name '*.min.js' -delete \
; fi

# If a requirements.txt file exists, use pip to install packages
# listed there. We don't want to save cached wheels in the image
# to avoid wasting space.
ONBUILD RUN echo "Checking for pip 'requirements.txt'..." \
; cd "${REPO_DIR}/childimage/" \
; if test -f "requirements.txt" ; then \
${NB_PYTHON_PREFIX}/bin/pip install --no-cache -r requirements.txt \
; fi

# Add the r packages
ONBUILD RUN echo "Checking for 'install.R" \
; cd "${REPO_DIR}/childimage/" \
; if test -f "install.R" ; then echo "Using install.R" & \
Rscript install.R \
; fi

# If a start file exists, put that under ${REPO_DIR}/childimage/start.
# This is sourced in ${REPO_DIR}/start
ONBUILD RUN echo "Checking for 'start'..." \
; cd "${REPO_DIR}/childimage/" \
; if test -f "start" ; then \
chmod +x start \
; fi

# If a postBuild file exists, run it!
# After it's done, we try to remove any possible cruft commands there
# left behind under $HOME - particularly stuff that jupyterlab extensions
# leave behind.
ONBUILD RUN echo "Checking for 'postBuild'..." \
; cd "${REPO_DIR}/childimage/" \
; if test -f "postBuild" ; then \
chmod +x postBuild \
&& ./postBuild \
&& rm -rf /tmp/* \
&& rm -rf ${HOME}/.cache ${HOME}/.npm ${HOME}/.yarn \
&& rm -rf ${NB_PYTHON_PREFIX}/share/jupyter/lab/staging \
&& find ${CONDA_DIR} -follow -type f -name '*.a' -delete \
&& find ${CONDA_DIR} -follow -type f -name '*.js.map' -delete \
; fi

## End ONBUILD section for child images
################################

# Revert to default user and home as pwd
USER ${NB_USER}
WORKDIR ${HOME}
52 changes: 52 additions & 0 deletions scripts/install-apt-packages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash
# Required User: root

echo "Running install-apt-packages.sh"

# Check that a file name is provided
if [ -z "$1" ]; then
echo "Error: install-apt-packages.sh requires a file name (a list of apt packages and typically called apt.txt)." >&2
echo "Usage: RUN /pyrocket_scripts/install-apt-packages.sh <filename>" >&2
exit 1
fi

# Check if the script is run as root
if [[ $(id -u) -ne 0 ]]; then
echo "Error: install-apt-packages.sh must be run as root. Please use 'USER root' in your Dockerfile before running this script."
echo "Remember to switch back to the non-root user with 'USER ${NB_USER}' after running this script."
exit 1
fi

echo "Running install-apt-packages.sh as root..."

# Set variable for the provided file
apt_file="$1"
echo " Using packages file: ${apt_file}"

# Check if the specified file exists
if [ ! -f "${apt_file}" ]; then
echo " Error: File '${apt_file}' not found. Ensure the file exists and try again."
exit 1
fi

# Update package list and handle errors
echo " Updating package list..."
if ! apt-get update --fix-missing; then
echo " Error: Failed to update package list. Exiting."
exit 1
fi

# Install packages and handle errors
echo " Installing packages from ${apt_file}..."
package_list=$(grep -v '^\s*#' "${apt_file}" | grep -v '^\s*$' | sed 's/\r//g; s/#.*//; s/^[[:space:]]*//; s/[[:space:]]*$//' | awk '{$1=$1};1')
if ! apt-get install --yes --no-install-recommends $package_list; then
echo " Error: Installation of packages failed. Please check the package names and try again."
exit 1
fi

# Clean up
apt-get autoremove --purge
apt-get clean
rm -rf /var/lib/apt/lists/*

echo " Success! install-apt-packages.sh"
59 changes: 59 additions & 0 deletions scripts/install-conda-packages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash
# Required User: NB_USER

# Check if a filename argument is provided
if [ -z "$1" ]; then
echo "Error: install-conda-packages.sh requires a file name (either conda-lock.yml or environment.yml)." >&2
echo "Usage: RUN /pyrocket_scripts/install-conda-packages.sh <filename.yml>" >&2
exit 1
fi

# Check if running as root and switch to NB_USER if needed
if [[ $(id -u) -eq 0 ]]; then
echo "Switching to ${NB_USER} to run install-conda-packages.sh"
exec su "${NB_USER}" -c "/bin/bash $0 $1" # Pass along the filename argument
fi

# Main script execution as NB_USER
echo "Running install-conda-packages.sh as ${NB_USER}"

# Set the file variable to the provided argument
ENV_FILE="$1"

# Verify the file exists and is readable
if [ ! -f "$ENV_FILE" ]; then
echo " Error: File '$ENV_FILE' not found. Please provide a valid file path." >&2
echo " Usage: RUN /pyrocket_scripts/install-conda-packages.sh <filename.yml>" >&2
exit 1
fi

echo " Found file: $ENV_FILE"

# Determine file type based on content
if grep -q "lock_set" "$ENV_FILE"; then
echo " Detected conda-lock.yml file."
${NB_PYTHON_PREFIX}/bin/conda-lock install --name ${CONDA_ENV} -f "$ENV_FILE"
INSTALLATION_HAPPENED=true
elif grep -q "name:" "$ENV_FILE"; then
echo " Detected environment.yml file."
${CONDA_DIR}/condabin/mamba env update --name ${CONDA_ENV} -f "$ENV_FILE"
INSTALLATION_HAPPENED=true
else
# If neither condition matches, output a helpful error message
echo "Error: Unrecognized file format in '${env_file}'."
echo " - For an environment.yml file, ensure it includes a 'name:' entry. Any name is acceptable."
echo " - For a conda-lock.yml file, ensure it includes a 'lock_set:' entry."
exit 1
fi

# Run cleanup if installation occurred
if [ "$INSTALLATION_HAPPENED" = true ]; then
${CONDA_DIR}/condabin/mamba clean -yaf
find ${CONDA_DIR} -follow -type f -name '*.a' -delete
find ${CONDA_DIR} -follow -type f -name '*.js.map' -delete
if ls ${NB_PYTHON_PREFIX}/lib/python*/site-packages/bokeh/server/static > /dev/null 2>&1; then
find ${NB_PYTHON_PREFIX}/lib/python*/site-packages/bokeh/server/static -follow -type f -name '*.js' ! -name '*.min.js' -delete
fi
fi

echo " Success! install-conda-packages.sh"
45 changes: 45 additions & 0 deletions scripts/install-desktop.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/bash
# Required User: root

echo "Running setup-desktop.sh"

# Check if the script is run as root
if [[ $(id -u) -ne 0 ]]; then
echo " Error: This script must be run as root. Please use 'USER root' in your Dockerfile before running this script."
echo " Remember to switch back to the non-root user with 'USER ${NB_USER}' after running this script."
exit 1
fi

# Check if a filename argument is provided
if [ -n "$1" ]; then
echo " Warning: Passed-in file '$1' is ignored. Looking for Desktop files in the 'Desktop' directory in your repository." >&2
fi

echo " Checking for ${REPO_DIR}/childimage/..."
if [ -d "${REPO_DIR}/childimage/" ]; then
cd "${REPO_DIR}/childimage/" || exit 1

echo " Checking for Desktop directory..."
if test -d "${REPO_DIR}/childimage/Desktop"; then

echo " ${REPO_DIR}/childimage/Desktop directory found. Proceeding with installation..."

mkdir -p "${REPO_DIR}/Desktop"
cp -r ${REPO_DIR}/childimage/Desktop/* "${REPO_DIR}/Desktop/" 2>/dev/null

# Check if desktop.sh exists before executing
if test -f "${REPO_DIR}/desktop.sh"; then
echo " Running ${REPO_DIR}/desktop.sh."
chmod +x "${REPO_DIR}/desktop.sh"
"${REPO_DIR}/desktop.sh"
else
echo " Warning: desktop.sh not found. Skipping execution."
fi
else
echo " No Desktop directory found in ${REPO_DIR}/childimage/. Skipping setup."
fi
else
echo " Directory ${REPO_DIR}/childimage/ does not exist. Skipping script."
fi

echo " Success! install-desktop.sh"
40 changes: 40 additions & 0 deletions scripts/install-pip-packages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash
# Required User: NB_USER

# Check if a filename argument is provided
if [ -z "$1" ]; then
echo "Error: install-pip-packages.sh requires an input file of package names (typically called requirements.txt)." >&2
echo "Usage: RUN /pyrocket_scripts/install-pip-packages.sh <filename>" >&2
exit 1
fi

# Check if running as root and switch to NB_USER if needed
if [[ $(id -u) -eq 0 ]]; then
echo "Switching to ${NB_USER} to run install-pip-packages.sh"
exec su "${NB_USER}" -c "/bin/bash $0 $1" # Pass along the filename argument
fi

# Main script execution as NB_USER
echo "Running install-pip-packages.sh as ${NB_USER}"


# Set variable for the provided file
requirements_file="$1"
echo " Using packages file: ${requirements_file}"

# Check if the specified file exists
if [ ! -f "${requirements_file}" ]; then
echo " Error: File '${requirements_file}' not found. Ensure the file exists and try again."
exit 1
fi

echo " Installing pip packages from ${requirements_file} as ${NB_USER}..."

# Install pip packages and handle errors
if ! ${NB_PYTHON_PREFIX}/bin/pip install --no-cache -r "${requirements_file}"; then
echo " Error: Installation of packages from '${requirements_file}' failed. Please check the package names and try again."
exit 1
fi

echo " Success! install-pip-packages.sh"

38 changes: 38 additions & 0 deletions scripts/install-r-packages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash
# Required User: NB_USER

# Check if a filename argument is provided
if [ -z "$1" ]; then
echo "Error: install-r-packages.sh requires an input file (an R script and typically called install.R)." >&2
echo "Usage: RUN /pyrocket_scripts/install-r-packages.sh <filename>" >&2
exit 1
fi

# Check if running as root and switch to NB_USER if needed
if [[ $(id -u) -eq 0 ]]; then
echo "Switching to ${NB_USER} to run install-r-packages.sh"
exec su "${NB_USER}" -c "/bin/bash $0 $1" # Pass along the filename argument
fi

# Main script execution as NB_USER
echo "Running install-r-packages.sh as ${NB_USER}"

# Set the file variable to the provided argument
INSTALL_FILE="$1"

# Verify the file exists and is readable
if [ ! -f "$INSTALL_FILE" ]; then
echo " Error: File '$INSTALL_FILE' not found. Please provide a valid R script file." >&2
echo " Usage: RUN /pyrocket_scripts/install-r-packages.sh <filename>" >&2
exit 1
fi

echo " Found file: $INSTALL_FILE"

# Install R packages using the provided R script
if ! Rscript "$INSTALL_FILE"; then
echo " Error: Installation of packages from '$INSTALL_FILE' failed. Please check the script for errors." >&2
exit 1
fi

echo " Success! install-r-packages.sh"
Loading

0 comments on commit b3a167e

Please sign in to comment.