Skip to content

Unify what fsfork, confine and fsdiff print - #9

Merged
penberg merged 2 commits into
mainfrom
messages
Nov 3, 2026
Merged

penberg merged 2 commits into
mainfrom
messages

Conversation

@penberg

@penberg penberg commented Nov 3, 2026 •

Copy link
Copy Markdown
Owner

Unifies what the three tools print: errors, warnings, status lines and usage. Each had grown its own shape; now every message is prog: subject: problem, on one line, in lowercase, so that people and agents can read it, and it is still as short as a UNIX tool's.

Case Before After
name taken fsfork: /private/…/.p.x.base: File exists (os error 17) fsfork: p.x: file exists
base left over the same fsfork: p.x: its base .p.x.base is left over; remove it
missing fsfork: nope: No such file or directory (os error 2) fsfork: nope: no such file or directory
not a directory fsfork: /private/…/p/a: not a directory fsfork: p/a: not a directory
not a fork fsdiff: /abs/p: no base at /abs/.p.base; is it a fork? fsdiff: .: not a fork: no .p.base next to it
bad option Unrecognized argument: --bogus, a blank line, Run fsfork --help for more information. fsfork: unrecognized argument: --bogus and the usage line
conflicting options confine: --rm removes a fork, and -d runs the command without one confine: --rm cannot be given with -d, which makes no fork and the usage line
no such command (macOS) sandbox-exec: execvp() of 'nosuchcmd' failed: …, exit 71 confine: nosuchcmd: command not found, exit 127
no Landlock (Linux) confine: confine needs Landlock, … confine: Landlock is not available; it needs Linux 5.19 or later
  • Capitalization. The system's error text is lowercased and loses Rust's (os error N), so that it matches our own text.
  • Paths. A path is shown as it was typed. A path the command made itself, such as a fork's, is shown as it would be typed from the working directory: p.x, or ../turso.1. forked to still gives the full path, because the fork is named only there, and the command then runs somewhere else.
  • Usage errors print the man page's synopsis after the problem: the single most useful line for fixing the arguments.
  • confine looks for the command first. A command that isn't there now exits 127, as the man page says, and is checked before forking, so it leaves no fork. A path with a / in it is looked for in the directory the command runs in.
  • The git fallback warning is printed by the command that forked, so from confine it now says confine: and not fsfork:. It shows only the first line of git's error.

The message formatting lives in fsfork::message, which all three commands share. The lib now depends on argh, for parsing.

Stacked on #7, since it changes the same fsfork.rs. Merge that first.

Not changed

  • --help output is still argh's (Usage:, Options:). It goes to stdout and isn't a message.
  • On Linux, errors from cp during a fork are passed through as cp prints them.

Testing

cargo test and cargo clippy pass on macOS. New tests check exact stderr for usage errors in all three commands, for lowercase system errors with paths as typed, for taken names and left-over bases, and that confine says a missing command is not found, exits 127 and makes no fork. CI covers Linux. The Landlock message hasn't been seen on a machine without Landlock.

@penberg penberg changed the title Make fsfork, confine and fsdiff say what went wrong in one form Unify what fsfork, confine and fsdiff print Nov 3, 2026
Everyone who uses a shell knows that `exit` leaves it, so "exit to come
back" said nothing new, and made the line read unlike `confine`'s.
What the commands said on stderr was in many forms: the system's errors
capitalized, with Rust's "(os error 17)", and ours in lowercase; paths
made absolute, often in the temporary directory, whatever was typed; a
taken name said as the base being there, not the fork; argh's errors with
no command name and a blank line; and conflicting options explained at
length.

Now everything is `prog: subject: problem`, on one line, in lowercase:

    fsfork: p.x: file exists
    fsfork: p.x: its base .p.x.base is left over; remove it
    fsfork: nope: no such file or directory
    fsdiff: .: not a fork: no .p.base next to it
    confine: nosuchcmd: command not found

A path is as it was typed, or, if made by the command, as it would be
typed from the working directory. `forked to` still says where the fork
is in full, as it is said once, and the command then runs elsewhere.
Wrong arguments are said with how to give them:

    fsfork: -n cannot be given with a fork
    usage: fsfork [--no-ignore] [--print] [-n name] [dir [fork]]

`confine` looks for the command before running it, and before forking,
so that one that is not there is said to be not found, exits 127 as the
man page says, and leaves no fork, rather than being reported by
`sandbox-exec` with 71. On Linux, the Landlock error no longer says
"confine" twice. The warning when git cannot tell what is ignored is
said by the command that forked, `confine` too, with the first line of
git's error.

The forms are kept in `fsfork::message`, which the three share.
@penberg
penberg changed the base branch from fsfork-shell to main November 3, 2026 08:52
@penberg
penberg merged commit bcb659e into main Nov 3, 2026
2 checks passed
@penberg
penberg deleted the messages branch November 3, 2026 08:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant