Skip to content

Commit

Permalink
Add experimental self-updating support (#223)
Browse files Browse the repository at this point in the history
* Add experimental self-updating support

* '3rd party' -> 'third party'

* Remove hidden commands from REPL completion

* Disable non-pyinstaller updaters
  • Loading branch information
pederhan authored Oct 22, 2024
1 parent f80ac3f commit ec7f956
Show file tree
Hide file tree
Showing 10 changed files with 713 additions and 42 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,39 +42,39 @@ The manual is available online at <https://unioslo.github.io/zabbix-cli/>.

### From source

> [!NOTE]
> We are in the process of acquiring the name `zabbix-cli` on PyPI. Until then, installation must be done via the mirror package `zabbix-cli-uio`.
#### pip(x)

```bash
pipx install zabbix-cli-uio
```

#### [uv](https://github.com/astral-sh/uv)
#### [uv](https://docs.astral.sh/uv/getting-started/installation/)

```bash
uv tool install zabbix-cli-uio
```

If you just want to try out the CLI without installing it:
#### [uvx](https://docs.astral.sh/uv/#tool-management)

```bash

uvx --from zabbix-cli-uio zabbix-cli
```

> [!NOTE]
> We are in the process of acquiring the name `zabbix-cli` on PyPI. Until then, installation must be done via the mirror package `zabbix-cli-uio`.
### Homebrew

A homebrew package exists, but it is not maintained by us. It can be installed with:
A homebrew package exists, but it is maintained by a third party. It can be installed with:

```bash
brew install zabbix-cli
```

### PyInstaller binaries
### Binary

Binaries built with PyInstaller can be found on the [releases page](https://github.com/unioslo/zabbix-cli/releases). We build binaries for Linux, macOS and Windows for each release.
Binaries built with PyInstaller can be found on the [releases page](https://github.com/unioslo/zabbix-cli/releases). We build binaries for Linux (x86), macOS (ARM) and Windows (x86) for each release.

## Quick start

Expand Down
2 changes: 2 additions & 0 deletions docs/.includes/admonition-pypi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
!!! note "PyPI package name"
We are in the process of acquiring the PyPI project `zabbix-cli`. Until then, installation must be done via the alias `zabbix-cli-uio`.
45 changes: 25 additions & 20 deletions docs/.includes/quick-install.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
=== "Cross-platform (pipx)"
=== "uv"

It is highly recommended to install the package with [`pipx`](https://pipx.pypa.io/stable/) to avoid conflicts with other Python packages on your system.
Install with [`uv`](https://docs.astral.sh/uv/getting-started/installation/) to avoid conflicts with other Python packages in your system:

```bash
pip install pipx
pipx install zabbix-cli-uio
uv tool install zabbix-cli-uio
```

This will install `zabbix-cli` in an isolated environment and make it available on your system path.
To try out Zabbix-CLI without installing it, run it directly with [`uvx`](https://docs.astral.sh/uv/#tool-management):

```bash
uvx --from zabbix-cli-uio zabbix-cli
```

{% include-markdown ".includes/admonition-pypi.md" %}

!!! note
We are in the process of acquiring the unmaintained PyPI package name `zabbixcli`, which will allow us to publish this package on PyPI under the name `zabbix-cli`. Until then, installation must be done via the aliased package name `zabbix-cli-uio`.
=== "pip(x)"

{% if install_expand is defined and install_expand == true %}
### Multiple installed versions
{% include-markdown ".includes/pipx-multiple.md" %}
{% endif %}
Install with [`pipx`](https://pipx.pypa.io/stable/) to avoid conflicts with other Python packages in your system:

=== "Cross-platform (pip)"
```bash
pipx install zabbix-cli-uio
```

If you prefer to install the package with `pip`, you can do so with the following command:
If you prefer to install the package with `pip`:

```bash
pip install zabbix-cli-uio
```

This will install `zabbix-cli` in your user environment.
{% include-markdown ".includes/admonition-pypi.md" %}

=== "MacOS"
=== "Homebrew"

You can install `zabbix-cli` with Homebrew:

Expand All @@ -39,16 +41,19 @@
!!! warning
The Homebrew package is maintained by a third party. It may be outdated or contain bugs. For the most up to date version, follow the installation instructions for pipx.

=== "PyInstaller Binary"
=== "Binary"

We build binaries with PyInstaller for each tagged release of Zabbix-cli. You can download the latest release from the [GitHub releases page](https://github.com/unioslo/zabbix-cli/releases).

Depending on your platform, you might need to make the binary executable:
Depending on your platform, you might need to make the binary executable and move it to a location in your `PATH`. Linux users can follow these steps:

```bash
# Rename and move the binary to a location in your PATH
mv zabbix-cli-ubuntu-22.04-3.12 /usr/local/bin/zabbix-cli
# Download the latest release and name it "zabbix-cli"
curl -L -o zabbix-cli https://github.com/unioslo/zabbix-cli/releases/latest/download/zabbix-cli-ubuntu-latest-3.12

# Make it executable
chmod +x /usr/local/bin/zabbix-cli
chmod +x zabbix-cli

# Move the binary to a location in your PATH
mv zabbix-cli /usr/local/bin/zabbix-cli
```
36 changes: 34 additions & 2 deletions docs/.includes/upgrade.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,49 @@
=== "uv"

```bash
uv tool upgrade zabbix-cli-uio
```

=== "pipx"

```bash
pipx upgrade zabbix-cli
pipx upgrade zabbix-cli-uio
```

=== "pip"

```bash
pip install --upgrade zabbix-cli
pip install --upgrade zabbix-cli-uio
```

=== "Homebrew"

```bash
brew upgrade zabbix-cli
```

=== "Binary (Automatic)"

Zabbix-cli has experimental support for updating itself. You can use the `zabbix-cli update` command to download and update the application to the latest version.

!!! danger "Write access required"
The application must have write access to itself and the directory it resides in.

```bash
zabbix-cli update
```

=== "Binary (Manual)"

The latest binary can be downloaded from [GitHub releases page](https://github.com/unioslo/zabbix-cli/releases). Download the binary for your platform and replace the current one.

To download the latest Linux binary and replace the current one:

```bash
curl -L -o zabbix-cli https://github.com/unioslo/zabbix-cli/releases/latest/download/zabbix-cli-ubuntu-latest-3.12

chmod +x zabbix-cli

# Replace destination with the path to the current binary
mv zabbix-cli /usr/local/bin/zabbix-cli
```
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Zabbix CLI is a command line application for interacting with Zabbix version 6 o

{% include-markdown ".includes/quick-install.md" %}

For the next steps or ways to customize the installation, head over to the detailed [installation](./guide/installation.md) guide.
For the next steps or ways to customize the installation, head over to the detailed [installation](./guide/installation.md) guide.
8 changes: 8 additions & 0 deletions zabbix_cli/_patches/click_repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ def repl( # noqa: C901
available_commands = group_ctx.command.commands
available_commands.pop(repl_command_name, None)

# Remove hidden commands
available_commands = {
cmd_name: cmd_obj
for cmd_name, cmd_obj in available_commands.items()
if not cmd_obj.hidden
}

group.commands = available_commands
prompt_kwargs = bootstrap_prompt(prompt_kwargs, group)

if isatty:
Expand Down
2 changes: 1 addition & 1 deletion zabbix_cli/app/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def _load_plugins_from_metadata(self, config: Config) -> None:
# By default, broken plugings will not break the application
# unless they are explicitly marked as required in the config.
# This is a deviation from the standard behavior of plugins, but
# since these are 3rd party plugins, we want to be more lenient
# since these are third party plugins, we want to be more lenient
# and not break the entire application if a plugin is broken.
if not conf or not conf.optional:
raise PluginLoadError(plugin.name, conf) from e
Expand Down
15 changes: 15 additions & 0 deletions zabbix_cli/commands/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,18 @@ def migrate_config(

conf.dump_to_file(destination)
success(f"Config migrated to {destination}")


@app.command("update", rich_help_panel=HELP_PANEL, hidden=True)
def update_application(ctx: typer.Context) -> None:
"""Update the application to the latest version.
Primarily intended for use with PyInstaller builds, but can also be
used for updating other installations (except Homebrew)."""
from zabbix_cli.update import update

info = update()
if info:
success(f"Application updated to {info.version}")
else:
success("Application updated.")
25 changes: 15 additions & 10 deletions zabbix_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,13 @@ def main_callback(

def should_skip_configuration(ctx: typer.Context) -> bool:
"""Check if the command should skip all configuration of the app."""
return ctx.invoked_subcommand in ["open", "sample_config", "show_dirs", "init"]
return ctx.invoked_subcommand in [
"update",
"open",
"sample_config",
"show_dirs",
"init",
]


def should_skip_login(ctx: typer.Context) -> bool:
Expand Down Expand Up @@ -229,16 +235,15 @@ def main() -> int:
"""Main entry point for the CLI."""
state = get_state()

# Load config before launching the app in order to:
# - configure logging
# - configure console output
# - load local plugins (defined in the config)
conf = _parse_config_arg()
config = get_config(conf, init=False)
state.config = config
app.load_plugins(state.config)

try:
# Load config before launching the app in order to:
# - configure logging
# - configure console output
# - load local plugins (defined in the config)
conf = _parse_config_arg()
config = get_config(conf, init=False)
state.config = config
app.load_plugins(state.config)
app()
except Exception as e:
from zabbix_cli.exceptions import handle_exception
Expand Down
Loading

0 comments on commit ec7f956

Please sign in to comment.