first commit
This commit is contained in:
108
profiles/desktop/.local/bin/distrobox
Executable file
108
profiles/desktop/.local/bin/distrobox
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/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
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
|
||||
version="1.8.2.2"
|
||||
|
||||
# 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}
|
||||
|
||||
Choose one of the available commands:
|
||||
assemble
|
||||
create
|
||||
enter
|
||||
list | ls
|
||||
rm
|
||||
stop
|
||||
upgrade
|
||||
ephemeral
|
||||
generate-entry
|
||||
version
|
||||
help
|
||||
EOF
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
show_help
|
||||
exit
|
||||
fi
|
||||
|
||||
distrobox_path="$(dirname "${0}")"
|
||||
distrobox_command="${1}"
|
||||
shift
|
||||
|
||||
# Simple wrapper to the distrobox utilities.
|
||||
# We just detect the 1st argument and launch the matching distrobox utility.
|
||||
case "${distrobox_command}" in
|
||||
assemble)
|
||||
"${distrobox_path}"/distrobox-assemble "$@"
|
||||
;;
|
||||
create)
|
||||
"${distrobox_path}"/distrobox-create "$@"
|
||||
;;
|
||||
enter)
|
||||
"${distrobox_path}"/distrobox-enter "$@"
|
||||
;;
|
||||
ls | list)
|
||||
"${distrobox_path}"/distrobox-list "$@"
|
||||
;;
|
||||
stop)
|
||||
"${distrobox_path}"/distrobox-stop "$@"
|
||||
;;
|
||||
rm)
|
||||
"${distrobox_path}"/distrobox-rm "$@"
|
||||
;;
|
||||
upgrade)
|
||||
"${distrobox_path}"/distrobox-upgrade "$@"
|
||||
;;
|
||||
generate-entry)
|
||||
"${distrobox_path}"/distrobox-generate-entry "$@"
|
||||
;;
|
||||
ephemeral)
|
||||
"${distrobox_path}"/distrobox-ephemeral "$@"
|
||||
;;
|
||||
-V | --version | version)
|
||||
printf "distrobox: %s\n" "${version}"
|
||||
exit 0
|
||||
;;
|
||||
help | --help | -h)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*) # Default case: If no more options then break out of the loop.
|
||||
printf >&2 "Error: invalid command\n"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
793
profiles/desktop/.local/bin/distrobox-assemble
Executable file
793
profiles/desktop/.local/bin/distrobox-assemble
Executable file
@@ -0,0 +1,793 @@
|
||||
#!/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/>.
|
||||
|
||||
# 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)"
|
||||
|
||||
# POSIX
|
||||
#
|
||||
default_input_file="./distrobox.ini"
|
||||
delete=-1
|
||||
distrobox_path="$(dirname "${0}")"
|
||||
dryrun=0
|
||||
boxname=""
|
||||
input_file=""
|
||||
replace=0
|
||||
root_flag=""
|
||||
# tmpfile will be used as a little buffer to pass variables without messing up
|
||||
# quoting and escaping
|
||||
tmpfile="$(mktemp -u)"
|
||||
tmp_download_file="$(mktemp -u)"
|
||||
verbose=0
|
||||
version="1.8.2.2"
|
||||
# initializing block of variables used in the manifest
|
||||
additional_flags=""
|
||||
additional_packages=""
|
||||
entry=""
|
||||
home=""
|
||||
hostname=""
|
||||
image=""
|
||||
clone=""
|
||||
init=""
|
||||
init_hooks=""
|
||||
nvidia=""
|
||||
pre_init_hooks=""
|
||||
pull=""
|
||||
root=""
|
||||
start_now=""
|
||||
unshare_groups=""
|
||||
unshare_ipc=""
|
||||
unshare_netns=""
|
||||
unshare_process=""
|
||||
unshare_devsys=""
|
||||
unshare_all=""
|
||||
volume=""
|
||||
exported_apps=""
|
||||
exported_bins=""
|
||||
exported_bins_path="${HOME}/.local/bin"
|
||||
|
||||
# Cleanup tmpfiles on exit
|
||||
trap 'rm -f ${tmpfile} ${tmp_download_file}' EXIT
|
||||
|
||||
# Despite of running this script via SUDO/DOAS being not supported (the
|
||||
# script itself will call the appropriate tool when necessary), we still want
|
||||
# to allow people to run it as root, logged in in a shell, and create rootful
|
||||
# containers.
|
||||
#
|
||||
# SUDO_USER is a variable set by SUDO and can be used to check whether the script was called by it. Same thing for DOAS_USER, set by DOAS.
|
||||
if [ -n "${SUDO_USER}" ] || [ -n "${DOAS_USER}" ]; then
|
||||
printf >&2 "Running %s via SUDO/DOAS is not supported." "$(basename "${0}")"
|
||||
printf >&2 "Instead, please try using root=true property in the distrobox.ini file.\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Source configuration files, this is done in an hierarchy so local files have
|
||||
# priority over system defaults
|
||||
# leave priority to environment variables.
|
||||
#
|
||||
# On NixOS, for the distrobox derivation to pick up a static config file shipped
|
||||
# by the package maintainer the path must be relative to the script itself.
|
||||
self_dir="$(dirname "$(realpath "$0")")"
|
||||
nix_config_file="${self_dir}/../share/distrobox/distrobox.conf"
|
||||
|
||||
config_files="
|
||||
${nix_config_file}
|
||||
/usr/share/distrobox/distrobox.conf
|
||||
/usr/share/defaults/distrobox/distrobox.conf
|
||||
/usr/etc/distrobox/distrobox.conf
|
||||
/usr/local/share/distrobox/distrobox.conf
|
||||
/etc/distrobox/distrobox.conf
|
||||
${XDG_CONFIG_HOME:-"${HOME}/.config"}/distrobox/distrobox.conf
|
||||
${HOME}/.distroboxrc
|
||||
"
|
||||
for config_file in ${config_files}; do
|
||||
# Shellcheck will give error for sourcing a variable file as it cannot follow
|
||||
# it. We don't care so let's disable this linting for now.
|
||||
# shellcheck disable=SC1090
|
||||
[ -e "${config_file}" ] && . "$(realpath "${config_file}")"
|
||||
done
|
||||
|
||||
[ -n "${DBX_VERBOSE}" ] && verbose="${DBX_VERBOSE}"
|
||||
|
||||
# Fixup variable=[true|false], in case we find it in the config file(s)
|
||||
[ "${verbose}" = "true" ] && verbose=1
|
||||
[ "${verbose}" = "false" ] && verbose=0
|
||||
|
||||
# show_help will print usage to stdout.
|
||||
# Arguments:
|
||||
# None
|
||||
# Expected global variables:
|
||||
# version: string distrobox version
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# print usage with examples.
|
||||
show_help()
|
||||
{
|
||||
cat << EOF
|
||||
distrobox version: ${version}
|
||||
|
||||
Usage:
|
||||
|
||||
distrobox assemble create
|
||||
distrobox assemble rm
|
||||
distrobox assemble create --file /path/to/file.ini
|
||||
distrobox assemble rm --file /path/to/file.ini
|
||||
distrobox assemble create --replace --file /path/to/file.ini
|
||||
|
||||
Options:
|
||||
|
||||
--file: path or URL to the distrobox manifest/ini file
|
||||
--name/-n: run against a single entry in the manifest/ini file
|
||||
--replace/-R: replace already existing distroboxes with matching names
|
||||
--dry-run/-d: only print the container manager command generated
|
||||
--verbose/-v: show more verbosity
|
||||
--version/-V: show version
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
while :; do
|
||||
case $1 in
|
||||
create)
|
||||
delete=0
|
||||
shift
|
||||
;;
|
||||
rm)
|
||||
delete=1
|
||||
shift
|
||||
;;
|
||||
--file)
|
||||
# Call a "show_help" function to display a synopsis, then exit.
|
||||
if [ -n "$2" ]; then
|
||||
input_file="${2}"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
-n | --name)
|
||||
# Call a "show_help" function to display a synopsis, then exit.
|
||||
if [ -n "$2" ]; then
|
||||
boxname="${2}"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
-h | --help)
|
||||
# Call a "show_help" function to display a synopsis, then exit.
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
-d | --dry-run)
|
||||
shift
|
||||
dryrun=1
|
||||
;;
|
||||
-v | --verbose)
|
||||
verbose=1
|
||||
shift
|
||||
;;
|
||||
-R | --replace)
|
||||
replace=1
|
||||
shift
|
||||
;;
|
||||
-V | --version)
|
||||
printf "distrobox: %s\n" "${version}"
|
||||
exit 0
|
||||
;;
|
||||
--) # End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*) # 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.
|
||||
# If we have a flagless option and container_name is not specified
|
||||
# then let's accept argument as container_name
|
||||
if [ -n "$1" ]; then
|
||||
input_file="$1"
|
||||
shift
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set verbosity
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
set -o xtrace
|
||||
fi
|
||||
|
||||
# check if we're getting the right inputs
|
||||
if [ "${delete}" -eq -1 ]; then
|
||||
printf >&2 "Please specify create or rm.\n"
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Fallback to distrobox.ini if no file is passed
|
||||
if [ -z "${input_file}" ]; then
|
||||
input_file="${default_input_file}"
|
||||
fi
|
||||
|
||||
# Check if file effectively exists
|
||||
if [ ! -e "${input_file}" ]; then
|
||||
|
||||
if command -v curl > /dev/null 2>&1; then
|
||||
download="curl --connect-timeout 3 --retry 1 -sLo"
|
||||
elif command -v wget > /dev/null 2>&1; then
|
||||
download="wget --timeout=3 --tries=1 -qO"
|
||||
fi
|
||||
|
||||
if ! ${download} - "${input_file}" > "${tmp_download_file}"; then
|
||||
printf >&2 "File %s does not exist.\n" "${input_file}"
|
||||
exit 1
|
||||
else
|
||||
input_file="${tmp_download_file}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# run_distrobox will create distrobox with parameters parsed from ini file.
|
||||
# Arguments:
|
||||
# name: name of the distrobox.
|
||||
# Expected global variables:
|
||||
# boxname: string name of the target container
|
||||
# tmpfile: string name of the tmpfile to read
|
||||
# delete: bool delete container
|
||||
# replace: bool replace container
|
||||
# dryrun: bool dryrun (only print, no execute)
|
||||
# verbose: bool verbose
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# execution of the proper distrobox-create command.
|
||||
run_distrobox()
|
||||
{
|
||||
name="${1}"
|
||||
additional_flags=""
|
||||
additional_packages=""
|
||||
entry=""
|
||||
home=""
|
||||
hostname=""
|
||||
image=""
|
||||
clone=""
|
||||
init=""
|
||||
init_hooks=""
|
||||
nvidia=""
|
||||
pre_init_hooks=""
|
||||
pull=""
|
||||
root=""
|
||||
start_now=""
|
||||
unshare_groups=""
|
||||
unshare_ipc=""
|
||||
unshare_netns=""
|
||||
unshare_process=""
|
||||
unshare_devsys=""
|
||||
unshare_all=""
|
||||
volume=""
|
||||
exported_apps=""
|
||||
exported_bins=""
|
||||
exported_bins_path="${HOME}/.local/bin"
|
||||
|
||||
# Skip item if --name used and no match is found
|
||||
if [ "${boxname}" != "" ] && [ "${boxname}" != "${name}" ]; then
|
||||
rm -f "${tmpfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Source the current block variables
|
||||
if [ -e "${tmpfile}" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "${tmpfile}" && rm -f "${tmpfile}"
|
||||
fi
|
||||
|
||||
if [ -n "${root}" ] && [ "${root}" -eq 1 ]; then
|
||||
root_flag="--root"
|
||||
fi
|
||||
|
||||
# We're going to delete, not create!
|
||||
if [ "${delete}" -ne 0 ] || [ "${replace}" -ne 0 ]; then
|
||||
printf " - Deleting %s...\n" "${name}"
|
||||
|
||||
if [ "${dryrun}" -eq 0 ]; then
|
||||
# shellcheck disable=SC2086,2248
|
||||
"${distrobox_path}"/distrobox rm ${root_flag} -f "${name}" > /dev/null || :
|
||||
fi
|
||||
|
||||
if [ "${delete}" -ne 0 ]; then
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# We're going to create!
|
||||
printf " - Creating %s...\n" "${name}"
|
||||
|
||||
# If distrobox already exist, and we have replace enabled, destroy the container
|
||||
# we have to recreate it.
|
||||
# shellcheck disable=SC2086,2248
|
||||
if "${distrobox_path}"/distrobox-list ${root_flag} | grep -qw " ${name} " && [ "${dryrun}" -eq 0 ]; then
|
||||
printf >&2 "%s already exists\n" "${name}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Now we dynamically generate the distrobox-create command based on the
|
||||
# declared flags.
|
||||
result_command="${distrobox_path}/distrobox-create --yes"
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
result_command="${result_command} -v"
|
||||
fi
|
||||
if [ -n "${name}" ]; then
|
||||
result_command="${result_command} --name $(sanitize_variable "${name}")"
|
||||
fi
|
||||
if [ -n "${image}" ]; then
|
||||
result_command="${result_command} --image $(sanitize_variable "${image}")"
|
||||
fi
|
||||
if [ -n "${clone}" ]; then
|
||||
result_command="${result_command} --clone $(sanitize_variable "${clone}")"
|
||||
fi
|
||||
if [ -n "${init}" ] && [ "${init}" -eq 1 ]; then
|
||||
result_command="${result_command} --init"
|
||||
fi
|
||||
if [ -n "${root}" ] && [ "${root}" -eq 1 ]; then
|
||||
result_command="${result_command} --root"
|
||||
fi
|
||||
if [ -n "${pull}" ] && [ "${pull}" -eq 1 ]; then
|
||||
result_command="${result_command} --pull"
|
||||
fi
|
||||
if [ -n "${entry}" ] && [ "${entry}" -eq 0 ]; then
|
||||
result_command="${result_command} --no-entry"
|
||||
fi
|
||||
if [ -n "${nvidia}" ] && [ "${nvidia}" -eq 1 ]; then
|
||||
result_command="${result_command} --nvidia"
|
||||
fi
|
||||
if [ -n "${unshare_netns}" ] && [ "${unshare_netns}" -eq 1 ]; then
|
||||
result_command="${result_command} --unshare-netns"
|
||||
fi
|
||||
if [ -n "${unshare_groups}" ] && [ "${unshare_groups}" -eq 1 ]; then
|
||||
result_command="${result_command} --unshare-groups"
|
||||
fi
|
||||
if [ -n "${unshare_ipc}" ] && [ "${unshare_ipc}" -eq 1 ]; then
|
||||
result_command="${result_command} --unshare-ipc"
|
||||
fi
|
||||
if [ -n "${unshare_process}" ] && [ "${unshare_process}" -eq 1 ]; then
|
||||
result_command="${result_command} --unshare-process"
|
||||
fi
|
||||
if [ -n "${unshare_devsys}" ] && [ "${unshare_devsys}" -eq 1 ]; then
|
||||
result_command="${result_command} --unshare-devsys"
|
||||
fi
|
||||
if [ -n "${unshare_all}" ] && [ "${unshare_all}" -eq 1 ]; then
|
||||
result_command="${result_command} --unshare-all"
|
||||
fi
|
||||
if [ -n "${home}" ]; then
|
||||
result_command="${result_command} --home $(sanitize_variable "${home}")"
|
||||
fi
|
||||
if [ -n "${hostname}" ]; then
|
||||
result_command="${result_command} --hostname $(sanitize_variable "${hostname}")"
|
||||
fi
|
||||
if [ -n "${init_hooks}" ]; then
|
||||
IFS="¤"
|
||||
args=": ;"
|
||||
separator=""
|
||||
for arg in ${init_hooks}; do
|
||||
if [ -z "${arg}" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Convert back from base64
|
||||
arg="$(echo "${arg}" | base64 -d)"
|
||||
args="${args} ${separator} ${arg}"
|
||||
|
||||
# Prepare for the next line, if we already have a ';' or '&&', do nothing
|
||||
# else prefer adding '&&'
|
||||
if ! echo "${arg}" | grep -qE ';[[:space:]]{0,1}$' &&
|
||||
! echo "${arg}" | grep -qE '&&[[:space:]]{0,1}$'; then
|
||||
separator="&&"
|
||||
else
|
||||
separator=""
|
||||
fi
|
||||
done
|
||||
result_command="${result_command} --init-hooks $(sanitize_variable "${args}")"
|
||||
fi
|
||||
# Replicable flags
|
||||
if [ -n "${pre_init_hooks}" ]; then
|
||||
IFS="¤"
|
||||
args=": ;"
|
||||
separator=""
|
||||
for arg in ${pre_init_hooks}; do
|
||||
if [ -z "${arg}" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Convert back from base64
|
||||
arg="$(echo "${arg}" | base64 -d)"
|
||||
args="${args} ${separator} ${arg}"
|
||||
|
||||
# Prepare for the next line, if we already have a ';' or '&&', do nothing
|
||||
# else prefer adding '&&'
|
||||
if ! echo "${arg}" | grep -qE ';[[:space:]]{0,1}$' &&
|
||||
! echo "${arg}" | grep -qE '&&[[:space:]]{0,1}$'; then
|
||||
separator="&&"
|
||||
else
|
||||
separator=""
|
||||
fi
|
||||
done
|
||||
result_command="${result_command} --pre-init-hooks $(sanitize_variable "${args}")"
|
||||
fi
|
||||
if [ -n "${additional_packages}" ]; then
|
||||
IFS="¤"
|
||||
args=""
|
||||
for packages in ${additional_packages}; do
|
||||
if [ -z "${packages}" ]; then
|
||||
continue
|
||||
fi
|
||||
args="${args} ${packages}"
|
||||
done
|
||||
result_command="${result_command} --additional-packages $(sanitize_variable "${args}")"
|
||||
fi
|
||||
if [ -n "${volume}" ]; then
|
||||
IFS="¤"
|
||||
for vol in ${volume}; do
|
||||
if [ -z "${vol}" ]; then
|
||||
continue
|
||||
fi
|
||||
result_command="${result_command} --volume $(sanitize_variable "${vol}")"
|
||||
done
|
||||
fi
|
||||
if [ -n "${additional_flags}" ]; then
|
||||
IFS="¤"
|
||||
for flag in ${additional_flags}; do
|
||||
if [ -z "${flag}" ]; then
|
||||
continue
|
||||
fi
|
||||
result_command="${result_command} --additional-flags $(sanitize_variable "${flag}")"
|
||||
done
|
||||
fi
|
||||
|
||||
# Execute the distrobox-create command
|
||||
if [ "${dryrun}" -ne 0 ]; then
|
||||
echo "${result_command}"
|
||||
return
|
||||
fi
|
||||
eval "${result_command}"
|
||||
|
||||
# If we need to start immediately, do it, so that the container
|
||||
# is ready to be entered.
|
||||
if [ -n "${start_now}" ] && [ "${start_now}" -eq 1 ]; then
|
||||
# Here we execute the `distrobox enter` command with a `/dev/null` stdin.
|
||||
# This is due to the fact that this command is very likely to be executed inside
|
||||
# the read loop in the prse_file function. This way we avoid stdin to be swallowed by
|
||||
# this command execution. This is valid for all the `distrobox enter` calls from now on.
|
||||
#
|
||||
# shellcheck disable=SC2086,2248
|
||||
"${distrobox_path}"/distrobox enter ${root_flag} "${name}" -- touch /dev/null < /dev/null
|
||||
fi
|
||||
|
||||
# if there are exported bins and apps declared, let's export them
|
||||
if [ -n "${exported_apps}" ] || [ -n "${exported_bins}" ]; then
|
||||
# First we start the container
|
||||
# shellcheck disable=SC2086,2248
|
||||
"${distrobox_path}"/distrobox enter ${root_flag} "${name}" -- touch /dev/null < /dev/null
|
||||
|
||||
IFS="¤"
|
||||
for apps in ${exported_apps}; do
|
||||
# Split the string by spaces
|
||||
IFS=" "
|
||||
for app in ${apps}; do
|
||||
# Export the app
|
||||
# shellcheck disable=SC2086,2248
|
||||
"${distrobox_path}"/distrobox enter ${root_flag} "${name}" -- distrobox-export --app "${app}" < /dev/null
|
||||
done
|
||||
done
|
||||
|
||||
IFS="¤"
|
||||
for bins in ${exported_bins}; do
|
||||
# Split the string by spaces
|
||||
IFS=" "
|
||||
for bin in ${bins}; do
|
||||
# Export the bin
|
||||
# shellcheck disable=SC2086,2248
|
||||
"${distrobox_path}"/distrobox enter ${root_flag} "${name}" -- distrobox-export --bin "${bin}" \
|
||||
--export-path "${exported_bins_path}" < /dev/null
|
||||
done
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# encode_variable will encode an input in base64, removing surrounding single/double quotes.
|
||||
# Arguments:
|
||||
# variable: string
|
||||
# Expected global variables:
|
||||
# None
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# a value string encoded in base64
|
||||
encode_variable()
|
||||
{
|
||||
variable="${1}"
|
||||
# remove surrounding quotes possibly added by the user
|
||||
if echo "${variable}" | grep -qE '^"'; then
|
||||
variable="$(echo "${variable}" | sed -e 's/^"//' -e 's/"$//')"
|
||||
elif echo "${variable}" | grep -qE "^'"; then
|
||||
variable="$(echo "${variable}" | sed -e "s/^'//" -e "s/'$//")"
|
||||
fi
|
||||
|
||||
echo "${variable}" | base64 -w 0
|
||||
}
|
||||
|
||||
# sanitize_variable will sanitize an input, add single/double quotes and escapes
|
||||
# Arguments:
|
||||
# variable: string
|
||||
# Expected global variables:
|
||||
# None
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# a value string sanitized
|
||||
sanitize_variable()
|
||||
{
|
||||
variable="${1}"
|
||||
|
||||
# If there are spaces but no quotes, let's add them
|
||||
if echo "${variable}" | grep -q " " &&
|
||||
! echo "${variable}" | grep -Eq "^'|^\""; then
|
||||
|
||||
# if we have double quotes we should wrap the whole line in single quotes
|
||||
# in order to not "undo" them
|
||||
if echo "${variable}" | grep -q '"'; then
|
||||
variable="'${variable}'"
|
||||
else
|
||||
variable="\"${variable}\""
|
||||
fi
|
||||
fi
|
||||
|
||||
# Return
|
||||
echo "${variable}"
|
||||
}
|
||||
|
||||
# parse_file will read and parse input file and call distrobox-create accordingly
|
||||
# Arguments:
|
||||
# file: string path of the manifest file to parse
|
||||
# Expected global variables:
|
||||
# tmpfile: string name of the tmpfile to read
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# None
|
||||
parse_file()
|
||||
{
|
||||
file="${1}"
|
||||
name=""
|
||||
|
||||
IFS='
|
||||
'
|
||||
while read -r line; do
|
||||
# Remove comments and trailing spaces
|
||||
line="$(echo "${line}" |
|
||||
sed 's/\t/ /g' |
|
||||
sed 's/^#.*//g' |
|
||||
sed 's/].*#.*//g' |
|
||||
sed 's/ #.*//g' |
|
||||
sed 's/\s*$//g')"
|
||||
|
||||
if [ -z "${line}" ]; then
|
||||
# blank line, skip
|
||||
continue
|
||||
fi
|
||||
|
||||
# Detect start of new section
|
||||
if [ "$(echo "${line}" | cut -c 1)" = '[' ]; then
|
||||
# We're starting a new section
|
||||
if [ -n "${name}" ]; then
|
||||
# We've finished the previous section, so this is the time to
|
||||
# perform the distrobox command, before going to the new section.
|
||||
run_distrobox "${name}"
|
||||
fi
|
||||
|
||||
# Remove brackets and spaces
|
||||
name="$(echo "${line}" | tr -d '][ ')"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Get key-values from the file
|
||||
key="$(echo "${line}" | cut -d'=' -f1 | tr -d ' ')"
|
||||
value="$(echo "${line}" | cut -d'=' -f2-)"
|
||||
|
||||
# Normalize true|false to 0|1
|
||||
[ "${value}" = "true" ] && value=1
|
||||
[ "${value}" = "false" ] && value=0
|
||||
|
||||
# Sanitize value, by whitespaces, quotes and escapes
|
||||
if [ "${key}" = "init_hooks" ] || [ "${key}" = "pre_init_hooks" ]; then
|
||||
# in case of shell commands (so the hooks) we prefer to pass the variable
|
||||
# around encoded, so that we don't accidentally execute stuff
|
||||
# and, we will execute sanitize_variable on the final string flag at the
|
||||
# end, instead of key/value base.
|
||||
value="$(encode_variable "${value}")"
|
||||
else
|
||||
value="$(sanitize_variable "${value}")"
|
||||
fi
|
||||
|
||||
# Save options to tempfile, to source it later
|
||||
touch "${tmpfile}"
|
||||
if [ -n "${key}" ] && [ -n "${value}" ]; then
|
||||
if grep -q "^${key}=" "${tmpfile}"; then
|
||||
# make keys cumulative
|
||||
value="\${${key}}¤${value}"
|
||||
fi
|
||||
echo "${key}=${value}" >> "${tmpfile}"
|
||||
fi
|
||||
done < "${file}"
|
||||
# Execute now one last time for the last block
|
||||
run_distrobox "${name}"
|
||||
}
|
||||
|
||||
# read_section reads the content of a section from a TOML file.
|
||||
# Arguments:
|
||||
# section: Name of the section to find (string).
|
||||
# file: Path to the file to search into (string).
|
||||
# Expected global variables:
|
||||
# None.
|
||||
# Expected env variables:
|
||||
# None.
|
||||
# Outputs:
|
||||
# Writes the found section body to stdout.
|
||||
# Exit behavior / errors:
|
||||
# Does not exit non‑zero on missing section; caller should treat empty output as needed.
|
||||
read_section()
|
||||
{
|
||||
section="$1"
|
||||
file="$2"
|
||||
awk -v sec="[${section}]" '
|
||||
$0 == sec {show=1; next}
|
||||
show && /^\[/ {exit}
|
||||
show && NF {print}
|
||||
' "${file}"
|
||||
}
|
||||
|
||||
# resolve_includes Resolve 'include' keys in a manifest by inlining referenced sections.
|
||||
# Arguments:
|
||||
# input_file: Path to the original manifest file that may contain 'include' keys.
|
||||
# output_file: Path to the file where the resolved manifest will be written (if empty, a temp file is used).
|
||||
# Expected global variables:
|
||||
# read_section (function) - used to extract referenced section bodies from input_file.
|
||||
# replace_line (function) - used to replace include lines with extracted content.
|
||||
# Expected env variables:
|
||||
# TMPDIR (optional) - may influence mktemp location.
|
||||
# Outputs:
|
||||
# Prints the path to the output file to stdout when completed.
|
||||
# Exit behavior / errors:
|
||||
# Exits with status 1 and writes to stderr on missing definitions, circular includes, or helper failures.
|
||||
resolve_includes()
|
||||
{
|
||||
input_file="$1"
|
||||
output_file="$2"
|
||||
include_stack=""
|
||||
|
||||
# At the starting point, the output file is equal to input_file
|
||||
# Later on, the output file will be edited as includes will be resolved
|
||||
cat "${input_file}" > "${output_file}"
|
||||
|
||||
n=0
|
||||
while true; do
|
||||
total_lines=$(wc -l < "${output_file}")
|
||||
[ "${n}" -gt "${total_lines}" ] && break
|
||||
|
||||
line=$(sed -n "$((n + 1))p" "${output_file}")
|
||||
|
||||
# Detected begin of a section: clear the include stack and go on
|
||||
if [ "$(echo "${line}" | cut -c 1)" = '[' ]; then
|
||||
include_stack=""
|
||||
n=$((n + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
# Match key=value from the current line
|
||||
key="$(echo "${line}" | cut -d'=' -f1 | tr -d ' ')"
|
||||
value="$(echo "${line}" | cut -d'=' -f2-)"
|
||||
|
||||
if [ "${key}" = "include" ]; then
|
||||
# Detect circular references while including other distrobox definitions
|
||||
# The reference stack is handled as a string of shape [name].[name].[name]
|
||||
if expr "${include_stack}" : ".*\[${value}\]" > /dev/null; then
|
||||
printf >&2 "ERROR circular reference detected: including [%s] again after %s\n" "${value}" "${include_stack}"
|
||||
exit 1
|
||||
else
|
||||
include_stack="[${value}]¤${include_stack}"
|
||||
fi
|
||||
|
||||
# Read the definition for the distrobox to include from the original file
|
||||
# and replace the current line with the found lines.
|
||||
# The line counter is not incremented to allow recursive include resolution
|
||||
inc=$(read_section "$(echo "${value}" | tr -d '"')" "${input_file}")
|
||||
if [ -z "${inc}" ]; then
|
||||
printf >&2 "ERROR cannot include '%s': definition not found\n" "${value}"
|
||||
exit 1
|
||||
fi
|
||||
l=$((n + 1))
|
||||
replace_line "${l}" "${inc}" "${output_file}" "${output_file}" > /dev/null
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
# Nothing to do, increment counter and go on
|
||||
n=$((n + 1))
|
||||
|
||||
done
|
||||
|
||||
echo "${output_file}"
|
||||
|
||||
}
|
||||
|
||||
# replace_line Replace a 1-based numbered line in a file with provided (possibly multiline) text.
|
||||
# Arguments:
|
||||
# line_number: 1-based index of the line to replace.
|
||||
# new_value: String to insert (may contain newlines).
|
||||
# input_file: Path to the original file to read from.
|
||||
# output_file: Path to write the resulting file (if empty, a temp file will be created).
|
||||
# Expected global variables:
|
||||
# None.
|
||||
# Expected env variables:
|
||||
# TMPDIR (optional) - may influence mktemp location.
|
||||
# Outputs:
|
||||
# Prints the path to the output file to stdout when complete.
|
||||
# Exit behavior / errors:
|
||||
# Exits with status 1 on fatal errors (e.g., mktemp failure).
|
||||
replace_line()
|
||||
{
|
||||
line_number="$1"
|
||||
new_value="$2"
|
||||
input_file="$3"
|
||||
output_file="$4"
|
||||
|
||||
# if no output file, use a temp file
|
||||
if [ -z "${output_file}" ]; then
|
||||
output_file=$(mktemp -u)
|
||||
fi
|
||||
|
||||
tmpfile=$(mktemp) || exit 1
|
||||
|
||||
# Split the file into two parts around the line to replace and combine with new_value
|
||||
# Print lines before line_number
|
||||
sed "$((line_number - 1))q" "${input_file}" > "${tmpfile}"
|
||||
|
||||
# Append the new_value
|
||||
printf "%s\n" "${new_value}" >> "${tmpfile}"
|
||||
|
||||
# Append lines after line_number
|
||||
sed -n "$((line_number + 1)),\$p" "${input_file}" >> "${tmpfile}"
|
||||
|
||||
# Replace original file with tmpfile
|
||||
mv "${tmpfile}" "${output_file}"
|
||||
|
||||
echo "${output_file}"
|
||||
}
|
||||
|
||||
# Exec
|
||||
expanded_file=$(mktemp -u)
|
||||
resolve_includes "${input_file}" "${expanded_file}"
|
||||
parse_file "${expanded_file}"
|
||||
1093
profiles/desktop/.local/bin/distrobox-create
Executable file
1093
profiles/desktop/.local/bin/distrobox-create
Executable file
File diff suppressed because it is too large
Load Diff
729
profiles/desktop/.local/bin/distrobox-enter
Executable file
729
profiles/desktop/.local/bin/distrobox-enter
Executable file
@@ -0,0 +1,729 @@
|
||||
#!/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
|
||||
# Optional env variables:
|
||||
# DBX_CONTAINER_ALWAYS_PULL
|
||||
# DBX_CONTAINER_CUSTOM_HOME
|
||||
# DBX_CONTAINER_GENERATE_ENTRY
|
||||
# DBX_CONTAINER_HOME_PREFIX
|
||||
# DBX_CONTAINER_HOSTNAME
|
||||
# DBX_CONTAINER_IMAGE
|
||||
# DBX_CONTAINER_MANAGER
|
||||
# DBX_CONTAINER_NAME
|
||||
# DBX_CONTAINER_CLEAN_PATH
|
||||
# DBX_NON_INTERACTIVE
|
||||
# DBX_VERBOSE
|
||||
# DBX_SKIP_WORKDIR
|
||||
# DBX_SUDO_PROGRAM
|
||||
|
||||
# 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)"
|
||||
|
||||
app_cache_dir=${XDG_CACHE_HOME:-"${HOME}/.cache"}/distrobox
|
||||
|
||||
trap cleanup TERM INT HUP EXIT
|
||||
|
||||
# cleanup will remove fifo and temp files, and print to stdout
|
||||
# container's logs in case of error and verbose.
|
||||
# Arguments:
|
||||
# None
|
||||
# Expected global variables:
|
||||
# container_manager: string container manager to use
|
||||
# container_name: string container name
|
||||
# app_cache_dir: string cache dire to write file into
|
||||
# logs_pid: string pid of the podman/docker logs process
|
||||
# verbose: bool verbose
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# None
|
||||
cleanup()
|
||||
{
|
||||
rm -f "${app_cache_dir}/.${container_name}.fifo"
|
||||
if [ -n "${logs_pid:-}" ]; then
|
||||
kill "${logs_pid:-}" 2> /dev/null || :
|
||||
fi
|
||||
if [ "${verbose}" -eq 1 ]; then
|
||||
${container_manager} logs "${container_name}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Despite of running this script via SUDO/DOAS being not supported (the
|
||||
# script itself will call the appropriate tool when necessary), we still want
|
||||
# to allow people to run it as root, logged in in a shell, and create rootful
|
||||
# containers.
|
||||
#
|
||||
# SUDO_USER is a variable set by SUDO and can be used to check whether the script was called by it. Same thing for DOAS_USER, set by DOAS.
|
||||
if {
|
||||
[ -n "${SUDO_USER}" ] || [ -n "${DOAS_USER}" ]
|
||||
} && [ "$(id -ru)" -eq 0 ]; then
|
||||
printf >&2 "Running %s via SUDO/DOAS is not supported. Instead, please try running:\n" "$(basename "${0}")"
|
||||
printf >&2 " %s --root %s\n" "$(basename "${0}")" "$*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Defaults
|
||||
# by default we use getent to get the login shell of the user and use that
|
||||
container_custom_command=0
|
||||
container_command_user="$(echo "${USER}" | sed 's|\\|\\\\|g')"
|
||||
container_image_default="registry.fedoraproject.org/fedora-toolbox:latest"
|
||||
container_manager="autodetect"
|
||||
container_manager_additional_flags=""
|
||||
container_name=""
|
||||
container_name_default="my-distrobox"
|
||||
non_interactive=0
|
||||
|
||||
# Use cd + dirname + pwd so that we do not have relative paths in mount points
|
||||
# We're not using "realpath" here so that symlinks are not resolved this way
|
||||
# "realpath" would break situations like Nix or similar symlink based package
|
||||
# management.
|
||||
distrobox_enter_path="$(cd "$(dirname "$0")" && pwd)/distrobox-enter"
|
||||
dryrun=0
|
||||
headless=0
|
||||
# If the user runs this script as root in a login shell, set rootful=1.
|
||||
# There's no need for them to pass the --root flag option in such cases.
|
||||
[ "$(id -ru)" -eq 0 ] && rootful=1 || rootful=0
|
||||
skip_workdir=0
|
||||
verbose=0
|
||||
clean_path=0
|
||||
version="1.8.2.2"
|
||||
|
||||
# Source configuration files, this is done in an hierarchy so local files have
|
||||
# priority over system defaults
|
||||
# leave priority to environment variables.
|
||||
#
|
||||
# On NixOS, for the distrobox derivation to pick up a static config file shipped
|
||||
# by the package maintainer the path must be relative to the script itself.
|
||||
self_dir="$(dirname "$(realpath "$0")")"
|
||||
nix_config_file="${self_dir}/../share/distrobox/distrobox.conf"
|
||||
|
||||
config_files="
|
||||
${nix_config_file}
|
||||
/usr/share/distrobox/distrobox.conf
|
||||
/usr/share/defaults/distrobox/distrobox.conf
|
||||
/usr/etc/distrobox/distrobox.conf
|
||||
/usr/local/share/distrobox/distrobox.conf
|
||||
/etc/distrobox/distrobox.conf
|
||||
${XDG_CONFIG_HOME:-"${HOME}/.config"}/distrobox/distrobox.conf
|
||||
${HOME}/.distroboxrc
|
||||
"
|
||||
for config_file in ${config_files}; do
|
||||
# Shellcheck will give error for sourcing a variable file as it cannot follow
|
||||
# it. We don't care so let's disable this linting for now.
|
||||
# shellcheck disable=SC1090
|
||||
[ -e "${config_file}" ] && . "$(realpath "${config_file}")"
|
||||
done
|
||||
# If we're running this script as root -- as in, logged in in the shell as root
|
||||
# user, and not via SUDO/DOAS --, we don't need to set distrobox_sudo_program
|
||||
# as it's meaningless for this use case.
|
||||
if [ "$(id -ru)" -ne 0 ]; then
|
||||
# If the DBX_SUDO_PROGRAM/distrobox_sudo_program variable was set by the
|
||||
# user, use its value instead of "sudo". But only if not running the script
|
||||
# as root (UID 0).
|
||||
distrobox_sudo_program=${DBX_SUDO_PROGRAM:-${distrobox_sudo_program:-"sudo"}}
|
||||
fi
|
||||
|
||||
[ -n "${DBX_CONTAINER_MANAGER}" ] && container_manager="${DBX_CONTAINER_MANAGER}"
|
||||
[ -n "${DBX_CONTAINER_NAME}" ] && container_name="${DBX_CONTAINER_NAME}"
|
||||
[ -n "${DBX_CONTAINER_CLEAN_PATH}" ] && clean_path=1
|
||||
[ -n "${DBX_SKIP_WORKDIR}" ] && skip_workdir="${DBX_SKIP_WORKDIR}"
|
||||
[ -n "${DBX_NON_INTERACTIVE}" ] && non_interactive="${DBX_NON_INTERACTIVE}"
|
||||
[ -n "${DBX_VERBOSE}" ] && verbose="${DBX_VERBOSE}"
|
||||
|
||||
# Fixup variable=[true|false], in case we find it in the config file(s)
|
||||
[ "${non_interactive}" = "true" ] && non_interactive=1
|
||||
[ "${non_interactive}" = "false" ] && non_interactive=0
|
||||
[ "${verbose}" = "true" ] && verbose=1
|
||||
[ "${verbose}" = "false" ] && verbose=0
|
||||
|
||||
# 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-enter --name fedora-39 -- bash -l
|
||||
distrobox-enter my-alpine-container -- sh -l
|
||||
distrobox-enter --additional-flags "--preserve-fds" --name test -- bash -l
|
||||
distrobox-enter --additional-flags "--env MY_VAR=value" --name test -- bash -l
|
||||
MY_VAR=value distrobox-enter --additional-flags "--preserve-fds" --name test -- bash -l
|
||||
|
||||
Options:
|
||||
|
||||
--name/-n: name for the distrobox default: my-distrobox
|
||||
--/-e: end arguments execute the rest as command to execute at login default: default ${USER}'s shell
|
||||
--clean-path: reset PATH inside container to FHS standard
|
||||
--no-tty/-T: do not instantiate a tty
|
||||
--no-workdir/-nw: always start the container from container's home directory
|
||||
--additional-flags/-a: additional flags to pass to the container manager command
|
||||
--help/-h: show this message
|
||||
--root/-r: launch podman/docker/lilipod with root privileges. Note that if you need root this is the preferred
|
||||
way over "sudo distrobox" (note: if using a program other than 'sudo' for root privileges is necessary,
|
||||
specify it through the DBX_SUDO_PROGRAM env variable, or 'distrobox_sudo_program' config variable)
|
||||
--dry-run/-d: only print the container manager command generated
|
||||
--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
|
||||
;;
|
||||
-T | -H | --no-tty)
|
||||
shift
|
||||
headless=1
|
||||
;;
|
||||
-r | --root)
|
||||
shift
|
||||
rootful=1
|
||||
;;
|
||||
-V | --version)
|
||||
printf "distrobox: %s\n" "${version}"
|
||||
exit 0
|
||||
;;
|
||||
-d | --dry-run)
|
||||
shift
|
||||
dryrun=1
|
||||
;;
|
||||
-nw | --no-workdir)
|
||||
shift
|
||||
skip_workdir=1
|
||||
;;
|
||||
-n | --name)
|
||||
if [ -n "$2" ]; then
|
||||
container_name="$2"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
-a | --additional-flags)
|
||||
if [ -n "$2" ]; then
|
||||
if [ -z "${container_manager_additional_flags=}" ]; then
|
||||
container_manager_additional_flags="$(echo "${2}" | sed -E "s/(--[a-zA-Z]+) ([^ ]+)/\1=\2/g" | sed 's/ --/\n--/g')"
|
||||
else
|
||||
container_manager_additional_flags="${container_manager_additional_flags}
|
||||
$(echo "${2}" | sed -E "s/(--[a-zA-Z]+) ([^ ]+)/\1=\2/g" | sed 's/ --/\n--/g')"
|
||||
fi
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
-Y | --yes)
|
||||
non_interactive=1
|
||||
shift
|
||||
;;
|
||||
-e | --exec | --)
|
||||
container_custom_command=1
|
||||
shift
|
||||
# We pass the rest of arguments as $@ at the end
|
||||
break
|
||||
;;
|
||||
--clean-path)
|
||||
shift
|
||||
clean_path=1
|
||||
;;
|
||||
-*) # 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.
|
||||
# If we have a flagless option and container_name is not specified
|
||||
# then let's accept argument as container_name
|
||||
if [ -n "$1" ]; then
|
||||
container_name="$1"
|
||||
shift
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set verbosity
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
set -o xtrace
|
||||
fi
|
||||
|
||||
if [ -z "${container_name}" ]; then
|
||||
container_name="${container_name_default}"
|
||||
fi
|
||||
|
||||
if [ ! -t 0 ] || [ ! -t 1 ]; then
|
||||
headless=1
|
||||
fi
|
||||
# We depend on a container manager let's be sure we have it
|
||||
# First we use podman, else docker, else lilipod
|
||||
case "${container_manager}" in
|
||||
autodetect)
|
||||
if command -v podman > /dev/null; then
|
||||
container_manager="podman"
|
||||
elif command -v podman-launcher > /dev/null; then
|
||||
container_manager="podman-launcher"
|
||||
elif command -v docker > /dev/null; then
|
||||
container_manager="docker"
|
||||
elif command -v lilipod > /dev/null; then
|
||||
container_manager="lilipod"
|
||||
fi
|
||||
;;
|
||||
podman)
|
||||
container_manager="podman"
|
||||
;;
|
||||
podman-launcher)
|
||||
container_manager="podman-launcher"
|
||||
;;
|
||||
lilipod)
|
||||
container_manager="lilipod"
|
||||
;;
|
||||
docker)
|
||||
container_manager="docker"
|
||||
;;
|
||||
*)
|
||||
printf >&2 "Invalid input %s.\n" "${container_manager}"
|
||||
printf >&2 "The available choices are: 'autodetect', 'podman', 'docker', 'lilipod'\n"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Be sure we have a container manager to work with.
|
||||
if ! command -v "${container_manager}" > /dev/null && [ "${dryrun}" -eq 0 ]; then
|
||||
# Error: we need at least one between docker, podman or lilipod.
|
||||
printf >&2 "Missing dependency: we need a container manager.\n"
|
||||
printf >&2 "Please install one of podman, docker or lilipod.\n"
|
||||
printf >&2 "You can follow the documentation on:\n"
|
||||
printf >&2 "\tman distrobox-compatibility\n"
|
||||
printf >&2 "or:\n"
|
||||
printf >&2 "\thttps://github.com/89luca89/distrobox/blob/main/docs/compatibility.md\n"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
# add verbose if -v is specified
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
container_manager="${container_manager} --log-level debug"
|
||||
fi
|
||||
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
if [ "${rootful}" -ne 0 ]; then
|
||||
container_manager="${distrobox_sudo_program-} ${container_manager}"
|
||||
fi
|
||||
|
||||
# generate_enter_command will produce a Podman, Docker or Lilipod command to execute to enter the container.
|
||||
# Arguments:
|
||||
# None
|
||||
# Expected global variables:
|
||||
# container_manager: string container manager to use
|
||||
# container_name: string container name
|
||||
# container_manager_additional_flags: string container manager additional flags to use
|
||||
# container_home: string container's home path
|
||||
# container_path: string container's default PATH variable
|
||||
# headless: bool headless mode
|
||||
# skip_workdir: bool skip workdir
|
||||
# verbose: bool verbose
|
||||
# unshare_groups
|
||||
# distrobox_enter_path
|
||||
# Expected env variables:
|
||||
# PATH
|
||||
# USER
|
||||
# PWD
|
||||
# XDG_DATA_DIRS
|
||||
# XDG_CONFIG_DIRS
|
||||
# Outputs:
|
||||
# prints the podman, docker or lilipod command to enter the distrobox container
|
||||
generate_enter_command()
|
||||
{
|
||||
result_command="exec"
|
||||
result_command="${result_command}
|
||||
--interactive"
|
||||
result_command="${result_command}
|
||||
--detach-keys="
|
||||
|
||||
# In case of initful systems or unshared groups, we don't enter directly
|
||||
# as our user, but we instead enter as root, and then su $USER, in order
|
||||
# to trigger a proper login
|
||||
if [ "${unshare_groups:-0}" -eq 1 ]; then
|
||||
result_command="${result_command}
|
||||
--user=root"
|
||||
else
|
||||
result_command="${result_command}
|
||||
--user=${USER}"
|
||||
fi
|
||||
|
||||
# For some usage, like use in service, or launched by non-terminal
|
||||
# eg. from desktop files, TTY can fail to instantiate, and fail to enter
|
||||
# the container.
|
||||
# To work around this, --headless let's you skip the --tty flag and make it
|
||||
# work in tty-less situations.
|
||||
# Disable tty also if we're NOT in a tty (test -t 0, test -t 1).
|
||||
if [ "${headless}" -eq 0 ]; then
|
||||
result_command="${result_command}
|
||||
--tty"
|
||||
fi
|
||||
|
||||
# Entering container using our user and workdir.
|
||||
# Start container from working directory. Else default to home. Else do /.
|
||||
# Since we are entering from host, drop at workdir through '/run/host'
|
||||
# which represents host's root inside container. Any directory on host
|
||||
# even if not explicitly mounted is bound to exist under /run/host.
|
||||
# Since user $HOME is very likely present in container, enter there directly
|
||||
# to avoid confusing the user about shifted paths.
|
||||
# pass distrobox-enter path, it will be used in the distrobox-export tool.
|
||||
if [ "${skip_workdir}" -eq 0 ]; then
|
||||
workdir="${PWD:-${container_home:-"/"}}"
|
||||
if [ -n "${workdir##*"${container_home}"*}" ]; then
|
||||
workdir="/run/host${workdir}"
|
||||
fi
|
||||
else
|
||||
# Skipping workdir we just enter $HOME of the container.
|
||||
workdir="${container_home}"
|
||||
fi
|
||||
|
||||
result_command="${result_command}
|
||||
--workdir=${workdir}"
|
||||
result_command="${result_command}
|
||||
--env=CONTAINER_ID=${container_name}"
|
||||
result_command="${result_command}
|
||||
--env=DISTROBOX_ENTER_PATH=${distrobox_enter_path}"
|
||||
|
||||
# Loop through all the environment vars
|
||||
# and export them to the container.
|
||||
set +o xtrace
|
||||
# disable logging for this snippet, or it will be too talkative.
|
||||
# We filter the environment so that we do not have strange variables or
|
||||
# multiline.
|
||||
# We also NEED to ignore the HOME variable, as this is set at create time
|
||||
# and needs to stay that way to use custom home dirs. or it will be too talkative.
|
||||
result_command="${result_command}
|
||||
$(printenv | grep '=' | grep -Ev '"|`|\$' |
|
||||
grep -Ev '^(CONTAINER_ID|FPATH|HOST|HOSTNAME|HOME|PATH|PROFILEREAD|SHELL|XDG_SEAT|XDG_VTNR|XDG_.*_DIRS|^_)' |
|
||||
sed 's/ /\ /g' | sed 's/^\(.*\)$/--env=\1/g')"
|
||||
|
||||
# Start with the $PATH set in the container's config
|
||||
container_paths="${container_path:-""}"
|
||||
# Ensure the standard FHS program paths are in PATH environment
|
||||
standard_paths="/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin"
|
||||
|
||||
if [ "${clean_path}" -eq 1 ]; then
|
||||
# only add the standard paths
|
||||
for standard_path in ${standard_paths}; do
|
||||
if [ -z "${container_paths}" ]; then
|
||||
container_paths="${standard_path}"
|
||||
else
|
||||
container_paths="${container_paths}:${standard_path}"
|
||||
fi
|
||||
done
|
||||
else
|
||||
# collect standard paths not existing from host PATH
|
||||
for standard_path in ${standard_paths}; do
|
||||
pattern="(:|^)${standard_path}(:|$)"
|
||||
if ! echo "${PATH}" | grep -Eq "${pattern}"; then
|
||||
if [ -z "${container_paths}" ]; then
|
||||
container_paths="${standard_path}"
|
||||
else
|
||||
container_paths="${container_paths}:${standard_path}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
# append additional standard paths to host PATH to get final container_paths
|
||||
if [ -n "${container_paths}" ]; then
|
||||
container_paths="${PATH}:${container_paths}"
|
||||
else
|
||||
container_paths="${PATH}"
|
||||
fi
|
||||
fi
|
||||
|
||||
result_command="${result_command}
|
||||
--env=PATH=${container_paths}"
|
||||
|
||||
# Ensure the standard FHS program paths are in XDG_DATA_DIRS environment
|
||||
standard_paths="/usr/local/share /usr/share"
|
||||
container_paths="${XDG_DATA_DIRS:-}"
|
||||
# add to the XDG_DATA_DIRS only after the host's paths, and only if not already present.
|
||||
for standard_path in ${standard_paths}; do
|
||||
pattern="(:|^)${standard_path}(:|$)"
|
||||
if [ -z "${container_paths}" ]; then
|
||||
container_paths="${standard_path}"
|
||||
elif ! echo "${container_paths}" | grep -Eq "${pattern}"; then
|
||||
container_paths="${container_paths}:${standard_path}"
|
||||
fi
|
||||
done
|
||||
result_command="${result_command}
|
||||
--env=XDG_DATA_DIRS=${container_paths}"
|
||||
|
||||
# This correctly sets the XDG_* dirs to the container_home
|
||||
# it will be $HOME if using regular home dirs
|
||||
# if will be $container_home if using a custom home during create
|
||||
result_command="${result_command}
|
||||
--env=XDG_CACHE_HOME=${container_home}/.cache
|
||||
--env=XDG_CONFIG_HOME=${container_home}/.config
|
||||
--env=XDG_DATA_HOME=${container_home}/.local/share
|
||||
--env=XDG_STATE_HOME=${container_home}/.local/state"
|
||||
|
||||
# Ensure the standard FHS program paths are in XDG_CONFIG_DIRS environment
|
||||
standard_paths="/etc/xdg"
|
||||
container_paths="${XDG_CONFIG_DIRS:-}"
|
||||
# add to the XDG_CONFIG_DIRS only after the host's paths, and only if not already present.
|
||||
for standard_path in ${standard_paths}; do
|
||||
pattern="(:|^)${standard_path}(:|$)"
|
||||
if [ -z "${container_paths}" ]; then
|
||||
container_paths="${standard_path}"
|
||||
elif ! echo "${container_paths}" | grep -Eq "${pattern}"; then
|
||||
container_paths="${container_paths}:${standard_path}"
|
||||
fi
|
||||
done
|
||||
result_command="${result_command}
|
||||
--env=XDG_CONFIG_DIRS=${container_paths}"
|
||||
|
||||
# re-enable logging if it was enabled previously.
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
set -o xtrace
|
||||
fi
|
||||
|
||||
# Add additional flags
|
||||
if [ -n "${container_manager_additional_flags}" ]; then
|
||||
result_command="${result_command}
|
||||
${container_manager_additional_flags}"
|
||||
fi
|
||||
|
||||
# Run selected container with specified command.
|
||||
result_command="${result_command}
|
||||
${container_name}"
|
||||
|
||||
# Return generated command.
|
||||
# here we remove tabs as an artifact of using indentation in code to improve
|
||||
# readability
|
||||
printf "%s\n" "${result_command}" | tr -d '\t'
|
||||
}
|
||||
|
||||
container_home="${HOME}"
|
||||
container_path="${PATH}"
|
||||
unshare_groups=0
|
||||
# Now inspect the container we're working with.
|
||||
container_status="unknown"
|
||||
eval "$(${container_manager} inspect --type container --format \
|
||||
'container_status={{.State.Status}};
|
||||
unshare_groups={{ index .Config.Labels "distrobox.unshare_groups" }};
|
||||
{{range .Config.Env}}{{if and (ge (len .) 5) (eq (slice . 0 5) "HOME=")}}container_home={{slice . 5 | printf "%q"}}{{end}}{{end}};
|
||||
{{range .Config.Env}}{{if and (ge (len .) 5) (eq (slice . 0 5) "PATH=")}}container_path={{slice . 5 | printf "%q"}}{{end}}{{end}}' \
|
||||
"${container_name}")"
|
||||
|
||||
# dry run mode, just generate the command and print it. No execution.
|
||||
if [ "${dryrun}" -ne 0 ]; then
|
||||
cmd="$(generate_enter_command | sed 's/\t//g')"
|
||||
printf "%s %s\n" "${cmd}" "$*"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if the container is even there
|
||||
if [ "${container_status}" = "unknown" ]; then
|
||||
# If not, prompt to create it first
|
||||
# If we're not-interactive, just don't ask questions
|
||||
if [ "${non_interactive}" -eq 1 ]; then
|
||||
response="yes"
|
||||
else
|
||||
printf >&2 "Create it now, out of image %s? [Y/n]: " "${container_image_default}"
|
||||
read -r response
|
||||
response="${response:-"Y"}"
|
||||
fi
|
||||
|
||||
# Accept only y,Y,Yes,yes,n,N,No,no.
|
||||
case "${response}" in
|
||||
y | Y | Yes | yes | YES)
|
||||
# Ok, let's create the container with just 'distrobox create $container_name
|
||||
create_command="$(dirname "${0}")/distrobox-create"
|
||||
if [ "${rootful}" -ne 0 ]; then
|
||||
create_command="${create_command} --root"
|
||||
fi
|
||||
|
||||
create_command="${create_command} --yes -i ${container_image_default} -n ${container_name}"
|
||||
|
||||
printf >&2 "Creating the container %s\n" "${container_name}"
|
||||
|
||||
if [ "${dryrun}" -ne 1 ]; then
|
||||
${create_command}
|
||||
fi
|
||||
;;
|
||||
n | N | No | no | NO)
|
||||
printf >&2 "Ok. For creating it, run this command:\n"
|
||||
printf >&2 "\tdistrobox create <name-of-container> --image <remote>/<docker>:<tag>\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
|
||||
|
||||
# If the container is not already running, we need to start if first
|
||||
if [ "${container_status}" != "running" ]; then
|
||||
# If container is not running, start it first
|
||||
#
|
||||
# Here, we save the timestamp before launching the start command, so we can
|
||||
# be sure we're working with this very same session of logs later.
|
||||
log_timestamp="$(date -u +%FT%T).000000000+00:00"
|
||||
${container_manager} start "${container_name}" > /dev/null
|
||||
#
|
||||
# Check if the container is going in error status earlier than the
|
||||
# entrypoint
|
||||
if [ "$(${container_manager} inspect \
|
||||
--type container \
|
||||
--format "{{.State.Status}}" "${container_name}")" != "running" ]; then
|
||||
|
||||
printf >&2 "\033[31m Error: could not start entrypoint.\n\033[0m"
|
||||
container_manager_log="$(${container_manager} logs "${container_name}")"
|
||||
printf >&2 "%s\n" "${container_manager_log}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf >&2 "%-40s\t" "Starting container..."
|
||||
mkdir -p "${app_cache_dir}"
|
||||
rm -f "${app_cache_dir}/.${container_name}.fifo"
|
||||
mkfifo "${app_cache_dir}/.${container_name}.fifo"
|
||||
while true; do
|
||||
# Exit early in case of crashed/stopped container during setup
|
||||
if [ "$(${container_manager} inspect --type container --format '{{.State.Status}}' "${container_name}")" != "running" ]; then
|
||||
printf >&2 "\nContainer Setup Failure!\n"
|
||||
exit 1
|
||||
fi
|
||||
# save starting loop timestamp in temp variable, we'll use it
|
||||
# after to let logs command minimize possible holes
|
||||
${container_manager} logs --since "${log_timestamp}" -f "${container_name}" \
|
||||
> "${app_cache_dir}/.${container_name}.fifo" 2>&1 &
|
||||
logs_pid="$!"
|
||||
|
||||
# read logs from log_timestamp to now, line by line
|
||||
while IFS= read -r line; do
|
||||
case "${line}" in
|
||||
"+"*)
|
||||
# Ignoring logging commands
|
||||
;;
|
||||
"Error:"*)
|
||||
printf >&2 "\033[31m %s\n\033[0m" "${line}"
|
||||
exit 1
|
||||
;;
|
||||
"Warning:"*)
|
||||
printf >&2 "\n\033[33m %s\033[0m" "${line}"
|
||||
;;
|
||||
"distrobox:"*)
|
||||
current_line="$(echo "${line}" | cut -d' ' -f2-)"
|
||||
# Save current line in the status, to avoid printing the same line multiple times
|
||||
printf >&2 "\033[32m [ OK ]\n\033[0m%-40s\t" "${current_line}"
|
||||
;;
|
||||
"container_setup_done"*)
|
||||
printf >&2 "\033[32m [ OK ]\n\033[0m"
|
||||
kill "${logs_pid}" > /dev/null 2>&1
|
||||
break 2
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
done < "${app_cache_dir}/.${container_name}.fifo"
|
||||
done
|
||||
# cleanup fifo
|
||||
rm -f "${app_cache_dir}/.${container_name}.fifo"
|
||||
printf >&2 "\nContainer Setup Complete!\n"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
# Execution section, in this section we will manipulate the positional parameters
|
||||
# in order to generate our long docker/podman/lilipod command to execute.
|
||||
#
|
||||
# We use positional parameters in order to have the shell manage escaping and spaces
|
||||
# so we remove the problem of we having to handle them.
|
||||
#
|
||||
# 1 - handle absence of custom command, we will need to add a getent command to
|
||||
# execute the right container's user's shell
|
||||
# 2 - in case of unshared groups (or initful) we need to trigger a proper login
|
||||
# using `su`, so we will need to manipulate these arguments accorodingly
|
||||
# 3 - prepend our generated command
|
||||
# to do this, we use `tac` so we reverse loop it and prepend each argument.
|
||||
# 4 - now that we're done, we can prepend our container_command
|
||||
# we will need to use `rev` to reverse it as we reverse loop and prepend each
|
||||
# argument
|
||||
################################################################################
|
||||
#
|
||||
# Setup default commands if none are specified
|
||||
# execute a getent command using the /bin/sh shell
|
||||
# to find out the default shell of the user, and
|
||||
# do a login shell with it (eg: /bin/bash -l)
|
||||
if [ "${container_custom_command}" -eq 0 ]; then
|
||||
set - "$@" "/bin/sh" "-c" "\$(getent passwd '${container_command_user}' | cut -f 7 -d :) -l"
|
||||
fi
|
||||
|
||||
# If we have a command and we're unsharing groups, we need to execute those
|
||||
# command using su $container_command_user
|
||||
# if we're in a tty, also allocate one
|
||||
if [ "${unshare_groups:-0}" -eq 1 ]; then
|
||||
# shellcheck disable=SC2089,SC2016
|
||||
set -- "-c" '"$0" "$@"' -- "$@"
|
||||
set -- "-s" "/bin/sh" "$@"
|
||||
if [ "${headless}" -eq 0 ]; then
|
||||
set -- "--pty" "$@"
|
||||
fi
|
||||
set -- "-m" "$@"
|
||||
set -- "${container_command_user}" "$@"
|
||||
set -- "su" "$@"
|
||||
fi
|
||||
|
||||
# Generate the exec command and run it
|
||||
cmd="$(generate_enter_command | awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--]}')"
|
||||
# Reverse it so we can reverse loop and prepend the command's arguments
|
||||
# to our positional parameters
|
||||
IFS='
|
||||
'
|
||||
for arg in ${cmd}; do
|
||||
set - "${arg}" "$@"
|
||||
done
|
||||
|
||||
# Prepend the container manager command
|
||||
# reverse it first, so we can loop backward as we're prepending not appending
|
||||
IFS=' '
|
||||
for arg in $(echo "${container_manager}" | rev); do
|
||||
arg="$(echo "${arg}" | rev)"
|
||||
set - "${arg}" "$@"
|
||||
done
|
||||
|
||||
exec "$@"
|
||||
282
profiles/desktop/.local/bin/distrobox-ephemeral
Executable file
282
profiles/desktop/.local/bin/distrobox-ephemeral
Executable file
@@ -0,0 +1,282 @@
|
||||
#!/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
|
||||
# Optional env variables:
|
||||
# DBX_CONTAINER_MANAGER
|
||||
# DBX_CONTAINER_NAME
|
||||
# DBX_VERBOSE
|
||||
# DBX_SUDO_PROGRAM
|
||||
|
||||
# Despite of running this script via SUDO/DOAS being not supported (the
|
||||
# script itself will call the appropriate tool when necessary), we still want
|
||||
# to allow people to run it as root, logged in in a shell, and create rootful
|
||||
# containers.
|
||||
#
|
||||
# SUDO_USER is a variable set by SUDO and can be used to check whether the script was called by it. Same thing for DOAS_USER, set by DOAS.
|
||||
if {
|
||||
[ -n "${SUDO_USER}" ] || [ -n "${DOAS_USER}" ]
|
||||
} && [ "$(id -ru)" -eq 0 ]; then
|
||||
printf >&2 "Running %s via SUDO/DOAS is not supported. Instead, please try running:\n" "$(basename "${0}")"
|
||||
printf >&2 " %s --root %s\n" "$(basename "${0}")" "$*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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)"
|
||||
|
||||
trap cleanup TERM INT HUP
|
||||
|
||||
name=$(mktemp -u distrobox-XXXXXXXXXX)
|
||||
container_command=""
|
||||
create_flags=""
|
||||
distrobox_path="$(dirname "${0}")"
|
||||
extra_flags=""
|
||||
# If the user runs this script as root in a login shell, set rootful=1.
|
||||
# There's no need for them to pass the --root flag option in such cases.
|
||||
[ "$(id -ru)" -eq 0 ] && rootful=1 || rootful=0
|
||||
verbose=0
|
||||
version="1.8.2.2"
|
||||
container_additional_packages=""
|
||||
container_init_hook=" "
|
||||
container_manager_additional_flags=""
|
||||
container_pre_init_hook=" "
|
||||
|
||||
# Source configuration files, this is done in an hierarchy so local files have
|
||||
# priority over system defaults
|
||||
# leave priority to environment variables.
|
||||
#
|
||||
# On NixOS, for the distrobox derivation to pick up a static config file shipped
|
||||
# by the package maintainer the path must be relative to the script itself.
|
||||
self_dir="$(dirname "$(realpath "$0")")"
|
||||
nix_config_file="${self_dir}/../share/distrobox/distrobox.conf"
|
||||
|
||||
config_files="
|
||||
${nix_config_file}
|
||||
/usr/share/distrobox/distrobox.conf
|
||||
/usr/share/defaults/distrobox/distrobox.conf
|
||||
/usr/etc/distrobox/distrobox.conf
|
||||
/usr/local/share/distrobox/distrobox.conf
|
||||
/etc/distrobox/distrobox.conf
|
||||
${XDG_CONFIG_HOME:-"${HOME}/.config"}/distrobox/distrobox.conf
|
||||
${HOME}/.distroboxrc
|
||||
"
|
||||
for config_file in ${config_files}; do
|
||||
# Shellcheck will give error for sourcing a variable file as it cannot follow
|
||||
# it. We don't care so let's disable this linting for now.
|
||||
# shellcheck disable=SC1090
|
||||
[ -e "${config_file}" ] && . "$(realpath "${config_file}")"
|
||||
done
|
||||
|
||||
[ -n "${DBX_VERBOSE}" ] && verbose="${DBX_VERBOSE}"
|
||||
|
||||
# Fixup variable=[true|false], in case we find it in the config file(s)
|
||||
[ "${verbose}" = "true" ] && verbose=1
|
||||
[ "${verbose}" = "false" ] && verbose=0
|
||||
|
||||
# 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-ephemeral [--root/-r]
|
||||
|
||||
Options:
|
||||
|
||||
--root/-r: launch podman/docker/lilipod with root privileges. Note that if you need root this is the preferred
|
||||
way over "sudo distrobox" (note: if using a program other than 'sudo' for root privileges is necessary,
|
||||
specify it through the DBX_SUDO_PROGRAM env variable, or 'distrobox_sudo_program' config variable)
|
||||
--verbose/-v: show more verbosity
|
||||
--help/-h: show this message
|
||||
--/-e: end arguments execute the rest as command to execute at login default: default ${USER}'s shell
|
||||
--version/-V: show version
|
||||
|
||||
See also:
|
||||
|
||||
distrobox-ephemeral also inherits all the flags from distrobox-create:
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
while :; do
|
||||
case $1 in
|
||||
-h | --help)
|
||||
# Call a "show_help" function to display a synopsis, then exit.
|
||||
show_help
|
||||
"${distrobox_path}"/distrobox-create --help | tail -n +2
|
||||
exit 0
|
||||
;;
|
||||
-r | --root)
|
||||
shift
|
||||
rootful=1
|
||||
;;
|
||||
-v | --verbose)
|
||||
verbose=1
|
||||
shift
|
||||
;;
|
||||
-V | --version)
|
||||
printf "distrobox: %s\n" "${version}"
|
||||
exit 0
|
||||
;;
|
||||
-e | --exec | --)
|
||||
shift
|
||||
container_command="-- $*"
|
||||
break
|
||||
;;
|
||||
-n | --name)
|
||||
# Ignore --name on ephemeral
|
||||
if [ -n "$2" ]; then
|
||||
name="${2}"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
-a | --additional-flags)
|
||||
if [ -n "$2" ]; then
|
||||
container_manager_additional_flags="${container_manager_additional_flags} ${2}"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
-ap | --additional-packages)
|
||||
if [ -n "$2" ]; then
|
||||
container_additional_packages="${container_additional_packages} ${2}"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
--init-hooks)
|
||||
if [ -n "$2" ]; then
|
||||
container_init_hook="$2"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
--pre-init-hooks)
|
||||
if [ -n "$2" ]; then
|
||||
container_pre_init_hook="${2}"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*) # Default case: If no more options then break out of the loop.
|
||||
# If we have a flagless option and container_name is not specified
|
||||
# then let's accept argument as container_name
|
||||
if [ -n "$1" ]; then
|
||||
create_flags="${create_flags} $1"
|
||||
shift
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -o nounset
|
||||
# set verbosity
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
set -o xtrace
|
||||
extra_flags="${extra_flags} --verbose"
|
||||
fi
|
||||
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
if [ "${rootful}" -ne 0 ]; then
|
||||
extra_flags="${extra_flags} --root"
|
||||
fi
|
||||
|
||||
# generate_ephemeral_create_command will produce a distrobox-create command to execute.
|
||||
# Arguments:
|
||||
# None
|
||||
# Expected global variables:
|
||||
# distrobox_path = string distrobox path
|
||||
# name = string container name
|
||||
# extra_flags = string extra flags to inject
|
||||
# create_flags = string create extra flags to inject
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# prints the distrobox-create command handling special flags
|
||||
generate_ephemeral_create_command()
|
||||
{
|
||||
result_command="${distrobox_path}/distrobox-create"
|
||||
if [ -n "${container_manager_additional_flags}" ]; then
|
||||
result_command="${result_command} \
|
||||
--additional-flags \"${container_manager_additional_flags}\""
|
||||
fi
|
||||
if [ -n "${container_additional_packages}" ]; then
|
||||
result_command="${result_command} \
|
||||
--additional-packages \"${container_additional_packages}\""
|
||||
fi
|
||||
if [ -n "${container_init_hook}" ]; then
|
||||
result_command="${result_command} \
|
||||
--init-hooks \"${container_init_hook}\""
|
||||
fi
|
||||
if [ -n "${container_pre_init_hook}" ]; then
|
||||
result_command="${result_command} \
|
||||
--pre-init-hooks \"${container_pre_init_hook}\""
|
||||
fi
|
||||
result_command="${result_command} \
|
||||
${extra_flags} ${create_flags} --yes --name ${name}"
|
||||
|
||||
# Return generated command.
|
||||
printf "%s" "${result_command}"
|
||||
}
|
||||
|
||||
# cleanup will ensure we remove the ephemeral container
|
||||
# Arguments:
|
||||
# None
|
||||
# Expected global variables:
|
||||
# name: string the name of the container
|
||||
# extra_flags: string extra flags to append to the distrobox command
|
||||
# distrobox_path: string path to the distrobox script
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# None
|
||||
cleanup()
|
||||
{
|
||||
trap - TERM INT HUP
|
||||
# shellcheck disable=SC2086
|
||||
"${distrobox_path}"/distrobox-rm ${extra_flags} --force "${name}" --yes
|
||||
}
|
||||
|
||||
cmd="$(generate_ephemeral_create_command)"
|
||||
# shellcheck disable=SC2086
|
||||
eval ${cmd}
|
||||
# shellcheck disable=SC2086
|
||||
"${distrobox_path}"/distrobox-enter ${extra_flags} "${name}" ${container_command}
|
||||
exit_code="$?"
|
||||
|
||||
cleanup
|
||||
|
||||
exit "${exit_code}"
|
||||
711
profiles/desktop/.local/bin/distrobox-export
Executable file
711
profiles/desktop/.local/bin/distrobox-export
Executable file
@@ -0,0 +1,711 @@
|
||||
#!/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.2"
|
||||
|
||||
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
|
||||
378
profiles/desktop/.local/bin/distrobox-generate-entry
Executable file
378
profiles/desktop/.local/bin/distrobox-generate-entry
Executable file
@@ -0,0 +1,378 @@
|
||||
#!/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
|
||||
# Optional env variables:
|
||||
# DBX_CONTAINER_MANAGER
|
||||
# DBX_VERBOSE
|
||||
|
||||
# Despite of running this script via SUDO/DOAS being not supported (the
|
||||
# script itself will call the appropriate tool when necessary), we still want
|
||||
# to allow people to run it as root, logged in in a shell, and create rootful
|
||||
# containers.
|
||||
#
|
||||
# SUDO_USER is a variable set by SUDO and can be used to check whether the script was called by it. Same thing for DOAS_USER, set by DOAS.
|
||||
if {
|
||||
[ -n "${SUDO_USER}" ] || [ -n "${DOAS_USER}" ]
|
||||
} && [ "$(id -ru)" -eq 0 ]; then
|
||||
printf >&2 "Running %s via SUDO/DOAS is not supported. Instead, please try running:\n" "$(basename "${0}")"
|
||||
printf >&2 " %s --root %s\n" "$(basename "${0}")" "$*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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)"
|
||||
|
||||
# If the user runs this script as root in a login shell, set rootful=1.
|
||||
# There's no need for them to pass the --root flag option in such cases.
|
||||
[ "$(id -ru)" -eq 0 ] && rootful=1 || rootful=0
|
||||
extra_flags=""
|
||||
all=0
|
||||
container_manager="autodetect"
|
||||
container_name_default="my-distrobox"
|
||||
delete=0
|
||||
icon="auto"
|
||||
icon_default="${XDG_DATA_HOME:-${HOME}/.local/share}/icons/terminal-distrobox-icon.svg"
|
||||
verbose=0
|
||||
online=0
|
||||
version="1.8.2.2"
|
||||
|
||||
# Source configuration files, this is done in an hierarchy so local files have
|
||||
# priority over system defaults
|
||||
# leave priority to environment variables.
|
||||
#
|
||||
# On NixOS, for the distrobox derivation to pick up a static config file shipped
|
||||
# by the package maintainer the path must be relative to the script itself.
|
||||
self_dir="$(dirname "$(realpath "$0")")"
|
||||
nix_config_file="${self_dir}/../share/distrobox/distrobox.conf"
|
||||
|
||||
config_files="
|
||||
${nix_config_file}
|
||||
/usr/share/distrobox/distrobox.conf
|
||||
/usr/share/defaults/distrobox/distrobox.conf
|
||||
/usr/etc/distrobox/distrobox.conf
|
||||
/usr/local/share/distrobox/distrobox.conf
|
||||
/etc/distrobox/distrobox.conf
|
||||
${XDG_CONFIG_HOME:-"${HOME}/.config"}/distrobox/distrobox.conf
|
||||
${HOME}/.distroboxrc
|
||||
"
|
||||
for config_file in ${config_files}; do
|
||||
# Shellcheck will give error for sourcing a variable file as it cannot follow
|
||||
# it. We don't care so let's disable this linting for now.
|
||||
# shellcheck disable=SC1090
|
||||
[ -e "${config_file}" ] && . "$(realpath "${config_file}")"
|
||||
done
|
||||
|
||||
[ -n "${DBX_CONTAINER_MANAGER}" ] && container_manager="${DBX_CONTAINER_MANAGER}"
|
||||
[ -n "${DBX_VERBOSE}" ] && verbose="${DBX_VERBOSE}"
|
||||
|
||||
# Fixup variable=[true|false], in case we find it in the config file(s)
|
||||
[ "${verbose}" = "true" ] && verbose=1
|
||||
[ "${verbose}" = "false" ] && verbose=0
|
||||
|
||||
# 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-generate-entry container-name [--delete] [--icon [auto,/path/to/icon]]
|
||||
|
||||
Options:
|
||||
|
||||
--help/-h: show this message
|
||||
--all/-a: perform for all distroboxes
|
||||
--delete/-d: delete the entry
|
||||
--icon/-i: specify a custom icon [/path/to/icon] (default auto)
|
||||
--root/-r: perform on rootful distroboxes
|
||||
--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)
|
||||
verbose=1
|
||||
shift
|
||||
;;
|
||||
-V | --version)
|
||||
printf "distrobox: %s\n" "${version}"
|
||||
exit 0
|
||||
;;
|
||||
-d | --delete)
|
||||
delete=1
|
||||
shift
|
||||
;;
|
||||
-a | --all)
|
||||
all=1
|
||||
shift
|
||||
;;
|
||||
-i | --icon)
|
||||
if [ -n "$2" ]; then
|
||||
icon="$2"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
-r | --root)
|
||||
shift
|
||||
rootful=1
|
||||
;;
|
||||
--) # End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*) # 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.
|
||||
# If we have a flagless option and container_name is not specified
|
||||
# then let's accept argument as container_name
|
||||
if [ -n "$1" ]; then
|
||||
container_name="$1"
|
||||
shift
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set verbosity
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
set -o xtrace
|
||||
fi
|
||||
|
||||
if [ -z "${container_name:-}" ]; then
|
||||
container_name="${container_name_default}"
|
||||
fi
|
||||
|
||||
if [ "${all}" -ne 0 ]; then
|
||||
container_names="$(distrobox list --no-color | tail -n +2 | cut -d'|' -f2 | tr -d ' ')"
|
||||
for container_name in ${container_names}; do
|
||||
if [ "${delete}" -ne 0 ]; then
|
||||
"${0}" "${container_name}" --delete
|
||||
continue
|
||||
fi
|
||||
"${0}" "${container_name}"
|
||||
done
|
||||
exit
|
||||
fi
|
||||
|
||||
# If we delete, just ask confirmation and exit.
|
||||
if [ "${delete}" -ne 0 ]; then
|
||||
rm -f "${XDG_DATA_HOME:-${HOME}/.local/share}/applications/${container_name}.desktop"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v curl > /dev/null && ! command -v wget > /dev/null; then
|
||||
printf >&2 "Icon generation depends on either curl or wget\n"
|
||||
printf >&2 "Fallbacking to default icon.\n"
|
||||
download="null"
|
||||
fi
|
||||
|
||||
if command -v curl > /dev/null 2>&1; then
|
||||
download="curl --connect-timeout 3 --retry 1 -sLo"
|
||||
elif command -v wget > /dev/null 2>&1; then
|
||||
download="wget --timeout=3 --tries=1 -qO"
|
||||
fi
|
||||
|
||||
# We depend on a container manager let's be sure we have it
|
||||
# First we use podman, else docker, else lilipod
|
||||
case "${container_manager}" in
|
||||
autodetect)
|
||||
if command -v podman > /dev/null; then
|
||||
container_manager="podman"
|
||||
container_manager_cp_command="podman cp"
|
||||
elif command -v podman-launcher > /dev/null; then
|
||||
container_manager="podman-launcher"
|
||||
container_manager_cp_command="podman-launcher cp"
|
||||
elif command -v docker > /dev/null; then
|
||||
container_manager="docker"
|
||||
container_manager_cp_command="docker cp -L"
|
||||
elif command -v lilipod > /dev/null; then
|
||||
container_manager="lilipod"
|
||||
container_manager_cp_command="lilipod cp"
|
||||
fi
|
||||
;;
|
||||
podman)
|
||||
container_manager="podman"
|
||||
container_manager_cp_command="podman cp"
|
||||
;;
|
||||
podman-launcher)
|
||||
container_manager="podman-launcher"
|
||||
container_manager_cp_command="podman-launcher cp"
|
||||
;;
|
||||
lilipod)
|
||||
container_manager="lilipod"
|
||||
container_manager_cp_command="lilipod cp"
|
||||
;;
|
||||
docker)
|
||||
container_manager="docker"
|
||||
container_manager_cp_command="docker cp -L"
|
||||
;;
|
||||
*)
|
||||
printf >&2 "Invalid input %s.\n" "${container_manager}"
|
||||
printf >&2 "The available choices are: 'autodetect', 'podman', 'docker', 'lilipod'\n"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Be sure we have a container manager to work with.
|
||||
if ! command -v "${container_manager}" > /dev/null; then
|
||||
# Error: we need at least one between docker, podman or lilipod.
|
||||
printf >&2 "Missing dependency: we need a container manager.\n"
|
||||
printf >&2 "Please install one of podman, docker or lilipod.\n"
|
||||
printf >&2 "You can follow the documentation on:\n"
|
||||
printf >&2 "\tman distrobox-compatibility\n"
|
||||
printf >&2 "or:\n"
|
||||
printf >&2 "\thttps://github.com/89luca89/distrobox/blob/main/docs/compatibility.md\n"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
# add verbose if -v is specified
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
container_manager="${container_manager} --log-level debug"
|
||||
container_manager_cp_command="${container_manager_cp_command} --log-level debug"
|
||||
fi
|
||||
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
if [ "${rootful}" -ne 0 ]; then
|
||||
extra_flags="${extra_flags} --root"
|
||||
container_manager="${distrobox_sudo_program:-"sudo"} ${container_manager}"
|
||||
container_manager_cp_command="${distrobox_sudo_program:-"sudo"} ${container_manager_cp_command}"
|
||||
fi
|
||||
|
||||
if ! ${container_manager} inspect --type container "${container_name}" > /dev/null; then
|
||||
printf >&2 "Cannot find container %s. Please create it first.\n" "${container_name}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure the destination dir exists.
|
||||
mkdir -p "${XDG_DATA_HOME:-${HOME}/.local/share}/applications"
|
||||
mkdir -p "${XDG_DATA_HOME:-${HOME}/.local/share}/icons/distrobox"
|
||||
|
||||
distrobox_path="$(dirname "$(realpath "${0}")")"
|
||||
entry_name="$(echo "${container_name}" | cut -c1 | tr "[:lower:]" "[:upper:]")$(echo "${container_name}" | cut -c2-)"
|
||||
|
||||
if [ "${icon}" = "auto" ]; then
|
||||
# Set icon to the generic terminal as a fallback.
|
||||
icon="${icon_default}"
|
||||
# This is a NON comprehensive list of logos of the most popular distributions. If you find logos for
|
||||
# other supported distros, add it here.
|
||||
DISTRO_ICON_MAP="
|
||||
alma:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/alma-distrobox.png
|
||||
alpine:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/alpine-distrobox.png
|
||||
alt:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/alt-distrobox.png
|
||||
arch:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/arch-distrobox.png
|
||||
centos:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/centos-distrobox.png
|
||||
clear--os:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/clear-distrobox.png
|
||||
debian:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/debian-distrobox.png
|
||||
deepin:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/deepin-distrobox.png
|
||||
fedora:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/fedora-distrobox.png
|
||||
gentoo:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/gentoo-distrobox.png
|
||||
kali:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/kali-distrobox.png
|
||||
kdeneon:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/kdeneon-distrobox.png
|
||||
opensuse-leap:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/opensuse-distrobox.png
|
||||
opensuse-tumbleweed:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/opensuse-distrobox.png
|
||||
rhel:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/redhat-distrobox.png
|
||||
rocky:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/rocky-distrobox.png
|
||||
ubuntu:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/ubuntu-distrobox.png
|
||||
vanilla:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/vanilla-distrobox.png
|
||||
void:https://raw.githubusercontent.com/89luca89/distrobox/main/docs/assets/png/distros/void-distrobox.png
|
||||
"
|
||||
# Try to detect container's distribution by using /etc/os-release
|
||||
${container_manager_cp_command} "${container_name}":/etc/os-release /tmp/"${container_name}".os-release
|
||||
container_distro="$(grep "^ID=" /tmp/"${container_name}".os-release |
|
||||
cut -d'=' -f2- |
|
||||
sed "s|linux||g" |
|
||||
tr -d ' ' |
|
||||
tr -d '"')"
|
||||
|
||||
if [ "${rootful}" -ne 0 ]; then
|
||||
${distrobox_sudo_program:-"sudo"} rm -f /tmp/"${container_name}".os-release
|
||||
else
|
||||
rm -f /tmp/"${container_name}".os-release
|
||||
fi
|
||||
|
||||
icon_url="$(echo "${DISTRO_ICON_MAP}" | grep "${container_distro}:" | cut -d':' -f2-)"
|
||||
|
||||
# Distro not found in our map, fallback to generic icon
|
||||
if [ -z "${icon_url}" ]; then
|
||||
icon_url="https://raw.githubusercontent.com/89luca89/distrobox/main/icons/terminal-distrobox-icon.svg"
|
||||
container_distro="terminal-distrobox-icon"
|
||||
fi
|
||||
|
||||
if [ -n "${icon_url}" ] && [ "${download}" != "null" ]; then
|
||||
icon_extension="${icon_url##*.}"
|
||||
|
||||
if [ "${online}" -lt 1 ] && ${download} - "${icon_url}" > "${XDG_DATA_HOME:-${HOME}/.local/share}/icons/distrobox/${container_distro}.${icon_extension}"; then
|
||||
icon="${XDG_DATA_HOME:-${HOME}/.local/share}/icons/distrobox/${container_distro}.${icon_extension}"
|
||||
else
|
||||
# Wget failed for some reasons. Default to generic terminal icon as declared at the beginning.
|
||||
printf >&2 "Warning: Failed to download icon. Defaulting to generic one.\n"
|
||||
fi
|
||||
else
|
||||
# Distribution not found in the list. Default to generic terminal icon as declared at the beginning.
|
||||
printf >&2 "Warning: Distribution not found in default icon set. Defaulting to generic one.\n"
|
||||
fi
|
||||
fi
|
||||
|
||||
cat << EOF > "${XDG_DATA_HOME:-${HOME}/.local/share}/applications/${container_name}.desktop"
|
||||
[Desktop Entry]
|
||||
Name=${entry_name}
|
||||
GenericName=Terminal entering ${entry_name}
|
||||
Comment=Terminal entering ${entry_name}
|
||||
Categories=Distrobox;System;Utility
|
||||
Exec=${distrobox_path}/distrobox enter ${extra_flags} ${container_name}
|
||||
Icon=${icon}
|
||||
Keywords=distrobox;
|
||||
NoDisplay=false
|
||||
Terminal=true
|
||||
TryExec=${distrobox_path}/distrobox
|
||||
Type=Application
|
||||
Actions=Remove;
|
||||
|
||||
[Desktop Action Remove]
|
||||
Name=Remove ${entry_name} from system
|
||||
Exec=${distrobox_path}/distrobox rm ${extra_flags} ${container_name}
|
||||
EOF
|
||||
234
profiles/desktop/.local/bin/distrobox-host-exec
Executable file
234
profiles/desktop/.local/bin/distrobox-host-exec
Executable file
@@ -0,0 +1,234 @@
|
||||
#!/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.2"
|
||||
|
||||
# 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 $?
|
||||
2811
profiles/desktop/.local/bin/distrobox-init
Executable file
2811
profiles/desktop/.local/bin/distrobox-init
Executable file
File diff suppressed because it is too large
Load Diff
240
profiles/desktop/.local/bin/distrobox-install
Executable file
240
profiles/desktop/.local/bin/distrobox-install
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/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
|
||||
|
||||
next=0
|
||||
no_color=0
|
||||
verbose=0
|
||||
version=1.8.2.2
|
||||
|
||||
# show_help will print usage to stdout.
|
||||
# Arguments:
|
||||
# None
|
||||
# Outputs:
|
||||
# print usage with examples.
|
||||
show_help()
|
||||
{
|
||||
cat << EOF
|
||||
install --prefix /usr/local
|
||||
|
||||
Options:
|
||||
--prefix/-P: base bath where all files will be deployed (default /usr/local if root, ~/.local if not)
|
||||
--next/-N: install latest development version from git, instead of the latest stable release.
|
||||
--no-color: disable color formatting
|
||||
--help/-h: show this message
|
||||
-v: show more verbosity
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
while :; do
|
||||
case $1 in
|
||||
-h | --help)
|
||||
# Call a "show_help" function to display a synopsis, then exit.
|
||||
show_help
|
||||
exit
|
||||
;;
|
||||
--no-color)
|
||||
shift
|
||||
no_color=1
|
||||
;;
|
||||
-v | --verbose)
|
||||
shift
|
||||
verbose=1
|
||||
;;
|
||||
-N | --next)
|
||||
shift
|
||||
next=1
|
||||
;;
|
||||
-P | --prefix)
|
||||
if [ -n "$2" ]; then
|
||||
prefix="$2"
|
||||
shift
|
||||
shift
|
||||
fi
|
||||
;;
|
||||
*) # Default case: If no more options then break out of the loop.
|
||||
break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# if we're in not a tty, don't use colors
|
||||
BOLD_GREEN=""
|
||||
BOLD_RED=""
|
||||
CLEAR=""
|
||||
if [ -t 0 ] && [ -t 1 ] && [ "${no_color}" -ne 1 ]; then
|
||||
# we're in a tty, use colors
|
||||
BOLD_GREEN='\033[1;32m'
|
||||
BOLD_RED='\033[1;31m'
|
||||
CLEAR='\033[0m'
|
||||
fi
|
||||
|
||||
if [ -z "${prefix}" ]; then
|
||||
prefix="/usr/local"
|
||||
# in case we're not root, just default to the home directory
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
prefix="${HOME}/.local"
|
||||
fi
|
||||
fi
|
||||
dest_path="${prefix}/bin"
|
||||
man_dest_path="${prefix}/share/man/man1"
|
||||
icon_dest_path="${prefix}/share/icons/hicolor"
|
||||
completion_bash_dest_path="${prefix}/share/bash-completion/completions/"
|
||||
completion_zsh_dest_path="${prefix}/share/zsh/site-functions/"
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set verbosity
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
set -o xtrace
|
||||
fi
|
||||
|
||||
# get current dir
|
||||
curr_dir=$(dirname "$0")
|
||||
cd "${curr_dir}" || exit 1
|
||||
|
||||
# if files are available, install files in dest directory
|
||||
# else download targz and uncompress it
|
||||
if [ -e "${curr_dir}/distrobox-enter" ]; then
|
||||
if ! install -d "${dest_path}" "${man_dest_path}" "${completion_bash_dest_path}" \
|
||||
"${completion_zsh_dest_path}" "${icon_dest_path}/scalable/apps"; then
|
||||
printf >&2 "Do you have permission to write to %s?\n" "${prefix}"
|
||||
exit 1
|
||||
fi
|
||||
for file in distrobox*; do
|
||||
if ! install -m 0755 "${file}" "${dest_path}"; then
|
||||
printf >&2 "Do you have permission to write to %s?\n" "${dest_path}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
if [ -e "man" ]; then
|
||||
for file in man/man1/*; do
|
||||
install -m 0644 "${file}" "${man_dest_path}"
|
||||
done
|
||||
fi
|
||||
if [ -e "completions" ]; then
|
||||
for file in completions/bash/*; do
|
||||
install -m 0644 "${file}" "${completion_bash_dest_path}"
|
||||
done
|
||||
fi
|
||||
if [ -e "completions" ]; then
|
||||
for file in completions/zsh/*; do
|
||||
install -m 0644 "${file}" "${completion_zsh_dest_path}"
|
||||
done
|
||||
fi
|
||||
if [ -e icons/terminal-distrobox-icon.svg ]; then
|
||||
install -m 0644 icons/terminal-distrobox-icon.svg "${icon_dest_path}/scalable/apps"
|
||||
for sz in 16 22 24 32 36 48 64 72 96 128 256; do
|
||||
install -d "${icon_dest_path}/${sz}x${sz}/apps"
|
||||
install -m 0644 icons/hicolor/"${sz}x${sz}"/apps/terminal-distrobox-icon.png \
|
||||
"${icon_dest_path}/${sz}x${sz}/apps"
|
||||
done
|
||||
fi
|
||||
else
|
||||
printf >&2 "%b Checking dependencies...\n%b" "${BOLD_GREEN}" "${CLEAR}"
|
||||
# check that we have base dependencies
|
||||
if ! {
|
||||
command -v curl > /dev/null || command -v wget > /dev/null
|
||||
} || ! command -v tar > /dev/null; then
|
||||
printf >&2 "Online install depends on tar and either curl or wget\n"
|
||||
printf >&2 "Ensure you have all dependencies installed.\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if command -v curl > /dev/null 2>&1; then
|
||||
download="curl -sLo"
|
||||
elif command -v wget > /dev/null 2>&1; then
|
||||
download="wget -qO"
|
||||
fi
|
||||
|
||||
printf >&2 "%b Downloading...\n%b" "${BOLD_RED}" "${CLEAR}"
|
||||
if [ "${next}" -eq 0 ]; then
|
||||
release_ver="89luca89/distrobox/archive/refs/tags/${version}.tar.gz"
|
||||
release_name=$(basename "${release_ver}")
|
||||
else
|
||||
release_ver="89luca89/distrobox/archive/refs/heads/main.tar.gz"
|
||||
release_name="main"
|
||||
fi
|
||||
# go in tmp
|
||||
tmp_dir="$(mktemp -d)"
|
||||
cd "${tmp_dir}"
|
||||
# download our target
|
||||
${download} "${release_name}" "https://github.com/${release_ver}"
|
||||
# uncompress
|
||||
printf >&2 "%b Unpacking...\n%b" "${BOLD_RED}" "${CLEAR}"
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
tar xvf "${release_name}"
|
||||
else
|
||||
tar xf "${release_name}"
|
||||
fi
|
||||
# deploy our files
|
||||
if ! install -d "${dest_path}" "${man_dest_path}" "${completion_bash_dest_path}" \
|
||||
"${completion_zsh_dest_path}" "${icon_dest_path}/scalable/apps"; then
|
||||
printf >&2 "Do you have permission to write to %s?\n" "${prefix}"
|
||||
exit 1
|
||||
fi
|
||||
for file in "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')"/distrobox*; do
|
||||
if ! install -m 0755 "${file}" "${dest_path}"; then
|
||||
printf >&2 "Do you have permission to write to %s?\n" "${dest_path}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
if [ -e "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')/man/" ]; then
|
||||
for file in "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')"/man/man1/*; do
|
||||
install -m 0644 "${file}" "${man_dest_path}"
|
||||
done
|
||||
fi
|
||||
if [ -e "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')/completions/bash/" ]; then
|
||||
for file in "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')"/completions/bash/*; do
|
||||
install -m 0644 "${file}" "${completion_bash_dest_path}"
|
||||
done
|
||||
fi
|
||||
if [ -e "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')/completions/zsh/" ]; then
|
||||
for file in "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')"/completions/zsh/*; do
|
||||
install -m 0644 "${file}" "${completion_zsh_dest_path}"
|
||||
done
|
||||
fi
|
||||
if [ -e "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')"/icons/terminal-distrobox-icon.svg ]; then
|
||||
install -m 0644 "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')"/icons/terminal-distrobox-icon.svg \
|
||||
"${icon_dest_path}/scalable/apps"
|
||||
for sz in 16 22 24 32 36 48 64 72 96 128 256; do
|
||||
install -d "${icon_dest_path}/${sz}x${sz}/apps"
|
||||
install -m 0644 "distrobox-$(echo "${release_name}" | sed 's/.tar.gz//g')/icons/hicolor/${sz}x${sz}/apps/terminal-distrobox-icon.png" \
|
||||
"${icon_dest_path}/${sz}x${sz}/apps"
|
||||
done
|
||||
fi
|
||||
|
||||
# securely delete unneeded files
|
||||
cd
|
||||
if [ -n "${tmp_dir}" ] && [ -e "${tmp_dir}" ]; then
|
||||
rm -rf "${tmp_dir}"
|
||||
fi
|
||||
fi
|
||||
|
||||
[ ! -w "${dest_path}" ] && printf >&2 "Cannot write into %s, permission denied.\n" "${dest_path}" && exit 1
|
||||
[ ! -w "${man_dest_path}" ] && printf >&2 "Cannot write into %s, permission denied.\n" "${man_dest_path}" && exit 1
|
||||
|
||||
printf >&2 "%b Installation successful!\n%b" "${BOLD_GREEN}" "${CLEAR}"
|
||||
printf >&2 "%b Shell scripts are located in %b%s\n%b" "${CLEAR}" "${BOLD_RED}" "${dest_path}" "${CLEAR}"
|
||||
printf >&2 "%b Manpages are located in %b%s\n%b" "${CLEAR}" "${BOLD_RED}" "${man_dest_path}" "${CLEAR}"
|
||||
|
||||
if ! echo "${PATH}" | grep -q "${dest_path}"; then
|
||||
printf >&2 "%b Be sure that %b%s%b is in your %b\$PATH%b environment variable to be able to use distrobox without specifying the full path.\n%s" "${CLEAR}" "${BOLD_RED}" "${dest_path}" "${CLEAR}" "${BOLD_RED}" "${CLEAR}" "${CLEAR}"
|
||||
fi
|
||||
276
profiles/desktop/.local/bin/distrobox-list
Executable file
276
profiles/desktop/.local/bin/distrobox-list
Executable file
@@ -0,0 +1,276 @@
|
||||
#!/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
|
||||
# Optional env variables:
|
||||
# DBX_CONTAINER_MANAGER
|
||||
# DBX_VERBOSE
|
||||
# DBX_SUDO_PROGRAM
|
||||
|
||||
# Despite of running this script via SUDO/DOAS being not supported (the
|
||||
# script itself will call the appropriate tool when necessary), we still want
|
||||
# to allow people to run it as root, logged in in a shell, and create rootful
|
||||
# containers.
|
||||
#
|
||||
# SUDO_USER is a variable set by SUDO and can be used to check whether the script was called by it. Same thing for DOAS_USER, set by DOAS.
|
||||
if {
|
||||
[ -n "${SUDO_USER}" ] || [ -n "${DOAS_USER}" ]
|
||||
} && [ "$(id -ru)" -eq 0 ]; then
|
||||
printf >&2 "Running %s via SUDO/DOAS is not supported. Instead, please try running:\n" "$(basename "${0}")"
|
||||
printf >&2 " %s --root %s\n" "$(basename "${0}")" "$*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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
|
||||
no_color=0
|
||||
# If the user runs this script as root in a login shell, set rootful=1.
|
||||
# There's no need for them to pass the --root flag option in such cases.
|
||||
[ "$(id -ru)" -eq 0 ] && rootful=1 || rootful=0
|
||||
verbose=0
|
||||
version="1.8.2.2"
|
||||
container_manager="autodetect"
|
||||
|
||||
# Source configuration files, this is done in an hierarchy so local files have
|
||||
# priority over system defaults
|
||||
# leave priority to environment variables.
|
||||
#
|
||||
# On NixOS, for the distrobox derivation to pick up a static config file shipped
|
||||
# by the package maintainer the path must be relative to the script itself.
|
||||
self_dir="$(dirname "$(realpath "$0")")"
|
||||
nix_config_file="${self_dir}/../share/distrobox/distrobox.conf"
|
||||
|
||||
config_files="
|
||||
${nix_config_file}
|
||||
/usr/share/distrobox/distrobox.conf
|
||||
/usr/share/defaults/distrobox/distrobox.conf
|
||||
/usr/etc/distrobox/distrobox.conf
|
||||
/usr/local/share/distrobox/distrobox.conf
|
||||
/etc/distrobox/distrobox.conf
|
||||
${XDG_CONFIG_HOME:-"${HOME}/.config"}/distrobox/distrobox.conf
|
||||
${HOME}/.distroboxrc
|
||||
"
|
||||
for config_file in ${config_files}; do
|
||||
# Shellcheck will give error for sourcing a variable file as it cannot follow
|
||||
# it. We don't care so let's disable this linting for now.
|
||||
# shellcheck disable=SC1090
|
||||
[ -e "${config_file}" ] && . "$(realpath "${config_file}")"
|
||||
done
|
||||
|
||||
[ -n "${DBX_VERBOSE}" ] && verbose="${DBX_VERBOSE}"
|
||||
|
||||
# Fixup variable=[true|false], in case we find it in the config file(s)
|
||||
[ "${verbose}" = "true" ] && verbose=1
|
||||
[ "${verbose}" = "false" ] && verbose=0
|
||||
|
||||
# If we're running this script as root -- as in logged in in the shell as root
|
||||
# user, and not via SUDO/DOAS --, we don't need to set distrobox_sudo_program
|
||||
# as it's meaningless for this use case.
|
||||
if [ "$(id -ru)" -ne 0 ]; then
|
||||
# If the DBX_SUDO_PROGRAM/distrobox_sudo_program variable was set by the
|
||||
# user, use its value instead of "sudo". But only if not running the script
|
||||
# as root (UID 0).
|
||||
distrobox_sudo_program=${DBX_SUDO_PROGRAM:-${distrobox_sudo_program:-"sudo"}}
|
||||
fi
|
||||
[ -n "${DBX_CONTAINER_MANAGER}" ] && container_manager="${DBX_CONTAINER_MANAGER}"
|
||||
|
||||
# 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-list
|
||||
|
||||
Options:
|
||||
|
||||
--help/-h: show this message
|
||||
--no-color: disable color formatting
|
||||
--root/-r: launch podman/docker/lilipod with root privileges. Note that if you need root this is the preferred
|
||||
way over "sudo distrobox" (note: if using a program other than 'sudo' for root privileges is necessary,
|
||||
specify it through the DBX_SUDO_PROGRAM env variable, or 'distrobox_sudo_program' config variable)
|
||||
--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
|
||||
;;
|
||||
--no-color)
|
||||
shift
|
||||
no_color=1
|
||||
;;
|
||||
-r | --root)
|
||||
shift
|
||||
rootful=1
|
||||
;;
|
||||
-v | --verbose)
|
||||
verbose=1
|
||||
shift
|
||||
;;
|
||||
-V | --version)
|
||||
printf "distrobox: %s\n" "${version}"
|
||||
exit 0
|
||||
;;
|
||||
--) # End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*) # 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
|
||||
|
||||
# We depend on a container manager let's be sure we have it
|
||||
# First we use podman, else docker, else lilipod
|
||||
case "${container_manager}" in
|
||||
autodetect)
|
||||
if command -v podman > /dev/null; then
|
||||
container_manager="podman"
|
||||
elif command -v podman-launcher > /dev/null; then
|
||||
container_manager="podman-launcher"
|
||||
elif command -v docker > /dev/null; then
|
||||
container_manager="docker"
|
||||
elif command -v lilipod > /dev/null; then
|
||||
container_manager="lilipod"
|
||||
fi
|
||||
;;
|
||||
podman)
|
||||
container_manager="podman"
|
||||
;;
|
||||
podman-launcher)
|
||||
container_manager="podman-launcher"
|
||||
;;
|
||||
lilipod)
|
||||
container_manager="lilipod"
|
||||
;;
|
||||
docker)
|
||||
container_manager="docker"
|
||||
;;
|
||||
*)
|
||||
printf >&2 "Invalid input %s.\n" "${container_manager}"
|
||||
printf >&2 "The available choices are: 'autodetect', 'podman', 'docker', 'lilipod'\n"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Be sure we have a container manager to work with.
|
||||
if ! command -v "${container_manager}" > /dev/null; then
|
||||
# Error: we need at least one between docker, podman or lilipod.
|
||||
printf >&2 "Missing dependency: we need a container manager.\n"
|
||||
printf >&2 "Please install one of podman, docker or lilipod.\n"
|
||||
printf >&2 "You can follow the documentation on:\n"
|
||||
printf >&2 "\tman distrobox-compatibility\n"
|
||||
printf >&2 "or:\n"
|
||||
printf >&2 "\thttps://github.com/89luca89/distrobox/blob/main/docs/compatibility.md\n"
|
||||
exit 127
|
||||
fi
|
||||
# add verbose if -v is specified
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
container_manager="${container_manager} --log-level debug"
|
||||
fi
|
||||
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
if [ "${rootful}" -ne 0 ]; then
|
||||
container_manager="${distrobox_sudo_program-} ${container_manager}"
|
||||
fi
|
||||
|
||||
# List containers using custom format that included MOUNTS
|
||||
# we do this as we can detect the custom mounts done by distrobox to distringuish
|
||||
# between a normal container and a distrobox one.
|
||||
container_list=$(${container_manager} ps -a --no-trunc --format \
|
||||
"{{.ID}}|{{.Image}}|{{.Names}}|{{.Status}}|{{.Labels}}{{.Mounts}}")
|
||||
printf "%-12s | %-20s | %-18s | %-30s\n" \
|
||||
"ID" "NAME" "STATUS" "IMAGE"
|
||||
IFS='
|
||||
'
|
||||
|
||||
# if we're in not a tty, don't use colors
|
||||
GREEN=""
|
||||
YELLOW=""
|
||||
CLEAR=""
|
||||
if [ -t 0 ] && [ -t 1 ] && [ "${no_color}" -ne 1 ]; then
|
||||
# we're in a tty, use colors
|
||||
GREEN='\033[32m'
|
||||
YELLOW='\033[33m'
|
||||
CLEAR='\033[0m'
|
||||
fi
|
||||
# Header of the output
|
||||
for container in ${container_list}; do
|
||||
# Check if the current container has a custom mount point for distrobox.
|
||||
if [ -z "${container##*distrobox*}" ]; then
|
||||
|
||||
# Extract the information for the single container to pretty print it
|
||||
container_id="$(printf "%s" "${container}" | cut -d'|' -f1 | cut -c1-12)"
|
||||
container_image="$(printf "%s" "${container}" | cut -d'|' -f2)"
|
||||
container_name="$(printf "%s" "${container}" | cut -d'|' -f3)"
|
||||
container_status="$(printf "%s" "${container}" | cut -d'|' -f4)"
|
||||
|
||||
IFS=' '
|
||||
|
||||
# If the container is Up and Running, print it in green and go next.
|
||||
if [ -z "${container_status##*Up*}" ] || [ -z "${container_status##*running*}" ]; then
|
||||
# echo -e is not defined in posix, and printing with %s will not work
|
||||
# for colors, so we're disabling this lint for color prints.
|
||||
# shellcheck disable=SC2059
|
||||
printf "${GREEN}"
|
||||
else
|
||||
# shellcheck disable=SC2059
|
||||
printf "${YELLOW}"
|
||||
fi
|
||||
# print it in yellow if not Running
|
||||
printf "%-12s | %-20s | %-18s | %-30s" \
|
||||
"${container_id}" "${container_name}" "${container_status}" "${container_image}"
|
||||
|
||||
# shellcheck disable=SC2059
|
||||
printf "${CLEAR}\n"
|
||||
fi
|
||||
done
|
||||
464
profiles/desktop/.local/bin/distrobox-rm
Executable file
464
profiles/desktop/.local/bin/distrobox-rm
Executable file
@@ -0,0 +1,464 @@
|
||||
#!/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
|
||||
# Optional env variables:
|
||||
# DBX_CONTAINER_MANAGER
|
||||
# DBX_CONTAINER_NAME
|
||||
# DBX_CONTAINER_RM_CUSTOM_HOME
|
||||
# DBX_NON_INTERACTIVE
|
||||
# DBX_VERBOSE
|
||||
# DBX_SUDO_PROGRAM
|
||||
|
||||
# Despite of running this script via SUDO/DOAS being not supported (the
|
||||
# script itself will call the appropriate tool when necessary), we still want
|
||||
# to allow people to run it as root, logged in in a shell, and create rootful
|
||||
# containers.
|
||||
#
|
||||
# SUDO_USER is a variable set by SUDO and can be used to check whether the script was called by it. Same thing for DOAS_USER, set by DOAS.
|
||||
if {
|
||||
[ -n "${SUDO_USER}" ] || [ -n "${DOAS_USER}" ]
|
||||
} && [ "$(id -ru)" -eq 0 ]; then
|
||||
printf >&2 "Running %s via SUDO/DOAS is not supported. Instead, please try running:\n" "$(basename "${0}")"
|
||||
printf >&2 " %s --root %s\n" "$(basename "${0}")" "$*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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
|
||||
all=0
|
||||
container_manager="autodetect"
|
||||
distrobox_flags=""
|
||||
distrobox_path="$(dirname "$(realpath "${0}")")"
|
||||
force=0
|
||||
force_flag=""
|
||||
non_interactive=0
|
||||
# If the user runs this script as root in a login shell, set rootful=1.
|
||||
# There's no need for them to pass the --root flag option in such cases.
|
||||
[ "$(id -ru)" -eq 0 ] && rootful=1 || rootful=0
|
||||
verbose=0
|
||||
rm_home=0
|
||||
response_rm_home="N"
|
||||
version="1.8.2.2"
|
||||
|
||||
# Source configuration files, this is done in an hierarchy so local files have
|
||||
# priority over system defaults
|
||||
# leave priority to environment variables.
|
||||
#
|
||||
# On NixOS, for the distrobox derivation to pick up a static config file shipped
|
||||
# by the package maintainer the path must be relative to the script itself.
|
||||
self_dir="$(dirname "$(realpath "$0")")"
|
||||
nix_config_file="${self_dir}/../share/distrobox/distrobox.conf"
|
||||
|
||||
config_files="
|
||||
${nix_config_file}
|
||||
/usr/share/distrobox/distrobox.conf
|
||||
/usr/share/defaults/distrobox/distrobox.conf
|
||||
/usr/etc/distrobox/distrobox.conf
|
||||
/usr/local/share/distrobox/distrobox.conf
|
||||
/etc/distrobox/distrobox.conf
|
||||
${XDG_CONFIG_HOME:-"${HOME}/.config"}/distrobox/distrobox.conf
|
||||
${HOME}/.distroboxrc
|
||||
"
|
||||
for config_file in ${config_files}; do
|
||||
# Shellcheck will give error for sourcing a variable file as it cannot follow
|
||||
# it. We don't care so let's disable this linting for now.
|
||||
# shellcheck disable=SC1090
|
||||
[ -e "${config_file}" ] && . "$(realpath "${config_file}")"
|
||||
done
|
||||
|
||||
[ -n "${DBX_CONTAINER_MANAGER}" ] && container_manager="${DBX_CONTAINER_MANAGER}"
|
||||
[ -n "${DBX_CONTAINER_RM_CUSTOM_HOME}" ] && rm_home="${DBX_CONTAINER_RM_CUSTOM_HOME}"
|
||||
[ -n "${DBX_NON_INTERACTIVE}" ] && non_interactive="${DBX_NON_INTERACTIVE}"
|
||||
[ -n "${DBX_VERBOSE}" ] && verbose="${DBX_VERBOSE}"
|
||||
|
||||
# Fixup variable=[true|false], in case we find it in the config file(s)
|
||||
[ "${non_interactive}" = "true" ] && non_interactive=1
|
||||
[ "${non_interactive}" = "false" ] && non_interactive=0
|
||||
[ "${verbose}" = "true" ] && verbose=1
|
||||
[ "${verbose}" = "false" ] && verbose=0
|
||||
|
||||
# If we're running this script as root - as in logged in in the shell as root
|
||||
# user, and not via SUDO/DOAS -, we don't need to set distrobox_sudo_program
|
||||
# as it's meaningless for this use case.
|
||||
if [ "$(id -ru)" -ne 0 ]; then
|
||||
# If the DBX_SUDO_PROGRAM/distrobox_sudo_program variable was set by the
|
||||
# user, use its value instead of "sudo". But only if not running the script
|
||||
# as root (UID 0).
|
||||
distrobox_sudo_program=${DBX_SUDO_PROGRAM:-${distrobox_sudo_program:-"sudo"}}
|
||||
fi
|
||||
|
||||
# Declare it AFTER config sourcing because we do not want a default name set for rm.
|
||||
container_name_default="my-distrobox"
|
||||
container_name_list=""
|
||||
|
||||
# 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-rm [-f/--force] container-name [container-name1 container-name2 ...]
|
||||
|
||||
Options:
|
||||
|
||||
--all/-a: delete all distroboxes
|
||||
--force/-f: force deletion
|
||||
--rm-home: remove the mounted home if it differs from the host user's one
|
||||
--root/-r: launch podman/docker/lilipod with root privileges. Note that if you need root this is the preferred
|
||||
way over "sudo distrobox" (note: if using a program other than 'sudo' for root privileges is necessary,
|
||||
specify it through the DBX_SUDO_PROGRAM env variable, or 'distrobox_sudo_program' config variable)
|
||||
--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
|
||||
;;
|
||||
-a | --all)
|
||||
shift
|
||||
all=1
|
||||
;;
|
||||
-r | --root)
|
||||
shift
|
||||
rootful=1
|
||||
;;
|
||||
--rm-home)
|
||||
shift
|
||||
rm_home=1
|
||||
;;
|
||||
-v | --verbose)
|
||||
verbose=1
|
||||
shift
|
||||
;;
|
||||
-V | --version)
|
||||
printf "distrobox: %s\n" "${version}"
|
||||
exit 0
|
||||
;;
|
||||
-f | --force)
|
||||
force=1
|
||||
non_interactive=1
|
||||
shift
|
||||
;;
|
||||
-Y | --yes)
|
||||
non_interactive=1
|
||||
shift
|
||||
;;
|
||||
--) # End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*) # 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.
|
||||
# If we have a flagless option and container_name is not specified
|
||||
# then let's accept argument as container_name
|
||||
if [ -n "$1" ]; then
|
||||
container_name_list="${container_name_list} $1"
|
||||
shift
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set verbosity
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
set -o xtrace
|
||||
fi
|
||||
|
||||
# We depend on a container manager let's be sure we have it
|
||||
# First we use podman, else docker, else lilipod
|
||||
case "${container_manager}" in
|
||||
autodetect)
|
||||
if command -v podman > /dev/null; then
|
||||
container_manager="podman"
|
||||
elif command -v podman-launcher > /dev/null; then
|
||||
container_manager="podman-launcher"
|
||||
elif command -v docker > /dev/null; then
|
||||
container_manager="docker"
|
||||
elif command -v lilipod > /dev/null; then
|
||||
container_manager="lilipod"
|
||||
fi
|
||||
;;
|
||||
podman)
|
||||
container_manager="podman"
|
||||
;;
|
||||
podman-launcher)
|
||||
container_manager="podman-launcher"
|
||||
;;
|
||||
lilipod)
|
||||
container_manager="lilipod"
|
||||
;;
|
||||
docker)
|
||||
container_manager="docker"
|
||||
;;
|
||||
*)
|
||||
printf >&2 "Invalid input %s.\n" "${container_manager}"
|
||||
printf >&2 "The available choices are: 'autodetect', 'podman', 'docker', 'lilipod'\n"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Be sure we have a container manager to work with.
|
||||
if ! command -v "${container_manager}" > /dev/null; then
|
||||
# Error: we need at least one between docker, podman or lilipod.
|
||||
printf >&2 "Missing dependency: we need a container manager.\n"
|
||||
printf >&2 "Please install one of podman, docker or lilipod.\n"
|
||||
printf >&2 "You can follow the documentation on:\n"
|
||||
printf >&2 "\tman distrobox-compatibility\n"
|
||||
printf >&2 "or:\n"
|
||||
printf >&2 "\thttps://github.com/89luca89/distrobox/blob/main/docs/compatibility.md\n"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
# add verbose if -v is specified
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
container_manager="${container_manager} --log-level debug"
|
||||
fi
|
||||
|
||||
# add -f if force is specified
|
||||
if [ "${force}" -ne 0 ]; then
|
||||
force_flag="--force"
|
||||
fi
|
||||
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
if [ "${rootful}" -ne 0 ]; then
|
||||
container_manager="${distrobox_sudo_program-} ${container_manager}"
|
||||
distrobox_flags="--root"
|
||||
fi
|
||||
|
||||
# If all, just set container_name to the list of names in distrobox-list
|
||||
if [ "${all}" -ne 0 ]; then
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
# shellcheck disable=SC2086,2248
|
||||
container_name_list="$("${distrobox_path}"/distrobox-list ${distrobox_flags} --no-color |
|
||||
tail -n +2 | cut -d'|' -f2 | tr -d ' ' | tr '\n' ' ')"
|
||||
fi
|
||||
|
||||
if [ -z "${container_name_list}" ] && [ "${all}" -ne 0 ]; then
|
||||
printf >&2 "No containers found.\n"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# check if we have containers to delete
|
||||
if [ -z "${container_name_list}" ]; then
|
||||
container_name_list="${container_name_default}"
|
||||
fi
|
||||
|
||||
# cleanup_exports will remove exported apps and bins for container to delete.
|
||||
# Arguments:
|
||||
# container_name: string container name
|
||||
# Expected global variables:
|
||||
# distrobox_flags: string additional distrobox flags to use
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# None
|
||||
cleanup_exports()
|
||||
{
|
||||
container_name="$1"
|
||||
IFS='¤'
|
||||
printf "Removing exported binaries...\n"
|
||||
binary_files="$(grep -rl "# distrobox_binary" "${HOME}/.local/bin" 2> /dev/null | sed 's/./\\&/g' |
|
||||
xargs -I{} grep -le "# name: ${container_name}$" "{}" | sed 's/./\\&/g' |
|
||||
xargs -I{} printf "%s¤" "{}" 2> /dev/null || :)"
|
||||
for file in ${binary_files}; do
|
||||
printf "Removing exported binary %s...\n" "${file}"
|
||||
rm -f "${file}"
|
||||
done
|
||||
|
||||
# Remove exported gui apps from this container in default path
|
||||
# shellcheck disable=SC2086,SC2038
|
||||
desktop_files="$(find "${HOME}/.local/share/applications/${container_name}"* -type f -o -type l 2> /dev/null | sed 's/./\\&/g' |
|
||||
xargs -I{} grep -le "Exec=.*${container_name} " "{}" | sed 's/./\\&/g' |
|
||||
xargs -I{} printf "%s¤" "{}" 2> /dev/null || :)"
|
||||
for file in ${desktop_files}; do
|
||||
if [ -e "${file}" ]; then
|
||||
app="$(grep -Eo "Name=.*" "${file}" | head -n 1 | cut -d'=' -f2)"
|
||||
icon="$(grep -Eo "Icon=.*" "${file}" | head -n 1 | cut -d'=' -f2)"
|
||||
|
||||
printf "Removing exported app %s...\n" "${app}"
|
||||
rm -f "${file}"
|
||||
find "${HOME}/.local/share/icons" -name "${icon}.*" -delete
|
||||
fi
|
||||
done
|
||||
unset IFS
|
||||
}
|
||||
|
||||
# delete_container will remove input container
|
||||
# Arguments:
|
||||
# container_name: string container name
|
||||
# Expected global variables:
|
||||
# container_manager: string container manager to use
|
||||
# distrobox_flags: string distrobox additional flags
|
||||
# non_interactive: bool non interactive mode
|
||||
# force_flag: bool force mode
|
||||
# rm_home: bool remove home
|
||||
# verbose: bool verbose
|
||||
# Expected env variables:
|
||||
# None
|
||||
# Outputs:
|
||||
# None
|
||||
delete_container()
|
||||
{
|
||||
container_name="$1"
|
||||
# Inspect the container we're working with.
|
||||
container_status="$(${container_manager} inspect --type container \
|
||||
--format '{{.State.Status}}' "${container_name}" || :)"
|
||||
# Does the container exist? check if inspect reported errors
|
||||
if [ -z "${container_status}" ]; then
|
||||
# If not, prompt to create it first
|
||||
printf >&2 "Cannot find container %s.\n" "${container_name}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Retrieve container's HOME, and check if it's different from host's one. In
|
||||
# this case we prompt for deletion of the custom home.
|
||||
container_home=$(${container_manager} inspect --type container --format \
|
||||
'{{range .Config.Env}}{{if and (ge (len .) 5) (eq (slice . 0 5) "HOME=")}}{{slice . 5}}{{end}}{{end}}' "${container_name}")
|
||||
# Prompt for confirmation
|
||||
if [ "${container_home}" != "${HOME}" ]; then
|
||||
if [ "${non_interactive}" -eq 0 ] &&
|
||||
[ "${rm_home}" -eq 1 ]; then
|
||||
|
||||
printf "Do you want to remove custom home of container %s (%s)? [y/N]: " "${container_name}" "${container_home}"
|
||||
read -r response_rm_home
|
||||
response_rm_home="${response_rm_home:-"N"}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate home response
|
||||
# Accept only y,Y,Yes,yes,n,N,No,no.
|
||||
case "${response_rm_home}" in
|
||||
y | Y | Yes | yes | YES)
|
||||
rm_home_local=1
|
||||
;;
|
||||
n | N | No | no | NO)
|
||||
rm_home_local=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
|
||||
|
||||
# Remove the container
|
||||
printf "Removing container...\n"
|
||||
# shellcheck disable=SC2086,SC2248
|
||||
${container_manager} rm ${force_flag} --volumes "${container_name}"
|
||||
|
||||
# Remove exported apps and bins
|
||||
cleanup_exports "${container_name}"
|
||||
|
||||
# We're going to delete the box, let's also delete the entry
|
||||
verbose_arg=""
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
verbose_arg="--verbose"
|
||||
fi
|
||||
"$(dirname "$(realpath "${0}")")/distrobox-generate-entry" "${container_name}" --delete "${verbose_arg}"
|
||||
|
||||
# Remove custom home
|
||||
if [ "${rm_home_local}" -eq 1 ]; then
|
||||
rm -r "${container_home}"
|
||||
printf "Successfully removed %s\n" "${container_home}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Prompt for confirmation
|
||||
if [ "${non_interactive}" -eq 0 ] && [ "${force}" -eq 0 ]; then
|
||||
printf "Do you really want to delete containers:%s? [Y/n]: " "${container_name_list}"
|
||||
read -r response
|
||||
response="${response:-"Y"}"
|
||||
else
|
||||
response="yes"
|
||||
fi
|
||||
|
||||
for container in ${container_name_list}; do
|
||||
if [ "$(${container_manager} inspect --type container --format '{{.State.Status}}' "${container}")" = "running" ]; then
|
||||
if [ "${non_interactive}" -eq 0 ] && [ "${force}" -eq 0 ]; then
|
||||
printf "Container %s running, do you want to force delete them? [Y/n]: " "${container_name_list}"
|
||||
read -r response_force
|
||||
response_force="${response_force:-"Y"}"
|
||||
else
|
||||
response_force="yes"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Accept only y,Y,Yes,yes,n,N,No,no.
|
||||
case "${response_force:-"N"}" in
|
||||
y | Y | Yes | yes | YES)
|
||||
force=1
|
||||
force_flag="--force"
|
||||
break
|
||||
;;
|
||||
n | N | No | no | NO) ;;
|
||||
|
||||
*) # 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"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Accept only y,Y,Yes,yes,n,N,No,no.
|
||||
case "${response}" in
|
||||
y | Y | Yes | yes | YES)
|
||||
for container in ${container_name_list}; do
|
||||
delete_container "${container}"
|
||||
done
|
||||
;;
|
||||
n | N | No | no | NO)
|
||||
printf "Aborted.\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
|
||||
305
profiles/desktop/.local/bin/distrobox-stop
Executable file
305
profiles/desktop/.local/bin/distrobox-stop
Executable file
@@ -0,0 +1,305 @@
|
||||
#!/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
|
||||
# Optional env variables:
|
||||
# DBX_CONTAINER_MANAGER
|
||||
# DBX_CONTAINER_NAME
|
||||
# DBX_NON_INTERACTIVE
|
||||
# DBX_VERBOSE
|
||||
# DBX_SUDO_PROGRAM
|
||||
|
||||
# Despite of running this script via SUDO/DOAS being not supported (the
|
||||
# script itself will call the appropriate tool when necessary), we still want
|
||||
# to allow people to run it as root, logged in in a shell, and create rootful
|
||||
# containers.
|
||||
#
|
||||
# SUDO_USER is a variable set by SUDO and can be used to check whether the script was called by it. Same thing for DOAS_USER, set by DOAS.
|
||||
if {
|
||||
[ -n "${SUDO_USER}" ] || [ -n "${DOAS_USER}" ]
|
||||
} && [ "$(id -ru)" -eq 0 ]; then
|
||||
printf >&2 "Running %s via SUDO/DOAS is not supported. Instead, please try running:\n" "$(basename "${0}")"
|
||||
printf >&2 " %s --root %s\n" "$(basename "${0}")" "$*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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
|
||||
all=0
|
||||
container_manager="autodetect"
|
||||
distrobox_flags=""
|
||||
distrobox_path="$(dirname "$(realpath "${0}")")"
|
||||
container_name=""
|
||||
container_name_default="my-distrobox"
|
||||
container_name_list=""
|
||||
non_interactive=0
|
||||
# If the user runs this script as root in a login shell, set rootful=1.
|
||||
# There's no need for them to pass the --root flag option in such cases.
|
||||
[ "$(id -ru)" -eq 0 ] && rootful=1 || rootful=0
|
||||
verbose=0
|
||||
version="1.8.2.2"
|
||||
|
||||
# Source configuration files, this is done in an hierarchy so local files have
|
||||
# priority over system defaults
|
||||
# leave priority to environment variables.
|
||||
#
|
||||
# On NixOS, for the distrobox derivation to pick up a static config file shipped
|
||||
# by the package maintainer the path must be relative to the script itself.
|
||||
self_dir="$(dirname "$(realpath "$0")")"
|
||||
nix_config_file="${self_dir}/../share/distrobox/distrobox.conf"
|
||||
|
||||
config_files="
|
||||
${nix_config_file}
|
||||
/usr/share/distrobox/distrobox.conf
|
||||
/usr/share/defaults/distrobox/distrobox.conf
|
||||
/usr/etc/distrobox/distrobox.conf
|
||||
/usr/local/share/distrobox/distrobox.conf
|
||||
/etc/distrobox/distrobox.conf
|
||||
${XDG_CONFIG_HOME:-"${HOME}/.config"}/distrobox/distrobox.conf
|
||||
${HOME}/.distroboxrc
|
||||
"
|
||||
for config_file in ${config_files}; do
|
||||
# Shellcheck will give error for sourcing a variable file as it cannot follow
|
||||
# it. We don't care so let's disable this linting for now.
|
||||
# shellcheck disable=SC1090
|
||||
[ -e "${config_file}" ] && . "$(realpath "${config_file}")"
|
||||
done
|
||||
|
||||
[ -n "${DBX_CONTAINER_MANAGER}" ] && container_manager="${DBX_CONTAINER_MANAGER}"
|
||||
[ -n "${DBX_CONTAINER_NAME}" ] && container_name="${DBX_CONTAINER_NAME}"
|
||||
[ -n "${DBX_NON_INTERACTIVE}" ] && non_interactive="${DBX_NON_INTERACTIVE}"
|
||||
[ -n "${DBX_VERBOSE}" ] && verbose="${DBX_VERBOSE}"
|
||||
|
||||
# Fixup variable=[true|false], in case we find it in the config file(s)
|
||||
[ "${verbose}" = "true" ] && verbose=1
|
||||
[ "${verbose}" = "false" ] && verbose=0
|
||||
[ "${non_interactive}" = "true" ] && non_interactive=1
|
||||
[ "${non_interactive}" = "false" ] && non_interactive=0
|
||||
|
||||
# If we're running this script as root - as in logged in in the shell as root
|
||||
# user, and not via SUDO/DOAS -, we don't need to set distrobox_sudo_program
|
||||
# as it's meaningless for this use case.
|
||||
if [ "$(id -ru)" -ne 0 ]; then
|
||||
# If the DBX_SUDO_PROGRAM/distrobox_sudo_program variable was set by the
|
||||
# user, use its value instead of "sudo". But only if not running the script
|
||||
# as root (UID 0).
|
||||
distrobox_sudo_program=${DBX_SUDO_PROGRAM:-${distrobox_sudo_program:-"sudo"}}
|
||||
fi
|
||||
|
||||
[ -n "${DBX_SUDO_PROGRAM}" ] && distrobox_sudo_program="${DBX_SUDO_PROGRAM}"
|
||||
|
||||
# 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-stop container-name
|
||||
|
||||
Options:
|
||||
|
||||
--all/-a: stop all distroboxes
|
||||
--yes/-Y: non-interactive, stop without asking
|
||||
--help/-h: show this message
|
||||
--root/-r: launch podman/docker/lilipod with root privileges. Note that if you need root this is the preferred
|
||||
way over "sudo distrobox" (note: if using a program other than 'sudo' for root privileges is necessary,
|
||||
specify it through the DBX_SUDO_PROGRAM env variable, or 'distrobox_sudo_program' config variable)
|
||||
--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
|
||||
;;
|
||||
-a | --all)
|
||||
shift
|
||||
all=1
|
||||
;;
|
||||
-r | --root)
|
||||
shift
|
||||
rootful=1
|
||||
;;
|
||||
-v | --verbose)
|
||||
verbose=1
|
||||
shift
|
||||
;;
|
||||
-V | --version)
|
||||
printf "distrobox: %s\n" "${version}"
|
||||
exit 0
|
||||
;;
|
||||
-Y | --yes)
|
||||
non_interactive=1
|
||||
shift
|
||||
;;
|
||||
--) # End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*) # 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.
|
||||
# If we have a flagless option and container_name is not specified
|
||||
# then let's accept argument as container_name
|
||||
if [ -n "$1" ]; then
|
||||
container_name_list="${container_name_list} $1"
|
||||
shift
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set verbosity
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
set -o xtrace
|
||||
fi
|
||||
|
||||
if [ -z "${container_name}" ]; then
|
||||
container_name="${container_name_default}"
|
||||
fi
|
||||
|
||||
# We depend on a container manager let's be sure we have it
|
||||
# First we use podman, else docker, else lilipod
|
||||
case "${container_manager}" in
|
||||
autodetect)
|
||||
if command -v podman > /dev/null; then
|
||||
container_manager="podman"
|
||||
elif command -v podman-launcher > /dev/null; then
|
||||
container_manager="podman-launcher"
|
||||
elif command -v docker > /dev/null; then
|
||||
container_manager="docker"
|
||||
elif command -v lilipod > /dev/null; then
|
||||
container_manager="lilipod"
|
||||
fi
|
||||
;;
|
||||
podman)
|
||||
container_manager="podman"
|
||||
;;
|
||||
podman-launcher)
|
||||
container_manager="podman-launcher"
|
||||
;;
|
||||
lilipod)
|
||||
container_manager="lilipod"
|
||||
;;
|
||||
docker)
|
||||
container_manager="docker"
|
||||
;;
|
||||
*)
|
||||
printf >&2 "Invalid input %s.\n" "${container_manager}"
|
||||
printf >&2 "The available choices are: 'autodetect', 'podman', 'docker', 'lilipod'\n"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Be sure we have a container manager to work with.
|
||||
if ! command -v "${container_manager}" > /dev/null; then
|
||||
# Error: we need at least one between docker, podman or lilipod.
|
||||
printf >&2 "Missing dependency: we need a container manager.\n"
|
||||
printf >&2 "Please install one of podman, docker or lilipod.\n"
|
||||
printf >&2 "You can follow the documentation on:\n"
|
||||
printf >&2 "\tman distrobox-compatibility\n"
|
||||
printf >&2 "or:\n"
|
||||
printf >&2 "\thttps://github.com/89luca89/distrobox/blob/main/docs/compatibility.md\n"
|
||||
exit 127
|
||||
fi
|
||||
# add verbose if -v is specified
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
container_manager="${container_manager} --log-level debug"
|
||||
fi
|
||||
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
if [ "${rootful}" -ne 0 ]; then
|
||||
container_manager="${distrobox_sudo_program-} ${container_manager}"
|
||||
distrobox_flags="--root"
|
||||
fi
|
||||
|
||||
# If all, just set container_name to the list of names in distrobox-list
|
||||
if [ "${all}" -ne 0 ]; then
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
# shellcheck disable=SC2086,2248
|
||||
container_name_list="$("${distrobox_path}"/distrobox-list ${distrobox_flags} --no-color |
|
||||
tail -n +2 | cut -d'|' -f2 | tr -d ' ' | tr '\n' ' ')"
|
||||
fi
|
||||
|
||||
if [ -z "${container_name_list}" ] && [ "${all}" -ne 0 ]; then
|
||||
printf >&2 "No containers found.\n"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# check if we have containers to delete
|
||||
if [ -z "${container_name_list}" ]; then
|
||||
container_name_list="${container_name_default}"
|
||||
else
|
||||
# strip leading whitespace from container name
|
||||
container_name_list="$(echo "${container_name_list}" | sed -E 's/^[[:space:]]+//')"
|
||||
fi
|
||||
|
||||
if [ "${non_interactive}" -eq 0 ]; then
|
||||
# Prompt to stop the container.
|
||||
printf "Do you really want to stop %s? [Y/n]: " "${container_name_list}"
|
||||
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)
|
||||
# Stop the container
|
||||
for container_name in ${container_name_list}; do
|
||||
${container_manager} stop "${container_name}"
|
||||
done
|
||||
;;
|
||||
n | N | No | no | NO)
|
||||
printf "Aborted.\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
|
||||
272
profiles/desktop/.local/bin/distrobox-upgrade
Executable file
272
profiles/desktop/.local/bin/distrobox-upgrade
Executable file
@@ -0,0 +1,272 @@
|
||||
#!/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/>.
|
||||
|
||||
# Despite of running this script via SUDO/DOAS being not supported (the
|
||||
# script itself will call the appropriate tool when necessary), we still want
|
||||
# to allow people to run it as root, logged in in a shell, and create rootful
|
||||
# containers.
|
||||
#
|
||||
# SUDO_USER is a variable set by SUDO and can be used to check whether the script was called by it. Same thing for DOAS_USER, set by DOAS.
|
||||
if {
|
||||
[ -n "${SUDO_USER}" ] || [ -n "${DOAS_USER}" ]
|
||||
} && [ "$(id -ru)" -eq 0 ]; then
|
||||
printf >&2 "Running %s via SUDO/DOAS is not supported. Instead, please try running:\n" "$(basename "${0}")"
|
||||
printf >&2 " %s --root %s\n" "$(basename "${0}")" "$*"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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)"
|
||||
|
||||
all=0
|
||||
running=0
|
||||
container_manager="autodetect"
|
||||
distrobox_flags=""
|
||||
distrobox_path="$(dirname "$(realpath "${0}")")"
|
||||
rootful=0
|
||||
verbose=0
|
||||
version="1.8.2.2"
|
||||
|
||||
# Source configuration files, this is done in an hierarchy so local files have
|
||||
# priority over system defaults
|
||||
# leave priority to environment variables.
|
||||
#
|
||||
# On NixOS, for the distrobox derivation to pick up a static config file shipped
|
||||
# by the package maintainer the path must be relative to the script itself.
|
||||
self_dir="$(dirname "$(realpath "$0")")"
|
||||
nix_config_file="${self_dir}/../share/distrobox/distrobox.conf"
|
||||
|
||||
config_files="
|
||||
${nix_config_file}
|
||||
/usr/share/distrobox/distrobox.conf
|
||||
/usr/share/defaults/distrobox/distrobox.conf
|
||||
/usr/etc/distrobox/distrobox.conf
|
||||
/usr/local/share/distrobox/distrobox.conf
|
||||
/etc/distrobox/distrobox.conf
|
||||
${XDG_CONFIG_HOME:-"${HOME}/.config"}/distrobox/distrobox.conf
|
||||
${HOME}/.distroboxrc
|
||||
"
|
||||
for config_file in ${config_files}; do
|
||||
# Shellcheck will give error for sourcing a variable file as it cannot follow
|
||||
# it. We don't care so let's disable this linting for now.
|
||||
# shellcheck disable=SC1090
|
||||
[ -e "${config_file}" ] && . "$(realpath "${config_file}")"
|
||||
done
|
||||
|
||||
[ -n "${DBX_CONTAINER_MANAGER}" ] && container_manager="${DBX_CONTAINER_MANAGER}"
|
||||
[ -n "${DBX_VERBOSE}" ] && verbose="${DBX_VERBOSE}"
|
||||
|
||||
# Fixup variable=[true|false], in case we find it in the config file(s)
|
||||
[ "${verbose}" = "true" ] && verbose=1
|
||||
[ "${verbose}" = "false" ] && verbose=0
|
||||
|
||||
# If we're running this script as root - as in logged in in the shell as root
|
||||
# user, and not via SUDO/DOAS -, we don't need to set distrobox_sudo_program
|
||||
# as it's meaningless for this use case.
|
||||
if [ "$(id -ru)" -ne 0 ]; then
|
||||
# If the DBX_SUDO_PROGRAM/distrobox_sudo_program variable was set by the
|
||||
# user, use its value instead of "sudo". But only if not running the script
|
||||
# as root (UID 0).
|
||||
distrobox_sudo_program=${DBX_SUDO_PROGRAM:-${distrobox_sudo_program:-"sudo"}}
|
||||
fi
|
||||
|
||||
# Declare it AFTER config sourcing because we do not want a default name set.
|
||||
container_name=""
|
||||
|
||||
# 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-upgrade container-name
|
||||
distrobox-upgrade --all
|
||||
|
||||
Options:
|
||||
|
||||
--help/-h: show this message
|
||||
--all/-a: perform for all distroboxes
|
||||
--running: perform only for running distroboxes
|
||||
--root/-r: launch podman/docker/lilipod with root privileges. Note that if you need root this is the preferred
|
||||
way over "sudo distrobox" (note: if using a program other than 'sudo' for root privileges is necessary,
|
||||
specify it through the DBX_SUDO_PROGRAM env variable, or 'distrobox_sudo_program' config variable)
|
||||
--verbose/-v: show more verbosity
|
||||
--version/-V: show version
|
||||
EOF
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
show_help
|
||||
exit
|
||||
fi
|
||||
|
||||
# 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)
|
||||
verbose=1
|
||||
shift
|
||||
;;
|
||||
-V | --version)
|
||||
printf "distrobox: %s\n" "${version}"
|
||||
exit 0
|
||||
;;
|
||||
-a | --all)
|
||||
all=1
|
||||
shift
|
||||
;;
|
||||
--running)
|
||||
running=1
|
||||
shift
|
||||
;;
|
||||
-r | --root)
|
||||
shift
|
||||
rootful=1
|
||||
;;
|
||||
--) # End of all options.
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*) # 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.
|
||||
# If we have a flagless option and container_name is not specified
|
||||
# then let's accept argument as container_name
|
||||
if [ -n "$1" ]; then
|
||||
container_name="${container_name} $1"
|
||||
shift
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
# set verbosity
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
set -o xtrace
|
||||
fi
|
||||
|
||||
if [ -z "${container_name}" ] && [ "${all}" -eq 0 ] && [ "${running}" -eq 0 ]; then
|
||||
printf >&2 "Please specify the name of the container.\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We depend on a container manager let's be sure we have it
|
||||
# First we use podman, else docker, else lilipod
|
||||
case "${container_manager}" in
|
||||
autodetect)
|
||||
if command -v podman > /dev/null; then
|
||||
container_manager="podman"
|
||||
elif command -v podman-launcher > /dev/null; then
|
||||
container_manager="podman-launcher"
|
||||
elif command -v docker > /dev/null; then
|
||||
container_manager="docker"
|
||||
elif command -v lilipod > /dev/null; then
|
||||
container_manager="lilipod"
|
||||
fi
|
||||
;;
|
||||
podman)
|
||||
container_manager="podman"
|
||||
;;
|
||||
podman-launcher)
|
||||
container_manager="podman-launcher"
|
||||
;;
|
||||
lilipod)
|
||||
container_manager="lilipod"
|
||||
;;
|
||||
docker)
|
||||
container_manager="docker"
|
||||
;;
|
||||
*)
|
||||
printf >&2 "Invalid input %s.\n" "${container_manager}"
|
||||
printf >&2 "The available choices are: 'autodetect', 'podman', 'docker', 'lilipod'\n"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Be sure we have a container manager to work with.
|
||||
if ! command -v "${container_manager}" > /dev/null; then
|
||||
# Error: we need at least one between docker, podman or lilipod.
|
||||
printf >&2 "Missing dependency: we need a container manager.\n"
|
||||
printf >&2 "Please install one of podman, docker or lilipod.\n"
|
||||
printf >&2 "You can follow the documentation on:\n"
|
||||
printf >&2 "\tman distrobox-compatibility\n"
|
||||
printf >&2 "or:\n"
|
||||
printf >&2 "\thttps://github.com/89luca89/distrobox/blob/main/docs/compatibility.md\n"
|
||||
exit 127
|
||||
fi
|
||||
|
||||
# add verbose if -v is specified
|
||||
if [ "${verbose}" -ne 0 ]; then
|
||||
container_manager="${container_manager} --log-level debug"
|
||||
fi
|
||||
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
if [ "${rootful}" -ne 0 ]; then
|
||||
container_manager="${distrobox_sudo_program} ${container_manager}"
|
||||
distrobox_flags="--root"
|
||||
fi
|
||||
|
||||
# If all, just set container_name to the list of names in distrobox-list
|
||||
if [ "${all}" -ne 0 ]; then
|
||||
|
||||
# prepend sudo (or the specified sudo program) if we want our container manager to be rootful
|
||||
# shellcheck disable=SC2086,2248
|
||||
container_name="$("${distrobox_path}"/distrobox-list ${distrobox_flags} --no-color |
|
||||
tail -n +2 | cut -d'|' -f2 | tr -d ' ')"
|
||||
|
||||
# If running, set container_name to the list of names of running instances
|
||||
if [ "${running}" -ne 0 ]; then
|
||||
# shellcheck disable=SC2086,2248
|
||||
container_name="$("${distrobox_path}"/distrobox-list ${distrobox_flags} --no-color |
|
||||
tail -n +2 | grep -iE '\| running|up' | cut -d'|' -f2 | tr -d ' ')"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Launch the entrypoint in upgrade mode
|
||||
for container in ${container_name}; do
|
||||
printf >&2 "\033[1;31m Upgrading %s...\n\033[0m" "${container}"
|
||||
# shellcheck disable=SC2086,SC2248
|
||||
"${distrobox_path}"/distrobox-enter \
|
||||
${distrobox_flags} ${container} -- sh -c \
|
||||
"command -v su-exec 2>/dev/null && su-exec root /usr/bin/entrypoint --upgrade || command -v doas 2>/dev/null && doas /usr/bin/entrypoint --upgrade || sudo -S /usr/bin/entrypoint --upgrade"
|
||||
done
|
||||
706
profiles/desktop/.local/bin/gogh.sh
Executable file
706
profiles/desktop/.local/bin/gogh.sh
Executable file
@@ -0,0 +1,706 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Variables to avoid repeated calls to tput
|
||||
for n in {0..15}; do
|
||||
declare C$n=$(tput setaf $n)
|
||||
done
|
||||
CR=$(tput sgr0)
|
||||
CS0=$(tput sgr 0)
|
||||
|
||||
# Define traps and trapfunctions early in case any errors before script exits
|
||||
GLOBAL_VAR_CLEANUP(){
|
||||
echo "Cleanup up..."
|
||||
[[ -n "$(command -v TILIX_TMP_CLEANUP)" ]] && TILIX_TMP_CLEANUP
|
||||
[[ -n "$(command -v ALACRITTY_APPLY_TMP_CLEANUP)" ]] && ALACRITTY_APPLY_TMP_CLEANUP
|
||||
[[ -n "$(command -v TERMINATOR_APPLY_TMP_CLEANUP)" ]] && TERMINATOR_APPLY_TMP_CLEANUP
|
||||
[[ -n "$(command -v APPLY_SCRIPT_TMP_CLEANUP)" ]] && APPLY_SCRIPT_TMP_CLEANUP
|
||||
unset PROFILE_NAME
|
||||
unset PROFILE_SLUG
|
||||
unset TILIX_RES
|
||||
unset TERMINAL
|
||||
echo "Done"
|
||||
}
|
||||
|
||||
trap 'GLOBAL_VAR_CLEANUP; trap - EXIT' EXIT HUP INT QUIT PIPE TERM
|
||||
|
||||
# TO-DO: Investigate dynamically building this array e.g.
|
||||
# curl -s https://github.com/Gogh-Co/Gogh/tree/master/themes | grep -o "title=.*\.sh\" " | awk -F '=' '{print $2}'
|
||||
declare -a THEMES=(
|
||||
'3024-day.sh'
|
||||
'3024-night.sh'
|
||||
'aci.sh'
|
||||
'acme.sh'
|
||||
'aco.sh'
|
||||
'adventure-time.sh'
|
||||
'afterglow.sh'
|
||||
'alien-blood.sh'
|
||||
'apprentice.sh'
|
||||
'arc-dark.sh'
|
||||
'arc-light.sh'
|
||||
'argonaut.sh'
|
||||
'arthur.sh'
|
||||
'astrodark.sh'
|
||||
'atelier-cave.sh'
|
||||
'atelier-dune.sh'
|
||||
'atelier-estuary.sh'
|
||||
'atelier-forest.sh'
|
||||
'atelier-heath.sh'
|
||||
'atelier-lakeside.sh'
|
||||
'atelier-plateau.sh'
|
||||
'atelier-savanna.sh'
|
||||
'atelier-seaside.sh'
|
||||
'atelier-sulphurpool.sh'
|
||||
'atom.sh'
|
||||
'aura.sh'
|
||||
'ayaka.sh'
|
||||
'ayu-dark.sh'
|
||||
'ayu-light.sh'
|
||||
'ayu-mirage.sh'
|
||||
'azu.sh'
|
||||
'base2tone-cave.sh'
|
||||
'base2tone-desert.sh'
|
||||
'base2tone-drawbridge.sh'
|
||||
'base2tone-earth.sh'
|
||||
'base2tone-evening.sh'
|
||||
'base2tone-field.sh'
|
||||
'base2tone-forest.sh'
|
||||
'base2tone-garden.sh'
|
||||
'base2tone-heath.sh'
|
||||
'base2tone-lake.sh'
|
||||
'base2tone-lavender.sh'
|
||||
'base2tone-mall.sh'
|
||||
'base2tone-meadow.sh'
|
||||
'base2tone-morning.sh'
|
||||
'base2tone-motel.sh'
|
||||
'base2tone-pool.sh'
|
||||
'base2tone-porch.sh'
|
||||
'base2tone-sea.sh'
|
||||
'base2tone-space.sh'
|
||||
'base2tone-suburb.sh'
|
||||
'base4tone-classic-a.sh'
|
||||
'base4tone-classic-b.sh'
|
||||
'base4tone-classic-c.sh'
|
||||
'base4tone-classic-d.sh'
|
||||
'base4tone-classic-e.sh'
|
||||
'base4tone-classic-f.sh'
|
||||
'base4tone-classic-i.sh'
|
||||
'base4tone-classic-l.sh'
|
||||
'base4tone-classic-o.sh'
|
||||
'base4tone-classic-p.sh'
|
||||
'base4tone-classic-q.sh'
|
||||
'base4tone-classic-r.sh'
|
||||
'base4tone-classic-s.sh'
|
||||
'base4tone-classic-t.sh'
|
||||
'base4tone-classic-u.sh'
|
||||
'base4tone-classic-w.sh'
|
||||
'base4tone-modern-c.sh'
|
||||
'base4tone-modern-n.sh'
|
||||
'base4tone-modern-w.sh'
|
||||
'belafonte-day.sh'
|
||||
'belafonte-night.sh'
|
||||
'bim.sh'
|
||||
'birds-of-paradise.sh'
|
||||
'blazer.sh'
|
||||
'blue-dolphin.sh'
|
||||
'blue-moon-light.sh'
|
||||
'blue-moon.sh'
|
||||
'bluloco-light.sh'
|
||||
'bluloco-zsh-light.sh'
|
||||
'borland.sh'
|
||||
'breadog.sh'
|
||||
'breath-darker.sh'
|
||||
'breath-light.sh'
|
||||
'breath-silverfox.sh'
|
||||
'breath.sh'
|
||||
'breeze.sh'
|
||||
'broadcast.sh'
|
||||
'brogrammer.sh'
|
||||
'butrin.sh'
|
||||
'c64.sh'
|
||||
'cai.sh'
|
||||
'campbell.sh'
|
||||
'catppuccin-frappe.sh'
|
||||
'catppuccin-latte.sh'
|
||||
'catppuccin-macchiato.sh'
|
||||
'catppuccin-mocha.sh'
|
||||
'chalk.sh'
|
||||
'chalkboard.sh'
|
||||
'chameleon.sh'
|
||||
'ciapre.sh'
|
||||
'city-lights.sh'
|
||||
'clone-of-ubuntu.sh'
|
||||
'clrs.sh'
|
||||
'cobalt-2.sh'
|
||||
'cobalt-neon.sh'
|
||||
'colorcli.sh'
|
||||
'crayon-pony-fish.sh'
|
||||
'dark-pastel.sh'
|
||||
'darkside.sh'
|
||||
'dehydration.sh'
|
||||
'desert.sh'
|
||||
'dimmed-monokai.sh'
|
||||
'dissonance.sh'
|
||||
'doom-one.sh'
|
||||
'dracula.sh'
|
||||
'earthsong.sh'
|
||||
'elemental.sh'
|
||||
'elementary.sh'
|
||||
'elic.sh'
|
||||
'elio.sh'
|
||||
'espresso-libre.sh'
|
||||
'espresso.sh'
|
||||
'everblush.sh'
|
||||
'everforest-dark-hard.sh'
|
||||
'everforest-dark-medium.sh'
|
||||
'everforest-dark-soft.sh'
|
||||
'everforest-light-hard.sh'
|
||||
'everforest-light-medium.sh'
|
||||
'everforest-light-soft.sh'
|
||||
'fairy-floss-dark.sh'
|
||||
'fairy-floss.sh'
|
||||
'fishtank.sh'
|
||||
'flat-remix.sh'
|
||||
'flat.sh'
|
||||
'flatland.sh'
|
||||
'flexoki-dark.sh'
|
||||
'flexoki-light.sh'
|
||||
'foxnightly.sh'
|
||||
'freya.sh'
|
||||
'frontend-delight.sh'
|
||||
'frontend-fun-forrest.sh'
|
||||
'frontend-galaxy.sh'
|
||||
'geohot.sh'
|
||||
'github-dark.sh'
|
||||
'github-light.sh'
|
||||
'gogh.sh'
|
||||
'gooey.sh'
|
||||
'google-dark.sh'
|
||||
'google-light.sh'
|
||||
'gotham.sh'
|
||||
'grape.sh'
|
||||
'grass.sh'
|
||||
'gruvbox-dark.sh'
|
||||
'gruvbox-material-dark.sh'
|
||||
'gruvbox-material-light.sh'
|
||||
'gruvbox.sh'
|
||||
'guezwhoz.sh'
|
||||
'hardcore.sh'
|
||||
'harper.sh'
|
||||
'hemisu-dark.sh'
|
||||
'hemisu-light.sh'
|
||||
'highway.sh'
|
||||
'hipster-green.sh'
|
||||
'homebrew-light.sh'
|
||||
'homebrew-ocean.sh'
|
||||
'homebrew.sh'
|
||||
'horizon-bright.sh'
|
||||
'horizon-dark.sh'
|
||||
'hurtado.sh'
|
||||
'hybrid.sh'
|
||||
'ibm-3270-high-contrast.sh'
|
||||
'ibm3270.sh'
|
||||
'ic-green-ppl.sh'
|
||||
'ic-orange-ppl.sh'
|
||||
'iceberg.sh'
|
||||
'idle-toes.sh'
|
||||
'ir-black.sh'
|
||||
'jackie-brown.sh'
|
||||
'japanesque.sh'
|
||||
'jellybeans.sh'
|
||||
'jup.sh'
|
||||
'kanagawa-dragon.sh'
|
||||
'kanagawa-lotus.sh'
|
||||
'kanagawa-wave.sh'
|
||||
'kibble.sh'
|
||||
'kokuban.sh'
|
||||
'laserwave.sh'
|
||||
'later-this-evening.sh'
|
||||
'lavandula.sh'
|
||||
'liquid-carbon-transparent.sh'
|
||||
'liquid-carbon.sh'
|
||||
'lunaria-dark.sh'
|
||||
'lunaria-eclipse.sh'
|
||||
'lunaria-light.sh'
|
||||
'maia.sh'
|
||||
'man-page.sh'
|
||||
'mar.sh'
|
||||
'material.sh'
|
||||
'mathias.sh'
|
||||
'medallion.sh'
|
||||
'minimalist-dark.sh'
|
||||
'miramare.sh'
|
||||
'misterioso.sh'
|
||||
'modus-operandi-tinted.sh'
|
||||
'modus-operandi.sh'
|
||||
'modus-vivendi-tinted.sh'
|
||||
'modus-vivendi.sh'
|
||||
'molokai.sh'
|
||||
'mona-lisa.sh'
|
||||
'mono-amber.sh'
|
||||
'mono-cyan.sh'
|
||||
'mono-green.sh'
|
||||
'mono-red.sh'
|
||||
'mono-white.sh'
|
||||
'mono-yellow.sh'
|
||||
'monokai-dark.sh'
|
||||
'monokai-pro-light-sun.sh'
|
||||
'monokai-pro-light.sh'
|
||||
'monokai-pro-machine.sh'
|
||||
'monokai-pro-ocatagon.sh'
|
||||
'monokai-pro-ristretto.sh'
|
||||
'monokai-pro-spectrum.sh'
|
||||
'monokai-pro.sh'
|
||||
'monokai-soda.sh'
|
||||
'moonfly.sh'
|
||||
'morada.sh'
|
||||
'n0tch2k.sh'
|
||||
'nanosecond.sh'
|
||||
'neon-night.sh'
|
||||
'neopolitan.sh'
|
||||
'nep.sh'
|
||||
'neutron.sh'
|
||||
'night-owl.sh'
|
||||
'nightfly.sh'
|
||||
'nightlion-v1.sh'
|
||||
'nightlion-v2.sh'
|
||||
'nighty.sh'
|
||||
'nord-light.sh'
|
||||
'nord.sh'
|
||||
'novel.sh'
|
||||
'obsidian.sh'
|
||||
'ocean-dark.sh'
|
||||
'oceanic-next.sh'
|
||||
'ollie.sh'
|
||||
'omni.sh'
|
||||
'one-dark.sh'
|
||||
'one-half-black.sh'
|
||||
'one-light.sh'
|
||||
'oxocarbon-dark.sh'
|
||||
'palenight.sh'
|
||||
'pali.sh'
|
||||
'panda.sh'
|
||||
'paper.sh'
|
||||
'papercolor-dark.sh'
|
||||
'papercolor-light.sh'
|
||||
'paraiso-dark.sh'
|
||||
'paul-millr.sh'
|
||||
'pencil-dark.sh'
|
||||
'pencil-light.sh'
|
||||
'peppermint.sh'
|
||||
'pixiefloss.sh'
|
||||
'pnevma.sh'
|
||||
'powershell.sh'
|
||||
'predawn.sh'
|
||||
'pro.sh'
|
||||
'purple-people-eater.sh'
|
||||
'quiet.sh'
|
||||
'red-alert.sh'
|
||||
'red-sands.sh'
|
||||
'relaxed.sh'
|
||||
'rippedcasts.sh'
|
||||
'rose-pine-dawn.sh'
|
||||
'rose-pine-moon.sh'
|
||||
'rose-pine.sh'
|
||||
'royal.sh'
|
||||
'sat.sh'
|
||||
'sea-shells.sh'
|
||||
'seafoam-pastel.sh'
|
||||
'selenized-black.sh'
|
||||
'selenized-dark.sh'
|
||||
'selenized-light.sh'
|
||||
'selenized-white.sh'
|
||||
'seoul256-light.sh'
|
||||
'seoul256.sh'
|
||||
'seti.sh'
|
||||
'shaman.sh'
|
||||
'shel.sh'
|
||||
'slate.sh'
|
||||
'smyck.sh'
|
||||
'snazzy.sh'
|
||||
'soft-server.sh'
|
||||
'solarized-darcula.sh'
|
||||
'solarized-dark-higher-contrast.sh'
|
||||
'solarized-dark.sh'
|
||||
'solarized-light.sh'
|
||||
'sonokai.sh'
|
||||
'spacedust.sh'
|
||||
'spacegray-eighties-dull.sh'
|
||||
'spacegray-eighties.sh'
|
||||
'spacegray.sh'
|
||||
'sparky.sh'
|
||||
'spring.sh'
|
||||
'square.sh'
|
||||
'srcery.sh'
|
||||
'summer-pop.sh'
|
||||
'sundried.sh'
|
||||
'sweet-eliverlara.sh'
|
||||
'sweet-terminal.sh'
|
||||
'symphonic.sh'
|
||||
'synthwave-alpha.sh'
|
||||
'synthwave.sh'
|
||||
'teerb.sh'
|
||||
'tempus-autumn.sh'
|
||||
'tempus-classic.sh'
|
||||
'tempus-dawn.sh'
|
||||
'tempus-day.sh'
|
||||
'tempus-dusk.sh'
|
||||
'tempus-fugit.sh'
|
||||
'tempus-future.sh'
|
||||
'tempus-night.sh'
|
||||
'tempus-past.sh'
|
||||
'tempus-rift.sh'
|
||||
'tempus-spring.sh'
|
||||
'tempus-summer.sh'
|
||||
'tempus-tempest.sh'
|
||||
'tempus-totus.sh'
|
||||
'tempus-warp.sh'
|
||||
'tempus-winter.sh'
|
||||
'tender.sh'
|
||||
'terminal-basic.sh'
|
||||
'terminix-dark.sh'
|
||||
'thayer-bright.sh'
|
||||
'tin.sh'
|
||||
'tiwahu-dark.sh'
|
||||
'tiwahu-light.sh'
|
||||
'tokyo-night-light.sh'
|
||||
'tokyo-night-storm.sh'
|
||||
'tokyo-night.sh'
|
||||
'tomorrow-night-blue.sh'
|
||||
'tomorrow-night-bright.sh'
|
||||
'tomorrow-night-eighties.sh'
|
||||
'tomorrow-night.sh'
|
||||
'tomorrow.sh'
|
||||
'toy-chest.sh'
|
||||
'treehouse.sh'
|
||||
'twilight.sh'
|
||||
'ura.sh'
|
||||
'urple.sh'
|
||||
'vacme.sh'
|
||||
'vag.sh'
|
||||
'vaombe.sh'
|
||||
'vaughn.sh'
|
||||
'vibrant-ink.sh'
|
||||
'vs-code-dark.sh'
|
||||
'vs-code-light.sh'
|
||||
'warm-neon.sh'
|
||||
'website.sh'
|
||||
'wez.sh'
|
||||
'wild-cherry.sh'
|
||||
'wombat.sh'
|
||||
'wryan.sh'
|
||||
'wzoreck.sh'
|
||||
'zenburn.sh'
|
||||
)
|
||||
|
||||
# Allow developer to change url to forked url for easier testing
|
||||
BASE_URL=${BASE_URL:-"https://raw.githubusercontent.com/Gogh-Co/Gogh/master"}
|
||||
PROGRESS_URL="https://raw.githubusercontent.com/phenonymous/shell-progressbar/1.0/progress.sh"
|
||||
|
||||
SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
capitalize() {
|
||||
local ARGUMENT=$1
|
||||
local RES=""
|
||||
local STR=""
|
||||
local RES_NO_TRAIL_SPACE=""
|
||||
|
||||
for CHAR in $ARGUMENT; do
|
||||
STR=$(echo "${CHAR:0:1}" | tr "[:lower:]" "[:upper:]")"${CHAR:1} "
|
||||
RES="${RES}${STR}"
|
||||
RES_NO_TRAIL_SPACE="$(echo -e "${RES}" | sed -e 's/[[:space:]]*$//')"
|
||||
done
|
||||
|
||||
echo "${RES_NO_TRAIL_SPACE}"
|
||||
}
|
||||
|
||||
|
||||
# Used to get required python scripts, either from the internet or from local directory
|
||||
if [[ ! -f "${SCRIPT_PATH}/apply-alacritty.py" ]]; then
|
||||
ALACRITTY_APPLY_TMP_CLEANUP() {
|
||||
rm -rf "${GOGH_ALACRITTY_SCRIPT}"
|
||||
unset GOGH_ALACRITTY_SCRIPT
|
||||
}
|
||||
export GOGH_ALACRITTY_SCRIPT="$(mktemp -t gogh.alacritty.XXXXXX)"
|
||||
if [[ "$(uname)" = "Darwin" ]]; then
|
||||
# OSX ships with curl and ancient bash
|
||||
curl -so "${GOGH_ALACRITTY_SCRIPT}" "${BASE_URL}/apply-alacritty.py"
|
||||
else
|
||||
# Linux ships with wget
|
||||
wget -qO "${GOGH_ALACRITTY_SCRIPT}" "${BASE_URL}/apply-alacritty.py"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# Used to get required python scripts, either from the internet or from local directory
|
||||
if [[ ! -e "${SCRIPT_PATH}/apply-terminator.py" ]]; then
|
||||
TERMINATOR_APPLY_TMP_CLEANUP() {
|
||||
rm -rf "${GOGH_TERMINATOR_SCRIPT}"
|
||||
unset GOGH_TERMINATOR_SCRIPT
|
||||
}
|
||||
export GOGH_TERMINATOR_SCRIPT="$(mktemp -t gogh.terminator.XXXXXX)"
|
||||
if [[ "$(uname)" = "Darwin" ]]; then
|
||||
# OSX ships with curl and ancient bash
|
||||
curl -so "${GOGH_TERMINATOR_SCRIPT}" "${BASE_URL}/apply-terminator.py"
|
||||
else
|
||||
# Linux ships with wget
|
||||
wget -qO "${GOGH_TERMINATOR_SCRIPT}" "${BASE_URL}/apply-terminator.py"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# Used to get required shell scripts, either from the internet or from local directory
|
||||
if [[ ! -e "${SCRIPT_PATH}/apply-colors.sh" ]]; then
|
||||
APPLY_SCRIPT_TMP_CLEANUP() {
|
||||
rm -rf "${GOGH_APPLY_SCRIPT}"
|
||||
unset GOGH_APPLY_SCRIPT
|
||||
}
|
||||
export GOGH_APPLY_SCRIPT="$(mktemp -t gogh.apply.XXXXXX)"
|
||||
if [[ "$(uname)" = "Darwin" ]]; then
|
||||
# OSX ships with curl and ancient bash
|
||||
curl -so "${GOGH_APPLY_SCRIPT}" "${BASE_URL}/apply-colors.sh"
|
||||
else
|
||||
# Linux ships with wget
|
||||
wget -qO "${GOGH_APPLY_SCRIPT}" "${BASE_URL}/apply-colors.sh"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
set_gogh() {
|
||||
string=$1
|
||||
string_r="${string%???}"
|
||||
string_s=${string_r//\./_}
|
||||
result=$(capitalize "${string_s}")
|
||||
url="${BASE_URL}/installs/$1"
|
||||
|
||||
export {PROFILE_NAME,PROFILE_SLUG}="$result"
|
||||
|
||||
if [[ -e "${SCRIPT_PATH}/installs/$1" ]]; then
|
||||
bash "${SCRIPT_PATH}/installs/$1"
|
||||
else
|
||||
if [[ "$(uname)" = "Darwin" ]]; then
|
||||
# OSX ships with curl
|
||||
bash -c "$(curl -sLo- "${url}")"
|
||||
else
|
||||
# Linux ships with wget
|
||||
bash -c "$(wget -qO- "${url}")"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
remove_file_extension (){
|
||||
echo "${1%.*}"
|
||||
}
|
||||
|
||||
|
||||
### Get length of an array
|
||||
ARRAYLENGTH=${#THEMES[@]}
|
||||
|
||||
|
||||
# |
|
||||
# | ::::::: Print logo
|
||||
# |
|
||||
tput clear
|
||||
if [[ ${COLUMNS:-$(tput cols)} -ge 80 ]]; then
|
||||
gogh_str=""
|
||||
gogh_str+=" \n"
|
||||
gogh_str+=" █████████ █████ \n"
|
||||
gogh_str+=" ███ ███ ███ \n"
|
||||
gogh_str+=" ███ ██████ ███████ ███████ \n"
|
||||
gogh_str+=" ███ ███ ███ ███ ███ ███ ███ \n"
|
||||
gogh_str+=" ███ █████ ███ ███ ███ ███ ███ ███ \n"
|
||||
gogh_str+=" ███ ███ ███ ███ ███ ███ ███ ███ \n"
|
||||
gogh_str+=" █████████ ██████ ███████ ████ █████ \n"
|
||||
gogh_str+=" ${C0}█████████${C1}█████████${C2}█████████${C3}█████████${C4}█████${CS0}███${C4}█${C5}█████████${C6}█████████${C7}█████████ \n"
|
||||
gogh_str+=" ${C0}█████████${C1}█████████${C2}█████████${C3}█████████${CS0}███${C4}██${CS0}███${C4}█${C5}█████████${C6}█████████${C7}█████████ \n"
|
||||
gogh_str+=" ${C0}█████████${C1}█████████${C2}█████████${C3}█████████${C4}█${CR}██████${C4}██${C5}█████████${C6}█████████${C7}█████████ \n"
|
||||
gogh_str+=" ${C8}█████████${C9}█████████${C10}█████████${C11}█████████${C12}█████████${C13}█████████${C14}█████████${C15}█████████${CS0} \n"
|
||||
gogh_str+=" ${C8}█████████${C9}█████████${C10}█████████${C11}█████████${C12}█████████${C13}█████████${C14}█████████${C15}█████████${CS0} \n"
|
||||
gogh_str+=" ${C8}█████████${C9}█████████${C10}█████████${C11}█████████${C12}█████████${C13}█████████${C14}█████████${C15}█████████${CS0} \n"
|
||||
gogh_str+=" "
|
||||
|
||||
|
||||
printf '%b\n' "${gogh_str}"
|
||||
sleep 2.5
|
||||
else
|
||||
echo -e "\nGogh\n"
|
||||
for c in C{0..15}; do
|
||||
echo -n "${!c}█████${CR}"
|
||||
[[ $c == C7 ]] && echo # new line
|
||||
done
|
||||
echo
|
||||
fi
|
||||
|
||||
|
||||
# |
|
||||
# | ::::::: Print Themes
|
||||
# |
|
||||
echo -e "\nThemes:\n"
|
||||
|
||||
# Cross-platform function to format theme names
|
||||
format_theme_name() {
|
||||
local name="$1"
|
||||
# Remove .sh extension and any other extensions
|
||||
name="${name%.*}"
|
||||
# Replace hyphens with spaces
|
||||
name="${name//-/ }"
|
||||
# Capitalize first letter of each word using awk (cross-platform)
|
||||
echo "$name" | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2)} 1'
|
||||
}
|
||||
|
||||
# Column display of available themes
|
||||
# Note: /usr/bin/column uses tabs and does not support ANSI codes yet (merged but not released)
|
||||
MAXL=$(( $(printf "%s\n" "${THEMES[@]}" | wc -L) - 3 )) # Biggest theme name without the extension
|
||||
NCOLS=$(( ${COLUMNS:-$(tput cols)} / (10+MAXL) )) # number of columns, 10 is the length of ' ( xxx ) '
|
||||
NROWS=$(( (ARRAYLENGTH-1)/NCOLS + 1 )) # number of rows
|
||||
row=0
|
||||
|
||||
while ((row < NROWS)); do
|
||||
col=0
|
||||
while ((col < NCOLS)); do
|
||||
NUM=$((col*NROWS+row))
|
||||
NAME="${THEMES[$NUM]}"
|
||||
if [[ -n $NAME ]]; then
|
||||
FORMATTED_NAME=$(format_theme_name "$NAME")
|
||||
printf " ( ${C4}%3d${CR} ) %-${MAXL}s" $((NUM+1)) "$FORMATTED_NAME"
|
||||
fi
|
||||
((col++))
|
||||
done
|
||||
echo
|
||||
((row++))
|
||||
done
|
||||
|
||||
echo -e " (${C4} ALL ${CR}) All themes"
|
||||
|
||||
# |
|
||||
# | ::::::: Select Option
|
||||
# |
|
||||
echo -e "\nUsage : Enter Desired Themes Numbers (${C4}OPTIONS${CR}) Separated By A Blank Space"
|
||||
echo -e " Press ${C4}ENTER${CR} without options to Exit\n"
|
||||
read -r -p 'Enter OPTION(S) : ' -a OPTION
|
||||
|
||||
# Automagically generate options if user opts for all themes
|
||||
[[ "$OPTION" == ALL ]] && OPTION=($(seq -s " " $ARRAYLENGTH))
|
||||
|
||||
# |
|
||||
# | ::::::: Get terminal
|
||||
# |
|
||||
if [[ -z "${TERMINAL:-}" ]]; then
|
||||
# |
|
||||
# | Check for the terminal name (depening on os)
|
||||
# | ===========================================
|
||||
OS="$(uname)"
|
||||
if [[ "$OS" = "Darwin" ]]; then
|
||||
TERMINAL=$TERM_PROGRAM
|
||||
elif [[ "${OS#CYGWIN}" != "${OS}" ]]; then
|
||||
TERMINAL="mintty"
|
||||
elif [[ "$TERM" = "xterm-kitty" ]]; then
|
||||
TERMINAL="kitty"
|
||||
elif [[ "${TERM}" = "linux" ]]; then
|
||||
TERMINAL="linux"
|
||||
elif [[ "${HOME}" = *com.termux* ]]; then
|
||||
TERMINAL="termux"
|
||||
else
|
||||
# |
|
||||
# | Depending on how the script was invoked, we need
|
||||
# | to loop until pid is no longer a subshell
|
||||
# | ===========================================
|
||||
pid="$$"
|
||||
TERMINAL="$(ps -h -o comm -p $pid)"
|
||||
while [[ "${TERMINAL:(-2)}" == "sh" ]]; do
|
||||
pid="$(ps -h -o ppid -p $pid)"
|
||||
TERMINAL="$(ps -h -o comm -p $pid)"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# |
|
||||
# | ::::::: Fancy progressbar for lengthy operations
|
||||
# |
|
||||
if [[ ${#OPTION[@]} -gt 5 ]]; then
|
||||
# Note: We use eval here because we want the functions to be available in this script
|
||||
if [[ "$(uname)" = "Darwin" ]]; then
|
||||
eval "$(curl -so- ${PROGRESS_URL})" 2> /dev/null
|
||||
else
|
||||
eval "$(wget -qO- ${PROGRESS_URL})" 2> /dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# |
|
||||
# | Tilix supports fg/bg in color schemes - ask wether user wants to go that route
|
||||
# | This is to avoid creating multiple profiles just for colors
|
||||
# | ===========================================
|
||||
if [[ "$TERMINAL" = "tilix" ]] && [[ ${#OPTION[@]} -gt 0 ]]; then
|
||||
echo
|
||||
read -r -p "Tilix detected - use color schemes instead of profiles? [y/N] " -n 1 TILIX_RES
|
||||
echo
|
||||
|
||||
# |
|
||||
# | When selecting multiple themes and user opts for color schemes, we save all themes
|
||||
# | in a tmpdir and copy the files once all themes has been processed.. If a user
|
||||
# | desides to abort before all themes has been processed this section will cleanup the tmpdir
|
||||
# | =======================================
|
||||
if [[ ${TILIX_RES::1} =~ ^(y|Y)$ ]]; then
|
||||
TILIX_TMP_CLEANUP() {
|
||||
echo
|
||||
echo "Cleaning up"
|
||||
rm -rf "$scratchdir"
|
||||
unset LOOP OPTLENGTH scratchdir
|
||||
echo "Done..."
|
||||
exit 0
|
||||
}
|
||||
|
||||
scratchdir=$(mktemp -d -t gogh.tilix.XXXXXXXX)
|
||||
export scratchdir
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# |
|
||||
# | ::::::: Export one-off variables
|
||||
# |
|
||||
[[ -n "${TILIX_RES:-}" ]] && export TILIX_RES
|
||||
export TERMINAL LOOP OPTLENGTH=${#OPTION[@]}
|
||||
|
||||
|
||||
# |
|
||||
# | ::::::: Apply Theme
|
||||
# |
|
||||
|
||||
declare color_dot_str
|
||||
for c in C{0..15}; do
|
||||
color_dot_str+="${!c}•${CR}"
|
||||
[[ $c == C7 ]] && color_dot_str+=" "
|
||||
done
|
||||
|
||||
# Note:
|
||||
# Constants with a leading 0 are interpreted as octal numbers
|
||||
# Hence option 08 and 09 will not work
|
||||
# Solution is to remove the leading 0 from the parsed options
|
||||
command -v bar::start > /dev/null && bar::start
|
||||
for OP in "${OPTION[@]#0}"; do
|
||||
# See appy_tilixschemes in apply-colors.sh for usage of LOOP
|
||||
LOOP=$((${LOOP:-0}+1))
|
||||
|
||||
command -v bar::status_changed > /dev/null && bar::status_changed $LOOP ${#OPTION[@]}
|
||||
|
||||
if [[ OP -le ARRAYLENGTH && OP -gt 0 ]]; then
|
||||
|
||||
FILENAME=$(remove_file_extension "${THEMES[((OP-1))]}")
|
||||
FILENAME_SPACE="${FILENAME//-/ }"
|
||||
echo -e "\nTheme: $(capitalize "${FILENAME_SPACE}")"
|
||||
echo "${color_dot_str}"
|
||||
echo
|
||||
|
||||
SET_THEME="${THEMES[((OP-1))]}"
|
||||
set_gogh "${SET_THEME}"
|
||||
else
|
||||
echo -e "${C1} ~ INVALID OPTION! ~${CR}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
# If you skip || : and the command does not exist the script will exit with code 1
|
||||
# this will always return exit code 0 if we got this far
|
||||
command -v bar::stop > /dev/null && bar::stop || :
|
||||
994
profiles/desktop/.local/bin/rofi-pass
Executable file
994
profiles/desktop/.local/bin/rofi-pass
Executable file
@@ -0,0 +1,994 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# rofi-pass
|
||||
# (c) 2015 Rasmus Steinke <rasi@xssn.at>
|
||||
basecommand="$0"
|
||||
|
||||
# set default settings
|
||||
_rofi () {
|
||||
rofi -no-auto-select -i "$@"
|
||||
}
|
||||
|
||||
_pwgen () {
|
||||
pwgen -y "$@"
|
||||
}
|
||||
|
||||
_image_viewer () {
|
||||
feh -
|
||||
}
|
||||
|
||||
config_dir=${XDG_CONFIG_HOME:-$HOME/.config}
|
||||
cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}
|
||||
|
||||
# We expect to find these fields in pass(1)'s output
|
||||
URL_field='url'
|
||||
USERNAME_field='user'
|
||||
AUTOTYPE_field='autotype'
|
||||
OTPmethod_field='otp_method'
|
||||
|
||||
default_autotype="user :tab pass"
|
||||
delay=2
|
||||
wait=0.2
|
||||
type_delay=12
|
||||
default_do='menu' # menu, copyPass, typeUser, typePass, copyUser, copyUrl, viewEntry, typeMenu, actionMenu, copyMenu, openUrl
|
||||
auto_enter='false'
|
||||
notify='false'
|
||||
clip=primary
|
||||
clip_clear=45
|
||||
default_user="${ROFI_PASS_DEFAULT_USER-$(whoami)}"
|
||||
default_user2=john_doe
|
||||
password_length=12
|
||||
fix_layout=false
|
||||
|
||||
# default shortcuts
|
||||
autotype="Alt+1"
|
||||
type_user="Alt+2"
|
||||
type_pass="Alt+3"
|
||||
open_url="Alt+4"
|
||||
type_otp="Alt+5"
|
||||
copy_name="Alt+u"
|
||||
copy_url="Alt+l"
|
||||
copy_pass="Alt+p"
|
||||
show="Alt+o"
|
||||
copy_menu="Alt+c"
|
||||
action_menu="Alt+a"
|
||||
type_menu="Alt+t"
|
||||
help="Alt+h"
|
||||
switch="Alt+x"
|
||||
insert_pass="Alt+n"
|
||||
qrcode="Alt+q"
|
||||
previous_root="Shift+Left"
|
||||
next_root="Shift+Right"
|
||||
clipboard_backend=${ROFI_PASS_CLIPBOARD_BACKEND:-xclip}
|
||||
backend=${ROFI_PASS_BACKEND:-xdotool}
|
||||
|
||||
case "$clipboard_backend" in
|
||||
"xclip") ;;
|
||||
"wl-clipboard") ;;
|
||||
*)
|
||||
>&2 echo "Invalid clipboard backend '$clipboard_backend', falling back to xclip"
|
||||
clipboard_backend=xclip
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$backend" in
|
||||
"xdotool") ;;
|
||||
"ydotool") ;;
|
||||
"wtype") ;;
|
||||
*)
|
||||
>&2 echo "Invalid backend '$backend', falling back to xdotool"
|
||||
backend=xdotool
|
||||
;;
|
||||
esac
|
||||
|
||||
# Safe permissions
|
||||
umask 077
|
||||
|
||||
# Backends for clipboard manipulation
|
||||
_clip_in_primary_wl-clipboard() {
|
||||
wl-copy -p
|
||||
}
|
||||
|
||||
_clip_in_clipboard_wl-clipboard() {
|
||||
wl-copy
|
||||
}
|
||||
|
||||
_clip_out_primary_wl-clipboard() {
|
||||
wl-paste -p
|
||||
}
|
||||
|
||||
_clip_out_clipboard_wl-clipboard() {
|
||||
wl-paste
|
||||
}
|
||||
|
||||
_clip_in_primary_xclip() {
|
||||
xclip
|
||||
}
|
||||
|
||||
_clip_in_clipboard_xclip() {
|
||||
xclip -selection clipboard
|
||||
}
|
||||
|
||||
_clip_out_primary_xclip() {
|
||||
xclip -o
|
||||
}
|
||||
|
||||
_clip_out_clipboard_xclip() {
|
||||
xclip --selection clipboard -o
|
||||
}
|
||||
|
||||
# Backends for typing what's in stdin
|
||||
_do_type_xdotool() {
|
||||
xdotool type --delay ${type_delay} --clearmodifiers --file -
|
||||
}
|
||||
|
||||
_do_type_ydotool() {
|
||||
ydotool type --key-delay ${type_delay} --file -
|
||||
}
|
||||
|
||||
_do_type_wtype() {
|
||||
wtype -d ${type_delay} -
|
||||
}
|
||||
|
||||
# Backends for pressing the key specified by the first argument ($1)
|
||||
_do_press_key_xdotool() {
|
||||
xdotool key "$1"
|
||||
}
|
||||
|
||||
_do_press_key_wtype() {
|
||||
wtype -P "$1" -p "$1"
|
||||
}
|
||||
|
||||
has_qrencode() {
|
||||
command -v qrencode >/dev/null 2>&1
|
||||
}
|
||||
|
||||
listgpg () {
|
||||
mapfile -d '' pw_list < <(find -L . -name '*.gpg' -print0)
|
||||
pw_list=("${pw_list[@]#./}")
|
||||
printf '%s\n' "${pw_list[@]}" | sort -n
|
||||
}
|
||||
|
||||
# get all password files and output as newline-delimited text
|
||||
list_passwords() {
|
||||
cd "${root}" || exit
|
||||
mapfile -t pw_list < <(listgpg)
|
||||
printf '%s\n' "${pw_list[@]%.gpg}" | sort -n
|
||||
}
|
||||
|
||||
doClip () {
|
||||
case "$clip" in
|
||||
"primary") ${clip_in_primary} ;;
|
||||
"clipboard") ${clip_in_clipboard} ;;
|
||||
"both") ${clip_in_primary}; ${clip_out_primary} | ${clip_in_clipboard} ;;
|
||||
esac
|
||||
}
|
||||
|
||||
checkIfPass () {
|
||||
printf '%s\n' "${root}: $selected_password" >| "$cache_dir/rofi-pass/last_used"
|
||||
}
|
||||
|
||||
|
||||
autopass () {
|
||||
if [[ $backend == "xdotool" ]]; then
|
||||
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
|
||||
xset r off
|
||||
fi
|
||||
|
||||
rm -f "$cache_dir/rofi-pass/last_used"
|
||||
printf '%s\n' "${root}: $selected_password" > "$cache_dir/rofi-pass/last_used"
|
||||
for word in ${stuff["$AUTOTYPE_field"]}; do
|
||||
case "$word" in
|
||||
":tab") ${do_press_key} Tab ;;
|
||||
":space") ${do_press_key} space ;;
|
||||
":delay") sleep "${delay}" ;;
|
||||
":enter") ${do_press_key} Return ;;
|
||||
":otp") printf '%s' "$(generateOTP)" | ${do_type} ;;
|
||||
"pass") printf '%s' "${password}" | ${do_type} ;;
|
||||
"path") printf '%s' "${selected_password}" | rev | cut -d'/' -f1 | rev | ${do_type} ;;
|
||||
*) printf '%s' "${stuff[${word}]}" | ${do_type} ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ${auto_enter} == "true" ]]; then
|
||||
${do_press_key} Return
|
||||
fi
|
||||
|
||||
if [[ $backend == "xdotool" ]]; then
|
||||
xset r "$x_repeat_enabled"
|
||||
unset x_repeat_enabled
|
||||
fi
|
||||
|
||||
clearUp
|
||||
}
|
||||
|
||||
generateQrCode() {
|
||||
has_qrencode
|
||||
|
||||
if [[ $? -eq "1" ]]; then
|
||||
printf '%s\n' "qrencode not found" | _rofi -dmenu
|
||||
exit_code=$?
|
||||
if [[ $exit_code -eq "1" ]]; then
|
||||
exit
|
||||
else
|
||||
"${basecommand}"
|
||||
fi
|
||||
fi
|
||||
|
||||
checkIfPass
|
||||
pass "$selected_password" | head -n 1 | qrencode -d 300 -v 8 -l H -o - | _image_viewer
|
||||
if [[ $? -eq "1" ]]; then
|
||||
printf '%s\n' "" | _rofi -dmenu -mesg "Image viewer not defined or cannot read from pipe"
|
||||
exit_value=$?
|
||||
if [[ $exit_value -eq "1" ]]; then
|
||||
exit
|
||||
else
|
||||
"${basecommand}"
|
||||
fi
|
||||
fi
|
||||
clearUp
|
||||
}
|
||||
|
||||
openURL () {
|
||||
checkIfPass
|
||||
$BROWSER "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${URL_field}: " | gawk '{sub(/:/,"")}{print $2}1' | head -1)"; exit;
|
||||
clearUp
|
||||
}
|
||||
|
||||
typeUser () {
|
||||
checkIfPass
|
||||
|
||||
if [[ $backend == "xdotool" ]]; then
|
||||
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
|
||||
xset r off
|
||||
fi
|
||||
|
||||
printf '%s' "${stuff[${USERNAME_field}]}" | ${do_type}
|
||||
|
||||
if [[ $backend == "xdotool" ]]; then
|
||||
xset r "$x_repeat_enabled"
|
||||
unset x_repeat_enabled
|
||||
fi
|
||||
|
||||
clearUp
|
||||
}
|
||||
|
||||
typePass () {
|
||||
checkIfPass
|
||||
|
||||
if [[ $backend == "xdotool" ]]; then
|
||||
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
|
||||
xset r off
|
||||
fi
|
||||
|
||||
printf '%s' "${password}" | ${do_type}
|
||||
|
||||
if [[ $notify == "true" ]]; then
|
||||
if [[ "${stuff[notify]}" == "false" ]]; then
|
||||
:
|
||||
else
|
||||
notify-send "rofi-pass" "finished typing password";
|
||||
fi
|
||||
elif [[ $notify == "false" ]]; then
|
||||
if [[ "${stuff[notify]}" == "true" ]]; then
|
||||
notify-send "rofi-pass" "finished typing password";
|
||||
else
|
||||
:
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $backend == "xdotool" ]]; then
|
||||
xset r "$x_repeat_enabled"
|
||||
unset x_repeat_enabled
|
||||
fi
|
||||
|
||||
clearUp
|
||||
}
|
||||
|
||||
typeField () {
|
||||
checkIfPass
|
||||
local to_type
|
||||
|
||||
if [[ $backend == "xdotool" ]]; then
|
||||
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
|
||||
xset r off
|
||||
fi
|
||||
|
||||
case $typefield in
|
||||
"OTP") to_type="$(generateOTP)" ;;
|
||||
*) to_type="${stuff[${typefield}]}" ;;
|
||||
esac
|
||||
|
||||
printf '%s' "$to_type" | ${do_type}
|
||||
|
||||
if [[ $backend == "xdotool" ]]; then
|
||||
xset r "$x_repeat_enabled"
|
||||
unset x_repeat_enabled
|
||||
fi
|
||||
|
||||
unset to_type
|
||||
|
||||
clearUp
|
||||
}
|
||||
|
||||
generateOTP () {
|
||||
checkIfPass
|
||||
|
||||
# First, we check if there is a non-conventional OTP command in the pass file
|
||||
if PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep -q "${OTPmethod_field}: "; then
|
||||
# We execute the commands after otp_method: AS-IS
|
||||
bash -c "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${OTPmethod_field}: " | cut -d' ' -f2-)"
|
||||
else
|
||||
# If there is no method defined, fallback to pass-otp
|
||||
PASSWORD_STORE_DIR="${root}" pass otp "$selected_password"
|
||||
fi
|
||||
|
||||
clearUp
|
||||
}
|
||||
|
||||
copyUser () {
|
||||
checkIfPass
|
||||
printf '%s' "${stuff[${USERNAME_field}]}" | doClip
|
||||
clearUp
|
||||
}
|
||||
|
||||
copyField () {
|
||||
checkIfPass
|
||||
printf '%s' "${stuff[${copyfield}]}" | doClip
|
||||
clearUp
|
||||
}
|
||||
|
||||
copyURL () {
|
||||
checkIfPass
|
||||
printf '%s' "${stuff[${URL_field}]}" | doClip
|
||||
clearUp
|
||||
}
|
||||
|
||||
copyPass () {
|
||||
checkIfPass
|
||||
printf '%s' "$password" | doClip
|
||||
if [[ $notify == "true" ]]; then
|
||||
notify-send "rofi-pass" "Copied Password\\nClearing in $clip_clear seconds"
|
||||
fi
|
||||
|
||||
if [[ $notify == "true" ]]; then
|
||||
(sleep $clip_clear; printf '%s' "" | ${clip_in_primary}; printf '%s' "" | ${clip_in_clipboard} | notify-send "rofi-pass" "Clipboard cleared") &
|
||||
elif [[ $notify == "false" ]]; then
|
||||
(sleep $clip_clear; printf '%s' "" | ${clip_in_primary}; printf '%s' "" | ${clip_in_clipboard}) &
|
||||
fi
|
||||
}
|
||||
|
||||
viewEntry () {
|
||||
checkIfPass
|
||||
showEntry "${selected_password}"
|
||||
}
|
||||
|
||||
generatePass () {
|
||||
askmenu_content=(
|
||||
"Yes"
|
||||
"No"
|
||||
)
|
||||
|
||||
askGenMenu=$(printf '%s\n' "${askmenu_content[@]}" | _rofi -dmenu -p "Generate new Password for ${selected_password}? > ")
|
||||
askgen_exit=$?
|
||||
|
||||
if [[ $askgen_exit -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
if [[ $askGenMenu == "Yes" ]]; then
|
||||
true
|
||||
elif [[ $askGenMenu == "No" ]]; then
|
||||
actionMenu
|
||||
fi
|
||||
|
||||
checkIfPass
|
||||
|
||||
symbols_content=(
|
||||
"0 Cancel"
|
||||
"1 Yes"
|
||||
"2 No"
|
||||
)
|
||||
|
||||
symbols=$(printf '%s\n' "${symbols_content[@]}" | _rofi -dmenu -p "Use Symbols? > ")
|
||||
symbols_val=$?
|
||||
|
||||
if [[ $symbols_val -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
if [[ $symbols == "0 Cancel" ]]; then
|
||||
mainMenu;
|
||||
elif [[ $symbols == "1 Yes" ]]; then
|
||||
symbols="";
|
||||
elif [[ $symbols == "2 No" ]]; then
|
||||
symbols="-n";
|
||||
fi
|
||||
|
||||
HELP="Enter Number or hit Enter to use default length"
|
||||
length=$(printf '%s' "" | _rofi -dmenu -mesg "${HELP}" -p "Password length? (Default: ${password_length}) > ")
|
||||
length_exit=$?
|
||||
|
||||
if [[ $length_exit -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
if [[ $length == "" ]]; then
|
||||
PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${password_length}" > /dev/null;
|
||||
else
|
||||
PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${length}" > /dev/null;
|
||||
fi
|
||||
}
|
||||
|
||||
# main Menu
|
||||
mainMenu () {
|
||||
if [[ $1 == "--bmarks" ]]; then
|
||||
selected_password="$(list_passwords 2>/dev/null \
|
||||
| _rofi -mesg "Bookmarks Mode. ${switch} to switch" \
|
||||
-dmenu \
|
||||
-kb-custom-10 "${switch}" \
|
||||
-select "$entry" \
|
||||
-p "rofi-pass > ")"
|
||||
|
||||
rofi_exit=$?
|
||||
|
||||
if [[ $rofi_exit -eq 1 ]]; then
|
||||
exit
|
||||
elif [[ $rofi_exit -eq 19 ]]; then
|
||||
${basecommand}
|
||||
elif [[ $rofi_exit -eq 0 ]]; then
|
||||
openURL
|
||||
fi
|
||||
else
|
||||
unset selected_password
|
||||
|
||||
args=( -dmenu
|
||||
-kb-custom-1 "${autotype}"
|
||||
-kb-custom-2 "${type_user}"
|
||||
-kb-custom-3 "${type_pass}"
|
||||
-kb-custom-4 "${open_url}"
|
||||
-kb-custom-5 "${copy_name}"
|
||||
-kb-custom-6 "${copy_pass}"
|
||||
-kb-custom-7 "${show}"
|
||||
-kb-custom-8 "${copy_url}"
|
||||
-kb-custom-9 "${type_menu}"
|
||||
-kb-custom-10 "${previous_root}"
|
||||
-kb-custom-11 "${next_root}"
|
||||
-kb-custom-12 "${type_otp}"
|
||||
-kb-custom-14 "${action_menu}"
|
||||
-kb-custom-15 "${copy_menu}"
|
||||
-kb-custom-16 "${help}"
|
||||
-kb-custom-17 "${switch}"
|
||||
-kb-custom-18 "${insert_pass}"
|
||||
-kb-custom-19 "${qrcode}"
|
||||
)
|
||||
args+=( -kb-mode-previous "" # These keyboard shortcut options are needed, because
|
||||
-kb-mode-next "" # Shift+<Left|Right> are otherwise taken by rofi.
|
||||
-select "$entry"
|
||||
-p "> " )
|
||||
|
||||
if [[ ${#roots[@]} -gt "1" || $custom_root == "true" ]]; then
|
||||
args+=(-mesg "PW Store: ${root}")
|
||||
fi
|
||||
|
||||
selected_password="$(list_passwords 2>/dev/null | _rofi "${args[@]}")"
|
||||
|
||||
rofi_exit=$?
|
||||
if [[ $rofi_exit -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
# Actions based on exit code, which do not need the entry.
|
||||
# The exit code for -kb-custom-X is X+9.
|
||||
case "${rofi_exit}" in
|
||||
19) roots_index=$(( (roots_index-1+roots_length) % roots_length)); root=${roots[$roots_index]}; mainMenu; return ;;
|
||||
20) roots_index=$(( (roots_index+1) % roots_length)); root=${roots[$roots_index]}; mainMenu; return ;;
|
||||
25) helpMenu; return ;;
|
||||
26) ${basecommand} --bmarks; return ;;
|
||||
esac
|
||||
|
||||
mapfile -t password_temp < <(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
|
||||
password=${password_temp[0]}
|
||||
|
||||
if [[ ${password} == "#FILE="* ]]; then
|
||||
pass_file="${password#*=}"
|
||||
mapfile -t password_temp2 < <(PASSWORD_STORE_DIR="${root}" pass show "${pass_file}")
|
||||
password=${password_temp2[0]}
|
||||
fi
|
||||
|
||||
fields=$(printf '%s\n' "${password_temp[@]:1}" | awk '$1 ~ /:$/ || /otpauth:\/\// {$1=$1;print}')
|
||||
declare -A stuff
|
||||
stuff["pass"]=${password}
|
||||
|
||||
if [[ -n $fields ]]; then
|
||||
while read -r LINE; do
|
||||
unset _id _val
|
||||
case "$LINE" in
|
||||
"otpauth://"*|"${OTPmethod_field}"*)
|
||||
_id="OTP"
|
||||
_val=""
|
||||
;;
|
||||
*)
|
||||
_id="${LINE%%: *}"
|
||||
_val="${LINE#* }"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -n "$_id" ]]; then
|
||||
stuff["${_id}"]=${_val}
|
||||
fi
|
||||
done < <(printf '%s\n' "${fields}")
|
||||
|
||||
if test "${stuff['autotype']+autotype}"; then
|
||||
:
|
||||
else
|
||||
stuff["autotype"]="${USERNAME_field} :tab pass"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "${stuff["${AUTOTYPE_field}"]}" ]]; then
|
||||
if [[ -n $default_autotype ]]; then
|
||||
stuff["${AUTOTYPE_field}"]="${default_autotype}"
|
||||
fi
|
||||
fi
|
||||
if [[ -z "${stuff["${USERNAME_field}"]}" ]]; then
|
||||
if [[ -n $default_user ]]; then
|
||||
if [[ "$default_user" == ":filename" ]]; then
|
||||
stuff["${USERNAME_field}"]="$(basename "$selected_password")"
|
||||
else
|
||||
stuff["${USERNAME_field}"]="${default_user}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"
|
||||
|
||||
# actions based on keypresses
|
||||
# The exit code for -kb-custom-X is X+9.
|
||||
case "${rofi_exit}" in
|
||||
0) typeMenu ;;
|
||||
10) sleep $wait; autopass ;;
|
||||
11) sleep $wait; typeUser ;;
|
||||
12) sleep $wait; typePass ;;
|
||||
13) openURL ;;
|
||||
14) copyUser ;;
|
||||
15) copyPass ;;
|
||||
16) viewEntry ;;
|
||||
17) copyURL ;;
|
||||
18) default_do="menu" typeMenu ;;
|
||||
21) sleep $wait; typefield=OTP; typeField ;;
|
||||
23) actionMenu ;;
|
||||
24) copyMenu ;;
|
||||
27) insertPass ;;
|
||||
28) generateQrCode ;;
|
||||
esac
|
||||
clearUp
|
||||
}
|
||||
|
||||
|
||||
clearUp () {
|
||||
password=''
|
||||
selected_password=''
|
||||
unset stuff
|
||||
unset password
|
||||
unset selected_password
|
||||
unset password_temp
|
||||
unset stuff
|
||||
}
|
||||
|
||||
helpMenu () {
|
||||
_rofi -dmenu -mesg "Hint: All hotkeys are configurable in config file" -p "Help > " <<- EOM
|
||||
${autotype}: Autotype
|
||||
${type_user}: Type Username
|
||||
${type_pass}: Type Password
|
||||
${type_otp}: Type OTP
|
||||
${qrcode}: Generate and display qrcode
|
||||
---
|
||||
${copy_name}: Copy Username
|
||||
${copy_pass}: Copy Password
|
||||
${copy_url}: Copy URL
|
||||
${open_url}: Open URL
|
||||
${copy_menu}: Copy Custom Field
|
||||
---
|
||||
${action_menu}: Edit, Move, Delete, Re-generate Submenu
|
||||
${show}: Show Password File
|
||||
${insert_pass}: Insert new Pass Entry
|
||||
${switch}: Switch Pass/Bookmark Mode
|
||||
---
|
||||
${previous_root}: Switch to previous password store (--root)
|
||||
${next_root}: Switch to next password store (--root)
|
||||
EOM
|
||||
help_val=$?
|
||||
|
||||
if [[ $help_val -eq 1 ]]; then
|
||||
exit;
|
||||
else
|
||||
unset helptext; mainMenu;
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
typeMenu () {
|
||||
if [[ -n $default_do ]]; then
|
||||
if [[ $default_do == "menu" ]]; then
|
||||
checkIfPass
|
||||
local -a keys=("${!stuff[@]}")
|
||||
keys=("${keys[@]/$AUTOTYPE_field}")
|
||||
typefield=$({ printf '%s' "${AUTOTYPE_field}" ; printf '%s\n' "${keys[@]}" | sort; } | _rofi -dmenu -p "Choose Field to type > ")
|
||||
typefield_exit=$?
|
||||
if [[ $typefield_exit -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
case "$typefield" in
|
||||
'') exit ;;
|
||||
'pass') sleep $wait; typePass ;;
|
||||
"${AUTOTYPE_field}") sleep $wait; autopass ;;
|
||||
*) sleep $wait; typeField
|
||||
esac
|
||||
clearUp
|
||||
elif [[ $default_do == "${AUTOTYPE_field}" ]]; then
|
||||
sleep $wait; autopass
|
||||
else
|
||||
${default_do}
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
copyMenu () {
|
||||
checkIfPass
|
||||
copyfield=$(printf '%s\n' "${!stuff[@]}" | sort | _rofi -dmenu -p "Choose Field to copy > ")
|
||||
val=$?
|
||||
if [[ $val -eq 1 ]]; then
|
||||
exit;
|
||||
fi
|
||||
if [[ $copyfield == "pass" ]]; then
|
||||
copyPass;
|
||||
else
|
||||
copyField
|
||||
fi
|
||||
clearUp
|
||||
}
|
||||
|
||||
actionMenu () {
|
||||
checkIfPass
|
||||
action_content=("< Return"
|
||||
"---"
|
||||
"1 Move Password File"
|
||||
"2 Copy Password File"
|
||||
"3 Delete Password File"
|
||||
"4 Edit Password File"
|
||||
"5 Generate New Password"
|
||||
)
|
||||
|
||||
action=$(printf '%s\n' "${action_content[@]}" | _rofi -dmenu -p "Choose Action > ")
|
||||
if [[ ${action} == "1 Move Password File" ]]; then
|
||||
manageEntry move;
|
||||
elif [[ ${action} == "3 Delete Password File" ]]; then
|
||||
manageEntry delete;
|
||||
elif [[ ${action} == "2 Copy Password File" ]]; then
|
||||
manageEntry copy;
|
||||
elif [[ ${action} == "4 Edit Password File" ]]; then
|
||||
manageEntry edit;
|
||||
elif [[ ${action} == "5 Generate New Password" ]]; then
|
||||
generatePass;
|
||||
elif [[ ${action} == "< Return" ]]; then
|
||||
mainMenu;
|
||||
elif [[ ${action} == "" ]]; then
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
showEntry () {
|
||||
if [[ -z $pass_content ]]; then
|
||||
pass_temp=$(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
|
||||
password="${pass_temp%%$'\n'*}"
|
||||
pass_key_value=$(printf '%s\n' "${pass_temp}" | tail -n+2 | grep ': ')
|
||||
declare -A stuff
|
||||
|
||||
while read -r LINE; do
|
||||
_id="${LINE%%: *}"
|
||||
_val="${LINE#* }"
|
||||
stuff["${_id}"]=${_val}
|
||||
done < <(printf '%s\n' "${pass_key_value}")
|
||||
|
||||
stuff["pass"]=${password}
|
||||
|
||||
if test "${stuff['autotype']+autotype}"; then
|
||||
:
|
||||
else
|
||||
stuff["autotype"]="${USERNAME_field} :tab pass"
|
||||
fi
|
||||
|
||||
pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"
|
||||
fi
|
||||
|
||||
bla_content=("< Return"
|
||||
"${pass_content}"
|
||||
)
|
||||
|
||||
bla=$(printf '%s\n' "${bla_content[@]}" | _rofi -dmenu -mesg "Enter: Copy entry to clipboard" -p "> ")
|
||||
rofi_exit=$?
|
||||
|
||||
word=$(printf '%s' "$bla" | gawk -F': ' '{print $1}')
|
||||
|
||||
if [[ ${rofi_exit} -eq 1 ]]; then
|
||||
exit
|
||||
elif [[ ${rofi_exit} -eq 0 ]]; then
|
||||
if [[ ${bla} == "< Return" ]]; then
|
||||
mainMenu
|
||||
else
|
||||
if [[ -z $(printf '%s' "${stuff[${word}]}") ]]; then
|
||||
printf '%s' "$word" | doClip
|
||||
else
|
||||
printf '%s' "${stuff[${word}]}" | doClip
|
||||
fi
|
||||
if [[ $notify == "true" ]]; then
|
||||
notify-send "rofi-pass" "Copied Password\\nClearing in $clip_clear seconds"
|
||||
fi
|
||||
if [[ $notify == "true" ]]; then
|
||||
(sleep $clip_clear; printf '%s' "" | ${clip_in_primary}; printf '%s' "" | ${clip_in_clipboard} | notify-send "rofi-pass" "Clipboard cleared") &
|
||||
elif [[ $notify == "false" ]]; then
|
||||
(sleep $clip_clear; printf '%s' "" | ${clip_in_primary}; printf '%s' "" | ${clip_in_clipboard}) &
|
||||
fi
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
exit
|
||||
unset stuff
|
||||
unset password
|
||||
unset selected_password
|
||||
unset password_temp
|
||||
unset stuff
|
||||
exit
|
||||
}
|
||||
|
||||
manageEntry () {
|
||||
if [[ "$1" == "edit" ]]; then
|
||||
EDITOR=$EDITOR PASSWORD_STORE_DIR="${root}" pass edit "${selected_password}"
|
||||
mainMenu
|
||||
elif [[ $1 == "move" ]]; then
|
||||
cd "${root}" || exit
|
||||
group_array=(*/)
|
||||
group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
|
||||
if [[ $group == "" ]]; then
|
||||
exit
|
||||
fi
|
||||
PASSWORD_STORE_DIR="${root}" pass mv "$selected_password" "${group}"
|
||||
mainMenu
|
||||
elif [[ $1 == "copy" ]]; then
|
||||
cd "${root}" || exit
|
||||
group_array=(*/)
|
||||
group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
|
||||
if [[ $group == "" ]]; then
|
||||
exit
|
||||
else
|
||||
new_name="$(listgpg | _rofi -dmenu -format 'f' -mesg "Copying to same Group. Please enter a name for the new entry" -p "> ")"
|
||||
fi
|
||||
PASSWORD_STORE_DIR="${root}" pass cp "$selected_password" "${group}/${new_name}"
|
||||
mainMenu
|
||||
elif [[ "$1" == "delete" ]]; then
|
||||
HELP="Selected entry: ${selected_password}"
|
||||
ask_content=("Yes"
|
||||
"No"
|
||||
)
|
||||
ask=$(printf '%s\n' "${ask_content[@]}" | _rofi -mesg "${HELP}" -dmenu -p "Are You Sure? > ")
|
||||
if [[ "$ask" == "Yes" ]]; then
|
||||
PASSWORD_STORE_DIR="${root}" pass rm --force "${selected_password}"
|
||||
elif [[ "$ask" == "No" ]]; then
|
||||
mainMenu
|
||||
elif [[ -z "$ask" ]]; then
|
||||
exit
|
||||
fi
|
||||
else
|
||||
mainMenu
|
||||
fi
|
||||
}
|
||||
|
||||
edit_pass() {
|
||||
if [[ $edit_new_pass == "true" ]]; then
|
||||
PASSWORD_STORE_DIR="${root}" pass edit "${1}"
|
||||
fi
|
||||
}
|
||||
|
||||
insertPass () {
|
||||
url=$(${clip_out_clipboard})
|
||||
|
||||
if [[ "${url:0:4}" == "http" ]]; then
|
||||
domain_name="$(printf '%s\n' "${url}" | awk -F / '{l=split($3,a,"."); print (a[l-1]=="com"?a[l-2] OFS:X) a[l-1] OFS a[l]}' OFS=".")"
|
||||
help_content="Domain: ${domain_name}
|
||||
Type name, make sure it is unique"
|
||||
else
|
||||
help_content="Hint: Copy URL to clipboard before calling this menu.
|
||||
Type name, make sure it is unique"
|
||||
fi
|
||||
|
||||
cd "${root}" || exit
|
||||
group_array=(*/)
|
||||
grouplist=$(printf '%s\n' "${group_array[@]%/}")
|
||||
name="$(listgpg | _rofi -dmenu -format 'f' -filter "${domain_name}" -mesg "${help_content}" -p "> ")"
|
||||
val=$?
|
||||
|
||||
if [[ $val -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
user_content=("${default_user2}"
|
||||
"${USER}"
|
||||
"${default_user}"
|
||||
)
|
||||
|
||||
user=$(printf '%s\n' "${user_content[@]}" | _rofi -dmenu -mesg "Chose Username or type" -p "> ")
|
||||
val=$?
|
||||
|
||||
if [[ $val -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
group_content=("No Group"
|
||||
"---"
|
||||
"${grouplist}"
|
||||
)
|
||||
|
||||
group=$(printf '%s\n' "${group_content[@]}" | _rofi -dmenu -p "Choose Group > ")
|
||||
val=$?
|
||||
|
||||
if [[ $val -eq 1 ]]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
pw=$(printf '%s' "Generate" | _rofi -dmenu -password -p "Password > " -mesg "Type Password or hit Enter to generate one")
|
||||
|
||||
if [[ $pw == "Generate" ]]; then
|
||||
pw=$(_pwgen "${password_length}")
|
||||
fi
|
||||
|
||||
clear
|
||||
|
||||
if [[ "$group" == "No Group" ]]; then
|
||||
if [[ $url == http* ]]; then
|
||||
pass_content=("${pw}"
|
||||
"---"
|
||||
"${USERNAME_field}: ${user}"
|
||||
"${URL_field}: ${url}"
|
||||
)
|
||||
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && edit_pass "${name}"
|
||||
else
|
||||
pass_content=("${pw}"
|
||||
"---"
|
||||
"${USERNAME_field}: ${user}"
|
||||
)
|
||||
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && edit_pass "${name}"
|
||||
fi
|
||||
else
|
||||
if [[ $url == http* ]]; then
|
||||
pass_content=("${pw}"
|
||||
"---"
|
||||
"${USERNAME_field}: ${user}"
|
||||
"${URL_field}: ${url}"
|
||||
)
|
||||
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null && edit_pass "${group}/${name}"
|
||||
else
|
||||
pass_content=("${pw}"
|
||||
"---"
|
||||
"${USERNAME_field}: ${user}"
|
||||
)
|
||||
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null && edit_pass "${group}/${name}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
help_msg () {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
rofi-pass [command]
|
||||
|
||||
Commands:
|
||||
--insert insert new entry to password store
|
||||
--root set custom root directories (colon separated)
|
||||
--last-used highlight last used item
|
||||
--show-last show details of last used Entry
|
||||
--bmarks start in bookmarks mode
|
||||
|
||||
rofi-pass version 1.5.3
|
||||
EOF
|
||||
}
|
||||
|
||||
get_config_file () {
|
||||
configs=("$ROFI_PASS_CONFIG"
|
||||
"$config_dir/rofi-pass/config"
|
||||
"/etc/rofi-pass.conf")
|
||||
|
||||
# return the first config file with a valid path
|
||||
for config in "${configs[@]}"; do
|
||||
# '-n' is needed in case ROFI_PASS_CONFIG is not set
|
||||
if [[ -n "${config}" && -f "${config}" ]]; then
|
||||
printf "%s" "$config"
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
main () {
|
||||
# load config file
|
||||
config_file="$(get_config_file)"
|
||||
[[ -n "$config_file" ]] && source "$config_file"
|
||||
|
||||
# create tmp dir
|
||||
if [[ ! -d "$cache_dir/rofi-pass" ]]; then
|
||||
mkdir -p "$cache_dir/rofi-pass"
|
||||
fi
|
||||
|
||||
# set backends
|
||||
clip_in_primary=_clip_in_primary_${clipboard_backend}
|
||||
clip_in_clipboard=_clip_in_clipboard_${clipboard_backend}
|
||||
clip_out_primary=_clip_out_primary_${clipboard_backend}
|
||||
clip_out_clipboard=_clip_out_clipboard_${clipboard_backend}
|
||||
|
||||
do_type=_do_type_${backend}
|
||||
do_press_key=_do_press_key_${backend}
|
||||
|
||||
# backwards compat
|
||||
if [[ -n "$xdotool_delay" ]]; then
|
||||
>&2 echo "Setting 'xdotool_delay' is deprecated. Please update your configuration to use 'type_delay' instead"
|
||||
type_delay=${xdotool_delay}
|
||||
fi
|
||||
|
||||
# Only valid for the xdotool backend
|
||||
if [[ $backend == "xdotool" ]]; then
|
||||
# fix keyboard layout if enabled in config
|
||||
if [[ $fix_layout == "true" ]]; then
|
||||
layout_cmd
|
||||
fi
|
||||
fi
|
||||
|
||||
# check for BROWSER variable, use xdg-open as fallback
|
||||
if [[ -z $BROWSER ]]; then
|
||||
export BROWSER=xdg-open
|
||||
fi
|
||||
|
||||
# check if alternative root directory was given on commandline
|
||||
if [[ -r "$cache_dir/rofi-pass/last_used" ]] && [[ $1 == "--last-used" || $1 == "--show-last" ]]; then
|
||||
roots=("$(awk -F ': ' '{ print $1 }' "$cache_dir/rofi-pass/last_used")")
|
||||
elif [[ -n "$2" && "$1" == "--root" ]]; then
|
||||
custom_root=true; IFS=: read -r -a roots <<< "$2"
|
||||
elif [[ -n $root ]]; then
|
||||
custom_root=true; IFS=: read -r -a roots <<< "${root}"
|
||||
elif [[ -n ${PASSWORD_STORE_DIR} ]]; then
|
||||
roots=("${PASSWORD_STORE_DIR}")
|
||||
else
|
||||
roots=("$HOME/.password-store")
|
||||
fi
|
||||
roots_index=0
|
||||
roots_length=${#roots[@]}
|
||||
export root=${roots[$roots_index]}
|
||||
export PASSWORD_STORE_DIR="${root}"
|
||||
case $1 in
|
||||
--insert)
|
||||
insertPass
|
||||
;;
|
||||
--root)
|
||||
mainMenu
|
||||
;;
|
||||
--help)
|
||||
help_msg
|
||||
;;
|
||||
--last-used)
|
||||
if [[ -r "$cache_dir/rofi-pass/last_used" ]]; then
|
||||
entry="$(awk -F ': ' '{ print $2 }' "$cache_dir/rofi-pass/last_used")"
|
||||
fi
|
||||
mainMenu
|
||||
;;
|
||||
--show-last)
|
||||
if [[ -r "$cache_dir/rofi-pass/last_used" ]]; then
|
||||
selected_password="$(awk -F ': ' '{ print $2 }' "$cache_dir/rofi-pass/last_used")" viewEntry
|
||||
else
|
||||
mainMenu
|
||||
fi
|
||||
;;
|
||||
--bmarks)
|
||||
mainMenu --bmarks;
|
||||
;;
|
||||
*)
|
||||
mainMenu
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
49
profiles/desktop/.local/bin/video_extract
Executable file
49
profiles/desktop/.local/bin/video_extract
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
usage() {
|
||||
echo "Usage: $(basename "$0") file_name start end"
|
||||
}
|
||||
|
||||
extract_images() {
|
||||
local video_file=$1
|
||||
local start=$2
|
||||
local end=$3
|
||||
local start_in_seconds
|
||||
local end_in_seconds
|
||||
local date_diff
|
||||
|
||||
start_in_seconds=$(date --date "${start}" +%s)
|
||||
end_in_seconds=$(date --date "${end}" +%s)
|
||||
date_diff=$((end_in_seconds - start_in_seconds))
|
||||
|
||||
ffmpeg -ss "${start}" -t ${date_diff} -i "${video_file}" -qscale:v 2 output_%03d.jpg
|
||||
}
|
||||
|
||||
if [[ $# -ne 3 ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
||||
echo "ffmpeg: command not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FILENAME=$1
|
||||
START=$2
|
||||
END=$3
|
||||
|
||||
if [ ! -f "${FILENAME}" ]; then
|
||||
echo "${FILENAME}: not a file"
|
||||
exit 1
|
||||
fi
|
||||
if ! { [[ ${START} =~ ^([0-9]{2}:)?[0-9]{2}:[0-9]{2}$ ]] && date -d "${START}" >/dev/null 2>&1; }; then
|
||||
echo "${START}: incorrect time"
|
||||
exit 1
|
||||
fi
|
||||
if ! { [[ ${END} =~ ^([0-9]{2}:)?[0-9]{2}:[0-9]{2}$ ]] && date -d "${END}" >/dev/null 2>&1; }; then
|
||||
echo "${END}: incorrect time"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
extract_images "${FILENAME}" "${START}" "${END}"
|
||||
Reference in New Issue
Block a user