53 Commits
Author SHA1 Message Date
Alessio Biancalana 736989b677 fix(enter): use a real isatty check for --tty allocation (#2193)
* fix(enter): use a real isatty check for --tty allocation

* test(containermanager): make IsTTY regression test lint-clean
2026-08-09 19:15:49 +02:00
Alessio Biancalana 6cef357d3b fix: add license headers to new files 2026-08-02 17:40:16 +02:00
Alessio Biancalana 7ee57a7721 feat(migrate): detect outdated containers via distrobox.version label 2026-08-02 17:36:05 +02:00
Alessio Biancalana e793feccf8 feat(migrate): add distrobox migrate subcommand for v1→v2 containers 2026-08-02 17:30:52 +02:00
Luca Di Maio 1308ae11ce chore(license): add GPL-3.0 SPDX header to Go sources (#2173)
The legacy shell tree carried a per-file license header; the Go rewrite
shipped without one. Add it to all files and enforce it going forward
via golangci-lint's goheader linter, so the notice can't be dropped.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-07-24 18:08:51 +02:00
Luca Di Maio e513cf8d8a refactor(cleanup): remove dead code and duplication (#2172)
* refactor(userenv): drop unreachable UID/GID id-command fallbacks

os.Getuid/os.Getgid only return -1 on Windows, and distrobox is
Linux/macOS only, so the `id -ru`/`id -rg` fallbacks never executed.
Call them directly and drop the now-unused //nolint:gocognit.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>

* refactor(config): use maps.Copy in mergeConfigMaps

Replace the hand-rolled nested-loop map merge with the stdlib
maps.Copy. Rename the variadic parameter to configMaps so it no
longer shadows the maps package.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>

* refactor(ephemeral): drop DryRun field shadowing CreateOptions

EphemeralOptions embedded CreateOptions yet redeclared DryRun,
shadowing it. Remove the field and rely on promotion; set DryRun
in the embedded CreateOptions at the call sites instead.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>

* refactor(create): drop duplicate local --verbose flag

The root command already declares --verbose/-v as a persistent
flag, so create's local copy was redundant. Remove it; -v and
--verbose on `distrobox create` still resolve to the global.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>

* refactor(containermanager): use time.RFC3339Nano in TimestampNow

Replace the hand-written "…000000000+00:00" layout with the stdlib
RFC3339Nano constant. Output is equivalent RFC3339 (UTC "Z", trailing
zeros trimmed), still valid input for `podman/docker logs --since`.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>

---------

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-07-24 11:01:07 +02:00
Luca Di Maio 8561affccb fix(enter): parse distrobox flags after the container name (#2165)
`distrobox enter my-box --help` and any distrobox flag placed after the
container name, was passed to the container manager as the command instead
of being parsed, so it failed with a crun error. This diverged from the
original bash distrobox-enter, which keeps parsing flags after the name and
only starts the command at -e/--exec/--.

The port stopped flag parsing at the first positional (StopOnNthArg), which
cannot tell the name from the command: when --name or DBX_CONTAINER_NAME
already supplies the name, the first positional *is* the command. So the
command boundary is resolved before parsing and everything past it is handed
to urfave verbatim, letting flags be recognized wherever they appear while
the custom command is still passed through untouched. ephemeral gets the
same treatment.

Unknown flags after the name are rejected, as in bash, so a mistyped flag
surfaces instead of being silently executed inside the container.

Fixes https://github.com/89luca89/distrobox/issues/2160

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-07-18 17:00:12 +02:00
Alessio Attilio 7146d04dfa fix: resolve --version flag conflict with --verbose/-v 2026-07-08 23:19:28 +02:00
Luca Di Maio 94ae7fa1ac feat(compat): preserve v1 entry points after v2 single-binary split
v1 containers bind-mount distrobox-{init,export,host-exec} from host
$bindir, and v1 desktop entries launch via `distrobox-enter`. Both
would silently break under v2's single binary. argv[0] dispatch
routes distrobox-* symlinks to the right subcommand, and the helpers
ship at the v1 paths so v1 containers keep working.

BREAKING CHANGE: v2 rc1 and rc2 prerelease containers used ~/.local/share/distrobox/v2/
for their helpers and must be recreated.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-29 15:09:53 +02:00
Alessio Biancalana c7478fdf5f fix: forbidigo on completion stdout writes 2026-06-25 14:27:15 +02:00
Luca Di Maio 4acf784a7d feat(completion): add bash and zsh shell completion
Wrappers in completions/ call --generate-shell-completion; a Go
ShellComplete callback emits flag names so urfave's default response
(subcommands only) is replaced with the full candidate set.

This replaces old hard-coded way to auto-complete using shell script's
parsing.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 13:39:47 +02:00
Luca Di Maio c574800e72 refactor(create): align flag Value with displayed default
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:26 +02:00
Luca Di Maio bdc2576f2c refactor(config): centralize DBX_* env-var resolution
Env vars were read in three layers — cli.EnvVars on flags, os.Getenv
in CLI actions, and the podman provider — leaving library users no
single override point. Funnelling every DBX_* through pkg/config gives
consumers one injection point, lets the container manager receive its
configuration instead of sniffing for it, and fixes the create flags
whose Usage advertised a default the env-set value was already
shadowing.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:25 +02:00
Luca Di Maio 9ab96ee1e0 refactor(rm): route command-layer prints through ui.Printer
Replace four fmt.Print*/Fprintf calls in pkg/commands/rm.go with a
printer field on RmCommand, converting warnUnknownContainers and
findExportedDesktopApps to methods. cli/rm, assemble, and ephemeral
propagate the new constructor arg so library users can control output.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:25 +02:00
Luca Di Maio 3a4fc6a89e fix(rm): wire DBX_CONTAINER_RM_CUSTOM_HOME into --rm-home
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:25 +02:00
Luca Di Maio d0bc6af01b fix(stop): honor DBX_CONTAINER_NAME when no positional given
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:25 +02:00
Luca Di Maio f89b8dc8d7 fix(create): show the host's hostname in --hostname Usage
Shell distrobox-create:204 prints `default: $(uname -n)`. Compute it
via os.Hostname() at command-build time so --help mirrors the shell.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:24 +02:00
Luca Di Maio a1037e6094 fix(create): drop --image Value default so the empty-check survives
Value: cfg.DefaultContainerImage made cmd.String("image") never empty,
which killed the `containerImage == ""` branch in makeContainerImage
and spuriously triggered the `name == default` fallback for `--name foo`
alone. The Usage string already shows the default.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:24 +02:00
Luca Di Maio ecd155afb1 fix(test): align test with new enter behaviour
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:24 +02:00
Luca Di Maio 333e28ae56 chore(enter): fix gofmt alignment
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:24 +02:00
Luca Di Maio 556c8bb2ec fix(create): honor positional container_name argument
`distrobox create --image alpine my-box` silently ignored the
positional; only --name was read. Override ContainerName from
cmd.Args().First() to match the shell (distrobox-create:453-461).

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:23 +02:00
Luca Di Maio 5a3c65bb62 fix(rm): fix(rm): confirm deletions once and default the prompts to yes, match shell behaviour
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:21 +02:00
Luca Di Maio 6388503959 fix(upgrade): match shell prompting
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:21 +02:00
Luca Di Maio 8c5b5658b9 fix(enter): support noworkdir flag
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:21 +02:00
Luca Di Maio 9844159d0f fix(enter): match shell version, prompt user to create missing container if not existing
Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:21 +02:00
Luca Di Maio 1f2e769fb9 feat(cli): add SUDO/DOAS guard to match shell distrobox
Restore the reference shell's refusal of `sudo distrobox`.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-25 09:07:20 +02:00
Luca Di Maio a4618cdbb4 fix(compat): honor DBX_* env vars, autodetect, prompt, root parity
Wire per-command DBX_* env sources, default container_manager to autodetect, reject invalid prompt input, and treat uid 0 as rootful.
2026-06-25 09:07:20 +02:00
Alessio Biancalana 3d59d11ab5 fix(enter,ephemeral): support -e/--exec marker for custom command 2026-06-25 09:07:20 +02:00
balanza 8e676666b7 feat(create): implement --compatibility to fetch supported image list
Ports show_compatibility from bash distrobox-create. Downloads
docs/compatibility.md from upstream and caches the parsed list
in the user cache dir.
2026-06-14 13:04:28 +02:00
Emanuele De Cupis 56db400663 fix(rm): propagate verbose flag to generate-entry cleanup (#2109) 2026-06-14 13:04:28 +02:00
Emanuele De Cupis b6ed98f86e fix(assemble): accept manifest file as positional argument (#2105)
`distrobox assemble create /path/to/file.ini` and
`distrobox assemble rm /path/to/file.ini` now work the same way as the
original Bash `distrobox-assemble` script, in addition to the existing
`--file` flag. When both are supplied, `--file` takes precedence
(explicit over implicit). When neither is given, the default
`./distrobox.ini` is still used.

The resolution logic is extracted into a `resolveManifestPath` helper
with unit tests covering flag precedence, positional fallback and the
default path.
2026-06-14 13:04:28 +02:00
Emanuele De Cupis 9a1356076b fix(ephemeral): pass custom command to enter (#2104)
Forward the command/arguments collected after `--` on the ephemeral CLI
through `EphemeralOptions.CustomCommand` to the underlying enter
command, matching the bash reference (`distrobox-enter ... ${name}
${container_command}`). Without this, examples like `distrobox
ephemeral --image alpine -- cat /etc/os-release` would silently drop
the trailing command and just open an interactive shell.
2026-06-14 13:04:28 +02:00
Luca Di Maio 65b55ae981 fix(cli): match upstream when no container name is given (#2093)
- enter: fall back to cfg.DefaultContainerName (was passing "" to the manager)
- rm: fall back to cfg.DefaultContainerName (was a silent no-op)
- upgrade: error with "Please specify the name of the container." (was silently using my-distrobox)

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-14 13:04:28 +02:00
balanza d3219c019f fix(cli): use correct app claim 2026-06-14 13:04:28 +02:00
balanza 3d68de95de fix(cli): read correct version
Previously, the CLI hardcoded "1.0.0" as the version string in two places (the root command and the generate-entry subcommand).

Introduce pkg/version, a minimal package that exposes a single variable Version, defaulting to "dev". The root command now references such a value; generate-entry does not need it al all

The Makefile computes the version at build time by running:

git describe --tags --always
This produces the exact tag name when HEAD is tagged, or --g when it is not, giving a precise description of the build relative to the nearest ancestor tag. If git is unavailable, the value falls back to "dev".

The resulting string is injected into the binary via:

-ldflags "-X github.com/89luca89/distrobox/pkg/version.Version=<value>" so that distrobox --version and distrobox generate-entry --version both report the exact version of the build.
2026-06-14 13:04:28 +02:00
balanza 3058b51aaa fix(cli): sort commands alphabetically 2026-06-14 13:04:28 +02:00
balanza 9c3b2b9170 fix(root): validate rootful execution with the actual sudo program 2026-06-14 13:04:28 +02:00
balanza 58b654f98d fix(assemble): handle root for each entry
`assemble` command cannot be executed as root. Instead, each item can
either be processed by a rootful or rootless container manager.
2026-06-14 13:04:28 +02:00
balanza 7789effb77 refactor(cli): rename and move root validation 2026-06-14 13:04:28 +02:00
balanza fb8516f84f refactor(cli): compose commands with decorators
Some flags are shared to many commands but not to all (example: `--root`). By composing decorators, each command can be configured so that is assigned only to the flags that matters.
2026-06-14 13:04:28 +02:00
Luca Di Maio af76d23461 fix(enter): preserve argv boundaries in custom command
CustomCommand was joined into a string and re-split on whitespace,
collapsing quoted args — `sh -c "echo a || echo b"` lost its script
body, and any value passed by upgrade/assemble with embedded spaces
or quotes got mangled. Pass argv through as []string end-to-end.

Signed-off-by: Luca Di Maio <luca.dimaio1@gmail.com>
2026-06-14 13:04:28 +02:00
balanza ed57d2bdd9 fix(create): print default container name 2026-06-14 13:04:28 +02:00
Emanuele De Cupis b581ace4c7 fix: passing root correctly to create and generate-entry command (#2068)
* fix(create): handle root correctly

The `root` flag is handled in the root cli command. if we re-declare the
flag here we shadow it, resulting in a contaner manager initializated as
non-root.

Before this commit, these two commands produce respectively one root and
one non-root execution
```
distrobox --root create # root
distrobox create --root # non-root
```

* fix(generate-entry): handle root correctly

The `root` flag is handled in the root cli command. if we re-declare the
flag here we shadow it, resulting in a contaner manager initializated as
non-root.

Before this commit, these two commands produce respectively one root and
one non-root execution
```
distrobox --root generate-entry # root
distrobox generate-entry --root # non-root
```
2026-06-14 13:04:28 +02:00
Yiming Sun 73c48517ef fix(enter): unshare_groups su args and tty handling (#2063)
* enter(next): fix unshare_groups su args and tty handling

* test(docker): fix noTTY semantics in buildCommandArgs cases

* cli(enter): fix no-tty help text
2026-06-14 13:04:28 +02:00
Fabrizio Sestito 603f41e58a fix(cli): add podman-laucher to invalid container manager message
Signed-off-by: Fabrizio Sestito <fabrizio.sestito@suse.com>
2026-06-14 13:04:28 +02:00
Fabrizio Sestito 730ca303a1 fix(providers): execute correct binary for podman-launcher provider
Signed-off-by: Fabrizio Sestito <fabrizio.sestito@suse.com>
2026-06-14 13:04:28 +02:00
Fabrizio Sestito cc05d828c7 feat(cli): wire-up autodetect
Signed-off-by: Fabrizio Sestito <fabrizio.sestito@suse.com>
2026-06-14 13:04:28 +02:00
balanza b63fc88a89 refactor(config): move XDG_DATA_HOME read into userenv 2026-06-14 13:04:28 +02:00
balanza ec99b5d884 fix(config): read container image and name from config 2026-06-14 13:04:28 +02:00
balanza d9e4ffc57d refactor(config): trickle down config values to commands 2026-06-14 13:04:28 +02:00