Last active
June 24, 2025 10:30
-
-
Save jmkim/0281a433a94a993acef3d4224c7ec21e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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