chore(repo): make the go rewrite the root project (#60)

* chore(repo): remove shell implementation

* chore(repo): remove bash completion for sub-commands

There is no need for separate files as there will be no dedicated binary
for sub-commands

* chore(repo): remove zsh completion for sub-commands

There is no need for separate files as there will be no dedicated binary
for sub-commands

* chore(repo): delete RFC

We are not using RFC at the moment

* chore(repo): move golang project to the root

* chore(ci): move golang project to the root

* chore(repo): use standard .gitignore for golang projects

source: https://github.com/github/gitignore/blob/main/Go.gitignore

* chore(ci): compatibility CI to handle a golang project

* refactor(ci): run shell script checks against the inside-distrobox files

* refactor(ci): merge ci.yml workflow into main.yml
This commit is contained in:
Emanuele De Cupis authored and Alessio Biancalana committed 2026-06-14 13:04:28 +02:00
1 parent 2631fb48f5
commit 5a9649e6ee
88 files changed
+404 -4427

No files matched your search

+11 -1
View File
@@ -38,7 +38,7 @@ jobs:
# Fetch from compatibility table all the distros supported
- id: check_file_changed
run: |
if git diff --name-only HEAD^ HEAD | grep -Ev "host-exec|generate-entry|ephemeral|upgrade" | grep -E "^distrobox|compatibility.md"; then
if git diff --name-only HEAD^ HEAD | grep -E '\.go$|go\.mod|go\.sum|Makefile|docs/compatibility\.md|internal/inside-distrobox/assets/'; then
echo "::set-output name=distrobox_changed::True"
else
echo "::set-output name=distrobox_changed::False"
@@ -87,6 +87,16 @@ jobs:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v6.0.2
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build distrobox binary
run: |
make build
cp ./bin/distrobox ./distrobox
# Ensure distrobox create works:
- name: Distrobox create
shell: 'script -q -e -c "bash {0}"'
+49 -5
View File
@@ -14,7 +14,50 @@ on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
env:
SHELL_SCRIPTS_DIR: internal/inside-distrobox/assets
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v6.0.1
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version-file: "go.mod"
- run: make
golangci:
name: Golangci-lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v6.0.1
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version-file: "go.mod"
- name: golangci-lint
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v2.5.0
fmtcheck:
name: Go fmt check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v6.0.1
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version-file: "go.mod"
- name: format check
run: |
make fmt
if [ -n "$(git status --porcelain)" ]; then
echo "Code is not formatted. Please run 'make fmt' and commit the changes."
git --no-pager diff
exit 1
fi
dash:
runs-on: ubuntu-latest
@@ -24,7 +67,7 @@ jobs:
- name: Run dash -n
run: |
result=0
for file in $(find . -type f -not -path "*.git*" -a -not -path "*completions*"); do
for file in $(find ${SHELL_SCRIPTS_DIR} -type f); do
if file "$file" | grep -qi shell; then
echo "### Checking file $file..."
dash -n $file
@@ -43,7 +86,7 @@ jobs:
run: |
result=0
podman pull docker.io/peterdavehello/shfmt:latest
for file in $(find . -type f -not -path "*.git*"); do
for file in $(find ${SHELL_SCRIPTS_DIR} -type f); do
if file "$file" | grep -qi shell; then
echo "### Checking file $file..."
podman run --rm -v "$PWD:/mnt" docker.io/peterdavehello/shfmt:latest shfmt -d -s -ci -sr -kp -fn -i=0 -p /mnt/$file
@@ -67,7 +110,7 @@ jobs:
run: |
result=0
podman pull docker.io/koalaman/shellcheck:stable
for file in $(find . -type f -name ".*" -prune -o -print | grep -v '.git'); do
for file in $(find ${SHELL_SCRIPTS_DIR} -type f); do
if file "$file" | grep -qi shell; then
echo "### Checking file $file..."
# Should read the .shellcheckrc file to behave like -s sh -a -o all -Sstyle -Calways -x -e SC2310,SC2311,SC2312
@@ -93,6 +136,7 @@ jobs:
uses: redhat-plumbers-in-action/differential-shellcheck@v5
with:
severity: style
scan-directory: ${{ env.SHELL_SCRIPTS_DIR }}
token: ${{ secrets.GITHUB_TOKEN }}
bashate:
@@ -108,7 +152,7 @@ jobs:
- name: Run bashate
run: |
sudo pip3 install -U bashate
for file in $(find . -type f -not -path "*.git*"); do
for file in $(find ${SHELL_SCRIPTS_DIR} -type f); do
if file "$file" | grep -qi shell; then
echo "### Checking file $file..."
bashate -i E002,E003,E010,E011 --max-line-length 120 $file
@@ -137,6 +181,6 @@ jobs:
run: |
curl -L -O https://github.com/89luca89/shell-funcheck/releases/download/v0.0.1/shell-funcheck-amd64
chmod +x ./shell-funcheck-amd64
for i in distrobox*; do
for i in ${SHELL_SCRIPTS_DIR}/*; do
./shell-funcheck-amd64 check "$i"
done
-55
View File
@@ -1,55 +0,0 @@
name: CI (golang)
on:
workflow_call:
pull_request:
paths:
- "rewrite/**"
- ".github/workflows/rewrite-ci.yml"
permissions:
contents: read
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v6.0.1
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version-file: "rewrite/go.mod"
- run: make
working-directory: rewrite
golangci:
name: Golangci-lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v6.0.1
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version-file: "rewrite/go.mod"
- name: golangci-lint
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v2.5.0
working-directory: rewrite
fmtcheck:
name: Go fmt check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v6.0.1
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version-file: "rewrite/go.mod"
- name: format check
working-directory: rewrite
run: |
make fmt
if [ -n "$(git status --porcelain)" ]; then
echo "Code is not formatted. Please run 'make fmt' and commit the changes."
git --no-pager diff
exit 1
fi
+28
View File
@@ -1,3 +1,31 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin/
# Test binary, built with `go test -c`
*.test
# Code coverage profiles and other test artifacts
*.out
coverage.*
*.coverprofile
profile.cov
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
go.work.sum
# env file
.env
# Editor/IDE
tags
*.vim
TODO.txt
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
+3 -3
View File
@@ -38,7 +38,7 @@ _generate_from_help() {
fi
if [[ ${prev} == "--image" ]] || [[ ${prev} == "-i" ]]; then
COMPREPLY+=($(compgen -W "$(distrobox-create --compatibility)" -- ${cur}))
COMPREPLY+=($(compgen -W "$(distrobox create --compatibility)" -- ${cur}))
return 0
fi
@@ -50,7 +50,7 @@ _generate_from_help() {
[[ ${command} != *"version"* ]] && [[ ${command} != *"help"* ]]; then
while IFS= read -r line; do
list+="$line "
done < <(distrobox-list --no-color | tail -n+2 | cut -d'|' -f2)
done < <(distrobox list --no-color | tail -n+2 | cut -d'|' -f2)
COMPREPLY=($(compgen -W "${list}" "${cur}"))
return 0
fi
@@ -62,7 +62,7 @@ __distrobox() {
VALID_WORDS+=" --version --help"
COMPREPLY=($(compgen -W "${VALID_WORDS}" -- "${COMP_WORDS[1]}"))
elif [ "${#COMP_WORDS[@]}" -gt "2" ]; then
_generate_from_help distrobox-"${COMP_WORDS[1]}"
_generate_from_help distrobox "${COMP_WORDS[1]}"
fi
}
-13
View File
@@ -1,13 +0,0 @@
# shellcheck disable=all
if [ -e /usr/share/bash-completion/completions/distrobox ]; then
source /usr/share/bash-completion/completions/distrobox
fi
if [ -e /usr/local/share/bash-completion/completions/distrobox ]; then
source /usr/local/share/bash-completion/completions/distrobox
fi
if [ -e "${HOME}/.local/share/bash-completion/completions/distrobox" ]; then
source "${HOME}/.local/share/bash-completion/completions/distrobox"
fi
complete -F _generate_from_help distrobox-assemble
-13
View File
@@ -1,13 +0,0 @@
# shellcheck disable=all
if [ -e /usr/share/bash-completion/completions/distrobox ]; then
source /usr/share/bash-completion/completions/distrobox
fi
if [ -e /usr/local/share/bash-completion/completions/distrobox ]; then
source /usr/local/share/bash-completion/completions/distrobox
fi
if [ -e "${HOME}/.local/share/bash-completion/completions/distrobox" ]; then
source "${HOME}/.local/share/bash-completion/completions/distrobox"
fi
complete -F _generate_from_help distrobox-create
-13
View File
@@ -1,13 +0,0 @@
# shellcheck disable=all
if [ -e /usr/share/bash-completion/completions/distrobox ]; then
source /usr/share/bash-completion/completions/distrobox
fi
if [ -e /usr/local/share/bash-completion/completions/distrobox ]; then
source /usr/local/share/bash-completion/completions/distrobox
fi
if [ -e "${HOME}/.local/share/bash-completion/completions/distrobox" ]; then
source "${HOME}/.local/share/bash-completion/completions/distrobox"
fi
complete -F _generate_from_help distrobox-enter
-13
View File
@@ -1,13 +0,0 @@
# shellcheck disable=all
if [ -e /usr/share/bash-completion/completions/distrobox ]; then
source /usr/share/bash-completion/completions/distrobox
fi
if [ -e /usr/local/share/bash-completion/completions/distrobox ]; then
source /usr/local/share/bash-completion/completions/distrobox
fi
if [ -e "${HOME}/.local/share/bash-completion/completions/distrobox" ]; then
source "${HOME}/.local/share/bash-completion/completions/distrobox"
fi
complete -F _generate_from_help distrobox-ephemeral
-13
View File
@@ -1,13 +0,0 @@
# shellcheck disable=all
if [ -e /usr/share/bash-completion/completions/distrobox ]; then
source /usr/share/bash-completion/completions/distrobox
fi
if [ -e /usr/local/share/bash-completion/completions/distrobox ]; then
source /usr/local/share/bash-completion/completions/distrobox
fi
if [ -e "${HOME}/.local/share/bash-completion/completions/distrobox" ]; then
source "${HOME}/.local/share/bash-completion/completions/distrobox"
fi
complete -F _generate_from_help distrobox-generate-entry
-13
View File
@@ -1,13 +0,0 @@
# shellcheck disable=all
if [ -e /usr/share/bash-completion/completions/distrobox ]; then
source /usr/share/bash-completion/completions/distrobox
fi
if [ -e /usr/local/share/bash-completion/completions/distrobox ]; then
source /usr/local/share/bash-completion/completions/distrobox
fi
if [ -e "${HOME}/.local/share/bash-completion/completions/distrobox" ]; then
source "${HOME}/.local/share/bash-completion/completions/distrobox"
fi
complete -F _generate_from_help distrobox-list
-13
View File
@@ -1,13 +0,0 @@
# shellcheck disable=all
if [ -e /usr/share/bash-completion/completions/distrobox ]; then
source /usr/share/bash-completion/completions/distrobox
fi
if [ -e /usr/local/share/bash-completion/completions/distrobox ]; then
source /usr/local/share/bash-completion/completions/distrobox
fi
if [ -e "${HOME}/.local/share/bash-completion/completions/distrobox" ]; then
source "${HOME}/.local/share/bash-completion/completions/distrobox"
fi
complete -F _generate_from_help distrobox-rm
-13
View File
@@ -1,13 +0,0 @@
# shellcheck disable=all
if [ -e /usr/share/bash-completion/completions/distrobox ]; then
source /usr/share/bash-completion/completions/distrobox
fi
if [ -e /usr/local/share/bash-completion/completions/distrobox ]; then
source /usr/local/share/bash-completion/completions/distrobox
fi
if [ -e "${HOME}/.local/share/bash-completion/completions/distrobox" ]; then
source "${HOME}/.local/share/bash-completion/completions/distrobox"
fi
complete -F _generate_from_help distrobox-stop
-13
View File
@@ -1,13 +0,0 @@
# shellcheck disable=all
if [ -e /usr/share/bash-completion/completions/distrobox ]; then
source /usr/share/bash-completion/completions/distrobox
fi
if [ -e /usr/local/share/bash-completion/completions/distrobox ]; then
source /usr/local/share/bash-completion/completions/distrobox
fi
if [ -e "${HOME}/.local/share/bash-completion/completions/distrobox" ]; then
source "${HOME}/.local/share/bash-completion/completions/distrobox"
fi
complete -F _generate_from_help distrobox-upgrade
+313
View File
@@ -3,6 +3,26 @@
local curcontext="$curcontext" state line
typeset -A opt_args
_distrobox_containers() {
local -a containers
containers=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
_describe -t containers 'available containers' containers
}
_distrobox_images() {
local -a images
images=("${(@f)$(distrobox create --compatibility | awk 'NF {print $0}')}")
_wanted images expl 'compatible image' compadd -a images
}
_distrobox_running_containers() {
local -a containers
containers=($(distrobox list | awk -F'|' '$3 ~ /Up/ { gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2 }'))
if (( ${#containers} > 0 )); then
_describe -t running-containers 'running containers' containers
fi
}
_distrobox_commands() {
local -a commands
commands=(
@@ -21,6 +41,299 @@ _distrobox_commands() {
_describe -t commands 'distrobox command' commands
}
_distrobox-assemble() {
_message -r "Create or remove containers in batches, based on a manifest file."
_arguments \
'1:command:(create rm)' \
'--file[path to the distrobox manifest/ini file]:file:_files' \
'(--name -n)'{-n,--name}'[run against a single entry in the manifest/ini file]:entry name:' \
'(--replace -R)'{-R,--replace}'[replace already existing distroboxes with matching names]' \
'(--dry-run -d)'{-d,--dry-run}'[only print the container manager command generated]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]'
}
_distrobox-create() {
local -a options
local expl
local state
options=(
'(-i --image)'{-i,--image}'[Specify image to use for the container]:image:_distrobox_images'
'(-n --name)'{-n,--name}'[Specify name for the distrobox]:distrobox name:'
'--hostname[Specify hostname for the distrobox]:hostname:'
'(-p --pull)'{-p,--pull}'[Pull the image even if it exists locally (implies --yes)]'
'(-Y --yes)'{-Y,--yes}'[Non-interactive, pull images without asking]'
'(-r --root)'{-r,--root}'[Launch with root privileges using podman/docker/lilipod]'
'(-c --clone)'{-c,--clone}'[Name of the distrobox container to use as base for a new container]:clone container name:'
'(-H --home)'{-H,--home}'[Select a custom HOME directory for the container]:path:_files -/'
'--volume[Add additional volumes to the container]:volume:_files'
'(-a --additional-flags)'{-a,--additional-flags}'[Additional flags to pass to the container manager command]:flags:'
'(-ap --additional-packages)'{-ap,--additional-packages}'[Additional packages to install during setup]:package:'
'--init-hooks[Commands to execute during container initialization]:command:'
'--pre-init-hooks[Commands to execute prior to container initialization]:command:'
'(-I --init)'{-I,--init}'[Use an init system inside the container]'
'--nvidia[Try to integrate host nVidia drivers into the guest]'
'--unshare-devsys[Do not share host devices and sysfs dirs from host]'
'--unshare-groups[Do not forward users additional groups into the container]'
'--unshare-ipc[Do not share ipc namespace with host]'
'--unshare-netns[Do not share the net namespace with host]'
'--unshare-process[Do not share process namespace with host]'
'--unshare-all[Activate all the unshare flags]'
'(-C --compatibility)'{-C,--compatibility}'[Show list of compatible images]'
'(-h --help)'{-h,--help}'[Show this message]'
'--no-entry[Do not generate a container entry in the application list]'
'(-d --dry-run)'{-d,--dry-run}'[Only print the container manager command generated]'
'(-v --verbose)'{-v,--verbose}'[Show more verbosity]'
'(-V --version)'{-V,--version}'[Show version]'
'--absolutely-disable-root-password-i-am-really-positively-sure[Skip user password setup, leaving it blank]'
)
_message -r "Create new distroboxes."
_arguments \
'1:containers:->container' \
'*:options:->options' \
$options[@]
}
_distrobox-enter() {
local -a options
local expl
local state
local _db_cc
_db_cc=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
options=(
'(--name -n)'{-n,--name}'[name for the distrobox]:container:_distrobox_containers'
'--[end arguments and execute the rest as command to execute at login]:command:_command_names'
'(--no-tty -T)'{-T,--no-tty}'[do not instantiate a tty]'
'(--no-workdir -nw)'{-nw,--no-workdir}'[always start the container from container home directory]'
'(--additional-flags -a)'{-a,--additional-flags}'[additional flags to pass to the container manager command]:flags:'
'(--help -h)'{-h,--help}'[show this message]'
'(--root -r)'{-r,--root}'[launch podman/docker/lilipod with root privileges]'
'(--dry-run -d)'{-d,--dry-run}'[only print the container manager command generated]'
'(--verbose -v)'{-v,--verbose}'[show more verbosity]'
'(--version -V)'{-V,--version}'[show version]'
)
_message -r "Start and enter a distrobox."
if [[ -n "$_db_cc" ]]; then
_arguments -C \
'1:containers:_distrobox_containers' \
$options[@]
else
_message -r "No containers exist."
_arguments $options[@]
fi
}
_distrobox-ephemeral() {
local -a options
local expl
local state
options=(
'(-i --image)'{-i,--image}'[Specify image to use for the container]:image:_distrobox_images'
'(-n --name)'{-n,--name}'[Specify name for the distrobox]:distrobox name:'
'--hostname[Specify hostname for the distrobox]:hostname:'
'(-p --pull)'{-p,--pull}'[Pull the image even if it exists locally (implies --yes)]'
'(-Y --yes)'{-Y,--yes}'[Non-interactive, pull images without asking]'
'(-r --root)'{-r,--root}'[Launch with root privileges using podman/docker/lilipod]'
'(-c --clone)'{-c,--clone}'[Name of the distrobox container to use as base for a new container]:clone container name:'
'(-H --home)'{-H,--home}'[Select a custom HOME directory for the container]:path:_files -/'
'--volume[Add additional volumes to the container]:volume:_files'
'(-a --additional-flags)'{-a,--additional-flags}'[Additional flags to pass to the container manager command]:flags:'
'(-ap --additional-packages)'{-ap,--additional-packages}'[Additional packages to install during setup]:package:'
'--init-hooks[Commands to execute during container initialization]:command:'
'--pre-init-hooks[Commands to execute prior to container initialization]:command:'
'(-I --init)'{-I,--init}'[Use an init system inside the container]'
'--nvidia[Try to integrate host nVidia drivers into the guest]'
'--unshare-devsys[Do not share host devices and sysfs dirs from host]'
'--unshare-groups[Do not forward users additional groups into the container]'
'--unshare-ipc[Do not share ipc namespace with host]'
'--unshare-netns[Do not share the net namespace with host]'
'--unshare-process[Do not share process namespace with host]'
'--unshare-all[Activate all the unshare flags]'
'(-C --compatibility)'{-C,--compatibility}'[Show list of compatible images]'
'(-h --help)'{-h,--help}'[Show this message]'
'--no-entry[Do not generate a container entry in the application list]'
'(-d --dry-run)'{-d,--dry-run}'[Only print the container manager command generated]'
'(-v --verbose)'{-v,--verbose}'[Show more verbosity]'
'(-V --version)'{-V,--version}'[Show version]'
'--absolutely-disable-root-password-i-am-really-positively-sure[Skip user password setup, leaving it blank]'
)
_message -r "Create temporary distroboxes that are auto destroyed."
_arguments \
'1:containers:->container' \
'*:options:->options' \
$options[@]
}
_distrobox-export() {
_message -r "Export an app or a binary from the container to the host."
_arguments \
'(--app -a)'{-a,--app}'[name of the application to export]:application name:' \
'(--bin -b)'{-b,--bin}'[absolute path of the binary to export]:path to binary:_files' \
'(--delete -d)'{-d,--delete}'[delete exported application or binary]' \
'(--export-label -el)'{-el,--export-label}'[label to add to exported application name, use "none" to disable]:label:' \
'(--export-path -ep)'{-ep,--export-path}'[path where to export the binary]:export path:_files' \
'(--extra-flags -ef)'{-ef,--extra-flags}'[extra flags to add to the command]:extra flags:' \
'(--enter-flags -nf)'{-nf,--enter-flags}'[flags to add to distrobox enter]:enter flags:' \
'--list-apps[list applications exported from this container]' \
'--list-binaries[list binaries exported from this container, use -ep to specify custom paths to search]' \
'(--sudo -S)'{-S,--sudo}'[specify if the exported item should be run as sudo]' \
'(--help -h)'{-h,--help}'[show this message]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]'
}
_distrobox generate-entry() {
local expl
local -a options
local _db_cc
_db_cc=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
options=(
'(-h --help)'{-h,--help}'[show this message]'
'(-a --all)'{-a,--all}'[perform for all distroboxes]'
'(-d --delete)'{-d,--delete}'[delete the entry]'
'(-i --icon)'{-i,--icon}'[specify a custom icon (default auto)]:icon path:(auto _files)'
'(-r --root)'{-r,--root}'[perform on rootful distroboxes]'
'(-v --verbose)'{-v,--verbose}'[show more verbosity]'
'(-V --version)'{-V,--version}'[show version]'
)
_message -r "Create a desktop icon for a distrobox"
if [[ -n "$_db_cc" ]]; then
_arguments \
'*:containers:_distrobox_containers' \
$options[@]
else
_message -r "No containers exist."
_arguments $options[@]
fi
}
_distrobox-host-exec() {
_message -r "Execute a command on the host while in a container"
_arguments \
'*:command:_command' \
'(--help -h)'{-h,--help}'[show this message]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]' \
'(--yes -Y)'{-Y,--yes}'[Automatically answer yes to prompt host-spawn will be installed on the guest system if not detected]'
}
_distrobox-init() {
_message -r "Init the distrobox (not to be launched manually)"
_arguments \
'(--name -n)'{-n,--name}'[user name]:user name:' \
'(--user -u)'{-u,--user}'[uid of the user]:uid:' \
'(--group -g)'{-g,--group}'[gid of the user]:gid:' \
'(--home -d)'{-d,--home}'[path/to/home of the user]:home path:_files' \
'(--help -h)'{-h,--help}'[show this message]' \
'--additional-packages[packages to install in addition]:packages:' \
'(--init -I)'{-I,--init}'[whether to use or not init]' \
'--pre-init-hooks[commands to execute prior to init]:commands:' \
'--nvidia[try to integrate hosts nVidia drivers in the guest]' \
'(--upgrade -U)'{-U,--upgrade}'[run init in upgrade mode]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]' \
'--:[end arguments execute the rest as command to execute during init]:command:_command'
}
_distrobox-list() {
_message -r "List available distroboxes."
_arguments \
'(--help -h)'{-h,--help}'[show this message]' \
'--no-color[disable color formatting]' \
'(--root -r)'{-r,--root}'[launch podman/docker/lilipod with root privileges]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]'
}
_distrobox-rm() {
# expl is an internal zsh array that gets passed to _arguments bts
local expl
local -a options
local _db_cc
# Check for existing containers and store the result into var _db_cc
_db_cc=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
# Array of optargs to pass to _arguments for matching and completion
options=(
'(-a --all)'{-a,--all}'[delete all distroboxes]'
'(-f --force)'{-f,--force}'[force deletion]'
'--rm-home[remove the mounted home if it differs from the host users one]'
'(-r --root)'{-r,--root}'[launch podman/docker/lilipod with root privileges]'
'(-h --help)'{-h,--help}'[show this message]'
'(-v --verbose)'{-v,--verbose}'[show more verbosity]'
'(-V --version)'{-V,--version}'[show version]'
)
_message -r "Delete one or more distroboxes."
# If containers exist then do an action
if [[ -n "$_db_cc" ]]; then
# Match both container names and optargs
_arguments \
'*:containers:_distrobox_containers' \
$options[@]
# If no containers exist then do an action
else
# Display message to user and match optargs only
_message -r "No containers exist."
_arguments $options[@]
fi
}
_distrobox-stop() {
local expl
local -a options
local _db_rcc
_db_rcc=($(distrobox list | awk -F'|' '$3 ~ /Up/ { gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2 }'))
options=(
'(-a --all)'{-a,--all}'[stop all distroboxes]'
'(-Y --yes)'{-Y,--yes}'[non-interactive, stop without asking]'
'(-r --root)'{-r,--root}'[launch podman/docker/lilipod with root privileges]'
'(-h --help)'{-h,--help}'[show this message]'
'(-v --verbose)'{-v,--verbose}'[show more verbosity]'
'(-V --version)'{-V,--version}'[show version]'
)
_message -r "Stop running distrobox containers."
if [[ -n "$_db_rcc" ]]; then
_arguments -C \
'*:containers:_distrobox_running_containers' \
$options[@]
else
_message -r "No running containers."
_arguments $options[@]
fi
}
_distrobox-upgrade() {
local expl
local -a options
local _db_cc
_db_cc=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
options=(
'(-a --all)'{-a,--all}'[upgrade all distroboxes]'
'--running[perform only for running distroboxes]'
'(-r --root)'{-r,--root}'[launch podman/docker/lilipod with root privileges]'
'(-h --help)'{-h,--help}'[show this message]'
'(-v --verbose)'{-v,--verbose}'[show more verbosity]'
'(-V --version)'{-V,--version}'[show version]'
)
_message -r "Upgrade distroboxes using container's package manager."
if [[ -n "$_db_cc" ]]; then
_arguments \
'*:containers:_distrobox_containers' \
$options[@]
else
_message -r "No containers exist."
_arguments $options[@]
fi
}
_arguments -C \
'1: :_distrobox_commands' \
'*:: :->args'
-11
View File
@@ -1,11 +0,0 @@
#compdef distrobox-assemble
_message -r "Create or remove containers in batches, based on a manifest file."
_arguments \
'1:command:(create rm)' \
'--file[path to the distrobox manifest/ini file]:file:_files' \
'(--name -n)'{-n,--name}'[run against a single entry in the manifest/ini file]:entry name:' \
'(--replace -R)'{-R,--replace}'[replace already existing distroboxes with matching names]' \
'(--dry-run -d)'{-d,--dry-run}'[only print the container manager command generated]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]'
-46
View File
@@ -1,46 +0,0 @@
#compdef distrobox-create
_distrobox-create() {
local -a options
local expl
local state
# Array of optargs to pass to _arguments for matching and completion
options=(
'(-i --image)'{-i,--image}'[Specify image to use for the container]:image:_distrobox_images'
'(-n --name)'{-n,--name}'[Specify name for the distrobox]:distrobox name:'
'--hostname[Specify hostname for the distrobox]:hostname:'
'(-p --pull)'{-p,--pull}'[Pull the image even if it exists locally (implies --yes)]'
'(-Y --yes)'{-Y,--yes}'[Non-interactive, pull images without asking]'
'(-r --root)'{-r,--root}'[Launch with root privileges using podman/docker/lilipod]'
'(-c --clone)'{-c,--clone}'[Name of the distrobox container to use as base for a new container]:clone container name:'
'(-H --home)'{-H,--home}'[Select a custom HOME directory for the container]:path:_files -/'
'--volume[Add additional volumes to the container]:volume:_files'
'(-a --additional-flags)'{-a,--additional-flags}'[Additional flags to pass to the container manager command]:flags:'
'(-ap --additional-packages)'{-ap,--additional-packages}'[Additional packages to install during setup]:package:'
'--init-hooks[Commands to execute during container initialization]:command:'
'--pre-init-hooks[Commands to execute prior to container initialization]:command:'
'(-I --init)'{-I,--init}'[Use an init system inside the container]'
'--nvidia[Try to integrate host nVidia drivers into the guest]'
'--unshare-devsys[Do not share host devices and sysfs dirs from host]'
'--unshare-groups[Do not forward users additional groups into the container]'
'--unshare-ipc[Do not share ipc namespace with host]'
'--unshare-netns[Do not share the net namespace with host]'
'--unshare-process[Do not share process namespace with host]'
'--unshare-all[Activate all the unshare flags]'
'(-C --compatibility)'{-C,--compatibility}'[Show list of compatible images]'
'(-h --help)'{-h,--help}'[Show this message]'
'--no-entry[Do not generate a container entry in the application list]'
'(-d --dry-run)'{-d,--dry-run}'[Only print the container manager command generated]'
'(-v --verbose)'{-v,--verbose}'[Show more verbosity]'
'(-V --version)'{-V,--version}'[Show version]'
'--absolutely-disable-root-password-i-am-really-positively-sure[Skip user password setup, leaving it blank]'
)
# Simple logic
_message -r "Create new distroboxes."
_arguments \
'1:containers:->container' \
'*:options:->options' \
$options[@]
}
_distrobox-create
-35
View File
@@ -1,35 +0,0 @@
#compdef distrobox-enter
_distrobox-enter() {
local -a options
local expl
local state
local _db_cc
_db_cc=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
options=(
'(--name -n)'{-n,--name}'[name for the distrobox]:container:_distrobox_containers'
'--[end arguments and execute the rest as command to execute at login]:command:_command_names'
'(--no-tty -T)'{-T,--no-tty}'[do not instantiate a tty]'
'(--no-workdir -nw)'{-nw,--no-workdir}'[always start the container from container home directory]'
'(--additional-flags -a)'{-a,--additional-flags}'[additional flags to pass to the container manager command]:flags:'
'(--help -h)'{-h,--help}'[show this message]'
'(--root -r)'{-r,--root}'[launch podman/docker/lilipod with root privileges]'
'(--dry-run -d)'{-d,--dry-run}'[only print the container manager command generated]'
'(--verbose -v)'{-v,--verbose}'[show more verbosity]'
'(--version -V)'{-V,--version}'[show version]'
)
_message -r "Start and enter a distrobox."
if [[ -n "$_db_cc" ]]; then
_arguments -C \
'1:containers:_distrobox_containers' \
$options[@]
else
_message -r "No containers exist."
_arguments $options[@]
fi
}
_distrobox-enter
-46
View File
@@ -1,46 +0,0 @@
#compdef distrobox-ephemeral
_distrobox-ephemeral() {
local -a options
local expl
local state
# Array of optargs to pass to _arguments for matching and completion
options=(
'(-i --image)'{-i,--image}'[Specify image to use for the container]:image:_distrobox_images'
'(-n --name)'{-n,--name}'[Specify name for the distrobox]:distrobox name:'
'--hostname[Specify hostname for the distrobox]:hostname:'
'(-p --pull)'{-p,--pull}'[Pull the image even if it exists locally (implies --yes)]'
'(-Y --yes)'{-Y,--yes}'[Non-interactive, pull images without asking]'
'(-r --root)'{-r,--root}'[Launch with root privileges using podman/docker/lilipod]'
'(-c --clone)'{-c,--clone}'[Name of the distrobox container to use as base for a new container]:clone container name:'
'(-H --home)'{-H,--home}'[Select a custom HOME directory for the container]:path:_files -/'
'--volume[Add additional volumes to the container]:volume:_files'
'(-a --additional-flags)'{-a,--additional-flags}'[Additional flags to pass to the container manager command]:flags:'
'(-ap --additional-packages)'{-ap,--additional-packages}'[Additional packages to install during setup]:package:'
'--init-hooks[Commands to execute during container initialization]:command:'
'--pre-init-hooks[Commands to execute prior to container initialization]:command:'
'(-I --init)'{-I,--init}'[Use an init system inside the container]'
'--nvidia[Try to integrate host nVidia drivers into the guest]'
'--unshare-devsys[Do not share host devices and sysfs dirs from host]'
'--unshare-groups[Do not forward users additional groups into the container]'
'--unshare-ipc[Do not share ipc namespace with host]'
'--unshare-netns[Do not share the net namespace with host]'
'--unshare-process[Do not share process namespace with host]'
'--unshare-all[Activate all the unshare flags]'
'(-C --compatibility)'{-C,--compatibility}'[Show list of compatible images]'
'(-h --help)'{-h,--help}'[Show this message]'
'--no-entry[Do not generate a container entry in the application list]'
'(-d --dry-run)'{-d,--dry-run}'[Only print the container manager command generated]'
'(-v --verbose)'{-v,--verbose}'[Show more verbosity]'
'(-V --version)'{-V,--version}'[Show version]'
'--absolutely-disable-root-password-i-am-really-positively-sure[Skip user password setup, leaving it blank]'
)
# Simple logic
_message -r "Create temporary distroboxes that are auto destroyed."
_arguments \
'1:containers:->container' \
'*:options:->options' \
$options[@]
}
_distrobox-ephemeral
-17
View File
@@ -1,17 +0,0 @@
#compdef distrobox-export
_message -r "Export an app or a binary from the container to the host."
_arguments \
'(--app -a)'{-a,--app}'[name of the application to export]:application name:' \
'(--bin -b)'{-b,--bin}'[absolute path of the binary to export]:path to binary:_files' \
'(--delete -d)'{-d,--delete}'[delete exported application or binary]' \
'(--export-label -el)'{-el,--export-label}'[label to add to exported application name, use "none" to disable]:label:' \
'(--export-path -ep)'{-ep,--export-path}'[path where to export the binary]:export path:_files' \
'(--extra-flags -ef)'{-ef,--extra-flags}'[extra flags to add to the command]:extra flags:' \
'(--enter-flags -nf)'{-nf,--enter-flags}'[flags to add to distrobox-enter]:enter flags:' \
'--list-apps[list applications exported from this container]' \
'--list-binaries[list binaries exported from this container, use -ep to specify custom paths to search]' \
'(--sudo -S)'{-S,--sudo}'[specify if the exported item should be run as sudo]' \
'(--help -h)'{-h,--help}'[show this message]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]'
-35
View File
@@ -1,35 +0,0 @@
#compdef distrobox-generate-entry
_distrobox-generate-entry() {
# expl is an internal zsh array that gets passed to _arguments bts
local expl
local -a options
local _db_cc
# Check for existing containers and store the result into var _db_cc
_db_cc=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
# Array of optargs to pass to _arguments for matching and completion
options=(
'(-h --help)'{-h,--help}'[show this message]'
'(-a --all)'{-a,--all}'[perform for all distroboxes]'
'(-d --delete)'{-d,--delete}'[delete the entry]'
'(-i --icon)'{-i,--icon}'[specify a custom icon (default auto)]:icon path:(auto _files)'
'(-r --root)'{-r,--root}'[perform on rootful distroboxes]'
'(-v --verbose)'{-v,--verbose}'[show more verbosity]'
'(-V --version)'{-V,--version}'[show version]'
)
_message -r "Create a desktop icon for a distrobox"
# If containers exist then do an action
if [[ -n "$_db_cc" ]]; then
# Match both container names and optargs
_arguments \
'*:containers:_distrobox_containers' \
$options[@]
# If no containers exist then do an action
else
# Display message to user and match optargs only
_message -r "No containers exist."
_arguments $options[@]
fi
}
_distrobox-generate-entry
-9
View File
@@ -1,9 +0,0 @@
#compdef distrobox-host-exec
_message -r "Execute a command on the host while in a container"
_arguments \
'*:command:_command' \
'(--help -h)'{-h,--help}'[show this message]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]' \
'(--yes -Y)'{-Y,--yes}'[Automatically answer yes to prompt host-spawn will be installed on the guest system if not detected]'
-17
View File
@@ -1,17 +0,0 @@
#compdef distrobox-init
_message -r "Init the distrobox (not to be launched manually)"
_arguments \
'(--name -n)'{-n,--name}'[user name]:user name:' \
'(--user -u)'{-u,--user}'[uid of the user]:uid:' \
'(--group -g)'{-g,--group}'[gid of the user]:gid:' \
'(--home -d)'{-d,--home}'[path/to/home of the user]:home path:_files' \
'(--help -h)'{-h,--help}'[show this message]' \
'--additional-packages[packages to install in addition]:packages:' \
'(--init -I)'{-I,--init}'[whether to use or not init]' \
'--pre-init-hooks[commands to execute prior to init]:commands:' \
'--nvidia[try to integrate hosts nVidia drivers in the guest]' \
'(--upgrade -U)'{-U,--upgrade}'[run init in upgrade mode]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]' \
'--:[end arguments execute the rest as command to execute during init]:command:_command'
-9
View File
@@ -1,9 +0,0 @@
#compdef distrobox-list
_message -r "List available distroboxes."
_arguments \
'(--help -h)'{-h,--help}'[show this message]' \
'--no-color[disable color formatting]' \
'(--root -r)'{-r,--root}'[launch podman/docker/lilipod with root privileges]' \
'(--verbose -v)'{-v,--verbose}'[show more verbosity]' \
'(--version -V)'{-V,--version}'[show version]'
-36
View File
@@ -1,36 +0,0 @@
#compdef distrobox-rm
_distrobox-rm() {
# expl is an internal zsh array that gets passed to _arguments bts
local expl
local -a options
local _db_cc
# Check for existing containers and store the result into var _db_cc
_db_cc=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
# Array of optargs to pass to _arguments for matching and completion
options=(
'(-a --all)'{-a,--all}'[delete all distroboxes]'
'(-f --force)'{-f,--force}'[force deletion]'
'--rm-home[remove the mounted home if it differs from the host users one]'
'(-r --root)'{-r,--root}'[launch podman/docker/lilipod with root privileges]'
'(-h --help)'{-h,--help}'[show this message]'
'(-v --verbose)'{-v,--verbose}'[show more verbosity]'
'(-V --version)'{-V,--version}'[show version]'
)
_message -r "Delete one or more distroboxes."
# If containers exist then do an action
if [[ -n "$_db_cc" ]]; then
# Match both container names and optargs
_arguments \
'*:containers:_distrobox_containers' \
$options[@]
# If no containers exist then do an action
else
# Display message to user and match optargs only
_message -r "No containers exist."
_arguments $options[@]
fi
}
_distrobox-rm
-31
View File
@@ -1,31 +0,0 @@
#compdef distrobox-stop
_distrobox-stop() {
local expl
local -a options
local _db_rcc
_db_rcc=($(distrobox list | awk -F'|' '$3 ~ /Up/ { gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2 }'))
options=(
'(-a --all)'{-a,--all}'[stop all distroboxes]'
'(-Y --yes)'{-Y,--yes}'[non-interactive, stop without asking]'
'(-r --root)'{-r,--root}'[launch podman/docker/lilipod with root privileges]'
'(-h --help)'{-h,--help}'[show this message]'
'(-v --verbose)'{-v,--verbose}'[show more verbosity]'
'(-V --version)'{-V,--version}'[show version]'
)
_message -r "Stop running distrobox containers."
if [[ -n "$_db_rcc" ]]; then
_arguments -C \
'*:containers:_distrobox_running_containers' \
$options[@]
else
_message -r "No running containers."
_arguments $options[@]
fi
}
_distrobox-stop
-31
View File
@@ -1,31 +0,0 @@
#compdef distrobox-upgrade
_distrobox-upgrade() {
local expl
local -a options
local _db_cc
_db_cc=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
options=(
'(-a --all)'{-a,--all}'[upgrade all distroboxes]'
'--running[perform only for running distroboxes]'
'(-r --root)'{-r,--root}'[launch podman/docker/lilipod with root privileges]'
'(-h --help)'{-h,--help}'[show this message]'
'(-v --verbose)'{-v,--verbose}'[show more verbosity]'
'(-V --version)'{-V,--version}'[show version]'
)
_message -r "Upgrade distroboxes using container's package manager."
if [[ -n "$_db_cc" ]]; then
_arguments \
'*:containers:_distrobox_containers' \
$options[@]
else
_message -r "No containers exist."
_arguments $options[@]
fi
}
_distrobox-upgrade
-7
View File
@@ -1,7 +0,0 @@
#autoload
_distrobox_containers() {
local -a containers
containers=("${(@f)$(distrobox list | sed 1d | awk -F'|' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//')}")
_describe -t containers 'available containers' containers
}
-7
View File
@@ -1,7 +0,0 @@
#autoload
_distrobox_images() {
local -a images
images=("${(@f)$(distrobox-create --compatibility | awk 'NF {print $0}')}")
_wanted images expl 'compatible image' compadd -a images
}
@@ -1,9 +0,0 @@
#autoload
_distrobox_running_containers() {
local -a containers
containers=($(distrobox list | awk -F'|' '$3 ~ /Up/ { gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2 }'))
if (( ${#containers} > 0 )); then
_describe -t running-containers 'running containers' containers
fi
}
View File
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
-3
View File
@@ -1,3 +0,0 @@
*.vim
TODO.txt
bin/
-81
View File
@@ -1,81 +0,0 @@
| | |
| :----------- | :------------- |
| Feature Name | Rewrite in GO |
| Start Date | Nov 28th, 2025 |
| State | **ACCEPTED** |
# Summary
[summary]: #summary
Rewrite Distrobox from `sh` to `GO`: motivation, core principles and architecture.
# Motivation
[motivation]: #motivation
We want Distrobox to live long and prosper. As the tool is being used by more and more people with diverse
environment setup, the need to add support to more stuff is pressing.
The key factor to not mess it up it's **maintainability**.
We believe that by rewriting Distrobox in `GO` we can:
* add new features safely, by having extensive testing;
* have a better developer experience, through the use of a modern coding and testing toolchain;
* engage more with the community, by using a popular programming language;
# Design
[design]: #design
## Core principles
* Keep feature parity with the actual Distrobox implementation.
* Keep dependency list short.
* Enforce conventions with strict linting.
* Isolate the shell from core Distrobox logic.
* Write humble code.
## Architecture
### `cmd/main.go`
Entrypoint of the application, build and execute the CLI root command.
### `internal/cli/root.go`
Root CLI command.
* Load global configuration from either file or environment variables, and define the defaults.
* Define the global flags that are valid for every sub command (example: `--verbose`).
* Select, instantiate and run the appropriate sub command.
### `internal/cli/<command>.go`
Any command exposed through the CLI (example: `distrobox list`). It's the component that is aware of the shell, and it
manipulates Distrobox input/output by parsing the command flags and printing logs appropriately.
* Define command-specific flags.
* Instantiate and execute the relative command package.
* Handle command termination.
* Define shell printing logic by injecting a custom logger to the command package.
* Handle verbosity of the logs to the `stdout`.
### `pkg/command/<command>.go`
Implement the Distrobox command logic. It has no knowledge about the environment in which it is executed.
* Exposes a `Execute()` function that accepts input params as arguments and can return either `error` or the execution result.
* A custom logger is injected; a command knows nothing about verbosity, log level and (eventually) pretty printing.
Commands may also have different needs depending on their behaviour:
* Some commands are meant to be immediate and return a result (example: `list`); for such commands, the output data is returned in the execution result object.
* Some are long-running and require to return progress feedback to the user (example: `create`); such commands will log writes to the provided logger, delegating the presentation to the caller.
* Finally, some are _interactive_ and need to interact with the shell (example: `enter`); such command will require as input instances of `io.Reader` and `io.Writer` (that, for the shell scenario, can be bound to `stdin` and `stdout` respectively).
### `pkg/containermanager/containermanager.go`
Module that defines the interface for interacting with the actual system container manager.
### `pkg/containermanager/providers/<provider>.go`
Actual implementation of a container manager (examples: `docker`, `podman`, `lxc`, etc).
@@ -1,711 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-3.0-only
#
# This file is part of the distrobox project:
# https://github.com/89luca89/distrobox
#
# Copyright (C) 2021 distrobox contributors
#
# distrobox is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3
# as published by the Free Software Foundation.
#
# distrobox is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with distrobox; if not, see <http://www.gnu.org/licenses/>.
# POSIX
# Expected env variables:
# HOME
# USER
# DISTROBOX_ENTER_PATH
# DISTROBOX_HOST_HOME
# Ensure we have our env variables correctly set
[ -z "${USER}" ] && USER="$(id -run)"
[ -z "${HOME}" ] && HOME="$(getent passwd "${USER}" | cut -d':' -f6)"
[ -z "${SHELL}" ] && SHELL="$(getent passwd "${USER}" | cut -d':' -f7)"
# Defaults
container_name="${CONTAINER_ID:-}"
[ -z "${container_name}" ] && container_name="$(grep "name=" /run/.containerenv | cut -d'=' -f2- | tr -d '"')"
export_action=""
exported_app=""
exported_app_label=""
exported_bin=""
exported_delete=0
extra_flags=""
enter_flags=""
# Use DBX_HOST_HOME if defined, else fallback to HOME
# DBX_HOST_HOME is set in case container is created
# with custom --home directory
host_home="${DISTROBOX_HOST_HOME:-"${HOME}"}"
dest_path="${DISTROBOX_EXPORT_PATH:-${host_home}/.local/bin}"
is_sudo=0
rootful=""
sudo_prefix=""
verbose=0
version="1.8.2.4"
sudo_askpass_path="${dest_path}/distrobox_sudo_askpass"
sudo_askpass_script="#!/bin/sh
if command -v zenity 2>&1 > /dev/null; then
zenity --password
elif command -v kdialog 2>&1 > /dev/null; then
kdialog --password 'A password is required...'
else
exit 127
fi"
# We depend on some commands, let's be sure we have them
base_dependencies="basename find grep sed"
for dep in ${base_dependencies}; do
if ! command -v "${dep}" > /dev/null; then
printf >&2 "Missing dependency: %s\n" "${dep}"
exit 127
fi
done
# show_help will print usage to stdout.
# Arguments:
# None
# Expected global variables:
# version: distrobox version
# Expected env variables:
# None
# Outputs:
# print usage with examples.
show_help()
{
cat << EOF
distrobox version: ${version}
Usage:
distrobox-export --app mpv [--extra-flags "flags"] [--enter-flags "flags"] [--delete] [--sudo]
distrobox-export --bin /path/to/bin [--export-path ~/.local/bin] [--extra-flags "flags"] [--enter-flags "flags"] [--delete] [--sudo]
Options:
--app/-a: name of the application to export or absolute path to desktopfile to export
--bin/-b: absolute path of the binary to export
--list-apps: list applications exported from this container
--list-binaries: list binaries exported from this container, use -ep to specify custom paths to search
--delete/-d: delete exported application or binary
--export-label/-el: label to add to exported application name.
Use "none" to disable.
Defaults to (on \$container_name)
--export-path/-ep: path where to export the binary
--extra-flags/-ef: extra flags to add to the command
--enter-flags/-nf: flags to add to distrobox-enter
--sudo/-S: specify if the exported item should be run as sudo
--help/-h: show this message
--verbose/-v: show more verbosity
--version/-V: show version
EOF
}
# Parse arguments
while :; do
case $1 in
-h | --help)
# Call a "show_help" function to display a synopsis, then exit.
show_help
exit 0
;;
-v | --verbose)
shift
verbose=1
;;
-V | --version)
printf "distrobox: %s\n" "${version}"
exit 0
;;
-a | --app)
if [ -n "$2" ]; then
export_action="app"
exported_app="$2"
shift
shift
fi
;;
-b | --bin)
if [ -n "$2" ]; then
export_action="bin"
exported_bin="$2"
shift
shift
fi
;;
--list-apps)
export_action="list-apps"
exported_bin="null"
shift
;;
--list-binaries)
export_action="list-binaries"
exported_bin="null"
shift
;;
-S | --sudo)
is_sudo=1
shift
;;
-el | --export-label)
if [ -n "$2" ]; then
exported_app_label="$2"
shift
shift
fi
;;
-ep | --export-path)
if [ -n "$2" ]; then
dest_path="$2"
shift
shift
fi
;;
-ef | --extra-flags)
if [ -n "$2" ]; then
extra_flags="$2"
shift
shift
fi
;;
-nf | --enter-flags)
if [ -n "$2" ]; then
enter_flags="$2"
shift
shift
fi
;;
-d | --delete)
exported_delete=1
shift
;;
-*) # Invalid options.
printf >&2 "ERROR: Invalid flag '%s'\n\n" "$1"
show_help
exit 1
;;
*) # Default case: If no more options then break out of the loop.
break ;;
esac
done
set -o errexit
set -o nounset
# set verbosity
if [ "${verbose}" -ne 0 ]; then
set -o xtrace
fi
# Ensure we can write stuff there
if [ ! -e "${dest_path}" ]; then
mkdir -p "${dest_path}"
fi
# Check we're running inside a container and not on the host.
if [ ! -f /run/.containerenv ] && [ ! -f /.dockerenv ] && [ -z "${container:-}" ]; then
printf >&2 "You must run %s inside a container!\n" " $(basename "$0")"
exit 126
fi
# Check if we're in a rootful or rootless container.
if grep -q "rootless=0" /run/.containerenv 2> /dev/null; then
rootful="--root"
# We need an askpass script for SUDO_ASKPASS, to launch graphical apps
# from the drawer
if [ ! -e "${sudo_askpass_path}" ]; then
echo "${sudo_askpass_script}" > "${sudo_askpass_path}"
chmod +x "${sudo_askpass_path}"
fi
fi
# We're working with HOME, so we must run as USER, not as root.
if [ "$(id -u)" -eq 0 ]; then
printf >&2 "You must not run %s as root!\n" " $(basename "$0")"
exit 1
fi
# Ensure we're not receiving more than one action at time.
if [ -n "${exported_app}" ] && [ -n "${exported_bin}" ]; then
printf >&2 "Error: Invalid arguments, choose only one action below.\n"
printf >&2 "Error: You can only export one thing at time.\n"
exit 2
fi
# Filter enter_flags and remove redundant options
if [ -n "${enter_flags}" ]; then
# shellcheck disable=SC2086
set -- ${enter_flags}
filtered_flags=""
# Inform user that certain flags are redundant
while [ $# -gt 0 ]; do
case "$1" in
--root | -r)
printf >&2 "Warning: %s argument will be set automatically and should be removed.\n" "${1}"
;;
--name | -n)
printf >&2 "Warning: %s argument will be set automatically and should be removed.\n" "${1}"
shift
;;
*)
filtered_flags="${filtered_flags} $1"
;;
esac
shift
done
enter_flags="${filtered_flags}"
fi
# Command to execute
container_command_suffix="'${exported_bin}' ${extra_flags} \"\$@\""
# Check if exported application/binary should be run with sudo privileges
if [ "${is_sudo}" -ne 0 ]; then
sudo_prefix="sudo -S"
if ! ${sudo_prefix} test > /dev/null 2>&1; then
sudo_prefix="sudo"
fi
# Edge case for systems with doas
if command -v doas > /dev/null >&1; then
sudo_prefix="doas"
container_command_suffix="sh -l -c \"'${exported_bin}' ${extra_flags} \$@\""
fi
# Edge case for systems without sudo
if command -v su-exec > /dev/null >&1; then
sudo_prefix="su-exec root"
container_command_suffix="sh -l -c \"'${exported_bin}' ${extra_flags} \$@\""
fi
fi
# Prefix to add to an existing command to work through the container
container_command_prefix="${DISTROBOX_ENTER_PATH:-"distrobox-enter"} ${rootful} -n ${container_name} ${enter_flags} -- ${sudo_prefix} "
if [ -n "${rootful}" ]; then
container_command_prefix="env SUDO_ASKPASS=\"${sudo_askpass_path}\" DBX_SUDO_PROGRAM=\"sudo --askpass\" ${container_command_prefix}"
fi
if [ -z "${exported_app_label}" ]; then
exported_app_label=" (on ${container_name})"
elif [ "${exported_app_label}" = "none" ]; then
exported_app_label=""
else
# Add a leading space so that we can have "NAME LABEL" in the entry
exported_app_label=" ${exported_app_label}"
fi
# generate_script will generate a script from template. This script will wrap the
# exported binary in order to ensure it will be executed in the right container.
# Arguments:
# None
# Expected global variables:
# CONTAINER_ID: id of the current container
# container_command_suffix: string to postpone to the command to launch
# container_name: string name of this container
# dest_path: string path where to export the binary
# enter_flags: string extra flags to append to the distrobox enter command
# exported_bin: string path to the binary to export
# exported_delete: bool delete the binary exported
# extra_flags: string extra flags to append to the exported app command
# rootful: bool if this is a rootful container
# sudo_prefix: string sudo command to prepend to the exported command
# Expected env variables:
# None
# Outputs:
# print generated script.
generate_script()
{
cat << EOF
#!/bin/sh
# distrobox_binary
# name: ${container_name}
if [ -z "\${CONTAINER_ID}" ]; then
exec "${DISTROBOX_ENTER_PATH:-"distrobox-enter"}" ${rootful} -n ${container_name} ${enter_flags} -- ${sudo_prefix} ${container_command_suffix}
elif [ -n "\${CONTAINER_ID}" ] && [ "\${CONTAINER_ID}" != "${container_name}" ]; then
exec distrobox-host-exec '${dest_path}/$(basename "${exported_bin}")' "\$@"
else
exec ${sudo_prefix} '${exported_bin}' "\$@"
fi
EOF
return $?
}
# export_binary will export selected binary to destination directory.
# the following function will use generate_script to create a shell script in
# dest_path that will execute the exported binary in the selected distrobox.
#
# Arguments:
# None
# Expected global variables:
# CONTAINER_ID: id of the current container
# container_name: string name of this container
# dest_path: string path where to export the binary
# exported_bin: string path to the binary to export
# exported_delete: bool delete the binary exported
# Expected env variables:
# None
# Outputs:
# a generated_script in dest_path
# or error code.
export_binary()
{
# Ensure the binary we're exporting is installed
if [ ! -f "${exported_bin}" ]; then
printf >&2 "Error: cannot find %s.\n" "${exported_bin}"
return 127
fi
# generate dest_file path
dest_file="${dest_path}/$(basename "${exported_bin}")"
# create the binary destination path if it doesn't exist
mkdir -p "${dest_path}"
# If we're deleting it, just do it and exit
if [ "${exported_delete}" -ne 0 ]; then
# ensure it's a distrobox exported binary
if ! grep -q "distrobox_binary" "${dest_file}"; then
printf >&2 "Error: %s is not exported.\n" "${exported_bin}"
return 1
fi
if rm -f "${dest_file}"; then
printf "%s from %s removed successfully from %s.\nOK!\n" \
"${exported_bin}" "${container_name}" "${dest_path}"
return 0
fi
return 1
fi
# test if we have writing rights on the file
if ! touch "${dest_file}"; then
printf >&2 "Error: cannot create destination file %s.\n" "${dest_file}"
return 1
fi
# create the script from template and write to file
if generate_script > "${dest_file}"; then
chmod +x "${dest_file}"
printf "%s from %s exported successfully in %s.\nOK!\n" \
"${exported_bin}" "${container_name}" "${dest_path}"
return 0
fi
# Unknown error.
return 3
}
# export_application will export input graphical application to the host.
# the following function will scan the distrobox for desktop and icon files for
# the selected application. It will then put the needed icons in the host's icons
# directory and create a new .desktop file that will execute the selected application
# in the distrobox.
#
# Arguments:
# None
# Expected global variables:
# CONTAINER_ID: id of the current container
# container_command_prefix: string to prepend to the command to launch
# container_name: string name of this container
# exported_app: string name of the app to export
# exported_app_label: string label to use to mark the exported app
# exported_delete: bool if we want to delete or not
# extra_flags: string extra flags to append to the exported app command
# host_home: home path ofr the host, where to search desktop files
# Expected env variables:
# None
# Outputs:
# needed icons in /run/host/$host_home/.local/share/icons
# needed desktop files in /run/host/$host_home/.local/share/applications
# or error code.
export_application()
{
canon_dirs=""
# In case we're explicitly going for a full desktopfile path
if [ -e "${exported_app}" ]; then
desktop_files="${exported_app}"
else
IFS=":"
if [ -n "${XDG_DATA_DIRS}" ]; then
for xdg_data_dir in ${XDG_DATA_DIRS}; do
[ -d "${xdg_data_dir}/applications" ] && canon_dirs="${canon_dirs} ${xdg_data_dir}/applications"
done
else
[ -d /usr/share/applications ] && canon_dirs="/usr/share/applications"
[ -d /usr/local/share/applications ] && canon_dirs="${canon_dirs} /usr/local/share/applications"
[ -d /var/lib/flatpak/exports/share/applications ] && canon_dirs="${canon_dirs} /var/lib/flatpak/exports/share/applications"
fi
if [ -n "${XDG_DATA_HOME}" ]; then
[ -d "${XDG_DATA_HOME}/applications" ] && canon_dirs="${canon_dirs} ${XDG_DATA_HOME}/applications"
else
[ -d "${HOME}/.local/share/applications" ] && canon_dirs="${canon_dirs} ${HOME}/.local/share/applications"
fi
unset IFS
# In this phase we search for applications to export.
# First find command will grep through all files in the canonical directories
# and only list files that contain the $exported_app, excluding those that
# already contains a distrobox-enter command. So skipping already exported apps.
# Second find will list all files that contain the name specified, so that
# it is possible to export an app not only by its executable name but also
# by its launcher name.
desktop_files=$(
# shellcheck disable=SC2086
find ${canon_dirs} -type f -print -o -type l -print | sed 's/./\\&/g' |
xargs -I{} grep -l -e "Exec=.*${exported_app}.*" -e "Name=.*${exported_app}.*" "{}" | sed 's/./\\&/g' |
xargs -I{} grep -L -e "Exec=.*${DISTROBOX_ENTER_PATH:-"distrobox.*enter"}.*" "{}" | sed 's/./\\&/g' |
xargs -I{} printf "%s¤" "{}"
)
fi
# Ensure the app we're exporting is installed
# Check that we found some desktop files first.
if [ -z "${desktop_files}" ]; then
printf >&2 "Error: cannot find any desktop files.\n"
printf >&2 "Error: trying to export a non-installed application.\n"
return 127
fi
# Find icons by using the Icon= specification. If it's only a name, we'll
# search for the file, if it's already a path, just grab it.
icon_files=""
IFS="¤"
for desktop_file in ${desktop_files}; do
if [ -z "${desktop_file}" ]; then
continue
fi
icon_name="$(grep Icon= "${desktop_file}" | cut -d'=' -f2- | paste -sd "¤" -)"
for icon in ${icon_name}; do
if case "${icon_name}" in "/"*) true ;; *) false ;; esac &&
[ -e "${icon_name}" ]; then
# In case it's an hard path, conserve it and continue
icon_files="${icon_files}¤${icon_name}"
else
# If it's not an hard path, find all files in the canonical paths.
icon_files="${icon_files}¤$(find \
/usr/share/icons \
/usr/share/pixmaps \
/var/lib/flatpak/exports/share/icons -iname "*${icon}*" \
-printf "%p¤" 2> /dev/null || :)"
fi
done
# remove leading delimiter
icon_files=${icon_files#¤}
done
# create applications dir if not existing
mkdir -p "/run/host${host_home}/.local/share/applications"
# copy icons in home directory
icon_file_absolute_path=""
IFS="¤"
for icon_file in ${icon_files}; do
if [ -z "${icon_file}" ]; then
continue
fi
# replace canonical paths with equivalent paths in HOME
icon_home_directory="$(dirname "${icon_file}" |
sed "s|/usr/share/|\/run\/host\/${host_home}/.local/share/|g" |
sed "s|/var/lib/flatpak/exports/share|\/run\/host\/${host_home}/.local/share/|g" |
sed "s|pixmaps|icons|g")"
# check if we're exporting an icon which is not in a canonical path
if [ "${icon_home_directory}" = "$(dirname "${icon_file}")" ]; then
icon_home_directory="${host_home}/.local/share/icons/"
icon_file_absolute_path="${icon_home_directory}$(basename "${icon_file}")"
fi
# check if we're exporting or deleting
if [ "${exported_delete}" -ne 0 ]; then
# we need to remove, not export
rm -rf "${icon_home_directory:?}"/"$(basename "${icon_file:?}")"
continue
fi
# we wanto to export the application's icons
mkdir -p "${icon_home_directory}"
if [ ! -e "${icon_home_directory}/$(basename "${icon_file}")" ] && [ -e "$(realpath "${icon_file}")" ]; then
cp -rf "$(realpath "${icon_file}")" "${icon_home_directory}"
fi
done
# create desktop files for the distrobox
IFS="¤"
for desktop_file in ${desktop_files}; do
if [ -z "${desktop_file}" ]; then
continue
fi
desktop_original_file="$(basename "${desktop_file}")"
desktop_home_file="${container_name}-$(basename "${desktop_file}")"
# check if we're exporting or deleting
if [ "${exported_delete}" -ne 0 ]; then
rm -f "/run/host${host_home}/.local/share/applications/${desktop_original_file}"
rm -f "/run/host${host_home}/.local/share/applications/${desktop_home_file}"
# we're done, go to next
continue
fi
# Add command_prefix
# Add extra flags
# Add closing quote
# If a TryExec is present, we have to fake it as it will not work
# through the container separation
sed "s|^Exec=\(.*\)|Exec=${container_command_prefix} \1 |g" "${desktop_file}" |
sed "s|\(%.*\)|${extra_flags} \1|g" |
sed "/^TryExec=.*/d" |
sed "/^DBusActivatable=true/d" |
sed "s|Name.*|&${exported_app_label}|g" \
> "/run/host${host_home}/.local/share/applications/${desktop_home_file}"
# in the end we add the final quote we've opened in the "container_command_prefix"
if ! grep -q "StartupWMClass" "/run/host${host_home}/.local/share/applications/${desktop_home_file}"; then
printf "StartupWMClass=%s\n" "${exported_app}" >> "\
/run/host${host_home}/.local/share/applications/${desktop_home_file}"
fi
# In case of an icon in a non canonical path, we need to replace the path
# in the desktop file.
if [ -n "${icon_file_absolute_path}" ]; then
sed -i "s|Icon=.*|Icon=${icon_file_absolute_path}|g" \
"/run/host${host_home}/.local/share/applications/${desktop_home_file}"
# we're done, go to next
continue
fi
# In case of an icon in a canonical path, but specified as an absolute
# we need to replace the path in the desktop file.
sed -i "s|Icon=/usr/share/|Icon=/run/host${host_home}/.local/share/|g" \
"/run/host${host_home}/.local/share/applications/${desktop_home_file}"
sed -i "s|pixmaps|icons|g" \
"/run/host${host_home}/.local/share/applications/${desktop_home_file}"
done
# Update the desktop files database to ensure exported applications will
# show up in the taskbar/desktop menu/whatnot right after running this
# script.
/usr/bin/distrobox-host-exec --yes update-desktop-database "${host_home}/.local/share/applications" > /dev/null 2>&1 || :
if [ "${exported_delete}" -ne 0 ]; then
printf "Application %s successfully un-exported.\nOK!\n" "${exported_app}"
printf "%s will disappear from your applications list in a few seconds.\n" "${exported_app}"
else
printf "Application %s successfully exported.\nOK!\n" "${exported_app}"
printf "%s will appear in your applications list in a few seconds.\n" "${exported_app}"
fi
}
# list_exported_applications will print all exported applications in canonical directories.
# the following function will list exported desktop files from this container.
#
# Arguments:
# None
# Expected global variables:
# host_home: home path ofr the host, where to search desktop files
# CONTAINER_ID: id of the current container
# Expected env variables:
# None
# Outputs:
# a list of exported apps
# or error code.
list_exported_applications()
{
# In this phase we search for applications exported.
# First find command will grep through all files in the canonical directories
# and only list files that contain the $DISTROBOX_ENTER_PATH.
desktop_files=$(
# shellcheck disable=SC2086
find "/run/host${host_home}/.local/share/applications" -type f -print -o -type l -print 2> /dev/null | sed 's/./\\&/g' |
xargs -I{} grep -l -e "Exec=.*${DISTROBOX_ENTER_PATH:-"distrobox.*enter"}.*" "{}" | sed 's/./\\&/g' |
xargs -I{} printf "%s¤" "{}"
)
# Then we try to pretty print them.
IFS="¤"
for i in ${desktop_files}; do
if [ -z "${i}" ]; then
continue
fi
# Get app name, and remove label
name="$(grep -Eo 'Name=.*' "${i}" | head -n 1 | cut -d'=' -f2- | sed 's|(.*)||g')"
# Print only stuff we exported from this box!
if echo "${i}" | grep -q "${CONTAINER_ID}"; then
printf "%-20s | %-30s\n" "${name}" "${i}"
fi
done
unset IFS
}
# list_exported_binaries will print all exported binaries.
# the following function will list exported desktop files from this container.
# If no export-path is specified, it searches in the default path.
#
# Arguments:
# None
# Expected global variables:
# dest_path: destination path where to search binaries
# CONTAINER_ID: id of the current container
# Expected env variables:
# None
# Outputs:
# a list of exported apps
# or error code.
list_exported_binaries()
{
# In this phase we search for binaries exported.
# First find command will grep through all files in the canonical directories
# and only list files that contain the comment "# distrobox_binary".
binary_files=$(
find "${dest_path}" -type f -print 2> /dev/null | sed 's/./\\&/g' |
xargs -I{} grep -l -e "^# distrobox_binary" "{}" | sed 's/./\\&/g' |
xargs -I{} printf "%s¤" "{}"
)
# Then we try to pretty print them.
IFS="¤"
for i in ${binary_files}; do
if [ -z "${i}" ]; then
continue
fi
# Get original binary name
name="$(grep -B1 "fi" "${i}" | grep exec | cut -d' ' -f2)"
# Print only stuff we exported from this box!
if grep "^# name:.*" "${i}" | grep -q "${CONTAINER_ID}"; then
printf "%-20s | %-30s\n" "${name}" "${i}"
fi
done
unset IFS
}
# Main routine
case "${export_action}" in
app)
export_application
;;
bin)
export_binary
;;
list-apps)
list_exported_applications
;;
list-binaries)
list_exported_binaries
;;
*)
printf >&2 "Invalid arguments, choose an action below.\n"
show_help
exit 2
;;
esac
@@ -1,234 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-3.0-only
#
# This file is part of the distrobox project:
# https://github.com/89luca89/distrobox
#
# Copyright (C) 2022 distrobox contributors
#
# distrobox is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3
# as published by the Free Software Foundation.
#
# distrobox is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with distrobox; if not, see <http://www.gnu.org/licenses/>.
# Ensure we have our env variables correctly set
[ -z "${USER}" ] && USER="$(id -run)"
[ -z "${HOME}" ] && HOME="$(getent passwd "${USER}" | cut -d':' -f6)"
[ -z "${SHELL}" ] && SHELL="$(getent passwd "${USER}" | cut -d':' -f7)"
# Defaults
host_command=""
non_interactive=0
# If we're in a non-interactive shell, let's act accordingly
if [ ! -t 1 ] ||
! tty > /dev/null 2>&1; then
non_interactive=1
fi
distrobox_host_exec_default_command="${SHELL:-/bin/sh}"
host_spawn_version="v1.6.0"
download_command=""
sudo_command=""
verbose=0
version="1.8.2.4"
# show_help will print usage to stdout.
# Arguments:
# None
# Expected global variables:
# version: distrobox version
# Expected env variables:
# None
# Outputs:
# print usage with examples.
show_help()
{
cat << EOF
distrobox version: ${version}
Usage:
distrobox-host-exec [command [arguments]]
distrobox-host-exec ls
distrobox-host-exec bash -l
distrobox-host-exec flatpak run org.mozilla.firefox
distrobox-host-exec podman ps -a
Options:
--help/-h: show this message
--verbose/-v: show more verbosity
--version/-V: show version
--yes/-Y: Automatically answer yes to prompt:
host-spawn will be installed on the guest system
if host-spawn is not detected.
This behaviour is default when running in a non-interactive shell.
EOF
}
# If we're a symlink to a command, use that as command to exec, and skip arg parsing.
if [ "$(basename "${0}")" != "distrobox-host-exec" ]; then
host_command="$(basename "${0}")"
fi
# Parse arguments
if [ -z "${host_command}" ]; then
# Skip argument parsing if we're a symlink
while :; do
case $1 in
-h | --help)
# Call a "show_help" function to display a synopsis, then exit.
show_help
exit 0
;;
-v | --verbose)
verbose=1
shift
;;
-V | --version)
printf "distrobox: %s\n" "${version}"
printf "host-spawn: %s\n" "${host_spawn_version}"
exit 0
;;
-Y | --yes)
non_interactive=1
shift
;;
--) # End of all options.
shift
;;
-*) # Invalid options.
printf >&2 "ERROR: Invalid flag '%s'\n\n" "$1"
show_help
exit 1
;;
*)
if [ -n "$1" ]; then
host_command=$1
shift
fi
break
;;
esac
done
fi
set -o errexit
set -o nounset
# set verbosity
if [ "${verbose}" -ne 0 ]; then
set -o xtrace
fi
# Check we're running inside a container and not on the host
if [ ! -f /run/.containerenv ] && [ ! -f /.dockerenv ] && [ -z "${container:-}" ]; then
printf >&2 "You must run %s inside a container!\n" " $(basename "$0")"
exit 126
fi
if [ -z "${host_command}" ]; then
host_command="${distrobox_host_exec_default_command}"
fi
if [ "$(id -ru)" -ne 0 ]; then
if command -v sudo 2> /dev/null > /dev/null; then
sudo_command="sudo"
else
sudo_command="su -l -c"
fi
fi
if command -v curl > /dev/null 2>&1; then
download_command="curl -sLfo"
elif command -v wget > /dev/null 2>&1; then
download_command="wget -qO"
fi
# Normalize architecture name to comply to golang/release naming
architecture="$(uname -m)"
if echo "${architecture}" | grep -q armv; then
architecture="$(echo "${architecture}" | grep -Eo "armv[0-9]+")"
fi
# Setup host-spawn as a way to execute commands back on the host
if ! command -v host-spawn > /dev/null ||
[ "$(printf "%s\n%s\n" "${host_spawn_version}" "$(host-spawn --version)" |
sort -V | head -n 1)" != "${host_spawn_version}" ]; then
# if non-interactive flag flag hasn't been set
if [ "${non_interactive}" -eq 0 ]; then
# Prompt to download it.
printf "Warning: host-spawn not found or version is too old!\n"
printf "Do you want to install host-spawn utility? [Y/n] "
read -r response
response=${response:-"Y"}
else
response="yes"
fi
# Accept only y,Y,Yes,yes,n,N,No,no.
case "${response}" in
y | Y | Yes | yes | YES)
# Download matching version with current distrobox
if ! ${download_command} /tmp/host-spawn \
"https://github.com/1player/host-spawn/releases/download/${host_spawn_version}/host-spawn-${architecture}"; then
printf "Error: Cannot download host-spawn\n"
exit 1
fi
if [ -e /tmp/host-spawn ]; then
${sudo_command} sh -c "mv /tmp/host-spawn /usr/bin/"
${sudo_command} sh -c "chmod +x /usr/bin/host-spawn"
fi
;;
n | N | No | no | NO)
printf "Installation aborted, please install host-spawn.\n"
exit 0
;;
*) # Default case: If no more options then break out of the loop.
printf >&2 "Invalid input.\n"
printf >&2 "The available choices are: y,Y,Yes,yes,YES or n,N,No,no,NO.\nExiting.\n"
exit 1
;;
esac
fi
# This makes host-spawn work on initful containers, where the dbus session is
# separate from the host, we point the dbus session straight to the host's socket
# in order to talk with the org.freedesktop.Flatpak.Development.HostCommand on the host
[ -z "${XDG_RUNTIME_DIR:-}" ] && XDG_RUNTIME_DIR="/run/user/$(id -ru)"
[ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ] && DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -ru)/bus"
XDG_RUNTIME_DIR="/run/host/${XDG_RUNTIME_DIR}"
DBUS_SESSION_BUS_ADDRESS="unix:path=/run/host/$(echo "${DBUS_SESSION_BUS_ADDRESS}" | cut -d '=' -f2-)"
###
# This workaround is needed because of a bug in gio (used by xdg-open) where
# a race condition happens when allocating a pty, leading to the command
# being killed before having time to be executed.
#
# https://gitlab.gnome.org/GNOME/glib/-/issues/2695
# https://github.com/1player/host-spawn/issues/7
#
# As an (ugly) workaround, we will not allocate a pty for those commands.
###
# Also, we don't initialize a pty, if we're not in a tty.
if [ "$(basename "${host_command}")" = "xdg-open" ] ||
[ "$(basename "${host_command}")" = "gio" ] ||
[ "$(basename "${host_command}")" = "flatpak" ] ||
[ ! -t 1 ] ||
! tty > /dev/null 2>&1; then
host-spawn --no-pty "${host_command}" "$@"
# Exit here, we don't continue execution
exit $?
fi
host-spawn "${host_command}" "$@"
# Exit here, we don't continue execution
exit $?
File diff suppressed because it is too large. Load diff
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.