По мере распространения Go и Rust появляется всё больше программ, которые состоят из одного бинарника без каких-либо нестандартных зависимостей, и которые мы устанавливаем руками, скачивая релиз с GitHub: либо потому, что данного приложения ещё нет в вашем дистрибутиве, либо потому, что просто хочется всегда иметь актуальную версию, а не ждать, когда её затянут в дистрибутив.

Ставить (а особенно обновлять) такие приложения руками – занятие неблагодарное, особенно когда их количество становится больше одного-двух – и хочется какой-то автоматизации. У меня таких программ около десятка, и довольно долгое время я пользовался различными наколеночными скриптами вроде этого для поддержания их актуальности. Но bash-скрипт – это всё-таки как-то несерьёзно, и поэтому всегда хотелось чего-то более управляемого в виде нормального приложения. Найти что-то готовое, что удовлетворяло бы всем моим потребностям, мне сходу не удалось – поэтому некоторое время назад решил пойти моим излюбленным путём и написать своё приложение под эту конкретную задачу.

binup

Пара недель кодинга по вечерам – и родилась утилита binup. Сегодня я зарелизил версию 1.0.0 и полностью перешёл на неё со своих скриптов. Буду рад, если получившаяся тула будет полезна кому-то кроме меня.

Вот как она работает: вы создаёте конфигурационный файл ~/.config/binup/config.yaml с примерно следующим содержимым, в котором описываете конкретное приложение (как его найти на GitHub):

tools:
  binup:
    project: KonishchevDmitry/binup
    release_matcher: binup-linux-x64-*

… запускаете binup install или binup upgrade – и тула устанавливает, либо обновляет указанные вами приложения.

Работает binup довольно просто: она нигде не хранит никакую информацию об установленных приложениях, а вместо этого при запуске смотрит на их текущий статус: если нужного бинарника нет, то устанавливает его; если же есть, то пробует запустить приложение с --version, чтобы определить текущую версию приложения и сравнить её с последним релизом на GitHub. Если же версию определить не удалось (к примеру, программа вовсе может не поддерживать флаг --version), то binup ориентируется на время модификации файла, которое при установке приложения задаёт равным времени модификации релиза.

Конфигурация

Вот пример конфигурационного файла со всеми доступными на данный момент опциями:

# Path where to install the binaries (the default is ~/.local/bin)
path: /usr/local/bin

tools:
  # Binary name
  prometheus:
    # GitHub project name
    project: prometheus/prometheus

    # Changelog URL (will be printed on app upgrade)
    changelog: https://github.com/prometheus/prometheus/blob/main/CHANGELOG.md

    # Release archive pattern:
    # * By default shell-like glob matching is used (https://docs.rs/globset/latest/globset/#syntax)
    # * Pattern started with '~' is treated as regular expression (https://docs.rs/regex/latest/regex/#syntax)
    release_matcher: prometheus-*.linux-amd64.tar.gz

    # Binary path to look for inside the release archive. If it's not specified, the tool name will be used.
    binary_matcher: "*/prometheus"

    # Post-install script
    post: systemctl restart prometheus

# If you have a lot of tools, you may hit GitHub API rate limits for anonymous requests at some moment.
# So it's recommended to obtain GitHub token (https://github.com/settings/tokens) and specify it here.
# No permissions are required for the token – it's needed just to make API requests non-anonymous.
github:
  token: $token

Последующее развитие

Развивать её в какой-то полноценный пакетный менеджер вроде Homebrew я точно не планирую, но вот в рамках решения вышеописанной задачи – вполне.

Пока что из наиболее явных потенциальных фичей видится поддержка GitLab, если возникнет такая необходимость (лично у меня пока что нет ни одного приложения с него), а также явно напрашивается генерация какого-то дефолтного release_matcher‘а в зависимости от текущей ОС и архитектуры.

Прямо сейчас она закрывает все мои потребности, но вполне вероятно, что в процессе использования будут возникать новые – и тогда буду закрывать и их.