Skip to content

1.16 Step | WriteControlScript + PatchBashrc

Omisen edited this page Aug 15, 2026 · 11 revisions

The last two steps: they install the odoo helper command and close the project's third critical protection (C3) — care for the user's personal files. They live in src/steps/write_control_script.rs and src/steps/patch_bashrc.rs. A port of lib/control_script.sh.

They complete the triad of protections: DB anti-drop (do not destroy) · init hard stop (do not write) · surgical bashrc (do not alter).


Ownership: SUDO_USER, neither odoo nor root

These artifacts belong to whoever ran sudo (SUDO_USER), not to the odoo user and not to root. The command is installed for that user only (~/.local/bin), never globally in /usr/local/bin — a security choice from the original Bash (reduce exposure), preserved. The home is determined with getent passwd <user>, not assumed to be /home/<user>. A missing SUDO_USER is an error.


1 — WriteControlScript (the clean one)

Our own material, in the user's directories. It follows the pattern of the earlier steps.

Phase Behaviour
snapshot do the ~/.scripts/odoo.sh script and the ~/.local/bin/odoo symlink already exist? and did the directories exist? For a named instance both carry the instance name (odoo-cliente-x), so each installation gets a helper of its own instead of overwriting the other's
run always writes odoo.sh (a wrapper over systemctl {start|stop|restart|status} plus dev), chmod +x, creates the symlink if missing, chowns to SUDO_USER. If the script was already there, it is backed up first
undo CreatedByUs → remove; Preexistingput the backup back. The directories only if we created them and they are empty

Tests: ownership == SUDO_USER (never odoo/root), no path under /usr/, a pre-existing script saved and restored.

Why the script is always rewritten. Its contents are generated by us and carry the service name inside (SERVICE_NAME=odoo18). Skipping it because “it already exists” meant that, after reinstalling a different Odoo version, the odoo helper kept driving the old service — and the user only found out when odoo restart did not do what it should.

The PreState here does not protect somebody else's content: it protects the decision to remove it in the undo. But a file with that name could still be somebody else's, and we have no way to know: hence it is set aside before being rewritten, and the undo puts it back — the same treatment as the nginx vhost and odoo.conf.


2 — PatchBashrc (the installer's most delicate mutation)

The .bashrc is the user's most intimate config file: aliases, functions, their own things. The “surgical” promise here means that, if the user rolls back, their file comes back byte for byte as it was — without our line, and without scars.

We add exactly one line, only if it is not already there:

export PATH="$HOME/.local/bin:$PATH"
Phase Behaviour
snapshot does the .bashrc exist? is the line already present? (exact line match, grep -Fqx)
run if absent: back up the file, then append the SINGLE line (never rewrite the whole file)
undo if we added it: restore from the backup (primary) → fall back to removing the exact line

Firm rules (CLAUDE.md)

  • Never rewrite or truncate the whole .bashrc. Only append/remove the single line, or restore the backup.
  • Exact match, never fuzzy: if the user had a different handwritten PATH line, the undo does not touch it.
  • Line already present (Preexisting) → it is not ours → run and undo are no-ops (no duplicates, no removals).
  • If the file did not exist and we created it → the undo removes it.

Why restoring from the backup is the primary method

It brings the file back to its exact pre-modification state, with no risk of removing the wrong line. The exact match (remove_exact_line) is the robust fallback when the backup is not available.


Design notes

  • No step-to-step channel added: sudo_user is read-only input in the Context (from the environment, like os_info), not mutable shared state. The only shared state remains db_created_by_us.
  • control_script_content and remove_exact_line are pure functions, tested separately.
  • Tests protecting C3: a round trip of the .bashrc (after run+undo, identical to the original with aliases and functions intact), line already present → no-op, .bashrc created → removed, and a different PATH line of the user's survives (exact match).

Clone this wiki locally