app-store: add manifest registry and CLI
This commit is contained in:
parent
33dcb35ddc
commit
7c5ad8e53d
@ -218,6 +218,11 @@ Pointer: see `docs/embedded/docker-zigbee2mqtt.md` for the canonical version.
|
|||||||
|
|
||||||
Pointer: see `docs/embedded/vhost-manager.md` for the canonical version.
|
Pointer: see `docs/embedded/vhost-manager.md` for the canonical version.
|
||||||
|
|
||||||
|
#### **embedded/app-store.md** 🛒
|
||||||
|
*Plugin manifest format and CLI for the SecuBox App Store.*
|
||||||
|
|
||||||
|
Pointer: see `docs/embedded/app-store.md` for the canonical version.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 5. Tools & Scripts Documentation
|
### 5. Tools & Scripts Documentation
|
||||||
|
|||||||
95
DOCS/embedded/app-store.md
Normal file
95
DOCS/embedded/app-store.md
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# SecuBox App Store & Manifests
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Last Updated:** 2025-12-28
|
||||||
|
**Status:** Active
|
||||||
|
|
||||||
|
This guide outlines the initial “SecuBox Apps” registry format and the `secubox-app` CLI helper. It currently ships with a single manifest (Zigbee2MQTT), but the workflow scales to other Docker/LXC/native services such as Lyrion.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Manifest Layout (`plugins/<app>/manifest.json`)
|
||||||
|
|
||||||
|
Each plugin folder contains a `manifest.json`. Example (Zigbee2MQTT):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "zigbee2mqtt",
|
||||||
|
"name": "Zigbee2MQTT",
|
||||||
|
"type": "docker",
|
||||||
|
"description": "Dockerized Zigbee gateway",
|
||||||
|
"packages": ["secubox-app-zigbee2mqtt", "luci-app-zigbee2mqtt"],
|
||||||
|
"ports": [{ "name": "frontend", "protocol": "http", "port": 8080 }],
|
||||||
|
"volumes": ["/srv/zigbee2mqtt"],
|
||||||
|
"network": { "default_mode": "lan", "dmz_supported": true },
|
||||||
|
"wizard": {
|
||||||
|
"uci": "/etc/config/zigbee2mqtt",
|
||||||
|
"steps": ["serial_port", "mqtt_host", "credentials", "frontend_port"]
|
||||||
|
},
|
||||||
|
"profiles": ["home", "lab"],
|
||||||
|
"actions": {
|
||||||
|
"install": "zigbee2mqttctl install",
|
||||||
|
"check": "zigbee2mqttctl check",
|
||||||
|
"update": "zigbee2mqttctl update",
|
||||||
|
"status": "/etc/init.d/zigbee2mqtt status"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Required keys**
|
||||||
|
|
||||||
|
| Key | Purpose |
|
||||||
|
|-----|---------|
|
||||||
|
| `id` | Unique identifier used by the CLI (`secubox-app install <id>`). |
|
||||||
|
| `name` / `description` | Display metadata. |
|
||||||
|
| `type` | `docker`, `lxc`, or `native`. |
|
||||||
|
| `packages` | List of OpenWrt packages to install/remove. |
|
||||||
|
| `actions.install/update/check/status` | Optional shell commands executed after opkg operations. |
|
||||||
|
|
||||||
|
**Optional keys**
|
||||||
|
|
||||||
|
- `ports`: Document exposed services for the App Store UI.
|
||||||
|
- `volumes`: Persistent directories (e.g., `/srv/zigbee2mqtt`).
|
||||||
|
- `network`: Defaults + whether DMZ mode is supported.
|
||||||
|
- `wizard`: UCI file and logical steps for the future wizard UI.
|
||||||
|
- `profiles`: Tags to pre-load when applying OS-like profiles.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CLI Usage (`secubox-tools/secubox-app`)
|
||||||
|
|
||||||
|
Copy or install `secubox-tools/secubox-app` on the router (ensure it’s executable). Commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List manifests
|
||||||
|
secubox-app list
|
||||||
|
|
||||||
|
# Inspect raw manifest
|
||||||
|
secubox-app show zigbee2mqtt
|
||||||
|
|
||||||
|
# Install packages + run install action
|
||||||
|
secubox-app install zigbee2mqtt
|
||||||
|
|
||||||
|
# Run status command (if defined)
|
||||||
|
secubox-app status zigbee2mqtt
|
||||||
|
|
||||||
|
# Update or remove
|
||||||
|
secubox-app update zigbee2mqtt
|
||||||
|
secubox-app remove zigbee2mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
- `SECUBOX_PLUGINS_DIR`: override manifest directory (default `../plugins`).
|
||||||
|
|
||||||
|
The CLI relies on `opkg` and `jsonfilter`, so run it on the router (or within the OpenWrt SDK). It is idempotent: reinstalling an already-installed app simply confirms package state and reruns optional install hooks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Future Integration
|
||||||
|
|
||||||
|
- LuCI App Store page will consume the same manifest directory to render cards, filters, and install buttons.
|
||||||
|
- Wizards will read the `wizard.steps` metadata to present guided forms.
|
||||||
|
- Profiles can bundle manifests with specific network modes (e.g., DMZ + Zigbee2MQTT + Lyrion).
|
||||||
|
|
||||||
|
For now, Zigbee2MQTT demonstrates the format. Additional manifests should follow the same schema to ensure the CLI and future UIs remain consistent.
|
||||||
|
|
||||||
@ -234,6 +234,19 @@ Follow this template when creating or revising documentation:
|
|||||||
|
|
||||||
**Size:** Short (~120 lines)
|
**Size:** Short (~120 lines)
|
||||||
|
|
||||||
|
#### **embedded/app-store.md** 🛒
|
||||||
|
*Plugin manifest format and SecuBox App Store CLI.*
|
||||||
|
|
||||||
|
**Contents:**
|
||||||
|
- Manifest schema (id/type/packages/actions, wizard metadata)
|
||||||
|
- Example manifest for Zigbee2MQTT
|
||||||
|
- `secubox-app` CLI usage (list/show/install/status/update/remove)
|
||||||
|
- Notes on future LuCI App Store + profile integration
|
||||||
|
|
||||||
|
**When to use:** Creating new app manifests or scripting installs via CLI.
|
||||||
|
|
||||||
|
**Size:** Short (~120 lines)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 5. Tools & Scripts Documentation
|
### 5. Tools & Scripts Documentation
|
||||||
|
|||||||
95
docs/embedded/app-store.md
Normal file
95
docs/embedded/app-store.md
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# SecuBox App Store & Manifests
|
||||||
|
|
||||||
|
**Version:** 1.0.0
|
||||||
|
**Last Updated:** 2025-12-28
|
||||||
|
**Status:** Active
|
||||||
|
|
||||||
|
This guide outlines the initial “SecuBox Apps” registry format and the `secubox-app` CLI helper. It currently ships with a single manifest (Zigbee2MQTT), but the workflow scales to other Docker/LXC/native services such as Lyrion.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Manifest Layout (`plugins/<app>/manifest.json`)
|
||||||
|
|
||||||
|
Each plugin folder contains a `manifest.json`. Example (Zigbee2MQTT):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "zigbee2mqtt",
|
||||||
|
"name": "Zigbee2MQTT",
|
||||||
|
"type": "docker",
|
||||||
|
"description": "Dockerized Zigbee gateway",
|
||||||
|
"packages": ["secubox-app-zigbee2mqtt", "luci-app-zigbee2mqtt"],
|
||||||
|
"ports": [{ "name": "frontend", "protocol": "http", "port": 8080 }],
|
||||||
|
"volumes": ["/srv/zigbee2mqtt"],
|
||||||
|
"network": { "default_mode": "lan", "dmz_supported": true },
|
||||||
|
"wizard": {
|
||||||
|
"uci": "/etc/config/zigbee2mqtt",
|
||||||
|
"steps": ["serial_port", "mqtt_host", "credentials", "frontend_port"]
|
||||||
|
},
|
||||||
|
"profiles": ["home", "lab"],
|
||||||
|
"actions": {
|
||||||
|
"install": "zigbee2mqttctl install",
|
||||||
|
"check": "zigbee2mqttctl check",
|
||||||
|
"update": "zigbee2mqttctl update",
|
||||||
|
"status": "/etc/init.d/zigbee2mqtt status"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Required keys**
|
||||||
|
|
||||||
|
| Key | Purpose |
|
||||||
|
|-----|---------|
|
||||||
|
| `id` | Unique identifier used by the CLI (`secubox-app install <id>`). |
|
||||||
|
| `name` / `description` | Display metadata. |
|
||||||
|
| `type` | `docker`, `lxc`, or `native`. |
|
||||||
|
| `packages` | List of OpenWrt packages to install/remove. |
|
||||||
|
| `actions.install/update/check/status` | Optional shell commands executed after opkg operations. |
|
||||||
|
|
||||||
|
**Optional keys**
|
||||||
|
|
||||||
|
- `ports`: Document exposed services for the App Store UI.
|
||||||
|
- `volumes`: Persistent directories (e.g., `/srv/zigbee2mqtt`).
|
||||||
|
- `network`: Defaults + whether DMZ mode is supported.
|
||||||
|
- `wizard`: UCI file and logical steps for the future wizard UI.
|
||||||
|
- `profiles`: Tags to pre-load when applying OS-like profiles.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CLI Usage (`secubox-tools/secubox-app`)
|
||||||
|
|
||||||
|
Copy or install `secubox-tools/secubox-app` on the router (ensure it’s executable). Commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List manifests
|
||||||
|
secubox-app list
|
||||||
|
|
||||||
|
# Inspect raw manifest
|
||||||
|
secubox-app show zigbee2mqtt
|
||||||
|
|
||||||
|
# Install packages + run install action
|
||||||
|
secubox-app install zigbee2mqtt
|
||||||
|
|
||||||
|
# Run status command (if defined)
|
||||||
|
secubox-app status zigbee2mqtt
|
||||||
|
|
||||||
|
# Update or remove
|
||||||
|
secubox-app update zigbee2mqtt
|
||||||
|
secubox-app remove zigbee2mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
- `SECUBOX_PLUGINS_DIR`: override manifest directory (default `../plugins`).
|
||||||
|
|
||||||
|
The CLI relies on `opkg` and `jsonfilter`, so run it on the router (or within the OpenWrt SDK). It is idempotent: reinstalling an already-installed app simply confirms package state and reruns optional install hooks.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Future Integration
|
||||||
|
|
||||||
|
- LuCI App Store page will consume the same manifest directory to render cards, filters, and install buttons.
|
||||||
|
- Wizards will read the `wizard.steps` metadata to present guided forms.
|
||||||
|
- Profiles can bundle manifests with specific network modes (e.g., DMZ + Zigbee2MQTT + Lyrion).
|
||||||
|
|
||||||
|
For now, Zigbee2MQTT demonstrates the format. Additional manifests should follow the same schema to ensure the CLI and future UIs remain consistent.
|
||||||
|
|
||||||
36
plugins/zigbee2mqtt/manifest.json
Normal file
36
plugins/zigbee2mqtt/manifest.json
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"id": "zigbee2mqtt",
|
||||||
|
"name": "Zigbee2MQTT",
|
||||||
|
"description": "Dockerized Zigbee gateway (secubox-app-zigbee2mqtt + LuCI UI).",
|
||||||
|
"type": "docker",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": "https://www.zigbee2mqtt.io/",
|
||||||
|
"packages": [
|
||||||
|
"secubox-app-zigbee2mqtt",
|
||||||
|
"luci-app-zigbee2mqtt"
|
||||||
|
],
|
||||||
|
"ports": [
|
||||||
|
{ "name": "frontend", "protocol": "http", "port": 8080, "expose": true }
|
||||||
|
],
|
||||||
|
"volumes": ["/srv/zigbee2mqtt"],
|
||||||
|
"network": {
|
||||||
|
"default_mode": "lan",
|
||||||
|
"dmz_supported": true
|
||||||
|
],
|
||||||
|
"wizard": {
|
||||||
|
"uci": "/etc/config/zigbee2mqtt",
|
||||||
|
"steps": [
|
||||||
|
"serial_port",
|
||||||
|
"mqtt_host",
|
||||||
|
"credentials",
|
||||||
|
"frontend_port"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"profiles": ["home", "lab"],
|
||||||
|
"actions": {
|
||||||
|
"install": "zigbee2mqttctl install",
|
||||||
|
"check": "zigbee2mqttctl check",
|
||||||
|
"update": "zigbee2mqttctl update",
|
||||||
|
"status": "/etc/init.d/zigbee2mqtt status"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -240,6 +240,27 @@ git push # validation runs automatically
|
|||||||
./secubox-tools/install-git-hooks.sh
|
./secubox-tools/install-git-hooks.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Apps & Plugin Registry
|
||||||
|
|
||||||
|
#### secubox-app
|
||||||
|
|
||||||
|
CLI helper for the nascent SecuBox App Store. It reads `plugins/*/manifest.json`, installs/removes the packages listed there, and runs optional shell actions (`install`, `check`, `update`, `status`) defined in the manifest.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List manifests and install state
|
||||||
|
secubox-app list
|
||||||
|
|
||||||
|
# Install Zigbee2MQTT (packages + zigbee2mqttctl install)
|
||||||
|
secubox-app install zigbee2mqtt
|
||||||
|
|
||||||
|
# Show manifest or run status/update
|
||||||
|
secubox-app show zigbee2mqtt
|
||||||
|
secubox-app status zigbee2mqtt
|
||||||
|
secubox-app update zigbee2mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
Environment: set `SECUBOX_PLUGINS_DIR` to override the manifest directory (default `../plugins`). Requires `opkg` and `jsonfilter`, so run it on an OpenWrt system (or within the SDK chroot).
|
||||||
|
|
||||||
### Maintenance Tools
|
### Maintenance Tools
|
||||||
|
|
||||||
#### secubox-repair.sh
|
#### secubox-repair.sh
|
||||||
|
|||||||
210
secubox-tools/secubox-app
Executable file
210
secubox-tools/secubox-app
Executable file
@ -0,0 +1,210 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# SecuBox Apps CLI
|
||||||
|
# Lists/installs/removes plugin manifests declared under plugins/*/manifest.json
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
PLUGINS_DIR="${SECUBOX_PLUGINS_DIR:-$(cd "$(dirname "$0")/../plugins" && pwd)}"
|
||||||
|
OPKG_UPDATED=0
|
||||||
|
|
||||||
|
info() { printf '[INFO] %s\n' "$*"; }
|
||||||
|
warn() { printf '[WARN] %s\n' "$*" >&2; }
|
||||||
|
err() { printf '[ERROR] %s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'USAGE'
|
||||||
|
SecuBox Apps CLI
|
||||||
|
Usage: secubox-app <command> [arguments]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
list Show available app manifests
|
||||||
|
show <app-id> Display manifest details
|
||||||
|
install <app-id> Install required packages + run install action
|
||||||
|
remove <app-id> Remove packages listed in manifest
|
||||||
|
status <app-id> Show install state and run status action if defined
|
||||||
|
update <app-id> Run plugin update action or opkg upgrade
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
SECUBOX_PLUGINS_DIR Override plugin manifest directory (default: ../plugins)
|
||||||
|
USAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
require_tool() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || { err "Missing dependency: $1"; exit 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
require_opkg() { require_tool opkg; }
|
||||||
|
require_jsonfilter() { require_tool jsonfilter; }
|
||||||
|
|
||||||
|
manifest_path() {
|
||||||
|
local id="$1"
|
||||||
|
local file="$PLUGINS_DIR/$id/manifest.json"
|
||||||
|
[ -f "$file" ] || { err "Manifest not found for '$id' ($file)"; exit 1; }
|
||||||
|
printf '%s' "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest_field() {
|
||||||
|
local file="$1"; shift
|
||||||
|
jsonfilter -s "$file" -e "$1" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest_packages() {
|
||||||
|
local file="$1"
|
||||||
|
jsonfilter -s "$file" -e '@.packages[*]' 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest_action() {
|
||||||
|
local file="$1"; shift
|
||||||
|
jsonfilter -s "$file" -e "@.actions.$1" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_opkg_updated() {
|
||||||
|
[ "$OPKG_UPDATED" -eq 1 ] && return
|
||||||
|
opkg update >/dev/null
|
||||||
|
OPKG_UPDATED=1
|
||||||
|
}
|
||||||
|
|
||||||
|
packages_installed() {
|
||||||
|
local all_installed=0
|
||||||
|
local partial=0
|
||||||
|
local pkg
|
||||||
|
for pkg in $1; do
|
||||||
|
if opkg status "$pkg" >/dev/null 2>&1; then
|
||||||
|
continue
|
||||||
|
else
|
||||||
|
all_installed=1
|
||||||
|
fi
|
||||||
|
[ -n "$partial" ]
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin_state() {
|
||||||
|
local file="$1"
|
||||||
|
local pkgs pkg missing=0 installed=0 total=0
|
||||||
|
pkgs=$(manifest_packages "$file")
|
||||||
|
for pkg in $pkgs; do
|
||||||
|
total=$((total+1))
|
||||||
|
if opkg status "$pkg" >/dev/null 2>&1; then
|
||||||
|
installed=$((installed+1))
|
||||||
|
else
|
||||||
|
missing=$((missing+1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "$total" -eq 0 ]; then
|
||||||
|
echo "n/a"
|
||||||
|
elif [ "$missing" -eq 0 ]; then
|
||||||
|
echo "installed"
|
||||||
|
elif [ "$installed" -eq 0 ]; then
|
||||||
|
echo "missing"
|
||||||
|
else
|
||||||
|
echo "partial"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
list_plugins() {
|
||||||
|
require_jsonfilter
|
||||||
|
require_opkg
|
||||||
|
printf '%-16s %-22s %-10s %-10s\n' "ID" "Name" "Type" "State"
|
||||||
|
printf '%-16s %-22s %-10s %-10s\n' "--" "----" "----" "-----"
|
||||||
|
find "$PLUGINS_DIR" -mindepth 2 -maxdepth 2 -name manifest.json | sort | while read -r file; do
|
||||||
|
local id name type state
|
||||||
|
id=$(manifest_field "$file" '@.id')
|
||||||
|
name=$(manifest_field "$file" '@.name')
|
||||||
|
type=$(manifest_field "$file" '@.type')
|
||||||
|
state=$(plugin_state "$file")
|
||||||
|
printf '%-16s %-22s %-10s %-10s\n' "$id" "${name:-Unknown}" "${type:-?}" "$state"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
show_manifest() {
|
||||||
|
require_jsonfilter
|
||||||
|
local file=$(manifest_path "$1")
|
||||||
|
cat "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_plugin() {
|
||||||
|
require_jsonfilter
|
||||||
|
require_opkg
|
||||||
|
local file=$(manifest_path "$1")
|
||||||
|
local pkgs pkg
|
||||||
|
pkgs=$(manifest_packages "$file")
|
||||||
|
if [ -z "$pkgs" ]; then
|
||||||
|
warn "Manifest has no packages; nothing to install."
|
||||||
|
else
|
||||||
|
for pkg in $pkgs; do
|
||||||
|
if opkg status "$pkg" >/dev/null 2>&1; then
|
||||||
|
info "$pkg already installed"
|
||||||
|
else
|
||||||
|
info "Installing $pkg"
|
||||||
|
ensure_opkg_updated
|
||||||
|
opkg install "$pkg"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
local install_cmd
|
||||||
|
install_cmd=$(manifest_action "$file" install)
|
||||||
|
if [ -n "$install_cmd" ]; then
|
||||||
|
info "Running install action: $install_cmd"
|
||||||
|
sh -c "$install_cmd"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_plugin() {
|
||||||
|
require_jsonfilter
|
||||||
|
require_opkg
|
||||||
|
local file=$(manifest_path "$1")
|
||||||
|
local pkgs pkg
|
||||||
|
pkgs=$(manifest_packages "$file")
|
||||||
|
for pkg in $pkgs; do
|
||||||
|
if opkg status "$pkg" >/dev/null 2>&1; then
|
||||||
|
info "Removing $pkg"
|
||||||
|
opkg remove "$pkg"
|
||||||
|
else
|
||||||
|
info "$pkg not installed"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin_status_cmd() {
|
||||||
|
require_jsonfilter
|
||||||
|
local file=$(manifest_path "$1")
|
||||||
|
local status_cmd
|
||||||
|
status_cmd=$(manifest_action "$file" status)
|
||||||
|
local state
|
||||||
|
state=$(plugin_state "$file")
|
||||||
|
printf 'App: %s\nState: %s\n' "$1" "$state"
|
||||||
|
if [ -n "$status_cmd" ]; then
|
||||||
|
printf 'Status command output:\n'
|
||||||
|
sh -c "$status_cmd" || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
update_plugin() {
|
||||||
|
require_jsonfilter
|
||||||
|
require_opkg
|
||||||
|
local file=$(manifest_path "$1")
|
||||||
|
local update_cmd pkgs pkg
|
||||||
|
update_cmd=$(manifest_action "$file" update)
|
||||||
|
if [ -n "$update_cmd" ]; then
|
||||||
|
info "Running update action: $update_cmd"
|
||||||
|
sh -c "$update_cmd"
|
||||||
|
else
|
||||||
|
pkgs=$(manifest_packages "$file")
|
||||||
|
for pkg in $pkgs; do
|
||||||
|
info "Upgrading $pkg"
|
||||||
|
ensure_opkg_updated
|
||||||
|
opkg upgrade "$pkg" || true
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
list) shift; list_plugins ;;
|
||||||
|
show) shift; [ $# -ge 1 ] || { err "show requires an app id"; exit 1; }; show_manifest "$1" ;;
|
||||||
|
install) shift; [ $# -ge 1 ] || { err "install requires an app id"; exit 1; }; install_plugin "$1" ;;
|
||||||
|
remove) shift; [ $# -ge 1 ] || { err "remove requires an app id"; exit 1; }; remove_plugin "$1" ;;
|
||||||
|
status) shift; [ $# -ge 1 ] || { err "status requires an app id"; exit 1; }; plugin_status_cmd "$1" ;;
|
||||||
|
update) shift; [ $# -ge 1 ] || { err "update requires an app id"; exit 1; }; update_plugin "$1" ;;
|
||||||
|
help|--help|-h|'') usage ;;
|
||||||
|
*) err "Unknown command: $1"; usage; exit 1 ;;
|
||||||
|
esac
|
||||||
Loading…
Reference in New Issue
Block a user