19

I have a Fedora system (A) where I have installed some packages over the time. Now I want to install Fedora on another computer (B) and I want to install the same packages on it.

In Debian terms I want to accomplish something like this:

$ dpkg --get-selections > pkg_sel_host_a  # on host_a
$ dpkg --set-selections < pkg_sel_host_a  # on host_b

But to be honest, I really want a better method to select the same packages on the new Fedora 19 system (B): I just want to install the packages from system A that were explicitly mentioned on a dnf install (or yum install) command line - and not those that were installed as dependencies!

Why? Because perhaps dependencies have changed - and I don't want to install outdated dependencies on the new system. Plus, when I remove packages I want to remove the (possibly) then unneeded automatically installed dependencies (i.e. orphans) as well.

I've found dnf list installed - but it does not display if a package was explicitly selected or just installed because of a dependency.

How do I get that information on Fedora?

What is the Fedora/dnf way to replicate package selections?

maxschlepzig
  • 57,532

7 Answers7

15

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):

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.

maxschlepzig
  • 57,532
  • I'm not sure if this approach will get everything, I noticed these on my system when I ran repoquery ...: "Invalid yumdb querytag 'reason' for installed pkg: HandBrake-cli-0.9.5-1.fc14.x86_64" – slm Jul 13 '13 at 15:41
  • @slm, hm, from what repository was handbrake installed? Perhaps the repository setup has something to do with it? – maxschlepzig Jul 13 '13 at 16:24
  • I think it might have been a standalone RPM that I installed using yum localinstall .... I had a fair amount of packages that fell into that camp though. – slm Jul 13 '13 at 16:35
  • repoquery --installed --qf '%{n} - %{yumdb_info.reason}' --all 2>&1|grep -v "user$"|grep -v "dep$" |wc -l returned 90 packages. – slm Jul 13 '13 at 16:39
7

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.

James Antill
  • 1,973
3

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.

maxschlepzig
  • 57,532
  • Nice way to take the best of both our answers! I'd give you more than a +1 if I could for the eventual solution + the nice comparison of the various ways to do it. – slm Jul 13 '13 at 22:53
2

I have an older version of Fedora (14) so my yum includes a less feature rich version of yum, but you might want to take a look at the yum history feature. I believe you can get the info you're looking for from that command.

history list

$ sudo yum history list
Loaded plugins: langpacks, presto, refresh-packagekit
Adding en_US to language list
ID     | Login user             | Date and time    | Action(s)      | Altered
-------------------------------------------------------------------------------
   862 | System <unset>         | 2013-07-12 18:00 | Install        |    1   
   861 | System <unset>         | 2013-07-09 03:11 | Install        |    1   
   860 | System <unset>         | 2013-07-01 13:40 | Install        |    1   
   859 | System <unset>         | 2013-06-29 22:07 | Install        |    1   
   858 | System <unset>         | 2013-06-25 22:33 | Install        |    1 P<
   857 | System <unset>         | 2013-06-23 22:28 | Update         |    1 >E
   856 | System <unset>         | 2013-06-23 21:33 | Install        |    1   
   ...

You can go back to the very first transaction by passing a list of numbers to yum history list:

$ sudo yum history list `seq 1 10`
Loaded plugins: langpacks, presto, refresh-packagekit
Adding en_US to language list
ID     | Login user             | Date and time    | Action(s)      | Altered
-------------------------------------------------------------------------------
    10 | Sam M. (local) <saml>  | 2010-12-18 23:23 | Install        |    2   
     9 | Sam M. (local) <saml>  | 2010-12-18 23:15 | Install        |   38   
     8 | Sam M. (local) <saml>  | 2010-12-18 23:12 | Install        |    1   
     7 | Sam M. (local) <saml>  | 2010-12-18 23:09 | Install        |    1  <
     6 | Sam M. (local) <saml>  | 2010-12-18 22:37 | Install        |    1 > 
     5 | Sam M. (local) <saml>  | 2010-12-18 21:57 | Install        |    1   
     4 | System <unset>         | 2010-12-18 21:21 | Install        |    5   
     3 | System <unset>         | 2010-12-18 21:18 | Install        |    4   
     2 | System <unset>         | 2010-12-18 21:10 | Install        |    3   
     1 | System <unset>         | 2010-12-18 19:14 | Install        | 1189

