Understanding and Using GenericSetup in Plone
A detailed look at GenericSetup, wherein we will learn what it is and how it can be used within Plone.
Introduction
An introduction, wherein we learn what GenericSetup is and why we even care.
What is GenericSetup? I'm glad you've asked... of course, since I'm the one writing this tutorial, you really didn't have much choice but to ask, did you? But even though I put the words into your mouth, I think that in the end you will also be glad you asked. GenericSetup is a major step forward in managing Plone site configuration, and GenericSetup is a core part of how Plone handles its own site creation process.
Okay, that's all well and good. But what is it? Simply put, GenericSetup is a Zope-based toolkit for managing site configuration. Not much clearer? Maybe this would work better as a story:
Meet Guy Ablaze. Guy is a Plone site developer, who manages websites built with Plone, and even develops add-on products for Plone using Python. Guy never uses Plone just out of the box. Instead, he does a lot of customization for every site he deploys. All of his sites have custom skins, where the CSS and template modifications live. A lot of his sites use custom content types. Rarely does he find that the default site tabs are to his liking; he often replaces those with custom tabs. And there are a myriad of little tweaks and adjustments that he makes to each site, to get it working just so, to satisfy his demanding customers' diverse requirements.
Guy knows that it is a good idea to be able to recreate a customer's site without having to do a lot of twiddling in the ZMI, so he creates install methods for each of the sites that he manages. These install methods are written in Python. Each one is comprised of a bunch of steps. One step is to install custom skins, containing the site's look and feel. Another step might be to install some custom types, while a third customizes the site tabs. And of course there are a bunch of little steps that correspond to all of the miscellaneous tweaks that he's made.
Guy is reasonably happy with this arrangement, but, you know, there are some ways that it could be better. First, he finds that he has to write a lot of repetitive boilerplate code in his various install methods. Also, using Python instructions to describe how his site should be configured doesn't really fit his brain. He'd much rather just be able to make a list of the types he wants and have them automatically get installed. Also, it would be great if he could not only import site configuration, but export site configuration. As in, he wants to make some changes to the site, maybe using the Plone interface, maybe using the ZMI, and then be able to spit that out to be loaded somewhere else. And, wow, the mind boggles... wouldn't it be great to be able to compare site configurations? To be able to ask "What has been manually changed in my site since I did the original installation?" and get a meaningful answer?
Luckily, Guy CAN do all of these things, and more, using GenericSetup!
I know, I know... It's tremendously exciting! I'll give you a minute to pick your jaw up off the floor, to fully react to and conquer your disbelief before going on..... time passes ....
Recovered yet? Good, then let's learn more...
Profiles (or "Make Sure You've Got My Good Side")
The beginning of a high level overview of GenericSetup, wherein we learn about the different types of profiles.
So let's look a little more closely at how GenericSetup achieves all of this wonder and magic.
First, GenericSetup introduces the idea of the configuration profile. A profile is a set of XML files that describe the configuration of your site. Note the fundamental difference between a profile and an install method; install methods define a set of steps that must be run to get a result, while a profile actually describes the result itself. This makes a lot more sense, semantically. It also brings site configuration down from the lofty clouds of programmer-land, to a realm where non-programmer-type site managers might even be able to look at the configuration and understand what it means. Imagine!
What does a GenericSetup profile look like? Well, you can see a very simple demonstration profile that has been recently added to the GenericSetup software itself. If you want to see a much more complex profile, you can look at the default Plone profile. I won't go into detail, but I will point out a couple of things these profiles have in common.
First, you'll notice that they both contain "import_steps.xml" and "export_steps.xml" files. The import_steps.xml file defines all of the steps that need to be taken when this configuration is loaded into your site, while export_steps.xml describes the steps that should be taken when you want to generate a new configuration profile from the live site. If we look a little bit more closely at the import_steps.xml file, we'll see that it contains a number of <import-step> tags, each of which have an id, a version, a title, and a handler (more on what these mean later). Some of them also contain one or more nested <dependency> tags. These dependency tags allow you to specify that certain steps must be run before other ones. For instance, it does us no good to configure the actions tool (which is handled by the "actions" import step) before the actions tool is instantiated (which is handled by the "toolset" import step). Therefore, in the "actions" import step you'll typically see the following nested tag: <dependency step="toolset" />. (Note: As of GenericSetup 1.4, it is also possible to register profile steps using ZCML tags.)
Next, you'll see that there are a bunch of other files. Each of these other files deals w/ a specific aspect of your site's configuration, and is usually related to a single step that was included in the import and/or export steps. Common examples of these additional files include:
- toolset.xml
- Registers all of the tools available to the site. This must happen before the tools are configured.
- skins.xml
- A list of all of the skin paths that should be added to the skins tool when your site is configured.
- skins(folder)
- Contains all of the templates, images, and css files for your skins.
- types.xml
- A list of all of the types that should be defined in the site's portal_types tool.
- types (folder)
- A folder containing other XML files, one for each type listed in types.xml. Each file contains detailed configuration information related to the specific custom content type for which it is named.
- workflows.xml
- Registers all of the workflows for the product (those in the workflows folder).
- workflows (folder)
- Contains the workflow definitions. Each subfolder contains one workflow. The workflows consist of a definition.xml file, and any supporting scripts necessary for the workflow operation.
An important point to note about profiles is: Not all profiles are created equal. In fact, there are two types of profiles that GenericSetup understands.
The first type is called a base profile. Base profiles, as you would guess, provide the base level information that a site needs to be created. Plone's default setup is defined via a GenericSetup base profile. Base profiles contain configuration information such as tools, workflows, types, register plug-ins for some packages. Most people building custom sites with will not need to ever create a base profile, and you should not create or alter your base profile until you have some practice.
Extension profiles are meant to be applied after base profiles. Any number of extension profiles can be applied to a site, whereas only a single base profile is ever be applied. Extension profiles are meant to describe new content types, custom skins, custom workflows, custom tools, and add
their configuration to what has already been set up in the base profile. All of these are additive actions, that is they do not make any changes to currently existing products. Changing configuration in existing tools, modifying content types to respond to different workflow, or any other modifications of the base profiles, are less safe actions, and only should be undertaken when you know what you are doing.
To see an example of the profile that describes your current site, and illustrates these concepts, export a snapshot, and take a look at what is done.
Starting to make sense? Great! Onward and upward...
The Setup Tool
Continuation of the high level GenericSetup overview, wherein we learn about the portal_setup tool and how to use it to apply profiles.
Now that you know what profiles are, and what they look like, you're probably starting to get a little bit curious about how you'd actually APPLY these profiles to your sites. This is understandable. Profiles aren't really much use all by themselves. You have to be able to USE them before they become useful. That's why they call it USEful, after all, isn't it. Ahem.
Anyway, the next thing you need to know about is the setup tool, which in Plone 2.5 and beyond should always exist as portal_setup at the root of your Plone site. The tool encapsulates all of the behaviour and (for now) all of the interface related to site configuration profile management. At the time of writing this, the interface is still a bit raw, but it is quite powerful and easy to use once you get the hang of it.
The first thing to know about the setup tool is that it is stateful. Specifically, I mean that at any given time, the setup tool is working in relation to an "active" profile. You can see which profile is currently active, as well as set the active profile from any of the available profiles, on the portal_setup properties tab in the ZMI:

