I have committed a new implementation of the UseFlags script and module, that is cleaner and more featureful than the existing version. It is interface-compatible with the current released version (2.9.5) and behaves the same way on valid input from the old version.
The rewrite served two purposes. One was cleaning up the code, which had grown a bit beyond what it was designed to do – generic flags particularly weren’t even a twinkle in the eye at the time the original design was put into place, nor mutually-exclusive flags. That led to some fairly hacky workarounds to deal with them, including a very ugly proxy object to allow extra data to be passed out of methods along with the sets of flags. Those are gone, and in place there is a UseFlagEngine class that maintains the state in a self-contained fashion.
The other purpose was allowing some new functionality that had been requested and that wasn’t easily or tidily doable on the old implementation. In particular, it will now support “profiles”, including whole sets of flag specifications in one go; “magic flags” that do more complicated things when enabled (such as +gnome also causing +gtk2, +gconf, +gnome-vfs); and disabling the “automatic flags” from installed programs, as well as the generic and mutually-exclusive flag behaviour.
A short summary of how this new version behaves from a user perspective: each file is parsed and the commands executed line-by-line. There are now user-specific files, and all files are parsed the same way. Indented blocks of commands will be executed when certain given conditions are met, and not otherwise. Other files of useflag commands may be included with a one-line command, allowing separate “profiles” of flags to be set up easily.
A major internal change is that every configuration file is now treated the same way – any one may perform any of the actions of any other. That isn’t by design so much as it being simpler to build only the one parser, but it does have some handy properties too. By convention, generic flags will still be defined in GenericFlags.conf, but they may be overridden (more on that later) at another point. It also includes user-specific flags in its standard execution. The full list of files executed if they are found is, in this order: /Programs/Scripts/Current/Data/DistUseFlags.conf, /System/Settings/GenericFlags.conf, ~/.config/Scripts/GenericFlags.conf, /System/Settings/UseFlags.conf, ~/.config/Scripts/UseFlags.conf.
Automatic flags may be disabled wholesale. -INSTALLED at any point will reverse the results of the automatic flag function. Most likely you would include this at the top of your UseFlags.conf, and it would be as if they never happened.
Similarly, generic flags and mutually-exclusive flags may be disabled with -GENERIC_FLAGS and -MUTUALLY_EXCLUSIVES. These will prevent the respective behaviours occurring at the end of flag parsing.
I’ve referred to “commands” a couple of times above. Each line in a flag configuration file is a command that has immediate effect. A block of commands may be indented one space, and will be executed when certain conditions are met – these are used by the if command, for example.
Currently defined are:
+foo and -foo – these set or unset the flag foo. If given a list of programs after them (as in +foo KDE-Base KDE-Libs), the flag will only be set or unset for programs in that list. This is the standard flag specification from before.
- foo: bar baz ... – this defines a generic flag foo with the contents bar baz …. This is the standard generic flag specification from before.
if foo – execute the following indented block if foo is set. This allows conditional behaviour in included files.
if foo is available – execute the following indented block if foo is available for the current program.
generic_prepend generic foo bar ... – prepend foo bar … to the generic flag generic. This means a GNOME profile could shift gtk2 to the head of the gui flag, for example.
generic_remove generic foo bar ... – remove foo bar … from the generic flag generic. This could disable a particular implementation from appearing at all.
generic_pop generic [other_generic] – remove the first component of generic and prepend it to other_generic if given (otherwise just drop it).
on foo and on -foo – execute the following indented block at a later point if foo is set or unset. This allows defining the “magic +gnome” that was requested before.
loop generic x – execute the following indented block for each component of generic, replacing “$x” in it with the respective component each iteration. This allows disabling all the component flags of a generic, to guarantee the usual generic behaviour.
break [n] – stop executing the current loop, or up to n outer loops if given.
include profile – find profile.useflags and execute it at this point. The search path is ~/.config/Scripts/UseFlags, /System/Settings/Scripts/UseFlags, /Programs/Scripts/Current/Data/UseFlags, and only the first file found will be included. This is to allow you to “shadow” a shipped version locally.
-* – empty the set of flags. This is the same as the old -* behaviour.
One further change (or non-change) to note – the USE environment variable, if set, is parsed in the old fashion and not as above. It is split on whitespace, and then +foo and -foo specifications, with optional @program modifiers, are handled in the same way they always were. on blocks and the special -INSTALLED behaviour (and the others) will still happen, however.
I will provide some examples of this in action in a later post. For now, you can try this in the trunk Scripts (not 2.9.5). `Compile Scripts SVN` will get that if you aren’t tracking trunk (they are pretty stable, so it probably won’t break anything).