Самообновляющийся bash-скрипт: если есть обновления, сначала обновить, затем продолжить с использованием Git.

Вопрос или проблема

Я пытаюсь добавить возможность для моего скрипта-установщика ArchLinux проверять, актуален ли он, на основе того, совпадает или нет его версия с номером версии, указанным на gitlab. Основной скрипт, который запускает установщик (и все пронумерованные файлы скриптов) — это скрипт aalis.sh, который по сути запускает другие файлы вместе. Нумерация версий будет в формате 1.2.3 (major.minor.patch).

Вообще говоря, всякий раз, когда я вношу изменения в скрипт, я изменяю номер версии скрипта на gitlab; и я хочу, чтобы сам скрипт мог определить, что его номер версии не совпадает с номером на github (в случае, когда кто-то использует устаревшую версию скрипта и пытается его запустить); и автоматически обновлялся с помощью git fetch origin master, а затем перезапускался с использованием обновленного содержимого.

Поместите все в функции перед обновлением скрипта. Это гарантирует, что весь код загружен до того, как содержимое скрипта будет заменено.

function some_function {
    ...
}

function main {
    ...
}

main "$@"

Если вы можете поместить вашу версию в отдельный файл, например version.sh. Это будет еще безопаснее.

Я разобрался! Я нашел ответ для получения файла из онлайн-репозитория скрипта, используя команду curl и изменив URL, чтобы просто получить файл VERSION.txt (который будет содержать только номер версии, такой как 2.4.0, и нашел ответ для фактической функциональности сравнения версий. После объединения двух ответов (и изменения вывода для скрипта test_compare_versions мой результат выглядит так

# Ответ от https://stackoverflow.com/a/49351294/17812185 авторства Maxxim
# Сравнить две строки версии [$1: строка версии 1 (v1), $2: строка версии 2 (v2)]
# Возвращаемые значения:
#   0: v1 == v2
#   1: v1 > v2
#   2: v1 < v2
# Основано на: https://stackoverflow.com/a/4025065 авторства Dennis Williamson
function compare_versions() {

    # Тривиальное тестирование v1 == v2 на основе строкового сравнения
    [[ "$1" == "$2" ]] && return 0

    # Локальные переменные
    local regex="^(.*)-r([0-9]*)$" va1=() vr1=0 va2=() vr2=0 len i IFS="."

    # Разбить строки версии на массивы, извлечь конечные ревизии
    if [[ "$1" =~ ${regex} ]]; then
        va1=(${BASH_REMATCH[1]})
        [[ -n "${BASH_REMATCH[2]}" ]] && vr1=${BASH_REMATCH[2]}
    else
        va1=($1)
    fi
    if [[ "$2" =~ ${regex} ]]; then
        va2=(${BASH_REMATCH[1]})
        [[ -n "${BASH_REMATCH[2]}" ]] && vr2=${BASH_REMATCH[2]}
    else
        va2=($2)
    fi

    # Привести va1 и va2 к одинаковой длине, заполняя пустые поля нулями
    (( ${#va1[@]} > ${#va2[@]} )) && len=${#va1[@]} || len=${#va2[@]}
    for ((i=0; i < len; ++i)); do
        [[ -z "${va1[i]}" ]] && va1[i]="0"
        [[ -z "${va2[i]}" ]] && va2[i]="0"
    done

    # Добавить ревизии, увеличить длину
    va1+=($vr1)
    va2+=($vr2)
    len=$((len+1))

    # *** DEBUG ***
    echo "TEST: '${va1[@]} (?) ${va2[@]}'"

    # Сравнить элементы версии, проверить, если v1 > v2 или v1 < v2
    for ((i=0; i < len; ++i)); do
        if (( 10#${va1[i]} > 10#${va2[i]} )); then
            return 1
        elif (( 10#${va1[i]} < 10#${va2[i]} )); then
            return 2
        fi
    done

    # Все элементы равны, значит, v1 == v2
    return 0
}

# Тест compare_versions [$1: строка версии 1, $2: строка версии 2, $3: ожидаемый результат]
function test_compare_versions() {
    compare_versions "$1" "$2"
    case $? in
        0) op="==" ;;
        1) op=">" ;;
        2) op="<" ;;
    esac

    if [[ "$op" == "==" ]]; then
        output ${LIGHT_GREEN} "Скрипт актуален!"
    elif [[ "$op" == "<" ]]; then
        output ${RED} "Скрипт устарел!!"
    elif [[ "$op" == ">" ]]; then
        output ${YELLOW} "Скрипт опережает релизную версию, значит, это должен быть релиз-кандидат или бета-версия!"
    else
        banner ${RED} "ЧТО-ТО ПОШЛО НЕ ТАК, ПОЖАЛУЙСТА, СООБЩИТЕ ОБ ЭТОЙ ОШИБКЕ НА GITLAB ПРОЕКТА"
    fi

}

VERSION=1.2.0
ONLINE_VERSION=$(curl -s https://gitlab.com/NovaViper/testing-for-aalis-version-checker/-/raw/main/VERSION.txt)
test_compare_versions $VERSION $ONLINE_VERSION

.

Ответ или решение

Рассмотрим задачу обновления скрипта bash, который будет проверять наличие обновлений и самостоятельно обновляться с помощью системы Git, прежде чем пользоваться его основным функционалом. Представленная проблема заключается в необходимости разработки механизма, который будет проверять версию установленного скрипта с версией на репозитории и, в случае несоответствия, обновлять его до актуальной версии.

Теория

Основная идея заключается в применении версии контроля Git для отслеживания и обновления скрипта. При любом изменении скрипта в репозитории посередством повышения версии, пользователям будет предложено обновить свою локальную копию, чтобы скрипт всегда использовал последние изменения. Это предотвращает возможные ошибки при выполнении устаревших команд или функционала и гарантирует работу с актуальными версиями.

Для достижения этой цели используется несколько важных шагов:

  1. Автоматизированная проверка версии: перед выполнением основной логики скрипта, необходимо реализовать функцию, которая будет сравнивать локальную версию скрипта и версию в репозитории GitLab.

  2. Скачивание актуальной версии: если версии не совпадают, скрипт должен скачать последнюю версию из репозитория.

  3. Самообновление: После скачивания новой версии, старый скрипт должен быть заменен на новый, и скрипт должен быть перезапущен.

Пример

Пример кода, приведенный ниже, детально объясняет, как можно интегрировать данный функционал в bash-скрипт. Основной фокус здесь — на функции сравнения версий и последовательности действий обновления:

#!/bin/bash

function compare_versions() {
    [[ "$1" == "$2" ]] && return 0
    local IFS=. i ver1=($1) ver2=($2)
    for ((i=0; i<${#ver1[@]}; i++)); do
        if [[ -z ${ver2[i]} ]]; then ver2[i]=0; fi
        if ((10#${ver1[i]} > 10#${ver2[i]})); then
            return 1
        elif ((10#${ver1[i]} < 10#${ver2[i]})); then
            return 2
        fi
    done
    return 0
}

function check_for_update() {
    local CURRENT_VERSION="1.2.0"
    local ONLINE_VERSION=$(curl -s https://gitlab.com/NovaViper/testing-for-aalis-version-checker/-/raw/main/VERSION.txt)

    compare_versions $CURRENT_VERSION $ONLINE_VERSION
    case $? in
        0) echo "Скрипт обновлен.";;
        1) echo "Скрипт новее, чем версия на GitLab.";;
        2)
            echo "Доступна новая версия скрипта. Выполняется обновление..."
            git fetch origin master
            git reset --hard origin/master
            exec ./$(basename $0)
            exit
            ;;
    esac
}

function main() {
    check_for_update
    echo "Выполнение основной функциональности скрипта..."
    # ... основная логика ...
}

main "$@"

Применение

  1. Запуск на сервере или локальной машине: Убедитесь, что установлен и настроен Git, а также предоставлены права доступа к репозиторию в GitLab, чтобы скрипт мог извлекать данные.

  2. Упрощенная актуализация пользователей: Пользователи, скачивающие или клонирующие репозиторий, будут автоматически проверять версию скрипта, что облегчит им пребывание на актуальной версии. Это особенно полезно для проектов, которые регулярно обновляют конфигурации и требования.

  3. Обработка возможных ошибок: Хорошо заметить, что наличие проверок на ошибки — жизненно необходимая часть скрипта, которая должна быть включена, чтобы избежать неправильного выполнения команд или сбоев в середине выполнения обновлений.

Подобный подход будет правильным и эффективным способом поддержания актуальности bash-скриптов, особенно если они часто используются в критически важных системах, где устаревание инструментов может привести к нежелательным результатам. Такой метод позволяет не только упростить управление версионностью, но и существенно сократить временные затраты на обновление программного обеспечения.

Оцените материал
Добавить комментарий

Капча загружается...