viv lock
Lock file maintenance: translate an existing composer.lock into
viv.lock without re-solving, write composer.lock back from viv.lock,
or merge a lock as a git merge driver.
Usage
Lock file maintenance: translate an existing `composer.lock` into chapter 1's `viv.lock` (#273), without re-solving, or merge one as a git merge driver (#275)
Usage: viv lock [OPTIONS] <COMMAND>
Commands:
convert Translate an existing `composer.lock` into `viv.lock` (#273): reads `DIR/composer.lock` and `DIR/composer.json`, and writes `DIR/viv.lock`, without re-solving anything
export Write `DIR/composer.lock` from `DIR/viv.lock` and `DIR/composer.json` (#344), through the same `lock_writer::write` a solve feeds: a team that stops committing `composer.lock` regenerates it this way in CI or on checkout
merge A git merge driver for `composer.lock`/`viv.lock` (#275): merges the three inputs by name-keyed package record instead of by text line, writes the result over `<ours>`, and exits 1 when a divergent name's own re-solve doesn't finish (a human decision then, not this chunk's job — see `docs/research.md` chapter 1). Git's merge-driver convention: `%O %A %B` (`git help gitattributes`'s "Defining a custom merge driver")
help Print this message or the help of the given subcommand(s)
Options:
-v, --verbose Raise logging to debug
--cache-dir <CACHE_DIR> Store location (default `$XDG_CACHE_HOME/vivace`, or `~/.cache/vivace`)
--offline Fail fast on any request instead of connecting: install errors, naming every package not already in the store; update solves from cached repository metadata only, erroring on an uncached package. Also set by `COMPOSER_DISABLE_NETWORK` (any value but unset, empty or `0`; Composer's own git-priming `prime` value is not special-cased here, since neither `install` nor `update` touch a git source)
-h, --help Print help
viv lock convert
Reads DIR/composer.lock and DIR/composer.json, and writes
DIR/viv.lock, without re-solving anything. --stdout prints the result
instead of writing it.
Translate an existing `composer.lock` into `viv.lock` (#273): reads `DIR/composer.lock` and `DIR/composer.json`, and writes `DIR/viv.lock`, without re-solving anything
Usage: viv lock convert [OPTIONS]
Options:
-d, --project-dir <PROJECT_DIR> Project directory holding composer.json and composer.lock [default: .]
-v, --verbose Raise logging to debug
--cache-dir <CACHE_DIR> Store location (default `$XDG_CACHE_HOME/vivace`, or `~/.cache/vivace`)
--stdout Print the translated lock to stdout instead of writing `viv.lock` to disk
--offline Fail fast on any request instead of connecting: install errors, naming every package not already in the store; update solves from cached repository metadata only, erroring on an uncached package. Also set by `COMPOSER_DISABLE_NETWORK` (any value but unset, empty or `0`; Composer's own git-priming `prime` value is not special-cased here, since neither `install` nor `update` touch a git source)
-h, --help Print help
viv lock export
Writes DIR/composer.lock from DIR/viv.lock and DIR/composer.json,
through the same writer a solve feeds. When composer.json names
isolated plugins in extra.viv.isolate, the export adds that map to
composer.lock as a top-level extra.viv.isolate key, which Composer
ignores. --check writes nothing and reports whether the existing
composer.lock already matches.
Write `DIR/composer.lock` from `DIR/viv.lock` and `DIR/composer.json` (#344), through the same `lock_writer::write` a solve feeds: a team that stops committing `composer.lock` regenerates it this way in CI or on checkout
Usage: viv lock export [OPTIONS]
Options:
-d, --project-dir <PROJECT_DIR> Project directory holding viv.lock and composer.json [default: .]
-v, --verbose Raise logging to debug
--cache-dir <CACHE_DIR> Store location (default `$XDG_CACHE_HOME/vivace`, or `~/.cache/vivace`)
--check Write nothing; exit 0 when the existing composer.lock already equals the export, 1 with a one-line diff summary otherwise
--offline Fail fast on any request instead of connecting: install errors, naming every package not already in the store; update solves from cached repository metadata only, erroring on an uncached package. Also set by `COMPOSER_DISABLE_NETWORK` (any value but unset, empty or `0`; Composer's own git-priming `prime` value is not special-cased here, since neither `install` nor `update` touch a git source)
-h, --help Print help
viv lock merge
A git merge driver for composer.lock/viv.lock: merges the three inputs
(%O %A %B, see git help gitattributes) by name-keyed package record
instead of by text line, and writes the result over ours. Configure it as
a merge= driver in .gitattributes and git config, not run by hand
day-to-day.
A git merge driver for `composer.lock`/`viv.lock` (#275): merges the three inputs by name-keyed package record instead of by text line, writes the result over `<ours>`, and exits 1 when a divergent name's own re-solve doesn't finish (a human decision then, not this chunk's job — see `docs/research.md` chapter 1). Git's merge-driver convention: `%O %A %B` (`git help gitattributes`'s "Defining a custom merge driver")
Usage: viv lock merge [OPTIONS] <BASE> <OURS> <THEIRS>
Arguments:
<BASE>
The common ancestor's version of the lock (`%O`)
<OURS>
This side's version (`%A`); overwritten with the merge result
<THEIRS>
The other side's version (`%B`)
Options:
-d, --project-dir <PROJECT_DIR>
Project directory whose composer.json supplies the root requirements and the repositories a divergent name's re-solve fetches against; for composer.lock, also the `content-hash`, and for viv.lock (#295), the sibling composer.lock the pinned set's `require` is read off
[default: .]
-v, --verbose
Raise logging to debug
--cache-dir <CACHE_DIR>
Store location (default `$XDG_CACHE_HOME/vivace`, or `~/.cache/vivace`)
--no-resolve
Skip the re-solve and go straight to chunk 1's conflict markers for any divergent name, in either format. For tests and offline use, where a network re-solve isn't wanted at all
--as-of <TIMESTAMP>
Resolve the divergent closure as the registry stood at this RFC 3339 timestamp: a released version Packagist's own `time` puts later than this is dropped from the pool, so a version that did not exist yet cannot be chosen. `dev-*` branch versions are never filtered this way — Packagist serves only a branch's current head, not a historical revision of one, so they always resolve to today's
--offline
Fail fast on any request instead of connecting: install errors, naming every package not already in the store; update solves from cached repository metadata only, erroring on an uncached package. Also set by `COMPOSER_DISABLE_NETWORK` (any value but unset, empty or `0`; Composer's own git-priming `prime` value is not special-cased here, since neither `install` nor `update` touch a git source)
--max-scope <MAX_SCOPE>
How far a divergent name's re-solve may escalate before giving up on markers (#296): `closure` is chunk 2's original scope (the divergent names plus their own locked closure), `dependents` adds pinned packages that directly require one of those, `seeded` (the default) is a full solve that prefers every non-divergent locked version but pins none of them hard
Possible values:
- closure: Rung 1: the divergent names plus their own locked transitive closure, everything else pinned hard (chunk 2's original behaviour)
- dependents: Rung 2: rung 1 plus any pinned package that directly requires a name in the closure
- seeded: Rung 3: a full solve over the merged manifest with every non-divergent locked version passed as `--minimal-changes`'s `preferred` pin set. Never a plain update: nothing is pinned hard, but a satisfying solution that keeps a preferred version is always preferred over one that doesn't
[default: seeded]
--offline-rung
Try one further, offline rung (#314) once the registry escalation above has already failed at every rung `--max-scope` allowed: one parent's own pinned record per divergent name (`ours` first, then `theirs`), checked against the two locks' own `require`/`conflict`/`replace`/`provide`/platform data with no registry fetch at all. Only ever a last resort before conflict markers, so it can never disagree with a registry answer that also finished — it only ever fires when there wasn't one. Off by default; a no-op for `viv.lock`, whose records carry none of the fields the check needs
-h, --help
Print help (see a summary with '-h')
Reads and writes
- Reads:
composer.json,composer.lock,viv.lock;mergealso reads the three merge inputs and, unless--no-resolve, fetches repository metadata over the network for a divergent package's re-solve. - Writes:
viv.lock(convert),composer.lock(export), theoursfile in place (merge).
Exit codes
0— converted, exported, or merged cleanly (includingexport --checkfinding the file already up to date).1—export --checkfinding a difference, or a divergent name's re-solve inmergenot finishing (conflict markers were written instead), or a filesystem error.2— as update, whenmerge's re-solve is a genuine dependency-resolution failure rather than a divergent-name conflict.