Skip to content

List a box's own commands, and let them take a per-box name on the host - #238

Open
kacperpaczos wants to merge 3 commits into
Dvlv:masterfrom
kacperpaczos:feat/box-commands
Open

List a box's own commands, and let them take a per-box name on the host#238
kacperpaczos wants to merge 3 commits into
Dvlv:masterfrom
kacperpaczos:feat/box-commands

Conversation

@kacperpaczos

Copy link
Copy Markdown
Contributor

Fixes #237. Builds on #236 (the chooser machinery it reuses); the diff here is only what is new on top of it.

A Commands section

The Applications page lists .desktop files, so a box holding only a command line tool looks empty. There is now a Commands group listing what the box itself has, each row with an Add to Terminal button that opens the add-command dialog with the name filled in.

What is scanned is a deliberate choice rather than a guess, and I checked each part on a real machine:

  • /usr/local/bin and /opt/*/bin inside the container: container-local, and in practice exactly what was installed by hand.
  • $HOME/.local/bin only when the box has its own home. In a default box that path is the shared host home, so scanning it would list the host's own tools as though they lived in the box - the check is "$HOME" != "${DISTROBOX_HOST_HOME:-$HOME}".
  • /usr/bin is left out. A freshly created box already shows 272 added entries there, because distrobox's first-run setup installs a pile of packages; nothing distinguishes a user install from that.

A host-side name

distrobox-export --bin always keeps the command's own name, so the same tool in two boxes can only fight over one entry on the host. The dialog gains a Name on host field (blank means "same as the command"). When it differs a chooser is written even with nothing in the way, since export cannot rename - and a chooser with a single target runs it without asking, so claude-work behaves like a normal command.

That required the generated script to separate two things it used to conflate: the host-facing name (the file, used in messages) and the command run inside the box. The marker records both (command= and a new cmd=), and the existing # distrobox_binary / # name: markers are unchanged.

Documentation

docs/tips.md gains a section on running the same application under separate profiles: give each box its own home directory, and the box keeps its own settings and logins while the host's files stay reachable and exports still land in the host's menu and PATH (distrobox-export resolves host_home from DISTROBOX_HOST_HOME, verified). The new-box form now explains the Home Directory field where the choice is actually made, instead of leaving it as a bare path input.

Screenshots

commands section
host name field

Testing

cargo test: 22 pass (4 new - the scan's parsing keeps one entry per name and drops find's error lines, relative junk and names that fail validation; the generated script runs the in-box command under its host name; the menu is guarded by the target count).

End to end on a virtual display with an isolated $HOME and a stub distrobox: the Commands section lists what the stub reports; adding claude as claude-praca writes a chooser whose marker reads command=claude-praca cmd=claude, and running it - through a pipe and through a pty - goes straight to distrobox enter second -- claude with no prompt. Adding the same host name from a second box merges it (boxes=second,fakebox, a # name: line each), and the pty run then shows the menu and dispatches to the chosen box.

One limitation I did not hide: a chooser holds one in-box command for all its targets, so boxes where the tool has different names would need separate host names. Say the word and I will make cmd= per target instead.

BoxBuddy could export an application to the host menu, but not a command
to the host terminal, and a command that exists both on the host and in a
box could only shadow one with the other.

The Exported Binaries section gains an "Add Command…" button. The command
is resolved inside the box first; if nothing on the host answers to that
name it is a plain `distrobox-export --bin`, exactly as before. When the
host already has one - its own binary, an earlier distrobox export, or a
chooser BoxBuddy wrote before - the dialog offers to replace it with a
chooser: a small self-contained bash script in ~/.local/bin that asks, at
invocation time, which one to run.

The chooser prints a numbered menu on stderr and reads the answer from
/dev/tty, so it never eats the program's own stdin. Scripts and pipes must
not block on a prompt, so with no terminal it runs the first target
silently, and BOXBUDDY_DISPATCH=host|<box> picks one outright. Adding the
same command from another box folds that box into the existing chooser
rather than replacing it.

The file carries distrobox's own `# distrobox_binary` and `# name: <box>`
markers next to BoxBuddy's, so `distrobox-export --list-binaries` still
finds the command and `--delete` still removes it; without them distrobox
would quietly lose sight of a command it had exported. The binaries list
skips entries that are choosers so they are not listed twice.

Nothing else knows about the chooser: the file is the whole state, and it
keeps working if BoxBuddy is uninstalled.
A tool installed inside a box was invisible in BoxBuddy: the applications
list only ever enumerates `.desktop` files, and a command line tool has
none. The Applications page now has a Commands section listing what the
box itself holds, each with an "Add to Terminal" button that opens the
existing add-command dialog with the name filled in.

The scan covers `/usr/local/bin` and `/opt/*/bin`, and `$HOME/.local/bin`
only when the box has a home of its own - distrobox shares the host's home
by default, so scanning it there would list the host's own tools as though
they lived in the box. `/usr/bin` is left out: between the base image and
distrobox's first-run setup it holds hundreds of entries with nothing to
tell a user install apart from them.

The add-command dialog gains a "Name on host" field. `distrobox-export`
always keeps the command's own name, so a different one can only be a
chooser, and a chooser is now written even with nothing in the way - with
a single target it runs it without asking. This is what lets the same tool
from several boxes sit on the host as separate profiles: `claude` from two
boxes becomes `claude-work` and `claude-personal`, each entering its own
box. The generated script therefore separates the host-facing name from
the command run inside the box, and the marker records both.

docs/tips.md explains using a box's own home directory to keep an
application's settings and logins separate while the host's files stay
reachable, and the new-box form now says the same thing where the choice
is actually made.
Four lines of explanation under a form is more than anyone reads. Same
three facts - own settings and logins, host files still reachable, exports
still land on the host - in one sentence.
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.

Commands installed in a box are invisible, and exports cannot be named per box

1 participant