204 lines
4.9 KiB
Markdown
204 lines
4.9 KiB
Markdown
# flow
|
|
|
|
`flow` is a CLI for managing development instances, containers, dotfiles, and host bootstrap.
|
|
|
|
## What is implemented
|
|
|
|
- Instance access via `flow enter`
|
|
- Container lifecycle under `flow dev`
|
|
- Dotfiles repo management (`flow dotfiles`)
|
|
- Bootstrap provisioning (`flow bootstrap`)
|
|
- Package installs from unified manifest definitions (`flow package`)
|
|
- Project sync checks (`flow sync`)
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
make build
|
|
make install-local
|
|
```
|
|
|
|
This installs `flow` to `~/.local/bin/flow`.
|
|
|
|
## Core behavior
|
|
|
|
### Security model
|
|
|
|
- `flow` must run as a regular user (root/sudo invocation is rejected).
|
|
- At startup, `flow` refreshes sudo credentials once (`sudo -v`) for privileged steps.
|
|
- Package `post-install` hooks run without sudo by default.
|
|
- A package hook can use sudo only when `allow_sudo: true` is explicitly set.
|
|
|
|
### Config location and merge rules
|
|
|
|
`flow` loads all YAML files from:
|
|
|
|
1. `~/.local/share/flow/dotfiles/_shared/flow/.config/flow/` (self-hosted, if present)
|
|
2. `~/.config/flow/` (local fallback)
|
|
|
|
Files are read alphabetically (`*.yaml` and `*.yml`) and merged at top level.
|
|
If the same top-level key appears in multiple files, the later filename wins.
|
|
|
|
`repository.pull-before-edit` controls whether `flow dotfiles edit` runs `git pull --rebase` first (default: `true`).
|
|
When pull brings new changes, flow shows an info message and waits for Enter before opening the editor.
|
|
|
|
### Dotfiles layout (flat with reserved dirs)
|
|
|
|
Inside your dotfiles repo root:
|
|
|
|
```text
|
|
_shared/
|
|
flow/
|
|
.config/flow/
|
|
config.yaml
|
|
packages.yaml
|
|
profiles.yaml
|
|
dnsmasq/
|
|
.user_hosts
|
|
_root/
|
|
opt/homebrew/etc/dnsmasq.conf
|
|
git/
|
|
.gitconfig
|
|
linux-auto/
|
|
nvim/
|
|
.config/nvim/init.lua
|
|
```
|
|
|
|
- `_shared/`: linked for all profiles
|
|
- `_root/` is a marker inside a package for absolute paths (via sudo), e.g. `dnsmasq/_root/etc/hostname -> /etc/hostname`
|
|
- every other directory at this level is a profile name
|
|
- any target conflict fails (including `_shared` vs profile)
|
|
|
|
### External module packages
|
|
|
|
Packages can be backed by an external git repository using `_module.yaml`:
|
|
|
|
```yaml
|
|
source: github:org/nvim-config
|
|
ref:
|
|
branch: main
|
|
```
|
|
|
|
- If a package directory contains `_module.yaml`, flow uses the fetched module content as package source.
|
|
- Any sibling files in that package directory are ignored (shown only in `--verbose`).
|
|
- Modules are refreshed on `flow dotfiles init` and `flow dotfiles sync` (not on `link`).
|
|
|
|
## Manifest model
|
|
|
|
Top-level keys:
|
|
|
|
- `profiles`
|
|
- `packages`
|
|
- optional global settings like `repository`, `paths`, `defaults`, `targets`
|
|
|
|
`environments` is not supported.
|
|
|
|
### Packages (unified)
|
|
|
|
```yaml
|
|
packages:
|
|
- name: fd
|
|
type: pkg
|
|
sources:
|
|
apt: fd-find
|
|
dnf: fd-find
|
|
brew: fd
|
|
|
|
- name: wezterm
|
|
type: cask
|
|
sources:
|
|
brew: wezterm
|
|
|
|
- name: neovim
|
|
type: binary
|
|
source: github:neovim/neovim
|
|
version: "0.10.4"
|
|
asset-pattern: "nvim-{{os}}-{{arch}}.tar.gz"
|
|
platform-map:
|
|
linux-x64: { os: linux, arch: x64 }
|
|
linux-arm64: { os: linux, arch: arm64 }
|
|
darwin-arm64: { os: macos, arch: arm64 }
|
|
extract-dir: "nvim-{{os}}64"
|
|
install:
|
|
bin: [bin/nvim]
|
|
share: [share/nvim]
|
|
man: [share/man/man1/nvim.1]
|
|
lib: [lib/libnvim.so]
|
|
```
|
|
|
|
### Profile package syntaxes
|
|
|
|
All are supported in one profile list:
|
|
|
|
```yaml
|
|
profiles:
|
|
macos-dev:
|
|
os: macos
|
|
packages:
|
|
- git
|
|
- cask/wezterm
|
|
- binary/neovim
|
|
- name: docker
|
|
allow_sudo: true
|
|
post-install: |
|
|
sudo groupadd docker || true
|
|
sudo usermod -aG docker $USER
|
|
```
|
|
|
|
### Templates
|
|
|
|
- `{{ env.VAR_NAME }}`
|
|
- `{{ version }}`
|
|
- `{{ os }}`
|
|
- `{{ arch }}`
|
|
|
|
### Bootstrap profile features
|
|
|
|
- `os` is required (`linux` or `macos`)
|
|
- `package-manager` optional (auto-detected if omitted)
|
|
- default locale is `en_US.UTF-8`
|
|
- shell auto-install + `chsh` when `shell:` is declared and missing
|
|
- `requires` validation for required env vars
|
|
- `ssh-keygen` definitions
|
|
- `runcmd` (runs after package installation)
|
|
- automatic config linking (`_shared` + profile, including package-local `_root` markers)
|
|
- `post-link` hook (runs after symlink phase)
|
|
- config skip patterns:
|
|
- package names (e.g. `nvim`)
|
|
- `_shared`
|
|
- `_profile`
|
|
- `_root`
|
|
|
|
## Command overview
|
|
|
|
```bash
|
|
flow enter personal@orb
|
|
flow dev create api -i tm0/node -p ~/projects/api
|
|
|
|
flow dotfiles init --repo git@github.com:you/dotfiles.git
|
|
flow dotfiles link --profile linux-auto
|
|
flow dotfiles undo
|
|
flow dotfiles status
|
|
flow dotfiles modules list
|
|
flow dotfiles modules sync
|
|
|
|
flow bootstrap list
|
|
flow bootstrap show linux-auto
|
|
flow bootstrap run --profile linux-auto --var USER_EMAIL=you@example.com
|
|
|
|
flow package install neovim
|
|
flow package list --all
|
|
|
|
flow sync check
|
|
flow completion install-zsh
|
|
```
|
|
|
|
## Development
|
|
|
|
```bash
|
|
python3 -m venv .venv
|
|
.venv/bin/pip install -e ".[dev]"
|
|
python3 -m pytest
|
|
FLOW_RUN_E2E_CONTAINER=1 .venv/bin/pytest -q tests/test_dotfiles_e2e_container.py
|
|
```
|