How to replicate installed package selection from one Fedora instance to another?

Since Fedora 26, the Dnf repoquery subcommand supports has a new option for listing all user-installed packages:

$ dnf repoquery --qf '%{name}' --userinstalled \
 | grep -v -- '-debuginfo$' \
 | grep -v '^\(kernel-modules\|kernel\|kernel-core\|kernel-devel\)$' > pkgs_a.lst

In contrast to other methods, it also lists all debuginfo packages. The additional grep in the above example filters them out.

To install the list on host B:

$ < pkgs_a.lst xargs dnf -y install

Dnf API

With recent Dnf versions (e.g. Fedora >= 23), the package database can be queried for user installed package names via the Dnf Python API:

$ python3 -c 'import dnf; b = dnf.Base(); b.fill_sack(); \
  l = sorted(set(x.name for x in b.iter_userinstalled() \
       if not x.name.endswith("-debuginfo") \
          and x.name not in \
             ["kernel-modules", "kernel", "kernel-core", "kernel-devel"] )); \
  print("\n".join(l)) ' > pkgs_a.lst

# dnf install $(cat pkgs_a.lst) # on host_b

By default, dnf install aborts if one or more packages aren't available anymore. Alternatively, dnf can be forced to install all remaining ones:

# dnf install --setopt=strict=0 $(cat pkgs_a.lst) # on host_b

PS: Put the above code and more into user-installed.py that also supports other distributions.

history userinstalled

On Fedora 23 and later, Dnf provides the

# dnf history userinstalled

command that lists all user installed packages. As of 2016-11, its usefulness is limited because there is no way to control its output and it prints packages fully qualified (i.e. including version information).

userinstalled Limitations

Note that the marking of packages as user-installed has some limitations on some Fedora versions, for Fedora 23-ish era systems (from around 2015-11) the following issues are relevant):

  • packages installed via the GUI are not included
  • packages installed via the command-not-found handler are not included
  • some packages installed by default (by anaconda) are included

Repoquery

On older Fedora systems, where Dnf, the Dnf API and dnf history userinstalled aren't available, one can use repoquery instead, e.g.:

$ repoquery --installed \
     --qf '%{n} | %{yumdb_info.reason} | %{yumdb_info.installed_by}' --all \
    | awk -F'|' ' $2 ~ /user/ && ($3 != 4294967295) { print $1 }'  \
    | sort -u > pkgs_a.lst

The second awk condition is used to exclude packages that were installed by the installer. The installer's user-id was apparently stored as 4294967295 - alternatively you can write something like ($3 == 0 || $3 == your-user-id).

Note that this command works on Fedora up to release 21 - but e.g. not on release 23, because the command repoquery was replaced with dnf repoquery. And dnf repoquery does not understand the %{yumdb_info.reason} tag.


The easiest way, and it's worked for a long time is:

yum-debug-dump => gives file.

yum-debug-restore <file-from-debug-dump>

...which works much like the get/set selections dpkg command, AIUI. Also note that if you are replaying history you can use:

yum history addon-info last saved_tx => gives file
yum load-tx <file-from-addon-info>

...instead of having to parse it yourself.


Inspired by slm's answer I've come up with following yum history based solution:

Get all detailed history on all yum install transactions (i.e. no upgrades), excluding those execited as part of initial installer actions (transactions 1 and 2 on my system, attributed to user 'System'):

$ yum history list all | awk -F'|' \
                            '$4 ~ /Install/ && $2 !~ /System/ {print $1}' \
    | xargs yum history info > yum_history

Filter explicitly installed packages and cut off version prefixes.

$ < yum_history grep '[^-]\<Install\>' | \
  awk '{ print $2 }' \
  | sed 's/\(-[0-9]\+:\|-[0-9]\+\.[0-9]\|-[0-9]\+-\|-[0-9]\+git\).\+\(\.fc1[1-7]\.\|\.noarch\).*$//' \
  | sort > hist_pkg_list

The ugly regular expression is needed such that all kinds of version suffixes are matched.

The results look quite fine on my system.

A comparison against the repoquery ansatz (on my system):

method         # packages
―――――――――――――――――――――――――
repoquery      569
repoquery-2nd  216
yum history    214

(I piped the repoquery results through sort -u)

Why are there differences? Because repoquery includes all the packages from transactions 1 and 2, i.e. all packages which were installed by the Fedora installer. This explains why repoquery includes the mentioned packages xorg-x11- drv-mga and friends.

Comparing repoquery-2nd and yum-history shows that repoquery-2nd is more accurate - it does not include some already removed packages. In addition it includes a few (2 on my system) packages from 'yum update'-operations, it seems.

Warning

The above history-based method only lists all explicitly installed packages over the complete lifetime of the system. It does not balance out those packages which were removed in a later transaction. Thus, this method needs some manual curating of the results and should only be used on systems were repoquery is not available.

Tags:

Fedora

Yum

Dnf