# Slices CLI.

See https://doc.slices-ri.eu/SupportingServices/slicescli.html

This is a meta-package that installs the core slices CLI, and the slices Basic Infrastructure CLI.

# How to add a new "Sub Command CLI" to slices-cli?

The main slices CLI scans the dirs in the `PATH` env variable for executable files that match the pattern `slices-*`. 

These are all called with the `--cli-manifest` option, to get the required meta-data.
If they return the correct meta-data, they are added to the list of sub commands.

Additionally, each slices subcommand CLI needs to have a `--version` option. 
This needs to return the version of the subcommand CLI.
The version should start with the letter `v`. The `--version` command should not return any other output than the version.
The main CLI will include this output when it is called with the `--version` option.

## Metadata manifest format

Example meta-data returned by `slices-helloworld --cli-manifest`:

```json
{
  "@type": "slices-cli:subcommand-metadata",
  "version": "1.0",
  "short_help": "Hello World Demo",
  "tab_completion_supported": true,
  "tab_completion_install_option": "--install-completion",
  "visible_aliases": [],
  "hidden_aliases": []
}
```

Details:
- The `@type` field is used to identify the meta-data manifest.
- The `version` field is the version of the meta-data manifest.
- The `short_help` field is used in the main slices CLI to generate the help text for the subcommand.
- The `tab_completion_supported` field is used to determine if the subcommand supports command line completion.
- The `tab_completion_install_option` field is used to determine the CLI option used to install the command line completion. 
- The `visible_aliases` field is used to add subcommand aliases that are visible in the main slices CLI --help.
- The `hidden_aliases` field is used to add aliases that are hidden in the main slices CLI --help.
  An example is `--install-completion`, which us used for CLIs written using the python [typer](https://typer.tiangolo.com/) CLI library.

## Version

Example output of `slices-helloworld --version`:

```
v1.3.2
```

# How are Sub Command CLIs called by the main CLI?

The sub CLI is called, via an `exec` call, replacing the `slices` process.
All command line options are passed to the subcommand CLI.

Note that the sub CLI is called with identical arguments. The subcommand is not removed.
This means that a call to `slices subcommand foobar` will call `slices-subcommand subcommand foobar`.

To summarize, the subcommand should answer the following:

```
slices-subcommand --version
slices-subcommand --cli-manifest
slices-subcommand subcommand (whatever options your subcommand supports)
slices --version : will show your subcommand and its version
```

## How should I access auth tokens and config?

Subcommand CLIs that are implemented in python should use the [Slices ClientLib Core for Python](https://gitlab.ilabt.imec.be/slices-public/slices-sdk/python/slices-clientlib-core-py).
This library provides access to all core slices functionality and can load the files from the ~/.slices` directory.

Subcommands implemented in other languages should use a [SDK](https://gitlab.ilabt.imec.be/slices-public/slices-sdk) for that language. 

In python, the basic code to load the config and auth tokens is:

```python
import sys
import os
from pathlib import Path
from slices_clientlib_core import SlicesClient
from slices_clientlib_core.base.auth import CredentialsBrokenError, load_auth_token_and_user
from slices_clientlib_core.base.config import (
    ConfigBrokenError,
    load_cli_central_api_clients_config,
    load_current_project_id,
)

api_config = Path(os.environ.get("SLICES_CUSTOM_CONFIG")) if "SLICES_CUSTOM_CONFIG" in os.environ else None

# First, we get the "central config". SlicesClient needs this.
# This will automatically get the config from the command line option, the env var, the cache, or online source.
try:
    central_config = load_cli_central_api_clients_config(api_config)
except ConfigBrokenError as e:
    print(f"{e}", file=sys.stderr)
    sys.exit(1)

# Next, we'll get the auth token and user info.
# This will automatically load the auth token from the cache and refresh it if needed.
# This also automatically supports external auth token providers that use SLICES_AUTH_TOKEN_PROVIDER.
try:
    auth_token, user_info = load_auth_token_and_user()
except CredentialsBrokenError as e:
    print(f"{e}", file=sys.stderr)
    print("Please log in again", file=sys.stderr)
    sys.exit(1)

# This example chooses to not support the case where the user is not logged in.
if user_info is None:
    print("You must be logged in to use this command", file=sys.stderr)
    sys.exit(1)

# We create the slices-clientlib-core SliceClient, which allows easy access to all APIs.
slices_client = SlicesClient(central_config=central_config)

# We get the current project ID.
# This automatically loads the project ID from the settings or from the env var.
project_id = load_current_project_id()
```

## Command line tab completion

The main CLI supports command line tab completion.
The completions for the subcommand CLIs are delegated to the completion installed by the subcommand CLI.

When `slices completion install` is called, the main CLI will:
- Install completion for all the subcommands. This is done using the `tab_completion_install_option` from the meta-data.
  For example, if the meta-data says `--install-completion`, then the main CLI will call `slices-helloworld --install-completion`.
- Install completion for the main CLI. This completion will internally call the subcommand CLI completion when needed.
  This mechanism relies on the fact that the subcommand completions are installed with `complete -F <function> ...`.

At the moment, command line completion is only supported for the `bash` and `zsh` shell.
Support for the `fish` shell might be added on request.

## Advanced metadata manifest format

If multiple subcommands are supported by the executable, this can be specified by a manifest with a different `@type`:

```json
{
  "@type": "slices-cli:multi-subcommand-metadata",
  "version": "1.0",
  "tab_completion_supported": true,
  "tab_completion_install_option": "--install-completion",
  "subcommands": [
    {
      "name": "helloworld",
      "short_help": "Hello World Demo",
      "visible_aliases": ["hello"],
      "hidden_aliases": ["hi", "hiworld"]
    },
    {
      "name": "hello-you",
      "short_help": "Hello You Demo",
      "visible_aliases": [],
      "hidden_aliases": []
    }
  ]
}
```
