=== Complicated alternative implementations === This should probably live on a zope utility? Is "config" confusable with other names, and if so what should we call it instead? The flags are named with the same syntax as Python identifiers. All punctuation is reserved so that we can try scope selectors like {{{server=edge/user_group=beta/soyuz_build_from_branch=True}}}. The value is a Unicode string. We will add a machine-readable registry of known names, with a help string and a description of the type to be stored in them. (A little like the Mailman admin interface but much simpler.) The values are stored in a database table, with two columns: name, value. (If we add scope selectors we'll add a third column, so you can quickly pull out all the rows possibly relevant to the name.) This means you perhaps can't change it while we're in readonly mode. Later we can split it to a separate replicated database, or to some non-sql database. More examples: * {{{sitewide_message=Going down for an upgrade, should be back in 10m}}} * {{{sitewide_countdown_time=20101220T00:00}}} (show "in %d minutes" based on this) * {{{if server(edge): if user_in(beta): bug_page_new=True}}} (show the new version of the bug page only on edge) * {{{if user_subset(0,10): registry_layout_new=True}}} (give users with id%10==0 a new layout to see how they like it) The story for how this works: request goes in to the app server code which calls {{{config('bug_page_new')}}}. (Based on this it will choose a different page template or turn on/off some parts of that template.) The config mechanism walks through the configuration settings looking for one that has the name 'bug_page_new' and matches the context. It checks for matches in the context by looking at all the selectors and calling a callable looked up by name. In this case it is 'server' which will look in the request object for the vhost header. Maybe we don't need multiple levels: if we want things active only on edge for users in ~launchpad-beta, we define a selector function that composes those things. Or we could eliminate the arguments to the selectors, and just make them simple callables. Alternative language: put the name first and then the selectors, so that there's exactly one per name: * {{{bug_page_new: server=edge,True,False}}} perhaps we should just use actual Python fragments: * {{{bug_page_new = True if server=='edge' else False}}} (These could be actually evaluated by Python, or they could just look like Python.) Or you could put all the logic into the app code and make the config a purely dumb dictionary: {{{ if user_in_beta or not config('bug_page_new_beta_only') ... }}} Perhaps the simplest thing would be to say there are several semi-statically-configured scopes, including "edge", "beta users", "everywhere" with a total ordering. We look through these in order for the relevant name. This would mean: * the configuration ui can be clear about how they interact * we don't need (or get) a minilanguage * the application code can do one query something like {{{select * from configuration natural join configuration_group where group in ('edge', 'beta', ...) order by group_priority}}}