history info

The following will show you what was installed as part of the 1st yum transaction:

$ sudo yum history info 1 | less
Loaded plugins: langpacks, presto, refresh-packagekit
Adding en_US to language list
Transaction ID : 1
Begin time     : Sat Dec 18 19:14:05 2010
Begin rpmdb    : 0:da39a3ee5e6b4b0d3255bfef95601890afd80709
End time       :            19:42:43 2010 (1718 seconds)
End rpmdb      : 1189:8c21e9e377c3ebdee936916208f74232d5d6235f
User           : System <unset>
Return-Code    : Success
Transaction performed with:
Packages Altered:
    Dep-Install ConsoleKit-0.4.2-3.fc14.x86_64
    Dep-Install ConsoleKit-libs-0.4.2-3.fc14.x86_64
    Dep-Install ConsoleKit-x11-0.4.2-3.fc14.x86_64
    Dep-Install GConf2-2.31.91-1.fc14.x86_64
    Dep-Install GConf2-gtk-2.31.91-1.fc14.x86_64
    Dep-Install ModemManager-0.4-4.git20100720.fc14.x86_64
    Install     NetworkManager-1:0.8.1-10.git20100831.fc14.x86_64
    Dep-Install NetworkManager-glib-1:0.8.1-10.git20100831.fc14.x86_64
    Install     NetworkManager-gnome-1:0.8.1-10.git20100831.fc14.x86_64
    Install     NetworkManager-openconnect-0.8.1-1.fc14.x86_64

Notice how yum reports whether a package was explicitly installed or installed because it was needed by a dependency. You could parse this info and get your list of packages that were explicitly installed.

slm
  • 369,824
  • I've added an answer based on your yum history idea, it also compares the results against the repoquery based method. As a side-effect I've extended my repoquery answer. – maxschlepzig Jul 13 '13 at 19:20
1
dnf repoquery --qf "%{name}" --userinstalled > userinstalled.txt
Flo
  • 11
  • 1
    As you look over the other 5 answers here, what do you notice that is different about your answer? There is absolutely no explanation of why or how your answer is better of different. It would be good if you could provide some description of you answer that covers these things. – Stephen Rauch Dec 21 '17 at 19:12
  • @StephenRauch, this command isn't included in the other answers, because it's a recent dnf addition. The --userinstalled switch was just added to dnf in May. I've tested it, and it gives accurate results. Modulo the kernel/kernel-core/kernel-modules packages which aren't really user-installed. It also also contains all *-debuginfo packages - but they can be easily filtered out, if necessary. – maxschlepzig Dec 22 '17 at 13:12
  • @maxschlepzig, thanks for the feedback, but this was actually a bit of a rhetorical question, trying to educate/prompt the answer-er into explaining that in the answer. – Stephen Rauch Dec 22 '17 at 16:32
  • @StephenRauch, fair enough, some editing certainly would be appropriate and would allow me to mark it as accepted answer. – maxschlepzig Dec 22 '17 at 16:36
0

To list packages you have installed, try this one-liner:

alias yum-userinstall="yumdb search command_line install* | grep command_line\ = | sort | uniq | sed -r -e 's/command_line = (.*)/yum \1/g'"

Result:

# yum-userinstall
     yum install bind-utils
     yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
     yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
     yum install lsof
     yum install nano
     yum install nfs-utils libnfsidmap
     yum install nmap-ncat
     yum install openscap-scanner
     yum install open-vm-tools

PS1: it doesn't show dependencies

PS2: it is sorted alphabetically

PS3: it doesn't show if you have removed the package later

-1

What I did (forgot the details, and I'm a lazy bum, so...

Get all installed packages: rpm -qa > file

Use sed(1) to get rid of version numbers and such (keep the architecture, if required). This required a few iterations to get it right, you want to replace the last stretch of -[0-9.]-[0-9].fc23 or similar by nothing, but there are funny version "numbers" too.

After installing as normal, do a yum -y install $(< file) (or dnf, as required).

You'll get some fallout of packages that don't exist anymore, or changed name, or were replaced by others.

vonbrand
  • 18,253
  • Ok, but this will mark all previously installed packages as user-intalled on the destination host. Even if they originally were only installed as a dependency. – maxschlepzig Feb 19 '16 at 06:48