Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

My newer-in-debian script

I wanted to use the really cool repology.org site to help track the packages I maintain in Devuan, so I don't get too behind. LeePen feels obligated to tell me when I'm behind, and that shouldn't be his job; I should be doing a better job.

So I wrote this script I can run whenever I feel like it.

files/2024/listings/newer-in-debian.sh (Source)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/bin/sh
# File: newer-in-debian.sh
# Location: /mnt/public/Support/Programs/repology.org/
# Author: bgstack15
# Startdate: 2023-12-28-5 17:42
# SPDX-License-Identifier: GPL-3.0-only
# Title: Newer in Debian script
# Purpose: List newer packages in debian than devuan that I maintain
# History:
# Usage: ./newer-in-debian.sh
# Reference:
#    https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux
#    https://repology.org/projects/?maintainer=bgstack15@gmail.com&inrepo=devuan_unstable&newest=1
# Improve:
# Dependencies:
#    req-devuan: jq, curl, devscripts
#    req-raw: jq, curl, rmadison
# Documentation: read repology

# CONFIG
test -z "${CACHE_DIR}" && CACHE_DIR="${XDG_CACHE_DIR:-${HOME}/.cache}"
test -z "${CACHE_FILE}" && CACHE_FILE="${CACHE_DIR}/newer-in-debian.cache"
test -z "${EMAIL}" && EMAIL=bgstack15@gmail.com
test -z "${RMADISON_URL_MAP_DEVUAN}" && export RMADISON_URL_MAP_DEVUAN=https://api.pkginfo.devuan.org/madison
BAD_COLOR='\033[0;31m' # red
GOOD_COLOR='\033[0;32m' # green
NEUTRAL='\033[0m' # no color

# CACHE OPERATIONS
# invalidate cache older than 23 hours
_cache_is_too_old="$( find "${CACHE_FILE}" -maxdepth 0 -mmin +$(( 60 * 23 )) -print -quit 2>/dev/null )"
test -n "${_cache_is_too_old}" && rm "${CACHE_FILE:-NOTHINGTODEL}"
test -n "${CLEAR_CACHE}" && rm "${CACHE_FILE:-NOTHINGTODEL}"

# test and rebuild cache if necessary
_cache_contents="$( cat "${CACHE_FILE}" 2>/dev/null )"
test -z "${_cache_contents}" && {
   curl --silent --header 'User-Agent: bgstack15-cli' "https://repology.org/api/v1/projects/?maintainer=${EMAIL}&inrepo=devuan_unstable" > "${CACHE_FILE}"
   _cache_contents="$( cat "${CACHE_FILE}" 2>/dev/null )"
} || {
   printf '%s\n' "Using cached package list." 1>&2
}

# if cache is still empty, then something broke with curl statement.
test -z "${_cache_contents}" && {
   printf '%s\n' "Fatal! Cache is still empty. Re-run with debugging. Aborted." 1>&2
   exit 1
}

# FUNCTIONS
_check_status() {
   package="${1}"
   # this only uses amd64. If I ever change personal architectures that I care about, I would need to update this.
   # The purpose is to avoid the "source" listing, which might not be the same version as a built architecture, due to binary repacks, e.g., lightdm_1.32.0-4+b1 in debian.
   # --source-and-binary converts "freeipa" source into "freeipa-client" amd64, and a few others but since the versions are all the same we just take the first one (head -n1)
   _deb="$( rmadison              --source-and-binary --architecture=amd64 --suite unstable "${package}" | awk -F'|' '{print $2}' | head -n1 | xargs | sed -r -e 's/\+b[1-9]$//;' )" ;
   # only do anything if the package exists in Debian.
   if test -n "${_deb}" ;
   then
      _dev="$( rmadison --url devuan --source-and-binary --architecture=amd64 --suite unstable "${package}" | awk -F'|' '{print $2}' | head -n1 | xargs | sed -r -e 's/\+b[1-9]$//;' )" ;
      _result="${BAD_COLOR}BAD${NEUTRAL}"
      echo "${_dev}" | grep -qE "${_deb}\+?devuan-?[0-9]" && {
         _result="${GOOD_COLOR}good${NEUTRAL}"
      }
      printf '%4b\t%s\t%s\t%s\n' "${_result}" "${package}" "${_deb}" "${_dev}"
   else
      printf '%4s\t%s\t\n' "none" "${package}" 1>&2
   fi
}

# MAIN
_package_list="$( <"${CACHE_FILE}" jq --raw-output 'keys[]' )"
# do not double-quote variable in next line with the for statement.
for package in ${_package_list} ;
do
   if test -n "${PARALLEL}" ;
   then
      _check_status "${package}" &
   else
      _check_status "${package}"
   fi
done
test -n "${PARALLEL}" && {
   wait
}

I use cache invalidation (which I hear is hard; I hope I did it right!). The web url is https://repology.org/projects/?maintainer=bgstack15@gmail.com&inrepo=devuan_unstable&newest=1. Some of these are original packages and don't have an upstream from Debian.

