Since the motivation is for backup and restore purposes, an alternative would be to run the script before running backup software, but it might be nice to keep it more frequently updated after each program installation/removal.
If once a day is sufficient, you could just adapt the old /etc/cron.daily/rpm script, at least conceptually. (I think it used to be āstandard equipmentā, like 20 Fedora releases ago. It would update a list of installed packages at /var/log/rpmpkgs once a day ā I still install a modified, more verbose version on all my systems, because I like to have that record locally.)
If updated-within-24-hours is too slow, thereās even /etc/cron.hourly, which would still let you avoid writing dnf plugins and whatnot just for that tiny bit of extra immediacy.
Hmm⦠a dnf plugin sounds like overkill. Also, would I really want to override transaction? I want to log only user-installed packages. Updates or system installed packages are not relevant and ideally should not trigger the script.
There is no /etc/cron.daily/rpm file on my system. I thought of a cron task, but that seems overkill too.
In the worst case I could just run the script before making updates. eg. vorta, a frontend to borgbackup, has a field for commands to run before and after a backup.
Not sure I really see how itās overkill, cron's kind of the path of least resistance for housekeeping tasks (which this is). If you want to keep your remote list updated, somethingās gotta update it. Either that happens automatically in response to changes, or regularly on a schedule. And if itās stored in Dropbox, itāll even handle versioning and checking whether there are any content changes each time the list gets written.
(Actually, Iād recommend something like the tempfile trick from that cron script: Run the command redirected to /tmp/something, then mv that file over the previous one in Dropbox. Output redirection that overwrites existing files doesnāt always sit well with the Dropbox sync daemon.)
By overkill I mean it would run far more often than needed, since packages arenāt often installed/removed. Granted, running it literally takes less than a secondā¦
Since the objective is for backups, I think Iāll just incorporate running the script into the backup routine, as frequent or infrequent as that may be.
Though, you could focus on the side benefits. If youāre running dnf once an hour to update your installed package list, youād probably spend a lot less time waiting for metadata refreshes at the beginning of dnf transactions, since the last run of the cron job would already have triggered a recent-enough update.
I donāt see why metadata needs to be refreshed to check the installed package list. I donāt think dnf repoquery --qf "%{name}" --userinstalled does that.
On a side note, how recent is recent enough for metadata refreshes not to be triggered?
It certainly shouldnāt need to be, and you may be right. Iāve gotten used to it refreshing before all sorts of operations, if itās been a while since the last refresh, but I donāt use it much for installed-only queries. (Iāll typically go straight to rpm, for those. However, --userinstalled is one of the reporting dimensions that rpm doesnāt know about, so that oneās a dnf repoquery exclusive.)
Your guess is as good as mine, there appears to be some sort of <jazzhands> algorithm </jazzhands> at work in making that decision. Iāve seen it refresh data that was mere minutes old, and Iāve seen it skip a refresh despite the cache being hours old.
Just now I experimentally ran a dnf repoquery --unneeded. (Which, as documented, will āDisplay only packages that can be removed by ādnf autoremoveā command.ā, so in theory it shouldnāt need remote repo data either.) dnf refreshed only the updates and rpmfusion-free-tainted repos, out of the 23 I have enabled, but not any of the rest. ĀÆ\_(ć)_/ĀÆ
A āsolutionā is always using --refresh, i.e. sudo dnf update --refresh. That way there is no surprise: it will always refresh metadata so updates can be enjoyed as quickly as possible.
Sorry Iām late and I havenāt any working example.
Going back to the original question, you can monitor a file when it changes, by using the Linux kernel subsystem called inotify.
There are various tools (dnf search inotify, incron looks interesting) in order to interact with it.
In practice, when a file (or a directory) is modified (or also accessed etc.) you can trigger a command. What file to monitor in your case? Well, I guess the file used by DNF to keep the transactions history (/var/lib/dnf/history.sqlite) could be a good candidate.
Yeah⦠Is there a file that tracks user installed packages? That distinction is important, since I see no point in tracking all (system) installed packages.
The rationale is to remember what packages I installed manually. Whatever system or dependency packages got automatically installed donāt matter, because if I were to reinstall or restore the OS, those would get sorted out on their own.
Well. I donāt know how to do it if you donāt have the initial list of the freshly installed OS.
Maybe tinkering with dnf history?
However, even if you have the list of all packages currently installed, it is not a problem to pass such list to dnf in a future OS fresh reinstallation: the already installed packages will be skipped.
As mentioned in the first post, dnf repoquery --qf "%{name}" --userinstalled works exactly as intended.
dnf history userinstalled is not ideal because it contains version, arch, and fedora release information instead of strictly the package name. That list wonāt work as-is in the future.
Keeping a list of all packages is also not good because system packages and dependencies may change. Reinstalling an old list may not work, or installed unnecessary packages.
I think we can consider this topic sufficiently explored. As it turns out, the first post already contains the best/simplest solution. Iām just surprised a better solution does not seem to exist.
As an answer to the specific issue here, not the general one of running a script after a command: the simplest one perhaps: just keep a list? I have this script that I continuously modify, for example: