env
stdlib/extra/env.hk: environment-variable reads.
A pure-Hanki face over the sys native seam, like io/fs. The [env] effect bubbles up through each delegating call. Any program that can touch the environment therefore says so in its signatures and can be refused wholesale with --deny env; env reads are the leading real-world exfiltration target (cloud credentials, CI tokens).
What this module refuses, and why
Reading is here; mutating ambient process state is not, and that is a decision and no gap:
- No
set!. A process-wide environment write is invisible in a signature: it changes what every later call sees, including in other actors, and nothing in the effect row says which variable moved.process.run_with!already takes an explicitMapoverlaid on the child's environment, which does the same work as an argument and no side effect; build it fromvars!when a script wants "everything I have, plus one more". - No
chdir!. The same case: a process-global working directory is the ambient mutable state the language avoids, andprocess.run_in!already takes the directory explicitly. - No
exit!.main!returns anint, and that is the exit path. A mid-scriptexit!skips it, along with anything the caller stacked behind the call. A script that must stop on a condition hascrash!for a genuine fault, and returning frommain!for an ordinary end.
Each of those would be a one-line delegation to write. The reason is recorded here for that reason, and not left to read as an oversight.
The effectful functions have no hermetic test: each is a thin delegation to the sys native seam, and exercising it needs real, non-deterministic OS state that cannot be asserted in the pure stdlib test pack; coverage for those is end-to-end through the CLI integration tests and example programs. _unflatten is the exception and is tested at the bottom: it is ordinary pure logic, and the seam's pairing rule is worth pinning.
get!
def get!(name: string) -> Option<string> [env]
Read the environment variable name. Some(value) when set, None when unset (or, in v0, when the value is not valid UTF-8). @no-doctest: reads the process environment; host-dependent, and cannot assert in a doctest
vars!
def vars!() -> Map<string, string> [env]
Every environment variable, as a map from name to value.
The whole environment in one read, which lets a script inspect it or hand a modified copy to process.run_with!. An entry whose name or value is not valid UTF-8 is skipped, which is get!'s answer for the same case. @no-doctest: reads the process environment; host-dependent, and cannot assert in a doctest
_unflatten
def _unflatten(flat: List<string>, i: int, acc: Map<string, string>) -> Map<string, string>
Rebuild the map from the seam's flattened [name, value, ...] list: the inverse of process._flatten_env, on the same wire form, which lets the two compose. A trailing odd element cannot occur (the seam emits pairs) and is dropped and never guessed at.
cwd!
def cwd!() -> Result<string, sys.FsError> [fs_read]
The process's current working directory.
Err(NotUtf8) when the path is not valid UTF-8, Err(Other) when the OS refuses the read; a directory can be deleted out from under a running process. Charges [fs_read] and not [env]: the answer comes from the filesystem and names a location on it. @no-doctest: reads the live working directory; host-dependent, and cannot assert in a doctest
home!
def home!() -> Option<string> [env]
The current user's home directory, or None when HOME is unset.
No more than a named get!("HOME"), by design: there is no fallback to a password-database lookup. A script that cares about the difference should see None and say what it wants, and one that does not can write home!().unwrap_or("."). @no-doctest: reads the process environment; host-dependent, and cannot assert in a doctest
temp_dir!
def temp_dir!() -> string [env]
The directory for temporary files: TMPDIR when set, else /tmp.
The POSIX rule, written out here and not hidden behind a seam call: the rule is the whole answer on the platforms Hanki targets, and a script that needs to know which of the two it got can read TMPDIR itself. Returns a plain string: there is always an answer. @no-doctest: reads the process environment; host-dependent, and cannot assert in a doctest