Handling FreeBSD package upgrades using pkg_add

I'm trying to use FreeBSD's pkg_add command to install and upgrade binary packages in a build-once-install-on-multiple-machines sort of scenario. It works well when installing a new package, but upgrades are baffling me. For example, if I want to upgrade a package that is depended on by another package, I can't just install it:

# pkg_add /path/to/somepackage-2.0.tbz
pkg_add: package 'somepackage' or its older version already installed

At this point, I can delete the older version of the package if I pass -f to the pkg_delete command:

# pkg_delete -f somepackage-1.0
pkg_delete: package 'somepackage-1.0' is required by these other packages
and may not be deinstalled (but I'll delete it anyway):
anotherpackage-1.0

But...and this is the killer...now the dependency information is gone! I can install the upgrade:

# pkg_add /path/to/somepackage-2.0.tbz

And now attempts to delete it will succeed without any errors:

# pkg_delete somepackage-2.0

How do I handle this gracefully (whereby "gracefully" means "in a fashion that preserves dependency information without requiring me to rebuild/reinstall and entire dependency chain").

Thanks!


Solution 1:

As you've found, pkg_add can't upgrade ports gracefully. The portupgrade package does this quite nicely however, and is the method I use and recommend (there are others available if you don't like this method).

Once the port is installed you can simply run portupgrade -aPP and it will upgrade all ports installed on the system using packages. If you don't want to update ever port, you can run portupgrade -RPP [category/port] to upgrade a particular port and the ports it depends on. Running the program without arguments will upgrade the port belonging to the current directory (i.e. cd /usr/ports/security/openssl ; portupgrade will upgrade openssl, without the -PP option it will build the port from source); and if you are not in a port directory it will display help (same as the -h option).

Edit:
By default portupgrade will install packages if they exist in the directory defined by the PKG_PATH environmental variable (defaults to $PACKAGES/All, $PACKAGES defaults to $PORTSDIR/packages; so the default path is /usr/ports/packages/All).

If they don't exist there, it will download the packages (by preference) from $PKG_SITES (takes a URI with subfolders Latest and All; no default value), or $PACKAGEROOT (takes a URI with the normal mirror path under it; default is "ftp://ftp.freebsd.org").

One easy way to do this, use one machine to build/cache packages that will be installed on other machine.

  • You can build packages from the ports tree with make package in the port's directory (which will also install the port).
  • You can use portupgrade to upgrade one machine and cache the package files for use on other machines, the aforementioned commands will cache the package files in the default directory (see above).
  • You can use portupgrade to fetch the packages only, and not install them, with portupgrade -aPPF or portupgrade -RPPF [category/port].

Once you have the cached package files you can share the directory via NFS, FTP, HTTP, etc; so long as the files are accessible from the other machines. Set the PACKAGES or PKG_SITE with the appropriate values to point to the caching server. Execute the typical portupgrade command, it should pull the packages from the caching server and install them.

Note: The port tree has to be up to date on all the servers for portupgrade to operate correctly (it will attempt to update to whatever version is in the local ports tree). If you're going to have the same ports/packages installed on all the computers, it might be easiest to share one servers /usr/ports directory (say over NFS) and mount it on all the other servers.

Solution 2:

Maybe pkg_replace is what you are looking for.

I'm using it for quit a some time now. One of my FreeBSD machines acts as build server and builds ( using portmaster ) all packages for the other machines. I'am using pkg_replace to install these prebuild packages on all other machines.

http://www.FreeBSD.org/cgi/url.cgi?ports/ports-mgmt/pkg_replace/pkg-descr