The "Plone Site" profile that is currently active in the example above is the default Plone base profile, the one that is used whenever you add a Plone site using the ZMI. Once you know what profile is active, you can click on the Import tab to see the import steps that are currently registered:

As you might guess, these import steps are directly related to the contents of the "import_steps.xml" file that is in the profile definition. Also, although you can't see it in the screenshot above, at the bottom of the import page are the following two buttons:

If you click the button on the right, then all of the import steps listed on the page will be run against your site, and all of the configuration defined in the active profile will be applied. If you click the button on the left, then only the import steps for which you have checked the corresponding box will be applied to your site. Groovy? You bet!
Important: Look in your list of steps for an item called "Content" (NOT "Content Type Registry"). If you import this step, anything that you have in your site that was not part of the setup process will be overwritten.
The Gotcha
And now, my friends, we've come to an important moment. We have now come to the point where I describe to you, the gentle reader, the first and perhaps most striking GenericSetup "gotcha". You might imagine that when you select a new profile to be the active profile, and then you browse back to the import tab, that you would ONLY see the import steps that were related to the active profile. This is NOT the case, however. Nope, it's not. Listen: the import steps that a profile registers are additive. That means that whenever you select a new profile as the active configuration, any new import steps are ADDed (get it, ADDitive... oh, never mind) to the set of already registered import steps. Therefore, whenever you select a new profile as the active profile, you will never see fewer import steps, you will only (possibly) see more.
I know how that makes you feel... you're currently crying an anguished, mournful banshee wail, a long drawn out "Why oh why! Why did they have to make this behavior so unintuitive? Why did they not simply list the import steps for the currently active profile? Oh, woe is me!"
To which I reply, "Wow, you really should take this stuff less seriously."
All that aside, I'll admit that this behaviour seems a bit odd, at first. There's a method to the madness, however. Please read on...
How Profiles are Applied
A little more detail on how profiles are applied, wherein we learn what REALLY happens when you click on one of the "import" buttons.
Okay, so you know now that profile import steps are additive. Let's look at the implications of this. To do so, we'll once again be following the adventures of our good friend Guy Ablaze, who has now drunk deeply of the GenericSetup kool-aid, having repented for and moved beyond his former Python-based install method ways.
Say Guy adds a Plone site. When he does, of course the "Plone Site" base profile is applied to his site, as it is for every Plone site. But then he wants to install the membrane product. membrane, it turns out, doesn't use the QuickInstaller / install method mechanism for installation, but instead provides an extension profile. So he goes to the portal_setup properties tab and selects "membrane" as the active site configuration. Then he returns to the import tab and clicks the "Import all steps" button.
GenericSetup will then iterate through every registered import step, which includes all of the steps of the base profile and the two additional steps defined by membrane's extension profile. For each step, it will examine the active profile to see it contains any applicable configuration. If config info for that import step exists, then the step will run and the configuration will be applied. If there is no config info for that step, then the step will be skipped and nothing will happen.
This is an important point, with some interesting consequences. Let's look at the membrane setup profile. You'll notice that the import_steps.xml file defines some new import steps. But you'll notice that it does NOT include a "toolset" import step, even though the membrane profile DOES include a toolset.xml file. It is unnecessary to add a "toolset" import step to the membrane profile, because this step is already registered with the base profile. When the "Import all steps" button is pressed, most of the registered steps will do nothing. But the "toolset" step will find the toolset.xml file and will apply the configuration there. Likewise, the additional import steps will find corresponding configuration info, and these steps will be run.
If Guy were to switch back to "Plone Site" as the active profile and then click on "Import all steps", then it would (re)apply all of the base configuration settings, but it would not find any configuration info for the membrane-specific steps, and would therefore skip them.
You might realize, then, that it is a good idea to become familiar with all of the import steps in the default Plone base profile. These are all available to you when you create extension profiles, and they don't even need to be added to your import_steps.xml file. All you need to do to define new types is to include a types.xml file and a properly constructed "types" folder. Similar statements hold true for specifying actions, workflows, and for registering skin paths.
In fact, if you are creating an extension profile that introduces no custom import steps, then you don't even NEED an import_steps.xml file. That's right... if you create a profile that defines some new types, maybe a workflow or two, a couple of custom actions, all of those profile steps are already included in Plone's default set of import steps. You only need to add an import_steps.xml file to your profile when you are introducing steps that are not included in the base profile.
Now, if you dare, you can go back to the last section and re-read the bit about the "gotcha". If you've understood everything I've covered here, you'll understand why the setup tool behaves in the manner described.
You still with me? Great, let's move on and learn about exports and snapshots.
Exports, Snapshots, and Comparisons
More of the high level GenericSetup overview, wherein we learn how to export profiles, and how to use snapshots.
The first thing you notice upon clicking on the 'export' tab of the portal_setup tool is how similar it is to the 'import' tab. It shows you a list of available steps (these are the export steps from export_steps.xml, of course), as well as two buttons at the bottom. One of the buttons says "Export selected steps" while the other reads "Export all steps".
These export steps are linked up to code that knows how to examine the actual site setup and, from this, generate the appropriate XML files for a GenericSetup profile that would replicate the current setup. If you click on the "Export all steps" button, you're browser should pop-up a file download dialog window, asking you where you want to save your setup_tool-YYYYMMDD######.tar.gz file. This file, when extracted, contains the XML files and directory structure for your GenericSetup profile.
It is important to note that the "active" site configuration, as specified on the properties tab of the setup tool, does NOT have an direct impact on the export process. Whenever an export is run, all of the specified steps are exported in full. In other words, if Guy Ablaze were to make the membrane profile active and then run an export, he would get (among other things) an export of ALL of the tools that exist in the site, even though the membrane profile only lists a single tool in the toolset.xml file.
In addition to file system exports, it is also possible to create a profile snapshot that lives entirely within the ZODB. If you click on the portal_setup "snapshots" tab you will see a "Create a Snapshot" button. Clicking on this button will do an export, only instead of offering you a tarball for download, instead it will create a new folder inside the "snapshots" folder in the setup tool. This new folder will contain ZODB file and folder objects which contain all of the XML that defines the site configuration at the time the snapshot was run.
Also useful in the setup tool is the "comparison" tab. On this tab you are able to pick between any two profiles, including any snapshots that you've created, and generate diffs between them to see what has changed. Here's an example of what this might look like:

In this example I've run a comparison between the "Plone Site" profile, which is the default Plone configuration, and a snapshot that I created just before the comparison. In so doing, I can easily tell what had been changed since the original Plone site creation.
Under the Hood
A programmer's overview of how GenericSetup profiles work, wherein we learn about exportimport packages and node adapters.
Okay, enough of the overview stuff. How does it REALLY work? What glues it all together? How would I create my own, completely custom, import steps, in order to configure this really cool thingamajobby that I will be installing in every Plone site I ever touch from this day forward?
The import process is initiated when you tell the setup tool to run some set of import steps. At this point, GenericSetup will iterate through each of the steps, extracting the "handler" attribute (specified in the step's XML tag in the import_steps.xml file from which it was loaded). This handler is a callable, usually a function, that accepts a single argument "context", which is some flavor of what GenericSetup calls an "import context". (The basic set of import and export contexts can be found in the GenericSetup/context.py file.) By convention, this handler function, and all of the associated adapters and other related import and export code, should live in either a module or a package called "exportimport" in your Product's package. For example, all of the Plone-specific import / export code lives in the Products.CMFPlone.exportimport package.
So what is this import handler supposed to do, then? Well, it's supposed to know which XML files in the profile it cares about, and it should read these in. Then it should query for a multiadapter. This multiadapter should adapt from some interface that marks the object that is being configured, and from GenericSetup's ISetupEnviron, which is implemented by the import context object. It should adapt to GenericSetup's IBody interface. For example, the ZCML that defines this adapter for the Plone properties tool (which can be found in CMFPlone/exportimport/configure.zcml) looks like this:
<adapter factory=".propertiestool.PlonePropertiesToolXMLAdapter" provides="Products.GenericSetup.interfaces.IBody" for="Products.CMFPlone.interfaces.IPropertiesTool Products.GenericSetup.interfaces.ISetupEnviron" />
The code that performs the adapter lookup in the importPloneProperties handler looks like this:
importer = queryMultiAdapter((ptool, context), IBody)
'importer', then, will be an instance of the PlonePropertiesToolXMLAdapter class, which implements GenericSetup's IBody interface; I'll leave it as an exercise to the reader to look up that interface, but I'll tell you that it defines a Zope 3 schema which includes a 'body' Text field. This is implemented (in the XMLAdapterBase that the properties tool's adapter extends) as a property, such that when you set the 'importer.body' to be the XML read in from the configuration file, this XML is parsed (using minidom) and the configuration is applied.
So, if you want have some fancy new frobnozz tool that you want your product to install, and you want to be able to manage the configuration of that tool using XML files in a GenericSetup profile, what would you do? Here are the steps:
- Add a toolset.xml to your extension profile that lists your tool's class, so it will be created during the toolset import step.
- Add a handler function in an appropriate place within your product's exportimport package. This function should accept a 'context' argument, it should read in any XML file(s), and (in most cases) it should set the body attribute to be the content of the XML file.
- Create and register an adapter that adapts from an IFrobNozz interface and ISetupEnviron to IBody. If you're subclassing from XMLAdapterBase, all you'll need to do is implement an _importNode method that accepts the minidom node that is the root of the XML tree in the configuration file. This should iterate through the tree and perform all necessary configuration.
- Add your new import step to your extension profile's import_steps.xml file.
- Add your new frobnozz.xml file to the extension profile.
That should do it!
Note that we've been looking at an XMLAdapterBase-based example. XMLAdapterBase is a good starting point for situations where you have a tool and a single XML file that contains the tool's configuration. Not all import steps are like this, though, and there are other utility classes that GenericSetup provides in its utils module. It is beyond the scope of this tutorial to cover them all in detail, but I will list a couple that you should know about:
- ObjectManagerHelpers
- When you need to import (or export) folderish objects that contain other objects, you will probably find this useful.
- PropertyManagerHelpers
- This provides some assistance when the configuration you need to perform relates to Zope's PropertyManager API.
Note also that, while we have been focusing on the import process, the export process works very similarly. Usually the same adapter is used for exporting as for importing. In the XMLAdapterBase situation, you would define an export handler that looked up the adapter, read the 'body' attribute (which would actually trigger introspection of the site state and creation of the DOM nodes and XML that represent that state), and then write this out to the appropriate filename.
Applying Policies at Site Creation Time
A description of how to register extension policies that can be applied at site creation time, wherein we learn how customization policies have gone the way of the dodo.
Those of you who have been doing Plone product development for a while are probably familiar with customization policies. Customization policies are site configuration bundles, defined in the older python-based semantics, that can be applied to a Plone site. One of the more handy features of customization policies is that they could be made to show up as an option when the Plone site was first created. If you didn't select one, you would get a default Plone site, but if you did, your site would get a bunch of extra configuration applied.
Unfortunately, customization policies are currently not supported in Plone 2.5. There has been some justified grumbling about this; they were not given a suitable deprecation period. The good news is that GenericSetup provides the same ability, and that it is quite easy to convert existing customization policies to GenericSetup profiles (although these profiles will consist of just a single handler that calls all of the pre-existing customization policy code).
First let's look at how GenericSetup profiles are defined. This is done using a profile_registry mechanism provided by GenericSetup, which can be imported into your product as so:
from Products.GenericSetup import profile_registry
Also defined are some constants for specifying the type of profile you are registering:
from Products.GenericSetup import BASE, EXTENSION
Once you have done these imports, a simple call to the profile_registry will register your profile. (Duh.) Here is what this call looks like for the membrane product:
profile_registry.registerProfile('default',
'membrane',
'Extension profile for membrane',
'profiles/default',
'membrane',
EXTENSION,
for_=IPloneSiteRoot)
I'm not going to go into a detailed description of all of the arguments (you can see the IProfileRegistry interface for that), but I will draw your attention to the final "for_" argument. This allows you to specify an interface that denotes the type of portal that the profile is meant to be used with. If you use the IPloneSiteRoot interface, defined for this purpose, then when you add a new Plone site, your profile will automatically show up as available to be applied when the site is created. Here is a screen shot of the Plone add form when a number of extension profiles have been registered:

