mirror of
https://github.com/webinstall/webi-installers.git
synced 2026-04-20 08:56:48 +00:00
1011 lines
31 KiB
Bash
1011 lines
31 KiB
Bash
#!/bin/sh
|
|
|
|
__bootstrap_webi() {
|
|
#PKG_NAME=
|
|
#WEBI_OS=
|
|
#WEBI_ARCH=
|
|
#WEBI_LIBC=
|
|
#WEBI_RELEASES=
|
|
#WEBI_CSV=
|
|
#WEBI_TAG=
|
|
#WEBI_VERSION=
|
|
#WEBI_MAJOR=
|
|
#WEBI_MINOR=
|
|
#WEBI_PATCH=
|
|
# TODO not sure if BUILD is the best name for this
|
|
#WEBI_BUILD=
|
|
#WEBI_GIT_TAG=
|
|
#WEBI_LTS=
|
|
#WEBI_CHANNEL=
|
|
#WEBI_EXT=
|
|
#WEBI_FORMATS=
|
|
#WEBI_PKG_URL=
|
|
#WEBI_PKG_FILE=
|
|
#WEBI_PKG_PATHNAME=
|
|
#PKG_OSES=
|
|
#PKG_ARCHES=
|
|
#PKG_LIBCS=
|
|
#PKG_FORMATS=
|
|
#PKG_LATEST=
|
|
#PKG_STABLE=
|
|
WEBI_PKG_DOWNLOAD=""
|
|
WEBI_DOWNLOAD_DIR="${HOME}/Downloads"
|
|
if command -v xdg-user-dir > /dev/null; then
|
|
WEBI_DOWNLOAD_DIR="$(xdg-user-dir DOWNLOAD)"
|
|
if [ "${WEBI_DOWNLOAD_DIR}" = "${HOME}" ]; then
|
|
WEBI_DOWNLOAD_DIR="${HOME}/Downloads"
|
|
fi
|
|
fi
|
|
|
|
WEBI_PKG_PATH="${WEBI_DOWNLOAD_DIR}/webi/${PKG_NAME:-error}/${WEBI_VERSION:-stable}"
|
|
|
|
# get the special formatted version
|
|
# (i.e. "go is go1.14" while node is "node v12.10.8")
|
|
my_versioned_name=""
|
|
_webi_canonical_name() {
|
|
if [ -n "$my_versioned_name" ]; then
|
|
echo "$my_versioned_name"
|
|
return 0
|
|
fi
|
|
|
|
if command -v pkg_format_cmd_version > /dev/null; then
|
|
my_versioned_name="'$(pkg_format_cmd_version "$WEBI_VERSION")'"
|
|
else
|
|
my_versioned_name="'$pkg_cmd_name v$WEBI_VERSION'"
|
|
fi
|
|
|
|
echo "$my_versioned_name"
|
|
}
|
|
|
|
# Update symlinks as per $HOME/.local/opt and $HOME/.local/bin install paths.
|
|
webi_link() {
|
|
if command -v pkg_link > /dev/null; then
|
|
pkg_link
|
|
return 0
|
|
fi
|
|
|
|
if test -n "${WEBI_SINGLE}"; then
|
|
rm -rf "$pkg_dst_cmd"
|
|
ln -s "$pkg_src_cmd" "$pkg_dst_cmd"
|
|
else
|
|
# 'pkg_dst' will default to $HOME/.local/opt/<pkg>
|
|
# 'pkg_src' will be the installed version,
|
|
# such as to $HOME/.local/opt/<pkg>-<version>
|
|
rm -rf "$pkg_dst"
|
|
ln -s "$pkg_src" "$pkg_dst"
|
|
fi
|
|
}
|
|
|
|
# detect if this program is already installed
|
|
# or if an installed version may cause conflict
|
|
webi_check_installed() {
|
|
# Test for existing version
|
|
set +e
|
|
my_path="$PATH"
|
|
PATH="$(dirname "$pkg_dst_cmd"):$PATH"
|
|
export PATH
|
|
my_current_cmd="$(command -v "$pkg_cmd_name")"
|
|
set -e
|
|
if [ -n "$my_current_cmd" ]; then
|
|
my_canonical_name="$(_webi_canonical_name)"
|
|
if [ "$my_current_cmd" != "$pkg_dst_cmd" ]; then
|
|
echo >&2 " $(t_err "WARN: possible PATH conflict between $my_canonical_name and currently installed version")"
|
|
echo >&2 " $(t_path "${pkg_dst_cmd}") (new)"
|
|
echo >&2 " $(t_path "${my_current_cmd}") (existing)"
|
|
#my_current_version=false
|
|
fi
|
|
# 'readlink' can't read links in paths on macOS 🤦
|
|
# but that's okay, 'cmp -s' is good enough for us
|
|
if cmp -s "${pkg_src_cmd}" "${my_current_cmd}"; then
|
|
echo " $(t_pkg "${my_canonical_name}") already installed:"
|
|
my_dst_rel="$(fn_sub_home "${pkg_dst}")"
|
|
printf " %s" "$(t_link "${my_dst_rel}")"
|
|
if [ "${pkg_src_cmd}" != "${my_current_cmd}" ]; then
|
|
my_src_rel="$(fn_sub_home "${pkg_src}")"
|
|
printf " => %s" "$(t_path "${my_src_rel}")"
|
|
fi
|
|
echo ""
|
|
exit 0
|
|
fi
|
|
if [ -x "$pkg_src_cmd" ]; then
|
|
webi_link
|
|
echo " Switched to ${my_canonical_name}:"
|
|
my_src_rel="$(fn_sub_home "${pkg_src}")"
|
|
my_dst_rel="$(fn_sub_home "${pkg_dst}")"
|
|
echo " $(t_link "${my_dst_rel}") => $(t_path "${my_src_rel}")"
|
|
exit 0
|
|
fi
|
|
fi
|
|
export PATH="$my_path"
|
|
}
|
|
|
|
webi_check_available() {
|
|
if test "$WEBI_CHANNEL" != "error"; then
|
|
return 0
|
|
fi
|
|
|
|
{
|
|
echo ""
|
|
echo " $(t_err "Error: no '${PKG_NAME:-"Unknown Package"}@${WEBI_TAG:-"Unknown Tag"}' release for '${WEBI_OS:-"Unknown OS"}' (${WEBI_LIBC:-"Unknown Libc"}) on '${WEBI_ARCH:-"Unknown CPU"}' as one of '${WEBI_FORMATS:-"Unknown File Type"}'")"
|
|
echo ""
|
|
echo " Latest Stable: ${PKG_STABLE}"
|
|
if test "${PKG_LATEST}" != "${PKG_STABLE}"; then
|
|
echo " Next Version: ${PKG_LATEST}"
|
|
fi
|
|
echo " CPUs: $PKG_ARCHES"
|
|
echo " OSes: $PKG_OSES"
|
|
echo " libcs: $PKG_LIBCS"
|
|
echo " Package Formats: $PKG_FORMATS"
|
|
echo " (check that the package name and version are correct)"
|
|
|
|
echo ""
|
|
my_release_url="$(echo "$WEBI_RELEASES" | sed 's:?.*::')"
|
|
my_release_params="$(echo "$WEBI_RELEASES" | sed 's:.*?:?:')"
|
|
echo " Double check at ${my_release_url}"
|
|
echo " ${my_release_params}"
|
|
echo ""
|
|
} >&2
|
|
|
|
exit 1
|
|
}
|
|
|
|
# detect if file is downloaded, and how to download it
|
|
webi_download() {
|
|
my_url="${1}"
|
|
my_dl="${2}"
|
|
my_dl_name="${3:-${PKG_NAME}}"
|
|
|
|
my_dl_rel="$(fn_sub_home "${my_dl}")"
|
|
|
|
WEBI_PKG_DOWNLOAD="${my_dl}"
|
|
export WEBI_PKG_DOWNLOAD
|
|
|
|
if [ -e "${my_dl}" ]; then
|
|
echo " $(t_dim 'Found') $(t_path "${my_dl_rel}")"
|
|
return 0
|
|
fi
|
|
echo " Downloading $(t_pkg "${my_dl_name}") from"
|
|
echo " $(t_url "${my_url}")"
|
|
fn_download_to_path "${my_url}" "${my_dl}"
|
|
echo " $(t_dim 'Saved as') $(t_path "${my_dl_rel}")"
|
|
}
|
|
|
|
webi_git_clone() { (
|
|
my_url="${1}"
|
|
my_dl="${2}"
|
|
|
|
my_dl_rel="$(fn_sub_home "${my_dl}")"
|
|
if [ -e "${my_dl}" ]; then
|
|
echo " $(t_dim 'Found') $(t_path "${my_dl_rel}")"
|
|
|
|
cp -RPp "${my_dl}" "${WEBI_TMP}/${WEBI_PKG_FILE}/"
|
|
return 0
|
|
fi
|
|
|
|
echo " Cloning $(t_url "${my_url}")"
|
|
cmd_git="git clone --config advice.detachedHead=false --quiet --depth=1 --single-branch"
|
|
rm -rf "${my_dl}.part"
|
|
if ! $cmd_git "${my_url}" --branch "${WEBI_GIT_TAG}" "${my_dl}.part"; then
|
|
echo >&2 " $(t_err "failed to git clone ${WEBI_PKG_URL}")"
|
|
exit 1
|
|
fi
|
|
mv "${my_dl}.part" "${my_dl}"
|
|
|
|
cp -RPp "${my_dl}" "${WEBI_TMP}/${WEBI_PKG_FILE}/"
|
|
); }
|
|
|
|
# detect which archives can be used
|
|
webi_extract() { (
|
|
cd "$WEBI_TMP"
|
|
|
|
my_dl_rel="$(
|
|
fn_sub_home "${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
|
|
)"
|
|
if test "$WEBI_EXT" = "tar.zst"; then
|
|
echo " Extracting $(t_path "${my_dl_rel}")"
|
|
unzstd -c --keep "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" | tar xf -
|
|
elif test "$WEBI_EXT" = "tar.xz"; then
|
|
echo " Extracting $(t_path "${my_dl_rel}")"
|
|
unxz -c -k "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" | tar xf -
|
|
elif test "$WEBI_EXT" = "tar.gz"; then
|
|
echo " Extracting $(t_path "${my_dl_rel}")"
|
|
tar xzf "${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
|
|
elif test "$WEBI_EXT" = "tar.bz2"; then
|
|
echo " Extracting $(t_path "${my_dl_rel}")"
|
|
tar xjf "${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
|
|
elif test "$WEBI_EXT" = "tar"; then
|
|
echo " Extracting $(t_path "${my_dl_rel}")"
|
|
tar xf "${WEBI_PKG_PATH}/$WEBI_PKG_FILE"
|
|
elif test "$WEBI_EXT" = "zip" || test "$WEBI_EXT" = "app.zip"; then
|
|
echo " Extracting $(t_path "${my_dl_rel}")"
|
|
unzip "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > __unzip__.log
|
|
elif test "$WEBI_EXT" = "exe"; then
|
|
echo " Moving $(t_path "${my_dl_rel}")"
|
|
echo " to $(t_path "$(fn_sub_home "$(pwd)")")"
|
|
mv "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" .
|
|
elif test "$WEBI_EXT" = "git"; then
|
|
echo " Moving $(t_path "${my_dl_rel}")"
|
|
mv "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" .
|
|
elif test "$WEBI_EXT" = "xz"; then
|
|
echo " Inflating $(t_path "${my_dl_rel}")"
|
|
unxz -c "${WEBI_PKG_PATH}/$WEBI_PKG_FILE" > "$(basename "$WEBI_PKG_FILE")"
|
|
else
|
|
echo " $(t_err 'Failed to extract') $(t_path "${WEBI_PKG_PATH}/$WEBI_PKG_FILE")"
|
|
exit 1
|
|
fi
|
|
); }
|
|
|
|
# use 'pathman' to update $HOME/.config/envman/PATH.env
|
|
webi_path_add() {
|
|
my_path="${1}"
|
|
|
|
# \v was chosen as it is extremely unlikely for a filename
|
|
# \1 could be an even better choice, but needs more testing.
|
|
# (currently tested working on: linux & mac)
|
|
# "\0001" should also work
|
|
my_delim="$(
|
|
printf '\v'
|
|
)"
|
|
|
|
my_path_expanded="$(
|
|
echo "${my_path}" |
|
|
sed -e "s${my_delim}\$HOME${my_delim}$HOME${my_delim}g" \
|
|
-e "s${my_delim}\${HOME}${my_delim}$HOME${my_delim}g" \
|
|
-e "s${my_delim}^~/${my_delim}$HOME/${my_delim}g"
|
|
)"
|
|
|
|
# A gift for @adamcstephens.
|
|
# See https://github.com/webinstall/webi-installers/issues/322
|
|
case "${PATH}" in
|
|
# matches whether the first, a middle, the last, or the only PATH entry
|
|
"${my_path_expanded}":* | \
|
|
*:"${my_path_expanded}":* | \
|
|
*:"${my_path_expanded}" | \
|
|
"${my_path_expanded}")
|
|
|
|
if fn_is_defined_in_all_shells "${my_path}"; then
|
|
return 0
|
|
fi
|
|
;;
|
|
*) ;;
|
|
esac
|
|
|
|
my_path_export="$(
|
|
echo "${my_path}" |
|
|
sed -e "s${my_delim}${HOME}${my_delim}\$HOME${my_delim}g" \
|
|
-e "s${my_delim}\${HOME}${my_delim}\$HOME${my_delim}g" \
|
|
-e "s${my_delim}^~/${my_delim}\$HOME/${my_delim}g"
|
|
)"
|
|
|
|
my_export="export PATH=\"$my_path_export:\$PATH\""
|
|
|
|
touch -a ~/.config/envman/PATH.env
|
|
if grep -q -F "${my_export}" ~/.config/envman/PATH.env; then
|
|
return 0
|
|
fi
|
|
|
|
echo "${my_export}" >> ~/.config/envman/PATH.env
|
|
|
|
mkdir -p "$_webi_tmp"
|
|
my_path_tilde="$(
|
|
echo "${my_path}" |
|
|
sed -e "s${my_delim}${HOME}${my_delim}~${my_delim}g"
|
|
)"
|
|
|
|
if ! test -f "$_webi_tmp/.PATH.env" ||
|
|
! grep -q -F "${my_path_tilde}" "$_webi_tmp/.PATH.env"; then
|
|
echo "${my_path_tilde}" >> "$_webi_tmp/.PATH.env"
|
|
fi
|
|
}
|
|
|
|
fn_is_defined_in_all_shells() {
|
|
my_path="${1}"
|
|
|
|
my_path_expanded="$(
|
|
echo "${my_path}" |
|
|
sed -e "s${my_delim}\$HOME|${my_delim}$HOME${my_delim}g" \
|
|
-e "s${my_delim}\${HOME}${my_delim}$HOME${my_delim}g" \
|
|
-e "s${my_delim}^~/${my_delim}$HOME/${my_delim}g"
|
|
)"
|
|
my_paths="$(
|
|
echo "${my_path_expanded}"
|
|
# $HOME/foo
|
|
echo "${my_path_expanded}" |
|
|
sed "s${my_delim}${HOME}${my_delim}\$HOME${my_delim}g"
|
|
# ${HOME}/foo
|
|
echo "${my_path_expanded}" |
|
|
sed "s${my_delim}${HOME}${my_delim}\${HOME}${my_delim}g"
|
|
echo "${my_path}"
|
|
)"
|
|
|
|
my_confs="$(
|
|
echo "${HOME}/.profile"
|
|
echo "${HOME}/.bashrc"
|
|
echo "${HOME}/.zshrc"
|
|
echo "${HOME}/.config/fish/config.fish"
|
|
)"
|
|
for my_conf in $my_confs; do
|
|
if ! test -e "${my_conf}"; then
|
|
continue
|
|
fi
|
|
|
|
if ! grep -q -F "${my_paths}" "${my_conf}"; then
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
# group common pre-install tasks as default
|
|
webi_pre_install() {
|
|
webi_check_installed
|
|
webi_check_available
|
|
if test "git" = "${WEBI_EXT}"; then
|
|
webi_git_clone \
|
|
"${WEBI_PKG_URL}" \
|
|
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
|
|
return 0
|
|
fi
|
|
webi_download \
|
|
"${WEBI_PKG_URL}" \
|
|
"${WEBI_PKG_PATH}/${WEBI_PKG_FILE}"
|
|
webi_extract
|
|
}
|
|
|
|
# move commands from the extracted archive directory
|
|
# to $HOME/.local/opt or $HOME/.local/bin
|
|
webi_install() {
|
|
b_src=''
|
|
if test -n "${WEBI_SINGLE}"; then
|
|
b_src="${pkg_src_cmd}"
|
|
mkdir -p "$(dirname "$pkg_src_cmd")"
|
|
else
|
|
echo " Removing $(t_path "${pkg_src}")"
|
|
rm -rf "$pkg_src"
|
|
b_src="${pkg_src}"
|
|
fi
|
|
|
|
echo " Moving $(t_path "${pkg_cmd_name}")"
|
|
echo " to $(t_path "$(fn_sub_home "${b_src}")")"
|
|
mv ./"${pkg_cmd_name}"* "${b_src}"
|
|
}
|
|
|
|
# run post-install functions - just updating PATH by default
|
|
webi_post_install() {
|
|
if test -n "${pkg_no_exec}"; then
|
|
return 0
|
|
fi
|
|
|
|
webi_path_add "$(dirname "$pkg_dst_cmd")"
|
|
}
|
|
|
|
_webi_enable_exec() {
|
|
if command -v spctl > /dev/null && command -v xattr > /dev/null; then
|
|
# note: some packages contain files that cannot be affected by xattr
|
|
xattr -r -d com.apple.quarantine "$pkg_src" || true
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
_webi_done_message() {
|
|
my_dst_rel="$(fn_sub_home "${pkg_dst_cmd}")"
|
|
my_canonical_name="$(_webi_canonical_name)"
|
|
echo ""
|
|
echo " Installed $(t_pkg "${my_canonical_name}") as $(t_link "${my_dst_rel}")"
|
|
}
|
|
|
|
##
|
|
## Set up tmp, download, and install directories
|
|
##
|
|
|
|
WEBI_TMP=${WEBI_TMP:-"$(mktemp -d -t webinstall-"${WEBI_PKG-}".XXXXXXXX)"}
|
|
export _webi_tmp="${_webi_tmp:-"$HOME/.local/opt/webi-tmp.d"}"
|
|
|
|
mkdir -p "${WEBI_PKG_PATH}"
|
|
mkdir -p "$HOME/.local/opt"
|
|
|
|
if test -e ~/.local/bin; then
|
|
echo " $(t_dim 'Found') $(t_path ' ~/.local/bin')"
|
|
else
|
|
echo " Creating$(t_path ' ~/.local/bin')"
|
|
mkdir -p "$HOME/.local/bin"
|
|
fi
|
|
fn_envman_init
|
|
|
|
##
|
|
##
|
|
## BEGIN custom override functions from <package>/install.sh
|
|
##
|
|
##
|
|
|
|
WEBI_SINGLE=
|
|
|
|
__init_installer() {
|
|
# the installer will be injected here
|
|
# {{ installer }}
|
|
|
|
return 0
|
|
}
|
|
|
|
__init_installer
|
|
|
|
##
|
|
##
|
|
## END custom override functions
|
|
##
|
|
##
|
|
|
|
# run everything with defaults or overrides as needed
|
|
if command -v pkg_install > /dev/null ||
|
|
command -v pkg_link > /dev/null ||
|
|
command -v pkg_post_install > /dev/null ||
|
|
command -v pkg_done_message > /dev/null ||
|
|
command -v pkg_format_cmd_version > /dev/null ||
|
|
[ -n "${WEBI_SINGLE-}" ] ||
|
|
[ -n "${pkg_cmd_name-}" ] ||
|
|
[ -n "${pkg_dst_cmd-}" ] ||
|
|
[ -n "${pkg_dst_dir-}" ] ||
|
|
[ -n "${pkg_dst-}" ] ||
|
|
[ -n "${pkg_src_cmd-}" ] ||
|
|
[ -n "${pkg_src_dir-}" ] ||
|
|
[ -n "${pkg_src-}" ]; then
|
|
|
|
pkg_cmd_name="${pkg_cmd_name:-$PKG_NAME}"
|
|
|
|
pkg_no_exec="${pkg_no_exec:-}"
|
|
|
|
if [ -n "${pkg_no_exec}" ]; then
|
|
pkg_dst_cmd="${pkg_dst}"
|
|
pkg_src="${pkg_dst}"
|
|
pkg_src_cmd="${pkg_dst}"
|
|
elif [ -n "${WEBI_SINGLE}" ]; then
|
|
pkg_dst_cmd="${pkg_dst_cmd:-$HOME/.local/bin/$pkg_cmd_name}"
|
|
pkg_dst="$pkg_dst_cmd"
|
|
|
|
#pkg_src_cmd="${pkg_src_cmd:-$HOME/.local/opt/$pkg_cmd_name-v$WEBI_VERSION/bin/$pkg_cmd_name-v$WEBI_VERSION}"
|
|
pkg_src_cmd="${pkg_src_cmd:-$HOME/.local/opt/$pkg_cmd_name-v$WEBI_VERSION/bin/$pkg_cmd_name}"
|
|
pkg_src="$pkg_src_cmd"
|
|
else
|
|
pkg_dst="${pkg_dst:-$HOME/.local/opt/$pkg_cmd_name}"
|
|
pkg_dst_cmd="${pkg_dst_cmd:-$pkg_dst/bin/$pkg_cmd_name}"
|
|
|
|
pkg_src="${pkg_src:-$HOME/.local/opt/$pkg_cmd_name-v$WEBI_VERSION}"
|
|
pkg_src_cmd="${pkg_src_cmd:-$pkg_src/bin/$pkg_cmd_name}"
|
|
fi
|
|
# shellcheck disable=SC2034 # used in ${WEBI_PKG}/install.sh
|
|
pkg_src_bin="$(dirname "$pkg_src_cmd")"
|
|
# shellcheck disable=SC2034 # used in ${WEBI_PKG}/install.sh
|
|
pkg_dst_bin="$(dirname "$pkg_dst_cmd")"
|
|
|
|
if command -v pkg_pre_install > /dev/null; then pkg_pre_install; else webi_pre_install; fi
|
|
|
|
(
|
|
cd "$WEBI_TMP"
|
|
my_src_rel="$(
|
|
fn_sub_home "${pkg_src_cmd}"
|
|
)"
|
|
if test -e "${pkg_src_cmd}"; then
|
|
echo " $(t_dim 'Found') $(t_path "${my_src_rel}") $(t_dim '(remove to force reinstall)')"
|
|
else
|
|
echo " Installing to $(t_path "${my_src_rel}")"
|
|
if command -v pkg_install > /dev/null; then pkg_install; else webi_install; fi
|
|
chmod a+x "$pkg_src"
|
|
chmod a+x "$pkg_src_cmd"
|
|
fi
|
|
)
|
|
|
|
if test -z "${pkg_no_exec}"; then
|
|
webi_link
|
|
_webi_enable_exec
|
|
fi
|
|
(
|
|
cd "$WEBI_TMP"
|
|
if command -v pkg_post_install > /dev/null; then pkg_post_install; else webi_post_install; fi
|
|
)
|
|
|
|
(
|
|
cd "$WEBI_TMP"
|
|
if command -v pkg_done_message > /dev/null; then pkg_done_message; else _webi_done_message; fi
|
|
)
|
|
|
|
echo ""
|
|
fi
|
|
|
|
webi_path_add "$HOME/.local/bin"
|
|
if [ -z "${_WEBI_CHILD-}" ] && [ -f "$_webi_tmp/.PATH.env" ]; then
|
|
if test -s "$_webi_tmp/.PATH.env"; then
|
|
# shellcheck disable=SC2088 # ~ should not expand here
|
|
echo " Edit $(t_path '~/.config/envman/PATH.env') to add:"
|
|
sort -u "$_webi_tmp/.PATH.env" | while read -r my_new_path; do
|
|
echo " $(t_path "${my_new_path}")"
|
|
done
|
|
echo ""
|
|
|
|
rm -f "$_webi_tmp/.PATH.env"
|
|
|
|
echo ">>> $(t_info 'ACTION REQUIRED') <<<"
|
|
echo " Copy, paste & run the following command:"
|
|
echo " $(t_attn 'source ~/.config/envman/PATH.env')"
|
|
echo " (newly opened terminal windows will update automatically)"
|
|
echo ""
|
|
fi
|
|
fi
|
|
|
|
rm -rf "$WEBI_TMP"
|
|
}
|
|
|
|
#########################################
|
|
# #
|
|
# Display Debug Info in Case of Failure #
|
|
# #
|
|
#########################################
|
|
|
|
fn_show_welcome_back() { (
|
|
if test -n "${WEBI_WELCOME:-}"; then
|
|
return 0
|
|
fi
|
|
|
|
echo ""
|
|
# invert t_task and t_pkg for top-level welcome message
|
|
printf -- ">>> %s %s <<<\n" \
|
|
"$(t_pkg 'Welcome to') $(t_task 'Webi')$(t_pkg '!')" \
|
|
"$(t_dim "- modern tools, instant installs.")"
|
|
echo " We expect your experience to be $(t_em 'absolutely perfect')!"
|
|
echo ""
|
|
echo " $(t_attn 'Success')? Star it! $(t_url 'https://github.com/webinstall/webi-installers')"
|
|
echo " $(t_attn 'Problem')? Report it: $(t_url 'https://github.com/webinstall/webi-installers/issues')"
|
|
echo " $(t_dim "(your system is") $(t_host "$(fn_get_os)")/$(t_host "$(uname -m)") $(t_dim "with") $(t_host "$(fn_get_libc)") $(t_dim "&") $(t_host "$(fn_get_http_client_name)")$(t_dim ")")"
|
|
|
|
sleep 0.2
|
|
); }
|
|
|
|
fn_get_os() { (
|
|
# Ex:
|
|
# GNU/Linux
|
|
# Android
|
|
# Linux (often Alpine, musl)
|
|
# Darwin
|
|
b_os="$(uname -o 2> /dev/null || echo '')"
|
|
b_sys="$(uname -s)"
|
|
if test -z "${b_os}" || test "${b_os}" = "${b_sys}"; then
|
|
# ex: 'Darwin' (and plain, non-GNU 'Linux')
|
|
echo "${b_sys}"
|
|
return 0
|
|
fi
|
|
|
|
if echo "${b_os}" | grep -q "${b_sys}"; then
|
|
# ex: 'GNU/Linux'
|
|
echo "${b_os}"
|
|
return 0
|
|
fi
|
|
|
|
# ex: 'Android/Linux'
|
|
echo "${b_os}/${b_sys}"
|
|
); }
|
|
|
|
fn_get_libc() { (
|
|
# Ex:
|
|
# musl
|
|
# libc
|
|
if ldd /bin/ls 2> /dev/null | grep -q 'musl' 2> /dev/null; then
|
|
echo 'musl'
|
|
elif fn_get_os | grep -q 'GNU|Linux'; then
|
|
echo 'gnu'
|
|
else
|
|
echo 'libc'
|
|
fi
|
|
); }
|
|
|
|
fn_get_http_client_name() { (
|
|
# Ex:
|
|
# curl
|
|
# curl+wget
|
|
b_client=""
|
|
if command -v curl > /dev/null; then
|
|
b_client="curl"
|
|
fi
|
|
if command -v wget > /dev/null; then
|
|
if test -z "${b_client}"; then
|
|
b_client="wget"
|
|
else
|
|
b_client="curl+wget"
|
|
fi
|
|
fi
|
|
|
|
echo "${b_client}"
|
|
); }
|
|
|
|
#########################################
|
|
# #
|
|
# For Making the Display Nice #
|
|
# #
|
|
#########################################
|
|
|
|
# Term Types
|
|
t_cmd() { (fn_printf '\e[2m\e[35m%s\e[39m\e[22m' "${1}"); }
|
|
t_host() { (fn_printf '\e[2m\e[33m%s\e[39m\e[22m' "${1}"); }
|
|
t_link() { (fn_printf '\e[1m\e[36m%s\e[39m\e[22m' "${1}"); }
|
|
t_path() { (fn_printf '\e[2m\e[32m%s\e[39m\e[22m' "${1}"); }
|
|
t_pkg() { (fn_printf '\e[1m\e[32m%s\e[39m\e[22m' "${1}"); }
|
|
t_task() { (fn_printf '\e[36m%s\e[39m' "${1}"); }
|
|
t_url() { (fn_printf '\e[2m%s\e[22m' "${1}"); }
|
|
|
|
# Levels
|
|
t_info() { (fn_printf '\e[1m\e[36m%s\e[39m\e[22m' "${1}"); }
|
|
t_attn() { (fn_printf '\e[1m\e[33m%s\e[39m\e[22m' "${1}"); }
|
|
t_warn() { (fn_printf '\e[1m\e[33m%s\e[39m\e[22m' "${1}"); }
|
|
t_err() { (fn_printf '\e[31m%s\e[39m' "${1}"); }
|
|
|
|
# Styles
|
|
t_bold() { (fn_printf '\e[1m%s\e[22m' "${1}"); }
|
|
t_dim() { (fn_printf '\e[2m%s\e[22m' "${1}"); }
|
|
t_em() { (fn_printf '\e[3m%s\e[23m' "${1}"); }
|
|
t_under() { (fn_printf '\e[4m%s\e[24m' "${1}"); }
|
|
|
|
# FG Colors
|
|
t_cyan() { (fn_printf '\e[36m%s\e[39m' "${1}"); }
|
|
t_green() { (fn_printf '\e[32m%s\e[39m' "${1}"); }
|
|
t_magenta() { (fn_printf '\e[35m%s\e[39m' "${1}"); }
|
|
t_yellow() { (fn_printf '\e[33m%s\e[39m' "${1}"); }
|
|
|
|
fn_printf() { (
|
|
a_style="${1}"
|
|
a_text="${2}"
|
|
if fn_is_tty; then
|
|
#shellcheck disable=SC2059
|
|
printf -- "${a_style}" "${a_text}"
|
|
else
|
|
printf -- '%s' "${a_text}"
|
|
fi
|
|
); }
|
|
|
|
fn_sub_home() { (
|
|
my_rel=${HOME}
|
|
my_abs=${1}
|
|
echo "${my_abs}" | sed "s:^${my_rel}:~:"
|
|
); }
|
|
|
|
###################################
|
|
# #
|
|
# Detect HTTP Client #
|
|
# #
|
|
###################################
|
|
|
|
fn_wget() { (
|
|
# Doc:
|
|
# Downloads the file at the given url to the given path
|
|
a_url="${1}"
|
|
a_path="${2}"
|
|
|
|
cmd_wget="wget -c -q --user-agent"
|
|
if fn_is_tty; then
|
|
cmd_wget="wget -c -q --show-progress --user-agent"
|
|
fi
|
|
# busybox wget doesn't support --show-progress
|
|
# See <https://github.com/webinstall/webi-installers/pull/772>
|
|
if readlink "$(command -v wget)" | grep -q busybox; then
|
|
cmd_wget="wget --user-agent"
|
|
fi
|
|
|
|
b_triple_ua="$(fn_get_target_triple_user_agent)"
|
|
b_agent="webi/wget ${b_triple_ua}"
|
|
if command -v curl > /dev/null; then
|
|
b_agent="webi/wget+curl ${b_triple_ua}"
|
|
fi
|
|
|
|
if ! $cmd_wget "${b_agent}" "${a_url}" -O "${a_path}"; then
|
|
echo >&2 " $(t_err "failed to download (wget)") '$(t_url "${a_url}")'"
|
|
echo >&2 " $cmd_wget '${b_agent}' '${a_url}' -O '${a_path}'"
|
|
echo >&2 " $(wget -V)"
|
|
return 1
|
|
fi
|
|
); }
|
|
|
|
fn_curl() { (
|
|
# Doc:
|
|
# Downloads the file at the given url to the given path
|
|
a_url="${1}"
|
|
a_path="${2}"
|
|
|
|
cmd_curl="curl -f -sSL -#"
|
|
if fn_is_tty; then
|
|
cmd_curl="curl -f -sSL"
|
|
fi
|
|
|
|
b_triple_ua="$(fn_get_target_triple_user_agent)"
|
|
b_agent="webi/curl ${b_triple_ua}"
|
|
if command -v wget > /dev/null; then
|
|
b_agent="webi/curl+wget ${b_triple_ua}"
|
|
fi
|
|
|
|
if ! $cmd_curl -A "${b_agent}" "${a_url}" -o "${a_path}"; then
|
|
echo >&2 " $(t_err "failed to download (curl)") '$(t_url "${a_url}")'"
|
|
echo >&2 " $cmd_curl -A '${b_agent}' '${a_url}' -o '${a_path}'"
|
|
echo >&2 " $(curl -V)"
|
|
return 1
|
|
fi
|
|
); }
|
|
|
|
fn_get_target_triple_user_agent() { (
|
|
# Ex:
|
|
# x86_64/unknown GNU/Linux/5.15.107-2-pve gnu
|
|
# arm64/unknown Darwin/22.6.0 libc
|
|
echo "$(uname -m)/unknown $(fn_get_os)/$(uname -r) $(fn_get_libc)"
|
|
); }
|
|
|
|
fn_download_to_path() { (
|
|
a_url="${1}"
|
|
a_path="${2}"
|
|
|
|
mkdir -p "$(dirname "${a_path}")"
|
|
if command -v curl > /dev/null; then
|
|
fn_curl "${a_url}" "${a_path}.part"
|
|
elif command -v wget > /dev/null; then
|
|
fn_wget "${a_url}" "${a_path}.part"
|
|
else
|
|
echo >&2 " $(t_err "failed to detect HTTP client (curl, wget)")"
|
|
return 1
|
|
fi
|
|
mv "${a_path}.part" "${a_path}"
|
|
); }
|
|
|
|
##############################################
|
|
# #
|
|
# Install or Update Webi and Install Package #
|
|
# #
|
|
##############################################
|
|
|
|
webi_upgrade() { (
|
|
a_path="${1}"
|
|
|
|
b_path_rel="$(fn_sub_home "${a_path}")"
|
|
b_checksum=""
|
|
if test -r "${a_path}"; then
|
|
b_checksum="$(fn_checksum "${a_path}")"
|
|
fi
|
|
if test "$b_checksum" = "${WEBI_CHECKSUM}"; then
|
|
sleep 0.1
|
|
return 0
|
|
fi
|
|
|
|
b_webi_file_url="${WEBI_HOST}/packages/webi/webi.sh"
|
|
b_tmp=''
|
|
if test -r "${a_path}"; then
|
|
b_ts="$(date -u '+%s')"
|
|
b_tmp="${a_path}.${b_ts}.bak"
|
|
mv "${a_path}" "${b_tmp}"
|
|
echo ""
|
|
echo "$(t_task 'Updating') $(t_pkg 'Webi')"
|
|
fi
|
|
|
|
echo " Downloading $(t_url "${b_webi_file_url}")"
|
|
echo " to $(t_path "${b_path_rel}")"
|
|
fn_download_to_path "${b_webi_file_url}" "${a_path}"
|
|
chmod u+x "${a_path}"
|
|
|
|
if test -r "${b_tmp}"; then
|
|
rm -f "${b_tmp}"
|
|
fi
|
|
); }
|
|
|
|
fn_checksum() {
|
|
a_filepath="${1}"
|
|
|
|
if command -v sha1sum > /dev/null; then
|
|
sha1sum "${a_filepath}" | cut -d' ' -f1 | cut -c 1-8
|
|
return 0
|
|
fi
|
|
|
|
if command -v shasum > /dev/null; then
|
|
shasum "${a_filepath}" | cut -d' ' -f1 | cut -c 1-8
|
|
return 0
|
|
fi
|
|
|
|
if command -v sha1 > /dev/null; then
|
|
sha1 "${a_filepath}" | cut -d'=' -f2 | cut -c 2-9
|
|
return 0
|
|
fi
|
|
|
|
echo >&2 " warn: no sha1 sum program"
|
|
date '+%F %H:%M'
|
|
}
|
|
|
|
##############################################
|
|
# #
|
|
# Detect TTY and run main #
|
|
# #
|
|
##############################################
|
|
|
|
fn_is_tty() {
|
|
if test "${WEBI_TTY}" = 'tty'; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
fn_detect_tty() { (
|
|
# stdin will NOT be a tty if it's being piped
|
|
# stdout & stderr WILL be a tty even when piped
|
|
# they are not a tty if being captured or redirected
|
|
# 'set -i' is NOT available in sh
|
|
if test -t 1 && test -t 2; then
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
); }
|
|
|
|
main() { (
|
|
set -e
|
|
set -u
|
|
#set -x
|
|
|
|
export WEBI_HOST=
|
|
export WEBI_CHECKSUM=
|
|
export WEBI_PKG=
|
|
|
|
WEBI_TTY="${WEBI_TTY:-}"
|
|
if test -z "${WEBI_TTY}"; then
|
|
if fn_detect_tty; then
|
|
WEBI_TTY="tty"
|
|
fi
|
|
export WEBI_TTY
|
|
fi
|
|
|
|
if test -z "${WEBI_WELCOME:-}"; then
|
|
fn_show_welcome_back
|
|
fi
|
|
export WEBI_WELCOME='shown'
|
|
|
|
# note: we may support custom locations in the future
|
|
export WEBI_HOME="${HOME}/.local"
|
|
b_webi_path="${WEBI_HOME}/bin/webi"
|
|
|
|
WEBI_CURRENT="${WEBI_CURRENT:-}"
|
|
if test "${WEBI_CURRENT}" != "${WEBI_CHECKSUM}"; then
|
|
webi_upgrade "${b_webi_path}"
|
|
export WEBI_CURRENT="${WEBI_CHECKSUM}"
|
|
fi
|
|
|
|
echo "$(t_task 'Installing') $(t_pkg "${WEBI_PKG}") $(t_task '...')"
|
|
__bootstrap_webi
|
|
); }
|
|
|
|
##############################################
|
|
# #
|
|
# envman helper functions #
|
|
# #
|
|
##############################################
|
|
|
|
fn_envman_init() { (
|
|
if ! test -r ~/.config/envman/; then
|
|
echo " Initializing ~/.config/envman/"
|
|
mkdir -p ~/.config/envman/
|
|
fi
|
|
|
|
# Note: the variables $BASH, $ZSH_NAME, etc are always empty
|
|
# because the active shell is always sh when this script runs
|
|
fn_envman_init_load_sh
|
|
fn_envman_init_shell sh '.profile' '.ash_history'
|
|
fn_envman_init_shell bash '.bashrc' '.bash_history'
|
|
fn_envman_init_shell zsh '.zshrc' '.zsh_sessions'
|
|
|
|
if command -v fish > /dev/null; then
|
|
fn_envman_init_load_fish
|
|
fn_envman_init_fish
|
|
fi
|
|
); }
|
|
|
|
fn_envman_init_load_sh() { (
|
|
touch -a ~/.config/envman/load.sh
|
|
if grep -q -F 'ENVMAN_LOAD' ~/.config/envman/load.sh; then
|
|
return 0
|
|
fi
|
|
|
|
cat << LOAD_SH > ~/.config/envman/load.sh
|
|
# Generated for envman. Do not edit.
|
|
# shellcheck disable=SC1090
|
|
|
|
touch -a ~/.config/envman/PATH.env
|
|
touch -a ~/.config/envman/ENV.env
|
|
touch -a ~/.config/envman/alias.env
|
|
touch -a ~/.config/envman/function.sh
|
|
|
|
# ENV first because we may use it in PATH
|
|
test -z "\${ENVMAN_LOAD:-}" && . ~/.config/envman/ENV.env
|
|
test -z "\${ENVMAN_LOAD:-}" && . ~/.config/envman/PATH.env
|
|
|
|
export ENVMAN_LOAD='loaded'
|
|
|
|
# function first because we may use it in alias
|
|
test -z "\${g_envman_load_sh:-}" && . ~/.config/envman/function.sh
|
|
test -z "\${g_envman_load_sh:-}" && . ~/.config/envman/alias.env
|
|
|
|
g_envman_load_sh='loaded'
|
|
LOAD_SH
|
|
|
|
); }
|
|
|
|
fn_envman_init_shell() { (
|
|
a_shell="${1}"
|
|
a_rc="${2}"
|
|
a_history="${3:-_history_file_doesnt_exist}"
|
|
a_login_shell="$(basename "${SHELL:-}")"
|
|
|
|
if ! command -v "${a_shell}" > /dev/null; then
|
|
return 0
|
|
fi
|
|
|
|
# .bashrc and .zshrc no longer exist by default on macOS
|
|
if ! test -e ~/"${a_rc}" && ! test -e ~/"${a_history}"; then
|
|
if test "${a_login_shell}" != "${a_shell}"; then
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
touch -a ~/"${a_rc}"
|
|
if grep -q -F '/.config/envman/load.sh' ~/"${a_rc}"; then
|
|
return 0
|
|
fi
|
|
|
|
# shellcheck disable=SC2088 # ~ should not expand here
|
|
echo >&2 " Edit $(t_path "~/${a_rc}") to $(t_cmd "source ~/.config/envman/load.sh")"
|
|
{
|
|
echo ''
|
|
echo '# Generated for envman. Do not edit.'
|
|
#shellcheck disable=SC2016 # vars should not expand here
|
|
echo '[ -s "$HOME/.config/envman/load.sh" ] && source "$HOME/.config/envman/load.sh"'
|
|
} >> ~/"${a_rc}"
|
|
); }
|
|
|
|
fn_envman_init_load_fish() { (
|
|
mkdir -p ~/.config/envman/
|
|
|
|
touch -a ~/.config/envman/load.fish
|
|
if grep -q -F 'ENVMAN_LOAD' ~/.config/envman/load.fish; then
|
|
return 0
|
|
fi
|
|
|
|
echo >&2 " Create ~/.config/envman/load.fish"
|
|
|
|
cat << EOF > ~/.config/envman/load.fish
|
|
# Generated for envman. Do not edit.
|
|
|
|
touch -a ~/.config/envman/PATH.env
|
|
touch -a ~/.config/envman/ENV.env
|
|
touch -a ~/.config/envman/alias.env
|
|
touch -a ~/.config/envman/function.fish
|
|
|
|
not set -q ENVMAN_LOAD; and source ~/.config/envman/ENV.env
|
|
not set -q ENVMAN_LOAD; and source ~/.config/envman/PATH.env
|
|
|
|
set -x ENVMAN_LOAD 'loaded'
|
|
|
|
not set -q g_envman_load_fish; and source ~/.config/envman/function.fish
|
|
not set -q g_envman_load_fish; and source ~/.config/envman/alias.env
|
|
|
|
set -g g_envman_load_fish 'loaded'
|
|
EOF
|
|
|
|
); }
|
|
|
|
fn_envman_init_fish() {
|
|
mkdir -p ~/.config/fish/
|
|
|
|
touch -a ~/.config/fish/config.fish
|
|
if grep -q -F '/.config/envman/load.fish' ~/.config/fish/config.fish; then
|
|
return 0
|
|
fi
|
|
|
|
# shellcheck disable=SC2088 # ~ should not expand here
|
|
echo >&2 " Edit $(t_path "~/.config/fish/config.fish") to $(t_cmd "source ~/.config/envman/load.fish")"
|
|
|
|
cat << EOF >> ~/.config/fish/config.fish
|
|
|
|
# Generated for envman. Do not edit.
|
|
test -s ~/.config/envman/load.fish; and source ~/.config/envman/load.fish
|
|
EOF
|
|
|
|
}
|
|
|
|
main
|