mirror of
https://github.com/Cheviiot/Nivora.git
synced 2026-08-03 15:51:12 +00:00
feat: add Nivora CLI and msvc-go-wine
This commit is contained in:
@@ -2,6 +2,18 @@
|
||||
|
||||
В файле фиксируются значимые изменения Nivora.
|
||||
|
||||
## 2026-07-25 — Nivora CLI
|
||||
|
||||
### Изменено
|
||||
|
||||
- Пакет `nivora-stplr` полностью переработан и переименован в `nivora-cli`.
|
||||
- Новая команда `nv` получила компактное интерактивное меню, русскую и
|
||||
английскую локализацию, диагностику, dry-run и генерацию автодополнения.
|
||||
- Повседневные операции доступны отдельными командами в стиле eepm:
|
||||
`nvi`, `nve`, `nvu`, `nvs`, `nvqi`, `nvqa`, `nvr`, `nvrl`, `nvf`, `nvd`
|
||||
и `nvc`.
|
||||
- Прежние команды семейства `sl*` удалены без слоя совместимости.
|
||||
|
||||
## 2026-07-24 — GitHub Desktop
|
||||
|
||||
### Добавлено
|
||||
|
||||
@@ -11,7 +11,7 @@ Nivora предлагает открытые рецепты упаковки д
|
||||
официальный репозиторий Stapler и не официальные пакеты upstream-проектов.
|
||||
|
||||
<!-- package-count -->
|
||||
**20 пакетов** · **6 категорий** · `amd64`, `arm64` и `all`
|
||||
**21 пакет** · **6 категорий** · `amd64`, `arm64` и `all`
|
||||
|
||||
[](https://github.com/Cheviiot/Nivora/actions/workflows/quality.yml)
|
||||
|
||||
@@ -66,6 +66,7 @@ stplr info nivora/codex
|
||||
| [ClaudeAlt](docs/packages/claude-alt.md) | `1.24012.0` | `amd64`, `arm64` | `stplr install nivora/claude-alt` |
|
||||
| [Codex](docs/packages/codex.md) | `26.721.31836` | `amd64` | `stplr install nivora/codex` |
|
||||
| [GitHub Desktop](docs/packages/github-desktop.md) | `3.6.3` | `amd64`, `arm64` | `stplr install nivora/github-desktop` |
|
||||
| [msvc-go-wine](https://github.com/Cheviiot/msvc-go-wine) | `0.1.0` | `amd64`, `arm64` | `stplr install nivora/msvc-go-wine` |
|
||||
| [OpenCode](https://opencode.ai/) | `1.18.4` | `amd64`, `arm64` | `stplr install nivora/opencode` |
|
||||
|
||||
### Рабочий стол
|
||||
@@ -88,7 +89,7 @@ stplr info nivora/codex
|
||||
|:--|:--:|:--:|:--|
|
||||
| [balenaEtcher](https://etcher.balena.io/) | `2.1.6` | `amd64` | `stplr install nivora/balena-etcher` |
|
||||
| [Fisher](https://github.com/jorgebucaran/fisher) | `4.4.8` | `all` | `stplr install nivora/fisher` |
|
||||
| [Nivora Stapler Helper](docs/packages/nivora-stplr.md) | `0.3.0` | `all` | `stplr install nivora/nivora-stplr` |
|
||||
| [Nivora CLI](docs/packages/nivora-cli.md) | `1.0.0` | `all` | `stplr install nivora/nivora-cli` |
|
||||
| [Ventoy](docs/packages/ventoy.md) | `1.1.17` | `amd64`, `arm64` | `stplr install nivora/ventoy` |
|
||||
|
||||
## Обновление
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ Stapler сам добавляет текущее `name` в generated `Provides`
|
||||
| `claude` | Upstream DEB: `Package: claude-desktop`; desktop-id `com.anthropic.Claude` сохранён; старое имя пакета `claude-desktop` заменяется |
|
||||
| `codex` | Отображаемое имя `Codex`; команда и desktop-id `codex-app` сохранены |
|
||||
| `github-desktop` | Официальный upstream `desktop/desktop`; Linux-сборка без стороннего форка |
|
||||
| `nivora-stplr` | Собственный helper Nivora |
|
||||
| `nivora-cli` | Многоязычная оболочка Nivora для Stapler |
|
||||
|
||||
## Локальные проверки
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
# Nivora CLI
|
||||
|
||||
Nivora CLI — компактная многоязычная оболочка для Stapler. Она упрощает
|
||||
установку, удаление, обновление и поиск пакетов, управление репозиториями и
|
||||
диагностику системы.
|
||||
|
||||
```bash
|
||||
sudo stplr install nivora/nivora-cli
|
||||
```
|
||||
|
||||
## Интерактивный режим
|
||||
|
||||
Команда `nv` без аргументов открывает компактное меню:
|
||||
|
||||
```text
|
||||
╭─ NIVORA ─────────────────────────────╮
|
||||
│ Простое управление пакетами Stapler │
|
||||
╰──────────────────────────────────────╯
|
||||
|
||||
Пакеты
|
||||
[i] Установить nvi
|
||||
[e] Удалить nve
|
||||
[u] Обновить nvu
|
||||
[s] Найти nvs
|
||||
[q] Информация nvqi
|
||||
[a] Все пакеты nvqa
|
||||
|
||||
Система
|
||||
[r] Обновить репозитории nvr
|
||||
[l] Репозитории nvrl
|
||||
[f] Исправить nvf
|
||||
[d] Диагностика nvd
|
||||
```
|
||||
|
||||
В конвейере или другом неинтерактивном окружении `nv` выводит обычную справку.
|
||||
|
||||
## Короткие команды
|
||||
|
||||
| Команда | Операция Stapler |
|
||||
|:--|:--|
|
||||
| `nvi package` | установить `nivora/package` |
|
||||
| `nve package` | удалить `nivora/package` |
|
||||
| `nvu` | обновить установленные пакеты |
|
||||
| `nvs query` | найти пакет |
|
||||
| `nvqi package` | показать информацию о пакете |
|
||||
| `nvqa` | показать каталог пакетов |
|
||||
| `nvr` | обновить индексы репозиториев |
|
||||
| `nvrl` | показать подключённые репозитории |
|
||||
| `nvf` | исправить состояние Stapler |
|
||||
| `nvd` | проверить окружение |
|
||||
| `nvc` | показать или изменить конфигурацию Stapler |
|
||||
|
||||
Основная команда принимает и полные названия операций:
|
||||
|
||||
```bash
|
||||
nv install codex
|
||||
nv search editor
|
||||
nv info codex
|
||||
nv repo list
|
||||
```
|
||||
|
||||
## Репозитории
|
||||
|
||||
Короткое имя автоматически получает префикс `nivora`:
|
||||
|
||||
```bash
|
||||
nvi codex # stplr install nivora/codex
|
||||
nvi other/package # stplr install other/package
|
||||
```
|
||||
|
||||
Репозиторий можно изменить или отключить:
|
||||
|
||||
```bash
|
||||
nvi --repo other package
|
||||
nvi --repo none package
|
||||
NIVORA_REPO=other nvi package
|
||||
```
|
||||
|
||||
Локальные пути и файлы пакетов никогда не получают префикс.
|
||||
|
||||
## Язык и оформление
|
||||
|
||||
Русский или английский язык выбирается по системной локали. Явное
|
||||
переопределение:
|
||||
|
||||
```bash
|
||||
nv --lang en help
|
||||
NIVORA_LANG=ru nvd
|
||||
```
|
||||
|
||||
Цветной вывод включается только для терминала. Его можно отключить стандартной
|
||||
переменной `NO_COLOR`, параметром `--no-color` или значением
|
||||
`NIVORA_COLOR=never`.
|
||||
|
||||
## Безопасность
|
||||
|
||||
Изменяющие систему операции запускаются через `sudo`. Другую команду повышения
|
||||
привилегий можно задать в `NIVORA_SUDO`. Аргументы передаются массивом без
|
||||
вычисления shell-строк. Параметр `--dry-run` показывает итоговую команду без её
|
||||
выполнения.
|
||||
|
||||
| Переменная | Назначение |
|
||||
|:--|:--|
|
||||
| `NIVORA_LANG` | язык интерфейса: `ru` или `en` |
|
||||
| `NIVORA_REPO` | репозиторий коротких имён |
|
||||
| `NIVORA_SUDO` | команда повышения привилегий |
|
||||
| `NIVORA_COLOR` | режим цвета; `never` отключает цвет |
|
||||
| `NIVORA_QUIET=1` | не печатать запускаемую команду |
|
||||
| `NO_COLOR` | стандартное отключение цвета |
|
||||
|
||||
Автодополнение для Bash, Fish или Zsh генерируется командой
|
||||
`nv completion <shell>`.
|
||||
@@ -1,43 +0,0 @@
|
||||
# Nivora Stapler Helper
|
||||
|
||||
`nivora-stplr` добавляет короткие команды для Stapler.
|
||||
|
||||
```bash
|
||||
sudo stplr install nivora/nivora-stplr
|
||||
```
|
||||
|
||||
## Команды
|
||||
|
||||
| Alias | Вызов Stapler |
|
||||
|:--|:--|
|
||||
| `sli` | `sudo stplr install` |
|
||||
| `slr` | `sudo stplr remove` |
|
||||
| `slu` | `sudo stplr up` |
|
||||
| `slf` | `sudo stplr fix` |
|
||||
| `slref` | `sudo stplr refresh` |
|
||||
| `sls` | `stplr search` |
|
||||
| `slii` | `stplr info` |
|
||||
| `sll` | `stplr list` |
|
||||
| `sl` | Диспетчер тех же команд |
|
||||
|
||||
Примеры:
|
||||
|
||||
```bash
|
||||
sli --repo nivora parsec
|
||||
slii nivora/codex
|
||||
slu --clean
|
||||
```
|
||||
|
||||
Короткое имя пакета не привязывается к Nivora по умолчанию. Префикс задаётся явно:
|
||||
|
||||
```bash
|
||||
export NIVORA_STPLR_REPO=nivora
|
||||
```
|
||||
|
||||
| Переменная | Назначение |
|
||||
|:--|:--|
|
||||
| `NIVORA_STPLR_REPO` | Префикс для коротких package names |
|
||||
| `NIVORA_STPLR_SUDO` | Команда повышения привилегий, по умолчанию `sudo` |
|
||||
| `NIVORA_STPLR_QUIET=1` | Не печатать команду перед запуском |
|
||||
|
||||
Helper не передаёт произвольные shell-строки через `sudo`.
|
||||
@@ -0,0 +1,25 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Cheviiot
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
This license covers msvc-go-wine's own source code. It does not cover the
|
||||
Microsoft Visual C++ Build Tools / Windows SDK that `msvc-go-wine download`
|
||||
fetches and unpacks, which remain governed by Microsoft's own license terms.
|
||||
@@ -0,0 +1,68 @@
|
||||
name='msvc-go-wine'
|
||||
version=0.1.1
|
||||
release=1
|
||||
summary='Cross compile with MSVC on Linux via Wine'
|
||||
summary_ru='Кросс-компиляция с MSVC на Linux через Wine'
|
||||
group='Development/Tools'
|
||||
desc='msvc-go-wine is a single-binary tool for cross compiling with the real MSVC toolchain on Linux via Wine. Once you run its download/install subcommands, cl, link, lib, rc, midl, mt, dumpbin, msbuild, nmake, ml, ml64, armasm, armasm64, cmd and findstr all work as drop-in commands, exactly like on Windows.'
|
||||
desc_ru='msvc-go-wine — однобинарный инструмент для кросс-компиляции с реальным MSVC на Linux через Wine. После выполнения его подкоманд download/install команды cl, link, lib, rc, midl, mt, dumpbin, msbuild, nmake, ml, ml64, armasm, armasm64, cmd и findstr работают как обычные команды, точно как в Windows.'
|
||||
homepage='https://github.com/Cheviiot/msvc-go-wine'
|
||||
maintainer='Cheviiot <https://github.com/Cheviiot>'
|
||||
|
||||
architectures=('amd64' 'arm64')
|
||||
|
||||
license=('MIT')
|
||||
|
||||
provides=()
|
||||
replaces=('msvc-go-wine')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method="dirty"
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
# wine/msitools/git are needed at runtime by `msvc-go-wine download`/`install`
|
||||
# and by the tool wrappers themselves, not just at build time.
|
||||
deps=()
|
||||
deps_debian=('wine' 'msitools' 'git')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('wine' 'msitools' 'git')
|
||||
deps_arch=('wine' 'msitools' 'git')
|
||||
deps_opensuse=('wine' 'msitools' 'git')
|
||||
deps_altlinux=('wine' 'msitools' 'git')
|
||||
|
||||
build_deps=('binutils')
|
||||
|
||||
# Prebuilt by msvc-go-wine's own CI (.github/workflows/release.yml) and
|
||||
# published to its GitHub Releases; renamed to a common local name so
|
||||
# package() doesn't need to branch on architecture.
|
||||
sources=(
|
||||
"https://github.com/Cheviiot/msvc-go-wine/releases/download/v${version}/msvc-go-wine-linux-amd64?~archive=false&~name=msvc-go-wine"
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
sources_arm64=(
|
||||
"https://github.com/Cheviiot/msvc-go-wine/releases/download/v${version}/msvc-go-wine-linux-arm64?~archive=false&~name=msvc-go-wine"
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:c4193012bab8499cf2000faba61bcd10f77c6faaeea088fe5748e3531f7134e3'
|
||||
'sha256:693a85757d0e3c527a78af6f12dc5068900c3cd363b92f0998ec41b607b15885'
|
||||
)
|
||||
|
||||
checksums_arm64=(
|
||||
'sha256:0bc74b95414085acba3e08a2b994063adc3c011cdff61f92e17810c34703ffbc'
|
||||
'sha256:693a85757d0e3c527a78af6f12dc5068900c3cd363b92f0998ec41b607b15885'
|
||||
)
|
||||
|
||||
package() {
|
||||
cd "${srcdir}"
|
||||
install-binary "${srcdir}/msvc-go-wine"
|
||||
install-license "${srcdir}/LICENSE" "msvc-go-wine/LICENSE"
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-license
|
||||
}
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
package_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
repo_root="$(cd "${package_dir}/.." && pwd)"
|
||||
exec "${repo_root}/tools/package_updates.sh" check "$(basename "$package_dir")"
|
||||
@@ -0,0 +1,16 @@
|
||||
Сведения о лицензии пакета Nivora CLI
|
||||
|
||||
Лицензия: MIT.
|
||||
Исходный проект: https://github.com/Cheviiot/Nivora
|
||||
|
||||
Нюансы пакета:
|
||||
- Пакет устанавливает оболочку Stapler с командами `nv`, `nvi`, `nve`, `nvu`, `nvs`, `nvqi`, `nvqa`, `nvr`, `nvrl`, `nvf`, `nvd` и `nvc`.
|
||||
- Nivora CLI не заменяет Stapler: все операции выполняются через системную команду `stplr`.
|
||||
- Через команду повышения привилегий запускаются только `install`, `remove`, `up`, `fix` и `refresh`.
|
||||
- Команды чтения `search`, `info` и `list` выполняются без повышения привилегий.
|
||||
- Префикс репозитория задается через `--repo <name>` или `NIVORA_REPO`; по умолчанию используется репозиторий `nivora`.
|
||||
- Пути вида `repo/package` не изменяются.
|
||||
- Nivora CLI не исполняет произвольные shell-строки через `sudo`.
|
||||
|
||||
Полный официальный текст MIT:
|
||||
https://opensource.org/licenses/MIT
|
||||
@@ -0,0 +1,55 @@
|
||||
name='nivora-cli'
|
||||
version='1.0.0'
|
||||
release=1
|
||||
summary='Friendly multilingual command shell for Stapler'
|
||||
summary_ru='Удобная многоязычная оболочка для Stapler'
|
||||
desc='Nivora CLI is a compact bilingual command shell for everyday Stapler package management, repository administration, diagnostics, interactive navigation and shell completion.'
|
||||
desc_ru='Nivora CLI — компактная двуязычная оболочка для управления пакетами и репозиториями Stapler, диагностики, интерактивной навигации и автодополнения.'
|
||||
group='System/Configuration/Packaging'
|
||||
homepage='https://github.com/Cheviiot/Nivora'
|
||||
maintainer='Cheviiot <https://github.com/Cheviiot>'
|
||||
|
||||
architectures=('all')
|
||||
license=('MIT')
|
||||
|
||||
provides=()
|
||||
replaces=('nivora-cli')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method='dirty'
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=()
|
||||
deps_debian=('bash' 'sudo')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('bash' 'sudo')
|
||||
deps_arch=('bash' 'sudo')
|
||||
deps_altlinux=('bash' 'sudo')
|
||||
deps_opensuse=('bash' 'sudo')
|
||||
|
||||
sources=(
|
||||
'local:///nivora'
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:438a5b3b73cd8f69108174b25e647b0f8013b3c16f4fcd5ca9e9769fd19f98b7'
|
||||
'sha256:16f1438f500706ac85b363c2549b392daef3a920b24139fca6b30f5648a7801a'
|
||||
)
|
||||
|
||||
package() {
|
||||
install -Dm755 "${srcdir}/nivora" "${pkgdir}/usr/bin/nv"
|
||||
|
||||
shortcut=''
|
||||
for shortcut in nvi nve nvu nvs nvqi nvqa nvr nvrl nvf nvd nvc; do
|
||||
ln -sfn nv "${pkgdir}/usr/bin/${shortcut}"
|
||||
done
|
||||
|
||||
install-license "${srcdir}/LICENSE" 'nivora-cli/LICENSE.nivora'
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-license
|
||||
}
|
||||
Executable
+546
@@ -0,0 +1,546 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
readonly NIVORA_VERSION='1.0.0'
|
||||
readonly DEFAULT_REPOSITORY='nivora'
|
||||
|
||||
language="${NIVORA_LANG:-}"
|
||||
repository="${NIVORA_REPO:-${DEFAULT_REPOSITORY}}"
|
||||
dry_run=0
|
||||
color_mode="${NIVORA_COLOR:-auto}"
|
||||
|
||||
detect_language() {
|
||||
[[ -n "$language" ]] && return
|
||||
case "${LC_ALL:-${LC_MESSAGES:-${LANG:-en}}}" in
|
||||
ru* | RU*) language='ru' ;;
|
||||
*) language='en' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
message() {
|
||||
local key="$1"
|
||||
case "${language}:${key}" in
|
||||
ru:title) printf 'Простое управление пакетами Stapler' ;;
|
||||
ru:usage) printf 'Использование' ;;
|
||||
ru:packages) printf 'Пакеты' ;;
|
||||
ru:system) printf 'Система' ;;
|
||||
ru:install) printf 'Установить' ;;
|
||||
ru:remove) printf 'Удалить' ;;
|
||||
ru:upgrade) printf 'Обновить' ;;
|
||||
ru:search) printf 'Найти' ;;
|
||||
ru:info) printf 'Информация' ;;
|
||||
ru:all_packages) printf 'Все пакеты' ;;
|
||||
ru:refresh) printf 'Обновить репозитории' ;;
|
||||
ru:repositories) printf 'Репозитории' ;;
|
||||
ru:fix) printf 'Исправить' ;;
|
||||
ru:doctor) printf 'Диагностика' ;;
|
||||
ru:config) printf 'Конфигурация' ;;
|
||||
ru:help) printf 'Справка' ;;
|
||||
ru:exit) printf 'Выход' ;;
|
||||
ru:choose) printf 'Выберите действие' ;;
|
||||
ru:package_prompt) printf 'Имя пакета' ;;
|
||||
ru:query_prompt) printf 'Поисковый запрос' ;;
|
||||
ru:unknown_command) printf 'неизвестная команда' ;;
|
||||
ru:unknown_choice) printf 'нет такого пункта' ;;
|
||||
ru:missing_argument) printf 'необходим аргумент' ;;
|
||||
ru:invalid_language) printf 'поддерживаются языки ru и en' ;;
|
||||
ru:invalid_repository) printf 'некорректное имя репозитория' ;;
|
||||
ru:stapler_missing) printf 'команда stplr не найдена' ;;
|
||||
ru:privilege_missing) printf 'команда повышения привилегий не найдена' ;;
|
||||
ru:running) printf 'Выполняется' ;;
|
||||
ru:preview) printf 'Предпросмотр' ;;
|
||||
ru:diagnostics) printf 'Диагностика окружения' ;;
|
||||
ru:ready) printf 'Система готова к работе' ;;
|
||||
ru:problems) printf 'Обнаружены проблемы' ;;
|
||||
ru:available) printf 'доступен' ;;
|
||||
ru:missing) printf 'не найден' ;;
|
||||
ru:language) printf 'Язык' ;;
|
||||
ru:repository) printf 'Репозиторий' ;;
|
||||
ru:privileges) printf 'Привилегии' ;;
|
||||
ru:commands) printf 'Короткие команды' ;;
|
||||
ru:options) printf 'Параметры' ;;
|
||||
ru:examples) printf 'Примеры' ;;
|
||||
en:title) printf 'Simple Stapler package management' ;;
|
||||
en:usage) printf 'Usage' ;;
|
||||
en:packages) printf 'Packages' ;;
|
||||
en:system) printf 'System' ;;
|
||||
en:install) printf 'Install' ;;
|
||||
en:remove) printf 'Remove' ;;
|
||||
en:upgrade) printf 'Upgrade' ;;
|
||||
en:search) printf 'Search' ;;
|
||||
en:info) printf 'Information' ;;
|
||||
en:all_packages) printf 'All packages' ;;
|
||||
en:refresh) printf 'Refresh repositories' ;;
|
||||
en:repositories) printf 'Repositories' ;;
|
||||
en:fix) printf 'Repair' ;;
|
||||
en:doctor) printf 'Diagnostics' ;;
|
||||
en:config) printf 'Configuration' ;;
|
||||
en:help) printf 'Help' ;;
|
||||
en:exit) printf 'Exit' ;;
|
||||
en:choose) printf 'Choose an action' ;;
|
||||
en:package_prompt) printf 'Package name' ;;
|
||||
en:query_prompt) printf 'Search query' ;;
|
||||
en:unknown_command) printf 'unknown command' ;;
|
||||
en:unknown_choice) printf 'unknown choice' ;;
|
||||
en:missing_argument) printf 'an argument is required' ;;
|
||||
en:invalid_language) printf 'supported languages are ru and en' ;;
|
||||
en:invalid_repository) printf 'invalid repository name' ;;
|
||||
en:stapler_missing) printf 'stplr command was not found' ;;
|
||||
en:privilege_missing) printf 'privilege command was not found' ;;
|
||||
en:running) printf 'Running' ;;
|
||||
en:preview) printf 'Preview' ;;
|
||||
en:diagnostics) printf 'Environment diagnostics' ;;
|
||||
en:ready) printf 'The system is ready' ;;
|
||||
en:problems) printf 'Problems found' ;;
|
||||
en:available) printf 'available' ;;
|
||||
en:missing) printf 'missing' ;;
|
||||
en:language) printf 'Language' ;;
|
||||
en:repository) printf 'Repository' ;;
|
||||
en:privileges) printf 'Privileges' ;;
|
||||
en:commands) printf 'Short commands' ;;
|
||||
en:options) printf 'Options' ;;
|
||||
en:examples) printf 'Examples' ;;
|
||||
*) printf '%s' "$key" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
setup_style() {
|
||||
if [[ "$color_mode" == 'never' || -n "${NO_COLOR:-}" || ! -t 1 ]]; then
|
||||
bold=''; dim=''; cyan=''; blue=''; green=''; red=''; reset=''
|
||||
return
|
||||
fi
|
||||
bold=$'\033[1m'
|
||||
dim=$'\033[2m'
|
||||
cyan=$'\033[38;5;44m'
|
||||
blue=$'\033[38;5;75m'
|
||||
green=$'\033[38;5;78m'
|
||||
red=$'\033[38;5;203m'
|
||||
reset=$'\033[0m'
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf '%s%sNivora:%s %s\n' "$bold" "$red" "$reset" "$*" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
validate_settings() {
|
||||
case "$language" in
|
||||
ru | en) ;;
|
||||
*)
|
||||
local invalid_language="$language"
|
||||
language='en'
|
||||
fail "$(message invalid_language): ${invalid_language}"
|
||||
;;
|
||||
esac
|
||||
if [[ "$repository" != 'none' &&
|
||||
! "$repository" =~ ^[[:alnum:]_.-]+$ ]]; then
|
||||
fail "$(message invalid_repository): ${repository}"
|
||||
fi
|
||||
}
|
||||
|
||||
parse_options() {
|
||||
arguments=()
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--lang)
|
||||
[[ "$#" -ge 2 ]] || fail "$(message missing_argument): --lang"
|
||||
language="$2"
|
||||
shift 2
|
||||
;;
|
||||
--lang=*)
|
||||
language="${1#--lang=}"
|
||||
shift
|
||||
;;
|
||||
--repo)
|
||||
[[ "$#" -ge 2 ]] || fail "$(message missing_argument): --repo"
|
||||
repository="$2"
|
||||
shift 2
|
||||
;;
|
||||
--repo=*)
|
||||
repository="${1#--repo=}"
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
dry_run=1
|
||||
shift
|
||||
;;
|
||||
--no-color)
|
||||
color_mode='never'
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
arguments+=("$@")
|
||||
break
|
||||
;;
|
||||
*)
|
||||
arguments+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
setup_style
|
||||
validate_settings
|
||||
}
|
||||
|
||||
print_header() {
|
||||
printf '%s%s╭─ NIVORA ─────────────────────────────╮%s\n' "$bold" "$cyan" "$reset"
|
||||
if [[ "$language" == 'ru' ]]; then
|
||||
printf '%s%s│%s Простое управление пакетами Stapler %s%s│%s\n' \
|
||||
"$cyan" "$bold" "$reset" "$bold" "$cyan" "$reset"
|
||||
else
|
||||
printf '%s%s│%s Simple Stapler package management %s%s│%s\n' \
|
||||
"$cyan" "$bold" "$reset" "$bold" "$cyan" "$reset"
|
||||
fi
|
||||
printf '%s%s╰──────────────────────────────────────╯%s\n' "$bold" "$cyan" "$reset"
|
||||
}
|
||||
|
||||
menu_row() {
|
||||
local key="$1"
|
||||
local label="$2"
|
||||
local shortcut="$3"
|
||||
local padding=$((23 - ${#label}))
|
||||
[[ "$padding" -lt 1 ]] && padding=1
|
||||
printf ' %s[%s]%s %s' "$cyan" "$key" "$reset" "$label"
|
||||
printf '%*s' "$padding" ''
|
||||
printf '%s%s%s\n' "$dim" "$shortcut" "$reset"
|
||||
}
|
||||
|
||||
interactive_menu() {
|
||||
if [[ ! -t 0 || ! -t 1 ]]; then
|
||||
show_help
|
||||
return
|
||||
fi
|
||||
|
||||
print_header
|
||||
printf '\n %s%s%s\n' "$bold" "$(message packages)" "$reset"
|
||||
menu_row i "$(message install)" nvi
|
||||
menu_row e "$(message remove)" nve
|
||||
menu_row u "$(message upgrade)" nvu
|
||||
menu_row s "$(message search)" nvs
|
||||
menu_row q "$(message info)" nvqi
|
||||
menu_row a "$(message all_packages)" nvqa
|
||||
printf '\n %s%s%s\n' "$bold" "$(message system)" "$reset"
|
||||
menu_row r "$(message refresh)" nvr
|
||||
menu_row l "$(message repositories)" nvrl
|
||||
menu_row f "$(message fix)" nvf
|
||||
menu_row d "$(message doctor)" nvd
|
||||
local help_label
|
||||
help_label="$(message help)"
|
||||
printf '\n %s[h]%s %s' "$cyan" "$reset" "$help_label"
|
||||
printf '%*s' "$((23 - ${#help_label}))" ''
|
||||
printf '%s[x]%s %s\n\n' "$cyan" "$reset" "$(message exit)"
|
||||
printf '%s › ' "$(message choose)"
|
||||
read -r choice
|
||||
case "$choice" in
|
||||
i) prompt_and_dispatch install package ;;
|
||||
e) prompt_and_dispatch remove package ;;
|
||||
u) dispatch upgrade ;;
|
||||
s) prompt_and_dispatch search query ;;
|
||||
q) prompt_and_dispatch info package ;;
|
||||
a) dispatch list ;;
|
||||
r) dispatch refresh ;;
|
||||
l) dispatch repo-list ;;
|
||||
f) dispatch fix ;;
|
||||
d) doctor ;;
|
||||
h) show_help ;;
|
||||
x | q!) return ;;
|
||||
*) fail "$(message unknown_choice): ${choice}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
prompt_and_dispatch() {
|
||||
local command_name="$1"
|
||||
local prompt_type="$2"
|
||||
local value
|
||||
if [[ "$prompt_type" == 'package' ]]; then
|
||||
printf '%s › ' "$(message package_prompt)"
|
||||
else
|
||||
printf '%s › ' "$(message query_prompt)"
|
||||
fi
|
||||
read -r value
|
||||
[[ -n "$value" ]] || fail "$(message missing_argument): ${command_name}"
|
||||
dispatch "$command_name" "$value"
|
||||
}
|
||||
|
||||
show_help() {
|
||||
print_header
|
||||
if [[ "$language" == 'ru' ]]; then
|
||||
cat <<EOF
|
||||
|
||||
${bold}$(message usage)${reset}
|
||||
nv интерактивное меню
|
||||
nv <команда> [аргументы] выполнить команду
|
||||
|
||||
${bold}$(message commands)${reset}
|
||||
${cyan}nvi${reset} <пакет...> установить ${cyan}nvr${reset} обновить репозитории
|
||||
${cyan}nve${reset} <пакет...> удалить ${cyan}nvrl${reset} показать репозитории
|
||||
${cyan}nvu${reset} обновить пакеты ${cyan}nvf${reset} исправить Stapler
|
||||
${cyan}nvs${reset} <запрос> найти ${cyan}nvd${reset} запустить диагностику
|
||||
${cyan}nvqi${reset} <пакет> информация ${cyan}nvc${reset} конфигурация Stapler
|
||||
${cyan}nvqa${reset} каталог пакетов
|
||||
|
||||
${bold}$(message options)${reset}
|
||||
--repo <имя|none> репозиторий коротких имён (по умолчанию: nivora)
|
||||
--lang <ru|en> язык интерфейса
|
||||
--dry-run показать команду без выполнения
|
||||
--no-color отключить цвета
|
||||
|
||||
${bold}$(message examples)${reset}
|
||||
nvi codex
|
||||
nvs editor
|
||||
nvqi codex
|
||||
nv --repo none install other/package
|
||||
EOF
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
${bold}$(message usage)${reset}
|
||||
nv interactive menu
|
||||
nv <command> [arguments] run a command
|
||||
|
||||
${bold}$(message commands)${reset}
|
||||
${cyan}nvi${reset} <package...> install ${cyan}nvr${reset} refresh repositories
|
||||
${cyan}nve${reset} <package...> remove ${cyan}nvrl${reset} list repositories
|
||||
${cyan}nvu${reset} upgrade packages ${cyan}nvf${reset} repair Stapler
|
||||
${cyan}nvs${reset} <query> search ${cyan}nvd${reset} run diagnostics
|
||||
${cyan}nvqi${reset} <package> information ${cyan}nvc${reset} configure Stapler
|
||||
${cyan}nvqa${reset} package catalog
|
||||
|
||||
${bold}$(message options)${reset}
|
||||
--repo <name|none> repository for short names (default: nivora)
|
||||
--lang <ru|en> interface language
|
||||
--dry-run print the command without running it
|
||||
--no-color disable colors
|
||||
|
||||
${bold}$(message examples)${reset}
|
||||
nvi codex
|
||||
nvs editor
|
||||
nvqi codex
|
||||
nv --repo none install other/package
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
need_stapler() {
|
||||
command -v stplr >/dev/null 2>&1 || fail "$(message stapler_missing)"
|
||||
}
|
||||
|
||||
privilege_command() {
|
||||
[[ "$EUID" -eq 0 ]] && return
|
||||
local command_name="${NIVORA_SUDO:-sudo}"
|
||||
command -v "$command_name" >/dev/null 2>&1 ||
|
||||
fail "$(message privilege_missing): ${command_name}"
|
||||
printf '%s\n' "$command_name"
|
||||
}
|
||||
|
||||
is_package_name() {
|
||||
local value="$1"
|
||||
[[ -n "$value" &&
|
||||
"$value" != -* &&
|
||||
"$value" != */* &&
|
||||
"$value" != ./* &&
|
||||
"$value" != ../* &&
|
||||
"$value" != /* &&
|
||||
"$value" != *.rpm &&
|
||||
"$value" != *.deb &&
|
||||
"$value" != *.pkg.tar.* ]]
|
||||
}
|
||||
|
||||
normalize_packages() {
|
||||
local argument
|
||||
for argument in "$@"; do
|
||||
if [[ "$repository" != 'none' ]] && is_package_name "$argument"; then
|
||||
printf '%s/%s\n' "$repository" "$argument"
|
||||
else
|
||||
printf '%s\n' "$argument"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
print_command() {
|
||||
local label
|
||||
if [[ "$dry_run" -eq 1 ]]; then
|
||||
label="$(message preview)"
|
||||
else
|
||||
label="$(message running)"
|
||||
fi
|
||||
printf '%s%s%s%s %s›%s' "$bold" "$blue" "$label" "$reset" "$cyan" "$reset" >&2
|
||||
printf ' %q' "$@" >&2
|
||||
printf '\n' >&2
|
||||
}
|
||||
|
||||
run_stapler() {
|
||||
local access="$1"
|
||||
shift
|
||||
need_stapler
|
||||
|
||||
local -a command=()
|
||||
local privilege
|
||||
if [[ "$access" == 'privileged' ]]; then
|
||||
privilege="$(privilege_command)"
|
||||
[[ -n "$privilege" ]] && command+=("$privilege")
|
||||
fi
|
||||
command+=(stplr "$@")
|
||||
|
||||
[[ "${NIVORA_QUIET:-0}" == '1' ]] || print_command "${command[@]}"
|
||||
[[ "$dry_run" -eq 1 ]] && return
|
||||
exec "${command[@]}"
|
||||
}
|
||||
|
||||
require_arguments() {
|
||||
local command_name="$1"
|
||||
local count="$2"
|
||||
[[ "$count" -gt 0 ]] || fail "$(message missing_argument): ${command_name}"
|
||||
}
|
||||
|
||||
doctor() {
|
||||
local failures=0
|
||||
local privilege="${NIVORA_SUDO:-sudo}"
|
||||
printf '%s%s%s\n\n' "$bold" "$(message diagnostics)" "$reset"
|
||||
|
||||
if command -v stplr >/dev/null 2>&1; then
|
||||
printf ' %s●%s %-14s %s\n' "$green" "$reset" 'Stapler' "$(message available)"
|
||||
else
|
||||
printf ' %s●%s %-14s %s\n' "$red" "$reset" 'Stapler' "$(message missing)"
|
||||
failures=1
|
||||
fi
|
||||
|
||||
if [[ "$EUID" -eq 0 ]] || command -v "$privilege" >/dev/null 2>&1; then
|
||||
printf ' %s●%s %-14s %s\n' \
|
||||
"$green" "$reset" "$(message privileges)" \
|
||||
"$([[ "$EUID" -eq 0 ]] && printf 'root' || printf '%s' "$privilege")"
|
||||
else
|
||||
printf ' %s●%s %-14s %s\n' \
|
||||
"$red" "$reset" "$(message privileges)" "$(message missing)"
|
||||
failures=1
|
||||
fi
|
||||
|
||||
printf ' %s●%s %-14s %s\n' "$green" "$reset" "$(message language)" "$language"
|
||||
printf ' %s●%s %-14s %s\n\n' \
|
||||
"$green" "$reset" "$(message repository)" "$repository"
|
||||
|
||||
if [[ "$failures" -eq 0 ]]; then
|
||||
printf '%s✓ %s%s\n' "$green" "$(message ready)" "$reset"
|
||||
else
|
||||
printf '%s✗ %s%s\n' "$red" "$(message problems)" "$reset"
|
||||
fi
|
||||
return "$failures"
|
||||
}
|
||||
|
||||
completion() {
|
||||
local shell="${1:-}"
|
||||
case "$shell" in
|
||||
bash)
|
||||
cat <<'EOF'
|
||||
_nivora() {
|
||||
local commands='install remove upgrade search info list refresh repo-list fix doctor config completion version help'
|
||||
if (( COMP_CWORD == 1 )); then
|
||||
COMPREPLY=($(compgen -W "$commands" -- "${COMP_WORDS[COMP_CWORD]}"))
|
||||
fi
|
||||
}
|
||||
complete -F _nivora nv
|
||||
EOF
|
||||
;;
|
||||
fish)
|
||||
cat <<'EOF'
|
||||
complete -c nv -f -n '__fish_use_subcommand' -a 'install remove upgrade search info list refresh repo-list fix doctor config completion version help'
|
||||
EOF
|
||||
;;
|
||||
zsh)
|
||||
cat <<'EOF'
|
||||
#compdef nv
|
||||
_arguments '1:command:(install remove upgrade search info list refresh repo-list fix doctor config completion version help)' '*::argument:->arguments'
|
||||
EOF
|
||||
;;
|
||||
*) fail "$(message missing_argument): completion <bash|fish|zsh>" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
dispatch() {
|
||||
local command_name="${1:-help}"
|
||||
[[ "$#" -gt 0 ]] && shift
|
||||
|
||||
case "$command_name" in
|
||||
install | i)
|
||||
require_arguments "$command_name" "$#"
|
||||
local -a packages=()
|
||||
mapfile -t packages < <(normalize_packages "$@")
|
||||
run_stapler privileged install "${packages[@]}"
|
||||
;;
|
||||
remove | erase | e)
|
||||
require_arguments "$command_name" "$#"
|
||||
local -a packages=()
|
||||
mapfile -t packages < <(normalize_packages "$@")
|
||||
run_stapler privileged remove "${packages[@]}"
|
||||
;;
|
||||
upgrade | update | u) run_stapler privileged up "$@" ;;
|
||||
search | s)
|
||||
require_arguments "$command_name" "$#"
|
||||
run_stapler user search "$@"
|
||||
;;
|
||||
info | query-info | qi)
|
||||
require_arguments "$command_name" "$#"
|
||||
local -a packages=()
|
||||
mapfile -t packages < <(normalize_packages "$@")
|
||||
run_stapler user info "${packages[@]}"
|
||||
;;
|
||||
list | packages | query-all | qa) run_stapler user list "$@" ;;
|
||||
refresh | r) run_stapler privileged refresh "$@" ;;
|
||||
repo-list | rl) run_stapler user repo list "$@" ;;
|
||||
repo)
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
run_stapler user repo list
|
||||
elif [[ "${1:-}" == 'list' || "${1:-}" == 'ls' ]]; then
|
||||
run_stapler user repo "$@"
|
||||
else
|
||||
run_stapler privileged repo "$@"
|
||||
fi
|
||||
;;
|
||||
fix | f) run_stapler privileged fix "$@" ;;
|
||||
doctor | d) doctor ;;
|
||||
config | c)
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
run_stapler user config show
|
||||
else
|
||||
run_stapler user config "$@"
|
||||
fi
|
||||
;;
|
||||
completion) completion "$@" ;;
|
||||
support) run_stapler user support "$@" ;;
|
||||
version | v | --version)
|
||||
printf 'Nivora CLI %s\n' "$NIVORA_VERSION"
|
||||
command -v stplr >/dev/null 2>&1 && stplr version
|
||||
;;
|
||||
help | h | -h | --help) show_help ;;
|
||||
*) fail "$(message unknown_command): ${command_name}" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main() {
|
||||
detect_language
|
||||
setup_style
|
||||
parse_options "$@"
|
||||
set -- "${arguments[@]}"
|
||||
|
||||
case "$(basename "$0")" in
|
||||
nv)
|
||||
if [[ "$#" -eq 0 ]]; then interactive_menu; else dispatch "$@"; fi
|
||||
;;
|
||||
nvi) dispatch install "$@" ;;
|
||||
nve) dispatch remove "$@" ;;
|
||||
nvu) dispatch upgrade "$@" ;;
|
||||
nvs) dispatch search "$@" ;;
|
||||
nvqi) dispatch info "$@" ;;
|
||||
nvqa) dispatch list "$@" ;;
|
||||
nvr) dispatch refresh "$@" ;;
|
||||
nvrl) dispatch repo-list "$@" ;;
|
||||
nvf) dispatch fix "$@" ;;
|
||||
nvd) doctor ;;
|
||||
nvc) dispatch config "$@" ;;
|
||||
nivora) dispatch "$@" ;;
|
||||
*) fail "$(message unknown_command): $(basename "$0")" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -1,16 +0,0 @@
|
||||
Сведения о лицензии пакета Nivora Stapler Helper
|
||||
|
||||
Лицензия: MIT.
|
||||
Исходный проект: https://github.com/Cheviiot/Nivora
|
||||
|
||||
Нюансы пакета:
|
||||
- Пакет устанавливает CLI-helper для Stapler с командами `sl`, `sli`, `slr`, `slu`, `slf`, `slref`, `sls`, `slii` и `sll`.
|
||||
- Helper не заменяет Stapler: все операции выполняются через системную команду `stplr`.
|
||||
- Через команду повышения привилегий запускаются только `install`, `remove`, `up`, `fix` и `refresh`.
|
||||
- Команды чтения `search`, `info` и `list` выполняются без повышения привилегий.
|
||||
- Префикс репозитория задается через `--repo <name>` или `NIVORA_STPLR_REPO`; по умолчанию короткие имена не привязаны к одному репозиторию.
|
||||
- Пути вида `repo/package` не изменяются.
|
||||
- Helper не исполняет произвольные shell-строки через `sudo`.
|
||||
|
||||
Полный официальный текст MIT:
|
||||
https://opensource.org/licenses/MIT
|
||||
@@ -1,55 +0,0 @@
|
||||
name='nivora-stplr'
|
||||
version='0.3.0'
|
||||
release=1
|
||||
summary='Short command helper for Stapler'
|
||||
summary_ru='Короткие команды для Stapler'
|
||||
desc='Nivora Stapler Helper provides short commands for common Stapler operations across configured repositories and elevates only operations that modify packages or caches.'
|
||||
desc_ru='Nivora Stapler Helper добавляет короткие команды для типовых операций Stapler и повышает привилегии только для изменения пакетов и кэша.'
|
||||
group='System/Configuration/Packaging'
|
||||
homepage='https://github.com/Cheviiot/Nivora'
|
||||
maintainer='Cheviiot <https://github.com/Cheviiot>'
|
||||
|
||||
architectures=('all')
|
||||
license=('MIT')
|
||||
|
||||
provides=()
|
||||
replaces=('nivora-stplr')
|
||||
conflicts=()
|
||||
|
||||
auto_reqprov_method='dirty'
|
||||
auto_req=0
|
||||
auto_prov=0
|
||||
|
||||
deps=()
|
||||
deps_debian=('bash' 'sudo')
|
||||
deps_ubuntu=("${deps_debian[@]}")
|
||||
deps_fedora=('bash' 'sudo')
|
||||
deps_arch=('bash' 'sudo')
|
||||
deps_altlinux=('bash' 'sudo')
|
||||
deps_opensuse=('bash' 'sudo')
|
||||
|
||||
sources=(
|
||||
'local:///nivora-stplr'
|
||||
'local:///LICENSE'
|
||||
)
|
||||
|
||||
checksums=(
|
||||
'sha256:7b0c2a69aed30bc39ac5546aabd0cb82d45b857a52408b4326ad1fd667684ecb'
|
||||
'sha256:c5674e6873211a8ea0f08ee3a950f809c9145c60750746dafff9aee7e1c21cf1'
|
||||
)
|
||||
|
||||
package() {
|
||||
install -Dm755 "${srcdir}/nivora-stplr" "${pkgdir}/usr/bin/sl"
|
||||
|
||||
shortcut=''
|
||||
for shortcut in sli slr slu slf slref sls slii sll; do
|
||||
ln -sfn sl "${pkgdir}/usr/bin/${shortcut}"
|
||||
done
|
||||
|
||||
install-license "${srcdir}/LICENSE" 'nivora-stplr/LICENSE.nivora'
|
||||
}
|
||||
|
||||
files() {
|
||||
files-find-binary
|
||||
files-find-license
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_prefix="${NIVORA_STPLR_REPO:-}"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Nivora Stapler Helper
|
||||
|
||||
Usage:
|
||||
sl <command> [args...]
|
||||
sli <package> [stplr args...] sudo stplr install <package>
|
||||
slr <package> [stplr args...] sudo stplr remove <package>
|
||||
slu [stplr args...] sudo stplr up
|
||||
slf [stplr args...] sudo stplr fix
|
||||
slref [stplr args...] sudo stplr refresh
|
||||
sls <query> [stplr args...] stplr search <query>
|
||||
slii <package> [stplr args...] stplr info <package>
|
||||
sll [stplr args...] stplr list
|
||||
|
||||
Commands:
|
||||
install, in, i install package with sudo
|
||||
remove, rm, r remove package with sudo
|
||||
up, upgrade, u upgrade installed packages with sudo
|
||||
fix, f run stplr fix with sudo
|
||||
refresh, ref refresh repositories with sudo
|
||||
search, s search packages
|
||||
info, show show package info
|
||||
list, ls list repository packages
|
||||
help show this help
|
||||
|
||||
Options:
|
||||
--repo <name> prefix short package names with repository, e.g. sli --repo nivora parsec
|
||||
|
||||
Environment:
|
||||
NIVORA_STPLR_REPO optional repository prefix for short names, default: disabled
|
||||
NIVORA_STPLR_SUDO privilege command, default: sudo
|
||||
NIVORA_STPLR_QUIET=1 do not print command before execution
|
||||
EOF
|
||||
}
|
||||
|
||||
die() {
|
||||
echo "nivora-stplr: $*" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
need_stplr() {
|
||||
command -v stplr >/dev/null 2>&1 || die "команда stplr не найдена"
|
||||
}
|
||||
|
||||
sudo_cmd() {
|
||||
if [[ "${EUID}" -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local command_name="${NIVORA_STPLR_SUDO:-sudo}"
|
||||
command -v "${command_name}" >/dev/null 2>&1 || die "команда ${command_name} не найдена"
|
||||
printf '%s\n' "${command_name}"
|
||||
}
|
||||
|
||||
is_package_token() {
|
||||
local value="$1"
|
||||
|
||||
[[ -n "${value}" ]] || return 1
|
||||
[[ "${value}" == -* ]] && return 1
|
||||
[[ "${value}" == */* ]] && return 1
|
||||
[[ "${value}" == ./* || "${value}" == ../* || "${value}" == /* ]] && return 1
|
||||
[[ "${value}" == *.rpm || "${value}" == *.deb || "${value}" == *.pkg.tar.* ]] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
normalize_package() {
|
||||
local value="$1"
|
||||
|
||||
if [[ -n "${repo_prefix}" ]] && is_package_token "${value}"; then
|
||||
printf '%s/%s\n' "${repo_prefix}" "${value}"
|
||||
else
|
||||
printf '%s\n' "${value}"
|
||||
fi
|
||||
}
|
||||
|
||||
normalize_package_args() {
|
||||
local arg
|
||||
|
||||
for arg in "$@"; do
|
||||
normalize_package "${arg}"
|
||||
done
|
||||
}
|
||||
|
||||
extract_repo_option() {
|
||||
local -n output_ref="$1"
|
||||
shift
|
||||
|
||||
output_ref=()
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--repo)
|
||||
[[ "$#" -ge 2 ]] || die "для --repo нужно имя репозитория"
|
||||
repo_prefix="$2"
|
||||
shift 2
|
||||
;;
|
||||
--repo=*)
|
||||
repo_prefix="${1#--repo=}"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
output_ref+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
print_and_exec() {
|
||||
local -a command=("$@")
|
||||
|
||||
if [[ "${NIVORA_STPLR_QUIET:-0}" != "1" ]]; then
|
||||
printf '=>'
|
||||
printf ' %q' "${command[@]}"
|
||||
printf '\n'
|
||||
fi
|
||||
|
||||
exec "${command[@]}"
|
||||
}
|
||||
|
||||
run_stplr() {
|
||||
local mode="$1"
|
||||
shift
|
||||
|
||||
need_stplr
|
||||
|
||||
local -a command=()
|
||||
if [[ "${mode}" == "sudo" ]]; then
|
||||
local privilege
|
||||
privilege="$(sudo_cmd)"
|
||||
if [[ -n "${privilege}" ]]; then
|
||||
command+=("${privilege}")
|
||||
fi
|
||||
fi
|
||||
|
||||
command+=(stplr "$@")
|
||||
print_and_exec "${command[@]}"
|
||||
}
|
||||
|
||||
require_args() {
|
||||
local command_name="$1"
|
||||
local count="$2"
|
||||
|
||||
if [[ "${count}" -eq 0 ]]; then
|
||||
die "для команды ${command_name} нужен аргумент"
|
||||
fi
|
||||
}
|
||||
|
||||
dispatch() {
|
||||
local command_name="$1"
|
||||
shift
|
||||
|
||||
case "${command_name}" in
|
||||
install | in | i)
|
||||
require_args "${command_name}" "$#"
|
||||
local -a args=()
|
||||
extract_repo_option args "$@"
|
||||
require_args "${command_name}" "${#args[@]}"
|
||||
mapfile -t normalized < <(normalize_package_args "${args[@]}")
|
||||
run_stplr sudo install "${normalized[@]}"
|
||||
;;
|
||||
remove | rm | r | erase | delete | del)
|
||||
require_args "${command_name}" "$#"
|
||||
local -a args=()
|
||||
extract_repo_option args "$@"
|
||||
require_args "${command_name}" "${#args[@]}"
|
||||
mapfile -t normalized < <(normalize_package_args "${args[@]}")
|
||||
run_stplr sudo remove "${normalized[@]}"
|
||||
;;
|
||||
up | upgrade | u)
|
||||
run_stplr sudo up "$@"
|
||||
;;
|
||||
fix | f)
|
||||
run_stplr sudo fix "$@"
|
||||
;;
|
||||
refresh | ref)
|
||||
run_stplr sudo refresh "$@"
|
||||
;;
|
||||
search | s)
|
||||
require_args "${command_name}" "$#"
|
||||
run_stplr user search "$@"
|
||||
;;
|
||||
info | show)
|
||||
require_args "${command_name}" "$#"
|
||||
local -a args=()
|
||||
extract_repo_option args "$@"
|
||||
require_args "${command_name}" "${#args[@]}"
|
||||
mapfile -t normalized < <(normalize_package_args "${args[@]}")
|
||||
run_stplr user info "${normalized[@]}"
|
||||
;;
|
||||
list | ls | l)
|
||||
run_stplr user list "$@"
|
||||
;;
|
||||
version | support)
|
||||
run_stplr user "${command_name}" "$@"
|
||||
;;
|
||||
help | -h | --help | "")
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
die "неизвестная команда: ${command_name}. Запустите: sl help"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main() {
|
||||
local invoked
|
||||
invoked="$(basename "$0")"
|
||||
|
||||
case "${invoked}" in
|
||||
sli) dispatch install "$@" ;;
|
||||
slr) dispatch remove "$@" ;;
|
||||
slu) dispatch up "$@" ;;
|
||||
slf) dispatch fix "$@" ;;
|
||||
slref) dispatch refresh "$@" ;;
|
||||
sls) dispatch search "$@" ;;
|
||||
slii) dispatch info "$@" ;;
|
||||
sll) dispatch list "$@" ;;
|
||||
sl)
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
usage
|
||||
return 0
|
||||
fi
|
||||
local command_name="$1"
|
||||
shift
|
||||
dispatch "${command_name}" "$@"
|
||||
;;
|
||||
*)
|
||||
die "неизвестное имя запуска: ${invoked}"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
temp_dir="$(mktemp -d)"
|
||||
|
||||
cleanup() {
|
||||
find "$temp_dir" -mindepth 1 -delete
|
||||
rmdir "$temp_dir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
mkdir -p "${temp_dir}/bin"
|
||||
log="${temp_dir}/commands.log"
|
||||
|
||||
cat >"${temp_dir}/bin/stplr" <<'EOF'
|
||||
#!/bin/bash
|
||||
printf 'stplr' >>"$NIVORA_TEST_LOG"
|
||||
printf ' %s' "$@" >>"$NIVORA_TEST_LOG"
|
||||
printf '\n' >>"$NIVORA_TEST_LOG"
|
||||
EOF
|
||||
|
||||
cat >"${temp_dir}/bin/test-sudo" <<'EOF'
|
||||
#!/bin/bash
|
||||
printf 'sudo' >>"$NIVORA_TEST_LOG"
|
||||
printf ' %s' "$@" >>"$NIVORA_TEST_LOG"
|
||||
printf '\n' >>"$NIVORA_TEST_LOG"
|
||||
exec "$@"
|
||||
EOF
|
||||
|
||||
chmod 0755 "${temp_dir}/bin/"*
|
||||
for alias in sli slii sl; do
|
||||
ln -s "$repo_root/nivora-stplr/nivora-stplr" "${temp_dir}/bin/${alias}"
|
||||
done
|
||||
|
||||
export NIVORA_TEST_LOG="$log"
|
||||
export NIVORA_STPLR_SUDO=test-sudo
|
||||
export NIVORA_STPLR_QUIET=1
|
||||
export PATH="${temp_dir}/bin:${PATH}"
|
||||
|
||||
sli --repo nivora parsec --clean
|
||||
slii nivora/codex
|
||||
|
||||
cat >"${temp_dir}/expected" <<'EOF'
|
||||
sudo stplr install nivora/parsec --clean
|
||||
stplr install nivora/parsec --clean
|
||||
stplr info nivora/codex
|
||||
EOF
|
||||
|
||||
diff -u "${temp_dir}/expected" "$log"
|
||||
echo 'OK: Nivora helper'
|
||||
Executable
+96
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
temp_dir="$(mktemp -d)"
|
||||
|
||||
cleanup() {
|
||||
find "$temp_dir" -mindepth 1 -delete
|
||||
rmdir "$temp_dir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
mkdir -p "${temp_dir}/bin"
|
||||
log="${temp_dir}/commands.log"
|
||||
|
||||
cat >"${temp_dir}/bin/stplr" <<'EOF'
|
||||
#!/bin/bash
|
||||
printf 'stplr' >>"$NIVORA_TEST_LOG"
|
||||
printf ' %s' "$@" >>"$NIVORA_TEST_LOG"
|
||||
printf '\n' >>"$NIVORA_TEST_LOG"
|
||||
EOF
|
||||
|
||||
cat >"${temp_dir}/bin/test-sudo" <<'EOF'
|
||||
#!/bin/bash
|
||||
printf 'sudo' >>"$NIVORA_TEST_LOG"
|
||||
printf ' %s' "$@" >>"$NIVORA_TEST_LOG"
|
||||
printf '\n' >>"$NIVORA_TEST_LOG"
|
||||
exec "$@"
|
||||
EOF
|
||||
|
||||
chmod 0755 "${temp_dir}/bin/"*
|
||||
for alias in nv nvi nve nvu nvs nvqi nvqa nvr nvrl nvf nvd nvc; do
|
||||
ln -s "${repo_root}/nivora-cli/nivora" "${temp_dir}/bin/${alias}"
|
||||
done
|
||||
|
||||
export NIVORA_TEST_LOG="$log"
|
||||
export NIVORA_SUDO='test-sudo'
|
||||
export NIVORA_QUIET=1
|
||||
export PATH="${temp_dir}/bin:${PATH}"
|
||||
|
||||
nvi codex --clean
|
||||
nve other/package
|
||||
nvu
|
||||
nvs editor
|
||||
nvqi --json codex
|
||||
nvqa --installed
|
||||
nvr
|
||||
nvrl
|
||||
nvf
|
||||
nvc
|
||||
nv --repo none install local-name
|
||||
|
||||
cat >"${temp_dir}/expected" <<'EOF'
|
||||
sudo stplr install nivora/codex --clean
|
||||
stplr install nivora/codex --clean
|
||||
sudo stplr remove other/package
|
||||
stplr remove other/package
|
||||
sudo stplr up
|
||||
stplr up
|
||||
stplr search editor
|
||||
stplr info --json nivora/codex
|
||||
stplr list --installed
|
||||
sudo stplr refresh
|
||||
stplr refresh
|
||||
stplr repo list
|
||||
sudo stplr fix
|
||||
stplr fix
|
||||
stplr config show
|
||||
sudo stplr install local-name
|
||||
stplr install local-name
|
||||
EOF
|
||||
|
||||
diff -u "${temp_dir}/expected" "$log"
|
||||
|
||||
nv --lang en --help >"${temp_dir}/help-en"
|
||||
nv --lang ru --help >"${temp_dir}/help-ru"
|
||||
nv --lang ru completion fish >"${temp_dir}/completion"
|
||||
nvd --lang en >"${temp_dir}/doctor"
|
||||
NIVORA_QUIET=0 nv --lang en --dry-run install codex \
|
||||
>"${temp_dir}/preview-stdout" 2>"${temp_dir}/preview"
|
||||
|
||||
grep -q 'Simple Stapler package management' "${temp_dir}/help-en"
|
||||
grep -q 'Простое управление пакетами Stapler' "${temp_dir}/help-ru"
|
||||
grep -q 'nvi.*установить' "${temp_dir}/help-ru"
|
||||
grep -q '__fish_use_subcommand' "${temp_dir}/completion"
|
||||
grep -q 'The system is ready' "${temp_dir}/doctor"
|
||||
grep -q 'Preview.*test-sudo stplr install nivora/codex' "${temp_dir}/preview"
|
||||
[[ ! -s "${temp_dir}/preview-stdout" ]]
|
||||
|
||||
if nv --lang de help >"${temp_dir}/invalid-out" 2>"${temp_dir}/invalid"; then
|
||||
echo 'Ожидалась ошибка для неподдерживаемого языка' >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -q 'supported languages are ru and en' "${temp_dir}/invalid"
|
||||
|
||||
echo 'OK: Nivora CLI'
|
||||
@@ -13,8 +13,9 @@ readonly -a PACKAGES=(
|
||||
fisher
|
||||
github-desktop
|
||||
happ
|
||||
msvc-go-wine
|
||||
netbird
|
||||
nivora-stplr
|
||||
nivora-cli
|
||||
opencode
|
||||
parsec
|
||||
pineconemc
|
||||
@@ -226,8 +227,9 @@ latest_version() {
|
||||
github_latest_release desktop/desktop | sed 's/^release-//'
|
||||
;;
|
||||
happ) github_latest_release Happ-proxy/happ-desktop ;;
|
||||
msvc-go-wine) github_latest_release Cheviiot/msvc-go-wine ;;
|
||||
netbird) github_latest_release netbirdio/netbird ;;
|
||||
nivora-stplr) current_version nivora-stplr ;;
|
||||
nivora-cli) current_version nivora-cli ;;
|
||||
opencode) github_latest_release anomalyco/opencode ;;
|
||||
parsec) latest_parsec ;;
|
||||
pineconemc) github_latest_release ElyPrismLauncher/Launcher ;;
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ if [[ "${#python_files[@]}" -gt 0 ]]; then
|
||||
fi
|
||||
|
||||
python3 -m unittest discover -s tests -p 'test_*.py' -v
|
||||
bash tests/test_helper.sh
|
||||
bash tests/test_nivora_cli.sh
|
||||
bash tests/test_claude_alt.sh
|
||||
bash tests/test_codex_computer_use.sh
|
||||
bash tests/test_happ_theme.sh
|
||||
|
||||
@@ -28,7 +28,7 @@ readonly -a lifecycle_packages=(
|
||||
'clash-verge-rev|/usr/bin/clash-verge|/home/nivora-test/.local/share/io.github.clash-verge-rev.clash-verge-rev/nivora-lifecycle-state|/usr/share/applications/Clash Verge.desktop|/usr/share/icons/hicolor/128x128/apps/clash-verge.png'
|
||||
'claude|/usr/bin/claude-desktop|/home/nivora-test/.config/Claude/nivora-lifecycle-state|/usr/share/applications/com.anthropic.Claude.desktop|/usr/share/icons/hicolor/128x128/apps/claude-desktop.png'
|
||||
'codex|/usr/bin/codex-app|/home/nivora-test/.codex/nivora-lifecycle-state|/usr/share/applications/codex-app.desktop|/usr/share/icons/hicolor/512x512/apps/codex-app.png'
|
||||
'nivora-stplr|/usr/bin/sl|/home/nivora-test/.config/nivora-stplr/nivora-lifecycle-state|-|-'
|
||||
'nivora-cli|/usr/bin/nv|/home/nivora-test/.config/nivora-cli/nivora-lifecycle-state|-|-'
|
||||
'opencode|/usr/bin/opencode-desktop|/home/nivora-test/.config/opencode/nivora-lifecycle-state|/usr/share/applications/opencode-desktop.desktop|/usr/share/icons/hicolor/128x128/apps/ai.opencode.desktop.png'
|
||||
'tailscale|/usr/bin/tailscale|/var/lib/tailscale/nivora-lifecycle-state|/usr/lib/systemd/system/tailscaled.service|-'
|
||||
'netbird|/usr/bin/netbird|/var/lib/netbird/nivora-lifecycle-state|/usr/lib/systemd/system/netbird.service|-'
|
||||
|
||||
@@ -23,8 +23,9 @@ EXPECTED_PACKAGES = (
|
||||
"fisher",
|
||||
"github-desktop",
|
||||
"happ",
|
||||
"msvc-go-wine",
|
||||
"netbird",
|
||||
"nivora-stplr",
|
||||
"nivora-cli",
|
||||
"opencode",
|
||||
"parsec",
|
||||
"pineconemc",
|
||||
@@ -48,7 +49,7 @@ REQUIRED_ROOT_FILES = {
|
||||
Path("docs/packages/codex.md"),
|
||||
Path("docs/packages/github-desktop.md"),
|
||||
Path("docs/packages/opencode.md"),
|
||||
Path("docs/packages/nivora-stplr.md"),
|
||||
Path("docs/packages/nivora-cli.md"),
|
||||
Path("docs/packages/ventoy.md"),
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user