In order to create an Extension Profile from a Customization Policy, then, you would perform the following steps:
- Register an extension profile with the GenericSetup profile registry (don't forget 'for_ = IPloneSiteRoot').
- Add a single import step in import_steps.xml, which calls a 'runPolicy' handler.
- Write the runPolicy function, which should accept a 'context' argument, but which simply calls the same code that the customization policy calls.
Creating an uninstall profile
GenericSetup allows you to remove configuration
So far you have learned how to add configuration to a Plone site with GenericSetup... But what if you want to remove it again? Typically any
Plone Product author wants to offer uninstall of his project.
Fortunately, GenericSetup allows you to pinpoint and remove selected elements. From a high level you do this:
- Create an additional GenericSetup profile with the name "uninstall" - many times you can just copy the "default" profile
- Sprinkle remove="True" attributes around the XML files
- Wire the uninstall profile up with the Install.py of your product if you like.
How to create an uninstall profile
Consider a profile that configures a custom portal type, e.g. the following lines in types.xml and the corresponding MyType.xml
<?xml version="1.0"?>
<object name="portal_types" meta_type="Plone Types Tool">
<object name="MyType"
meta_type="Factory-based Type Information with dynamic views"/>
</object>
Now, copy the types.xml over to a new profile directory called uninstall and alter it a bit:
<?xml version="1.0"?>
<object name="portal_types" meta_type="Plone Types Tool">
<object name="MyType"
meta_type="Factory-based Type Information with dynamic views" remove="True" />
</object>
That's it. Run the new profile and it will remove the MyType configuration.
If you like, you can clean it up a bit:
<?xml version="1.0"?>
<object name="portal_types">
<object name="MyType" remove="True"/>
</object>
What works and what doesn't yet
The magic "remove" attribute has been implemented for many of the GenericSetup handlers, but not all of them.
Remove works for these handlers:
- Skins
- Types
- Workflows
- Catalog indexes
It does not work for these -- yet:
- Actions
- Properties
- Configlets
I haven't tested with the rest of the handlers.
Wiring up the Quick Installer
You can wire up the uninstall profile with Quick Installer the same way as you wire up a normal install profile, e.g.
from Products.CMFCore.utils import getToolByName
def uninstall(portal):
setup_tool = getToolByName(portal, 'portal_setup')
setup_tool.setImportContext('profile-MYPRODUCT:uninstall')
setup_tool.runAllImportSteps()
setup_tool.setImportContext('profile-CMFPlone:plone')
return "Ran all uninstall steps."
Until all the GenericSetup handlers support the "remove" attribute, you might need a hybrid uninstall method that runs an uninstall profile and uninstalls the remaining elements using old style scripting afterwards.
The Future
What GenericSetup doesn't do, wherein we learn about cool features that don't yet exist.
GenericSetup already offers a number of advantages over previous mechanisms for managing site configuration. It promises to solve even more problems, however. This section will talk about some of these possibilities, and what still needs to happen before these possibilities can become a reality.
Migrations
The first area that could be improved with the use of GenericSetup is the Plone migration infrastructure. Currently, migrations are handled by tracking the installed Plone version number. If the filesystem version of Plone is higher than the version stored in the ZODB, then the migration tool can be used to run all required migration steps, which are defined in Python as a set of operations to perform.
Sound familiar?
That's right, it's not much different than the earlier product installation or site creation mechanisms. In fact, a number of migration steps, such as changes to action or workflow definitions, could be achieved via GenericSetup-land just by the application of a new profile.
It is evident that this use case has already been thought about; in the import_steps.xml file for most profiles you will see a 'version' attribute on all of <import-step> tags. This is meant to be used like a serial number on a BIND zone file, for those of you familiar w/ BIND. For those of you who aren't, the idea is that you'd set the version to be related to the date, something like 'version="YYYYMMDD-01"' would work. Whenever you make changes to the configuration, then, you'd update the version of the import step. Then the setup tool would be able to tell you which import steps were out of date, making it easy to select them and apply the new config to your site. The interface that makes use of this version attribute is not yet in place, however.
Okay, that would cover a number of migration tasks, but there are other tasks that cannot be represented simply by a change in the configuration. Florent Guillaume gave the example of merging two content types into a single one; you could represent the new set of content types easily enough, but there's no way to represent the step where some of the existing content is converted to the other type. CPS has already tackled this problem within their own usage of GenericSetup; they've introduced a new ZCML directive that looks like this:
<cps:upgradeStep
title="Replace CMF URL tool with a CPS-specific one"
source="3.3.4" destination="3.3.5"
handler=".upgrade.upgradeURLTool"
checker=".upgrade.check_upgradeURLTool"
/>
This registers an upgrade step with the system. As is clear, it specifies the source and destination versions, and the callable handler that actually performs the operation. It also registers a checker method, which will ascertain whether or not the upgrade step actually needs to happen.
Product Installation
As we have already seen, GenericSetup can be used as an alternative to CMFQuickInstaller as a way to install your products into a Plone site. While GenericSetup is a better approach to product config management, it is not yet ready to completely replace the trusty portal_quickinstaller completely. First, the GenericSetup interface is a bit unwieldy compared to QI. Second, there is not yet any support in GenericSetup for uninstalling profiles. For site configuration management this isn't such a show-stopper, but it's considered a core feature for add-on product management.
Another advantage to using GenericSetup for product installation will be that all products will then be able to use whatever migration features GenericSetup makes available. As described above, Plone has its own migration system. Products often require migration as well, however; currently, each product needs to implement its own migration engine in order to get this support. When all products are managed as GenericSetup profiles, then GenericSetup will become the shared migration engine.
Help Wanted
So when is all this glorious work gonna get done? Well, this is open source, so the only correct answer is "When the people who have the skills to do so get around to it." Do you have the skills to where you could contribute to these efforts? Do you have some time to help? If so, then what are you waiting for? Download the latest GenericSetup code from the Zope svn repository and get going!
Acknowledgements
Kudos and acknowledgements, wherein we learn some of the people to thank for this fine piece of code, and also where to get more assistance.
As with all endeavours in this interconnected world of ours, this tutorial wouldn't exist without the collective efforts of a number of individuals. Many thanks to everyone who has developed and/or provided documentation for GenericSetup thus far. Special thanks to the following folks:
- Martijn Pieters, for writing CMFSetup (the precursor to GenericSetup) in the first place.
- Tres Seaver, for extensive contributions to GenericSetup, and for giving me an initial spin around the system so that I understood what the heck I was dealing with.
- Florent Guillaume, for significant coding contributions and for providing the first real GenericSetup documentation, in his blog.
- Yvo Schubbe (AKA Yuppie), for general stewarding of the GenericSetup codebase, and for always responding quickly to inquiries on the CMF list.
Finally, where should one go if one has specific questions about GenericSetup? As I intimated above, GenericSetup originated as CMFSetup, a part of the CMF project. It was recognized as more generally useful, however, and was refactored to work in a non-CMF context. However, the CMF (along with CMF-based projects such as Plone and CPS) is still the most visible codebase using GenericSetup, and all of the core GenericSetup developers are also CMF developers. As such, the best place to get help is currently from the fine folks on the CMF mailing list (also available via GMane).
Good luck, and happy configuring!
