Sync aptss 4.5.0

Signed-off-by: shenmo <jifengshenmo@outlook.com>
This commit is contained in:
shenmo 2025-02-24 11:47:44 +00:00 committed by Gitee
parent 6fa0e11927
commit f02c279c8a
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F

@ -1,21 +1,25 @@
#!/bin/bash #!/bin/bash
# #
# apt-fast v1.9 # apt-fast v1.10.0
# Use this just like aptitude or apt-get for faster package downloading. # Use this just like aptitude or apt-get for faster package downloading.
# #
# Copyright: 2008-2012 Matt Parnell, http://www.mattparnell.com # Copyright: 2008-2012 Matt Parnell, http://www.mattparnell.com
# Improvements, maintenance, revisions - 2012, 2017-2018 Dominique Lasserre # Improvements, maintenance, revisions - 2012, 2017-2019 Dominique Lasserre
# #
# You may distribute this file under the terms of the GNU General # You may distribute this file under the terms of the GNU General
# Public License as published by the Free Software Foundation; either # Public License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version. # version 3 of the License, or (at your option) any later version.
# #
shopt -s nullglob
[ -n "$DEBUG" ] && set -xv [ -n "$DEBUG" ] && set -xv
# Print colored messages. # Print colored messages.
# Usage: msg "message text" "message type" "optional: err" # Usage: msg "message text" "message type" "optional: err"
# Message types are 'normal', 'hint' or 'warning'. Warnings and messages with a # Message types are 'normal', 'hint' or 'warning'. Warnings and messages with a
# third argument are piped to stderr. # third argument are piped to stderr.
THREADS=$(nproc 2>/dev/null || echo 4)
msg(){ msg(){
msg_options=() msg_options=()
case "$2" in case "$2" in
@ -34,7 +38,7 @@ msg(){
} }
# Search for known options and decide if root privileges are needed. # Search for known options and decide if root privileges are needed.
root=1 # default value: we need root privileges root=$#
option= option=
for argument in "$@"; do for argument in "$@"; do
case "$argument" in case "$argument" in
@ -70,7 +74,6 @@ TMP__APTMGR="${_APTMGR-${TMP_RANDOM}}"
TMP_APTCACHE="${APTCACHE-${TMP_RANDOM}}" TMP_APTCACHE="${APTCACHE-${TMP_RANDOM}}"
TMP_DLDIR="${DLDIR-${TMP_RANDOM}}" TMP_DLDIR="${DLDIR-${TMP_RANDOM}}"
TMP_DLLIST="${DLLIST-${TMP_RANDOM}}" TMP_DLLIST="${DLLIST-${TMP_RANDOM}}"
TMP_LISTDIR="${LISTDIR-${TMP_RANDOM}}"
TMP__MAXNUM="${MAXNUM-${TMP_RANDOM}}" TMP__MAXNUM="${MAXNUM-${TMP_RANDOM}}"
TMP__MAXCONPERSRV="${MAXCONPERSRV-${TMP_RANDOM}}" TMP__MAXCONPERSRV="${MAXCONPERSRV-${TMP_RANDOM}}"
TMP__SPLITCON="${SPLITCON-${TMP_RANDOM}}" TMP__SPLITCON="${SPLITCON-${TMP_RANDOM}}"
@ -78,6 +81,7 @@ TMP__MINSPLITSZ=${MINSPLITSZ-${TMP_RANDOM}}
TMP__PIECEALGO=${PIECEALGO-${TMP_RANDOM}} TMP__PIECEALGO=${PIECEALGO-${TMP_RANDOM}}
TMP_aptfast_prefix="${aptfast_prefix-${TMP_RANDOM}}" TMP_aptfast_prefix="${aptfast_prefix-${TMP_RANDOM}}"
TMP_APT_FAST_TIMEOUT="${APT_FAST_TIMEOUT-${TMP_RANDOM}}" TMP_APT_FAST_TIMEOUT="${APT_FAST_TIMEOUT-${TMP_RANDOM}}"
TMP_APT_FAST_APT_AUTH="${APT_FAST_APT_AUTH-${TMP_RANDOM}}"
TMP_VERBOSE_OUTPUT="${VERBOSE_OUTPUT-${TMP_RANDOM}}" TMP_VERBOSE_OUTPUT="${VERBOSE_OUTPUT-${TMP_RANDOM}}"
TMP_ftp_proxy="${ftp_proxy-${TMP_RANDOM}}" TMP_ftp_proxy="${ftp_proxy-${TMP_RANDOM}}"
TMP_http_proxy="${http_proxy-${TMP_RANDOM}}" TMP_http_proxy="${http_proxy-${TMP_RANDOM}}"
@ -85,7 +89,7 @@ TMP_https_proxy="${https_proxy-${TMP_RANDOM}}"
# Check for proper privileges. # Check for proper privileges.
# Call explicitly with environment variables to get them into root conext. # Call explicitly with environment variables to get them into root conext.
if [ "$root" = 1 ] && [ "$UID" != 0 ]; then if [ "$root" -ne 0 ] && [ "$UID" != 0 ]; then
exec sudo DEBUG="$DEBUG" \ exec sudo DEBUG="$DEBUG" \
LCK_FILE="$TMP_LCK_FILE" \ LCK_FILE="$TMP_LCK_FILE" \
DOWNLOADBEFORE="$TMP_DOWNLOADBEFORE" \ DOWNLOADBEFORE="$TMP_DOWNLOADBEFORE" \
@ -93,7 +97,6 @@ if [ "$root" = 1 ] && [ "$UID" != 0 ]; then
APTCACHE="$TMP_APTCACHE" \ APTCACHE="$TMP_APTCACHE" \
DLDIR="$TMP_DLDIR" \ DLDIR="$TMP_DLDIR" \
DLLIST="$TMP_DLLIST" \ DLLIST="$TMP_DLLIST" \
LISTDIR="$TMP_LISTDIR" \
_MAXNUM="$TMP__MAXNUM" \ _MAXNUM="$TMP__MAXNUM" \
_MAXCONPERSRV="$TMP__MAXCONPERSRV" \ _MAXCONPERSRV="$TMP__MAXCONPERSRV" \
_SPLITCON="$TMP__SPLITCON" \ _SPLITCON="$TMP__SPLITCON" \
@ -101,6 +104,7 @@ if [ "$root" = 1 ] && [ "$UID" != 0 ]; then
_PIECEALGO="$TMP__PIECEALGO" \ _PIECEALGO="$TMP__PIECEALGO" \
aptfast_prefix="$TMP_aptfast_prefix" \ aptfast_prefix="$TMP_aptfast_prefix" \
APT_FAST_TIMEOUT="$TMP_APT_FAST_TIMEOUT" \ APT_FAST_TIMEOUT="$TMP_APT_FAST_TIMEOUT" \
APT_FAST_APT_AUTH="$TMP_APT_FAST_APT_AUTH" \
VERBOSE_OUTPUT="$TMP_VERBOSE_OUTPUT" \ VERBOSE_OUTPUT="$TMP_VERBOSE_OUTPUT" \
ftp_proxy="$TMP_ftp_proxy" \ ftp_proxy="$TMP_ftp_proxy" \
http_proxy="$TMP_http_proxy" \ http_proxy="$TMP_http_proxy" \
@ -108,7 +112,6 @@ if [ "$root" = 1 ] && [ "$UID" != 0 ]; then
"$0" "$@" "$0" "$@"
fi fi
# Define lockfile. # Define lockfile.
# Use /tmp as directory because everybody (not only root) has to have write # Use /tmp as directory because everybody (not only root) has to have write
# permissions. # permissions.
@ -123,27 +126,39 @@ LCK_FD=99
# Set default package manager, APT cache, temporary download dir, # Set default package manager, APT cache, temporary download dir,
# temporary download list file, and maximal parallel downloads # temporary download list file, and maximal parallel downloads
_APTMGR=apt-get _APTMGR=apt-get
eval "$(apt-config shell APTCACHE Dir::Cache::archives/d)" eval "$(apt-config shell APTCACHE Dir::Cache::archives/d)"
# Check if APT config option Dir::Cache::archives::apt-fast-partial is set. # Check if APT config option Dir::Cache::archives::apt-fast-partial is set.
eval "$(apt-config shell apt_fast_partial Dir::Cache::archives::apt-fast-partial/d)" eval "$(apt-config shell apt_fast_partial Dir::Cache::archives::apt-fast-partial/d)"
if [ -z "$apt_fast_partial" ]; then if [ -z "$apt_fast_partial" ]; then
eval "$(apt-config -o Dir::Cache::archives::apt-fast-partial=apt-fast shell DLDIR Dir::Cache::archives::apt-fast-partial/d)" DLDIR="$(realpath "${APTCACHE}/../apt-fast")"
else else
eval "$(apt-config shell DLDIR Dir::Cache::archives::apt-fast-partial/d)" DLDIR="${apt_fast_partial}"
fi fi
# Currently not needed.
eval "$(apt-config shell LISTDIR Dir::State::lists/d)" # Check for apt auth files
eval "$(apt-config shell NETRC Dir::Etc::netrc/f)"
eval "$(apt-config shell NETRCDIR Dir::Etc::netrcparts/d)"
APTAUTHFILES=()
if [ -f "$NETRC" ]; then
APTAUTHFILES=("$NETRC")
fi
APTAUTHFILES+=("$NETRCDIR"*)
if [ "$IS_ACE_ENV" != "" ];then if [ "$IS_ACE_ENV" != "" ];then
DLLIST="/tmp/apt-fast-in-container.list" DLLIST="/tmp/apt-fast-in-container.list"
else else
DLLIST="/tmp/apt-fast.list" DLLIST="/tmp/apt-fast.list"
fi fi
_MAXNUM=5 _MAXNUM=5
_MAXCONPERSRV=10 _MAXCONPERSRV=10
_SPLITCON=8 _SPLITCON=8
_MINSPLITSZ="1M" _MINSPLITSZ="1M"
_PIECEALGO="default" _PIECEALGO="default"
MIRRORS=()
# Prefix in front of apt-fast output: # Prefix in front of apt-fast output:
aptfast_prefix= aptfast_prefix=
@ -162,6 +177,9 @@ APT_FAST_TIMEOUT=60
# Ask for download confirmation if unset # Ask for download confirmation if unset
DOWNLOADBEFORE= DOWNLOADBEFORE=
# Enable APT authentication support
APT_FAST_APT_AUTH=1
# Formatted package list in download confirmation if unset # Formatted package list in download confirmation if unset
VERBOSE_OUTPUT= VERBOSE_OUTPUT=
@ -188,7 +206,6 @@ https_proxy=
[ "$TMP_APTCACHE" = "$TMP_RANDOM" ] || APTCACHE="$TMP_APTCACHE" [ "$TMP_APTCACHE" = "$TMP_RANDOM" ] || APTCACHE="$TMP_APTCACHE"
[ "$TMP_DLDIR" = "$TMP_RANDOM" ] || DLDIR="$TMP_DLDIR" [ "$TMP_DLDIR" = "$TMP_RANDOM" ] || DLDIR="$TMP_DLDIR"
[ "$TMP_DLLIST" = "$TMP_RANDOM" ] || DLLIST="$TMP_DLLIST" [ "$TMP_DLLIST" = "$TMP_RANDOM" ] || DLLIST="$TMP_DLLIST"
[ "$TMP_LISTDIR" = "$TMP_RANDOM" ] || LISTDIR="$TMP_LISTDIR"
[ "$TMP__MAXNUM" = "$TMP_RANDOM" ] || _MAXNUM="$TMP__MAXNUM" [ "$TMP__MAXNUM" = "$TMP_RANDOM" ] || _MAXNUM="$TMP__MAXNUM"
[ "$TMP__MAXCONPERSRV" = "$TMP_RANDOM" ] || _MAXCONPERSRV="$TMP__MAXCONPERSRV" [ "$TMP__MAXCONPERSRV" = "$TMP_RANDOM" ] || _MAXCONPERSRV="$TMP__MAXCONPERSRV"
[ "$TMP__SPLITCON" = "$TMP_RANDOM" ] || _SPLITCON="$TMP__SPLITCON" [ "$TMP__SPLITCON" = "$TMP_RANDOM" ] || _SPLITCON="$TMP__SPLITCON"
@ -196,6 +213,7 @@ https_proxy=
[ "$TMP__PIECEALGO" = "$TMP_RANDOM" ] || _PIECEALGO="$TMP__PIECEALGO" [ "$TMP__PIECEALGO" = "$TMP_RANDOM" ] || _PIECEALGO="$TMP__PIECEALGO"
[ "$TMP_aptfast_prefix" = "$TMP_RANDOM" ] || aptfast_prefix="$TMP_aptfast_prefix" [ "$TMP_aptfast_prefix" = "$TMP_RANDOM" ] || aptfast_prefix="$TMP_aptfast_prefix"
[ "$TMP_APT_FAST_TIMEOUT" = "$TMP_RANDOM" ] || APT_FAST_TIMEOUT="$TMP_APT_FAST_TIMEOUT" [ "$TMP_APT_FAST_TIMEOUT" = "$TMP_RANDOM" ] || APT_FAST_TIMEOUT="$TMP_APT_FAST_TIMEOUT"
[ "$TMP_APT_FAST_APT_AUTH" = "$TMP_RANDOM" ] || APT_FAST_APT_AUTH="$TMP_APT_FAST_APT_AUTH"
[ "$TMP_VERBOSE_OUTPUT" = "$TMP_RANDOM" ] || VERBOSE_OUTPUT="$TMP_VERBOSE_OUTPUT" [ "$TMP_VERBOSE_OUTPUT" = "$TMP_RANDOM" ] || VERBOSE_OUTPUT="$TMP_VERBOSE_OUTPUT"
[ "$TMP_ftp_proxy" = "$TMP_RANDOM" ] || ftp_proxy="$TMP_ftp_proxy" [ "$TMP_ftp_proxy" = "$TMP_RANDOM" ] || ftp_proxy="$TMP_ftp_proxy"
[ "$TMP_http_proxy" = "$TMP_RANDOM" ] || http_proxy="$TMP_http_proxy" [ "$TMP_http_proxy" = "$TMP_RANDOM" ] || http_proxy="$TMP_http_proxy"
@ -279,7 +297,8 @@ cleanup_dllist()
cleanup_aptfast() cleanup_aptfast()
{ {
[ "$CLEANUP_STATE" -eq 0 ] && CLEANUP_STATE=$? local last_exit_code=$?
[ "$CLEANUP_STATE" -eq 0 ] && CLEANUP_STATE=$last_exit_code
cleanup_dllist cleanup_dllist
_remove_lock _remove_lock
} }
@ -308,7 +327,7 @@ get_mirrors(){
for mirror in "${mirrors[@]}"; do for mirror in "${mirrors[@]}"; do
# Real expension. # Real expension.
if [[ "$1" == "$mirror"* ]]; then if [[ "$1" == "$mirror"* ]]; then
filepath=${1#${mirror}} filepath="${1#"${mirror}"}"
# Build list for aria download list. # Build list for aria download list.
list="${mirrors[*]:1}" list="${mirrors[*]:1}"
echo -e "${list// /${filepath}\\t}$filepath\n" echo -e "${list// /${filepath}\\t}$filepath\n"
@ -319,67 +338,128 @@ get_mirrors(){
# No other mirrors found. # No other mirrors found.
echo "$1" echo "$1"
} }
##########SPARK ADJUST: END ##########SPARK ADJUST: END
AUTH_INFO_PARSED=()
# Parse apt authentication files.
# Undefined behavior on whitespaces in host, username or password.
prepare_auth(){
if [ "$APT_FAST_APT_AUTH" -eq 0 ]; then
return
fi
for auth_file in "${APTAUTHFILES[@]}"; do
# auth files have netrc syntax, possible multiline entries starting with "machine"
auth_info="$(tr '\n' ' ' < "$auth_file" | sed 's/\(\<machine\>\)/\n\1/g' | sed '1d')"
while IFS= read -r auth; do
machine="$(echo "$auth" | sed 's/.*\<machine\>[ \t]\+\([^ \t]\+\).*/\1/')"
login="$(echo "$auth" | sed 's/.*\<login\>[ \t]\+\([^ \t]\+\).*/\1/')"
password="$(echo "$auth" | sed 's/.*\<password\>[ \t]\+\([^ \t]\+\).*/\1/')"
# if machine does not have protocol, try https://
if ! [[ "$machine" =~ ^.*:// ]]; then
machine="https://$machine"
fi
if [ -z "$machine" ] || [ -z "$login" ] || [ -z "$password" ]; then
msg "Could not parse apt authentication (skipping): $auth ($auth_file)" "warning"
continue
fi
# use space separated string to convert back to array later
AUTH_INFO_PARSED+=("$machine $login $password")
done <<< "$auth_info"
done
}
# Gets URI as parameter and tries to add basic http credentials. Will fail on
# credentials that contain characters that need URL-encoding.
get_auth(){
if [ "$APT_FAST_APT_AUTH" -eq 0 ]; then
echo "$1"
return
fi
for auth_info in "${AUTH_INFO_PARSED[@]}"; do
# convert to array, don't escape variable here
auth_info_arr=($auth_info)
machine="${auth_info_arr[0]}"
# takes first match
if [[ "$1" == "$machine"* ]]; then
login="${auth_info_arr[1]}"
password="${auth_info_arr[2]}"
uri="$(echo "$1" | sed "s|^\([^:]\+://\)|\1$login:$password@|")"
echo "$uri"
return
fi
done
echo "$1"
}
# Globals to save package name, version, size and overall size. # Globals to save package name, version, size and overall size.
DOWNLOAD_DISPLAY= DOWNLOAD_DISPLAY=
DOWNLOAD_SIZE=0 DOWNLOAD_SIZE=0
# 获取包的URI
# Get the package URLs. # Get the package URLs.
get_uris(){ get_uris(){
if [ ! -d "$(dirname "$DLLIST")" ] if [ ! -d "$(dirname "$DLLIST")" ]
then then
if ! mkdir -p -- "$(dirname "$DLLIST")" if ! mkdir -p -- "$(dirname "$DLLIST")"
then then
msg "Could not create download file directory." "warning" msg "Could not create download file directory." "warning"
msg "无法创建下载文件夹" "warning" msg "无法创建下载目录" "warning"
exit 1 CLEANUP_STATE=1
exit
fi fi
elif [ -f "$DLLIST" ]; then elif [ -f "$DLLIST" ]; then
if ! rm -f -- "$DLLIST" 2>/dev/null && ! touch -- "$DLLIST" 2>/dev/null if ! rm -f -- "$DLLIST" 2>/dev/null && ! touch -- "$DLLIST" 2>/dev/null
then then
msg "Unable to write to download file. Try restarting with root permissions or run 'aptss clean' first." "warning" msg "Unable to write to download file. Try restarting with root permissions or run 'apt-fast clean' first." "warning"
msg "无法下载文件。尝试使用root权限或者运行 'aptss clean'" "warning" msg "无法下载文件。尝试使用root权限或者运行 'aptss clean'" "warning"
exit 1 CLEANUP_STATE=1
exit
fi fi
fi fi
# Add header to overwrite file. # Add header to overwrite file.
echo "# apt-fast mirror list: $(date)" > "$DLLIST" echo "# apt-fast mirror list: $(date)" > "$DLLIST"
#NOTE: aptitude doesn't have this functionality, so we use apt-get to get # NOTE: "aptitude" doesn't have this functionality
# package URIs. # so we use "${_APTMGR}" to get package URI's
# case "$_APTMGR" in case "$(basename "${_APTMGR}")" in
# apt|apt-get) uri_mgr=$_APTMGR;; 'apt'|'apt-get') uri_mgr="${_APTMGR}";;
# *) uri_mgr=apt-get;; *) uri_mgr='apt-get';;
# esac esac
# NOTE:apt可能出现变动不建议在脚本中使用因此在此统一改用apt-get
uri_mgr=apt-get
uris_full="$("$uri_mgr" "${APT_SCRIPT_WARNING[@]}" -y --print-uris "$@")" uris_full="$("$uri_mgr" "${APT_SCRIPT_WARNING[@]}" -y --print-uris "$@")"
uris_full_ret="$?" CLEANUP_STATE="$?"
if [ "$uris_full_ret" -ne 0 ] if [ "$CLEANUP_STATE" -ne 0 ]
then then
msg "Package manager quit with exit code.Here is the log" "warning" msg "Package manager quit with exit code.Here is the log" "warning"
msg "包管理器以错误代码退出.日志如下" "warning" msg "包管理器以错误代码退出.日志如下" "warning"
msg "${uris_full}" msg "${uris_full}"
exit "$uris_full_ret" exit"$CLEANUP_STATE"
fi fi
while read -r pkg_uri_info prepare_auth
do local tmpdir=$(mktemp -d) || {
[ -z "$pkg_uri_info" ] && continue msg "Failed to create tmp dir" "warning"
## --print-uris format is: msg "无法创建临时目录" "warning"
# 'fileurl' filename filesize checksum_hint:filechecksum exit 1
uri="$(echo "$pkg_uri_info" | cut -d' ' -f1 | tr -d "'")" }
filename="$(echo "$pkg_uri_info" | cut -d' ' -f2)" ## --print-uris format is:
filesize="$(echo "$pkg_uri_info" | cut -d' ' -f3)" # 'fileurl' filename filesize checksum_hint:filechecksum
checksum_string="$(echo "$pkg_uri_info" | cut -d' ' -f4)" process_package() {
hash_algo="$(echo "$checksum_string" | cut -d':' -f1)" local pkg_uri_info="$@"
checksum="$(echo "$checksum_string" | cut -d':' -f2)"
local display_line="" # 添加局部变量并初始化为空
IFS=' ' read -r uri filename filesize checksum_string _ <<<"$pkg_uri_info"
[ -z "$uri" ] && continue
uri="$(get_auth "${uri//"'"/}")"
IFS=':' read -r hash_algo checksum _ <<<"$checksum_string"
filename_decoded="$(urldecode "$filename")" filename_decoded="$(urldecode "$filename")"
DOWNLOAD_DISPLAY="${DOWNLOAD_DISPLAY}$(echo "$filename_decoded" | cut -d'_' -f1)" IFS='_' read -r pkg_name_decoded pkg_version_decoded _ <<<"$filename_decoded"
DOWNLOAD_DISPLAY="${DOWNLOAD_DISPLAY} $(echo "$filename_decoded" | cut -d'_' -f2)"
DOWNLOAD_DISPLAY="${DOWNLOAD_DISPLAY} $(echo "$filesize" | numfmt --to=iec-i --suffix=B)\n"
DOWNLOAD_SIZE=$((DOWNLOAD_SIZE + filesize))
display_line="${display_line}$pkg_name_decoded $pkg_version_decoded"
display_line="${display_line} $(echo "$filesize" | numfmt --to=iec-i --suffix=B)\n"
## whole uri comes encoded (urlencoded). Filename must NOT be decoded because ## whole uri comes encoded (urlencoded). Filename must NOT be decoded because
# plain aptitude do not decode it when download and install it. Therefore, we # plain aptitude do not decode it when download and install it. Therefore, we
@ -397,40 +477,44 @@ uri_mgr=apt-get
*) hash_algo= *) hash_algo=
esac esac
# Using apt-cache show package=version to ensure recover single and
# Using apt-cache show package=version to ensure recover single and
# correct package version. # correct package version.
# Warning: assuming that package naming uses '_' as field separator. # Warning: assuming that package naming uses '_' as field separator.
# Therefore, this code expects package-name_version_arch.deb Otherways # Therefore, this code expects package-name_version_arch.deb Otherwise
# below code will fail resoundingly # below code will fail resoundingly
if [ -z "$hash_algo" ]; then if [ -z "$hash_algo" ]; then
pkg_name="$(echo "$filename" | cut -d'_' -f1)" IFS='_' read -r pkg_name _ <<<"$filename"
pkg_version="$(echo "$filename" | cut -d'_' -f2)" pkg_version="$pkg_version_decoded"
pkg_version="$(urldecode "$pkg_version")" # Transform multi-line field output from apt-cache to single line and sort checksums, strongest first
package_info="$(apt-cache show "$pkg_name=$pkg_version")" package_info="$(apt-cache show "$pkg_name=$pkg_version" | sed ':r;$!{N;br};s/\n / /g' | sort -r)"
patch_checksum= while IFS=': ' read -r field checksum _
if [ -n "$SHA512_SUPPORTED" ]; then do
patch_checksum="$(echo "$package_info" | grep SHA512 | head -n 1)" case "$field" in
[ -n "$patch_checksum" ] && hash_algo="sha-512" SHA512)
fi [ -n "$SHA512_SUPPORTED" ] || continue
if [ -z "$patch_checksum" ] && [ -n "$SHA256_SUPPORTED" ]; then hash_algo="sha-512"
patch_checksum="$(echo "$package_info" | grep SHA256 | head -n 1)" break ;;
[ -n "$patch_checksum" ] && hash_algo="sha-256" SHA256)
fi [ -n "$SHA256_SUPPORTED" ] || continue
if [ -z "$patch_checksum" ] && [ -n "$SHA1_SUPPORTED" ]; then hash_algo="sha-256"
patch_checksum="$(echo "$package_info" | grep SHA1 | head -n 1)" break ;;
[ -n "$patch_checksum" ] && hash_algo="sha-1" SHA1)
fi [ -n "$SHA1_SUPPORTED" ] || continue
if [ -z "$patch_checksum" ] && [ -n "$MD5sum_SUPPORTED" ]; then hash_algo="sha-1"
patch_checksum="$(echo "$package_info" | grep MD5sum | head -n 1)" break ;;
[ -n "$patch_checksum" ] && hash_algo="md5" MD5sum)
fi [ -n "$MD5sum_SUPPORTED" ] || continue
hash_algo="md5"
break ;;
esac
done <<<"$package_info"
if [ -n "$patch_checksum" ]; then if [ -z "$hash_algo" ]; then
checksum="$(echo "$patch_checksum" | cut -d' ' -f2)" checksum=
else
msg "Couldn't get supported checksum for $pkg_name ($pkg_version)." "warning" msg "Couldn't get supported checksum for $pkg_name ($pkg_version)." "warning"
msg "无法获得 $pkg_name ($pkg_version) 的受支持的散列验证值" "warning" msg "无法获得 $pkg_name ($pkg_version) 版本受到支持的散列验证值" "warning"
REMOVE_WORKING_MESSAGE= REMOVE_WORKING_MESSAGE=
fi fi
fi fi
@ -438,21 +522,64 @@ uri_mgr=apt-get
hash_algo= hash_algo=
fi fi
{
get_mirrors "$uri"
#echo " dir=$DLDIR"
if [ -n "$hash_algo" ]; then
echo " checksum=$hash_algo=$checksum"
fi
echo " out=$filename"
} >> "$DLLIST"
done <<<"$(echo "$uris_full" | grep -E "^'(http(s|)|(s|)ftp)://")"
# 使用文件锁安全写入下载列表
(
flock -x 200 # 获取排他锁
{
get_mirrors "$uri"
[ -n "$hash_algo" ] && echo " checksum=$hash_algo=$checksum"
echo " out=$filename"
} >> "$DLLIST"
) 200>>"$DLLIST" # 使用文件描述符200关联锁文件
# 将显示信息和文件大小存入临时文件
echo "$display_line" >> "$tmpdir/display"
echo "$filesize" >> "$tmpdir/sizes"
}
# 主并行处理逻辑(新增线程控制)
mapfile -t pkg_uri_list < <(echo "$uris_full" | grep -E "^'(http(s|)|(s|)ftp)://")
total_pkgs=${#pkg_uri_list[@]}
threads=${THREADS:-4} # 默认4线程
per_thread=$(( (total_pkgs + threads - 1) / threads )) # 向上取整
# 分割任务到不同线程
for ((i=0; i<threads; i++)); do
start=$((i * per_thread))
end=$((start + per_thread -1))
[ $end -ge $total_pkgs ] && end=$((total_pkgs -1))
# 启动后台线程处理任务块
(
for ((j=start; j<=end; j++)); do
[ -z "${pkg_uri_list[j]}" ] && continue
process_package "${pkg_uri_list[j]}"
done
) &
done
# 等待所有后台任务完成
wait
# 合并显示信息
if [ -f "$tmpdir/display" ]; then
DOWNLOAD_DISPLAY+="\n$(cat "$tmpdir/display")"
fi
# 计算总下载大小
if [ -f "$tmpdir/sizes" ]; then
DOWNLOAD_SIZE=$(awk '{sum+=$1} END{print sum}' "$tmpdir/sizes")
fi
# 清理临时目录
rm -rf "$tmpdir"
#cat "$DLLIST" #cat "$DLLIST"
#LCK_RM
#exit #exit
} }
display_downloadfile(){ display_downloadfile(){
if [ -n "$VERBOSE_OUTPUT" ]; then if [ -n "$VERBOSE_OUTPUT" ]; then
cat "$DLLIST" cat "$DLLIST"
@ -460,11 +587,8 @@ display_downloadfile(){
DISPLAY_SORT_OPTIONS=(-k 1,1) DISPLAY_SORT_OPTIONS=(-k 1,1)
# Sort output after package download size (decreasing): # Sort output after package download size (decreasing):
#DISPLAY_SORT_OPTIONS=(-k 3,3 -hr) #DISPLAY_SORT_OPTIONS=(-k 3,3 -hr)
while read -r line; do while IFS=' ' read -r pkg ver size _; do
[ -z "$line" ] && continue [ -z "$pkg" ] && continue
pkg="$(echo "$line" | cut -d' ' -f1)"
ver="$(echo "$line" | cut -d' ' -f2)"
size="$(echo "$line" | cut -d' ' -f3)"
printf '%s%-40s %-20s %10s\n' "$aptfast_prefix" "$pkg" "$ver" "$size" printf '%s%-40s %-20s %10s\n' "$aptfast_prefix" "$pkg" "$ver" "$size"
done <<<"$(echo -e "$DOWNLOAD_DISPLAY" | sort "${DISPLAY_SORT_OPTIONS[@]}")" done <<<"$(echo -e "$DOWNLOAD_DISPLAY" | sort "${DISPLAY_SORT_OPTIONS[@]}")"
fi fi
@ -472,6 +596,7 @@ display_downloadfile(){
msg "下载大小: $(echo "$DOWNLOAD_SIZE" | numfmt --to=iec-i --suffix=B)" "normal" msg "下载大小: $(echo "$DOWNLOAD_SIZE" | numfmt --to=iec-i --suffix=B)" "normal"
} }
# Create and insert a PID number to lockfile. # Create and insert a PID number to lockfile.
_create_lock _create_lock
@ -481,19 +606,21 @@ CMD="$(echo "$_DOWNLOADER" | sed 's/^\s*\([^ ]\+\).*$/\1/')"
if [ ! "$(command -v "$CMD")" ]; then if [ ! "$(command -v "$CMD")" ]; then
msg "Command not found: $CMD" "normal" "err" msg "Command not found: $CMD" "normal" "err"
msg "You must configure $CONFFILE to use aria2c or another supported download manager" "normal" "err" msg "You must configure $CONFFILE to use aria2c or another supported download manager" "normal" "err"
exit 1 CLEANUP_STATE=1
exit
fi fi
# Make sure package manager is available. # Make sure package manager is available.
if [ ! "$(command -v "$_APTMGR")" ]; then if [ ! "$(command -v "$_APTMGR")" ]; then
msg "\`$_APTMGR\` command not available." "warning" msg "\`$_APTMGR\` command not available." "warning"
msg "You must configure $CONFFILE to use either apt-get or aptitude." "normal" "err" msg "You must configure $CONFFILE to use either apt-get or aptitude." "normal" "err"
exit 1 CLEANUP_STATE=1
exit
fi fi
# Disable script warning if apt is used. # Disable script warning if apt is used.
APT_SCRIPT_WARNING=() APT_SCRIPT_WARNING=()
if [ "$_APTMGR" == "apt" ]; then if [ "$(basename "${_APTMGR}")" == 'apt' ]; then
APT_SCRIPT_WARNING=(-o "Apt::Cmd::Disable-Script-Warning=true") APT_SCRIPT_WARNING=(-o "Apt::Cmd::Disable-Script-Warning=true")
fi fi
@ -540,6 +667,8 @@ while true; do
d) d)
DOWNLOAD_ONLY=true DOWNLOAD_ONLY=true
;; ;;
*)
;;
esac esac
done done
((OPTIND++)) ((OPTIND++))
@ -582,7 +711,7 @@ if [ "$option" == "install" ]; then
msg "Do you want to download the packages? [Y/n] " "question" msg "Do you want to download the packages? [Y/n] " "question"
while ((!updsys)); do while ((!updsys)); do
read -r -sn1 -t "$APT_FAST_TIMEOUT" answer || { msg; msg "Timed out." "warning"; exit 1; } read -r -sn1 -t "$APT_FAST_TIMEOUT" answer || { msg; msg "Timed out." "warning"; CLEANUP_STATE=1; exit; }
case "$answer" in case "$answer" in
[JjYy]) result=1; updsys=1 ;; [JjYy]) result=1; updsys=1 ;;
[Nn]) result=0; updsys=1 ;; [Nn]) result=0; updsys=1 ;;
@ -604,7 +733,7 @@ if [ "$option" == "install" ]; then
mkdir -p -- "$DLDIR" mkdir -p -- "$DLDIR"
fi fi
cd "$DLDIR" &>/dev/null || exit 1 cd "$DLDIR" &>/dev/null || { msg; msg "Not able to change into download directory." "warning"; CLEANUP_STATE=1; exit; }
eval "${_DOWNLOADER}" # execute downloadhelper command eval "${_DOWNLOADER}" # execute downloadhelper command
if [ "$(find "$DLDIR" -printf . | wc -c)" -gt 1 ]; then if [ "$(find "$DLDIR" -printf . | wc -c)" -gt 1 ]; then
@ -624,22 +753,26 @@ if [ "$option" == "install" ]; then
cd - &>/dev/null || msg "Failed to change back directory" "warning" cd - &>/dev/null || msg "Failed to change back directory" "warning"
fi fi
else else
exit 1 CLEANUP_STATE=1
exit
fi fi
else else
[ -t 1 ] && tput el [ -t 1 ] && tput el
fi fi
if [ -z "$DOWNLOAD_ONLY" ] || [ "$_APTMGR" == "aptitude" ]; then # different problem resolving for aptitude
if [ -z "$DOWNLOAD_ONLY" ] || [ "$(basename "${_APTMGR}")" == 'aptitude' ]; then
"${_APTMGR}" "${APT_SCRIPT_WARNING[@]}" "$@" "${_APTMGR}" "${APT_SCRIPT_WARNING[@]}" "$@"
fi fi
elif [ "$option" == "clean" ]; then elif [ "$option" == "clean" ]; then
"${_APTMGR}" "${APT_SCRIPT_WARNING[@]}" "$@" && { "${_APTMGR}" "${APT_SCRIPT_WARNING[@]}" "$@" && {
find "$DLDIR" -maxdepth 1 -type f -delete if [ -d "$DLDIR" ]; then
CLEANUP_STATE="$?" find "$DLDIR" -maxdepth 1 -type f -delete
[ -f "$DLLIST" ] && rm -f -- "$DLLIST"* || true CLEANUP_STATE="$?"
[ -f "$DLLIST" ] && rm -f -- "$DLLIST"* || true
fi
} }
elif [ "$option" == "download" ]; then elif [ "$option" == "download" ]; then
@ -657,7 +790,8 @@ elif [ "$option" == "download" ]; then
eval "${_DOWNLOADER}" eval "${_DOWNLOADER}"
fi fi
if [ "$_APTMGR" == "aptitude" ]; then # different problem resolving for aptitude
if [ "$(basename "${_APTMGR}")" == 'aptitude' ]; then
"${_APTMGR}" "$@" "${_APTMGR}" "$@"
fi fi