procman 0.3.0

A foreman-like process supervisor
# procman

[![crates.io](https://img.shields.io/crates/v/procman.svg)](https://crates.io/crates/procman)

A foreman-like process supervisor written in Rust. Reads a `Procfile`, spawns all listed commands, multiplexes their output with name prefixes, and tears everything down cleanly when any child exits or a signal arrives.

## Usage

```
cargo install --path .
```

### `procman run` — run all Procfile commands

```bash
procman run              # uses ./Procfile
procman run myapp.proc   # custom Procfile path
```

Bare `procman` with no subcommand is equivalent to `procman run`.

### `procman serve` — accept dynamic commands via a FIFO

```bash
procman serve /tmp/myapp.fifo &
```

Runs all Procfile commands and listens on a named FIFO for dynamically added commands. The FIFO is created automatically and removed on exit.

### `procman start` — send a command to a running server

```bash
procman start /tmp/myapp.fifo "redis-server --port 6380"
```

Opens the FIFO for writing and sends the command line. Fails immediately if no server is listening. The server parses the command using the same rules as Procfile entries (including env var substitution).

### Scripted service bringup

The `serve`/`start` pattern enables imperative orchestration — start a supervisor, wait for dependencies to become healthy, then add dependent services:

```bash
procman serve /tmp/myapp.fifo &
while ! curl -sf http://localhost:8080/health; do sleep 1; done
procman start /tmp/myapp.fifo "worker process-jobs"
```

An advisory `flock` on the Procfile prevents multiple instances from managing the same file simultaneously.

## Procfile Format

```
# Global environment variables (before any command lines)
DATABASE_URL=postgres://localhost/myapp
PORT=3000

# Commands — one per line
web serve --port $PORT
worker process-jobs --db $DATABASE_URL
```

- Lines starting with `#` are comments.
- Trailing `\` joins continuation lines.
- `KEY=value` lines before the first command set global environment variables.
- Inline `KEY=value` tokens at the start of a command line set per-command env vars. Values may be quoted: `FOO="hello world" myprogram`.
- `$VAR` references are substituted from the merged environment (inherited + global + inline). Undefined variables are a hard error — nothing is spawned.
- Process names are derived from the program basename. Duplicates get `.1`, `.2` suffixes.
- **Note:** Unlike a POSIX shell, inline env vars are passed to the child process *and* substituted into the command line. `FOO="abc" echo $FOO` will print `abc`, whereas a shell would expand `$FOO` before the assignment takes effect and print an empty line.

## Behavior

- All children share a process group.
- stderr is merged into stdout per-process.
- Output is prefixed with the process name, right-aligned and padded.
- Per-process logs are written to `./logs/<name>.log`.
- On SIGINT or SIGTERM, all children receive SIGTERM. After a 2-second grace period, remaining processes are sent SIGKILL.
- procman exits with the first child's exit code.

## License

MIT