-
-
Save ConnerWill/594f9ffdc9b0b519468c4fa9a2f40b72 to your computer and use it in GitHub Desktop.
'pkg' package manager wrapper for both Debian and Arch distros. (now in color! and with fzf!!!)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/data/data/com.termux/files/usr/bin/bash | |
set -eu | |
# Setup TERMUX_APP_PACKAGE_MANAGER | |
source "/data/data/com.termux/files/usr/bin/termux-setup-package-manager" || exit 1 | |
show_help() { | |
local cache_size | |
local cache_dir="" | |
if [ "$TERMUX_APP_PACKAGE_MANAGER" = "apt" ]; then | |
cache_dir="/data/data/com.termux/cache/apt/archives" | |
elif [ "$TERMUX_APP_PACKAGE_MANAGER" = "pacman" ]; then | |
cache_dir="/data/data/com.termux/files/usr/var/cache/pacman/pkg" | |
fi | |
cache_size=$(du -sh "$cache_dir" 2>/dev/null | cut -f1) | |
# \e[0;38;5;255m | |
# echo 'Usage: pkg [--check-mirror] command [arguments]' | |
# printf '\n' | |
# echo 'A tool for managing packages.' | |
# echo ' --check-mirror forces a re-check of availability of mirrors' | |
printf '\n' | |
echo 'Commands:' | |
printf '\n' | |
printf '\e[0;38;5;10m autoclean \e[0;38;5;255m- \e[3;4mRemove all outdated packages from .deb package cache\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m clean \e[0;38;5;255m- \e[3;4mRemove all packages from .deb package cache.\e[0m\n' | |
#[ -n "$cache_size" ] && printf " Using %s now\e[0m\n""$cache_size" | |
printf '\n' | |
printf '\e[0;38;5;10m files \e[0;38;5;8m<packages> \e[0;38;5;255m- \e[3;4mShow all files installed by packages.\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m install \e[0;38;5;8m<packages> \e[0;38;5;255m- \e[3;4mInstall specified packages.\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m reinstall \e[0;38;5;8m<packages> \e[0;38;5;255m- \e[3;4mReinstall specified installed packages at thelatest version.\e[0m\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m list-all \e[0;38;5;255m- \e[3;4mList all packages available in repositories.\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m list-installed \e[0;38;5;255m- \e[3;4mList installed packages.\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m search \e[0;38;5;8m<query> \e[0;38;5;255m- \e[3;4mSearch package by query, for example by name or description part.\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m fzf \e[0;38;5;8m[query] \e[0;38;5;255m- \e[3;4mList/Search all packages using fzf.\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m show \e[0;38;5;8m<packages> \e[0;38;5;255m- \e[3;4mShow basic metadata, such as dependencies.\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m uninstall \e[0;38;5;8m<packages> \e[0;38;5;255m- \e[3;4mUninstall specified packages. Configuration files will be left intact.\e[0m\n' | |
printf '\n' | |
printf '\e[0;38;5;10m upgrade \e[0;38;5;255m- \e[3;4mUpgrade all installed packages to the latest version.\e[0m\n' | |
printf '\n' | |
exit 1 | |
} | |
check_mirror() { | |
local mirror="${1%/}" | |
local timeout="${2-5}" | |
timeout "$((timeout + 1))" curl \ | |
--head \ | |
--fail \ | |
--connect-timeout "$timeout" \ | |
--location \ | |
--user-agent "Termux-PKG/2.0 mirror-checker (termux-tools 1.20) Termux (com.termux; install-prefix:/data/data/com.termux/files/usr)" \ | |
"$mirror/dists/stable/Release" >/dev/null 2>&1 | |
} | |
hostname() { | |
echo "$1" | awk -F'[/:]' '{print $4}' | |
} | |
last_modified() { | |
local mtime | |
local now | |
mtime=$(date -r "$1" '+%s') | |
now=$(date '+%s') | |
echo $((now - mtime)) | |
} | |
has_repo() { | |
# Check if root-repo or x11-repo are installed | |
repo="$1" | |
if [ -f "/data/data/com.termux/files/usr/etc/apt/sources.list.d/$repo.list" ]; then | |
echo true | |
else | |
echo false | |
fi | |
} | |
_fzf_function(){ | |
local searchquery | |
searchquery="$@" | |
apt list | fzf \ | |
--query "${searchquery}" \ | |
--reverse \ | |
--extended --ansi \ | |
--sync --print-query \ | |
--color='hl+:#ff00ff,hl:#00ff00' \ | |
--preview="apt show {} | egrep --regex '(^Package)|(^Description)' | column --separator ':' --table " \ | |
--preview-window='bottom,5' \ | |
} | |
get_mirror_url() { | |
source "$1" | |
echo $MAIN | |
} | |
get_mirror_weight() { | |
source "$1" | |
echo $WEIGHT | |
} | |
select_mirror() { | |
local default_repo="/data/data/com.termux/files/usr/etc/termux/mirrors/default" | |
if [ -d "/data/data/com.termux/files/usr/etc/termux/chosen_mirrors" ]; then | |
mirrors=($(find /data/data/com.termux/files/usr/etc/termux/chosen_mirrors/ -type f ! -name "*\.dpkg-old" ! -name "*~")) | |
elif [ -L "/data/data/com.termux/files/usr/etc/termux/chosen_mirrors" ]; then | |
# Broken symlink, use all mirrors | |
mirrors=("/data/data/com.termux/files/usr/etc/termux/mirrors/default") | |
mirrors+=($(find /data/data/com.termux/files/usr/etc/termux/mirrors/{asia,china,europe,north_america,russia}/ -type f ! -name "*\.dpkg-old" ! -name "*~")) | |
else | |
echo "No group of mirrors selected. You might want to select a group by running 'termux-change-repo'" | |
mirrors=("/data/data/com.termux/files/usr/etc/termux/mirrors/default") | |
mirrors+=($(find /data/data/com.termux/files/usr/etc/termux/mirrors/{asia,china,europe,north_america,russia}/ -type f ! -name "*\.dpkg-old" ! -name "*~")) | |
fi | |
local current_mirror | |
current_mirror=$(grep -m 1 -P "^\s*deb\s+" /data/data/com.termux/files/usr/etc/apt/sources.list | grep -oP 'https?://[^\s]+') | |
# Do not update mirror if $TERMUX_PKG_NO_MIRROR_SELECT was set. | |
if [ -n "${TERMUX_PKG_NO_MIRROR_SELECT-}" ] && [ -n "$current_mirror" ]; then | |
return | |
fi | |
# Mirrors are rotated if 6 hours timeout has been passed or mirror is no longer accessible. | |
local pkgcache="/data/data/com.termux/cache/apt/pkgcache.bin" | |
if [ -e "$pkgcache" ] && (( $(last_modified "$pkgcache") <= 6 * 3600 )) && [ "$force_check_mirror" = "false" ]; then | |
if [ -n "$current_mirror" ]; then | |
echo "Checking availability of current mirror:" | |
echo -n "[*] $current_mirror: " | |
if check_mirror "$current_mirror"; then | |
echo "ok" | |
return | |
else | |
echo "bad" | |
fi | |
fi | |
fi | |
# Test mirror availability, remove unaccessible mirrors from list. | |
echo "Testing the available mirrors:" | |
local parallel_jobs_max_count=10 | |
if [[ ! "$parallel_jobs_max_count" =~ ^[0-9]+$ ]] || \ | |
[[ "$parallel_jobs_max_count" -lt 1 ]] || \ | |
[[ "$parallel_jobs_max_count" -gt 1000 ]]; then | |
parallel_jobs_max_count=1 | |
fi | |
declare -a parallel_jobs_mirrors=() | |
declare -a parallel_jobs_weights=() | |
declare -a parallel_jobs_urls=() | |
declare -a parallel_jobs_numbers=() | |
declare -a parallel_jobs_pids=() | |
declare -a parallel_jobs_return_values=() | |
local i j mirror url job_number job_pid return_value | |
local total_mirrors=${#mirrors[@]} | |
local parallel_jobs_current_count=1 | |
set +e | |
i=0 | |
for mirror in "${!mirrors[@]}"; do | |
url="$(get_mirror_url ${mirrors[$mirror]})" | |
job_number=$parallel_jobs_current_count | |
parallel_jobs_current_count=$((parallel_jobs_current_count + 1)) | |
# Start mirror check in background | |
check_mirror "$url" & | |
job_pid=$! | |
parallel_jobs_mirrors=("${parallel_jobs_mirrors[@]}" "$mirror") | |
parallel_jobs_weights=("${parallel_jobs_weights[@]}" "$(get_mirror_weight ${mirrors[$mirror]})") | |
parallel_jobs_urls=("${parallel_jobs_urls[@]}" "$url") | |
parallel_jobs_numbers=("${parallel_jobs_numbers[@]}" "$job_number") | |
parallel_jobs_pids=("${parallel_jobs_pids[@]}" "$job_pid") | |
# If current job count has reached max value or is the last mirror, wait for already started jobs to finish | |
if [ "$job_number" -ge $parallel_jobs_max_count ] || \ | |
[ "$i" -ge $((total_mirrors - 1)) ]; then | |
j=0 | |
# For pids of all jobs | |
for job_pid in "${parallel_jobs_pids[@]}"; do | |
# Wait for job with matching pid to return | |
# echo "waiting for check_mirror job ${parallel_jobs_numbers[j]} for mirror \"${parallel_jobs_urls[j]}\" with pid ${parallel_jobs_pids[j]}" | |
wait "$job_pid" | |
return_value=$? | |
parallel_jobs_return_values=("${parallel_jobs_return_values[@]}" "$return_value") | |
j=$((j + 1)) | |
done | |
j=0 | |
# For return_values of all jobs | |
for return_value in "${parallel_jobs_return_values[@]}"; do | |
echo -n "[*] (${parallel_jobs_weights[j]}) ${parallel_jobs_urls[j]}: " | |
if [ "$return_value" -eq 0 ]; then | |
echo "ok" | |
else | |
echo "bad" | |
# echo "check_mirror job ${parallel_jobs_numbers[j]} for mirror \"${parallel_jobs_urls[j]}\" with pid ${parallel_jobs_pids[j]} failed with exit code $return_value" | |
unset "mirrors[${parallel_jobs_mirrors[j]}]" | |
fi | |
j=$((j + 1)) | |
done | |
# Reset job related variables | |
parallel_jobs_current_count=1 | |
parallel_jobs_mirrors=() | |
parallel_jobs_weights=() | |
parallel_jobs_urls=() | |
parallel_jobs_numbers=() | |
parallel_jobs_pids=() | |
parallel_jobs_return_values=() | |
fi | |
i=$((i + 1)) | |
done | |
set -e | |
# Build weighted array of valid mirrors | |
declare -a weighted_mirrors | |
local total_mirror_weight=0 | |
local weight | |
for mirror in "${!mirrors[@]}"; do | |
# Check if mirror was unset in parallel check | |
if [ -z "${mirrors[$mirror]-}" ]; then | |
continue | |
fi | |
weight="$(get_mirror_weight ${mirrors[$mirror]})" | |
total_mirror_weight=$((total_mirror_weight + weight)) | |
j=0 | |
while [ "$j" -lt "$weight" ]; do | |
weighted_mirrors+=(${mirrors[$mirror]}) | |
j=$((j + 1)) | |
done | |
done | |
# Select random mirror | |
local selected_mirror="" | |
if ((total_mirror_weight > 0)); then | |
local random_weight | |
random_weight=$(( (RANDOM % total_mirror_weight + 1) - 1 )) | |
echo "Picking mirror: (${random_weight}) ${weighted_mirrors[${random_weight}]}" | |
selected_mirror="${weighted_mirrors[${random_weight}]}" | |
fi | |
if [ -n "$selected_mirror" ]; then | |
( | |
source "$selected_mirror" | |
echo "deb $MAIN stable main" > /data/data/com.termux/files/usr/etc/apt/sources.list | |
if [ "$(has_repo x11)" == "true" ]; then | |
echo "deb $X11 x11 main" > /data/data/com.termux/files/usr/etc/apt/sources.list.d/x11.list | |
fi | |
if [ "$(has_repo root)" == "true" ]; then | |
echo "deb $ROOT root stable" > /data/data/com.termux/files/usr/etc/apt/sources.list.d/root.list | |
fi | |
) | |
fi | |
} | |
update_apt_cache() { | |
local current_host | |
current_host=$(sed -nE -e 's|^\s*deb\s+https?://(.+)\s+stable\s+main$|\1|p' /data/data/com.termux/files/usr/etc/apt/sources.list | head -n 1) | |
if [ -z "$current_host" ]; then | |
# No primary repositories configured? | |
apt update | |
return | |
fi | |
local metadata_file | |
metadata_file=$( | |
list_prefix=$(echo "$current_host" | sed 's|/|_|g') | |
arch=$(dpkg --print-architecture) | |
echo "/data/data/com.termux/files/usr/var/lib/apt/lists/${list_prefix}_dists_stable_main_binary-${arch}_Packages" | sed 's|__|_|g' | |
) | |
if [ ! -e "/data/data/com.termux/cache/apt/pkgcache.bin" ] || [ ! -e "$metadata_file" ]; then | |
apt update | |
return | |
fi | |
local cache_modified | |
cache_modified=$(last_modified "/data/data/com.termux/cache/apt/pkgcache.bin") | |
local sources_modified | |
sources_modified=$(last_modified "/data/data/com.termux/files/usr/etc/apt/sources.list") | |
if (( sources_modified <= cache_modified )) || (( cache_modified > 1200 )); then | |
apt update | |
fi | |
} | |
force_check_mirror=false | |
if [ "${1-}" = "--check-mirror" ]; then | |
force_check_mirror=true | |
shift 1 | |
fi | |
if [[ $# = 0 || $(echo "$1" | grep "^h") ]]; then | |
show_help | |
fi | |
CMD="$1" | |
shift 1 | |
ERROR=false | |
case "$TERMUX_APP_PACKAGE_MANAGER" in | |
apt) | |
case "$CMD" in | |
fi*) dpkg -L "$@";; | |
sh*|inf*) apt show "$@";; | |
add|i*) select_mirror; update_apt_cache; apt install "$@";; | |
autoc*) apt autoclean;; | |
cl*) apt clean;; | |
fz*) _fzf_function "$@" ;; | |
list-a*) apt list "$@";; | |
list-i*) apt list --installed "$@";; | |
rei*) apt install --reinstall "$@";; | |
se*) select_mirror; update_apt_cache; apt search "$@";; | |
un*|rem*|rm|del*) apt remove "$@";; | |
up*) select_mirror; apt update; apt full-upgrade "$@";; | |
*) ERROR=true;; | |
esac;; | |
pacman) | |
case "$CMD" in | |
f*) pacman -Ql "$@";; | |
sh*|inf*) pacman -Qi "$@";; | |
add|i*) pacman -Sy --needed "$@";; | |
autoc*) pacman -Sc;; | |
cl*) pacman -Scc;; | |
list-a*) pacman -Sl "$@";; | |
list-i*) pacman -Q "$@";; | |
rei*) pacman -S "$@";; | |
se*) pacman -Sys "$@";; | |
un*|rem*|rm|del*) pacman -Rcns "$@";; | |
up*) pacman -Syu "$@";; | |
*) ERROR=true;; | |
esac;; | |
esac | |
if $ERROR; then | |
printf "\n\e[0;38;5;190mUnknown command: '\e[0;1;38;5;196m%s\e[0;38;5;190m'\e[0m \e[0;3;4;38;5;8m(run 'pkg help' for usage information)\e[0m\n\n" "$CMD" ; exit 1 | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment