From 7af3394c298efbb5b021f1e47a7776775270dc87 Mon Sep 17 00:00:00 2001 From: Hien To Date: Wed, 13 Nov 2024 21:34:51 +0700 Subject: [PATCH 1/9] feat: install script for linux --- engine/templates/linux/install.sh | 230 ++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 engine/templates/linux/install.sh diff --git a/engine/templates/linux/install.sh b/engine/templates/linux/install.sh new file mode 100644 index 000000000..7cf72a6cd --- /dev/null +++ b/engine/templates/linux/install.sh @@ -0,0 +1,230 @@ +#!/bin/bash -e + +# Check for root privileges +if [ "$(id -u)" != "0" ]; then + echo "This script must be run as root. Please run again with sudo." + exit 1 +fi + +# Check and suggest installing jq and tar if not present +check_install_jq_tar() { + RED='\033[0;31m' + GREEN='\033[0;32m' + NC='\033[0m' # No Color + + if ! command -v jq &> /dev/null; then + echo -e "${RED}jq could not be found ...${NC}" + echo -e "${GREEN}Please install jq then rerun this script${NC}" + exit 1 + fi + + if ! command -v tar &> /dev/null; then + echo -e "${RED}tar could not be found ...${NC}" + echo -e "${GREEN}Please install tar then rerun this script${NC}" + exit 1 + fi +} + +# Function to fetch the latest version based on channel +get_latest_version() { + local channel=$1 + local tag_name + case $channel in + stable) + tag_name=$(curl -s "https://api.github.com/repos/janhq/cortex.cpp/releases/latest" | grep -oP '"tag_name": "\K(.*)(?=")') + ;; + beta) + tag_name=$(curl -s "https://api.github.com/repos/janhq/cortex.cpp/releases" | jq -r '.[] | select(.prerelease) | .tag_name' | head -n 1) + ;; + nightly) + tag_name=$(curl -s "https://delta.jan.ai/cortex/latest/version.json" | jq -r '.tag_name') + ;; + *) + echo "Invalid channel specified." + exit 1 + ;; + esac + echo "${tag_name#v}" +} + +# Determine the home directory based on the user +USER_TO_RUN_AS=${SUDO_USER:-$(whoami)} +if [ "$USER_TO_RUN_AS" = "root" ]; then + USER_HOME="/root" +else + USER_HOME="/home/$USER_TO_RUN_AS" +fi + +# Default values +CHANNEL="stable" +VERSION="" +IS_UPDATE="false" + +# Function to parse command-line arguments +parse_args() { + while [[ "$#" -gt 0 ]]; do + case $1 in + --channel) + CHANNEL="$2" + shift 2 + ;; + --version) + VERSION="$2" + shift 2 + ;; + --is_update) + IS_UPDATE="true" + shift 1 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac + done +} + +# Call parse_args function to handle options +parse_args "$@" + +# Check if VERSION is empty and fetch latest if necessary +if [ -z "$VERSION" ]; then + VERSION=$(get_latest_version $CHANNEL) +fi + +# Set paths based on channel +case $CHANNEL in + stable) + CLI_BINARY_NAME="cortex" + SERVER_BINARY_NAME="cortex-server" + DATA_DIR="$USER_HOME/cortexcpp" + UNINSTALL_SCRIPT="/usr/bin/cortex-uninstall.sh" + UPDATER_SCRIPT="/usr/bin/cortex-updater.sh" + CONFIGURATION_FILE="$USER_HOME/.cortexrc" + ;; + beta) + CLI_BINARY_NAME="cortex-beta" + SERVER_BINARY_NAME="cortex-server-beta" + DATA_DIR="$USER_HOME/cortexcpp-beta" + UNINSTALL_SCRIPT="/usr/bin/cortex-beta-uninstall.sh" + UPDATER_SCRIPT="/usr/bin/cortex-beta-updater.sh" + CONFIGURATION_FILE="$USER_HOME/.cortexrc-beta" + ;; + nightly) + CLI_BINARY_NAME="cortex-nightly" + SERVER_BINARY_NAME="cortex-server-nightly" + DATA_DIR="$USER_HOME/cortexcpp-nightly" + UNINSTALL_SCRIPT="/usr/bin/cortex-nightly-uninstall.sh" + UPDATER_SCRIPT="/usr/bin/cortex-nightly-updater.sh" + CONFIGURATION_FILE="$USER_HOME/.cortexrc-nightly" + ;; + *) + echo "Invalid channel specified." + exit 1 + ;; +esac + +INSTALL_DIR="/usr/bin" + +# Function to download and extract cortex +install_cortex() { + local channel=$1 + local version=$2 + local url="" + + case $channel in + stable) + url="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + ;; + beta) + url="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + ;; + nightly) + url="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-nightly.tar.gz" + ;; + esac + echo "Downloading cortex $channel version $version from $url" + curl -L $url -o /tmp/cortex.tar.gz + tar -xzvf /tmp/cortex.tar.gz -C /tmp + chmod +x /tmp/cortex/* + cp /tmp/cortex/* /usr/bin/ + # Check is update or not + if [ "$IS_UPDATE" = "false" ]; then + su -c "$INSTALL_DIR/$CLI_BINARY_NAME engines install llama-cpp" $USER_TO_RUN_AS + su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS + fi +} + +# Function to create uninstall script +create_uninstall_script() { + cat << EOF > $UNINSTALL_SCRIPT +#!/bin/bash +# Check for root privileges +if [ "\$(id -u)" != "0" ]; then + echo "This script must be run as root. Please run again with sudo." + exit 1 +fi + +echo "Stopping cortex..." +su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS +rm -rf $INSTALL_DIR/$CLI_BINARY_NAME +rm -rf $INSTALL_DIR/$SERVER_BINARY_NAME +rm -f $UNINSTALL_SCRIPT +rm -f $UPDATER_SCRIPT + +echo "Do you want to delete the ~/$DATA_DIR data folder and file ~/$CONFIGURATION_FILE? (yes/no) [default: no]" +read -r answer +while true; do + case "\$answer" in + [yY][eE][sS]|[yY]) + echo "Deleting cortex data folders..." + if [ -d "$DATA_DIR" ]; then + echo "Removing $DATA_DIR" + rm -rf "$DATA_DIR" > /dev/null 2>&1 + fi + if [ -f "$CONFIGURATION_FILE" ]; then + echo "Removing $CONFIGURATION_FILE" + rm -f "$CONFIGURATION_FILE" > /dev/null 2>&1 + fi + break + ;; + [nN][oO]|[nN]|"") + echo "Keeping the 'cortex' data folders." + break + ;; + *) + echo "Invalid response. Please type 'yes', 'no', 'y', or 'n' (case-insensitive)." + read -r answer + ;; + esac +done + +EOF + chmod +x $UNINSTALL_SCRIPT + echo "Uninstall script created at $UNINSTALL_SCRIPT" +} + +# Function to create updater script +create_updater_script() { + cat << EOF > $UPDATER_SCRIPT +#!/bin/bash +# Check for root privileges +if [ "\$(id -u)" != "0" ]; then + echo "This script must be run as root. Please run again with sudo." + exit 1 +fi +echo "Stopping cortex for update..." +su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS +curl -s https://raw.githubusercontent.com/janhq/cortex/feat/linux-bash-install-script/engine/templates/linux/install.sh | bash -s -- --channel $CHANNEL --is_update +EOF + chmod +x $UPDATER_SCRIPT + echo "Updater script created at $UPDATER_SCRIPT" +} + +# Run installation +check_install_jq_tar +install_cortex $CHANNEL $VERSION +create_uninstall_script +create_updater_script + +echo "Installation complete. Run cortex-uninstall.sh to uninstall and cortex-updater.sh to update." From d9376ed1b7a5529e3b9fca17d02ff5e61bb4538d Mon Sep 17 00:00:00 2001 From: Hien To Date: Thu, 14 Nov 2024 17:27:59 +0700 Subject: [PATCH 2/9] feat: linux bash install script support both .deb and binary --- engine/templates/linux/install.sh | 139 ++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 44 deletions(-) diff --git a/engine/templates/linux/install.sh b/engine/templates/linux/install.sh index 7cf72a6cd..e11b879c6 100644 --- a/engine/templates/linux/install.sh +++ b/engine/templates/linux/install.sh @@ -6,6 +6,14 @@ if [ "$(id -u)" != "0" ]; then exit 1 fi +# Determine the home directory based on the user +USER_TO_RUN_AS=${SUDO_USER:-$(whoami)} +if [ "$USER_TO_RUN_AS" = "root" ]; then + USER_HOME="/root" +else + USER_HOME="/home/$USER_TO_RUN_AS" +fi + # Check and suggest installing jq and tar if not present check_install_jq_tar() { RED='\033[0;31m' @@ -47,18 +55,11 @@ get_latest_version() { echo "${tag_name#v}" } -# Determine the home directory based on the user -USER_TO_RUN_AS=${SUDO_USER:-$(whoami)} -if [ "$USER_TO_RUN_AS" = "root" ]; then - USER_HOME="/root" -else - USER_HOME="/home/$USER_TO_RUN_AS" -fi - # Default values CHANNEL="stable" VERSION="" IS_UPDATE="false" +DEB_LOCAL="false" # Function to parse command-line arguments parse_args() { @@ -72,6 +73,10 @@ parse_args() { VERSION="$2" shift 2 ;; + --deb_local) + DEB_LOCAL="true" + shift 1 + ;; --is_update) IS_UPDATE="true" shift 1 @@ -99,24 +104,24 @@ case $CHANNEL in SERVER_BINARY_NAME="cortex-server" DATA_DIR="$USER_HOME/cortexcpp" UNINSTALL_SCRIPT="/usr/bin/cortex-uninstall.sh" - UPDATER_SCRIPT="/usr/bin/cortex-updater.sh" CONFIGURATION_FILE="$USER_HOME/.cortexrc" + DEB_APP_NAME="cortexcpp" ;; beta) CLI_BINARY_NAME="cortex-beta" SERVER_BINARY_NAME="cortex-server-beta" DATA_DIR="$USER_HOME/cortexcpp-beta" UNINSTALL_SCRIPT="/usr/bin/cortex-beta-uninstall.sh" - UPDATER_SCRIPT="/usr/bin/cortex-beta-updater.sh" CONFIGURATION_FILE="$USER_HOME/.cortexrc-beta" + DEB_APP_NAME="cortexcpp-beta" ;; nightly) CLI_BINARY_NAME="cortex-nightly" SERVER_BINARY_NAME="cortex-server-nightly" DATA_DIR="$USER_HOME/cortexcpp-nightly" UNINSTALL_SCRIPT="/usr/bin/cortex-nightly-uninstall.sh" - UPDATER_SCRIPT="/usr/bin/cortex-nightly-updater.sh" CONFIGURATION_FILE="$USER_HOME/.cortexrc-nightly" + DEB_APP_NAME="cortexcpp-nightly" ;; *) echo "Invalid channel specified." @@ -130,34 +135,67 @@ INSTALL_DIR="/usr/bin" install_cortex() { local channel=$1 local version=$2 - local url="" + local is_deb=$3 + local url_binary="" + local url_deb_local="" + local url_deb_network="" case $channel in stable) - url="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + url_binary="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + url_deb_local="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64-local-installer.deb" + url_deb_network="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64-network-installer.deb" ;; beta) - url="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + url_binary="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + url_deb_local="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64-local-installer.deb" + url_deb_network="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64-network-installer.deb" ;; nightly) - url="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-nightly.tar.gz" + url_binary="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-nightly.tar.gz" + url_deb_local="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-${version}-linux-amd64-local-installer.deb" + url_deb_network="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-${version}-linux-amd64-network-installer.deb" ;; esac - echo "Downloading cortex $channel version $version from $url" - curl -L $url -o /tmp/cortex.tar.gz - tar -xzvf /tmp/cortex.tar.gz -C /tmp - chmod +x /tmp/cortex/* - cp /tmp/cortex/* /usr/bin/ - # Check is update or not - if [ "$IS_UPDATE" = "false" ]; then - su -c "$INSTALL_DIR/$CLI_BINARY_NAME engines install llama-cpp" $USER_TO_RUN_AS - su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS + + if [ "$is_deb" = "true" ]; then + # Download the deb package + if [ "$DEB_LOCAL" = "true" ]; then + echo "Downloading cortex $channel version $version from $url_deb_local" + curl -L $url_deb_local -o /tmp/cortex.deb + else + echo "Downloading cortex $channel version $version from $url_deb_network" + curl -L $url_deb_network -o /tmp/cortex.deb + fi + + # Install the deb package + if [ "$IS_UPDATE" = "false" ]; then + apt-get install -y /tmp/cortex.deb + else + echo -e "n\n" | SKIP_POSTINSTALL=true apt-get install -y --allow-downgrades /tmp/cortex.deb + fi + rm -f /tmp/cortex.deb + else + echo "Downloading cortex $channel version $version from $url_binary" + curl -L $url_binary -o /tmp/cortex.tar.gz + tar -xzvf /tmp/cortex.tar.gz -C /tmp + chmod +x /tmp/cortex/* + cp /tmp/cortex/* /usr/bin/ + # Check is update or not + if [ "$IS_UPDATE" = "false" ]; then + su -c "$INSTALL_DIR/$CLI_BINARY_NAME engines install llama-cpp" $USER_TO_RUN_AS + su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS + fi + rm -rf /tmp/cortex + rm -f /tmp/cortex.tar.gz fi } # Function to create uninstall script create_uninstall_script() { - cat << EOF > $UNINSTALL_SCRIPT + local is_deb=$1 + if [ "$is_deb" = "false" ]; then + cat << EOF > $UNINSTALL_SCRIPT #!/bin/bash # Check for root privileges if [ "\$(id -u)" != "0" ]; then @@ -167,12 +205,11 @@ fi echo "Stopping cortex..." su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS -rm -rf $INSTALL_DIR/$CLI_BINARY_NAME -rm -rf $INSTALL_DIR/$SERVER_BINARY_NAME +rm -f $INSTALL_DIR/$CLI_BINARY_NAME +rm -f $INSTALL_DIR/$SERVER_BINARY_NAME rm -f $UNINSTALL_SCRIPT -rm -f $UPDATER_SCRIPT -echo "Do you want to delete the ~/$DATA_DIR data folder and file ~/$CONFIGURATION_FILE? (yes/no) [default: no]" +echo "Do you want to delete the $DATA_DIR data folder and file $CONFIGURATION_FILE? (yes/no) [default: no]" read -r answer while true; do case "\$answer" in @@ -200,31 +237,45 @@ while true; do done EOF - chmod +x $UNINSTALL_SCRIPT - echo "Uninstall script created at $UNINSTALL_SCRIPT" -} -# Function to create updater script -create_updater_script() { - cat << EOF > $UPDATER_SCRIPT + else + cat << EOF > $UNINSTALL_SCRIPT #!/bin/bash # Check for root privileges if [ "\$(id -u)" != "0" ]; then echo "This script must be run as root. Please run again with sudo." exit 1 fi -echo "Stopping cortex for update..." -su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS -curl -s https://raw.githubusercontent.com/janhq/cortex/feat/linux-bash-install-script/engine/templates/linux/install.sh | bash -s -- --channel $CHANNEL --is_update + +apt-get remove -y $DEB_APP_NAME +rm -f $UNINSTALL_SCRIPT EOF - chmod +x $UPDATER_SCRIPT - echo "Updater script created at $UPDATER_SCRIPT" + fi + + chmod +x $UNINSTALL_SCRIPT + echo "Uninstall script created at $UNINSTALL_SCRIPT" } # Run installation check_install_jq_tar -install_cortex $CHANNEL $VERSION -create_uninstall_script -create_updater_script -echo "Installation complete. Run cortex-uninstall.sh to uninstall and cortex-updater.sh to update." +IS_DEB="false" + +# Check if apt-get command is available +if command -v apt-get &> /dev/null; then + if [ "$IS_UPDATE" = "true" ]; then + # check if cortexcpp deb package is installed + if dpkg -l | grep -q $DEB_APP_NAME; then + IS_DEB="true" + else + IS_DEB="false" + fi + else + IS_DEB="true" + fi +fi + +install_cortex $CHANNEL $VERSION $IS_DEB +create_uninstall_script $IS_DEB + +echo "Installation complete. Run cortex-uninstall.sh to uninstall." From 5eb89ca8b2e486fb131b61f017ad20f9cf528867 Mon Sep 17 00:00:00 2001 From: Hien To Date: Wed, 13 Nov 2024 21:34:51 +0700 Subject: [PATCH 3/9] feat: install script for linux --- engine/templates/linux/install.sh | 230 ++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 engine/templates/linux/install.sh diff --git a/engine/templates/linux/install.sh b/engine/templates/linux/install.sh new file mode 100644 index 000000000..7cf72a6cd --- /dev/null +++ b/engine/templates/linux/install.sh @@ -0,0 +1,230 @@ +#!/bin/bash -e + +# Check for root privileges +if [ "$(id -u)" != "0" ]; then + echo "This script must be run as root. Please run again with sudo." + exit 1 +fi + +# Check and suggest installing jq and tar if not present +check_install_jq_tar() { + RED='\033[0;31m' + GREEN='\033[0;32m' + NC='\033[0m' # No Color + + if ! command -v jq &> /dev/null; then + echo -e "${RED}jq could not be found ...${NC}" + echo -e "${GREEN}Please install jq then rerun this script${NC}" + exit 1 + fi + + if ! command -v tar &> /dev/null; then + echo -e "${RED}tar could not be found ...${NC}" + echo -e "${GREEN}Please install tar then rerun this script${NC}" + exit 1 + fi +} + +# Function to fetch the latest version based on channel +get_latest_version() { + local channel=$1 + local tag_name + case $channel in + stable) + tag_name=$(curl -s "https://api.github.com/repos/janhq/cortex.cpp/releases/latest" | grep -oP '"tag_name": "\K(.*)(?=")') + ;; + beta) + tag_name=$(curl -s "https://api.github.com/repos/janhq/cortex.cpp/releases" | jq -r '.[] | select(.prerelease) | .tag_name' | head -n 1) + ;; + nightly) + tag_name=$(curl -s "https://delta.jan.ai/cortex/latest/version.json" | jq -r '.tag_name') + ;; + *) + echo "Invalid channel specified." + exit 1 + ;; + esac + echo "${tag_name#v}" +} + +# Determine the home directory based on the user +USER_TO_RUN_AS=${SUDO_USER:-$(whoami)} +if [ "$USER_TO_RUN_AS" = "root" ]; then + USER_HOME="/root" +else + USER_HOME="/home/$USER_TO_RUN_AS" +fi + +# Default values +CHANNEL="stable" +VERSION="" +IS_UPDATE="false" + +# Function to parse command-line arguments +parse_args() { + while [[ "$#" -gt 0 ]]; do + case $1 in + --channel) + CHANNEL="$2" + shift 2 + ;; + --version) + VERSION="$2" + shift 2 + ;; + --is_update) + IS_UPDATE="true" + shift 1 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac + done +} + +# Call parse_args function to handle options +parse_args "$@" + +# Check if VERSION is empty and fetch latest if necessary +if [ -z "$VERSION" ]; then + VERSION=$(get_latest_version $CHANNEL) +fi + +# Set paths based on channel +case $CHANNEL in + stable) + CLI_BINARY_NAME="cortex" + SERVER_BINARY_NAME="cortex-server" + DATA_DIR="$USER_HOME/cortexcpp" + UNINSTALL_SCRIPT="/usr/bin/cortex-uninstall.sh" + UPDATER_SCRIPT="/usr/bin/cortex-updater.sh" + CONFIGURATION_FILE="$USER_HOME/.cortexrc" + ;; + beta) + CLI_BINARY_NAME="cortex-beta" + SERVER_BINARY_NAME="cortex-server-beta" + DATA_DIR="$USER_HOME/cortexcpp-beta" + UNINSTALL_SCRIPT="/usr/bin/cortex-beta-uninstall.sh" + UPDATER_SCRIPT="/usr/bin/cortex-beta-updater.sh" + CONFIGURATION_FILE="$USER_HOME/.cortexrc-beta" + ;; + nightly) + CLI_BINARY_NAME="cortex-nightly" + SERVER_BINARY_NAME="cortex-server-nightly" + DATA_DIR="$USER_HOME/cortexcpp-nightly" + UNINSTALL_SCRIPT="/usr/bin/cortex-nightly-uninstall.sh" + UPDATER_SCRIPT="/usr/bin/cortex-nightly-updater.sh" + CONFIGURATION_FILE="$USER_HOME/.cortexrc-nightly" + ;; + *) + echo "Invalid channel specified." + exit 1 + ;; +esac + +INSTALL_DIR="/usr/bin" + +# Function to download and extract cortex +install_cortex() { + local channel=$1 + local version=$2 + local url="" + + case $channel in + stable) + url="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + ;; + beta) + url="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + ;; + nightly) + url="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-nightly.tar.gz" + ;; + esac + echo "Downloading cortex $channel version $version from $url" + curl -L $url -o /tmp/cortex.tar.gz + tar -xzvf /tmp/cortex.tar.gz -C /tmp + chmod +x /tmp/cortex/* + cp /tmp/cortex/* /usr/bin/ + # Check is update or not + if [ "$IS_UPDATE" = "false" ]; then + su -c "$INSTALL_DIR/$CLI_BINARY_NAME engines install llama-cpp" $USER_TO_RUN_AS + su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS + fi +} + +# Function to create uninstall script +create_uninstall_script() { + cat << EOF > $UNINSTALL_SCRIPT +#!/bin/bash +# Check for root privileges +if [ "\$(id -u)" != "0" ]; then + echo "This script must be run as root. Please run again with sudo." + exit 1 +fi + +echo "Stopping cortex..." +su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS +rm -rf $INSTALL_DIR/$CLI_BINARY_NAME +rm -rf $INSTALL_DIR/$SERVER_BINARY_NAME +rm -f $UNINSTALL_SCRIPT +rm -f $UPDATER_SCRIPT + +echo "Do you want to delete the ~/$DATA_DIR data folder and file ~/$CONFIGURATION_FILE? (yes/no) [default: no]" +read -r answer +while true; do + case "\$answer" in + [yY][eE][sS]|[yY]) + echo "Deleting cortex data folders..." + if [ -d "$DATA_DIR" ]; then + echo "Removing $DATA_DIR" + rm -rf "$DATA_DIR" > /dev/null 2>&1 + fi + if [ -f "$CONFIGURATION_FILE" ]; then + echo "Removing $CONFIGURATION_FILE" + rm -f "$CONFIGURATION_FILE" > /dev/null 2>&1 + fi + break + ;; + [nN][oO]|[nN]|"") + echo "Keeping the 'cortex' data folders." + break + ;; + *) + echo "Invalid response. Please type 'yes', 'no', 'y', or 'n' (case-insensitive)." + read -r answer + ;; + esac +done + +EOF + chmod +x $UNINSTALL_SCRIPT + echo "Uninstall script created at $UNINSTALL_SCRIPT" +} + +# Function to create updater script +create_updater_script() { + cat << EOF > $UPDATER_SCRIPT +#!/bin/bash +# Check for root privileges +if [ "\$(id -u)" != "0" ]; then + echo "This script must be run as root. Please run again with sudo." + exit 1 +fi +echo "Stopping cortex for update..." +su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS +curl -s https://raw.githubusercontent.com/janhq/cortex/feat/linux-bash-install-script/engine/templates/linux/install.sh | bash -s -- --channel $CHANNEL --is_update +EOF + chmod +x $UPDATER_SCRIPT + echo "Updater script created at $UPDATER_SCRIPT" +} + +# Run installation +check_install_jq_tar +install_cortex $CHANNEL $VERSION +create_uninstall_script +create_updater_script + +echo "Installation complete. Run cortex-uninstall.sh to uninstall and cortex-updater.sh to update." From a4e71e7cbd4084363b8ae2faa79d2957b810e0be Mon Sep 17 00:00:00 2001 From: Hien To Date: Thu, 14 Nov 2024 17:27:59 +0700 Subject: [PATCH 4/9] feat: linux bash install script support both .deb and binary --- engine/templates/linux/install.sh | 139 ++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 44 deletions(-) diff --git a/engine/templates/linux/install.sh b/engine/templates/linux/install.sh index 7cf72a6cd..e11b879c6 100644 --- a/engine/templates/linux/install.sh +++ b/engine/templates/linux/install.sh @@ -6,6 +6,14 @@ if [ "$(id -u)" != "0" ]; then exit 1 fi +# Determine the home directory based on the user +USER_TO_RUN_AS=${SUDO_USER:-$(whoami)} +if [ "$USER_TO_RUN_AS" = "root" ]; then + USER_HOME="/root" +else + USER_HOME="/home/$USER_TO_RUN_AS" +fi + # Check and suggest installing jq and tar if not present check_install_jq_tar() { RED='\033[0;31m' @@ -47,18 +55,11 @@ get_latest_version() { echo "${tag_name#v}" } -# Determine the home directory based on the user -USER_TO_RUN_AS=${SUDO_USER:-$(whoami)} -if [ "$USER_TO_RUN_AS" = "root" ]; then - USER_HOME="/root" -else - USER_HOME="/home/$USER_TO_RUN_AS" -fi - # Default values CHANNEL="stable" VERSION="" IS_UPDATE="false" +DEB_LOCAL="false" # Function to parse command-line arguments parse_args() { @@ -72,6 +73,10 @@ parse_args() { VERSION="$2" shift 2 ;; + --deb_local) + DEB_LOCAL="true" + shift 1 + ;; --is_update) IS_UPDATE="true" shift 1 @@ -99,24 +104,24 @@ case $CHANNEL in SERVER_BINARY_NAME="cortex-server" DATA_DIR="$USER_HOME/cortexcpp" UNINSTALL_SCRIPT="/usr/bin/cortex-uninstall.sh" - UPDATER_SCRIPT="/usr/bin/cortex-updater.sh" CONFIGURATION_FILE="$USER_HOME/.cortexrc" + DEB_APP_NAME="cortexcpp" ;; beta) CLI_BINARY_NAME="cortex-beta" SERVER_BINARY_NAME="cortex-server-beta" DATA_DIR="$USER_HOME/cortexcpp-beta" UNINSTALL_SCRIPT="/usr/bin/cortex-beta-uninstall.sh" - UPDATER_SCRIPT="/usr/bin/cortex-beta-updater.sh" CONFIGURATION_FILE="$USER_HOME/.cortexrc-beta" + DEB_APP_NAME="cortexcpp-beta" ;; nightly) CLI_BINARY_NAME="cortex-nightly" SERVER_BINARY_NAME="cortex-server-nightly" DATA_DIR="$USER_HOME/cortexcpp-nightly" UNINSTALL_SCRIPT="/usr/bin/cortex-nightly-uninstall.sh" - UPDATER_SCRIPT="/usr/bin/cortex-nightly-updater.sh" CONFIGURATION_FILE="$USER_HOME/.cortexrc-nightly" + DEB_APP_NAME="cortexcpp-nightly" ;; *) echo "Invalid channel specified." @@ -130,34 +135,67 @@ INSTALL_DIR="/usr/bin" install_cortex() { local channel=$1 local version=$2 - local url="" + local is_deb=$3 + local url_binary="" + local url_deb_local="" + local url_deb_network="" case $channel in stable) - url="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + url_binary="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + url_deb_local="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64-local-installer.deb" + url_deb_network="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64-network-installer.deb" ;; beta) - url="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + url_binary="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64.tar.gz" + url_deb_local="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64-local-installer.deb" + url_deb_network="https://github.com/janhq/cortex.cpp/releases/download/v${version}/cortex-${version}-linux-amd64-network-installer.deb" ;; nightly) - url="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-nightly.tar.gz" + url_binary="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-nightly.tar.gz" + url_deb_local="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-${version}-linux-amd64-local-installer.deb" + url_deb_network="https://delta.jan.ai/cortex/v${version}/linux-amd64/cortex-${version}-linux-amd64-network-installer.deb" ;; esac - echo "Downloading cortex $channel version $version from $url" - curl -L $url -o /tmp/cortex.tar.gz - tar -xzvf /tmp/cortex.tar.gz -C /tmp - chmod +x /tmp/cortex/* - cp /tmp/cortex/* /usr/bin/ - # Check is update or not - if [ "$IS_UPDATE" = "false" ]; then - su -c "$INSTALL_DIR/$CLI_BINARY_NAME engines install llama-cpp" $USER_TO_RUN_AS - su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS + + if [ "$is_deb" = "true" ]; then + # Download the deb package + if [ "$DEB_LOCAL" = "true" ]; then + echo "Downloading cortex $channel version $version from $url_deb_local" + curl -L $url_deb_local -o /tmp/cortex.deb + else + echo "Downloading cortex $channel version $version from $url_deb_network" + curl -L $url_deb_network -o /tmp/cortex.deb + fi + + # Install the deb package + if [ "$IS_UPDATE" = "false" ]; then + apt-get install -y /tmp/cortex.deb + else + echo -e "n\n" | SKIP_POSTINSTALL=true apt-get install -y --allow-downgrades /tmp/cortex.deb + fi + rm -f /tmp/cortex.deb + else + echo "Downloading cortex $channel version $version from $url_binary" + curl -L $url_binary -o /tmp/cortex.tar.gz + tar -xzvf /tmp/cortex.tar.gz -C /tmp + chmod +x /tmp/cortex/* + cp /tmp/cortex/* /usr/bin/ + # Check is update or not + if [ "$IS_UPDATE" = "false" ]; then + su -c "$INSTALL_DIR/$CLI_BINARY_NAME engines install llama-cpp" $USER_TO_RUN_AS + su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS + fi + rm -rf /tmp/cortex + rm -f /tmp/cortex.tar.gz fi } # Function to create uninstall script create_uninstall_script() { - cat << EOF > $UNINSTALL_SCRIPT + local is_deb=$1 + if [ "$is_deb" = "false" ]; then + cat << EOF > $UNINSTALL_SCRIPT #!/bin/bash # Check for root privileges if [ "\$(id -u)" != "0" ]; then @@ -167,12 +205,11 @@ fi echo "Stopping cortex..." su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS -rm -rf $INSTALL_DIR/$CLI_BINARY_NAME -rm -rf $INSTALL_DIR/$SERVER_BINARY_NAME +rm -f $INSTALL_DIR/$CLI_BINARY_NAME +rm -f $INSTALL_DIR/$SERVER_BINARY_NAME rm -f $UNINSTALL_SCRIPT -rm -f $UPDATER_SCRIPT -echo "Do you want to delete the ~/$DATA_DIR data folder and file ~/$CONFIGURATION_FILE? (yes/no) [default: no]" +echo "Do you want to delete the $DATA_DIR data folder and file $CONFIGURATION_FILE? (yes/no) [default: no]" read -r answer while true; do case "\$answer" in @@ -200,31 +237,45 @@ while true; do done EOF - chmod +x $UNINSTALL_SCRIPT - echo "Uninstall script created at $UNINSTALL_SCRIPT" -} -# Function to create updater script -create_updater_script() { - cat << EOF > $UPDATER_SCRIPT + else + cat << EOF > $UNINSTALL_SCRIPT #!/bin/bash # Check for root privileges if [ "\$(id -u)" != "0" ]; then echo "This script must be run as root. Please run again with sudo." exit 1 fi -echo "Stopping cortex for update..." -su -c "$INSTALL_DIR/$CLI_BINARY_NAME stop > /dev/null 2>&1" $USER_TO_RUN_AS -curl -s https://raw.githubusercontent.com/janhq/cortex/feat/linux-bash-install-script/engine/templates/linux/install.sh | bash -s -- --channel $CHANNEL --is_update + +apt-get remove -y $DEB_APP_NAME +rm -f $UNINSTALL_SCRIPT EOF - chmod +x $UPDATER_SCRIPT - echo "Updater script created at $UPDATER_SCRIPT" + fi + + chmod +x $UNINSTALL_SCRIPT + echo "Uninstall script created at $UNINSTALL_SCRIPT" } # Run installation check_install_jq_tar -install_cortex $CHANNEL $VERSION -create_uninstall_script -create_updater_script -echo "Installation complete. Run cortex-uninstall.sh to uninstall and cortex-updater.sh to update." +IS_DEB="false" + +# Check if apt-get command is available +if command -v apt-get &> /dev/null; then + if [ "$IS_UPDATE" = "true" ]; then + # check if cortexcpp deb package is installed + if dpkg -l | grep -q $DEB_APP_NAME; then + IS_DEB="true" + else + IS_DEB="false" + fi + else + IS_DEB="true" + fi +fi + +install_cortex $CHANNEL $VERSION $IS_DEB +create_uninstall_script $IS_DEB + +echo "Installation complete. Run cortex-uninstall.sh to uninstall." From 47e8283b44e2a36f341df7ed4036c950e3f313e9 Mon Sep 17 00:00:00 2001 From: Hien To Date: Fri, 15 Nov 2024 01:24:20 +0700 Subject: [PATCH 5/9] docs: update installation instruction for linux --- README.md | 14 +++++--- docs/docs/installation/linux.mdx | 56 ++++++++++++++------------------ 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 7a7a9ac2c..2239bb97a 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,18 @@ Cortex also has a [Network Installer](#network-installer) which downloads the ne

