~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/services/features/flags.py

  • Committer: Julian Edwards
  • Date: 2011-07-28 20:46:18 UTC
  • mfrom: (13553 devel)
  • mto: This revision was merged to the branch mainline in revision 13555.
  • Revision ID: julian.edwards@canonical.com-20110728204618-tivj2wx2oa9s32bx
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
    ]
11
11
 
12
12
 
13
 
import logging
14
 
 
15
13
from lp.services.features.rulesource import (
16
14
    NullFeatureRuleSource,
17
15
    StormFeatureRuleSource,
21
19
__metaclass__ = type
22
20
 
23
21
 
24
 
logger = logging.getLogger('lp.services.features')
25
 
 
26
22
value_domain_info = sorted([
27
23
    ('boolean',
28
24
     'Any non-empty value is true; an empty value is false.'),
37
33
# Data for generating web-visible feature flag documentation.
38
34
#
39
35
# Entries for each flag are:
40
 
# flag name, value domain, prose documentation, default behaviour, title,
41
 
# URL to a page with more information about the feature.
 
36
# flag name, value domain, prose documentation, default behaviour.
42
37
#
43
38
# Value domain as in value_domain_info above.
44
39
#
45
40
# NOTE: "default behaviour" does not specify a default value.  It
46
41
# merely documents the code's behaviour if no value is specified.
47
42
flag_info = sorted([
48
 
    ('baselayout.careers_link.disabled',
49
 
     'boolean',
50
 
     'Hide the link to the Canonical Careers site.',
51
 
     '',
52
 
     '',
53
 
     ''),
54
 
    ('bugs.affected_count_includes_dupes.disabled',
55
 
     'boolean',
56
 
     ("Disable adding up affected users across all duplicate bugs."),
57
 
     '',
58
 
     '',
59
 
     'https://bugs.launchpad.net/launchpad/+bug/678090'),
60
43
    ('bugs.bugtracker_components.enabled',
61
44
     'boolean',
62
45
     ('Enables the display of bugtracker components.'),
63
 
     '',
64
 
     '',
65
46
     ''),
66
 
    ('bugs.dynamic_bug_listings.enabled',
67
 
     'boolean',
68
 
     ('Enables the dynamic configuration of bug listings.'),
69
 
     '',
70
 
     'Dynamic bug listings',
71
 
     'http://blog.launchpad.net/?p=3005'),
72
 
    ('bugs.dynamic_bug_listings.pre_fetch',
73
 
     'boolean',
74
 
     ('Enables pre-fetching bug listing results.'),
75
 
     '',
76
 
     'Listing pre-fetching',
77
 
     'https://bugs.launchpad.net/launchpad/+bug/888756'),
78
47
    ('code.ajax_revision_diffs.enabled',
79
48
     'boolean',
80
49
     ("Offer expandable inline diffs for branch revisions."),
81
 
     '',
82
 
     '',
83
50
     ''),
84
51
    ('code.branchmergequeue',
85
52
     'boolean',
86
53
     'Enables merge queue pages and lists them on branch pages.',
87
 
     '',
88
 
     '',
89
54
     ''),
90
55
    ('code.incremental_diffs.enabled',
91
56
     'boolean',
92
57
     'Shows incremental diffs on merge proposals.',
93
 
     '',
94
 
     '',
95
 
     ''),
96
 
    ('code.simplified_branches_menu.enabled',
97
 
     'boolean',
98
 
     ('Display a simplified version of the branch menu (omit the counts).'),
99
 
     '',
100
 
     '',
101
58
     ''),
102
59
    ('hard_timeout',
103
60
     'float',
104
61
     'Sets the hard request timeout in milliseconds.',
105
 
     '',
106
 
     '',
107
62
     ''),
108
63
    ('mail.dkim_authentication.disabled',
109
64
     'boolean',
110
65
     'Disable DKIM authentication checks on incoming mail.',
111
 
     '',
112
 
     '',
113
66
     ''),
114
67
    ('malone.disable_targetnamesearch',
115
68
     'boolean',
116
69
     'If true, disables consultation of target names during bug text search.',
117
 
     '',
118
 
     '',
119
70
     ''),
120
 
    ('markdown.enabled',
121
 
     'boolean',
122
 
     'Interpret selected user content as Markdown.',
123
 
     'disabled',
124
 
     'Markdown',
125
 
     'https://launchpad.net/bugs/391780'),
126
71
    ('memcache',
127
72
     'boolean',
128
73
     'Enables use of memcached where it is supported.',
129
 
     'enabled',
130
 
     '',
131
 
     ''),
 
74
     'enabled'),
132
75
    ('profiling.enabled',
133
76
     'boolean',
134
77
     'Overrides config.profiling.profiling_allowed to permit profiling.',
135
 
     '',
136
 
     '',
137
78
     ''),
138
79
    ('soyuz.derived_series.max_synchronous_syncs',
139
80
     'int',
140
81
     "How many package syncs may be done directly in a web request.",
141
 
     '100',
142
 
     '',
143
 
     ''),
 
82
     '100'),
144
83
    ('soyuz.derived_series_ui.enabled',
145
84
     'boolean',
146
85
     'Enables derivative distributions pages.',
147
 
     '',
148
 
     '',
149
86
     ''),
150
87
    ('soyuz.derived_series_sync.enabled',
151
88
     'boolean',
152
89
     'Enables syncing of packages on derivative distributions pages.',
153
 
     '',
154
 
     '',
155
 
     ''),
156
 
    ('soyuz.derived_series_upgrade.enabled',
157
 
     'boolean',
158
 
     'Enables mass-upgrade of packages on derivative distributions pages.',
159
 
     '',
160
 
     '',
161
90
     ''),
162
91
    ('soyuz.derived_series_jobs.enabled',
163
92
     'boolean',
164
93
     "Compute package differences for derived distributions.",
165
 
     '',
166
 
     '',
167
94
     ''),
168
95
    ('translations.sharing_information.enabled',
169
96
     'boolean',
170
97
     'Enables display of sharing information on translation pages.',
171
 
     '',
172
 
     '',
173
98
     ''),
174
99
    ('visible_render_time',
175
100
     'boolean',
176
101
     'Shows the server-side page render time in the login widget.',
177
 
     '',
178
 
     '',
179
 
     ''),
180
 
    ('disclosure.dsp_picker.enabled',
181
 
     'boolean',
182
 
     'Enables the use of the new DistributionSourcePackage vocabulary for '
183
 
     'the source and binary package name pickers.',
184
 
     '',
185
 
     '',
186
 
     ''),
187
 
    ('disclosure.private_bug_visibility_rules.enabled',
188
 
     'boolean',
189
 
     ('Enables the application of additional privacy filter terms in bug '
190
 
      'queries to allow defined project roles to see private bugs.'),
191
 
     '',
192
 
     '',
193
 
     ''),
194
 
    ('disclosure.enhanced_private_bug_subscriptions.enabled',
195
 
     'boolean',
196
 
     ('Enables the auto subscribing and unsubscribing of users as a bug '
197
 
      'transitions between public, private and security related states.'),
198
 
     '',
199
 
     '',
200
 
     ''),
201
 
    ('disclosure.allow_multipillar_private_bugs.enabled',
202
 
     'boolean',
203
 
     'Allows private bugs to have more than one bug task.',
204
 
     '',
205
 
     '',
206
 
     ''),
207
 
    ('disclosure.users_hide_own_bug_comments.enabled',
208
 
     'boolean',
209
 
     'Allows users in project roles and comment owners to hide bug comments.',
210
 
     '',
211
 
     '',
212
 
     ''),
213
 
    ('disclosure.extra_private_team_LimitedView_security.enabled',
214
 
     'boolean',
215
 
     ('Enables additional checks to be done to determine whether a user has '
216
 
      'launchpad.LimitedView permission on a private team.'),
217
 
     '',
218
 
     '',
 
102
     ''),
 
103
    ('bugs.private_notification.enabled',
 
104
     'boolean',
 
105
     'Changes the appearance of notifications on private bugs.',
 
106
     ''),
 
107
    ('disclosure.picker_enhancements.enabled',
 
108
     'boolean',
 
109
     ('Enables the display of extra details in the person picker.'),
 
110
     ''),
 
111
    ('disclosure.person_affiliation_rank.enabled',
 
112
     'boolean',
 
113
     ('Enables ranking by pillar affiliation in the person picker.'),
219
114
     ''),
220
115
    ('bugs.autoconfirm.enabled_distribution_names',
221
116
     'space delimited',
222
117
     ('Enables auto-confirming bugtasks for distributions (and their '
223
118
      'series and packages).  Use the default domain.  Specify a single '
224
119
      'asterisk ("*") to enable for all distributions.'),
225
 
     'None are enabled',
226
 
     '',
227
 
     ''),
 
120
     'None are enabled'),
228
121
    ('bugs.autoconfirm.enabled_product_names',
229
122
     'space delimited',
230
123
     ('Enables auto-confirming bugtasks for products (and their '
231
124
      'series).  Use the default domain.  Specify a single '
232
125
      'asterisk ("*") to enable for all products.'),
233
 
     'None are enabled',
234
 
     '',
235
 
     ''),
236
 
    ('longpoll.merge_proposals.enabled',
237
 
     'boolean',
238
 
     ('Enables the longpoll mechanism for merge proposals so that diffs, '
239
 
      'for example, are updated in-page when they are ready.'),
240
 
     '',
241
 
     '',
242
 
     ''),
243
 
    ('ajax.batch_navigator.enabled',
244
 
     'boolean',
245
 
     ('If true, batch navigators which have been wired to do so use ajax '
246
 
     'calls to load the next batch of data.'),
247
 
     '',
248
 
     '',
249
 
     ''),
250
 
    ('disclosure.log_private_team_leaks.enabled',
251
 
     'boolean',
252
 
     ('Enables soft OOPSes for code that is mixing visibility rules, such '
253
 
      'as disclosing private teams, so the data can be analyzed.'),
254
 
     '',
255
 
     '',
256
 
     ''),
 
126
     'None are enabled'),
257
127
    ])
258
128
 
259
129
# The set of all flag names that are documented.
338
208
        if rule_source is None:
339
209
            rule_source = StormFeatureRuleSource()
340
210
        self.rule_source = rule_source
341
 
        self._current_scopes = Memoize(self._findCurrentScope)
342
211
 
343
212
    def getFlag(self, flag):
344
213
        """Get the value of a specific flag.
354
223
        return self._known_flags.lookup(flag)
355
224
 
356
225
    def _checkFlag(self, flag):
357
 
        return self._currentValueAndScope(flag)[0]
358
 
 
359
 
    def _currentValueAndScope(self, flag):
360
226
        self._needRules()
361
227
        if flag in self._rules:
362
228
            for scope, priority, value in self._rules[flag]:
363
229
                if self._known_scopes.lookup(scope):
364
 
                    self._debugMessage(
365
 
                        'feature match flag=%r value=%r scope=%r' %
366
 
                        (flag, value, scope))
367
 
                    return (value, scope)
368
 
            else:
369
 
                self._debugMessage('no rules matched for %r' % flag)
370
 
        else:
371
 
            self._debugMessage('no rules relevant to %r' % flag)
372
 
        return (None, None)
373
 
 
374
 
    def _debugMessage(self, message):
375
 
        logger.debug(message)
376
 
        # The OOPS machinery can also grab it out of the request if needed.
377
 
 
378
 
    def currentScope(self, flag):
379
 
        """The name of the scope of the matching rule with the highest
380
 
        priority.
381
 
        """
382
 
        return self._current_scopes.lookup(flag)
383
 
 
384
 
    def _findCurrentScope(self, flag):
385
 
        """Lookup method for self._current_scopes. See also `currentScope()`.
386
 
        """
387
 
        return self._currentValueAndScope(flag)[1]
 
230
                    return value
388
231
 
389
232
    def isInScope(self, scope):
390
233
        return self._known_scopes.lookup(scope)
424
267
        """Return {scope: active} for scopes that have been used so far."""
425
268
        return dict(self._known_scopes._known)
426
269
 
427
 
    def defaultFlagValue(self, flag):
428
 
        """Return the flag's value in the default scope."""
429
 
        self._needRules()
430
 
        if flag in self._rules:
431
 
            for scope, priority, value in self._rules[flag]:
432
 
                if scope == 'default':
433
 
                    return value
434
 
        return None
435
 
 
436
270
 
437
271
class NullFeatureController(FeatureController):
438
272
    """For use in testing: everything is turned off"""