在 Debian 上使用 dpkg-repack 备份可升级软件包

在 Debian 上使用 dpkg-repack 备份可升级软件包

我想列出可升级的软件包并自动将它们重新打包为 .debs。我的尝试:

fakeroot -u dpkg-repack `apt list --upgradable | cut -f1 -d"/" | awk '{if(NR>2)print}'`

因此它获取软件包名称,然后将名称重定向到 dpkg-repack。它部分起作用,因为当 amd64 和 i386 软件包存在且两者具有相同的名称时,dpkg-repack 会抛出错误 - 在这种情况下,它希望将体系结构添加到软件包名称中。

你知道该如何管理它吗?如果存在多个架构,它会自动生成两个 deb 吗?看来 dpkg-repack 不够智能,无法自动生成多个架构,它只会抛出错误消息,提示安装了多个同名的包

答案1

dpkg-repack我对所有可能受到操作影响的包使用以下脚本apt-get

#!/bin/zsh
#
# creates subdir and dpkg-repacks all relevant packages in it
#
DIR=$(date +%Y%m%d)
OPER=${@:-dist-upgrade}
mkdir -p $DIR
cd $DIR || exit 1
zmodload zsh/system

renice -n 20 -p $$ >/dev/null 2>/dev/null

nproc=$(nproc)
native_arch=$(dpkg --print-architecture)
typeset -U possible_arch=($native_arch all)
[[ $native_arch = amd64 ]] && possible_arch=($possible_arch i386)

function repacked() {
    local p=$1
    local a=$2
    local existing
    existing=(${p}_*${a}.deb(N) ${p}_*all.deb(N))   # no need to try repacking in a binary arch if _all already exists, because arch-specific and arch=all packages of the same name can't exist simultaneously
    if (($#existing)); then
        [[ "$a" = none ]] && unset a    # avoid confusing message with arch specified as "none"
        echo "Skipping $p${a:+:$a}, already repacked." >&2
        return 0
    fi
    return 1
}

function worker() {
    local pkg=$1
    local arch=$2
    local lockfd lockfd2
    local success=0
    local try_arch
    [[ -z "$pkg" ]] && return 0
    : >>"$pkg.$arch.lock"
    if zsystem flock -f lockfd -t 0 "$pkg.$arch.lock" 2>/dev/null; then
        if [[ $arch = none ]]; then
            for try_arch in $possible_arch; do
                repacked $pkg $try_arch && success=1
            done
            if ! ((success)) && ! dpkg-repack $pkg; then
                for try_arch in $possible_arch; do
                    echo "*** DEBUG: *** entering architecture guessing branch in worker()." >&2    # it's unclear whether this branch will ever even be run
                    repacked $pkg $try_arch && break    # avoid even locking if another thread got here first; allows main thread to start an additional worker sooner
                    : >>"$pkg.$try_arch.lock"
                    if zsystem flock -f lockfd2 -t 0 "$pkg.$try_arch.lock" 2>/dev/null; then
                        if repacked $pkg $try_arch; then    # make sure another thread didn't get to this package after our previous check but before acquiring the lock
                            success=1
                        else
                            dpkg-repack --arch=$try_arch $pkg:$try_arch && success=1
                        fi
                        rm $pkg.$try_arch.lock
                        zsystem flock -u $lockfd2
                        ((success)) && break
                    fi
                done
            fi
        else
            repacked $pkg $arch || dpkg-repack --arch=$arch $pkg:$arch  # TODO: run with loadwatch
        fi
        rm $pkg.$arch.lock
        zsystem flock -u $lockfd
    fi
}

# clean up any leftover locks from a previous invocation
for i in *.lock(N); do
    zsystem flock -f lockfd $i  # if they're still locked, a dpkg-repack may still be running; wait for it to finish
    rm $i
    zsystem flock -u $lockfd
done

for i in $(echo n \
    | LC_MESSAGES=C apt-get -d -u ${=OPER} 2>&1 \
    | sed -r '/^The following packages were automatically installed/,/^Use .apt(-get)? autoremove. to remove them/d
          /^The following NEW packages will be installed:/,/^The/s/^[[:space:]].*//
          /^The following packages have been kept back:/,/^The following packages will be upgraded:/d
          /^The following packages have unmet dependencies:/,$d' \
    | grep '^[[:space:]]' \
    | tr -d '*'); do
        if ((${i[(I):]})); then # package name includes architecture (separated by colon) -- index of colon within $i is not zero
            echo ${${i:t}/:/ }  # print name and architecture
        else
            p=${i:t}
            # guess architecture:
            [[ -e /var/lib/dpkg/info/${p}.list ]] && echo $p none   # we don't know the architecture, but perhaps dpkg-repack doesn't need it; have the worker try
            for try_arch in $possible_arch; do
                [[ -e /var/lib/dpkg/info/${p}:${try_arch}.list ]] && echo $p $try_arch
            done
        fi
done | sort -u | while read p a; do
    if ! repacked $p $a; then
        workers=(*.lock(N))
        while [[ $#workers -ge $nproc ]]; do    # wait for a worker slot to become available
            sleep 0.5
            workers=(*.lock(N))
        done
        [[ -n "$p" ]] && worker $p $a &
    fi
done
wait
rm -f *.lock(N)

只需使用与传递给 相同的参数来调用它即可apt-get。它将创建一个以今天的日期命名的目录,并将所有生成的 .deb 放入其中。它将并行重新打包与 CPU 核心数量相同的软件包。它是幂等的,因为如果软件包的 .deb 已经存在,它就不会再次重新打包,从而可以安全地中止并重新启动。

它具有硬连线的 i386 和 amd64 架构,因此如果您有其他东西,您将需要更改它。

相关内容