Skip to main content

lsupg Progress

I have made some progress on lsupg over the past few days. I made significant changes to the (internal) design as well as the (external) interface. Here is the current CLI:

Usage: lsupg [--debug] [-f|--format FORMAT] [--docker IMAGE] [COMPONENT ...]
  list items that can be upgraded

Available options:
  -h,--help                show help and exit
  --version                show version and exit
  --debug                  show debug output
  -f,--format FORMAT       output format (default: human)
  --docker IMAGE           Docker image
  COMPONENT ...            components (default: all)

FORMATs:
  human, csv, json, yaml

COMPONENTs:
  apk     Alpine Linux packages
  apt     Debian packages
  dnf     Fedora packages
  nix     Nix packages
  pacman  Arch Linux packages

Exit codes:
  0  no upgrades available
  1  program error
  2  program usage error
  3  one or more upgrades available

Components

apk

Parsing apk output is very straightforward. I do not know what the output looks like in the case that an upgrade requires the installation of a new package, however. Currently, the new package will simply not be listed.

Demonstration:

[lsupg] build$ ./lsupg --docker alpine:latest
apk  musl        1.2.2-r0  1.2.2-r1
apk  musl-utils  1.2.2-r0  1.2.2-r1

apt

Parsing apt output is very straightforward. New packages that are to be installed as a dependency of an upgrade are parsed correctly.

Demonstration:

[lsupg] build$ ./lsupg --docker debian:buster
apt  liblz4-1  1.8.3-1  1.8.3-1+deb10u1

dnf

Parsing dnf output is very straightforward, but it unfortunately does not include the version that is currently installed. This information could be obtained by running additional commands, but I am currently simply not showing that information. I also do not know what the output looks like in the case that an upgrade requires the installation of a new package. Currently, the new package will simply not be listed.

The dnf software is a replacement for yum, which it a replacement for rpm. In the fedora:34 image, either dnf or yum can be used to manage installed packages! Currently, I am just supporting dnf. If I find a system that still uses yum, I will implement support for it. In doing so, I should only run yum in cases where dnf has not already been run. If rpm support is added, it will likely need similar checks. There are various ways to implement this, but I will not worry about it until I have a need to do so.

Most Linux package managers have separate “update” and “upgrade” steps. The “update” step synchronizes the package database, and the “upgrade” step uses this database to determine which packages should be upgraded. Automated tools usually have a setting to avoid doing the “update” step too frequently, and the initial lsupg design included such an --update flag. The dnf software does not match this design, however, as it has the functionality built in. There is likely a setting in /etc/dnf to configure. Considering the options, I decided to remove the --update flag completely.

Demonstration:

[lsupg] build$ ./lsupg --docker fedora:34
dnf  coreutils.x86_64                      8.32-27.fc34
dnf  coreutils-common.x86_64               8.32-27.fc34
dnf  curl.x86_64                           7.76.1-4.fc34
dnf  dnf.noarch                            4.7.0-1.fc34
dnf  dnf-data.noarch                       4.7.0-1.fc34
dnf  elfutils-default-yama-scope.noarch    0.185-2.fc34
dnf  elfutils-libelf.x86_64                0.185-2.fc34
dnf  elfutils-libs.x86_64                  0.185-2.fc34
dnf  file-libs.x86_64                      5.39-6.fc34
dnf  glib2.x86_64                          2.68.2-1.fc34
dnf  glibc.x86_64                          2.33-15.fc34
dnf  glibc-common.x86_64                   2.33-15.fc34
dnf  glibc-minimal-langpack.x86_64         2.33-15.fc34
dnf  gnutls.x86_64                         3.7.2-1.fc34
dnf  krb5-libs.x86_64                      1.19.1-8.fc34
dnf  libcurl.x86_64                        7.76.1-4.fc34
dnf  libdnf.x86_64                         0.62.0-1.fc34
dnf  libgcc.x86_64                         11.1.1-3.fc34
dnf  libgomp.x86_64                        11.1.1-3.fc34
dnf  libidn2.x86_64                        2.3.1-1.fc34
dnf  librepo.x86_64                        1.14.0-1.fc34
dnf  libreport-filesystem.noarch           2.15.2-2.fc34
dnf  libsss_idmap.x86_64                   2.5.0-2.fc34
dnf  libsss_nss_idmap.x86_64               2.5.0-2.fc34
dnf  libstdc++.x86_64                      11.1.1-3.fc34
dnf  libtirpc.x86_64                       1.3.2-0.fc34
dnf  libxml2.x86_64                        2.9.12-4.fc34
dnf  libzstd.x86_64                        1.5.0-1.fc34
dnf  mpfr.x86_64                           4.1.0-7.fc34
dnf  python-pip-wheel.noarch               21.0.1-3.fc34
dnf  python3.x86_64                        3.9.5-2.fc34
dnf  python3-dnf.noarch                    4.7.0-1.fc34
dnf  python3-hawkey.x86_64                 0.62.0-1.fc34
dnf  python3-libdnf.x86_64                 0.62.0-1.fc34
dnf  python3-libs.x86_64                   3.9.5-2.fc34
dnf  sssd-client.x86_64                    2.5.0-2.fc34
dnf  systemd-libs.x86_64                   248.3-1.fc34
dnf  tpm2-tss.x86_64                       3.1.0-1.fc34
dnf  vim-minimal.x86_64                    2:8.2.2956-1.fc34
dnf  yum.noarch                            4.7.0-1.fc34
dnf  zchunk-libs.x86_64                    1.1.15-1.fc34

