feat: add leaf upgrade old new for upgrading

This commit is contained in:
2025-12-29 17:40:55 -05:00
parent d0600c4b07
commit 24c9bc3758

168
leaf
View File

@@ -75,12 +75,15 @@ main() {
pkgdir="${srcdir}"/__pkgdir__
if [[ x"$1" != x"dirct-install" ]]; then
rm -rf "${srcdir}" && install -dm755 "${srcdir}" && cd "${srcdir}"
mkdir -pv ${TMPDIR}
mkdir -pv ${HOME}
fi
leaf_${1}_package
done
;;
upgrade)
leaf_check_permission
[ $# -eq 3 ] || leaf_error "Usage: leaf upgrade <oldpkg> <newpkg>"
leaf_upgrade_package "$2" "$3"
;;
search)
leaf_search_package "${@:2}"
;;
@@ -246,22 +249,39 @@ leaf_merge_package() {
_group=$(stat -c %g ."${_item}")
install -d -m ${_mode} -o ${_owner} -g ${_group} "${_item}"
done
cat "${_trace_dir}"/FILES | while read -r _item; do
cat "${_trace_dir}"/FILES | while read -r _item; do
_mode=$(stat -c %a ."${_item}")
_owner=$(stat -c %u ."${_item}")
_group=$(stat -c %g ."${_item}")
if [[ "${_item}" == /etc/* && -e "${_item}" ]]; then
_item_conflict="$(dirname "${_item}")/._$(basename "${_item}").conflict_${PKG_NAME}_${_time}"
if (diff ."${_item}" "${_item}" > /dev/null); then
install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item}"
else
install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item_conflict}"
leaf_record_message "Config file confliction on ${_item}, the package provided version is installed as ${_item_conflict}."
fi
else
# Fast path: non-/etc, or /etc path that doesn't exist yet -> install/overwrite directly
if [[ "${_item}" != /etc/* || ! -e "${_item}" ]]; then
install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item}"
continue
fi
# Now: /etc/* and already exists on the system.
# Upgrade optimization: if OLD_TRACE_DIR is set and the current /etc file matches old baseline,
# then user didn't modify it -> overwrite with new version directly.
if [[ -n "${OLD_TRACE_DIR:-}" ]] \
&& leaf_conffile_is_unmodified "${_item}" "${OLD_TRACE_DIR}"; then
install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item}"
continue
fi
# Otherwise, fall back to conflict logic:
# - if content is identical -> overwrite (keeps permissions/ownership from pkg)
# - else -> write conflict file and keep user's current file
_item_conflict="$(dirname "${_item}")/._$(basename "${_item}").conflict_${PKG_NAME}_${_time}"
if diff -q ."${_item}" "${_item}" >/dev/null 2>&1; then
install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item}"
else
install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item_conflict}"
leaf_record_message "Config file confliction on ${_item}, the package provided version is installed as ${_item_conflict}."
fi
done
cat "${_trace_dir}"/LINKS | while read -r _item; do
cp -dp ."${_item}" "${_item}"
done
@@ -302,6 +322,7 @@ Option: prepare prepare packages but do not build
forece-install install packages even if test failed
dirct-install install packages directly from previous build
remove remove packages
upgrade upgrade oldpkg to newpkg (leaf upgrade old new)
clean clean all source folders
list list installed packages
search search packages by keyword
@@ -629,6 +650,9 @@ leaf_prepare_package() {
}
leaf_build_package() {
mkdir -pv ${TMPDIR}
mkdir -pv ${HOME}
leaf_prepare_package
leaf_phase_must "Building" src_build "Build failed."
@@ -713,6 +737,117 @@ leaf_force-install_package(){
leaf_install_package
}
leaf_upgrade_package() {
local old_query="$1" new_query="$2"
local old_prefix old_name new_prefix new_name
local new_srcdir new_pkgdir
local old_trace_dir new_trace_dir
local skipfile
# -------- resolve OLD (installed) --------
leaf_find_remove_pkgbuild "${old_query}"
old_prefix="${PKG_PREFIX}"
old_name="${PKG_NAME}"
old_trace_dir="${TRACE_DIR}/${old_prefix}/${old_name}"
OLD_TRACE_DIR="${old_trace_dir}"
# -------- resolve NEW (available) --------
leaf_find_pkgbuild "${new_query}"
new_prefix="${PKG_PREFIX}"
new_name="${PKG_NAME}"
# sanity
if [[ "${old_prefix}/${old_name}" == "${new_prefix}/${new_name}" ]]; then
leaf_error "upgrade: old and new refer to the same package: ${old_prefix}/${old_name}"
fi
# =========================================================
# 1) BUILD NEW (no ROOT touch)
# =========================================================
PKG_PREFIX="${new_prefix}"
PKG_NAME="${new_name}"
leaf_reset_state
leaf_message_init
source "${PKGBUILD_DIR}/${PKG_PREFIX}/${PKG_NAME}.PKGBUILD"
leaf_parse_options
srcdir="${BUILD_DIR}/${PKG_PREFIX}/${PKG_NAME}"
TMPDIR="${srcdir}/.leaf-tmp"
HOME="${srcdir}/.leaf-home"
export TMPDIR HOME
pkgdir="${srcdir}/__pkgdir__"
rm -rf -- "${srcdir}" && install -dm755 -- "${srcdir}" && cd "${srcdir}"
mkdir -pv -- "${TMPDIR}" "${HOME}"
leaf_build_package
new_srcdir="${srcdir}"
new_pkgdir="${pkgdir}"
# =========================================================
# 2) INSTALL NEW (touch ROOT)
# Use dirct-install path so we don't rebuild.
# =========================================================
PKG_PREFIX="${new_prefix}"
PKG_NAME="${new_name}"
leaf_reset_state
leaf_message_init
source "${PKGBUILD_DIR}/${PKG_PREFIX}/${PKG_NAME}.PKGBUILD"
leaf_parse_options
srcdir="${new_srcdir}"
pkgdir="${new_pkgdir}"
TMPDIR="${srcdir}/.leaf-tmp"
HOME="${srcdir}/.leaf-home"
export TMPDIR HOME
[ -d "${pkgdir}" ] || leaf_error "upgrade: built pkgdir missing: ${pkgdir}"
cd "${srcdir}" || leaf_error "upgrade: cannot enter build dir: ${srcdir}"
leaf_dirct-install_package
# new trace dir now exists (generated by leaf_dirct-install_package -> leaf_trace_package)
new_trace_dir="${TRACE_DIR}/${new_prefix}/${new_name}"
[ -d "${new_trace_dir}" ] || leaf_error "upgrade: new trace dir missing: ${new_trace_dir}"
# =========================================================
# 3) REMOVE OLD, but SKIP paths owned by NEW
# =========================================================
skipfile="$(mktemp "${TEMP_DIR}/leaf-upgrade-skip.XXXXXX")" || leaf_error "mktemp failed"
cat "${new_trace_dir}/FILES" "${new_trace_dir}/LINKS" "${new_trace_dir}/DIRS" > "${skipfile}" || {
rm -f -- "${skipfile}"
leaf_error "upgrade: cannot create skiplist"
}
PKG_PREFIX="${old_prefix}"
PKG_NAME="${old_name}"
leaf_reset_state
leaf_message_init
# old remove sources PKGBUILD from TRACE (best effort)
source "${old_trace_dir}/PKGBUILD" 2>/dev/null || true
export LEAF_REMOVE_SKIPLIST="${skipfile}"
leaf_remove_package
unset LEAF_REMOVE_SKIPLIST
rm -f -- "${skipfile}"
echo -e "${GREEN_COLOR}* Upgraded ${old_prefix}/${old_name} -> ${new_prefix}/${new_name}${CLEAR_COLOR}\n"
}
leaf_in_skiplist() {
# usage: leaf_in_skiplist <abs_path>
# return 0 if path in LEAF_REMOVE_SKIPLIST file
local p="$1"
[ -n "${LEAF_REMOVE_SKIPLIST:-}" ] || return 1
[ -r "${LEAF_REMOVE_SKIPLIST}" ] || return 1
grep -Fxq -- "$p" "${LEAF_REMOVE_SKIPLIST}" 2>/dev/null
}
leaf_remove_package() {
[ -n "$(grep "${PKG_PREFIX}/${PKG_NAME}" ${INSTALLED_PACKAGES})" ] || {
leaf_error "Package ${PKG_PREFIX}/${PKG_NAME} is NOT installed"
@@ -730,6 +865,9 @@ leaf_remove_package() {
# FILES
while read -r _file; do
if leaf_in_skiplist "${_file}"; then
continue
fi
if [[ "${_file}" == /etc/* && -e "${_file}" ]]; then
if [ "${_has_conffiles}" -eq 1 ]; then
if leaf_conffile_is_unmodified "${_file}" "${_trace_dir}"; then
@@ -760,6 +898,9 @@ leaf_remove_package() {
# LINKS
while read -r _link; do
if leaf_in_skiplist "${_link}"; then
continue
fi
if [[ "${_link}" == /etc/* && -e "${_link}" ]]; then
if [ "${_has_conffiles}" -eq 1 ]; then
if leaf_conffile_is_unmodified "${_link}" "${_trace_dir}"; then
@@ -776,6 +917,9 @@ leaf_remove_package() {
# DIRS
while read -r _directory; do
if leaf_in_skiplist "${_directory}"; then
continue
fi
if [[ -d "${_directory}" ]]; then
rmdir --ignore-fail-on-non-empty "${_directory}"
fi