feat(installer): implement Phase 3 — the patch tier
Some checks failed
PR Checks / rust-gates (pull_request) Failing after 46s
Some checks failed
PR Checks / rust-gates (pull_request) Failing after 46s
Two features need edits to stock ServUO sources, because the events they depend on do not exist. This adds the rung ladder of PLAN.md §2.2.1, the unsupported-version path of §2.2.2, and the record and cache Phase 4 will read. Three decisions were not settled by the plan: * The engine is fully native, with no `git`. §2.2.1 wrote rung 1 as "apply verbatim with git apply", but §1 chose the release tarball specifically so there would be no git on the shard host, and rung 2 needs a native applier regardless. Rung 1 keeps its distinct, stronger verdict — the whole file reproduced the diff's `index` pre-image, computed as a git blob SHA1 in process — while the write goes through the same code path as rung 2. On the real trees here that is not academic: the shipped .patch files are CRLF in a Windows checkout and two of their three targets are LF, so `git apply` refuses patches this applies correctly. * Per-patch metadata is declared by the release, with a built-in fallback. Which patches form one all-or-nothing unit, which companion .cs follows which, whether a CORE rebuild is needed and what declining costs are not derivable from a diff. servuo-plugins now declares them; overlay v0.1.1 is in the current bundle and declares nothing, so a built-in copy stands in for it. A checked-in fixture of the release workflow's own jq output asserts the two descriptions are identical, so the repos cannot drift quietly. * Pre-images are cached in the state directory. The tier edits files the operator owns, and `/etc/runicgateway/patches/originals/` is what turns "here are the hunks we added" into a revert anyone can verify — kept out of the ServUO tree, which uninstall has promised never to clean up. Everything else follows §2.2.1: exact matching with only line-ending and trailing-whitespace normalization, exactly one occurrence or it fails, all-or-nothing per patch file and again per feature, and a byte-preserving splice so nothing outside a hunk can be reformatted. Verified against the ServUO 57.4 tree on this machine across four scratch roots: a hand-patched tree (rung 0), a reverse-applied stock one (rung 1 on the real EventSink.cs, its blob matching the patch's declared pre-image), a mixed-rung feature, a tree with edits inside two patched regions (rung 3 — nothing written, nothing held back applied, no companions copied), and a non-57.4 tree both with and without the extra consent flag. Three consecutive runs left install.json byte-identical and the cached pre-image still pre-patch. Three reporting defects the live runs caught are fixed with tests: a dry run and a held-back patch both claimed to be "applied", the core-rebuild warning fired when nothing had been written and named a Scripts file as core, and a declined tier announced the loss of features install.json showed as applied. Refused patches are now cached too, since the refusal message names that path. Refs: docs/installer/PLAN.md §2.2, §5 Phase 3 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
16
src/cli.rs
16
src/cli.rs
@@ -2,20 +2,20 @@
|
||||
//!
|
||||
//! The shape here is not invented: `docs/installer/INSTALL.md` §2 was written before the binary and
|
||||
//! fixes every command and flag an operator can type. This module parses that surface *whole*, even
|
||||
//! though Phase 1 implements only part of it — a parser written once against the published contract
|
||||
//! cannot drift from it, and a flag that belongs to a later phase gets an explicit "not in this
|
||||
//! build" notice at the point where it would have taken effect (see `install.rs`). The one thing it
|
||||
//! must never do is accept `--patches` silently, which would let an operator believe stock ServUO
|
||||
//! files were touched when nothing was.
|
||||
//! where a later phase implements it — a parser written once against the published contract cannot
|
||||
//! drift from it, and a flag belonging to an unbuilt phase gets an explicit notice at the point
|
||||
//! where it would have taken effect (see `install.rs`). The tri-state on `--patches` is the part
|
||||
//! that carries weight: "not mentioned" has to stay distinguishable from "explicitly declined",
|
||||
//! because only the first may prompt and only an explicit yes may edit a stock ServUO file.
|
||||
//!
|
||||
//! Hand-rolled, like `link/sidecar/src/cli.rs`: a handful of flags, no completions, no subcommand
|
||||
//! trees. A parsing crate would be larger than the code it replaced.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
/// The verb. `Install` is the only one Phase 1 implements; the rest parse so that running them
|
||||
/// reports which phase they arrive in rather than "unrecognized argument", which would read as a
|
||||
/// typo rather than as an unfinished tool.
|
||||
/// The verb. `Install` is the only one built so far; the rest parse so that running them reports
|
||||
/// which phase they arrive in rather than "unrecognized argument", which would read as a typo
|
||||
/// rather than as an unfinished tool.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Command {
|
||||
Install,
|
||||
|
||||
Reference in New Issue
Block a user