Short Intro

In my paludis-hooks repo I’m trying to accumulate everything I’ve done to survive w/ for paludis – The Other Package Manager™. Yep, initially there was only hooks, but later I’ve added some other helpful things, I’m using for awhile… so probably the repo should be renamed.

Personally I like hooks, cuz that facility, out of the box, turns paludis into a really flexible package manager and thanks to them, feature like autopatch works much more better (and reliably) than the same feature of emerge became available long time after.

To install all that stuff, here is a ebuild in my overlay. And yes, that scm is the only version nowadays ;-) cuz I’m permanently doing some improvements w/o any release plan.

NOTE: To use it w/ Python 3 as a default interpreter make sure you have an appropriate paludis version installed.

Things in Details

Autopatch Hook

One of my first hooks inspired by an already dead repo of paludis’ hooks, I’ve found soon after migrated to paludis. That was one from a bunch of reasons to forget about emerge – a really easy way to apply my patches for broken packages w/o “writing” a my own ebuild and put it to my repo.

The idea is simple and straightforward: at any desired stage of ebuild processing apply some user provided patches placed into a some special place (configurable via /etc/paludis/hooks/configs/auto-patch.conf).

To apply a patch one have to put it into a directory under ${PATCH_DIR}/stage/category/pkgname-with-ver/ or to ${PATCH_DIR}/stage/category/pkgname/, so you don’t need to create a new directory (or symlink a previous pkg-spec-with-ver) when package version has bumped. Where the stage is one of the following: ebuild_compile_post, ebuild_compile_pre, ebuild_configure_post, ebuild_configure_pre, ebuild_install_pre or ebuild_unpack_post.

Recently I’ve killed all out of date patches from my local vault and made it public. For example w/o a patch cmake won’t colorize its output even if color explicitly requested when running w/ captured output. So to allow my Pluggable Output Processor works w/o suppressing colors of CMake I have /var/db/paludis/autopatches/ebuild_unpack_post/dev-utils/cmake/cmake-3.0.0-do-not-check-isatty.patch.

Filesystem Hook

This plugin can be used to make some manipulations in a package’s image, right after make install and before it will be actually merged into the system. Particularly I use it to make a permanent symlinks to a documentation for some packages I use in my work or to prevent undesired files to be installed (which is far better than ugly INSTALL_MASK).

Every action to apply described in terms of XML items of the configuration file /etc/paludis/hooks/configs/filesystem-manager.conf, where the root element is commands. A commands container consists of package elements which must have at least the spec attribute of a package to apply actions for. The other attributes are stop, with boolean true/false value to disable/enable further processing, if a given rule matched, and the descr attribute with a human readable action description. The package’s spec attribute specify the order how actions are matched and applied:

priority spec
16 cat/package-ver-rv:slot::repo
15 cat/package-ver-rv:slot
14 cat/package-ver-rv::repo
13 cat/package-ver-rv
12 cat/package:slot::repo
11 cat/package:slot
10 cat/package::repo
9 cat/package
priority spec
8 package-ver-rv:slot::repo
7 package-ver-rv:slot
6 package-ver-rv::repo
5 package-ver-rv
4 package:slot::repo
3 package:slot
2 package::repo
1 cat/*
0 */*

There are few children tags possible under the package element:

  • symlink – used to create a symlink and has attributes:
    • cd – change to this directory before making a symlink
    • src – source for the symlink
    • dst – destination of the symlink
  • mv – used to move or rename something in the image.
    • cd – set a working directory to this
    • src – source file or directory name
    • dst – destination path/name
  • rm – used to remove something from the image, so it will not be installed at all.
    • dst – what to remove
    • reverse – optional attribute to specify that command should remove everything except selected target(s)
  • if – used to check some (limited nowadays) constraints and execute nested actions if latter is true
    • use – the only mandatory attribute nowadays to check if given USE flag is turned on for matched package
    • negate – boolean attribute to negate result of a use check
  • mkdir – used to create a new directory
    • cd – change to this directory before doing anything
    • dst – the name of the directory to create

Paths in a rule may refer to shell variables like P, PN, PF, PV, PVR, as well as others, declared by PMS. Note, that all absolute paths are refer to the package’s image directory and not to the “real” filesystem.

Examples

This was an initial motivation to write this hook: I use the firefox to view a documentation to various packages. Documentation for =dev-lib/boost-1.54, for example, will be installed to the /usr/share/doc/boost-1.54. Firefox will remember that location and next time shows me hints (in a popup) with the most visited pages, when I type something in a location bar. Unfortunately after upgrade to =dev-libs/boost-1.55-r1 path to documentation obviously will be changed and that hints will not work without fixing. The second problem with that: I have to remember an exact package version with a ebuild’s revision number and should type it in a location bar a long time until firefox realized that visits count of some 1.55-r1 page is greater than same, but with 1.54 in the path, and will offer it instead. Except boost, I’ve got about 10 more packages w/ USE=doc flag enabled and I don’t want to remember all versions and revisions I currently have in my system… and bookmarks in firefox can’t help much in this case!

