install.rs

crates/veilvoice-setup/src/install.rs

veilvoice-setup · 594 lines · read the source here · or on GitHub

Put this program somewhere the system can find it.

Reached as veilvoice install on the command line and as the setup tab in the desktop application. Both call the functions below; neither has a copy of them. See the crate documentation for why that mattered enough to move this file out of the binary it used to live in.

Portable is the default, and installing is the exception

VeilVoice runs from wherever it is unpacked. Nothing has to be installed, nothing is written outside the folder unless the user does something that writes outside the folder, and deleting the folder removes it. That is the posture this project has always had and it is not being given up.

This exists because "runs from anywhere" and "I would like to type veilvoice in a terminal" are both reasonable, and the second needs three things a portable folder cannot provide: a stable location, an entry on PATH, and a way for the operating system to list and remove it.

No administrator, and nothing outside the user's own account

Everything here is per-user: %LOCALAPPDATA% on Windows, ~/.local on everything else, and on Windows the HKCU registry rather than HKLM. No elevation is requested, nothing is written to a system directory, and no service is created.

That is a deliberate limit rather than an oversight. A per-user install can be undone by the user who made it, needs no privilege to audit, and cannot break anybody else's account. A machine-wide install would need administrator rights, and the reason to ask for those has to be better than "so the program is on everyone's PATH".

Every change is reversible, and uninstall reverses exactly these

| What | Where | Undone by | |---|---|---| | The binaries | <prefix>/VeilVoice | removing that directory | | PATH entry | HKCU\Environment, or a shell profile line | removing just that entry | | Uninstall entry | HKCU\...\Uninstall\VeilVoice | deleting that key |

The PATH edit is the one that can damage something, so it is the one handled most carefully: the existing value is read, the entry is appended only if absent, and removal takes out that entry and nothing else. A tool that overwrites PATH wholesale has broken a machine, and doing it during an uninstall is worse -- that is the moment somebody is least inclined to check.

Why the registry through reg.exe

The same reason veilvoice-watch reads it that way: this workspace carries #![forbid(unsafe_code)] in every crate, and the Win32 registry API needs unsafe FFI. Shelling out to a system tool keeps that guarantee and costs a subprocess on an operation that runs once. reg.exe is resolved by absolute path -- resolving it by name would search the working directory first, which is finding F-13.

In plain words

Copies VeilVoice somewhere your system can find it, and adds that place to your path so typing veilvoice works.

It installs for you alone and needs no administrator rights. It also registers with the system's own list of installed programs, so removing it works the way removing anything else does.

Running VeilVoice straight out of a folder is a perfectly good way to use it, and the setup screen says so rather than treating portable as something missing.

WHAT THIS FILE CONTAINS

594 lines defining 18 functions (5 public), 2 types and 2 constants. Everything below is read out of the source, so it cannot disagree with the code.

The types it owns.

  • struct Status line 134 · What an installation currently looks like.
  • enum UserPath line 282

What happens when it runs. These are the ways in: public, and nothing else in this file calls them, so they are what an outside caller reaches first.

  • status line 154 · Read the current state without changing anything.
    reaches exe_name, path_contains, prefix
  • install line 484 · Install for this user.
    reaches add_to_path, bin_dir, copy_programs, prefix, register_uninstall, read_user_path, reg_exe, exe_name
  • uninstall line 511 · Remove what install added.
    reaches bin_dir, prefix, remove_from_path, unregister_uninstall, read_user_path, reg_exe

WHAT CALLS WHAT

reg_exe line 94 prefix line 100 bin_dir line 117 status line 154 exe_name line 175 path_contains line 189 copy_programs line 197 add_to_path line 240 read_user_path line 302 add_to_path line 351 register_uninstall line 361 register_uninstall line 402 remove_from_path line 413 remove_from_path line 459 unregister_uninstall line 469 unregister_uninstall line 479 install line 484 uninstall line 511 entry: a way in: public, and nothing in this file calls it api: public, and also used inside this file helper: private to this file dashed: a call that goes back up, or across a wrapped rank The functions this file defines, and the calls between them. An edge means the callee's name appears, called, inside the caller's body. This is a syntactic reading, not a type-resolved one.

The functions this file defines, and the calls between them. An edge means the callee's name appears, called, inside the caller's body. This is a syntactic reading, not a type-resolved one.

The same graph as Mermaid source
%%{init: {"theme":"base","themeVariables":{"background":"#1a1b26","primaryColor":"#1f2335","primaryTextColor":"#c0caf5","primaryBorderColor":"#7aa2f7","secondaryColor":"#16161e","tertiaryColor":"#16161e","lineColor":"#737aa2","textColor":"#c0caf5","mainBkg":"#1f2335","nodeBorder":"#7aa2f7","clusterBkg":"#16161e","clusterBorder":"#2f3549","fontFamily":"ui-monospace, SFMono-Regular, Consolas, monospace","fontSize":"14px"}}}%%
flowchart TD
    n_reg_exe["reg_exe<br/>line 94"]
    n_prefix["prefix<br/>line 100"]
    n_bin_dir["bin_dir<br/>line 117"]
    n_status(["status<br/>line 154"])
    n_exe_name["exe_name<br/>line 175"]
    n_path_contains["path_contains<br/>line 189"]
    n_copy_programs["copy_programs<br/>line 197"]
    n_add_to_path["add_to_path<br/>line 240"]
    n_read_user_path["read_user_path<br/>line 302"]
    n_add_to_path["add_to_path<br/>line 351"]
    n_register_uninstall["register_uninstall<br/>line 361"]
    n_register_uninstall["register_uninstall<br/>line 402"]
    n_remove_from_path["remove_from_path<br/>line 413"]
    n_remove_from_path["remove_from_path<br/>line 459"]
    n_unregister_uninstall["unregister_uninstall<br/>line 469"]
    n_unregister_uninstall["unregister_uninstall<br/>line 479"]
    n_install(["install<br/>line 484"])
    n_uninstall(["uninstall<br/>line 511"])
    n_add_to_path --> n_read_user_path
    n_add_to_path --> n_reg_exe
    n_bin_dir --> n_prefix
    n_copy_programs --> n_exe_name
    n_install --> n_add_to_path
    n_install --> n_bin_dir
    n_install --> n_copy_programs
    n_install --> n_prefix
    n_install --> n_register_uninstall
    n_read_user_path --> n_reg_exe
    n_register_uninstall --> n_exe_name
    n_register_uninstall --> n_reg_exe
    n_remove_from_path --> n_read_user_path
    n_remove_from_path --> n_reg_exe
    n_status --> n_exe_name
    n_status --> n_path_contains
    n_status --> n_prefix
    n_uninstall --> n_bin_dir
    n_uninstall --> n_prefix
    n_uninstall --> n_remove_from_path
    n_uninstall --> n_unregister_uninstall
    n_unregister_uninstall --> n_reg_exe
    click n_reg_exe href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L94" "open the source"
    click n_prefix href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L100" "open the source"
    click n_bin_dir href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L117" "open the source"
    click n_status href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L154" "open the source"
    click n_exe_name href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L175" "open the source"
    click n_path_contains href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L189" "open the source"
    click n_copy_programs href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L197" "open the source"
    click n_add_to_path href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L240" "open the source"
    click n_read_user_path href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L302" "open the source"
    click n_add_to_path href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L351" "open the source"
    click n_register_uninstall href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L361" "open the source"
    click n_register_uninstall href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L402" "open the source"
    click n_remove_from_path href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L413" "open the source"
    click n_remove_from_path href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L459" "open the source"
    click n_unregister_uninstall href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L469" "open the source"
    click n_unregister_uninstall href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L479" "open the source"
    click n_install href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L484" "open the source"
    click n_uninstall href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-setup/src/install.rs#L511" "open the source"
    classDef entry fill:#1f2335,stroke:#7aa2f7,color:#c0caf5
    class n_status,n_install,n_uninstall entry
    classDef api fill:#1f2335,stroke:#7dcfff,color:#c0caf5
    class n_prefix,n_bin_dir api
    classDef helper fill:#1f2335,stroke:#bb9af7,color:#c0caf5
    class n_reg_exe,n_exe_name,n_path_contains,n_copy_programs,n_add_to_path,n_read_user_path,n_add_to_path,n_register_uninstall,n_register_uninstall,n_remove_from_path,n_remove_from_path,n_unregister_uninstall,n_unregister_uninstall helper

This site loads no third-party script, so it cannot run Mermaid; the diagram above is the same nodes and edges drawn by the generator instead. GitHub renders the source below directly.

ITEMS

ItemLineDocumentation
NAME pub const78The name of the directory and the uninstall entry.
PROGRAMS const85Files that make up an installation, if they are beside the running binary.
reg_exe fn94reg.exe, by absolute path.
prefix pub fn100Where an installation goes, for this user only.
bin_dir pub fn117The directory a PATH entry should point at.
Status pub struct134What an installation currently looks like.
status pub fn154Read the current state without changing anything.
exe_name fn175A program's file name on this platform.
path_contains fn189Is dir already on this user's PATH?
copy_programs fn197Copy the binaries into place.
add_to_path fn240Add dir to the user's PATH, if it is not there already.
UserPath enum282
read_user_path fn302Read this user's PATH, distinguishing "not set" from "could not tell".
add_to_path fn351The Unix half: report that nothing was written, because nothing was.
register_uninstall fn361Register with Add/Remove Programs, so the system can list and remove it.
register_uninstall fn402The Unix half: nothing to register.
remove_from_path fn413Take this directory back out of the user's PATH, leaving the rest of it exactly as it was.
remove_from_path fn459The Unix half: nothing was written to a profile, so nothing is taken out.
unregister_uninstall fn469Take the Add/Remove Programs entry away again.
unregister_uninstall fn479The Unix half: nothing was registered, so nothing is unregistered.
install pub fn484Install for this user.
uninstall pub fn511Remove what install added.