Is there an elegant way to uninstall a bunch of automatically installed packages?

I have a script that automatically checks if all binaries used by that script are available on that system and if not, it searches for - and installs the packages providing the missing binaries.

Now I would like to give the user of that script the option to undo everything that the script installed, but the problem is that if for example the script installs wget and later the user decides to install wget independently of the script, my script would have no way of knowing that it shouldn’t remove wget when uninstalling its own dependencies.

Any ideas how I could achieve that without too much effort?

I was thinking about creating an rpm package, but my script is pretty complex and configurable. Depending on the configuration the script does install different packages.
So if I were to do this using an rpm package, I’d have to generate that dynamically during runtime which seems very complicated.

1 Like

Not really—if your script needs to undo what it did, it’ll need to keep track of what it did. If the script also has to take into account packages that a user may install later, that’s even harder—you need to keep track of what your script installed, then check the rpm/dnf database to verify if a package was installed by your script or separately by the user.

dnf has quite a detailed API, so all of this is doable—you can read the transaction history, figure out what was installed when and so on:

https://dnf.readthedocs.io/en/latest/api.html

This is assuming everything goes through dnf. If it goes through rpm, you’ll have to ues the rpm API etc.

I don’t quite see how making an rpm of the script contributes here—an rpm is merely an archive, like a zip file that contains the files of a built software. Can you clarify this?

1 Like

Okay thanks, I’ll look into this.
I was thinking about creating an rpm package because I was assuming that when you install an rpm package, dnf would remove its dependencies, but only those that haven’t been installed directly as well.

Ah, right. So, you’d make the packages you want to install be “Required” by this rpm package. Yes, that would work for installation. For uninstallation though, I think dnf would only remove packages that aren’t in use by anything else.

One way of undoing an install is to undo the dnf transaction (see man dnfhistory), but this may not work if lots of other transactions have already been made.

I use a script to install packages I need, but I don’t care about removing these at all, so it’s not as complex:

Yes, but that would be exactly what I want.

If the user wants to “uninstall” my script, it should automatically remove all dependencies it installed, but exclude the ones that have either been installed directly by the user or still have other packages relying on them.

1 Like

I should’ve written that better—dnf would only remove dependencies (libraries etc.) that aren’t in use by any installed packages that haven’t been explicitly asked to be removed. So, for example, let’s say your script or whatever installed A which pulled in B and C as dependencies. Later some other package D was installed that also uses B and C as dependencies. So when you later try to remove only A, dnf will see that B and C are still being used by D, so it won’t remove them but it will remove A. If you ask dnf to remove D later, B and C will also be removed if they’re not being used by anything else. (Note that explicitly trying to remove B will also try to remove A and D, since they can’t be used without B).

But this isn’t quite useful in your case where you want to check who installed the package and remove it only if it was installed by your script or whatever. dnf doesn’t care about who installed a package or when the package was installed. All it cares about is ensuring that the dependencies of all installed packages are satisfied. So, somehow, you will need to check what your script installed.

Maybe you can just keep a list of packages your script installed somewhere as an rc file: ~/.myscriptrc. Later when removing, you read from the list.

It isn’t perfect, though—what if a user manually removes something that was in the list but then later reinstalls it? Should that be removed when your script is “undone”? If not, how does your list remain up to date? There are far too many usage paths here where the user can do what they wish with dnf which make tracking of “what did the script install” quite a problem.

The only way to achieve this, is to centralize software installation and to revoke from a normal user all privileges to install any software. You can create a simple database where you register every software changes and so you can easy revert all software actions. This is a so called repository driven approach that lives for a long time now on mainframe systems (e.g. IBM System Z): there a user can’t install software and this is a centralized task for an Sysadmin. For further informations read an IBM System-Administration guide and follow the strategy in Fedora.