The solution is to make a “permanent” symbolic link which will stay the same for any version installed. Moreover it can be a little shorter :-) So instead of /usr/share/doc/boost-1.55.0-r1/html/index.html I have /usr/share/doc/boost/index.html as a hint in a location bar and don’t care about particular version installed.

To achieve that I’ve added a simple rule to my config:

<package spec="dev-libs/boost">
    <symlink cd="/usr/share/doc" src="${PF}/html" dst="${PN}" />
</package>

So, this rule will change current directory to /usr/share/doc inside an image directory and create a symbolic link boost pointing to boost-1.55-r1/html/.

Remove unused translations/locales

I have */* -nls and LUNGUAS: -* in my /etc/paludis/use.conf, but some packages just don’t have that USE flag, but install localizations anyway (yep, cuz ebuild authors just lazy ppl… most of the time). So app-admin/localpurge was “invented” to cleanup unused locales (all of them in my case). But localepurge will remove *.mo files after install, so when a package gets uninstalled, some files will be marked as gone. One simple rule will do the job better:

<package spec="*/*" descr="locale-cleaner">
    <rm cd="/usr/share/locale/" dst="*/LC_MESSAGES/*.mo" />
</package>

Because manipulations (deleting *.mo files) will be done before merge, all that files even won’t be counted by a package manager. And I’m not telling about that you don’t need to run any tool periodically (or via cron) – all your packages will be already clean w/o any manual actions required :)

Translations is a part of the “problem”: some packages (like alsa-utils) want to install translated manual pages as well. To remove them (everything except English) one may use the following rule:

<package spec="*/*" descr="man-pages-cleaner">
    <rm cd="/usr/share/man/" dst="man{0p,1,1p,2,3,3p,4,5,6,7,8}" reverse="true" />
</package>

Note the attribute reverse tells to the hook that everything except specified items (directories actually) should be removed.

Other usage examples can be found here. They are mostly targeted to remove unused/redundant/useless files installed by various packages to the /usr/share/doc and some other places.

Even more extreme rule

Recently I’ve added one more element: if – to check if a matched package has some desired USE flag turned on. Nowadays I have the following extreme rule in my config:

<package spec="*/*" descr="USE=-doc remover">
    <if use="doc" negate="true">
        <rm cd="/usr/share" dst="doc" />
    </if>
</package>

Attention

This rule will prevent to install any files to the /usr/share/doc/ from all packages, which do not have USE=doc enabled!

Unfortunately some packages, I want docs for, do not have that USE at all, so to stop this rule triggering, I’ve got a bunch of stoppers like this:

<package spec="clang-docs" stop="true" />
<package spec="python-docs" stop="true" />
<package spec="valgrind" stop="true" />

Working Directory in a RAM

Some users have a paludis woking directory mounted to a tmpfs. The big problem w/ this solution: some packages are too fat to be build in a RAM. Then to build them one have to umount selected location temporarily to build that packages. workdir-tmpfs hook is designed to solve that “problem”.

This hook record a disk space usage while a package gets build and the next time will try to move the working directory to the /dev/shm (providing a symbolic link to the original location) if there is enough space. Disk usage stats will be recorded only if a package builds successful. To move a working directory to a RAM disk it should have enough space: previously collected value plus some reserved space. Basically amount of bytes to reserve is a 10% of the stored value.

Default configuration file location is /etc/paludis/hooks/configs/workdir-tmpfs.conf. The hook’s configuration has the following default values:

MIN_RESERVED_SPACE=$(( 1024 * 1024 * 10 ))
MAX_RESERVED_SPACE=$(( 1024 * 1024 * 100 ))
DISK_USAGE_STATS_CACHE="/var/cache/paludis/disk_usage_stats.cache"

MIN_RESERVED_SPACE is a value to be used as an amount of a reserved space if 10% of a stored disk usage counter is less than it. The MAX_RESERVED_SPACE is an upper bound of that 10% – i.e. max reserved space can not exceed it. Defaults are 10M and 100M correspondingly.

Note

If some package fails to build, its working directory will be moved back to its original location from the RAM disk (i.e. /dev/shm)…

Manage Build Environments

This feature is not a hook actually, but some add-on to be used from the /etc/paludis/bashrc. It allows to manage compiler flags (as well as any other environments variables) on a per package basis, like it is possible in the portage via the package.env file.

To use it, one have to add the following to the /etc/paludis/bashrc somewhere after the CFLAGS and/or other definitions.

[ -e /usr/libexec/paludis-hooks/setup_pkg_env.bash ] && . /usr/libexec/paludis-hooks/setup_pkg_env.bash

