Skip to content

Commit b54e90c

Browse files
committed
feat: add ability to downgrade aur package using git
This reverts commit cb15393 and brings back `--git`.
1 parent 5804d1c commit b54e90c

File tree

5 files changed

+116
-5
lines changed

5 files changed

+116
-5
lines changed

dist/completion/downgrade/fish

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ complete -c $cmd -l pacman -xa "(complete -C(commandline -ct))" -d 'pacman comma
44
complete -c $cmd -l pacman-conf -r -d 'pacman configuration file'
55
complete -c $cmd -l pacman-cache -r -d 'pacman cache directory'
66
complete -c $cmd -l pacman-log -r -d 'pacman log file'
7+
complete -c $cmd -l git -d 'uses git for choosing version, viable only for aur packages'
78
complete -c $cmd -l maxdepth -x -d 'maximum depth to search for cached packages'
89
complete -c $cmd -l ala-url -x -d 'location of ALA server'
910
complete -c $cmd -l ala-only -d 'only use ALA server'

dist/completion/downgrade/zsh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ _downgrade () {
2020
'--pacman-conf[pacman configuration file]:pacman config file:_files' \
2121
'*--pacman-cache[pacman cache directory]:pacman cache directory:_path_files -/' \
2222
'--pacman-log[pacman log file]:pacman log file:_files' \
23+
'--git[uses git for choosing version, viable only for aur packages]' \
2324
'--maxdepth[maximum depth to search for cached packages]:maximum search depth' \
2425
'--ala-url[location of ALA server]:ala url' \
2526
'--ala-only[only use ALA server]' \

doc/downgrade.8.ronn

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ on the ALA.
7272
Pacman log file, default value is extracted from pacman configuration file, or
7373
otherwise defaults to _/var/log/pacman.log_.
7474

75+
* `--git`:
76+
If the pacman cache contains the source repository for the package (e.g. if
77+
you use yay and are downgrading an AUR package), present any version-like
78+
tags as available for downgrading (together with cached packages if
79+
present). If selected, build and install the package from sources checked
80+
out at that tag.
81+
82+
See [EXAMPLES].
83+
7584
* `--maxdepth`=<INTEGER>:
7685
Maximum depth to search for cached packages, defaults to _1_.
7786

@@ -168,6 +177,11 @@ Non-interactively downgrade `foo` to `1.0.0-1`
168177

169178
# downgrade --latest --prefer-cache --ignore never 'foo=1.0.0-1'
170179

180+
Present cached `downgrade` pkgbuilds together with tags with version greater
181+
than 9
182+
183+
# downgrade --git --pacman-cache ~/.cache/yay --maxdepth 2 'downgrade>9.0.0'
184+
171185
## AUTHORS
172186

173187
* Patrick Brisbin \<pbrisbin@gmail.com>

src/downgrade

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ $(gettext "Options"):
1919
$(gettext "pacman log file,")
2020
$(gettext "default value taken from pacman configuration file,")
2121
$(gettext "or otherwise defaults to") "/var/log/pacman.log"
22+
--git $(gettext "uses git for choosing version, viable only for aur packages")
2223
--maxdepth <$(gettext "integer")>
2324
$(gettext "maximum depth to search for cached packages, defaults to") 1
2425
--ala-url <url>
@@ -167,8 +168,10 @@ matches_name_version_filter() {
167168
return 0
168169
fi
169170

170-
version_regex="[^-]+-[0-9.]+"
171-
pkg_version=$(sed -r "s/.*$name-($version_regex)-(any|$DOWNGRADE_ARCH)\\.pkg\\.tar\\.(gz|xz|zst)/\1/g" <<<"$pkg")
171+
# version: 2025.11.12.r15.g0eed3fe
172+
version_regex="[a-zA-Z0-9.]+"
173+
hash_or_minor="([0-9]+|[a-z0-9]{6,})"
174+
pkg_version=$(sed -r "s/.*$name-($version_regex)(-$hash_or_minor)?-(any|$DOWNGRADE_ARCH)\\.(git)?pkg\\.tar\\.(gz|xz|zst)/\1\2/g" <<<"$pkg")
172175
cmp=$(vercmp "$pkg_version" "$search_version")
173176

174177
case "$operator" in
@@ -196,6 +199,34 @@ matches_name_version_filter() {
196199
esac
197200
}
198201

202+
search_git() {
203+
local name=$1 pairs path
204+
205+
# Delay this defaulting so #read_pacman_conf behavior is tested
206+
if ((!${#PACMAN_CACHE[@]})); then
207+
mapfile -t PACMAN_CACHE < <(read_pacman_conf CacheDir)
208+
fi
209+
210+
for cache in "${PACMAN_CACHE[@]}"; do
211+
path="$cache/$name" # directory name
212+
if ! [[ -d "$path/.git" ]]; then
213+
{
214+
gettext "\`$path\" not a git directory, skipping..."
215+
echo
216+
} >&2
217+
continue
218+
fi
219+
220+
# TODO: in future could be enhanced by counting every commit
221+
# that DOES NOT change version as minor like 0.0.1-2 instead of any
222+
# pair = abcd12 1.0
223+
pairs=$(git -C "$path" log -p --oneline --format="GIT: %h" PKGBUILD | grep -e 'GIT:.*' -e '+pkgver' | grep -Pzo 'GIT: .*\n\+pkgver=.*\n' | sed 's/GIT: \|+pkgver=//' | tr -d '\0')
224+
225+
# shellcheck disable=SC2086
226+
echo "$path/$name" $pairs | awk '{for(i=2;i<NF;i+=2) printf "%s-%s-%s-any.gitpkg.tar.gz\n", $1, $(i+1), $i}' | sort -V
227+
done
228+
}
229+
199230
search_ala() {
200231
local name=$1 uriname pkgfile_re index
201232

@@ -217,7 +248,10 @@ search_ala() {
217248
search_cache() {
218249
local name=$1 pkgfile_re index
219250

220-
pkgfile_re="$name-[^-]+-[0-9.]+-(any|$DOWNGRADE_ARCH)\\.pkg\\.tar\\.(gz|xz|zst)"
251+
# version: 2025.11.12.r15.g0eed3fe
252+
version_regex="[a-zA-Z0-9.]+"
253+
hash_or_minor="([0-9]+|[a-z0-9]{6,})"
254+
pkgfile_re="$name-($version_regex)(-$hash_or_minor)?-(any|$DOWNGRADE_ARCH)\\.pkg\\.tar\\.(gz|xz|zst)"
221255

222256
# Delay this defaulting so #read_pacman_conf behavior is tested
223257
if ((!${#PACMAN_CACHE[@]})); then
@@ -258,7 +292,7 @@ output_package() {
258292
fi
259293

260294
# Remote or local file
261-
if [[ $path =~ ^/ ]]; then
295+
if [[ $path =~ ^/ && ! ($path =~ gitpkg) ]]; then
262296
location="$(dirname "$path")"
263297
timestamp=$(stat -c '%y' "$path" | cut -d' ' -f1)
264298
else
@@ -293,7 +327,7 @@ extract_version_parts() {
293327
s|^.\{'${#pkgname}'\}-\?||;
294328
295329
# Strip package extension
296-
s|\.pkg\(\.tar\)\?\(\.[a-z0-9A-Z]\+\)\?$||;
330+
s|\.\(git\)\?pkg\(\.tar\)\?\(\.[a-z0-9A-Z]\+\)\?$||;
297331
298332
# (epoch:)?version(-release)?(-arch)? -> epoch,version,release,arch
299333
s|\(\([^:]*\):\)\?\([^-]*\)\(-\([^-]*\)\)\?\(-\(.*\)\)\?|\2,\3,\5,\7|;
@@ -320,6 +354,11 @@ process_term() {
320354

321355
candidates=($(printf '%s\n' "${candidates[@]}" | sort_packages))
322356

357+
# this is already sorted
358+
if ((DOWNGRADE_FROM_GIT)); then
359+
candidates=($(search_git "$name" | filter_packages "$name" "$operator" "$version") "${candidates[@]}")
360+
fi
361+
323362
if (("${#candidates[@]}" == 0)); then
324363
{
325364
gettext "No results found"
@@ -440,6 +479,9 @@ parse_options() {
440479
exit 1
441480
fi
442481
;;
482+
--git)
483+
DOWNGRADE_FROM_GIT=1
484+
;;
443485
--maxdepth)
444486
if [[ -n "$2" ]]; then
445487
shift
@@ -523,6 +565,34 @@ parse_options() {
523565
fi
524566
}
525567

568+
build_pkg() {
569+
local item="$1" path commit_hash build_failed versionreg hashreg gitpkgreg
570+
if [[ "$item" =~ .*gitpkg.tar.gz ]]; then
571+
# version: 2025.11.12.r15.g0eed3fe
572+
versionreg="([a-zA-Z0-9]+\.?)*"
573+
hashreg='[a-z0-9]{6,}'
574+
#hash_or_minor="-([0-9]+|[a-z0-9]{6,})" # leaving this as a note, only hash should appear tho
575+
gitpkgreg="(.*)-$versionreg-($hashreg)-(any|$DOWNGRADE_ARCH).gitpkg.tar.gz"
576+
path=$(dirname "$item")
577+
commit_hash=$(sed -r "s/$gitpkgreg/\3/" <<<"$item")
578+
579+
pushd "$path" >/dev/null
580+
su -P "$(stat -c"%U" PKGBUILD)" -c "git checkout $commit_hash &>/dev/null && makepkg -fs | tee makepkg.log"
581+
build_failed=$?
582+
# NOTE: when force-canceling, users might need to manually do checkout master
583+
# otherwise they won't be able to update that pkg using yay or whatever I guess...
584+
su "$(stat -c"%U" PKGBUILD)" -c "git switch - &>/dev/null"
585+
if ((build_failed)); then
586+
exit 1
587+
fi
588+
589+
item="$(find "$path" -maxdepth 1 -type f -name "$(sed -nr '/.*Finished making: ([^ ]+) ([^ ]+) .*/{s//\1-\2/;p}' makepkg.log)*" -print -quit)"
590+
rm makepkg.log
591+
popd >/dev/null
592+
fi
593+
printf "%s\0" "$item" >>new_to_install.downgrade
594+
}
595+
526596
cli() {
527597
local conf_args=()
528598

@@ -536,6 +606,14 @@ cli() {
536606

537607
# Proceed with rest of workflow
538608
main "${terms[@]}"
609+
if ((DOWNGRADE_FROM_GIT)); then
610+
for item in "${to_install[@]}"; do
611+
build_pkg "$item"
612+
done
613+
mapfile -d '' to_install <new_to_install.downgrade
614+
rm new_to_install.downgrade
615+
fi
616+
539617
pacman -U "${pacman_args[@]}" "${to_install[@]}"
540618
prompt_to_ignore "${to_ignore[@]}"
541619
}
@@ -545,6 +623,7 @@ PACMAN="pacman"
545623
PACMAN_CONF="/etc/pacman.conf"
546624
DOWNGRADE_ARCH="$(pacman-conf Architecture | head -n 1)"
547625
DOWNGRADE_ALA_URL="https://archive.archlinux.org"
626+
DOWNGRADE_FROM_GIT=0
548627
DOWNGRADE_FROM_ALA=1
549628
DOWNGRADE_FROM_CACHE=1
550629
DOWNGRADE_MAXDEPTH=1

test/search_git.t

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
$ source "$TESTDIR/helper.sh"
2+
> cache=$(mktemp -d)
3+
> git clone -q "https://aur.archlinux.org/downgrade.git" "$cache/downgrade"
4+
> write_pacman_conf "[options]" "CacheDir = $cache"
5+
> export DOWNGRADE_FROM_GIT=1
6+
7+
List packages based on git tags
8+
9+
$ search_git 'downgrade' | head -n 2
10+
/tmp/*/downgrade-5.1.3-0bdb507-any.gitpkg.tar.gz (glob)
11+
/tmp/*/downgrade-5.1.4-dee7bd9-any.gitpkg.tar.gz (glob)
12+
13+
Outputs appropriately for filter_packages
14+
15+
$ search_git 'downgrade' | filter_packages 'downgrade' '=~' '^7' | head -n 1
16+
/tmp/*/downgrade-7.0.0-513f504-any.gitpkg.tar.gz (glob)

0 commit comments

Comments
 (0)