- Linux: + Linux debian based distros: cortex-linux-local-installer.deb

- For Linux: Download the installer and run the following command in terminal: ```bash - sudo apt install ./cortex-local-installer.deb + # Linux debian based distros + curl -s https://raw.githubusercontent.com/janhq/cortex/dev/engine/templates/linux/install.sh | sudo bash -s -- --deb_local + + # Other Linux distros + curl -s https://raw.githubusercontent.com/janhq/cortex/dev/engine/templates/linux/install.sh | sudo bash -s ``` - The binary will be installed in the `/usr/bin/` directory. @@ -160,7 +164,7 @@ Cortex.cpp is available with a Network Installer, which is a smaller installer b

- Linux: + Linux debian based distros: cortex-linux-network-installer.deb

@@ -181,7 +185,7 @@ Cortex releases 2 preview versions for advanced users to try new features early Version Windows MacOS - Linux + Linux debian based distros Beta (Preview) @@ -234,7 +238,7 @@ Cortex releases 2 preview versions for advanced users to try new features early Version Type Windows MacOS - Linux + Linux debian based distros Beta (Preview) diff --git a/docs/docs/installation/linux.mdx b/docs/docs/installation/linux.mdx index 23e538a52..cf2e00fc0 100644 --- a/docs/docs/installation/linux.mdx +++ b/docs/docs/installation/linux.mdx @@ -20,43 +20,35 @@ This instruction is for stable releases. For beta and nightly releases, please r ### Prerequisites - OpenMPI +- curl +- jq +- tar ### Install Cortex.cpp -1. Download the Linux installer: - - From release: https://github.com/janhq/cortex.cpp/releases - - From quick download links: - - Local installer `.deb`: - - Stable: https://app.cortexcpp.com/download/latest/linux-amd64-local - - Beta: https://app.cortexcpp.com/download/beta/linux-amd64-local - - Nightly: https://app.cortexcpp.com/download/nightly/linux-amd64-local - - Network installer `.deb`: - - Stable: https://app.cortexcpp.com/download/latest/linux-amd64-network - - Beta: https://app.cortexcpp.com/download/beta/linux-amd64-network - - Nightly: https://app.cortexcpp.com/download/nightly/linux-amd64-network - - Binary: - - Stable: https://app.cortexcpp.com/download/latest/linux-amd64-binary - - Beta: https://app.cortexcpp.com/download/beta/linux-amd64-binary - - Nightly: https://app.cortexcpp.com/download/nightly/linux-amd64-binary - -2. Install Cortex.cpp using the following command: - ```bash - # Installer - sudo apt install ./cortex--linux-amd64-network-installer.deb +1. Install cortex with one command +- Linux debian base distros + ```bash + # Network installer + curl -s https://raw.githubusercontent.com/janhq/cortex/dev/engine/templates/linux/install.sh | sudo bash -s - # Binary - tar -xvf cortex--linux-amd64.tar.gz - cd cortex - sudo mv cortex /usr/bin/cortex - sudo chmod +x /usr/bin/Cortexs - sudo mv cortex-server /usr/bin/cortex-server + # Local installer + curl -s https://raw.githubusercontent.com/janhq/cortex/dev/engine/templates/linux/install.sh | sudo bash -s -- --deb_local + ``` - ## For binary, you need to install engine manually after extracting the binary - cortex engines install llama-cpp - ``` +- Other linux distros + ```bash + curl -s https://raw.githubusercontent.com/janhq/cortex/dev/engine/templates/linux/install.sh | sudo bash -s + ``` + +- Parameters + - `--channel ` cortex channel will be installed `stable`, `beta` or `nightly`. Default vaule is `stable` + - `--version ` version cortex want to install Ex `--version 1.0.2`. Default the script will get latest version of corresponding channel + - `--is_update` the current command run is for update + - `--deb_local` Using local installer for linux debian base distros -3. Ensure that Cortex.cpp is sucessfulyy installed: +2. Ensure that Cortex.cpp is sucessfulyy installed: ```bash # Stable cortex -v @@ -79,7 +71,7 @@ By default, Cortex.cpp is installed in the following directory: ## Uninstall Cortex.cpp ```bash # Stable version -sudo apt remove cortexcpp +sudo /usr/bin/cortex-uninstall.sh ``` ## Build from Source @@ -116,7 +108,7 @@ sudo apt remove cortexcpp ## Update cortex to latest version :::info -The script requires sudo permission. Supported for debians based systems only (Ubuntu, Debian, etc). +The script requires sudo permission. Supported for all linux distros. ::: ```bash sudo cortex update From 856128ca98869f4da055a35965fd39f911f772ba Mon Sep 17 00:00:00 2001 From: vansangpfiev Date: Mon, 18 Nov 2024 14:25:10 +0700 Subject: [PATCH 6/9] fix: update updater to support install by bash script --- engine/cli/commands/cortex_upd_cmd.cc | 199 ++++++++++-------- engine/cli/commands/cortex_upd_cmd.h | 9 +- engine/test/components/test_cortex_upd_cmd.cc | 34 --- 3 files changed, 123 insertions(+), 119 deletions(-) diff --git a/engine/cli/commands/cortex_upd_cmd.cc b/engine/cli/commands/cortex_upd_cmd.cc index 30d1ed3e2..804f1d67b 100644 --- a/engine/cli/commands/cortex_upd_cmd.cc +++ b/engine/cli/commands/cortex_upd_cmd.cc @@ -36,9 +36,6 @@ std::unique_ptr GetSystemInfoWithUniversal() { return system_info; } -// https://delta.jan.ai/cortex/v1.0.0-176/windows-amd64/cortex-1.0.0-176-windows-amd64-network-installer.exe -// https://delta.jan.ai/cortex/v1.0.0-176/mac-universal/cortex-1.0.0-176-mac-universal-network-installer.pkg -// https://delta.jan.ai/cortex/v1.0.0-176/linux-amd64/cortex-1.0.0-176-linux-amd64-network-installer.deb std::string GetNightlyInstallerName(const std::string& v, const std::string& os_arch) { const std::string kCortex = "cortex"; @@ -53,13 +50,14 @@ std::string GetNightlyInstallerName(const std::string& v, #endif } -// C:\Users\vansa\AppData\Local\Temp\cortex\cortex-windows-amd64-network-installer.exe std::string GetInstallCmd(const std::string& exe_path) { #if defined(__APPLE__) && defined(__MACH__) - return "sudo touch /var/tmp/cortex_installer_skip_postinstall_check && sudo installer " + return "sudo touch /var/tmp/cortex_installer_skip_postinstall_check && sudo " + "installer " "-pkg " + exe_path + - " -target / && sudo rm /var/tmp/cortex_installer_skip_postinstall_check"; + " -target / && sudo rm " + "/var/tmp/cortex_installer_skip_postinstall_check"; #elif defined(__linux__) return "echo -e \"n\\n\" | sudo SKIP_POSTINSTALL=true apt install -y " "--allow-downgrades " + @@ -70,8 +68,22 @@ std::string GetInstallCmd(const std::string& exe_path) { #endif } +std::string GetInstallCmdLinux(const std::string& script_path, + const std::string& channel, + const std::string& version) { + std::string cmd = "sudo " + script_path; + if (!channel.empty()) { + cmd += " --channel " + channel; + } + if (!version.empty()) { + cmd += " --version " + version.substr(1); + } + return cmd + " --is_update"; +} + bool InstallNewVersion(const std::filesystem::path& dst, - const std::string& exe_path) { + const std::string& exe_script_path, + const std::string& channel, const std::string& version) { std::filesystem::path temp = dst.parent_path() / "cortex_temp"; auto restore_binary = [&temp, &dst]() { if (std::filesystem::exists(temp)) { @@ -86,7 +98,14 @@ bool InstallNewVersion(const std::filesystem::path& dst, // rename binary std::rename(dst.string().c_str(), temp.string().c_str()); // install here - CommandExecutor c(GetInstallCmd(exe_path)); + std::string install_cmd; +#if defined(__linux__) + install_cmd = GetInstallCmdLinux(exe_script_path, channel, version); +#else + install_cmd = GetInstallCmd(exe_script_path); +#endif + CTL_INF("Cmd: " << install_cmd); + CommandExecutor c(install_cmd); auto output = c.execute(); if (!std::filesystem::exists(dst)) { CLI_LOG_ERROR("Something went wrong: could not execute command"); @@ -110,7 +129,6 @@ bool InstallNewVersion(const std::filesystem::path& dst, } return true; } - } // namespace std::optional CheckNewUpdate( @@ -200,76 +218,6 @@ std::optional CheckNewUpdate( return std::nullopt; } -bool ReplaceBinaryInflight(const std::filesystem::path& src, - const std::filesystem::path& dst) { - if (src == dst) { - // Already has the newest - return true; - } - - std::filesystem::path temp = dst.parent_path() / "cortex_temp"; - auto restore_binary = [&temp, &dst]() { - if (std::filesystem::exists(temp)) { - std::rename(temp.string().c_str(), dst.string().c_str()); - CLI_LOG("Restored binary file"); - } - }; - - try { - if (std::filesystem::exists(temp)) { - std::filesystem::remove(temp); - } -#if !defined(_WIN32) - // Get permissions of the executable file - struct stat dst_file_stat; - if (stat(dst.string().c_str(), &dst_file_stat) != 0) { - CLI_LOG_ERROR( - "Error getting permissions of executable file: " << dst.string()); - return false; - } - - // Get owner and group of the executable file - uid_t dst_file_owner = dst_file_stat.st_uid; - gid_t dst_file_group = dst_file_stat.st_gid; -#endif - - std::rename(dst.string().c_str(), temp.string().c_str()); - std::filesystem::copy_file( - src, dst, std::filesystem::copy_options::overwrite_existing); - -#if !defined(_WIN32) - // Set permissions of the executable file - if (chmod(dst.string().c_str(), dst_file_stat.st_mode) != 0) { - CLI_LOG_ERROR( - "Error setting permissions of executable file: " << dst.string()); - restore_binary(); - return false; - } - - // Set owner and group of the executable file - if (chown(dst.string().c_str(), dst_file_owner, dst_file_group) != 0) { - CLI_LOG_ERROR( - "Error setting owner and group of executable file: " << dst.string()); - restore_binary(); - return false; - } - - // Remove cortex_temp - if (unlink(temp.string().c_str()) != 0) { - CLI_LOG_ERROR("Error deleting self: " << strerror(errno)); - restore_binary(); - return false; - } -#endif - } catch (const std::exception& e) { - CLI_LOG_ERROR("Something went wrong: " << e.what()); - restore_binary(); - return false; - } - - return true; -} - void CortexUpdCmd::Exec(const std::string& v, bool force) { // Check for update, if current version is the latest, notify to user if (auto latest_version = commands::CheckNewUpdate(std::nullopt); @@ -314,6 +262,9 @@ void CortexUpdCmd::Exec(const std::string& v, bool force) { } bool CortexUpdCmd::GetStable(const std::string& v) { +#if defined(__linux__) + return GetLinuxInstallScript(v, "stable"); +#else std::optional downloaded_exe_path; auto system_info = GetSystemInfoWithUniversal(); CTL_INF("OS: " << system_info->os << ", Arch: " << system_info->arch); @@ -366,10 +317,14 @@ bool CortexUpdCmd::GetStable(const std::string& v) { }); assert(!!downloaded_exe_path); - return InstallNewVersion(dst, downloaded_exe_path.value()); + return InstallNewVersion(dst, downloaded_exe_path.value(), "", ""); +#endif } bool CortexUpdCmd::GetBeta(const std::string& v) { +#if defined(__linux__) + return GetLinuxInstallScript(v, "beta"); +#else std::optional downloaded_exe_path; auto system_info = GetSystemInfoWithUniversal(); CTL_INF("OS: " << system_info->os << ", Arch: " << system_info->arch); @@ -434,7 +389,8 @@ bool CortexUpdCmd::GetBeta(const std::string& v) { }); assert(!!downloaded_exe_path); - return InstallNewVersion(dst, downloaded_exe_path.value()); + return InstallNewVersion(dst, downloaded_exe_path.value(), "", ""); +#endif } std::optional CortexUpdCmd::HandleGithubRelease( @@ -500,6 +456,9 @@ std::optional CortexUpdCmd::HandleGithubRelease( } bool CortexUpdCmd::GetNightly(const std::string& v) { +#if defined(__linux__) + return GetLinuxInstallScript(v, "nightly"); +#else auto system_info = GetSystemInfoWithUniversal(); CTL_INF("OS: " << system_info->os << ", Arch: " << system_info->arch); @@ -566,6 +525,82 @@ bool CortexUpdCmd::GetNightly(const std::string& v) { } }); - return InstallNewVersion(dst, localPath.string()); + return InstallNewVersion(dst, localPath.string(), "", ""); +#endif +} + +bool CortexUpdCmd::GetLinuxInstallScript(const std::string& v, + const std::string& channel) { + std::vector path_list; + if (channel == "nightly") { + path_list = {"janhq", "cortex.cpp", "feat", "linux-bash-install-script", + "engine", "templates", "linux", "install.sh"}; + } else { + path_list = {"janhq", "cortex.cpp", "main", "engine", + "templates", "linux", "install.sh"}; + } + auto url_obj = url_parser::Url{ + .protocol = "https", + .host = "raw.githubusercontent.com", + .pathParams = path_list, + }; + + CTL_INF("Linux installer script path: " << url_parser::FromUrl(url_obj)); + + std::filesystem::path localPath = + std::filesystem::temp_directory_path() / "cortex" / path_list.back(); + try { + if (!std::filesystem::exists(localPath.parent_path())) { + std::filesystem::create_directories(localPath.parent_path()); + } + } catch (const std::filesystem::filesystem_error& e) { + CLI_LOG_ERROR("Failed to create directories: " << e.what()); + return false; + } + auto download_task = + DownloadTask{.id = "cortex", + .type = DownloadType::Cortex, + .items = {DownloadItem{ + .id = "cortex", + .downloadUrl = url_parser::FromUrl(url_obj), + .localPath = localPath, + }}}; + + auto result = download_service_->AddDownloadTask( + download_task, [](const DownloadTask& finishedTask) { + // try to unzip the downloaded file + CTL_INF("Downloaded cortex path: " + << finishedTask.items[0].localPath.string()); + + CTL_INF("Finished!"); + }); + if (result.has_error()) { + CLI_LOG_ERROR("Failed to download: " << result.error()); + return false; + } + + auto executable_path = file_manager_utils::GetExecutableFolderContainerPath(); + auto dst = executable_path / GetCortexBinary(); + cortex::utils::ScopeExit se([]() { + auto cortex_tmp = std::filesystem::temp_directory_path() / "cortex"; + try { + auto n = std::filesystem::remove_all(cortex_tmp); + CTL_INF("Deleted " << n << " files or directories"); + } catch (const std::exception& e) { + CTL_WRN(e.what()); + } + }); + try { + std::filesystem::permissions(localPath, + std::filesystem::perms::owner_exec | + std::filesystem::perms::group_exec | + std::filesystem::perms::others_exec, + std::filesystem::perm_options::add); + } catch (const std::filesystem::filesystem_error& e) { + CTL_WRN("Error: " << e.what()); + return false; + } + + return InstallNewVersion(dst, localPath.string(), channel, v); } } // namespace commands diff --git a/engine/cli/commands/cortex_upd_cmd.h b/engine/cli/commands/cortex_upd_cmd.h index bd3fc51df..9c500a999 100644 --- a/engine/cli/commands/cortex_upd_cmd.h +++ b/engine/cli/commands/cortex_upd_cmd.h @@ -86,9 +86,6 @@ inline std::string GetReleasePath() { std::optional CheckNewUpdate( std::optional timeout); -bool ReplaceBinaryInflight(const std::filesystem::path& src, - const std::filesystem::path& dst); - // This class manages the 'cortex update' command functionality // There are three release types available: // - Stable: Only retrieves the latest version @@ -109,5 +106,11 @@ class CortexUpdCmd { std::optional HandleGithubRelease(const Json::Value& assets, const std::string& os_arch); bool GetNightly(const std::string& v); + + // For Linux, we use different approach to update + // The installation bash script will perform the following tasks (all logic for update will be put into the bash script): + // - Detect whether the user is performing a new installation or an update. + // - Detect whether a .deb package needs to be installed or if the binary file should be installed directly. + bool GetLinuxInstallScript(const std::string& v, const std::string& channel); }; } // namespace commands diff --git a/engine/test/components/test_cortex_upd_cmd.cc b/engine/test/components/test_cortex_upd_cmd.cc index a8815f4f4..772889fbd 100644 --- a/engine/test/components/test_cortex_upd_cmd.cc +++ b/engine/test/components/test_cortex_upd_cmd.cc @@ -34,37 +34,3 @@ class CortexUpdCmdTest : public ::testing::Test { } } }; - -TEST_F(CortexUpdCmdTest, return_true_if_self_replace) { - EXPECT_TRUE(commands::ReplaceBinaryInflight("test", "test")); -} - -TEST_F(CortexUpdCmdTest, replace_binary_successfully) { - std::filesystem::path new_binary(kNewReleaseFile); - std::filesystem::path cur_binary(kCurReleaseFile); -#if !defined(_WIN32) - struct stat cur_file_stat; - EXPECT_TRUE(stat(cur_binary.string().c_str(), &cur_file_stat) == 0); -#endif - - EXPECT_TRUE(commands::ReplaceBinaryInflight(new_binary, cur_binary)); - -#if !defined(_WIN32) - EXPECT_FALSE(std::filesystem::exists(kCortexTemp)); - - struct stat new_file_stat; - EXPECT_TRUE(stat(cur_binary.string().c_str(), &new_file_stat) == 0); - EXPECT_EQ(cur_file_stat.st_uid, new_file_stat.st_uid); - EXPECT_EQ(cur_file_stat.st_gid, new_file_stat.st_gid); - EXPECT_EQ(cur_file_stat.st_mode, new_file_stat.st_mode); -#else - EXPECT_TRUE(std::filesystem::exists(kCortexTemp)); -#endif -} - -TEST_F(CortexUpdCmdTest, should_restore_old_binary_if_has_error) { - std::filesystem::path new_binary("Non-exist"); - std::filesystem::path cur_binary(kCurReleaseFile); - EXPECT_FALSE(commands::ReplaceBinaryInflight(new_binary, cur_binary)); - EXPECT_FALSE(std::filesystem::exists(kCortexTemp)); -} \ No newline at end of file From 429d25a5b09eb36a31e4d538193432e2126ee518 Mon Sep 17 00:00:00 2001 From: vansangpfiev Date: Mon, 18 Nov 2024 14:44:05 +0700 Subject: [PATCH 7/9] chore: hardcode url for stable and beta --- engine/cli/commands/cortex_upd_cmd.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/engine/cli/commands/cortex_upd_cmd.cc b/engine/cli/commands/cortex_upd_cmd.cc index 804f1d67b..3e8f3d296 100644 --- a/engine/cli/commands/cortex_upd_cmd.cc +++ b/engine/cli/commands/cortex_upd_cmd.cc @@ -536,8 +536,10 @@ bool CortexUpdCmd::GetLinuxInstallScript(const std::string& v, path_list = {"janhq", "cortex.cpp", "feat", "linux-bash-install-script", "engine", "templates", "linux", "install.sh"}; } else { - path_list = {"janhq", "cortex.cpp", "main", "engine", - "templates", "linux", "install.sh"}; + path_list = {"janhq", "cortex.cpp", "feat", "linux-bash-install-script", + "engine", "templates", "linux", "install.sh"}; + // path_list = {"janhq", "cortex.cpp", "main", "engine", + // "templates", "linux", "install.sh"}; } auto url_obj = url_parser::Url{ .protocol = "https", From f917452746558dfa3d2a4f4769e7a37437128d92 Mon Sep 17 00:00:00 2001 From: vansangpfiev Date: Tue, 19 Nov 2024 08:43:42 +0700 Subject: [PATCH 8/9] fix: update download url --- engine/cli/commands/cortex_upd_cmd.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/engine/cli/commands/cortex_upd_cmd.cc b/engine/cli/commands/cortex_upd_cmd.cc index 3e8f3d296..231594346 100644 --- a/engine/cli/commands/cortex_upd_cmd.cc +++ b/engine/cli/commands/cortex_upd_cmd.cc @@ -533,13 +533,11 @@ bool CortexUpdCmd::GetLinuxInstallScript(const std::string& v, const std::string& channel) { std::vector path_list; if (channel == "nightly") { - path_list = {"janhq", "cortex.cpp", "feat", "linux-bash-install-script", - "engine", "templates", "linux", "install.sh"}; + path_list = {"janhq", "cortex.cpp", "dev", "engine", + "templates", "linux", "install.sh"}; } else { - path_list = {"janhq", "cortex.cpp", "feat", "linux-bash-install-script", - "engine", "templates", "linux", "install.sh"}; - // path_list = {"janhq", "cortex.cpp", "main", "engine", - // "templates", "linux", "install.sh"}; + path_list = {"janhq", "cortex.cpp", "main", "engine", + "templates", "linux", "install.sh"}; } auto url_obj = url_parser::Url{ .protocol = "https", From 8cc695ccb9aaaf727cc66bfb1b127a14f41d5dc8 Mon Sep 17 00:00:00 2001 From: Hien To Date: Tue, 19 Nov 2024 10:50:27 +0700 Subject: [PATCH 9/9] chore: add warning for cortex update linux docs --- docs/docs/installation/linux.mdx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/docs/installation/linux.mdx b/docs/docs/installation/linux.mdx index 746ca3e6d..a14450f47 100644 --- a/docs/docs/installation/linux.mdx +++ b/docs/docs/installation/linux.mdx @@ -107,9 +107,10 @@ sudo /usr/bin/cortex-uninstall.sh ``` ## Update cortex to latest version -:::info -The script requires sudo permission. Supported for all linux distros. +:::warning +🚧 The script requires sudo permissions and works only if the user follows the installation instructions above or if the cortex binary file and the cortex-server binary file are installed in /usr/bin for all Linux distributions. If your binary files are located in a different folder, please manually update the binary files. ::: + ```bash sudo cortex update ``` \ No newline at end of file