Following this topic, here’s a technique that allows you to add free text to the database of your installed packages.
Since Pacman 6, there are free fields available in our packages. Here, we will make a slight detour of this functionality.
The idea is to create a simple text file with comments to insert into our packages. Example of pkg-note.text:
# remove comment
wxwidgets-common =
# add or update comments
python-ujson = not useful ?
python-rich = i love it !
python-selenium = AUR package :( == bad
These comments are injected into our local database using a simple Pacman hook. With each installation/update, the hook will read our pkg-note.txt
file and update our local database.
To read these comments, currently, only pacman -Qii
allows it.
pacman -Qii python-selenium
...
Extended Data : pkgtype=pkg
note=AUR package :( == bad
Installation:
- Place the 3 files in the same directory.
- Create symbolic links for the hook and its script. (sometime create /hooks.bin/ directory)
- Update your text file (before update/install packages).
chmod +x pkg-note.py
sudo ln -s $PWD/pkg-note.hook /etc/pacman.d/hooks/pkg-note.hook -f
sudo ln -s $PWD/pkg-note.py /etc/pacman.d/hooks.bin/pkg-note.py -f
Save comments without pacman action?
echo -e "wxwidgets-common \n python-rich" | sudo ./pkg-note.py
hook file
#/etc/pacman.d/hooks/pkg-note.hook
[Trigger]
Operation = Upgrade
Operation = Install
Type = Package
Target = *
[Action]
Description = Manage comments
When = PostTransaction
Exec = /etc/pacman.d/hooks.bin/pkg-note.py
NeedsTargets
script file
#!/usr/bin/env python
from pathlib import Path
import subprocess
import sys
KEY_ALPM = "%XDATA%"
KEY = "note"
path = Path(__file__).resolve(True).parent
DATABASE = path / "pkg-note.txt"
def where_is_desc(pkg):
"""/var/lib/pacman/local/pacman-6.1.0-7/desc"""
proc = subprocess.run(f"/usr/bin/pacman -Q {pkg}", shell=True, capture_output=True, text=True)
if proc.stderr:
return
version = proc.stdout.split()[1]
try:
return next(Path("/var/lib/pacman/local/").glob(f"{pkg}-{version}*/desc"))
except StopIteration:
pass
def change_content(data:str, new_value, key=KEY) -> str:
""" add, change or delete key """
if KEY_ALPM not in data and new_value:
data = f"{data}\n{KEY_ALPM}\n{key} = {new_value}\n"
else:
lines = data.splitlines()
if KEY_ALPM in lines:
i = lines.index(KEY_ALPM)
content = [l for l in lines[i:] if l]
if [l for l in content if l.startswith(f"{key}=")]:
l = next(l for l in content if l.startswith(f"{key}="))
if new_value:
data = data.replace(l, f"{key}={new_value}")
else:
data = data.replace(l, "")
elif new_value:
content = "\n".join(content)
data = data.replace(content, f"{content}\n{key}={new_value}")
return data
if __name__ == "__main__":
notes = {}
with open(DATABASE, 'r') as file_:
for line in file_:
try:
if line and not line.startswith("#") :
key, value = line.split("=", maxsplit=1)
notes[key.strip()] = value.strip().replace('=','=')
except ValueError as err:
print("BAD", DATABASE, "file")
print("line:", line)
print(err)
if not notes:
exit(0)
for line in sys.stdin:
line = line.strip()
if line in notes:
if desc := where_is_desc(line):
if data := change_content(desc.read_text(), notes[line], key=KEY):
desc.write_text(data)
print(f" # {desc} modified")
Useful?
I don’t know. But it’s a good proof of concept and it might give some ideas to developers.