Skip to content

Instantly share code, notes, and snippets.

@jmkim
Last active June 24, 2025 10:30
Show Gist options
  • Save jmkim/0281a433a94a993acef3d4224c7ec21e to your computer and use it in GitHub Desktop.
Save jmkim/0281a433a94a993acef3d4224c7ec21e to your computer and use it in GitHub Desktop.
#!/bin/sh
export SHELL_NAME="$(ps -p $$ -o comm=)"
export NANDBASE_GIT='https://github.com/doubleo-dev/nand-base.git'
export NANDBASE_ROOT="$HOME/nand-base"
export CONDA_INSTALLER_PATH="$NANDBASE_ROOT/Anaconda3-Linux-x86_64.sh"
export CONDA_PAGE_URL='https://www.anaconda.com/download/success'
export CONDA_LATEST_URL_REGEX='https://repo.anaconda.com/archive/Anaconda3-[^"]*-Linux-x86_64.sh'
export FLAG_DEPS_COMMON="$NANDBASE_ROOT/.deps-installed"
get_select() {
# Prompt for input in a Linux shell script
# https://stackoverflow.com/a/226724
__prompt="$1"
while true; do
echo -n "$__prompt ('yes' or 'no') : "
read __answer
case "$__answer" in
[YyTt1]* ) return 1; ;; # yes, true
[NnFf0]* ) return 0; ;; # no, false
* ) echo "ERROR: Please answer 'yes' or 'no'.";;
esac
done
}
is_sourced() {
# Detect if a script is being sourced
# https://stackoverflow.com/a/28776166
if [ -n "$ZSH_VERSION" ]; then
case "$ZSH_EVAL_CONTEXT" in *:file:*) return 0;; esac # sourced
else # add additional POSIX-compatible shell names here, if needed
case "${0##*/}" in dash|-dash|bash|-bash|ksh|-ksh|sh|-sh) return 0;; esac # sourced
fi
return 1 # not sourced
}
count_missing_submodules() {
__count=0
while read -r __line; do
case "$__line" in
-*) __count=$((__count + 1));;
esac
done
echo "$__count" # stdout the number of missing submodules
return $__count
}
conda_find_env() {
__env_name="$1"
if conda env list 2> /dev/null | awk '{print $1}' | grep -x "$__env_name" > /dev/null; then
return 0 # success
else
return 1 # failure
fi
}
conda_get_latest_url() {
# stdout the url
curl "$CONDA_PAGE_URL" 2>/dev/null | grep -o '' | head -n1
return $?
}
conda_download_latest() {
__conda_url="$1"
__conda_installer="$2"
curl -L "$__conda_url" -o "$__conda_installer"
return $?
}
check_deps() {
if ! is_sourced; then
echo 'ERROR: The script was executed directly, not sourced. Please run using "source" or "." (a single dot).'
echo ''
echo " expected: source $0"
echo " . $0"
echo " got: $0 $@"
echo ''
echo " hint: . $0 (Note the leading dot and the required space)"
echo ''
return 11
fi
__real_script_path="$(dirname "$(realpath "$0")")"
__expected_script_path="$NANDBASE_ROOT/bin"
if [ "$__real_script_path" != "$__expected_script_path" ]; then
echo 'ERROR: The script was executed in incorrect path. Please run at the expected path.'
echo ''
echo " expected: $__expected_script_path"
echo " got: $__real_script_path"
echo ''
echo " hint: . $_expected_script_path"
echo ''
echo ' note: To run the script anywhere, add following line to your shell rc file:'
echo ''
echo " echo PATH=\"$NANDBASE_ROOT/bin:$PATH\" > ~/.${SHELL_NAME}rc"
echo ''
get_select 'PROMPT: If you did not clone the NAND flash development base yet, do you want to download?'
if [ $? -eq 0 ]; then
return 12
fi
git clone --recursive "$NANDBASE_GIT" "$NANDBASE_ROOT"
if [ $? -ne 0 ]; then
echo 'ERROR: Failed to clone the NAND flash development base. Please clone it with Git manually.'
echo ''
echo " hint: git clone --recursive $NANDBASE_GIT $NANDBASE_ROOT"
echo ''
return 13
fi
echo 'INFO: NAND flash development base has been downloaded.'
echo ' Please re-run the script.'
echo ''
echo " hint: . $_expected_script_path"
return 14
fi
if [ ! -f "$FLAG_DEPS_COMMON" ]; then
get_select 'PROMPT: The common dependencies not installed. Install now?'
if [ $? -eq 0 ]; then
echo 'ERROR: The common dependencies not installed.'
echo ''
echo " expected: $FLAG_DEPS_COMMON"
echo ' got: (flag file does not exist at the expected path)'
echo ''
echo ' hint: sudo apt install git'
echo " touch $FLAG_DEPS_COMMON"
echo ''
return 15
fi
sudo apt install git
if [ $? -ne 0 ]; then
echo 'ERROR: An error occurred during installing the dependencies.'
echo ''
echo ' hint: sudo apt install git'
echo " touch $FLAG_DEPS_COMMON"
echo ''
return 16
fi
touch $FLAG_DEPS_COMMON
if [ $? -ne 0 ]; then
echo 'WARNING: Cannot access to the flag file. You should touch it manually.'
echo ''
echo " hint: touch $FLAG_DEPS_COMMON"
echo ''
fi
fi
__expected_git_path="$NANDBASE_ROOT/.git"
if [ ! -d "$__real_git_path" ]; then
get_select 'PROMPT: The NAND flash development base is missing. Download now?'
if [ $? -eq 0 ]; then
echo 'ERROR: The NAND flash development base is missing. Please clone it with Git.'
echo ''
echo " expected: $__expected_git_path"
echo ' got: (directory does not exist at the expected path)'
echo ''
echo " hint: git clone --recursive $NANDBASE_GIT $NANDBASE_ROOT"
echo ''
return 12
fi
git clone --recursive "$NANDBASE_GIT" "$NANDBASE_ROOT"
if [ $? -ne 0 ]; then
echo 'ERROR: Failed to clone the NAND flash development base. Please clone it with Git manually.'
echo ''
echo " hint: git clone --recursive $NANDBASE_GIT $NANDBASE_ROOT"
echo ''
return 13
fi
echo 'INFO: NAND flash development base downloaded completed.'
fi
which conda > /dev/null 2>&1
if [ $? -ne 0 ]; then
get_select "PROMPT: Anaconda is missing. Download now?"
if [ $? -eq 0 ]; then
echo 'ERROR: Anaconda is not installed. Please install it.'
echo ''
echo " hint: 1. Visit $CONDA_PAGE_URL"
echo ' 2. Open "Distribution Installers"'
echo ' 3. Download "Linux 64-Bit (x86) Installer"'
echo ' 4. Open a terminal and run the following commands:'
echo ''
echo ' chmod +x Anaconda3-$VERSION-Linux-x86_64.sh'
echo ' ./Anaconda3-$VERSION-Linux-x86_64.sh'
echo ''
echo ' 5. Follow the installer prompts. Enable shell integration when prompted.'
echo ' 6. Restart the terminal.'
echo ''
return 13
fi
__conda_installer="$CONDA_INSTALLER_PATH"
__conda_url="$(conda_get_latest_url)"
__retcode=$?
if [ $__retcode -eq 0 ]; then
echo "INFO: Downloading Anaconda installer from $__conda_url"
conda_download_latest "$__conda_url" "$__conda_installer"
__retcode=$?
fi
if [ $__retcode -ne 0 ]; then
echo 'ERROR: Failed to download Anaconda. Please download manually.'
echo ''
echo ' hint: 1. Check your Internet connection.'
echo " 2. Visit $CONDA_PAGE_URL"
echo ' 3. Open "Distribution Installers"'
echo ' 4. Download "Linux 64-Bit (x86) Installer"'
echo ' 5. Open a terminal and run the following commands:'
echo ''
echo ' chmod +x Anaconda3-$VERSION-Linux-x86_64.sh'
echo ' ./Anaconda3-$VERSION-Linux-x86_64.sh'
echo ''
echo ' 6. Follow the installer prompts. Enable shell integration when prompted.'
echo ' 7. Restart the terminal.'
echo ''
return 14
fi
echo "INFO: Anaconda installer downloaded to $__conda_installer"
echo 'INFO: Running Anaconda installer. Please follow the prompts. Enable shell integration when prompted.'
chmod +x "$__conda_installer"
"$__conda_installer"
if [ $? -ne 0 ]; then
echo 'ERROR: Anaconda installation failed.'
echo ''
echo ' hint: Check the error messages above.'
echo ''
return 15
fi
echo 'INFO: Anaconda installation completed.'
fi
return 0
}
check_deps_riot() {
if [ ! -d "$RIOTBASE" ]; then
get_select 'PROMPT: RIOT OS base submodule is missing. Download now?'
if [ $? -eq 0 ]; then
echo 'ERROR: Failed to load the RIOT OS base submodule.'
echo ''
echo " expected: $RIOTBASE"
echo ' got: (directory does not exist at the expected path)'
echo ''
echo " hint: cd $NANDBASE_ROOT"
echo ' git submodule update --init --recursive'
echo ''
return 31
fi
pushd "$NANDBASE_ROOT"
git submodule update --init --recursive
__retcode=$?
popd
if [ $__retcode -ne 0 ]; then
echo 'ERROR: An error occurred while downloading the RIOT OS.'
echo ''
echo " hint: cd $NANDBASE_ROOT"
echo ' git submodule update --init --recursive'
echo ''
return 32
fi
echo 'INFO: RIOT OS download completed.'
fi
if [ ! -d "$IDF_PATH" ]; then
get_select 'PROMPT: RIOT OS patched ESP-IDF is not installed. Install?'
if [ $? -eq 0 ]; then
echo 'ERROR: RIOT OS patched ESP-IDF is not installed properly.'
echo ''
echo " expected: $IDF_PATH"
echo ' got: (directory does not exist at the expected path)'
echo ''
echo " hint: cd $IDF_PATH"
echo ' git submodule update --init --recursive'
echo ''
return 33
fi
make -f ~/nand-base/riot/esp-idf.Makefile
if [ $? -ne 0 ]; then
echo 'ERROR: An error occurred during installing RIOT OS patched ESP-IDF.'
return 34
fi
echo 'INFO: RIOT OS patched ESP-IDF installation completed.'
fi
pushd "$IDF_PATH" > /dev/null 2>&1
__missing_submodules_count="$(git submodule status | count_missing_submodules)"
popd > /dev/null 2>&1
if [ "$__missing_submodules_count" != "0" ]; then
get_select 'PROMPT: RIOT OS patched ESP-IDF submodules not loaded. Download now?'
if [ $? -eq 0 ]; then
echo 'ERROR: RIOT OS patched ESP-IDF submodules not loaded properly.'
echo ''
echo ' expected: 0'
echo " got: $__missing_submodules_count (number of missing submodules)"
echo ''
echo ' hint: cd ~/nand-base/riot/esp-idf'
echo ' git submodule update --init --recursive'
echo ''
return 35
fi
pushd ~/nand-base/riot/esp-idf
git submodule update --init --recursive
__retcode=$?
popd
if [ $__retcode -ne 0 ]; then
echo 'ERROR: An error occurred during downloading the RIOT OS patched ESP-IDF submodules.'
return 36
fi
echo "INFO: RIOT OS patched ESP-IDF submodules have been loaded."
fi
conda_find_env "$CONDA_ENV_NAME"
if [ $? -ne 0 ]; then
get_select "PROMPT: Anaconda environment '$CONDA_ENV_NAME' not created. Create?"
if [ $? -eq 0 ]; then
echo 'ERROR: Anaconda environment '$CONDA_ENV_NAME' not created. Please create the environment.'
echo ''
echo " hint: conda create -n $CONDA_ENV_NAME python=3.8"
echo " conda activate $CONDA_ENV_NAME"
echo ' pip install psutil'
echo ''
return 37
fi
conda create -n "$CONDA_ENV_NAME" python=3.8
if [ $? -ne 0 ]; then
echo "ERROR: Anaconda environment '$CONDA_ENV_NAME' creation failed."
echo ''
echo ' hint: Check the error messages above.'
echo ' You can create the environment manually:'
echo ''
echo " conda create -n $CONDA_ENV_NAME python=3.8"
echo " conda activate $CONDA_ENV_NAME"
echo ' pip install psutil'
echo ''
return 38
fi
echo "INFO: Anaconda environment '$CONDA_ENV_NAME' has been created."
pip install psutil
if [ $? -ne 0 ]; then
echo "WARNING: Python dependency 'psutil' installation failed."
echo ''
echo ' hint: Check the error messages above. You must install it manually:'
echo ''
echo " conda activate $CONDA_ENV_NAME"
echo ' pip install psutil'
echo ''
echo ' note: This warning will not appear again.'
echo ' Stopping here. After installing, re-run this script to continue.'
echo ''
return 39
fi
fi
__expected_idf_env_path="$IDF_TOOLS_PATH/idf-env.json"
if [ ! -f "$__expected_idf_env_path" ]; then
get_select "PROMPT: ESP32 tools are not installed. Install?"
if [ $? -eq 0 ]; then
echo 'ERROR: ESP32 tools are not installed properly.'
echo ''
echo " expected: $__expected_idf_env_path"
echo ' got: (directory does not exist at the expected path)'
echo ''
echo " hint: export IDF_PATH=$IDF_PATH"
echo " export IDF_TOOLS_PATH=$IDF_TOOLS_PATH"
echo " conda activate '$CONDA_ENV_NAME'"
echo ' cd ~/nand-base/riot/esp-idf'
echo ' ./install.sh all'
echo ''
return 39
fi
activate_conda || return $?
pushd ~/nand-base/riot/esp-idf
./install.sh all
__retcode=$?
popd
if [ $__retcode -ne 0 ]; then
echo 'ERROR: An error occurred during installing the ESP32 tools.'
return 40
fi
echo "INFO: ESP32 tools installation completed."
fi
return 0
}
check_deps_esp() {
if [ ! -d "$IDF_PATH" ]; then
get_select "PROMPT: ESP-IDF is not installed. Install?"
if [ $? -eq 0 ]; then
echo 'ERROR: ESP-IDF is not installed properly.'
echo ''
echo " expected: $IDF_PATH"
echo ' got: (directory does not exist at the expected path)'
echo ''
echo ' hint: cd ~/nand-base'
echo ' git submodule update --init --recursive'
echo ''
return 51
fi
pushd ~/nand-base
git submodule update --init --recursive
__retcode=$?
popd
if [ $__retcode -ne 0 ]; then
echo 'ERROR: An error occurred during installing the ESP-IDF.'
return 52
fi
echo "INFO: ESP-IDF installation completed."
fi
pushd "$IDF_PATH" > /dev/null 2>&1
__missing_submodules_count="$(git submodule status | count_missing_submodules)"
popd > /dev/null 2>&1
if [ "$__missing_submodules_count" != "0" ]; then
echo 'ERROR: ESP-IDF submodules not loaded properly.'
echo ''
echo ' expected: 0'
echo " got: $__missing_submodules_count (number of missing submodules)"
echo ''
echo ' hint: cd ~/nand-base/esp/esp-idf'
echo ' git submodule update --init --recursive'
echo ''
return 53
fi
__expected_idf_env_path="$IDF_TOOLS_PATH/idf-env.json"
if [ ! -f "$__expected_idf_env_path" ]; then
get_select "PROMPT: ESP32 tools are not installed. Install?"
if [ $? -eq 0 ]; then
echo 'ERROR: ESP32 tools are not installed properly.'
echo ''
echo " expected: $__expected_idf_env_path"
echo ''
echo ' hint: cd ~/nand-base/esp/esp-idf'
echo ' ./install.sh all'
echo ''
return 54
fi
pushd ~/nand-base/esp/esp-idf
activate_conda || return $?
./install.sh all
__retcode=$?
popd
if [ $__retcode -ne 0 ]; then
echo 'ERROR: An error occurred during installing the ESP-IDF.'
return 55
fi
echo "INFO: ESP-IDF installation completed."
fi
conda_find_env "$CONDA_ENV_NAME"
if [ $? -ne 0 ]; then
get_select "PROMPT: Anaconda environment '$CONDA_ENV_NAME' not created. Create?"
if [ $? -eq 0 ]; then
echo 'ERROR: Anaconda environment '$CONDA_ENV_NAME' not created. Please create the environment.'
echo ''
echo " hint: conda create -n $CONDA_ENV_NAME python=3.11"
echo ''
return 56
fi
conda create -n "$CONDA_ENV_NAME" python=3.11
if [ $? -ne 0 ]; then
echo "ERROR: Anaconda environment '$CONDA_ENV_NAME' creation failed."
echo ''
echo ' hint: Check the error messages above.'
echo ''
return 57
fi
echo "INFO: Anaconda environment '$CONDA_ENV_NAME' has been created."
fi
return 0
}
activate_conda() {
__env_name="do-nand-$NANDBASE"
eval "$(conda shell.$SHELL_NAME hook)"
conda activate "$__env_name"
if [ $? -ne 0 ]; then
echo 'ERROR: Failed to activate Anaconda environment.'
echo ''
echo ' hint: Check the error messages above.'
echo ''
return 71
fi
echo "INFO: Anaconda environment '$__env_name' activated."
return 0
}
activate_nand_riot () {
if [ -f "$RIOTBASE/dist/tools/esptools/export.sh" ]; then
. "$RIOTBASE/dist/tools/esptools/export.sh" esp32s3 > /dev/null
fi
if [ -f "$IDF_PATH/export.sh" ]; then
. "$IDF_PATH/export.sh" > /dev/null 2>&1
fi
echo "INFO: '$NANDBASE' activated. To deactivate: exit and restart the shell."
return 0
}
activate_nand_esp() {
if [ -f "$IDF_PATH/export.sh" ]; then
. "$IDF_PATH/export.sh" > /dev/null 2>&1
fi
echo "INFO: '$NANDBASE' activated. To deactivate: exit and restart the shell."
return 0
}
__current_cmd="$(basename $0)"
# Step 1: Verify required dependencies
check_deps || return $?
# Step 2: Validate the provided command
case "$__current_cmd" in
'activate-nand-riot' | 'anr' | \
'activate-nand-esp' | 'ane') ;;
*)
echo 'ERROR: The command is not supported.'
echo ''
echo ' expected: activate-nand-riot (= anr)'
echo ' activate-nand-esp (= ane)'
echo " got: $__current_cmd"
echo ''
return 121
;;
esac
# Step 3: Set the env paths
case "$__current_cmd" in
'activate-nand-riot' | 'anr')
export NANDBASE='riot'
export NANDBASE_PATH="$NANDBASE_ROOT/$NANDBASE"
export RIOTBASE="$NANDBASE_PATH/RIOT"
export IDF_PATH="$NANDBASE_PATH/esp-idf"
export IDF_TOOLS_PATH="$NANDBASE_PATH/.espressif"
export CONDA_ENV_NAME="do-nand-$NANDBASE"
export DEPS_FLAG="$NANDBASE_PATH/.deps-installed"
;;
'activate-nand-esp' | 'ane')
export NANDBASE='esp'
export NANDBASE_PATH="$NANDBASE_ROOT/$NANDBASE"
export IDF_PATH="$NANDBASE_PATH/esp-idf"
export IDF_TOOLS_PATH="$NANDBASE_PATH/.espressif"
export CONDA_ENV_NAME="do-nand-$NANDBASE"
export DEPS_FLAG="$NANDBASE_PATH/.deps-installed"
;;
esac
# Step 4: Execute the appropriate command
case "$__current_cmd" in
'activate-nand-riot' | 'anr')
activate_conda || return $?
check_deps_riot || return $?
activate_nand_riot || return $?
;;
'activate-nand-esp' | 'ane')
check_deps_esp || return $?
activate_nand_esp || return $?
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment