updating documentation

- giving things a better structure
- better documentation with the way things need to be as a standard
This commit is contained in:
Matthew Stobbs
2026-02-04 22:26:15 -07:00
parent 4e65d36b64
commit e231c6ae7a
15 changed files with 221 additions and 194 deletions

View File

@@ -2,108 +2,83 @@
## Package definition
Package defintions are just `yaml` tasks in the directory
`tasks/pkgs`, which handle how a package is installed.
A "package" is just a yaml task list that defines how to install a piece of software.
It does this through the use of `helpers` that manage;
Most can be installed using the `syspkgs` list, and are simply
appending the package name to said list based on the system.
- dependency installations
- building from source
- linking binaries to a usable `PATH`
- calling external tools when required
- installation via package managers on the system
If a package can be installed via an entry to `syspkgs` for some,
but not all platforms, handling is done to either inform the user
that the package is not available, or to append the package name
to another installation method such as:
## Anatomy of a Package Definition
- `appimages` to install the appimage of a package
- `cargopkgs` to install via the rust cargo package manager
- `cargoversioned` to install version lockec cargo packages
- `caskpkgs` to install a homebrew cask
- `flatpkgs` to install flatpaks
- `gopkgs` to install using the `go install` command
- `npmpkgs` to install packages from npm
- `pipxpkgs` to install packages from Python pip
- `srcpkgs` to build packages from source
- `tappkgs` to install packages from home brew taps
It starts with package metadata, as a comment block above the installation steps.
This should come after the line `# vim: set filetype=yaml.ansible :`, which sets
up the correct linter and language server when using neovim/vim.
Alternative sources of packages can be defined with entries to:
### Metadata
- `fpremotes` to add a flatpak remote
- `brewtaps` to add a homebrew tap
### Adding system level repositories
Many packages exist in their own external repository for the
given system, such as `/etc/yum.repos.d` for RedHat based linux
distros, `/etc/apt/sources.list.d` for Debian based distros and
others. Since you an add the package to `syspkgs` by enabling a
repo, the coresponding task in `tasks/pkgs` should take the
steps needed to enable the repository.
### Packages with multiple instllation methods
Many packages can be installed in different ways, like the
`bitwarden` package. `bitwarden` can be installed as a `syspkg`
on some machines, a `caskpkg` on macOS, an `appimage`, a `flatpak`
or even a `snap`.
For such packages, a default is chosen to install, in the following order
of precedence: `syspkgs`, `flatpkgs`, `snappkgs`, `appimages`.
In that order, `syspkgs` and `caskpkgs` have equal weight, as it applies
to macOS.
## Formatting rules
- Use indentation explicitness. Lists should be indented:
The metadata consists of at minimum 6 key: value pairs
```yaml
# Good
my_good_list:
- my_list_item
# Bad
my_bad_list:
- my_list_item
# Package: <package name>
# Description: <package description>
# Version: <latest supported version of package. 'latest' is fine>
# Methods: <list of available methods for installation>
# Helpers: <list of helpers used by the package directly>
# Maintainers: <list of maintainers for this package>
```
This list should match package defaults where it makes sense, for example,
the `Version:` should match the default installed version of the package.
- Variables should be in snake case, separating words
- Short names are fine if they are explicit. ie `vers` can be used instead of `version`
- If more then one variable starts with the same words, put it into a dict if it makes sense:
### Configuration acknowledgement
The "Configuration acknowledgement" MUST be at the start of the yaml file,
and cover everything this package does. This is important for gating when
a package should be configured or not.
It looks like this, using the `air` package:
```yaml
# variables that should be a dict
cargo_locked: true
cargo_pkg: alacritty
# better to just be
cargo:
locked: true
pkg: alacritty
```
- Tasks **MUST** follow the convention in this example:
```yaml
- name: Capitalize first letter of name
- name: Start air configuration
when:
- each condition has it's own line
- (brackets around conditions with) or
(to show they are separate)
become: "{{ not use_local }}" # must be able to be used with use_local
become_user: # this should not be needed, but always follows become if it is
loop: "{{ my_loopable_list }}"
loop_control: # **MUST** always use at least loop_var for any loop
loop_var: my_item
ansible.builtin.set_fact: # always use the full module name
...
- "'air' is not in __configured"
block:
- name: Configure air installation method
...
- name: Finalize air configuration
ansible.builtin.set_fact:
__air_configured: true
```
- `name`: Every task needs a name, and the first letter must be capitalized
- `when`: If a when clause exists, it follows the name
- Each clause must have it's own line, including and `or` clause, as seen above
- `become`: must follow the when clause if it exists, name otherwise
- Any other `become_` settings follow `become` in alphabetical order
- `loop`: must be defined just before the module invocation
- Every loop needs to rename the `loop_var` to something that makes sense
- `until` is consider the same as `loop` for the purposes of placement
- The last item must be the module invocation, using the fully qualified name
- For example, don't use `set_fact:`, use `ansible.builtin.set_fact:`
or alternatively:
```yaml
- name: Start air configuration
when:
- __configured['air'] is undefined
```
This way, if a package is included as part of another packages build, it only happens once.
### Setting and adding package configuration to list
Adding the configuration for a package is done by appending the configuration to the
appropriate list. Each helper has it's own installation block in `tasks/main.yml`.
Depending on the package installation method, the package must be added to the appropriate list.
#### Different lists, and when to use them
The following is a list of the different lists that are used, and the
order they are run.
- system: pkg_sys
- Only for packages installed from the system package manager
- If a package adds a repository to handle the system installation, it should be
done in the package configuration itself. For example, installing `ghostty` via
the system package manager requires adding a copr repo on fedora. This should be
done in a section named 'Adding copr repository scottames/ghostty'

View File

@@ -1,4 +1,5 @@
# ansible_role_package
# Ansible package manager
## _A ports like system for ansible_
Manage package installation for a number of packages
that sometimes need special handling. Some are built from
@@ -10,14 +11,16 @@ special instructions to properly install and use. I decided to
simplify the management of those packages by creating a role with
special handling.
_The following are for general use. Not all packages have a candidate for system package managers_
Order of precedence for package installation:
1. System package manager (dnf, apt, homebrew, etc.)
2. Source built - only in some situations, like for fast moving software (neovim, hyprland)
3. Appimage (Linux only)
4. Flatpak (Linux only)
5. Snap (Linux only), takes precedence over flatpak on Ubuntu based systems
6. Language package manager (`cargo install`, `go install`, `npm install`, etc.)
- Includes language package managers like `go install`, `cargo install`, and `npm install`
3. Flatpak (Linux only)
4. Snap (Linux only)
5. Appimage (Linux only)
_This does not configure installed software, just installs it_
@@ -26,11 +29,11 @@ To install any of the available packages, they must be part of a list called
## Supported Operating Systems
- Fedora Linux
- MacOS
- RHEL based distributions *Experimental* *best effort*
- Debian *Experimental*
- Alpine linux *Experimental* *best effort)
- Fedora Linux _first class support_
- MacOS _best effort_
- RHEL based distributions _Experimental, best effort_
- Debian _Experimental, best effort_
- Alpine linux _Experimental, best effort_
## Available Packages

View File

@@ -0,0 +1,22 @@
# vim: set filetype=yaml.ansible :
# Helper: external repository
---
- name: Add copr repository
when:
- ansible_os_family == 'RedHat'
community.general.copr:
host: "{{ repo.host | default('copr.fedorainfracloud.org') }}"
state: "{{ repo.state | default('enabled') }}"
name: "@{{ repo.name }}"
include: "{{ repo.include | default(omit) }}"
exclude: "{{ repo.exclude | default(omit) }}"
- name: Add apt ppa
when:
- ansible_os_family == 'Debian'
ansible.builtin.apt_repository:
codename: "{{ repo.codename | default(omit) }}"
filename: "{{ repo.filename | default(omit) }}"
install_python_apt: true
repo: "{{ repo.name }}"
state: "{{ repo.state | default('present') }}"

View File

@@ -1,26 +1,33 @@
# vim: set filetype=yaml.ansible :
---
- name: Install appimage {{ pkg }}
become: "{{ ext_become }}"
become: "{{ install_become }}"
become_user: "{{ install_become_user }}"
block:
- name: Ensure appimage path exists
ansible.builtin.file:
path: "{{ path.appimage }}/{{ appimage_link_name }}"
mode: '0755'
path: "{{ path_appimage }}/{{ pkg.name }}"
mode: "{{ pkg.mode | default('0755') }}"
owner: "{{ pkg.owner | default(ansible_user_id) }}"
group: "{{ pkg.group | default(ansible_user_gid) }}"
state: directory
- name: Fetch appimage
become: "{{ ext_become }}"
become: "{{ install_become }}"
become_user: "{{ install_become_user }}"
ansible.builtin.get_url:
mode: '0755'
mode: "{{ pkg.mode | default('0755') }}"
owner: "{{ pkg.owner | default(ansible_user_id) }}"
group: "{{ pkg.group | default(ansible_user_gid) }}"
url: "{{ pkg.url }}"
dest: "{{ path_appimage }}/{{ pkg.name }}/{{ pkg.filename }}"
decompress: false
backup: true
url: "{{ appimage_url }}"
dest: "{{ path.appimage }}/{{ appimage_link_name }}/{{ appimage_file }}"
backup: false
- name: Link appimage to bin
become: "{{ ext_become }}"
become: "{{ install_become }}"
become_user: "{{ install_become_user }}"
ansible.builtin.file:
state: link
src: "{{ path.appimage }}/{{ appimage_link_name }}/{{ appimage_file }}"
path: "{{ path.bindir }}/{{ appimage_link_name }}"
src: "{{ path_appimage }}/{{ pkg.name }}/{{ pkg.filename }}"
path: "{{ path_bin }}/{{ pkg.name }}"

View File

@@ -1,42 +1,48 @@
# vim: set filetype=yaml.ansible :
---
- name: Extract archive to given path
- name: Ensure requirements met
when:
- pkg.extract_to is defined
- pkg.name is defined
- pkg.url is defined
block:
- name: Ensure directory exists
become: "{{ install_become }}"
become_user: "{{ install_become_user }}"
ansible.bulitin.file:
state: directory
path: "{{ pkg.extract_path }}"
mode: "{{ pkg.install_prefix_mode | default('0755') }}"
owner: "{{ pkg.install_prefix_owner | default(ansible_user_id)}}"
group: "{{ pkg.install_prefix_group | default(ansible_user_gid) }}"
- name: Extract archive to given path
block:
- name: Ensure directory exists
become: "{{ install_become }}"
become_user: "{{ install_become_user }}"
ansible.bulitin.file:
state: directory
path: "{{ pkg.extract_to }}"
mode: "{{ pkg.mode | default('0755') }}"
owner: "{{ pkg.owner | default(ansible_user_id)}}"
group: "{{ pkg.group | default(ansible_user_gid) }}"
- name: Download archive to cache
ansible.builtin.get_url:
dest: "{{ d_cache }}/{{ pkg.archive_name }}"
url: "{{ pkg.archive_url }}"
checksum: "{{ pkg.archive_checksum | default(omit) }}"
decompress: false
mode: '0644'
- name: Download archive to cache
ansible.builtin.get_url:
dest: "{{ d_cache }}/{{ pkg.name }}"
url: "{{ pkg.url }}"
checksum: "{{ pkg.checksum | default(omit) }}"
decompress: false
mode: '0644'
- name: Extract archive
ansible.builtin.unarchive:
dest: "{{ pkg.extract_path }}"
src: "{{ d_cache }}/{{ pkg.archive_name }}"
remote_src: true
include: "{{ pkg.archive_include | default(omit) }}"
exclude: "{{ pkg.archive_exclude | default(omit) }}"
- name: Extract archive
ansible.builtin.unarchive:
dest: "{{ pkg.extract_to }}"
src: "{{ d_cache }}/{{ pkg.name }}"
remote_src: true
include: "{{ pkg.include | default(omit) }}"
exclude: "{{ pkg.exclude | default(omit) }}"
- name: Symlink archive files
when:
- pkg.link_bin is defined
- pkg.link_bin | length > 0
loop: pkg.link_bin
loop_control:
loop_var: lnk
ansible.builtin.file:
state: link
path: "{{ lnk.to }}"
src: "{{ lnk.from }}"
force: "{{ lnk.force | default(omit) }}"
- name: Symlink archive files
when:
- pkg.bins is defined
- pkg.bins | length > 0
loop: pkg.bins
loop_control:
loop_var: lnk
ansible.builtin.file:
state: link
path: "{{ lnk.to }}"
src: "{{ lnk.from }}"
force: "{{ lnk.force | default(omit) }}"

View File

@@ -1,11 +1,10 @@
# vim: set filetype=yaml.ansible
---
- name: Install cargo {{ pkg }}
become: "{{ ext_become }}"
environment:
RUSTONIG_SYSTEM_LIBONIG: 1
- name: Install cargo
become: "{{ install_become }}"
become_user: "{{ install_become_user }}"
community.general.cargo:
name: "{{ pkg.name | default(pkg) }}"
version: "{{ pkg.vers | default(omit) }}"
path: "{{ path.cargo | default(path.prefix) }}"
locked: "{{ pkg.locked | default(omit) }}"
version: "{{ pkg.version | default(omit) }}"
locked: "{{ pkg.locked | default(false) }}"
path: "{{ install_prefix }}"

View File

@@ -4,11 +4,11 @@
block:
- name: Set build variables
ansible.builtin.set_fact:
git_path: "{{ d_tempdir.path }}/{{ name }}"
git_repo: "{{ repo }}"
git_depth: "{{ depth | default(1) }}"
git_recursive: "{{ recursive | default(true) }}"
git_version: "{{ version | default(omit) }}"
git_path: "{{ d_tempdir.path }}/{{ pkg.name }}"
git_repo: "{{ pkg.repo }}"
git_depth: "{{ pkg.depth | default(1) }}"
git_recursive: "{{ pkg.recursive | default(true) }}"
git_version: "{{ pkg.version | default(omit) }}"
- name: Fetch git repo
ansible.builtin.include_tasks:
@@ -16,9 +16,9 @@
- name: Build cargo release
ansible.builtin.command:
creates: "{{ bin_output }}"
chdir: "{{ git_path }}"
argv: "{{ [cargo, build] + cargo_build_flags }}"
creates: "{{ pkg.bin_output }}"
chdir: "{{ pkg.path }}"
argv: "{{ [cargo, build] + pkg.build_flags }}"
- name: Install cargo release
block:

View File

@@ -2,9 +2,9 @@
---
- name: Clone git repository
ansible.builtin.git:
depth: "{{ git_depth | default(1) }}"
dest: "{{ git_path }}"
force: "{{ git_force | default(true) }}"
recursive: "{{ git_recursive | default(true) }}"
repo: "{{ git_repo }}"
version: "{{ git_version | default(omit) }}"
depth: "{{ git.depth | default(1) }}"
dest: "{{ git.path }}"
force: "{{ git.force | default(true) }}"
recursive: "{{ git.recursive | default(true) }}"
repo: "{{ git.repo }}"
version: "{{ git.version | default(omit) }}"

View File

@@ -1,8 +1,10 @@
# vim: set filetype=yaml.ansible :
---
- name: Install npm {{ pkg }}
become: true
- name: Install npm
become: "{{ install_become }}"
become_user: "{{ install_become_user }}"
community.general.npm:
global: true
name: "{{ pkg }}"
state: present
global: "{{ pkg.global | default(true) }}"
name: "{{ pkg.name }}"
version: "{{ pkg.version | default('latest') }}"
state: "{{ pkg.state | default('present') }}"

View File

@@ -1,8 +1,14 @@
# vim: set filetype=yaml.ansible :
# Package: air
# Description: application auto reload for go
# Version: latest
# Methods: source (go install)
# Helpers: go_install
---
- name: Configure air # {{{
# {{{ Configure air
- name: Start air configuration
when:
- __air_configured is undefined
- "'air' not in __configured"
block:
- name: Set air install method
when:
@@ -44,6 +50,6 @@
ansible.builtin.set_fact:
pkg_go: "{{ pkg_go + [air_go_pkg] }}"
- name: Complete air configuration
- name: Finalize air configuration
ansible.builtin.set_fact:
__air_configured: true
__configured: "{{ __configured | combine( { 'air': true } ) }}"

View File

@@ -1,9 +1,5 @@
# vim: set filetype=yaml.ansible :
---
- name: Set maintainer
ansible.builtin.set_fact:
ansible_maintainers:
- Matthew Stobbs
- name: Configure ansible
when:
- __ansible_configured is undefined or

View File

@@ -1,6 +1,6 @@
# vim: set filetype=yaml.ansible :
---
- name: Add ansible_ls
- name: Configure ansible_ls
when:
- __ansible_ls_configured is undefined
block:
@@ -10,9 +10,19 @@
ansible.builtin.set_fact:
ansible_ls_install_method: "{% if install_method in ansible_ls_install_methods %}{{ install_method }}{% else %}{{ ansible_ls_install_methods[0] }}{% endif %}"
- name: Append ansible-language-server to pkg_npm
- name: Configure ansible_ls source npm installation
when:
- ansible_ls_install_method == 'source'
ansible.builtin.set_fact:
pkg_npm: "{{ pkg_npm + ['@ansible/ansible-language-server'] }}"
ansible_npm_pkg:
name: '@ansible/ansible-language-server'
global: true
- name: Append ansible-language-server to pkg_npm
when:
- ansible_ls_install_method == 'source'
ansible.builtin.set_fact:
pkg_npm: "{{ pkg_npm + [ansible_npm_pkg] }}"
- name: Set ansible_ls_configured
when:

View File

@@ -56,11 +56,11 @@
- name: Finalize go archive install
ansible.builtin.set_fact:
go_archive_install:
extract_path: "{{ go_extract_path }}"
archive_url: "{{ go_archive_url }}"
archive_name: "{{ go_archive }}"
archive_checksum: "{{ go_archive_sums[go_archive_version][ansible_system][go_arch] }}"
link_bin:
extract_to: "{{ go_extract_path }}"
url: "{{ go_archive_url }}"
name: "{{ go_archive }}"
checksum: "{{ go_archive_sums[go_archive_version][ansible_system][go_arch] }}"
bins:
- from: "{{ go_archive_path }}/go"
to: "{{ path_go }}"
force: true

View File

@@ -37,20 +37,21 @@ path_lib: "{{ install_prefix }}/lib"
# System paths
# empty lists that must be defined
pkg_appimage: [] # appimages to install
pkg_archive: [] # packages installed via prebuilt archive
pkg_cargo: [] # rust packages from cargo using `cargo install`
pkg_cargo_build: [] # rust packages using `cargo build` before install
pkg_flatpak: [] # flatpak packages to install
pkg_go: [] # go applications
pkg_npm: [] # npm commands
pkg_pipx: [] # pipx packages
pkg_sys_pip: [] # system pip packages
pkg_sh: [] # use shell commands to install a package
pkg_snap: [] # snpacraft.io packages
pkg_src: [] # packages built from source
pkg_sys: [] # system package manager packages
pkg_sys_pip: [] # system pip packages
pkg_zig: [] # zig packages
pkg_sh: [] # use shell commands to install a package
pkg_appimage: [] # appimages to install
pkg_flatpak: [] # flatpak packages to install
pkg_snap: [] # snpacraft.io packages
__configured: [] # list of configured packages
# Per package variables
## {{{ air