# eget Устанавливает утилиту [eget](https://github.com/zyedidia/eget) и через неё — пиновые бинарники релизов с GitHub (restic, rclone, btop, zellij и т.п.). Роль общая для всех серверных репозиториев; канон живёт в `ansible-roles`, копии вендорятся через `inv roles-pull`. ## Что делает 1. **Bootstrap eget.** Если нужной версии `eget` нет — качает архив релиза с GitHub напрямую (сам себя eget обновить не может — chicken-and-egg), распаковывает во временную директорию, ставит бинарник и убирает мусор. Идемпотентно: сверяет `eget --version` с `eget_version`. 2. **Установка пакетов.** Идёт по декларативному списку `eget_packages` и для каждого вызывает `eget --tag --upgrade-only …`. ## Идемпотентность и статус изменений `--upgrade-only` заставляет eget скачивать бинарник, только если релиз новее установленного файла (сравнение по mtime). Когда обновление не нужно, eget пишет в stderr `… requested release is not more recent than current version` и выходит с кодом 0. Роль **не** глушит вывод (`--quiet` убран намеренно) и по наличию этой подстроки (`eget_no_upgrade_marker`) выставляет `changed_when`: реальная установка → `changed`, пропуск → `ok`. Ненулевой код выхода eget (реальная ошибка) роняет таск штатно. > Ограничения `--upgrade-only` (сравнение по дате релиза vs mtime бинарника, а > не по версии — поэтому это **не** строгий пиннинг тега): > > - Бамп тега на релиз, опубликованный раньше текущей установки, и любой > **даунгрейд** eget сочтёт «не новее» и не поставит (роль покажет `ok`). > На практике теги двигают только вперёд на свежие релизы; откат версии — > вручную (удалить бинарник, затем прогнать роль). > - Если имя бинарника не совпадает с последним сегментом `repo` (напр. > `BurntSushi/ripgrep` → `rg`), eget не находит установленный файл, и роль > будет **переустанавливать пакет каждый прогон** (рапортуя `changed`). Все > текущие пакеты этим не задеты; для таких репозиториев ставь бинарник в > отдельную директорию либо не полагайся на статус `changed`. ## Переменные Полный список и значения по умолчанию — в `defaults/main.yml`. | Переменная | По умолчанию | Назначение | |------------|--------------|------------| | `eget_version` | `1.3.4` | Версия самой утилиты eget. | | `eget_install_path` | `/usr/bin/eget` | Куда ставить бинарник eget. | | `eget_download_url` | ссылка на релиз | URL архива eget (собирается из версии). | | `eget_download_checksum` | `""` | Необязательная проверка архива eget (формат `get_url.checksum`). | | `eget_packages_to` | `/usr/local/bin` | Директория для бинарников пакетов по умолчанию. | | `eget_packages` | `[]` | Декларативный список пакетов (см. ниже). | ### Схема элемента `eget_packages` | Ключ | Обяз. | Назначение | |------|:----:|------------| | `repo` | да | `owner/repo` на GitHub, напр. `restic/restic`. | | `tag` | да | Пиновка версии, напр. `v0.18.1`. | | `to` | нет | Целевая директория; по умолчанию `eget_packages_to`. | | `asset` | нет | Один фильтр ассета, напр. `zip` или `^musl` (`^` — анти-матч). | | `assets` | нет | Список фильтров (каждый → свой `--asset`); приоритетнее `asset`. | | `file` | нет | `--file` glob для выбора файла из архива. | ## Пример ```yaml - name: "Install eget and pinned binaries" hosts: all tasks: - name: "Install eget and tools" ansible.builtin.import_role: name: eget vars: eget_install_path: "/usr/local/bin/eget" eget_packages_to: "/usr/local/bin" eget_packages: - {repo: "restic/restic", tag: "v0.18.1"} - {repo: "rclone/rclone", tag: "v1.73.4", asset: "zip"} - {repo: "bootandy/dust", tag: "v1.2.4", asset: "gnu"} - {repo: "creativeprojects/resticprofile", tag: "v0.32.0", asset: "^no_self_update"} ``` ## License MIT