$ ./newer-in-debian.sh 
good    freeipa 4.10.2-2    4.10.2-2devuan1
good    lightdm 1.32.0-4    1.32.0-4devuan1
good    oddjob  0.34.7-2    0.34.7-2devuan1
none    pam-mkhomedir   
none    sgm 
none    systemctl-service-shim

I even added colors, and parallelization (but not really necessary now that we only run rmadison for Devuan if the rmadison for Debian returned anything), just for this blog post. You're welcome, future self.

Librewolf 121.0.1 now in OBS

I don't normally post on my blog merely when an application is updated in my OBS slice, but it's a big deal for this one because multiple pipeline problems have plagued this application.

I provide debianized LibreWolf sources so anyone can build his own package. I also use the public LibreWolf CI infrastructure to build the assets that then also get used by OBS to build the package.

Problem 1

The public (and only, that I know of) CI for librewolf hasn't worked in a few versions, and I haven't bothered to find my alt browser to sign in to whatever chat room it was to ask the LibreWolf folks what's up. I think it was a free instance or something and they probably reached their quota.

Problem 2

Due to the usrmerge drama in Debian, the OpenSUSE-focused Open Build Service doesn't have a great way to work with dpkgs. But finally, after enough project config modulations that include preinstall: systemd amongst a few other things, I can build packages again.

preinstall: usrmerge
prefer: usrmerge
prefer: libjpeg-dev, libjpeg62-turbo-dev
prefer: libjack-dev
prefer: libavcodec60
prefer: libavformat60
prefer: libavfilter9
Preinstall: libsystemd0
Preinstall: systemd

So I manually uploaded the 121.0.1 assets I built locally and dropped the _service file for now which tells the OBS worker node to fetch the publicly-built assets.

<services>
  <service name="download_url">
    <param name="protocol">https</param>
    <param name="host">storage.ci.librewolf.net</param>
    <param name="path">/artifacts/0/prepared/librewolf_120.0.1-1.debian.tar.xz</param>
    <param name="filename">librewolf_120.0.1-1.debian.tar.xz</param>
  </service>
  <service name="download_url">
    <param name="protocol">https</param>
    <param name="host">storage.ci.librewolf.net</param>
    <param name="path">/artifacts/0/prepared/librewolf_120.0.1-1.dsc</param>
    <param name="filename">librewolf_120.0.1-1.dsc</param>
  </service>
  <service name="download_url">
    <param name="protocol">https</param>
    <param name="host">storage.ci.librewolf.net</param>
    <param name="path">/artifacts/0/prepared/librewolf_120.0.1.orig.tar.xz</param>
    <param name="filename">librewolf_120.0.1.orig.tar.xz</param>
  </service>
</services>

And with my 3 manual assets, the package has now built. You're welcome, Infinity128, and everybody else!

An aside

The reason I use an alternate browser to visit the chat room with the LibreWolf guys is because it used to be gitter.im which used gitlab and wanted full access to your account, so I made a bgstack150 account on gitlab and used that to talk. I didn't want gitter.im having full access to whatever I have left on gitlab, so I used that alt account, and since it tied in SSO-like (read: Borg-like) to gitlab, I needed a different browser session and I've been too lazy to learn how to use multiple profiles in the same browser. But the last time I was in there, it was powered by matrix and is probably not necessary, but I still haven't bothered. The one other Librewolf CI project is alpine and that hasn't built in 2 months either so clearly they just weren't using it.

Codesign Powershell script

I work with some Powershell, and sometimes I even have to run Windows systems. Loading a function library was more complicated than it should have been, because I hadn't gotten my powershell script signed with a certificate. So here's how to do it with a valid cert.

$cert = (Get-ChildItem Cert:\localmachine\My -CodeSigningCert)[0]
Set-AuthenticodeSignature -File C:\Path\To\File.ps1 -Cert $cert -IncludeChain "All" -TimestampServer http://sha256timestamp.ws.symantec.com/sha256/timestamp

References

  1. How to Sign Digitally PowerShell Script With Code Signing.

Devuan Ceres and zenity that uses gtk3

I tend to use zenity for my basic dialog needs, and sometimes yad. I found out recently that zenity now looks like a child drew it (read: the GNOME people use it) instead of showing a real dialog box.

So after some poking around, I found out that I cannot just purge it: Steam depends on zenity, and that zenity now (as of version 4.0.0-1) depends on libgtk-4-0. So, I found using one of the more helpful Debian web pages which version of zenity still uses gtk3: 3.44.2-1.

