working version
This commit is contained in:
318
README.md
318
README.md
@@ -1,24 +1,18 @@
|
||||
# flow
|
||||
|
||||
`flow` is a CLI for managing development instances, containers, dotfiles, bootstrap profiles, and
|
||||
binary packages.
|
||||
|
||||
This repository contains the Python implementation of the tool and its command modules.
|
||||
`flow` is a CLI for managing development instances, containers, dotfiles, and host bootstrap.
|
||||
|
||||
## What is implemented
|
||||
|
||||
- Instance access via `flow enter`
|
||||
- Container lifecycle commands under `flow dev` (`create`, `exec`, `connect`, `list`, `stop`,
|
||||
`remove`, `respawn`)
|
||||
- Dotfiles management (`dotfiles` / `dot`)
|
||||
- Bootstrap planning and execution (`bootstrap` / `setup` / `provision`)
|
||||
- Binary package installation from manifest definitions (`package` / `pkg`)
|
||||
- Multi-repo sync checks (`sync`)
|
||||
- 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
|
||||
|
||||
Build and install a standalone binary (no pip install required for use):
|
||||
|
||||
```bash
|
||||
make build
|
||||
make install-local
|
||||
@@ -26,241 +20,163 @@ make install-local
|
||||
|
||||
This installs `flow` to `~/.local/bin/flow`.
|
||||
|
||||
## Configuration
|
||||
## Core behavior
|
||||
|
||||
`flow` uses XDG paths by default:
|
||||
### Security model
|
||||
|
||||
- `~/.config/devflow/config`
|
||||
- `~/.config/devflow/manifest.yaml`
|
||||
- `~/.local/share/devflow/`
|
||||
- `~/.local/state/devflow/`
|
||||
- `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` (INI)
|
||||
### Config location and merge rules
|
||||
|
||||
```ini
|
||||
[repository]
|
||||
dotfiles_url = git@github.com:you/dotfiles.git
|
||||
dotfiles_branch = main
|
||||
`flow` loads all YAML files from:
|
||||
|
||||
[paths]
|
||||
projects_dir = ~/projects
|
||||
1. `~/.local/share/flow/dotfiles/_shared/flow/.config/flow/` (self-hosted, if present)
|
||||
2. `~/.config/flow/` (local fallback)
|
||||
|
||||
[defaults]
|
||||
container_registry = registry.tomastm.com
|
||||
container_tag = latest
|
||||
tmux_session = default
|
||||
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.
|
||||
|
||||
[targets]
|
||||
# Format A: namespace = platform ssh_host [ssh_identity]
|
||||
personal = orb personal.orb
|
||||
### Dotfiles layout (flat with reserved dirs)
|
||||
|
||||
# Format B: namespace@platform = ssh_host [ssh_identity]
|
||||
work@ec2 = work.internal ~/.ssh/id_work
|
||||
Inside your dotfiles repo root:
|
||||
|
||||
```text
|
||||
_shared/
|
||||
flow/
|
||||
.config/flow/
|
||||
config.yaml
|
||||
packages.yaml
|
||||
profiles.yaml
|
||||
git/
|
||||
.gitconfig
|
||||
_root/
|
||||
general/
|
||||
etc/
|
||||
hostname
|
||||
linux-auto/
|
||||
nvim/
|
||||
.config/nvim/init.lua
|
||||
```
|
||||
|
||||
## Manifest format
|
||||
- `_shared/`: linked for all profiles
|
||||
- `_root/`: linked to absolute paths (via sudo), e.g. `_root/etc/hostname -> /etc/hostname`
|
||||
- every other directory at this level is a profile name
|
||||
- when `_shared` and profile conflict on the same target file, profile wins
|
||||
|
||||
The manifest is YAML with these top-level sections used by the current code:
|
||||
## Manifest model
|
||||
|
||||
- `profiles` for bootstrap profiles
|
||||
- `binaries` for package definitions
|
||||
- `package-map` for cross-package-manager name mapping
|
||||
Top-level keys:
|
||||
|
||||
`environments` is no longer supported.
|
||||
- `profiles`
|
||||
- `packages`
|
||||
- optional global settings like `repository`, `paths`, `defaults`, `targets`
|
||||
|
||||
Example:
|
||||
`environments` is not supported.
|
||||
|
||||
### Packages (unified)
|
||||
|
||||
```yaml
|
||||
profiles:
|
||||
linux-vm:
|
||||
os: linux
|
||||
hostname: "$HOSTNAME"
|
||||
shell: zsh
|
||||
locale: en_US.UTF-8
|
||||
requires: [HOSTNAME]
|
||||
packages:
|
||||
standard: [git, tmux, zsh, fd]
|
||||
binary: [neovim]
|
||||
ssh_keygen:
|
||||
- type: ed25519
|
||||
comment: "$USER@$HOSTNAME"
|
||||
runcmd:
|
||||
- mkdir -p ~/projects
|
||||
packages:
|
||||
- name: fd
|
||||
type: pkg
|
||||
sources:
|
||||
apt: fd-find
|
||||
dnf: fd-find
|
||||
brew: fd
|
||||
|
||||
package-map:
|
||||
fd:
|
||||
apt: fd-find
|
||||
dnf: fd-find
|
||||
brew: fd
|
||||
- name: wezterm
|
||||
type: cask
|
||||
sources:
|
||||
brew: wezterm
|
||||
|
||||
binaries:
|
||||
neovim:
|
||||
- name: neovim
|
||||
type: binary
|
||||
source: github:neovim/neovim
|
||||
version: "0.10.4"
|
||||
asset-pattern: "nvim-{{os}}-{{arch}}.tar.gz"
|
||||
platform-map:
|
||||
linux-amd64: { os: linux, arch: x86_64 }
|
||||
linux-x64: { os: linux, arch: x64 }
|
||||
linux-arm64: { os: linux, arch: arm64 }
|
||||
macos-arm64: { os: macos, arch: arm64 }
|
||||
install-script: |
|
||||
curl -fL "{{downloadUrl}}" -o /tmp/nvim.tar.gz
|
||||
tar -xzf /tmp/nvim.tar.gz -C /tmp
|
||||
rm -rf ~/.local/bin/nvim
|
||||
cp /tmp/nvim-*/bin/nvim ~/.local/bin/nvim
|
||||
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 + `_root`)
|
||||
- `post-link` hook (runs after symlink phase)
|
||||
- config skip patterns:
|
||||
- package names (e.g. `nvim`)
|
||||
- `_shared`
|
||||
- `_profile`
|
||||
- `_root`
|
||||
|
||||
## Command overview
|
||||
|
||||
### Enter instances
|
||||
|
||||
```bash
|
||||
flow enter personal@orb
|
||||
flow enter root@personal@orb
|
||||
flow enter personal@orb --dry-run
|
||||
```
|
||||
|
||||
If your local terminal uses `xterm-ghostty` or `wezterm`, `flow enter` shows a terminfo warning and
|
||||
a manual fix command before connecting. `flow` never installs terminfo on the target automatically.
|
||||
|
||||
### Containers
|
||||
|
||||
```bash
|
||||
flow dev create api -i tm0/node -p ~/projects/api
|
||||
flow dev connect api
|
||||
flow dev exec api -- npm test
|
||||
flow dev list
|
||||
flow dev stop api
|
||||
flow dev remove api
|
||||
```
|
||||
|
||||
### Dotfiles
|
||||
|
||||
```bash
|
||||
flow dotfiles init --repo git@github.com:you/dotfiles.git
|
||||
flow dotfiles link
|
||||
flow dotfiles link --profile linux-auto
|
||||
flow dotfiles status
|
||||
flow dotfiles relink
|
||||
flow dotfiles clean --dry-run
|
||||
flow dotfiles repo status
|
||||
flow dotfiles repo pull --relink
|
||||
flow dotfiles repo push
|
||||
```
|
||||
|
||||
### Bootstrap
|
||||
|
||||
```bash
|
||||
flow bootstrap list
|
||||
flow bootstrap show linux-vm
|
||||
flow bootstrap packages --profile linux-vm
|
||||
flow bootstrap packages --profile linux-vm --resolved
|
||||
flow bootstrap run --profile linux-vm --var HOSTNAME=devbox
|
||||
flow bootstrap run --profile linux-vm --dry-run
|
||||
```
|
||||
flow bootstrap show linux-auto
|
||||
flow bootstrap run --profile linux-auto --var USER_EMAIL=you@example.com
|
||||
|
||||
`flow bootstrap` auto-detects the package manager (`brew`, `apt`, `dnf`) when
|
||||
`package-manager` is not set in a profile.
|
||||
|
||||
### Packages
|
||||
|
||||
```bash
|
||||
flow package install neovim
|
||||
flow package list
|
||||
flow package list --all
|
||||
flow package remove neovim
|
||||
```
|
||||
|
||||
### Sync
|
||||
|
||||
```bash
|
||||
flow sync check
|
||||
flow sync check --no-fetch
|
||||
flow sync fetch
|
||||
flow sync summary
|
||||
```
|
||||
|
||||
### Completion
|
||||
|
||||
```bash
|
||||
flow completion install-zsh
|
||||
flow completion zsh
|
||||
```
|
||||
|
||||
## Self-hosted config priority
|
||||
|
||||
When present, `flow` prefers config from a linked dotfiles package:
|
||||
|
||||
1. `~/.local/share/devflow/dotfiles/flow/.config/flow/config`
|
||||
2. `~/.config/devflow/config`
|
||||
|
||||
And for manifest:
|
||||
|
||||
1. `~/.local/share/devflow/dotfiles/flow/.config/flow/manifest.yaml`
|
||||
2. `~/.config/devflow/manifest.yaml`
|
||||
|
||||
Passing an explicit file path to internal loaders bypasses this cascade.
|
||||
|
||||
## State format policy
|
||||
|
||||
`flow` currently supports only the v2 dotfiles link state format (`linked.json`). Older state
|
||||
formats are intentionally not supported.
|
||||
|
||||
## CLI behavior
|
||||
|
||||
- User errors return non-zero exit codes.
|
||||
- External command failures are surfaced as concise one-line errors (no traceback spam).
|
||||
- `Ctrl+C` exits with code `130`.
|
||||
|
||||
## Zsh completion
|
||||
|
||||
Recommended one-shot install:
|
||||
|
||||
```bash
|
||||
flow completion install-zsh
|
||||
```
|
||||
|
||||
Manual install (equivalent):
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.zsh/completions
|
||||
flow completion zsh > ~/.zsh/completions/_flow
|
||||
```
|
||||
|
||||
Then ensure your `.zshrc` includes:
|
||||
|
||||
```bash
|
||||
fpath=(~/.zsh/completions $fpath)
|
||||
autoload -Uz compinit && compinit
|
||||
```
|
||||
|
||||
Completion is dynamic and pulls values from your current config/manifest/state (for example
|
||||
bootstrap profiles, package names, dotfiles packages, and configured `enter` targets).
|
||||
|
||||
## Development
|
||||
|
||||
Binary build (maintainers):
|
||||
|
||||
```bash
|
||||
python3 -m pip install pyinstaller
|
||||
make build
|
||||
make install-local
|
||||
```
|
||||
|
||||
Useful targets:
|
||||
|
||||
```bash
|
||||
make clean
|
||||
```
|
||||
|
||||
Run tests:
|
||||
|
||||
```bash
|
||||
python3 -m pytest
|
||||
```
|
||||
|
||||
Local development setup:
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
.venv/bin/pip install -e ".[dev]"
|
||||
.venv/bin/pytest
|
||||
python3 -m pytest
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user