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
+151 -7
View File
@@ -75,12 +75,15 @@ main() {
pkgdir="${srcdir}"/__pkgdir__ pkgdir="${srcdir}"/__pkgdir__
if [[ x"$1" != x"dirct-install" ]]; then if [[ x"$1" != x"dirct-install" ]]; then
rm -rf "${srcdir}" && install -dm755 "${srcdir}" && cd "${srcdir}" rm -rf "${srcdir}" && install -dm755 "${srcdir}" && cd "${srcdir}"
mkdir -pv ${TMPDIR}
mkdir -pv ${HOME}
fi fi
leaf_${1}_package leaf_${1}_package
done done
;; ;;
upgrade)
leaf_check_permission
[ $# -eq 3 ] || leaf_error "Usage: leaf upgrade <oldpkg> <newpkg>"
leaf_upgrade_package "$2" "$3"
;;
search) search)
leaf_search_package "${@:2}" leaf_search_package "${@:2}"
;; ;;
@@ -246,22 +249,39 @@ leaf_merge_package() {
_group=$(stat -c %g ."${_item}") _group=$(stat -c %g ."${_item}")
install -d -m ${_mode} -o ${_owner} -g ${_group} "${_item}" install -d -m ${_mode} -o ${_owner} -g ${_group} "${_item}"
done done
cat "${_trace_dir}"/FILES | while read -r _item; do cat "${_trace_dir}"/FILES | while read -r _item; do
_mode=$(stat -c %a ."${_item}") _mode=$(stat -c %a ."${_item}")
_owner=$(stat -c %u ."${_item}") _owner=$(stat -c %u ."${_item}")
_group=$(stat -c %g ."${_item}") _group=$(stat -c %g ."${_item}")
if [[ "${_item}" == /etc/* && -e "${_item}" ]]; then
# 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}" _item_conflict="$(dirname "${_item}")/._$(basename "${_item}").conflict_${PKG_NAME}_${_time}"
if (diff ."${_item}" "${_item}" > /dev/null); then if diff -q ."${_item}" "${_item}" >/dev/null 2>&1; then
install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item}" install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item}"
else else
install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item_conflict}" 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}." leaf_record_message "Config file confliction on ${_item}, the package provided version is installed as ${_item_conflict}."
fi fi
else
install -D -m ${_mode} -o ${_owner} -g ${_group} ."${_item}" "${_item}"
fi
done done
cat "${_trace_dir}"/LINKS | while read -r _item; do cat "${_trace_dir}"/LINKS | while read -r _item; do
cp -dp ."${_item}" "${_item}" cp -dp ."${_item}" "${_item}"
done done
@@ -302,6 +322,7 @@ Option: prepare prepare packages but do not build
forece-install install packages even if test failed forece-install install packages even if test failed
dirct-install install packages directly from previous build dirct-install install packages directly from previous build
remove remove packages remove remove packages
upgrade upgrade oldpkg to newpkg (leaf upgrade old new)
clean clean all source folders clean clean all source folders
list list installed packages list list installed packages
search search packages by keyword search search packages by keyword
@@ -629,6 +650,9 @@ leaf_prepare_package() {
} }
leaf_build_package() { leaf_build_package() {
mkdir -pv ${TMPDIR}
mkdir -pv ${HOME}
leaf_prepare_package leaf_prepare_package
leaf_phase_must "Building" src_build "Build failed." leaf_phase_must "Building" src_build "Build failed."
@@ -713,6 +737,117 @@ leaf_force-install_package(){
leaf_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() { leaf_remove_package() {
[ -n "$(grep "${PKG_PREFIX}/${PKG_NAME}" ${INSTALLED_PACKAGES})" ] || { [ -n "$(grep "${PKG_PREFIX}/${PKG_NAME}" ${INSTALLED_PACKAGES})" ] || {
leaf_error "Package ${PKG_PREFIX}/${PKG_NAME} is NOT installed" leaf_error "Package ${PKG_PREFIX}/${PKG_NAME} is NOT installed"
@@ -730,6 +865,9 @@ leaf_remove_package() {
# FILES # FILES
while read -r _file; do while read -r _file; do
if leaf_in_skiplist "${_file}"; then
continue
fi
if [[ "${_file}" == /etc/* && -e "${_file}" ]]; then if [[ "${_file}" == /etc/* && -e "${_file}" ]]; then
if [ "${_has_conffiles}" -eq 1 ]; then if [ "${_has_conffiles}" -eq 1 ]; then
if leaf_conffile_is_unmodified "${_file}" "${_trace_dir}"; then if leaf_conffile_is_unmodified "${_file}" "${_trace_dir}"; then
@@ -760,6 +898,9 @@ leaf_remove_package() {
# LINKS # LINKS
while read -r _link; do while read -r _link; do
if leaf_in_skiplist "${_link}"; then
continue
fi
if [[ "${_link}" == /etc/* && -e "${_link}" ]]; then if [[ "${_link}" == /etc/* && -e "${_link}" ]]; then
if [ "${_has_conffiles}" -eq 1 ]; then if [ "${_has_conffiles}" -eq 1 ]; then
if leaf_conffile_is_unmodified "${_link}" "${_trace_dir}"; then if leaf_conffile_is_unmodified "${_link}" "${_trace_dir}"; then
@@ -776,6 +917,9 @@ leaf_remove_package() {
# DIRS # DIRS
while read -r _directory; do while read -r _directory; do
if leaf_in_skiplist "${_directory}"; then
continue
fi
if [[ -d "${_directory}" ]]; then if [[ -d "${_directory}" ]]; then
rmdir --ignore-fail-on-non-empty "${_directory}" rmdir --ignore-fail-on-non-empty "${_directory}"
fi fi