So I whipped up an Open Build Service project for zenity, but of course due to the ridiculous usrmerge problems Debian has introduced (and SUSE doesn't show any knack or willingness to fix on their behalf; can you blame them?!) the project doesn't build.

So I built it myself and host it on my own internal package repository. And then I updated my set-my-repos.sh script with 2 new lines. Thankfully I wrote a function I can call again.

confirm_preferences "all" "zenity" "zenity" "release" "600" "3.44.2-1"
confirm_preferences "all" "zenity-common" "zenity-common" "release" "600" "3.44.2-1"

Which if you don't bother to click through to that previous post, makes two files on a system where you run the script:

# file /etc/apt/preferences.d/zenity
Package: zenity
Version: 3.44.2-1
Pin: release
Pin-Priority: 600
# file /etc/apt/preferences.d/zenity-common
Package: zenity-common
Version: 3.44.2-1
Pin: release
Pin-Priority: 600

Perhaps I should have forked the package and given it a higher version, and figured how to enforce the same version. The d/control already has Depends: zenity-common (= ${source:Version}) but somehow it doesn't take effect; I was able to install zenity=3.44.2-1 but it kept my zenity-common=4.0.0-1 which failed, because gtk4 changes the paradigms of gtk so much that they got rid of the /usr/share/zenity/ directory with its xml-defined ui (glade?) business.

Fluxbox handle capslock media keys

VLC lets you configure global hotkeys, so you can map your XF86AudioPrev and related keys. However, when my Capslock is on, my keyboard sends different keycodes. Here's my fix for that.

I wrote a shell script to handle the logic.

files/2024/listings/vlc-command (Source)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/sh
# Startdate: 2024-01-01-2 14:36
# Purpose: to be a hotkey target for when CapsLock is on but I still press "Play/Pause" media button on the keyboard.
# Usage:
#    In ~/.fluxbox/keys:
#    # For capslock, media previous, pause, skip
#    171 :Exec bin/vlc-command skip
#    172 :Exec bin/vlc-command play-pause
#    173 :Exec bin/vlc-command previous

case "${1}" in
   "play-pause")
      dbus-send --type=method_call --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause
      ;;
   "previous"|"back"|"left")
      dbus-send --type=method_call --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Previous
      ;;
   "next"|"skip"|"right")
      dbus-send --type=method_call --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Next
      ;;
esac

And then in my ~/.fluxbox/keys file I added these statements:

# For capslock, media previous, pause, skip
171 :Exec bin/vlc-command skip
172 :Exec bin/vlc-command play-pause
173 :Exec bin/vlc-command previous

I derived these of course with xev(1).

Errata

And the reason I sometimes end up with capslock on is I always use capslock to help wake on a monitor. I thought it was an XKCD comic that pointed out that Windows admins would use Ctrl+Alt+Delete to wake up a system, and that by default that reboots a Linux system, so when I have switched over to using all-Linux years ago, I use other methods (Capslock) to see if a system is awake/locked.

Undocumented feature of update-repo

In my newly improved apt-based update-repo function, there is a neat feature I failed to describe elsewhere.

Because the function looks for files in /etc/apt/sources.list.d/ that match glob ${NAME}.list, you can run update-repo with:

update-repo ../sources

And it will update the normal Devuan repositories. I really should have put that in the documentation somewhere. Well, here it is now.

Improved update-repo for apt

I've updated my update-repo command for Debian-based distros, to display the available packages to update from the targetted repository. Also, I've adjusted the autocomplete to handle colons in the filenames, e.g., /etc/apt/sources.list.d/file:name.list. It will need to escape a colon with a slash, but accomplish what you want.

I updated this because my update-repo for rpm-based distros already shows the available updates.

# File: /usr/share/bgscripts/bashrc.d/debian.bashrc
# update-repo command for apt-get update just one repository
update-repo() {
   for source in "$@"; do
      sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/${source}.list" \
         -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"
      sudo apt-get -u upgrade -V --assume-no -o Dir::Etc::sourcelist="sources.list.d/${source}.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" | sed -n -r -e "/=>/s#^#${source}: #p;"
   done
}
# autocomplete for update-repo
_ppa_lists() {
   local cur
   _init_completion || return
   COMPREPLY=( $( find /etc/apt/sources.list.d/ -name "*${cur}*.list" \
      -exec basename {} \; 2>/dev/null | sed -r -e 's!\.list$!!;' -e 's/:/\\:/g;' 2>/dev/null ) )
   return 0
} &&
complete -F _ppa_lists update-repo

References

Weblinks

  1. package management - apt-get update only for a specific repository - Ask Ubuntu

Fedora sshd_config locale

Devuan includes this by default, but Fedora does not. There's probably good reasons. I'll take "Upstream doesn't package it that way" as a good reason!

files/2023/12/listings/allow-ssh-locale.sh (Source)

#!/bin/sh
# Startdate: 2023-12-14-5 10:17
# Reference:
#    https://stackoverflow.com/questions/29609371/how-not-to-pass-the-locale-through-an-ssh-connection-command
# Documentation:
#    Not needed for Devuan because this AcceptEnv is already in the default file sshd_config
tf="/etc/ssh/sshd_config.d/30-locale.conf"
test ! -f "${tf}" && touch "${tf}"
grep -qE '^AcceptEnv.*LC_\*' "${tf}" 1>/dev/null 2>&1 || {
   printf "%s\n" 'AcceptEnv LANG LC_*' >> "${tf}"
   systemctl reload sshd
}