[pacman-dev] [PATCH v2] Extend database upgrade script to handle alpm db version 9
Signed-off-by: Allan McRae <allan@archlinux.org> --- v2: Use awk to do symlink to actual directory replacement As an example of what changes get made: diff -Naur local.tmp/glibc-2.18-4/files local/glibc-2.18-4/files --- local.tmp/glibc-2.18-4/files 2013-09-18 18:45:35.747068765 +1000 +++ local/glibc-2.18-4/files 2013-09-18 18:51:29.633643945 +1000 @@ -4,8 +4,8 @@ etc/locale.gen etc/nscd.conf etc/rpc -lib/ -lib/libc.a +usr/lib/ +usr/lib/libc.a usr/ usr/bin/ usr/bin/catchsegv Note that now usr/lib/ is present twice in the file (may not always be the case) and these entries are out of alphabetical order. Both these are cosmetic to pacman. scripts/pacman-db-upgrade.sh.in | 59 ++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in index a1630c5..d6f4169 100644 --- a/scripts/pacman-db-upgrade.sh.in +++ b/scripts/pacman-db-upgrade.sh.in @@ -109,18 +109,57 @@ fi # do not let pacman run while we do this touch "$lockfile" -# pacman-3.4 to 3.5 upgrade - merge depends into desc -if [[ $(find "$dbroot"/local -name depends) ]]; then - msg "$(gettext "Pre-3.5 database format detected - upgrading...")" - for i in "$dbroot"/local/*; do - if [[ -f "$i"/depends ]]; then - cat "$i"/depends >> "$i"/desc - rm "$i"/depends - fi - done - msg "$(gettext "Done.")" +if [[ -f "${dbroot}"/local/.alpm_db_version ]]; then + db_version=$(cat "${dbroot}"/local/.alpm_db_version) fi +if [[ -z "$db_version" ]]; then + # pacman-3.4 to 3.5 upgrade - merge depends into desc + if [[ $(find "$dbroot"/local -name depends) ]]; then + msg "$(gettext "Pre-3.5 database format detected - upgrading...")" + for i in "$dbroot"/local/*; do + if [[ -f "$i"/depends ]]; then + cat "$i"/depends >> "$i"/desc + rm "$i"/depends + fi + done + msg "$(gettext "Done.")" + fi + + # pacman 4.1 to 4.2 upgrade - remove directory symlink support + dirlist=() + + unset GREP_OPTIONS + while IFS= read -r dir; do + dirlist+=("/${dir%/}") + done < <(grep -h '/$' "$dbroot"/local/*/files | sort -u) + + mapfile -t dirlist < <(find "${dirlist[@]}" -maxdepth 0 -type l) + + if [[ ${#dirlist[@]} != 0 ]]; then + msg "$(gettext "Pre-4.2 database format detected - upgrading...")" + for dir in "${dirlist[@]}"; do + realdir="$(cd $dir; pwd -P)" + for f in "$dbroot"/local/*/files; do + awk -v "dir=${dir#/}/" -v "realdir=${realdir#/}/" ' + BEGIN { + i = length(dir) + 1 + } + { + if (index($0, dir) == 1) { + printf("%s%s\n", realdir, substr($0, i)) + } else { + print + } + }' $f > $f.tmp + mv $f.tmp $f + done + done + fi +fi + +echo "9" > "$dbroot"/local/.alpm_db_version + # remove the lock file rm -f "$lockfile" -- 1.8.4
On 18/09/13 18:59, Allan McRae wrote:
Signed-off-by: Allan McRae <allan@archlinux.org> ---
v2: Use awk to do symlink to actual directory replacement
Any comments on this before it gets committed?
As an example of what changes get made:
diff -Naur local.tmp/glibc-2.18-4/files local/glibc-2.18-4/files --- local.tmp/glibc-2.18-4/files 2013-09-18 18:45:35.747068765 +1000 +++ local/glibc-2.18-4/files 2013-09-18 18:51:29.633643945 +1000 @@ -4,8 +4,8 @@ etc/locale.gen etc/nscd.conf etc/rpc -lib/ -lib/libc.a +usr/lib/ +usr/lib/libc.a usr/ usr/bin/ usr/bin/catchsegv
Note that now usr/lib/ is present twice in the file (may not always be the case) and these entries are out of alphabetical order. Both these are cosmetic to pacman.
scripts/pacman-db-upgrade.sh.in | 59 ++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-)
diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in index a1630c5..d6f4169 100644 --- a/scripts/pacman-db-upgrade.sh.in +++ b/scripts/pacman-db-upgrade.sh.in @@ -109,18 +109,57 @@ fi # do not let pacman run while we do this touch "$lockfile"
-# pacman-3.4 to 3.5 upgrade - merge depends into desc -if [[ $(find "$dbroot"/local -name depends) ]]; then - msg "$(gettext "Pre-3.5 database format detected - upgrading...")" - for i in "$dbroot"/local/*; do - if [[ -f "$i"/depends ]]; then - cat "$i"/depends >> "$i"/desc - rm "$i"/depends - fi - done - msg "$(gettext "Done.")" +if [[ -f "${dbroot}"/local/.alpm_db_version ]]; then + db_version=$(cat "${dbroot}"/local/.alpm_db_version) fi
+if [[ -z "$db_version" ]]; then + # pacman-3.4 to 3.5 upgrade - merge depends into desc + if [[ $(find "$dbroot"/local -name depends) ]]; then + msg "$(gettext "Pre-3.5 database format detected - upgrading...")" + for i in "$dbroot"/local/*; do + if [[ -f "$i"/depends ]]; then + cat "$i"/depends >> "$i"/desc + rm "$i"/depends + fi + done + msg "$(gettext "Done.")" + fi + + # pacman 4.1 to 4.2 upgrade - remove directory symlink support + dirlist=() + + unset GREP_OPTIONS + while IFS= read -r dir; do + dirlist+=("/${dir%/}") + done < <(grep -h '/$' "$dbroot"/local/*/files | sort -u) + + mapfile -t dirlist < <(find "${dirlist[@]}" -maxdepth 0 -type l) + + if [[ ${#dirlist[@]} != 0 ]]; then + msg "$(gettext "Pre-4.2 database format detected - upgrading...")" + for dir in "${dirlist[@]}"; do + realdir="$(cd $dir; pwd -P)" + for f in "$dbroot"/local/*/files; do + awk -v "dir=${dir#/}/" -v "realdir=${realdir#/}/" ' + BEGIN { + i = length(dir) + 1 + } + { + if (index($0, dir) == 1) { + printf("%s%s\n", realdir, substr($0, i)) + } else { + print + } + }' $f > $f.tmp + mv $f.tmp $f + done + done + fi +fi + +echo "9" > "$dbroot"/local/.alpm_db_version + # remove the lock file rm -f "$lockfile"
On 09/18/13 at 06:59pm, Allan McRae wrote:
Signed-off-by: Allan McRae <allan@archlinux.org> ---
v2: Use awk to do symlink to actual directory replacement
As an example of what changes get made:
diff -Naur local.tmp/glibc-2.18-4/files local/glibc-2.18-4/files --- local.tmp/glibc-2.18-4/files 2013-09-18 18:45:35.747068765 +1000 +++ local/glibc-2.18-4/files 2013-09-18 18:51:29.633643945 +1000 @@ -4,8 +4,8 @@ etc/locale.gen etc/nscd.conf etc/rpc -lib/ -lib/libc.a +usr/lib/ +usr/lib/libc.a usr/ usr/bin/ usr/bin/catchsegv
Note that now usr/lib/ is present twice in the file (may not always be the case) and these entries are out of alphabetical order. Both these are cosmetic to pacman.
scripts/pacman-db-upgrade.sh.in | 59 ++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-)
diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in index a1630c5..d6f4169 100644 --- a/scripts/pacman-db-upgrade.sh.in +++ b/scripts/pacman-db-upgrade.sh.in @@ -109,18 +109,57 @@ fi # do not let pacman run while we do this touch "$lockfile"
-# pacman-3.4 to 3.5 upgrade - merge depends into desc -if [[ $(find "$dbroot"/local -name depends) ]]; then - msg "$(gettext "Pre-3.5 database format detected - upgrading...")" - for i in "$dbroot"/local/*; do - if [[ -f "$i"/depends ]]; then - cat "$i"/depends >> "$i"/desc - rm "$i"/depends - fi - done - msg "$(gettext "Done.")" +if [[ -f "${dbroot}"/local/.alpm_db_version ]]; then + db_version=$(cat "${dbroot}"/local/.alpm_db_version) fi
+if [[ -z "$db_version" ]]; then + # pacman-3.4 to 3.5 upgrade - merge depends into desc + if [[ $(find "$dbroot"/local -name depends) ]]; then + msg "$(gettext "Pre-3.5 database format detected - upgrading...")" + for i in "$dbroot"/local/*; do + if [[ -f "$i"/depends ]]; then + cat "$i"/depends >> "$i"/desc + rm "$i"/depends + fi + done + msg "$(gettext "Done.")" + fi + + # pacman 4.1 to 4.2 upgrade - remove directory symlink support + dirlist=() + + unset GREP_OPTIONS + while IFS= read -r dir; do + dirlist+=("/${dir%/}") + done < <(grep -h '/$' "$dbroot"/local/*/files | sort -u)
This sort needs to be reversed. If a path contains multiple symlinks, the longer one needs to come first, otherwise awk will replace the shorter symlink and miss the longer one. For example: symlink1/ symlink1/symlink2/ ...
+ + mapfile -t dirlist < <(find "${dirlist[@]}" -maxdepth 0 -type l) + + if [[ ${#dirlist[@]} != 0 ]]; then + msg "$(gettext "Pre-4.2 database format detected - upgrading...")" + for dir in "${dirlist[@]}"; do + realdir="$(cd $dir; pwd -P)" + for f in "$dbroot"/local/*/files; do + awk -v "dir=${dir#/}/" -v "realdir=${realdir#/}/" ' + BEGIN { + i = length(dir) + 1 + } + { + if (index($0, dir) == 1) { + printf("%s%s\n", realdir, substr($0, i)) + } else { + print + } + }' $f > $f.tmp + mv $f.tmp $f
$f will include $dbroot, so it needs to be quoted as well. Depending on the file list, this may leave out parent directories of $realdir or leave behind parent directories of $dir that are no longer relevant. For example: path/ path/to/ path/to/symlink/ ... gives: path/ path/to/ other/path/to/realdir/ ... I don't think the leftover directories will hurt anything, but the missing parent directories will break -Qo.
+ done + done + fi +fi + +echo "9" > "$dbroot"/local/.alpm_db_version + # remove the lock file rm -f "$lockfile"
-- 1.8.4
Original-work-by: Allan McRae <allan@archlinux.org> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> --- Changes: * set alternate root with PACROOT environment variable * filter results through grep and sort to remove empty lines and duplicates * add parent directories (duplicates filtered out by sort) * verify that the resolved directory is inside our root * replace longer symlinks first * handle conflict between resolved directory and existing filelist entry scripts/pacman-db-upgrade.sh.in | 92 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 10 deletions(-) diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in index b0b0ac8..7ea4077 100644 --- a/scripts/pacman-db-upgrade.sh.in +++ b/scripts/pacman-db-upgrade.sh.in @@ -25,9 +25,17 @@ export TEXTDOMAINDIR='@localedir@' declare -r myver='@PACKAGE_VERSION@' +resolve_dir() { + local d="$(cd "$1"; pwd -P)" + [[ $d == */ ]] || d+=/ + printf "%s" "$d" +} + eval $(awk '/DBPath/ {print $1$2$3}' @sysconfdir@/pacman.conf) dbroot="${DBPath:-@localstatedir@/lib/pacman/}" +pacroot="$(resolve_dir "${PACROOT:-/}")" + USE_COLOR='y' m4_include(library/output_format.sh) @@ -112,18 +120,82 @@ fi # do not let pacman run while we do this touch "$lockfile" -# pacman-3.4 to 3.5 upgrade - merge depends into desc -if [[ $(find "$dbroot"/local -name depends) ]]; then - msg "$(gettext "Pre-3.5 database format detected - upgrading...")" - for i in "$dbroot"/local/*; do - if [[ -f "$i"/depends ]]; then - cat "$i"/depends >> "$i"/desc - rm "$i"/depends - fi - done - msg "$(gettext "Done.")" +if [[ -f "${dbroot}"/local/.alpm_db_version ]]; then + db_version=$(cat "${dbroot}"/local/.alpm_db_version) fi +if [[ -z "$db_version" ]]; then + # pacman-3.4 to 3.5 upgrade - merge depends into desc + if [[ $(find "$dbroot"/local -name depends) ]]; then + msg "$(gettext "Pre-3.5 database format detected - upgrading...")" + for i in "$dbroot"/local/*; do + if [[ -f "$i"/depends ]]; then + cat "$i"/depends >> "$i"/desc + rm "$i"/depends + fi + done + msg "$(gettext "Done.")" + fi + + # pacman 4.1 to 4.2 upgrade - remove directory symlink support + dirlist=() + + unset GREP_OPTIONS + while IFS= read -r dir; do + dirlist+=("${pacroot}${dir%/}") + done < <(grep -h '/$' "$dbroot"/local/*/files | sort -ru) + + mapfile -t dirlist < <(find "${dirlist[@]}" -maxdepth 0 -type l) + + if [[ ${#dirlist[@]} != 0 ]]; then + msg "$(gettext "Pre-4.2 database format detected - upgrading...")" + for dir in "${dirlist[@]}"; do + realdir="$(resolve_dir "$(cd $dir; pwd -P)")" + + # verify realdir is inside root + if [[ ${realdir:0:${#pacroot}} != $pacroot ]]; then + warning "$(gettext "symlink '%s' points outside pacman root, manual repair required")" "$dir" + continue + fi + + # convert to an appropriate form for the replacement + olddir="${dir:${#pacroot}}/" + newdir="${realdir:${#pacroot}}" + + # construct the parents of the new directory + parents="" + parent="$(dirname "$newdir")" + while [[ $parent != "." ]]; do + parents+="$parent/\n" + parent="$(dirname "$parent")" + done + + for f in "$dbroot"/local/*/files; do + awk -v "olddir=$olddir" -v "newdir=$newdir" -v "parents=$parents" ' + BEGIN { + i = length(olddir) + 1 + file = substr(newdir, 0, length(newdir) - 1) + } + { + if ($0 == olddir) { + printf("%s", parents) + printf("%s\n", newdir) + } else if ($0 == file) { + # skip + } else if (index($0, olddir) == 1) { + printf("%s%s\n", newdir, substr($0, i)) + } else { + print + } + }' "$f" | grep . | LC_ALL=C sort -u > "$f.tmp" + mv "$f.tmp" "$f" + done + done + fi +fi + +echo "9" > "$dbroot"/local/.alpm_db_version + # remove the lock file rm -f "$lockfile" -- 2.0.2
On 03/08/14 15:31, Andrew Gregory wrote:
Original-work-by: Allan McRae <allan@archlinux.org> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> ---
Changes: * set alternate root with PACROOT environment variable * filter results through grep and sort to remove empty lines and duplicates * add parent directories (duplicates filtered out by sort) * verify that the resolved directory is inside our root * replace longer symlinks first * handle conflict between resolved directory and existing filelist entry
This looks fine on first pass to me. Why do you think this is a WIP? Is there something more needing done? A
On 08/04/14 at 03:43pm, Allan McRae wrote:
On 03/08/14 15:31, Andrew Gregory wrote:
Original-work-by: Allan McRae <allan@archlinux.org> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> ---
Changes: * set alternate root with PACROOT environment variable * filter results through grep and sort to remove empty lines and duplicates * add parent directories (duplicates filtered out by sort) * verify that the resolved directory is inside our root * replace longer symlinks first * handle conflict between resolved directory and existing filelist entry
This looks fine on first pass to me. Why do you think this is a WIP? Is there something more needing done?
A
I think it's substantively ready but my bash and awk are not particularly great and probably in need of some cleanup and the PACROOT variable needs a little work. It at least needs to be documented, and I'm considering making it an option rather than an environment variable and making the default dbpath relative to it. apg
On 03/08/14 15:31, Andrew Gregory wrote:
Original-work-by: Allan McRae <allan@archlinux.org> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> ---
Big thanks for doing this!
Changes: * set alternate root with PACROOT environment variable
As you have pointed out, that needs to be a -r/--root flag and not an environmental variable
* filter results through grep and sort to remove empty lines and duplicates * add parent directories (duplicates filtered out by sort) * verify that the resolved directory is inside our root * replace longer symlinks first * handle conflict between resolved directory and existing filelist entry
scripts/pacman-db-upgrade.sh.in | 92 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 10 deletions(-)
diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in index b0b0ac8..7ea4077 100644 --- a/scripts/pacman-db-upgrade.sh.in +++ b/scripts/pacman-db-upgrade.sh.in @@ -25,9 +25,17 @@ export TEXTDOMAINDIR='@localedir@'
declare -r myver='@PACKAGE_VERSION@'
+resolve_dir() { + local d="$(cd "$1"; pwd -P)" + [[ $d == */ ]] || d+=/ + printf "%s" "$d" +} +
OK
eval $(awk '/DBPath/ {print $1$2$3}' @sysconfdir@/pacman.conf) dbroot="${DBPath:-@localstatedir@/lib/pacman/}"
+pacroot="$(resolve_dir "${PACROOT:-/}")" + USE_COLOR='y'
m4_include(library/output_format.sh) @@ -112,18 +120,82 @@ fi # do not let pacman run while we do this touch "$lockfile"
-# pacman-3.4 to 3.5 upgrade - merge depends into desc -if [[ $(find "$dbroot"/local -name depends) ]]; then - msg "$(gettext "Pre-3.5 database format detected - upgrading...")" - for i in "$dbroot"/local/*; do - if [[ -f "$i"/depends ]]; then - cat "$i"/depends >> "$i"/desc - rm "$i"/depends - fi - done - msg "$(gettext "Done.")" +if [[ -f "${dbroot}"/local/.alpm_db_version ]]; then + db_version=$(cat "${dbroot}"/local/.alpm_db_version) fi
OK.
+if [[ -z "$db_version" ]]; then + # pacman-3.4 to 3.5 upgrade - merge depends into desc + if [[ $(find "$dbroot"/local -name depends) ]]; then + msg "$(gettext "Pre-3.5 database format detected - upgrading...")" + for i in "$dbroot"/local/*; do + if [[ -f "$i"/depends ]]; then + cat "$i"/depends >> "$i"/desc + rm "$i"/depends + fi + done + msg "$(gettext "Done.")" + fi +
OK
+ # pacman 4.1 to 4.2 upgrade - remove directory symlink support + dirlist=() + + unset GREP_OPTIONS + while IFS= read -r dir; do + dirlist+=("${pacroot}${dir%/}") + done < <(grep -h '/$' "$dbroot"/local/*/files | sort -ru) +
OK
+ mapfile -t dirlist < <(find "${dirlist[@]}" -maxdepth 0 -type l) +
OK
+ if [[ ${#dirlist[@]} != 0 ]]; then
if (( ${#dirlist[@]} ))
+ msg "$(gettext "Pre-4.2 database format detected - upgrading...")" + for dir in "${dirlist[@]}"; do + realdir="$(resolve_dir "$(cd $dir; pwd -P)")" + + # verify realdir is inside root + if [[ ${realdir:0:${#pacroot}} != $pacroot ]]; then + warning "$(gettext "symlink '%s' points outside pacman root, manual repair required")" "$dir" + continue + fi
OK.
+ + # convert to an appropriate form for the replacement + olddir="${dir:${#pacroot}}/" + newdir="${realdir:${#pacroot}}" +
OK
+ # construct the parents of the new directory + parents="" + parent="$(dirname "$newdir")"
use bash: parent=${newdir%/*}
+ while [[ $parent != "." ]]; do
Should that be != '/' ? $ dirname /usr / Anyway, using the bash above this becomes while [[ -n "$parent" ]]; do
+ parents+="$parent/\n" + parent="$(dirname "$parent")" + done +
My awk is suboptimal... So I'll comment my understanding as I go...
+ for f in "$dbroot"/local/*/files; do + awk -v "olddir=$olddir" -v "newdir=$newdir" -v "parents=$parents" '
"parents=${parents[@]}"
+ BEGIN { + i = length(olddir) + 1 + file = substr(newdir, 0, length(newdir) - 1) + } + { + if ($0 == olddir) { + printf("%s", parents) + printf("%s\n", newdir)
OK (replacing old dir with newdir and its parents)
+ } else if ($0 == file) { + # skip
I do not understand what this bit is achieving!
+ } else if (index($0, olddir) == 1) { + printf("%s%s\n", newdir, substr($0, i))
OK ("moving" file in olddir to "newdir")
+ } else { + print
OK (not touching files outside of olddir)
+ } + }' "$f" | grep . | LC_ALL=C sort -u > "$f.tmp"
Why the grep?
+ mv "$f.tmp" "$f" + done + done + fi +fi + +echo "9" > "$dbroot"/local/.alpm_db_version +
OK
# remove the lock file rm -f "$lockfile"
On 08/10/14 at 01:16pm, Allan McRae wrote:
On 03/08/14 15:31, Andrew Gregory wrote:
Original-work-by: Allan McRae <allan@archlinux.org> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> ---
Big thanks for doing this!
Changes: * set alternate root with PACROOT environment variable
As you have pointed out, that needs to be a -r/--root flag and not an environmental variable
* filter results through grep and sort to remove empty lines and duplicates * add parent directories (duplicates filtered out by sort) * verify that the resolved directory is inside our root * replace longer symlinks first * handle conflict between resolved directory and existing filelist entry
scripts/pacman-db-upgrade.sh.in | 92 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 10 deletions(-)
diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in index b0b0ac8..7ea4077 100644 --- a/scripts/pacman-db-upgrade.sh.in +++ b/scripts/pacman-db-upgrade.sh.in
<snip>
+ # construct the parents of the new directory + parents="" + parent="$(dirname "$newdir")"
use bash: parent=${newdir%/*}
+ while [[ $parent != "." ]]; do
Should that be != '/' ?
$ dirname /usr /
Anyway, using the bash above this becomes while [[ -n "$parent" ]]; do
This won't work. $newdir has a trailing slash that would need to be removed and it's relative to $pacroot, so ${parent%/*} would eventually result in the base directory, not an empty string (which is why dirname eventually gives '.'). If the symlink points to $pacroot, $newdir could even be empty. My attempts to account for all of that in pure bash have been overly convoluted, but I'm open to suggestions.
+ parents+="$parent/\n" + parent="$(dirname "$parent")" + done +
My awk is suboptimal... So I'll comment my understanding as I go...
+ for f in "$dbroot"/local/*/files; do + awk -v "olddir=$olddir" -v "newdir=$newdir" -v "parents=$parents" '
"parents=${parents[@]}"
$parents is actually a string rather than an array because I don't think there's a way to pass an array to awk without mangling something.
+ BEGIN { + i = length(olddir) + 1 + file = substr(newdir, 0, length(newdir) - 1) + } + { + if ($0 == olddir) { + printf("%s", parents) + printf("%s\n", newdir)
OK (replacing old dir with newdir and its parents)
+ } else if ($0 == file) { + # skip
I do not understand what this bit is achieving!
If the newdir already exists in the file list as a file (i.e. somebody replaced a symlink with a directory) this will prevent a duplicate entry. I'll expand that comment so it's clearer.
+ } else if (index($0, olddir) == 1) { + printf("%s%s\n", newdir, substr($0, i))
OK ("moving" file in olddir to "newdir")
+ } else { + print
OK (not touching files outside of olddir)
+ } + }' "$f" | grep . | LC_ALL=C sort -u > "$f.tmp"
Why the grep?
Removes blank lines in case $newdir has no parents or equals $pacroot.
+ mv "$f.tmp" "$f" + done + done + fi +fi + +echo "9" > "$dbroot"/local/.alpm_db_version +
OK
# remove the lock file rm -f "$lockfile"
* convert dbpath from argument to option * add --config and --root options * read dbpath and root from config file * if root is set but not dbpath, dbpath is set relative to root Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> --- scripts/Makefile.am | 1 + scripts/pacman-db-upgrade.sh.in | 73 +++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 0b756ad..bc1dc10 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -54,6 +54,7 @@ endif #### Taken from the autoconf scripts Makefile.am #### edit = sed \ + -e 's|@rootdir[@]|$(ROOTDIR)|g' \ -e 's|@localedir[@]|$(localedir)|g' \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ -e 's|@localstatedir[@]|$(localstatedir)|g' \ diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in index b0b0ac8..70562e0 100644 --- a/scripts/pacman-db-upgrade.sh.in +++ b/scripts/pacman-db-upgrade.sh.in @@ -25,19 +25,25 @@ export TEXTDOMAINDIR='@localedir@' declare -r myver='@PACKAGE_VERSION@' -eval $(awk '/DBPath/ {print $1$2$3}' @sysconfdir@/pacman.conf) -dbroot="${DBPath:-@localstatedir@/lib/pacman/}" - -USE_COLOR='y' - m4_include(library/output_format.sh) +m4_include(library/parseopts.sh) + usage() { printf "pacman-db-upgrade (pacman) %s\n" "${myver}" echo printf -- "$(gettext "Upgrade the local pacman database to a newer format")\n" echo - printf -- "$(gettext "Usage: %s [--nocolor] [pacman_db_root]")\n" "$0" + printf -- "$(gettext "Usage: %s [options]")\n" "$0" + echo + printf -- "$(gettext "options:")\n" + printf -- "$(gettext " -b, --dbpath <path> set an alternate database location")\n" + printf -- "$(gettext " -h, --help show this help message and exit")\n" + printf -- "$(gettext " -r, --root <path> set an alternate installation root")\n" + printf -- "$(gettext " -V, --version show version information and exit")\n" + printf -- "$(gettext " --config <path> set an alternate configuration file")\n" + printf -- "$(gettext " --nocolor disable colorized output messages")\n" + echo } version() { @@ -58,6 +64,18 @@ die_r() { die "$@" } +get_opt_from_config() { + local keyname="$1" conffile="$2" + local key value + + while IFS=$'= \t' read -r key value _; do + if [[ $key = $keyname ]]; then + echo "$value" + return + fi + done <"$conffile" +} + # PROGRAM START # determine whether we have gettext; make it a no-op if we do not @@ -67,26 +85,39 @@ if ! type gettext &>/dev/null; then } fi -if [[ $1 = "-h" || $1 = "--help" ]]; then - usage - exit 0 -fi +USE_COLOR='y' -if [[ $1 = "-V" || $1 = "--version" ]]; then - version - exit 0 +OPT_SHORT="d:hr:V" +OPT_LONG=('confg' 'dbpath:' 'help' 'nocolor' 'root:' 'version') +if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then + exit 1 # E_INVALID_OPTION fi - -if [[ $1 = "--nocolor" ]]; then - USE_COLOR='n' +set -- "${OPTRET[@]}" +unset OPT_SHORT OPT_LONG OPTRET + +while true; do + case "$1" in + --config) shift; conffile="$1" ;; + -d|--dbpath) shift; dbroot="$1" ;; + -r|--root) shift; pacroot="$1" ;; + -h|--help) usage; exit 0 ;; + --nocolor) USE_COLOR='n' ;; + -V|--version) version; exit 0 ;; + -- ) shift; break 2 ;; + esac shift -fi +done -m4_include(library/term_colors.sh) +conffile=${conffile:-@sysconfdir@/pacman.conf} +[[ -z $pacroot ]] && pacroot="$(get_opt_from_config "RootDir" "$conffile")" +[[ -z $dbroot ]] && dbroot="$(get_opt_from_config "DBPath" "$conffile")" -if [[ -n $1 ]]; then - dbroot="$1" -fi +[[ -z $dbroot && -n $pacroot ]] && dbroot="$pacroot/@localstatedir@/lib/pacman" + +[[ -z $pacroot ]] && pacroot="@rootdir@" +[[ -z $dbroot ]] && dbroot="@localstatedir@/lib/pacman/" + +m4_include(library/term_colors.sh) if [[ ! -d $dbroot ]]; then die "$(gettext "%s does not exist or is not a directory.")" "$dbroot" -- 2.1.0
Original-work-by: Allan McRae <allan@archlinux.org> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> --- * rebase after converting to pacman-style options * expand awk comments * only resolve $pacroot if we're upgrading to 4.2 * only resolve $dir once scripts/pacman-db-upgrade.sh.in | 96 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 10 deletions(-) diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in index 70562e0..e582019 100644 --- a/scripts/pacman-db-upgrade.sh.in +++ b/scripts/pacman-db-upgrade.sh.in @@ -76,6 +76,12 @@ get_opt_from_config() { done <"$conffile" } +resolve_dir() { + local d="$(cd "$1"; pwd -P)" + [[ $d == */ ]] || d+=/ + printf "%s" "$d" +} + # PROGRAM START # determine whether we have gettext; make it a no-op if we do not @@ -143,18 +149,88 @@ fi # do not let pacman run while we do this touch "$lockfile" -# pacman-3.4 to 3.5 upgrade - merge depends into desc -if [[ $(find "$dbroot"/local -name depends) ]]; then - msg "$(gettext "Pre-3.5 database format detected - upgrading...")" - for i in "$dbroot"/local/*; do - if [[ -f "$i"/depends ]]; then - cat "$i"/depends >> "$i"/desc - rm "$i"/depends - fi - done - msg "$(gettext "Done.")" +if [[ -f "${dbroot}"/local/.alpm_db_version ]]; then + db_version=$(cat "${dbroot}"/local/.alpm_db_version) fi +if [[ -z "$db_version" ]]; then + # pacman-3.4 to 3.5 upgrade - merge depends into desc + if [[ $(find "$dbroot"/local -name depends) ]]; then + msg "$(gettext "Pre-3.5 database format detected - upgrading...")" + for i in "$dbroot"/local/*; do + if [[ -f "$i"/depends ]]; then + cat "$i"/depends >> "$i"/desc + rm "$i"/depends + fi + done + msg "$(gettext "Done.")" + fi + + # pacman 4.1 to 4.2 upgrade - remove directory symlink support + dirlist=() + + unset GREP_OPTIONS + while IFS= read -r dir; do + dirlist+=("${pacroot}${dir%/}") + done < <(grep -h '/$' "$dbroot"/local/*/files | sort -ru) + + mapfile -t dirlist < <(find "${dirlist[@]}" -maxdepth 0 -type l) + + if [[ ${#dirlist[@]} != 0 ]]; then + msg "$(gettext "Pre-4.2 database format detected - upgrading...")" + + pacroot="$(resolve_dir "$pacroot")" + + for dir in "${dirlist[@]}"; do + realdir="$(resolve_dir "$dir")" + + # verify realdir is inside root + if [[ ${realdir:0:${#pacroot}} != $pacroot ]]; then + warning "$(gettext "symlink '%s' points outside pacman root, manual repair required")" "$dir" + continue + fi + + # convert to an appropriate form for the replacement + olddir="${dir:${#pacroot}}/" + newdir="${realdir:${#pacroot}}" + + # construct the parents of the new directory + parents="" + parent="$(dirname "$newdir")" + while [[ $parent != "." ]]; do + parents+="$parent/\n" + parent="$(dirname "$parent")" + done + + for f in "$dbroot"/local/*/files; do + awk -v "olddir=$olddir" -v "newdir=$newdir" -v "parents=$parents" ' + BEGIN { + i = length(olddir) + 1 + file = substr(newdir, 0, length(newdir) - 1) + } + { + if ($0 == olddir) { + # replace symlink with its target, including parents + printf("%s", parents) + printf("%s\n", newdir) + } else if ($0 == file) { + # newdir already existed as a file, skip it + } else if (index($0, olddir) == 1) { + # update paths that were under olddir + printf("%s%s\n", newdir, substr($0, i)) + } else { + # print everything else as-is + print + } + }' "$f" | grep . | LC_ALL=C sort -u > "$f.tmp" + mv "$f.tmp" "$f" + done + done + fi +fi + +echo "9" > "$dbroot"/local/.alpm_db_version + # remove the lock file rm -f "$lockfile" -- 2.1.0
participants (2)
-
Allan McRae
-
Andrew Gregory