Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: apt cache performance #104

Merged
merged 2 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 16 additions & 22 deletions install_and_cache_pkgs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,6 @@ cache_dir="${1}"
# List of the packages to use.
input_packages="${@:3}"

# Trim commas, excess spaces, sort, and version syntax.
stevenh marked this conversation as resolved.
Show resolved Hide resolved
#
# NOTE: Unless specified, all APT package listings of name and version use
# colon delimited and not equals delimited syntax (i.e. <name>[:=]<ver>).
packages="$(get_normalized_package_list "${input_packages}")"

package_count=$(wc -w <<< "${packages}")
log "Clean installing and caching ${package_count} package(s)."

log_empty_line

manifest_main=""
log "Package list:"
for package in ${packages}; do
read package_name package_ver < <(get_package_name_ver "${package}")
manifest_main="${manifest_main}${package_name}=${package_ver},"
log "- ${package_name} (${package_ver})"
done
write_manifest "main" "${manifest_main}" "${cache_dir}/manifest_main.log"

log_empty_line

if ! apt-fast --version > /dev/null 2>&1; then
log "Installing apt-fast for optimized installs..."
# Install apt-fast for optimized installs.
Expand All @@ -59,6 +37,22 @@ fi

log_empty_line

packages="$(get_normalized_package_list "${input_packages}")"
package_count=$(wc -w <<< "${packages}")
log "Clean installing and caching ${package_count} package(s)."

log_empty_line

manifest_main=""
log "Package list:"
for package in ${packages}; do
manifest_main="${manifest_main}${package},"
log "- ${package}"
done
write_manifest "main" "${manifest_main}" "${cache_dir}/manifest_main.log"

log_empty_line

# Strictly contains the requested packages.
manifest_main=""
# Contains all packages including dependencies.
Expand Down
73 changes: 61 additions & 12 deletions lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ function get_installed_packages {
###############################################################################
# Splits a fully action syntax APT package into the name and version.
# Arguments:
# The action syntax colon delimited package pair or just the package name.
# The action syntax equals delimited package pair or just the package name.
# Returns:
# The package name and version pair.
###############################################################################
Expand All @@ -81,7 +81,9 @@ function get_package_name_ver {
IFS="${ORIG_IFS}"
# If version not found in the fully qualified package value.
if test -z "${ver}"; then
ver="$(grep "Version:" <<< "$(apt-cache show ${name})" | awk '{print $2}')"
# This is a fallback and should not be used any more as its slow.
log_err "Unexpected version resolution for package '${name}'..."
stevenh marked this conversation as resolved.
Show resolved Hide resolved
ver="$(apt-cache show ${name} | grep '^Version:' | awk '{print $2}')"
fi
echo "${name}" "${ver}"
}
Expand All @@ -91,16 +93,63 @@ function get_package_name_ver {
# Arguments:
# The comma and/or space delimited list of packages.
# Returns:
# Sorted list of space delimited packages.
# Sorted list of space delimited package name=version pairs.
###############################################################################
function get_normalized_package_list {
# Remove commas, and block scalar folded backslashes.
local stripped=$(echo "${1}" | sed 's/[,\]/ /g')
# Remove extraneous spaces at the middle, beginning, and end.
local trimmed="$(\
echo "${stripped}" \
| sed 's/\s\+/ /g; s/^\s\+//g; s/\s\+$//g')"
echo ${trimmed} | tr ' ' '\n' | sort | tr '\n' ' '
# Remove commas, and block scalar folded backslashes,
# extraneous spaces at the middle, beginning and end
# then sort.
packages=$(echo "${1}" | \
stevenh marked this conversation as resolved.
Show resolved Hide resolved
sed 's/[,\]/ /g; s/\s\+/ /g; s/^\s\+//g; s/\s\+$//g' | \
sort -t' ')

# Validate package names and get versions.
log_err "resolving package versions..."
stevenh marked this conversation as resolved.
Show resolved Hide resolved
data=$(apt-cache --quiet=0 --no-all-versions show ${packages} 2>&1 | \
grep -E '^(Package|Version|N):')
log_err "resolved"

local ORIG_IFS="${IFS}"
IFS=$'\n'
declare -A missing
local package_versions=''
local pkg='' sep=''
stevenh marked this conversation as resolved.
Show resolved Hide resolved
for v in ${data}; do
stevenh marked this conversation as resolved.
Show resolved Hide resolved
local key="${v%%: *}"
local val="${v##*: }"

case $key in
Package)
pkg=$val
;;
Version)
package_versions="${package_versions}${sep}"${pkg}=${val}""
sep=' '
;;
N)
# Warning messages.
case $val in
stevenh marked this conversation as resolved.
Show resolved Hide resolved
'Unable to locate package '*)
pkg="${val#'Unable to locate package '}"
# Avoid duplicate messages.
if [ -z "${missing[$pkg]}" ]; then
pkg="${val#'Unable to locate package '}"
stevenh marked this conversation as resolved.
Show resolved Hide resolved
log "Package '${pkg}' not found." >&2
missing[$pkg]=1
fi
;;
esac
;;
esac
done
IFS="${ORIG_IFS}"

if [ ${#missing[@]} -gt 0 ]; then
echo "aborted"
exit 5
fi

echo "${package_versions}"
}

###############################################################################
Expand All @@ -120,8 +169,8 @@ function get_tar_relpath {
fi
}

function log { echo "$(date +%H:%M:%S)" "${@}"; }
function log_err { >&2 echo "$(date +%H:%M:%S)" "${@}"; }
function log { echo "$(date +%T.%3N)" "${@}"; }
function log_err { >&2 echo "$(date +%T.%3N)" "${@}"; }

function log_empty_line { echo ""; }

Expand Down
21 changes: 1 addition & 20 deletions pre_cache_action.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,35 +53,16 @@ log "done"

log_empty_line

versioned_packages=""
log "Verifying packages..."
for package in ${packages}; do
if test ! "$(apt-cache show ${package})"; then
echo "aborted"
log "Package '${package}' not found." >&2
exit 5
fi
read package_name package_ver < <(get_package_name_ver "${package}")
versioned_packages=""${versioned_packages}" "${package_name}"="${package_ver}""
done
log "done"

log_empty_line

# Abort on any failure at this point.
set -e

log "Creating cache key..."

# TODO Can we prove this will happen again?
normalized_versioned_packages="$(get_normalized_package_list "${versioned_packages}")"
log "- Normalized package list is '${normalized_versioned_packages}'."

# Forces an update in cases where an accidental breaking change was introduced
# and a global cache reset is required.
force_update_inc="1"

value="${normalized_versioned_packages} @ ${version} ${force_update_inc}"
value="${packages} @ ${version} ${force_update_inc}"
log "- Value to hash is '${value}'."

key="$(echo "${value}" | md5sum | cut -f1 -d' ')"
Expand Down