diff --git a/README.md b/README.md index 39135b2..1488e87 100755 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ reproducible. - Automatic software updates using custom logic. - Group software installations into logical "steps" with sophisticated orchestration. - **Category headers** to visually organize your installers list. +- **Template variables** for dynamic values (architecture, OS, device ID) in commands and filenames. --- @@ -177,29 +178,29 @@ install: See [Installer Configuration](./docs/installer-configuration.md#categories) for more details. -| Field | Type | Description | -| ------------------ | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `name` | String (required) | Identifier for the step. It does not have to be unique, but is usually used to check for the app's existence, if applicable (can be overridden using `bin_name`) | -| `type` | String (required) | Type of the step. See [supported types](#supported-type-of-installers) for a comprehensive list of supported values. | -| `platforms` | Object (optional) | Platform-specific execution controls. See `platforms` subfields below. | -| `platforms.only` | Array of Strings | Platforms where the step should execute (e.g., `['macos', 'linux']`). Supercedes `platforms.except`. | -| `platforms.except` | Array of Strings | Platforms where the step should **not** execute; replaces `platforms.only`. | -| `machines` | Object (optional) | Machine-specific execution controls. Use `sofmani --machine-id` to get your machine ID. You can use raw IDs or aliases defined in `machine_aliases`. | -| `machines.only` | Array of Strings | Machine IDs or aliases where the step should execute. Supercedes `machines.except`. | -| `machines.except` | Array of Strings | Machine IDs or aliases where the step should **not** execute. | -| `steps` | Array of Installers | Sub-steps for `group` type. Allows nesting multiple steps together. | -| `opts` | Object (optional) | Step-specific options and configurations. Content varies depending on the `type`. See [supported types](#supported-type-of-installers) for a comprehensive list of supported values. | -| `bin_name` | String (optional) | Binary name for the installed software, used instead of `name` when checking for app's existence. | -| `check_has_update` | String (shell script) | Shell command to check whether an update is available for the installed software. This will override the default check provided by the corresponding `type`. The check **must succeed** (return exit code 0) if the app has an update, or fail (other status codes) if the app is up to date. | -| `check_installed` | String (shell script) | Shell command to check if the step has already been installed. If the check succeeds (exits with status 0), it means the app is already installed and can be skipped if not checking for updates. | -| `pre_install` | String (shell script) | Shell script to execute _before_ the step is installed. | -| `post_install` | String (shell script) | Shell script to execute _after_ the step is installed. | -| `pre_update` | String (shell script) | Shell script to execute _before_ the step is updated (if applicable). | -| `post_update` | String (shell script) | Shell script to execute _after_ the step is updated (if applicable). | -| `env_shell` | Object (optional) | Shell to use for command executions. See `env_shell` subfields below. | -| `env_shell.macos` | String (optional) | Shell to use for macOS command executions. If not specified, the default shell will be used. | -| `env_shell.linux` | String (optional) | Shell to use for Linux command executions. If not specified, the default shell will be used. | -| `skip_summary` | Boolean or Object | Exclude this installer from the summary. Set to `true` to skip both install/update summaries, or use `{install: true}` / `{update: true}` for granular control. Useful for installers that always run. | +| Field | Type | Description | +| ------------------ | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | String (required) | Identifier for the step. It does not have to be unique, but is usually used to check for the app's existence, if applicable (can be overridden using `bin_name`) | +| `type` | String (required) | Type of the step. See [supported types](#supported-type-of-installers) for a comprehensive list of supported values. | +| `platforms` | Object (optional) | Platform-specific execution controls. See `platforms` subfields below. | +| `platforms.only` | Array of Strings | Platforms where the step should execute (e.g., `['macos', 'linux']`). Supercedes `platforms.except`. | +| `platforms.except` | Array of Strings | Platforms where the step should **not** execute; replaces `platforms.only`. | +| `machines` | Object (optional) | Machine-specific execution controls. Use `sofmani --machine-id` to get your machine ID. You can use raw IDs or aliases defined in `machine_aliases`. | +| `machines.only` | Array of Strings | Machine IDs or aliases where the step should execute. Supercedes `machines.except`. | +| `machines.except` | Array of Strings | Machine IDs or aliases where the step should **not** execute. | +| `steps` | Array of Installers | Sub-steps for `group` type. Allows nesting multiple steps together. | +| `opts` | Object (optional) | Step-specific options and configurations. Content varies depending on the `type`. See [supported types](#supported-type-of-installers) for a comprehensive list of supported values. | +| `bin_name` | String (optional) | Binary name for the installed software, used instead of `name` when checking for app's existence. | +| `check_has_update` | String (shell script) | Shell command to check whether an update is available for the installed software. This will override the default check provided by the corresponding `type`. The check **must succeed** (return exit code 0) if the app has an update, or fail (other status codes) if the app is up to date. Supports [template variables](./docs/installer-configuration.md#template-variables). | +| `check_installed` | String (shell script) | Shell command to check if the step has already been installed. If the check succeeds (exits with status 0), it means the app is already installed and can be skipped if not checking for updates. Supports [template variables](./docs/installer-configuration.md#template-variables). | +| `pre_install` | String (shell script) | Shell script to execute _before_ the step is installed. Supports [template variables](./docs/installer-configuration.md#template-variables). | +| `post_install` | String (shell script) | Shell script to execute _after_ the step is installed. Supports [template variables](./docs/installer-configuration.md#template-variables). | +| `pre_update` | String (shell script) | Shell script to execute _before_ the step is updated (if applicable). Supports [template variables](./docs/installer-configuration.md#template-variables). | +| `post_update` | String (shell script) | Shell script to execute _after_ the step is updated (if applicable). Supports [template variables](./docs/installer-configuration.md#template-variables). | +| `env_shell` | Object (optional) | Shell to use for command executions. See `env_shell` subfields below. | +| `env_shell.macos` | String (optional) | Shell to use for macOS command executions. If not specified, the default shell will be used. | +| `env_shell.linux` | String (optional) | Shell to use for Linux command executions. If not specified, the default shell will be used. | +| `skip_summary` | Boolean or Object | Exclude this installer from the summary. Set to `true` to skip both install/update summaries, or use `{install: true}` / `{update: true}` for granular control. Useful for installers that always run. | ### Supported `type` of Installers diff --git a/docs/command-line-interface.md b/docs/command-line-interface.md index 481c7e7..d715327 100755 --- a/docs/command-line-interface.md +++ b/docs/command-line-interface.md @@ -11,19 +11,19 @@ repository. You can call `sofmani` with the following flags to alter the behavior for the current run: -| Flag | Description | -| --------------------- | ------------------------------------------------------- | -| `-d`, `--debug` | Enable debug mode. | -| `-D`, `--no-debug` | Disable debug mode (default). | -| `-u`, `--update` | Enable update checking. | -| `-U`, `--no-update` | Disable update checking (default). | -| `-s`, `--summary` | Enable installation summary (default). | -| `-S`, `--no-summary` | Disable installation summary. | -| `-f`, `--filter` | Filter by installer name (can be used multiple times)\* | -| `-l`, `--log-file` | Set log file path, or show current path if no value. | -| `-m`, `--machine-id` | Show machine ID and exit. | -| `-h`, `--help` | Display help information and exit. | -| `-v`, `--version` | Display version information and exit. | +| Flag | Description | +| -------------------- | ------------------------------------------------------- | +| `-d`, `--debug` | Enable debug mode. | +| `-D`, `--no-debug` | Disable debug mode (default). | +| `-u`, `--update` | Enable update checking. | +| `-U`, `--no-update` | Disable update checking (default). | +| `-s`, `--summary` | Enable installation summary (default). | +| `-S`, `--no-summary` | Disable installation summary. | +| `-f`, `--filter` | Filter by installer name (can be used multiple times)\* | +| `-l`, `--log-file` | Set log file path, or show current path if no value. | +| `-m`, `--machine-id` | Show machine ID and exit. | +| `-h`, `--help` | Display help information and exit. | +| `-v`, `--version` | Display version information and exit. | Each of these flags overrides the loaded config file, so while your default config can choose not to check for updates by default, you or another user can add the `--update` flag to override this diff --git a/docs/configuration-reference.md b/docs/configuration-reference.md index 1e68aca..c96e85f 100755 --- a/docs/configuration-reference.md +++ b/docs/configuration-reference.md @@ -51,6 +51,8 @@ Here is a breakdown of all configuration options: - Use `sofmani --machine-id` to get the machine ID for each of your machines. - These aliases can then be used in installer `machines.only` and `machines.except` fields instead of the raw machine IDs. + - The alias for the current machine is also available as the `{{ .DeviceIDAlias }}` template + variable and the `$DEVICE_ID_ALIAS` environment variable in all commands. - Example: ```yaml machine_aliases: diff --git a/docs/installer-configuration.md b/docs/installer-configuration.md index 5cf75b3..9e5ad37 100755 --- a/docs/installer-configuration.md +++ b/docs/installer-configuration.md @@ -117,7 +117,7 @@ These fields are shared by all installer types. Some fields may vary in behavior - **Type**: String or Boolean (optional) - **Description**: Enable or disable the step. Disabled steps are not run. This can either be a static boolean (`true` or `false`), or a command that returns a success status code for true, or - a failure for false. + a failure for false. Commands support [template variables](#template-variables). - **`tags`** - **Type** String (optional) @@ -173,29 +173,33 @@ These fields are shared by all installer types. Some fields may vary in behavior - **Description**: Shell command to check whether an update is available for the installed software. This will override the default check provided by the corresponding `type`. The check **must succeed** (return exit code 0) if the app has an update, or fail (other status codes) if - the app is up to date. + the app is up to date. Supports [template variables](#template-variables). - **`check_installed`** - **Type**: String (shell script) - **Description**: Shell command to check if the step has already been installed. If the check succeeds (exits with status 0), it means the app is already installed and can be skipped if not - checking for updates. + checking for updates. Supports [template variables](#template-variables). - **`pre_install`** - **Type**: String (shell script) - - **Description**: Shell script to execute _before_ the step is installed. + - **Description**: Shell script to execute _before_ the step is installed. Supports + [template variables](#template-variables). - **`post_install`** - **Type**: String (shell script) - - **Description**: Shell script to execute _after_ the step is installed. + - **Description**: Shell script to execute _after_ the step is installed. Supports + [template variables](#template-variables). - **`pre_update`** - **Type**: String (shell script) - - **Description**: Shell script to execute _before_ the step is updated (if applicable). + - **Description**: Shell script to execute _before_ the step is updated (if applicable). Supports + [template variables](#template-variables). - **`post_update`** - **Type**: String (shell script) - - **Description**: Shell script to execute _after_ the step is updated (if applicable). + - **Description**: Shell script to execute _after_ the step is updated (if applicable). Supports + [template variables](#template-variables). - **`env_shell`** - **Type**: Object (optional) @@ -247,10 +251,55 @@ These fields are shared by all installer types. Some fields may vary in behavior update: true ``` +## Template Variables + +All shell commands across installers support **Go template syntax** for dynamic value insertion. +This includes `opts.command`, `opts.update_command`, `pre_install`, `post_install`, `pre_update`, +`post_update`, `check_installed`, `check_has_update`, and `enabled` (when it's a shell command). + +Available variables: + +| Variable | Description | Example | +| ---------------------- | ------------------------------------------------------------------------------------ | --------------------------- | +| `{{ .Arch }}` | System architecture in Go format | `amd64`, `arm64` | +| `{{ .ArchAlias }}` | Architecture in common alias format | `x86_64`, `arm64` | +| `{{ .ArchGnu }}` | Architecture in GNU/Linux format | `x86_64`, `aarch64` | +| `{{ .OS }}` | Current operating system | `macos`, `linux`, `windows` | +| `{{ .DeviceID }}` | Unique machine identifier (truncated SHA-256 hash) | `5fa2a8e8193868df` | +| `{{ .DeviceIDAlias }}` | Friendly alias for the current machine, if defined in `machine_aliases` | `work-laptop` | +| `{{ .Tag }}` | Full tag name (only available in `github-release` `download_filename`) | `v1.0.0` | +| `{{ .Version }}` | Version without leading "v" (only available in `github-release` `download_filename`) | `1.0.0` | + +In addition, `DEVICE_ID` and `DEVICE_ID_ALIAS` are injected as **environment variables** into all +command executions, so they can also be referenced as `$DEVICE_ID` and `$DEVICE_ID_ALIAS` in shell +commands. + +### Example + +```yaml +machine_aliases: + work-laptop: 5fa2a8e8193868df + home-desktop: a1b2c3d4e5f67890 + +install: + - name: sync-config + type: shell + opts: + command: cp ~/dotfiles/config-{{ .DeviceIDAlias }}.yaml ~/.config/myapp/config.yaml + + - name: setup-tool + type: shell + opts: + command: | + echo "Setting up on device $DEVICE_ID ({{ .DeviceIDAlias }})" + ./setup.sh --arch {{ .Arch }} --os {{ .OS }} +``` + ## Supported `type` of Installers - **`shell`** - - **Description**: Executes arbitrary shell commands. + - **Description**: Executes arbitrary shell commands. Commands support + [template variables](#template-variables). - **Options**: - `opts.command`: The command to execute for installing. - `opts.update_command`: The command to execute for updating. @@ -293,10 +342,13 @@ These fields are shared by all installer types. Some fields may vary in behavior - `{{ .ArchAlias }}` - the architecture in common alias format, e.g. `x86_64`, `arm64` - `{{ .ArchGnu }}` - the architecture in GNU/Linux format, e.g. `x86_64`, `aarch64` - `{{ .OS }}` - the current operating system, e.g. `macos`, `linux`, `windows` + - `{{ .DeviceID }}` - the unique machine identifier (truncated SHA-256 hash) + - `{{ .DeviceIDAlias }}` - the friendly alias for the current machine, if defined in + `machine_aliases` **Legacy syntax (deprecated):** The old `{tag}`, `{version}`, `{arch}`, `{arch_alias}`, - `{arch_gnu}`, and `{os}` tokens are still supported but deprecated. A deprecation warning will - be logged at DEBUG level when they are used. + `{arch_gnu}`, `{os}`, `{device_id}`, and `{device_id_alias}` tokens are still supported but + deprecated. A deprecation warning will be logged at DEBUG level when they are used. Examples: @@ -315,9 +367,9 @@ These fields are shared by all installer types. Some fields may vary in behavior download_filename: myapp_{tag}_linux.tar.gz # outputs: myapp_v1.0.0_linux.tar.gz ``` - - `opts.archive_bin_name`: The name of the binary file inside the archive (tar/zip). - Use this when the filename inside the archive differs from the desired output `bin_name`. - If not set, falls back to `bin_name` (or the installer name). + - `opts.archive_bin_name`: The name of the binary file inside the archive (tar/zip). Use this + when the filename inside the archive differs from the desired output `bin_name`. If not set, + falls back to `bin_name` (or the installer name). ```yaml - name: cospend-cli @@ -328,7 +380,7 @@ These fields are shared by all installer types. Some fields may vary in behavior destination: ~/.local/bin strategy: tar download_filename: cospend-cli-linux-{{ .Arch }}.tar.gz - archive_bin_name: cospend-cli # file inside the tar is "cospend-cli", output will be "cospend" + archive_bin_name: cospend-cli # file inside the tar is "cospend-cli", output will be "cospend" ``` - `opts.github_token`: GitHub personal access token for authenticated API requests.