Converting FreeBSD systems from ports to a centralized package repository

by Garrett Wollman <wollman@freebsd.org>

I responded to a query on FreeBSD-stable about upgrading ports on a system that hadn't been kept particularly up to date, and I was asked to make a Web page out of my reply. Here goes.

Having just gone through this in two different environments, I can very very strongly recommend doing the following. It's not the “easy button” of the TV commercials, but it will make things much much easier in the future.

  1. Switch your system to pkgng if you haven't already. Unfortunately, this will not result in the right ports being marked as "automatic", so you'll need to do a bit of post-conversion surgery:
    1. Set all packages to "automatic" and get a list of leaf packages:
      # pkg set -A 1 -g '*'
      # pkg query -e '%#r==0' '%n-%v: %c'
      
    2. Then look through the output of pkg query to identify the leaf packages that are the ones you actually wanted explicitly to have installed. For each one of those:
      # pkg set -A 0 packagename
      
    3. Create a list of your desired packages:
      # pkg query -e '%a==0' '%o' > pkg-list
      
    4. Clean up the unnecessary local packages:
      # pkg autoremove
      

    (You can iterate the last three steps, aborting pkg autoremove each time but the last, until it doesn't offer to remove anything you care about keeping.)

    Repeat this process for each machine, and merge the resulting pkg-list files using sort -u. Make sure that pkgng is enabled for ports in /etc/make.conf.

  2. Install and set up poudriere. Copy /var/db/ports, /etc/src.conf, and /etc/make.conf to /usr/local/etc/poudriere.d (possibly with local variations as described in poudriere(8) under the heading "CUSTOMISATION").
  3. Run poudriere options for each jail and setname (if you created any sets following the customization section referenced above), providing the package list you constructed, to make sure that any new options are configured as you require them.
  4. Run poudriere bulk for each jail and setname (if you created any), providing the package list as before. This will create a pkgng repository for each jail and set, which you can serve by HTTP (using your choice of Web server) or SSH (with pkgng 1.1+), and all of these packages will have been built in a clean jail and (if their dependencies were specified correctly) will have no library inconsistencies.
  5. Configure your client machines to reference the appropriate repository created in step (4).
  6. Run pkg upgrade -fy on all of your machines, and resolve any inconsistencies by pkg remove-ing the offending local package.

That seems like a lot of work, and it is, but having done it, there's a huge benefit the next time you want to do update your systems:

Even for just three machines it was worth going through this process—and worth unifying all of my package sets and options. Since I now do one build instead of three, I'm no longer so concerned about minimizing dependencies; it's no big deal if some X libraries get installed on my server.