Whee, another confcache bugfix release. Version 0.3.3 is up in usual location. Adding it to portage shortly, since the bugfixes against 0.3 have been pretty minor, plus 0.3.x will sit for a bit while some refactoring occurs to better handle doing tricks to avoid invalidation of the cache.
Many thanks to Ed Catmur, Christian Lemke, and Diego 'Flameeyes' Pettenò for feedback and bug reports.
Confcache, version 0.3. Fixed up a bunch of ass biter issues in dealing with the sandbox when trying to start it up (versus confcache being called within a sandbox env); pretty confident it now works fine under userpriv, and standalone as of version 0.2
Wound up having to introduce a lovely little bit of twisty code- certain sandbox vars defined prior to starting the sandbox result in the sandbox not appending the usual sane defaults (allowing write to /dev/tty for example). The solution? Well, we shift those vars to the side, spawn an indirection script that appends them to the sandbox default, then execs the actual configure call.
Kind of nuts, but does the trick.
Aside from the quicky version 0.2 release, 0.3 was released a while after. Closed up some nasty gaps in staleness detection. At this point, I don't know any way to trip up the detection code- still get some occasional failures (mono for example), but the failures so far haven't been confcache's fault, issue has been that the package doesn't properly support --cache (which confcache uses).
Aside from that, rewrote the portage integration patch- back out the original if you have it, and raid the v3 from the usual place.
Addressing a couple of questions-
Why was configure complaining about stale build_alias/host_alias?
Bug, namely. Version 0.3 now digs through the args passed to configure, and (should) properly handle staleness detection for that facet
of configure caches.
Why isn't configure caching all configure tests?
Because the configure script has to be written to cache results. A
lot of default checks are cached, but a lot of package specific checks aren't written to cache (yell at upstream in other words).
Why isn't confcache working for ebuild xyz?
The current integration is active only for econf (it's the only place I can force it).
You can do a nasty little trick however to have confcache step in in the meantime. Add
function ./configure() { $CONFCACHE ./configure; }to your /etc/portage/bashrc. Shouldn't break stuff, but if it does it will be obvious- additionally, don't blame me. It's an evil hack, you've been duly warned :) .
Why is the global cache invalidated every run when I have cpufreq enabled?
Cpufreq changes the proc frequency (good thing), this info is exposed in /proc/cpuinfo, a file configure scripts check. The md5 changes
every time the proc changes frequency, thus invalidating the cache each time (bad thing). I'm aware of it, and intend to address this in
0.4.
Offhand, probably end of the weekend for 0.4- need to introduce a framework for registering triggers to override the normal md5 checks for certain files, so it'll require a bit of expansion to confcache.
Continuing to pillage year old patches out of the ebd portage branch, parallel-fetch.patch is available.
Roughly, this patch adds FEATURES="parallel-fetch", which when enabled (and merging more then one package), splits the buildplan execution into two processes- one building, the other doing strictly fetching.
Equivalent to (emerge -f target &> /dev/null < /dev/null &); emerge target , just saner (verifies distlocks are available for example).
Testing and feedback, as always, is desired and appreciated.
Got a little ticked off at the runtime cost of configure calls for package updates, so I wound up rewriting confcache from the ebd portage line as a stand alone tool (score, I can use it locally for development), and split a patch for portage stable integrating it as FEATURES="confcache". Ebuild, and portage patch are available in my devspace.
Rough example of the improvement run time wise, is a reduction of php's configure call from 80s to 25s. About what ebd was getting, if I recall correctly.
For those unfamiliar with what this feature/code is actually doing- autoconf scripts have the option to cache settings in a file, and reuse that file next time around. Save the result of checks/tests, basically, which can result in pretty massive speed ups sometimes.
The problem is that autoconf doesn't offer a way to quickly/cleanly verify the cache- for portage, this is a major issue since a glibc update should most likely invalidate the cache; you don't want configure tests using old results that are no longer correct.
Enter the sandbox. :)
Via the sandbox, we can track what the configure script accesses for it's tests. Store a list of the files checked, and their md5 checksums, and you have a way to check if the cache is stale or not. It's actually a bit more complicated (need to track env vars also), but that's the basic jist of it.
Either way, looking for testers and feedback- the gain from it should be obvious, so I'll avoid the usual pleading to get people to test stuff ;)
For the non-gentoo folk, well, grab our sandbox, install it, and install confcache and you will be able to use it to manage a global cache for configure calls. Still useful, although y'all will have a few more hoops to jump through ;)
Hola all. Patch still is a bit raw, due to the fact the integration chunk of it is 24 hours old, but my cache rewrite sitting in 2.1 and 3.x I've backported to 2.0.53_rc5 for anyone interested. Thanks to antarus, zmedico, fuzzyray, and Bastian Balthazar Bux for testing the hell out of it. Initial patches were rather raw.
Did some further improvements to it, lifting a couple of classes out of 3.x so as to cut down on unnecessary io overhead. Stats via FuzzyRay (Paul Varner), a 233mhz pentium with 256 megs and an amazing disk access speed of 9.74MB/sec. All tests are with 2.0.53_rc5 as base.
emerge --metadata with existing full cache
| Version | real | user | sys |
|---|---|---|---|
| vanilla | 9m30.580s | 4m9.230s | 0m17.850s |
| patched | 5m43.876s | 2m39.730s | 0m13.610s |
| Version | real | user | sys |
|---|---|---|---|
| vanilla | 35m30.164s | 26m49.250s | 1m23.410s |
| patched | 11m59.595s | 5m6.890s | 0m36.930s |
Not too shabby. Stats source available here. Patch is available here, and further feedback would be appreciated.
Be aware if you test it out, you're going to need to run a emerge --metadata after applying the patch to /usr/lib/portage/pym. CVS $PORTDIR users, you're stuck running a regen.
Jason added a portage-2.0.53 release candidate p.masked to the tree earlier today- notable changes since .52
Not the full list (generate the diff if you're after it, or raid the ChangeLog), but that's the notables. Please test it :)
Commited a variation of a patch I posted in this thread to stable earlier today. Covers two things-
Detection of $PORTDIR/metadata/cache format- currently portage stable uses an ordered list of (implicit) key -> value; this makes it essentially impossible to ever remove a key, and makes addition of keys have a hard limit. Bad. So... the new format is an old format I hacked out a year back, flat_hash, (explicit) key -> value unordered. Nothing hugely fancy, but does allow us to jam stuff in without issue.
Increased flexibility requires us to version the cache entry in some way, so that we know if entries are incompatible with the version of portage reading it. Additionally, we should have been versioning the expected ebuild env (how it will be called, what funcs are available, etc) long ago. EAPI is that; additions/extensions to the ebuild spec result in a new EAPI standard, for example, src_configure addition is part of what EAPI=1 is. With EAPI in the cache, we can know whether or not the local portage version is capable of properly handling that cache entry. A higher EAPI (later portage release) may add new metadata; any portage version that doesn't support that EAPI must in some way mark the entry as "I know of it, but I can't use this ebuild".
So... in that jumble, essentially the rsync metadata/cache auto-detection allows us to move over to a more flexible format without causing cache horkages every time we change stuff (as has happened often enough), and EAPI allows us to to version those entries, so that EAPI aware portage versions can protect themselves from doing something stupid.
That and a lot of emerge --metadata cleanups got stuck in, hopefully killing off any remaining failures during cache transfer ;)
Also dropped root requirement for emerge --metadata. That always bugged the heck out of me, since it wasn't needed...
Busy weekend; aside from having likely too much heineken over the weekend, been taking advantage of new laptop to do a fair amount of rewrite work; aside from ongoing innard work, completed the following repository filters-
Beyond that, finished off what I'm calling "conditional restrictions". All of the above (searching included) is based around restriction objects grouped as needed, fex "( package = diffball && category = dev-util && fullver = 0.6.5 )" which is created via
AndRestrictionSet(PackageRestriction("package", StrExactMatch("diffball")), PackageRestriction("category", StrExactMatch("dev-util")), PackageRestriction("fullver", VersionMatch("=", "0.6.5")));or... quite a bit easier,
atom("=dev-util/diffball-0.6.5");Atom provides a couple of nice attributes, but mainly translates (internally) the atom syntax into restriction objects when requested. Haven't explicitly mentioned it, but negation is available for each restriction object, including restriction groupings (atom is a boolean AND fex); so
atom("!=dev-util/diffball-0.6.5");becomes
AndRestrictionSet(PackageRestriction("package", StrExactMatch("dev-util")), PackageRestriction("category", StrExactMatch("diffball")), VersionMatch("=", "0.6.5", negate=True));
Realize it sounds a bit complex (partially because it is) but you can represent a *lot* via it, CONTENTS lookup via a ContainmentMatch for example, optionally limiting it to specific categories/packages. That said, all of the restriction stuff above is effectively boolean, either True or False in result- conditional restrictions aren't really. How do you represent a use dep? Aside from a cat/pkg/ver restriction, you need to force a change on the configuration wrapper, flipping the tk flag on for python for instance.
With potentially arbitrary grouping/construction/arrangement of restrictions, the resolver needs to be able to back out conditional changes from attempting a match down a particular restriction branch; fex, if
( category = dev-util && package = portage && ( ( use contains build && use not contains selinux ) || ( use contains xyz ) ) )matching will hit the first chunk of the boolean or, and if selinux is on, it needs to back out the build use flag enforcement (since that branch of matching failed), and then attempt the next match (forcing xyz on). It's kind of a thorny issue, complicated by the fact that certain conditionals cannot be toggled, your arch use flag for instance. So the use flag set needs to be protected somewhat (which is where portage.util.mappings.LimitedChangeSet comes into play). Further, if a use flag enforcement is requested, it must not be reversed in that branch of matching- you cannot require build on, and require build off. You back up to the point where build was flipped on, reverse the changes from that branch of matching, and see what other matches are possible. Basically a stack hack, with the package object (a mallable configurable package specifically) tracking changes, and the restriction's themselves pushing/popping changes as required.
This is a different mode of matching, initiated by the repository when it detects that it's working with mutable configuration wrappers (rather then an immutable wrapper, a binpkg that has it's use flags locked). That chunk of code allows for tracking and blocking unwanted configuration reversions, but aside from framework required to get to that point (something stable couldn't sanely support without a rewrite, oh gee, isn't this a rewrite? :), for the resolver to be truly package/format agnostic, it really can't know about conditionals. It deals in restrictions pulled from packages, graphing the package/restrictions out; if it were left at this point, use depends would be supported but the resolver would eat itself upon the first cycle-
What remains use/slot dep work wise is pretty much adding a hook to the configurable layer that allows the restrictions to hand off requests, and be told whether it is possible (and the configuration change is recorded), or that it's not possible. That portion is going to be fun, since basically it's a lot of introspection/navel gazing, but it's the remaining chunk to kill off in that particular area of work.
After that's finished, still have stuff remaining, but most of it isn't as nasty (imho, at least). Implementing
Any enhancements beyond that follow afterwards- which is where the new config format (samba.conf style) comes into play. First, disclaimer that it's not a forced config change, the current make.conf and make.profile will be mapped on the fly into the internal config representation, and that's functionality I don't foresee ever having a reason to drop, exempting lack of use. The samba style conf is a preferred internal, and for advanced configuration, preferred external format.
The reasons pretty much come down to the fact that how this beast is structured, determination of what classes/callables to use for a specific object (say your configured ebuild repository), is all done on the fly. The samba style config makes it *much* easier to specify domains (master obj/setting grouping), group repositories (and/or creating a repository set, aka PORTDIR + PORTDIR_OVERLAY with individual caches possible), cache groupings (slaved updates to multiple cache backends fex), use different classes for almost all objects (remote class for repo or cache or config), and in general, lots of crazy crap. Essentially, it allows you to represent trees of obj/settings streaming down from domain, and the interdeps between those objects/settings.
The samba style conf won't be forced as the only option for advanced configurations either, I'm using samba style mainly because python bundles a module that can parse the format already (ConfigParser). Alternative formats, properly implemented can use whatever config format they deem as long as the python object encapsulating the config is accessible via a ConfigParser akin api. From there, pretty much stick an autoexec section in the samba style config, or change defaults. Still fleshing out portage.config.central's capabilities, but at this point it will be possible once autoexec section support is added to central.
So the 'advanced' config basically is groupings of settings that map out to objects that central (based off of a config) arranges into what will be the internal (potentially external) api. If you note that make.conf settings are pretty much scalar, N overlays, single true ebuild repository, single binpkg db, single vdb, single set of build settings, it's not to hard to see that mapping that into the internal representation is easy; basically you just chunk the data up, and throw in whatever class overrides required.
With that disclaimer thrown out, and explanation for why a more powerful config is required, back to the extensibility bit, although frankly not a hell of a lot to say about it with details explained above. As stated, the config specifies class/callable to use, which is imported on the fly and executed. It'll allow for the guts to be replaced via config definitions, essentially plugins so via the config, you just change whatever implementation you've choosen for that grouping.
Bored peeps can do remote implementations of classes, or better implementations of existing (legacy I might add) specs; the binpkg format could stand an overhaul, and the vdb on disk layout blows, badly. Adding refcounts plus a global CONTENTS db to a vdb derivative would probably make *many* people happy who hate .keep files and slow CONTENTS lookup :)
On the plus side, no changes have been required of the portage tree (which would be design flaws, or indication of bad previous designs ;), so things are proceeding. Hell, a simple config change allowed me to dodge out of the metadata transfer post syncing, my setup runs directly off of $PORTDIR/metadata/cache, treating it (and the repository it's bound to) as unmodifiable. Frozen support, essentially. The flat_list (the database name for metadata/cache layout) format sucks, very bad on it's own for --searchDesc style ops (which access each pkg's metadata), but options are open for alternatives.
Meanwhile, back to the cage till the taming of this beast of a rewrite is completed. If interested in helping, pop into #gentoo-portage on irc.freenode.net, and hunt for someone who appears active, or just email dev-portage.
If you're using portage cvs head (not stable, using cvs head directly), please take note of an earlier warning/request. The short version is that the processor class that was mangled from portage.doebuild is being replaced, and ebuild*.sh will be broke in the process.
Aside from being reworked (this time around got a better grasp on how to implement it), majority of portage hardcoded paths in ebuild*.sh are being removed, and handed down the ebd pipes. Until it's finished (which will be a good chunk of time), cvs head will be broke, so if you're using cvs head kindly let the portage devs know so that we have an idea of how many people are affected, and snapshot what ever you're running, since once this starts won't be reverting till it's finished. Note this isn't a statement that you cannot use cvs head, just that so far it's been fairly stable, and that is going to change, the developmental branch will be broke while work is being done to correct long standing flaws.
Keep in mind that cvs head *is* a developmental branch- so far nobody has had to break it, although it was expected to occur (beyond me making a dumb typo and short term breaking something :). So kindly give a yell, either ask on the ml or irc, and be wary about cvsups.
So... what are restrictions, and why is this under the portage category? Restriction implies a yay/nay evaluation of a chunk of data, which if you look at most portage package interactions, they're application of restrictions to data. Bad description, but should make sense as I continue.
An atom, say =dev-util/diffball-0.6.2 is viewed in stable as a string, which is split up and various tests done to it to determine if a cpv (category/package-version, the atom above is cpv dev-util/diffball-0.6.2) matches. The idea has been kicked around for a bit, but essentially an atom is 3 restrictions; a category restriction, a package restriction, and a version restriction.
Where it gets useful is that if you treat an atom as a set of restrictions (specifically portage.restriction.restrictionSets.AndRestrictionSet, and yes, the namespace needs massive shortening), you can tag in other restrictions to it. Since you've broken it down into individual checks and used a general class to abstract the boolean matches of it, slipping in a use restriction or a slot restriction really isn't that complex.
Nice little world view there, except I'm simplifying it a bit; you need to establish an api/protocol for the restrictions to work against, eg the actual data it checks. To make that a sane, you need an api for package instances, which is underway.
Note that there is a lot more work involved then just slipping in a set of restrictions, this is just a design abstraction that allows for it to be easily tagged in (mainly due to Jason's work, I just broke his original Atom class down into restrictions). The resolver still needs to have a way to deal with merging of cpv's that have compatible use/slot restrictions, but that functionality probably can be pushed into the base restrictionSet, interaction/union functionality. Useful functionality anyways for restrictionSet and derivatives.
Beyond atom mangling, searchDesc queries, contents queries (which cpv(s) claim file/dir/link/dev/fifo xyz) all are essentially restrictions. You want to merge strictly built packages already? Could implement it as a repository restriction. The fun part is going to be keeping it quick, and doing optimizations/collapsing of restrictions, but so far it's seeming to work rather nicely.
If you're bored and feel like poking into it, look into gentoo-src/portage/portage; only disclaimer I'd offer is that it doesn't do cache regeneration at the moment, mainly because we haven't decided if we're going to break cvs head by importing the changed ebuild-daemon.{sh,lib}. If you're interested in docs, look at intro and layout.txt in rewrite-misc. layout.txt is background info (no longer accurate, good for background knowledge though), and intro should be pretty accurate.
Aside from that, if you're interested, pop into the channel and ask.
A replacement regeneration script was made live sunday morning, which obviously had a few issues. Regarding the difference in it, it cleanses out old metadata/cache entries, so we don't have 1000+ dead entries floating in there. Does it automatically.
So... now my little plea. If you notice the cache updates aren't coming through, as marduk did and blogged about here, kindly notify the people who are responsible for it so they can fix the thing. You can't fix a bug unless either you're told of it, or hit it yourself. So file a bug, email the responsible parties, etc.
A request in #gentoo-portage wound up with me whipping out a quicky interactive sandbox'd bash shell, preloaded with all ebuild funcs- probably useful for anyone who wants to test out commands, then dump the commands into an ebuild. Without further ado, the simple hack ebuild-shell is available in my devspace- two files needed, ebuild-env, and the bashrc, ebuild.bashrc.
Requires portage cvs though- it's not worth the effort trying to make it work for stable, since to do it, the ebuild funcs must be treated as a lib- which is exactly what I did for head already (it wasn't fun). So... upgrade to try it out, or just wait till head is stabled someday :)
Way back in around roughly june/july of 2004, I had a crazy idea of how to kill off a bunch of bugs, and
optimize regen runs- regen
runs being basically a massive set of calls to bash to source an ebuild in a carefully defined environment, to get
it's 'metadata', DEPENDS,RDEPENDS,SRC_URI, etc which is then store by python portage in a cache backend. This
process is a bit slow- regening the full tree on a p4 2.4ghz is well over 30 minutes if the cache is empty.
Why do we need this process/action? Because if you didn't have the auxdb cache (which holds said metadata), you'd
have to re-source the ebuild each time, which is *slow*. Jason Stubbs pegged it around 400x slower then cache.
The regen time is directly affected by a bunch of things- for example, if an eclass used by an ebuild is modified (mtime changes), then all ebuilds that use that eclass must now be re-sourced- this is because there is no way to determine what was changed in the eclass, thus the only safe course is to go and re-source all ebuilds.
Like I was saying, it's a slow process. I figured the startup of bash, and the initialization of the bash environment for getting the metadata keys could likely be sidestepped- why do this? Because in a full regen, you must suffer the cost of bash startup/re-initialization for every ebuild. Currently, 18,913 ebuilds (8,976 distinct packages), which adds up.
Essentially, what is needed is to rewrite ebuild.sh (bash portage) such that's it's a library, and callable. More importantly, you need to be able to save and load the environment via function calls- this must work. Consider it akin to how the kernel suspends a process- the process when restarted must be the same as what it was previously. The environment between 'phases' (unpack/compile/setup/install) is the same way. More importantly, you cannot have the environment from one 'depends' phase (the specific phase that gets metadata from an ebuild) bleed into another ebuild.
So long story short, you need to load/dump environments on the fly, and contain each executing ebuild/phase such that it doesn't taint the environment for when another ebuild is processed. This is tricky, but required if you want to avoid the bash startup costs for a regen. Yes, this is a lot of crap to fix/implement for a potentially crazy idea/scheme, but I still tried it. :)
In doing env fix ups, a lot of long standing bugs were fixed also- the restructuring detailed above allows for portage to run completely from a saved env- moreso, it requires portage to run from saved envs for everything past the setup phase (exemption to this is binpkgs, which is a matter for another blog entry). This makes it such that installed ebuilds no longer rely on eclasses in the tree- they just use the saved env, which already has the eclass. This fixes bug 46223, and also allows for the clean break of forced backwards compatibility for all eclass apis/existance (detailed in glep 33). Beyond that, env attributes (export/readonly) are tracked, and a host of other naggles were nailed down and fixed. Honestly, getting the env handling right, and doing this shift fixes a *lot* of issues with ebuild processing. Continuing on however..
So env handling is now sane, a nasty collection of long standing bugs are waxed... but I started this thing
because
I wanted to see what could be done to speed up regens. Effectively, what I call 'ebd', ebuild-daemon, is an ebuild
processor. Python portage spawns ebuild-daemon with a set of pipes into the bash side of portage. This allows the
daemon and python portage to have nice little chats, including things like dumping the env straight through the pipes
for an ebuild to process, notifying it what phases to process, and telling it to start processing, and report the
results.
This is not a one sided conversation though- bash portage can command python portage too, within limits. It
allows the bash portage to -
"Yeah yeah yeah. Give me stats, before I wallop you with a red herring" you're thinking... ok.
Original data sets, and methods are available
here.
Basic summary, wiped the cache between every run, ran each target 6 times via time emerge ${TARGET} --nopspinner
--quiet &> /dev/null avgs the datasets, and compared the resultant run times. These stats were collected with
portage 2.0.51-r2 as the
base, and ebd patch 20041027-2.
| target | vanilla/ebd | real | user | sys |
|---|---|---|---|---|
| timed @gnome | van | 00:59.13 | 00:38.28 | 00:18.04 |
| ebd | 00:43.46 | 00:28.12 | 00:13.41 | |
| timed @dev-util | van | 00:52.59 | 00:33.21 | 00:17.54 |
| ebd | 00:36.16 | 00:23.46 | 00:12.10 | |
| timed @sys | van | 02:29.43 | 01:35.21 | 00:49.10 |
| ebd | 01:50.10 | 01:11.53 | 00:36.42 | |
| timed @php | van | 00:38.27 | 00:25.34 | 00:11.12 |
| ebd | 00:18.04 | 00:12.15 | 00:05.13 | |
| timed regen | van | 34:06.46 | 21:25.41 | 11:48.25 |
| ebd | 22:52.19 | 14:23.35 | 07:39.23 |
Beyond that... I hated the emerge --metadata algorithm. It waxes the cache, and transfers everything. So I
rewrote that in ebd also (although it's not bound to it) to transfer only what has changed. More stats :)
| timed emerge --metadata | |||
|---|---|---|---|
| vanilla/ebd | real | user | sys |
| van | 01:51.37 | 00:54.13 | 00:12.22 |
| ebd | 00:57.50 | 00:20.56 | 00:05.05 |
So that's a bit quicker.
Note that this is in cvs head, and cvs head is under active development. So... other cruft may get jammed in
slowing this down, but the basic speedups are there currently.
Another portage glep has hit the mailing list, this time from spb (Stephen Bennett)- the email, and the glep
So... what the hell is it I spose is the logical question. Metapkg's are basically a non-installable node of indirection- it's depends/rdepends are always processed by portage. How is this different from a normal ebuild? If the ebuild is installed, and --deep wasn't specified, portage doesn't look into the nodes dependencies at all- it just assumes they're correct.
Virtuals, as they are implemented now are essentially installable- portage first hunts through your installed pkg database to find all providers of a certain virtual, thus knowing what virtuals are installed already. The problem with this is that portage has to walk the entire installed pkgs database to know what virtuals are installed already- aside from being slow, this approach really sucks if the virtual isn't installed. Portage has to walk the portdb (available ebuilds) and go looking for a 'provider'. This is slow, and makes implementation/handling of non-installed virtuals a pain in the ass- if for whater reason that provider winds up blocked later in the depgraph, the resolver is now past that stage, and must bail. Alternatively, it could go back and try to work it's way around the blocker, but that still is a pita, and leads to code duplication.
Assuming you're still reading, you can see our existing virtuals implementation... sucks, badly. Metapkgs address this quite nicely- a metapkg is basically a virtual, with all of the providers listed inline. Centralizes the providers into a common point that portage can look at, and have A) a list of pkgs to check to see if they're installed, B) have the order of what is preferable if no providers are installed.
Sounds great, except you lose a bit of flexibility- with metapkgs, users can no longer just add an ebuild that provides a virtual to their overlay, and have it satisfy the 'virtual'- they would need both the ebuild that can provide, and an overlay metapkg that includes the new ebuild in it's depends/rdepends. For that case, you gain speed/sanity for virtual processing, at the loss of a bit of flexibility.
An additional benefit of the metapkg for virtuals approach is that since metapkgs are ebuilds (stripped down ebuilds I'll grant you, but ebuilds none the less to the resolver) developers can now do versioned virtuals- have subsequent versions of a virtual that map several providers together under a common node. Nifty feature, and has been requested on occasion
Figured I'd pass along some material I used when I was first digging into portage development- Grant Goodyear's Portage Deconstruction. Bit sparse on information as to all of the crazy crap portage does (some of it good, some of it oh so bad), but definitely a useful read for anyone who is wondering how portage sets up the workdirs/environment for ebuilds to be processed within.