The random rantings of a concerned programmer.

Nov 20

(Untitled)

Category: Random

For some reason, I don’t have Cabal installed on my machine. I do a quick cd /usr/ports && make quicksearch name=cabal, and to my chagrin, it’s not in the FreeBSD ports tree either. Which means I’ll probably have the honor of writing the port for it. It, and a couple of other Haskell packages which cabal-install depends on (there’s like 5 or 6) which is going to be a bitch, because it means some packages will be in ports and some will be in Cabal.

Anyway, I’m too lazy to set up a jail, so I wiped all the Haskell packages off my system to start with a clean slate, so GHC is re-bootstrapping itself. In the meantime, I read the Cabal project proposal for kicks. Long story short, now I want to write a replacement/supplement for ports.

Don’t get me wrong, ports is awesome and all, but it’s a bit cumbersome. One of the things I kind-of hate about it is how it typically merges ports into the main tree. It’s a lot better than most Linux distributions, as most port maintainers will put a lot of stupid shit packages tend to install in /usr/local/share/PACKAGE/bin and link in the stuff you’d normally need. I think this is a step in the right direction — keeping all packages completely separate from one another and just symlinking them into the main tree, but currently this isn’t enforced by ports:

hark@kanaria> find /usr/local/bin -type l | wc -l
     187
hark@kanaria> find /usr/local/bin -type f | wc -l
    1747

I think it should be.

I mean, there have been efforts to do this before (like Gobolinux), but I don’t want to throw aside ports — that would be stupid. I want to effectively write a wrapper around ports which sets an appropriate PREFIX, installs the port, then links in the appropriate files based on the ports pkg-plist. Pretty straightforward.

Another thing that ports is missing is the ability to explicitly maintain multiple versions of the same port. Currently, the only way to do this is to have separate ports for each branch (which kind of works), and use symlinks to version binaries. For most applications, this is perfectly fine; but it’s horrid for maintenance — for example, a new version of Boost came out recently, and adding it into the ports tree is going to introduce a lot of API changes which will break a bunch of ports. Under the current ports system, it can either be added in immediately (much breakage), or the fragile applications can all be fixed before it gets added (release lag, maintenance nightmare). It should be possible to have both installed, and have the port indicate which one it wants to link against (if it has a preference). If you maintain them all in separate, versioned directories, this boils down to adding an extra ‘-L’ to the CFLAGS while resolving dependencies.

The final big problem I have with ports is that it isn’t scaling well. As easy as it is to interact with it’s flat layout, the number of ports have ballooned to the point where manipulating the tree (and, to a lesser degree, the pkgdb) efficiently is a task in itself. I’m trying to count the number of ports (I think it’s almost up to 20,000) in the tree, but the command

hark@kanaria> find /usr/ports -depth 2 -type d | wc -l

is taking forever (and raping my HDD in the meanwhile). Speaking of the pkgdb, oh god what a mess. There’s no transactionality, no locking. There are tools which can very accurately guess the state of the db when you dick it up, but if it gets blown away there’s no easy way of telling what you’ve got installed, and what binaries belong to what. The database of installed packages really needs to be replaced with a sane SQLite3 database rather than trying to smash it all into a flat file structure.

And it looks like there are 19411 ports currently in my ports tree.

Anyway, this is yet another project that I’ll never get anywhere on, but I do want to write what would effectively be a wrapper for ports. It would use ports to build and install the packages to versioned, per-package directories, then symlink what the port installs within it’s box to the local base.

I think the next step from there would be to strip out the current pkgdb entirely, and replace it with an SQLite3 database, adding more metadata at the same time. Right now, the pkgdb only keeps track of what depends on what — it doesn’t keep track of why. So when a core library (a build dependency, effectively) gets updated, the PORTREVISION of every port has to get bumped up to use that new library. The new system would sidestep this by automatically knowing what to rebuild, and rebuilding it when necessary. If the build fails with the updated library, the failing port can simply be adjusted to require a specific (older) version of that library.

Getting version-specific dependencies to work implies ripping out yet another section of the current ports Makefiles (or at least, hacking them a bit), but I don’t think it’s completely unreasonable.

tl;dr lol Haskell. I just need to generate some pkg-plists, do some testing, and these ports should be good to go. Hooray.

No comments

No Comments

Leave a comment