nix

Parsing nix output is not as straightforward. The issue is that it does not display package names and versions separately. For example, it displays nix-2.3.11 instead of nix and 2.3.11. Unless there are specific rules about package names and versions, it is impossible to parse perfectly. Currently, I split one the - character and assume that the version starts at the first chunk that starts with a digit. I may need to change this implementation in the future. Due to the way that Nix works, new packages are not (should not be) listed.

Demonstration:

[lsupg] build$ ./lsupg --docker nixos/nix:latest
apk  musl        1.2.2-r0  1.2.2-r1
apk  musl-utils  1.2.2-r0  1.2.2-r1
nix  nix         2.3.11    2.3.12

Notice that apk packages are listed as well, as the nixos/nix image is built using Alpine Linux.

pacman

Parsing pacman output is very straightforward. I do not know what the output looks like in the case that an upgrade requires the installation of a new package, however. Currently, the new package will simply not be listed.

Demonstration:

[lsupg] build$ ./lsupg --docker archlinux:latest
pacman  ca-certificates          20181109-4    20210603-1
pacman  ca-certificates-mozilla  3.64-1        3.67-1
pacman  ca-certificates-utils    20181109-4    20210603-1
pacman  cryptsetup               2.3.5-4       2.3.6-1
pacman  curl                     7.76.1-1      7.77.0-1
pacman  expat                    2.3.0-1       2.4.1-1
pacman  file                     5.40-3        5.40-5
pacman  filesystem               2021.01.19-1  2021.05.31-1
pacman  gcc-libs                 10.2.0-6      11.1.0-1
pacman  glibc                    2.33-4        2.33-5
pacman  gnutls                   3.7.1-1       3.7.2-2
pacman  kmod                     28-1          29-1
pacman  libcap                   2.49-1        2.50-2
pacman  libelf                   0.184-1       0.185-1
pacman  libidn2                  2.3.0-1       2.3.1-1
pacman  libldap                  2.4.58-2      2.4.58-3
pacman  libnftnl                 1.1.9-1       1.2.0-1
pacman  libnl                    3.5.0-2       3.5.0-3
pacman  libp11-kit               0.23.22-1     0.24.0-1
pacman  libpcap                  1.10.0-1      1.10.1-1
pacman  libtasn1                 4.16.0-1      4.17.0-1
pacman  libtirpc                 1.3.1-1       1.3.2-1
pacman  libxcrypt                4.4.20-1      4.4.22-4
pacman  linux-api-headers        5.10.13-1     5.12.3-1
pacman  lz4                      1:1.9.3-1     1:1.9.3-2
pacman  nettle                   3.7.2-1       3.7.3-1
pacman  p11-kit                  0.23.22-1     0.24.0-1
pacman  pacman                   5.2.2-3       6.0.0-3
pacman  pambase                  20200721.1-2  20210605-2
pacman  pcre2                    10.36-1       10.37-1
pacman  sqlite                   3.35.5-1      3.35.5-2
pacman  systemd                  248.2-2       248.3-2
pacman  systemd-libs             248.2-2       248.3-2
pacman  systemd-sysvcompat       248.2-2       248.3-2
pacman  util-linux               2.36.2-1      2.37-3
pacman  util-linux-libs          2.36.2-1      2.37-3
pacman  zstd                     1.4.9-1       1.5.0-1

Output Formats

human

The human format is for when a human reads the output in the terminal or when only the exit code is used. It displays a table with the following columns. Note that the headings are not displayed.

Column Heading Description
1 Component Name lsupg component
2 Item Name thing that can be upgraded
3 Installed Version version that is currently installed
4 Available Version version available for upgrade

The installed version and available version may be empty. I would like to use the following interpretations:

Installed Version Available Version Interpretation
Shown Shown upgrade/downgrade
Shown Empty removal
Empty Shown new install

Unfortunately, the current implementation of the dnf component does not include the installed versions of packages. I either need to get that information or not use these interpretations.

Demonstration:

[lsupg] build$ ./lsupg --docker alpine:latest
apk  musl        1.2.2-r0  1.2.2-r1
apk  musl-utils  1.2.2-r0  1.2.2-r1

csv

The csv format displays the information in CSV format.

Demonstration:

[lsupg] build$ ./lsupg --docker alpine:latest -f csv
apk,musl,1.2.2-r0,1.2.2-r1
apk,musl-utils,1.2.2-r0,1.2.2-r1

json

The json format displays the information in JSON format. Since it is intended to be machine-parsed, it it minimized.

Demonstration, with external reformatting for humans:

[lsupg] build$ ./lsupg --docker alpine:latest -f json | python3 -m json.tool
[
    {
        "available_version": "1.2.2-r1",
        "installed_version": "1.2.2-r0",
        "item_name": "musl",
        "component_name": "apk"
    },
    {
        "available_version": "1.2.2-r1",
        "installed_version": "1.2.2-r0",
        "item_name": "musl-utils",
        "component_name": "apk"
    }
]

yaml

The yaml format displays the information in YAML format.

Demonstration:

[lsupg] build$ ./lsupg --docker alpine:latest -f yaml
- available_version: 1.2.2-r1
  installed_version: 1.2.2-r0
  item_name: musl
  component_name: apk
- available_version: 1.2.2-r1
  installed_version: 1.2.2-r0
  item_name: musl-utils
  component_name: apk
Author

Travis Cardwell

Published

Tags