Now you can edit the /etc/paludis/package_env.conf to specify how environment should be changed to compile any particular package. For example, I have somethig like this:

#
# My per package environment settings
#

sys-devel/binutils binutils-extras

dev-lang/python extra-optimize
dev-db/sqlite extra-optimize
sys-apps/paludis extra-optimize

sys-libs/db use-bfd-linker

app-emulation/virtualbox no-gc-sections use-bfd-linker
media-libs/alsa-lib no-gc-sections
sys-devel/glibc no-gc-sections
x11-libs/cairo no-gc-sections

net-libs/webkit-gtk no-debug
www-client/firefox no-debug

Every line has a package spec and a space separated list of environment modifiers. They would be applied in the same order as specified in the config. Every modifier actually is a file from the /etc/paludis/env.conf.d/. In that file (an ordinal bash script actually to be sourced if a package name matched) defined some actions to modify CFLAGS, LDFLAGS or anything else you want. For example in /etc/paludis/bashrc I have the following definition for LDFLAGS:

LDFLAGS="-Wl,-O1 -Wl,--sort-common -Wl,--as-needed -Wl,--enable-new-dtags -Wl,--gc-sections -Wl,--hash-style=gnu"

Unfortunately, not all packages can link with --gc-sections option. For example app-emulation/virtualbox. It is why this package have no-gc-sections environment in my package_env.conf. You may use all functions provided by [flag-o-matic.eclass](https://devmanual.gentoo.org/eclass-reference/flag-o-matic.eclass/index.html) to manupulate compiler/linker flags! Here is mine /etc/paludis/env.conf.d/no-gc-sections.conf` for example:

einfo "Remove --gc-sections from linker flags"
filter-ldflags -Wl,--gc-sections

Yes, you can use logging functions as well ;-) The last command will remove undesired option from default (“global”) LDFLAGS. Unfortunately app-emulation/virtualbox also fails to build if default linker is ld.gold. The second environment (use-bfd-linker) tells to use ld.bfd to link that package:

if [ "bfd" != "$(readlink -f `which ld` | sed 's,.*\.\(bfd$\),\1,')" ]; then
    einfo "Use ld.bfd linker"
    append-ldflags -Wl,-fuse-ld=bfd
fi

Also there is a buch of other helper functions provided – you may check my paludis configuration for inspiration. Being an ordinal bash script one may use any other programs, sed for example, to modify environment and/or build flags for particular package.

New cave Subcommand

This package also add a “new” subcommand cave print-ebuild-path <spec> which just prints a full path to the ebuild according a given spec.

zaufi@gentop〉~〉 cave print-ebuild-path firefox
/usr/portage/www-client/firefox/firefox-26.0.ebuild

zaufi@gentop〉~〉 cave print-ebuild-path '<www-client/firefox-26.0'
/usr/portage/www-client/firefox/firefox-24.2.0.ebuild

zaufi@gentop〉~〉 cave print-ebuild-path paludis-hooks
/var/db/paludis/repositories/zaufi-overlay/sys-apps/paludis-hooks/paludis-hooks-scm.ebuild

This command (mostly) introduced for further scripts.

Short Aliases and Some Other Helpers

I use the following short aliases for the cave subcommands:

alias cs='cave search --index ${CAVE_SEARCH_INDEX}'
alias cm='cave manage-search-index --create ${CAVE_SEARCH_INDEX}'
alias cc='cave contents'
alias cr='cave resolve'
alias crz='cave resolve ${CAVE_RESUME_FILE_OPT}'
alias cw='cave show'
alias co='cave owner'
alias cu='cave uninstall'
alias cy='cave sync'
alias cz='cave resume -Cs ${CAVE_RESUME_FILE_OPT}'
alias world-up='cave resolve ${CAVE_RESUME_FILE_OPT} -c -km -Km -Cs -P "*/*" -Si -Rn world'
alias system-up='cave resolve ${CAVE_RESUME_FILE_OPT} -c -km -Km -Cs -P "*/*" -Si -Rn system'

Variables CAVE_SEARCH_INDEX and CAVE_RESUME_FILE_OPT are defined in /etc/env.d/90cave file. Also here some trick used to reintroduce bash completions for all that commands, so even if alias is used completions are still available.

Note that -km and -Km options are used. So when gentoo team adds some changes to ebuild w/o version bump, that options will add a target to rebuild. To show differences between ebuilds of installed package and just changed (and added as a target to rebuild on world-up “command”) one may use pkg_meta_diff <pkg-name> command.

To show differences between installed and the next best available ebuilds use pkg_ebuild_diff <pkg-name>.

Also here is a couple of functions to use: ebuild_for – to get a path of the ebuild according a given spec and show_ebuild_for to less it…

See Also

  • repository w/ my paludis configuration. Note, that it has various branches for my hardware.