Merge lp:~thumper/launchpad/ibranch-interface-smashing into lp:launchpad
- ibranch-interface-smashing
- Merge into devel
Proposed by
Tim Penhey
Status: | Merged |
---|---|
Approved by: | Robert Collins |
Approved revision: | no longer in the source branch. |
Merged at revision: | 11203 |
Proposed branch: | lp:~thumper/launchpad/ibranch-interface-smashing |
Merge into: | lp:launchpad |
Diff against target: |
750 lines (+259/-335) 3 files modified
lib/lp/code/configure.zcml (+17/-117) lib/lp/code/interfaces/branch.py (+239/-216) lib/lp/code/model/branch.py (+3/-2) |
To merge this branch: | bzr merge lp:~thumper/launchpad/ibranch-interface-smashing |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paul Hummer (community) | code | Approve | |
Review via email: mp+29969@code.launchpad.net |
Commit message
Move the attributes and methods of IBranch to other interfaces based on permissions.
Description of the change
Break the IBranch interface into other interfaces based on the required permissions.
There should be no other changes necessary.
There are two slight oddities with the resulting code.
I changed the IPrivacy inheritance in IBranch to be something that Branch directly provides. This is due to the fact that we were reimplmenting (or overriding) the private attribute defined by IPrivacy in the IBranch interface.
Secondly we are using an api mutator decorator on "private" which doesn't work when the private attibute isn't available in the same interface, so for now, I've left both private and setPrivate on IBranch.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/code/configure.zcml' |
2 | --- lib/lp/code/configure.zcml 2010-07-22 01:48:51 +0000 |
3 | +++ lib/lp/code/configure.zcml 2010-07-22 09:28:53 +0000 |
4 | @@ -439,129 +439,29 @@ |
5 | <class class="lp.code.model.branch.Branch"> |
6 | <require |
7 | permission="launchpad.View" |
8 | - attributes="id |
9 | - branch_type |
10 | - name |
11 | - url |
12 | - composePublicURL |
13 | - whiteboard |
14 | - target |
15 | - mirror_status_message |
16 | - private |
17 | - registrant |
18 | - owner |
19 | - description |
20 | - author |
21 | - reviewer |
22 | - code_reviewer |
23 | - isPersonTrustedReviewer |
24 | - product |
25 | - unique_name |
26 | - displayname |
27 | - sort_key |
28 | - lifecycle_status |
29 | - last_mirrored |
30 | - last_mirrored_id |
31 | - last_mirror_attempt |
32 | - mirror_failures |
33 | - pull_disabled |
34 | - next_mirror_time |
35 | - last_scanned |
36 | - last_scanned_id |
37 | - revision_count |
38 | - bug_branches |
39 | - linked_bugs |
40 | - getLinkedBugsAndTasks |
41 | - linkBug |
42 | - unlinkBug |
43 | - spec_links |
44 | - linkSpecification |
45 | - unlinkSpecification |
46 | - revision_history |
47 | - subscriptions |
48 | - subscribers |
49 | - date_created |
50 | - date_last_modified |
51 | - latest_revisions |
52 | - landing_targets |
53 | - landing_candidates |
54 | - dependent_branches |
55 | - _createMergeProposal |
56 | - addLandingTarget |
57 | - scheduleDiffUpdates |
58 | - getMergeQueue |
59 | - getRevisionsSince |
60 | - code_is_browseable |
61 | - browse_source_url |
62 | - code_import |
63 | - bzr_identity |
64 | - canBeDeleted |
65 | - deletionRequirements |
66 | - associatedProductSeries |
67 | - getProductSeriesPushingTranslations |
68 | - associatedSuiteSourcePackages |
69 | - branchIdentities |
70 | - branchLinks |
71 | - subscribe |
72 | - getSubscription |
73 | - hasSubscription |
74 | - unsubscribe |
75 | - getSubscriptionsByLevel |
76 | - getBranchRevision |
77 | - getMainlineBranchRevisions |
78 | - getMergeProposals |
79 | - getStackedBranches |
80 | - createBranchRevision |
81 | - getTipRevision |
82 | - updateScannedDetails |
83 | - getNotificationRecipients |
84 | - getScannerData |
85 | - getPullURL |
86 | - getInternalBzrUrl |
87 | - getBzrBranch |
88 | - requestMirror |
89 | - startMirroring |
90 | - mirrorFailed |
91 | - branch_format |
92 | - repository_format |
93 | - control_format |
94 | - stacked_on |
95 | - createBranchRevisionFromIDs |
96 | - distroseries |
97 | - sourcepackagename |
98 | - addToLaunchBag |
99 | - distribution |
100 | - sourcepackage |
101 | - codebrowse_url |
102 | - merge_queue |
103 | - namespace |
104 | - pending_writes |
105 | - commitsForDays |
106 | - needs_upgrading |
107 | - upgrade_pending |
108 | - getUpgradeFormat |
109 | - isBranchMergeable |
110 | - visibleByUser |
111 | - getRecipes |
112 | - "/> |
113 | + interface="canonical.launchpad.interfaces.launchpad.IPrivacy |
114 | + lp.code.interfaces.branch.IBranchAnyone |
115 | + lp.code.interfaces.branch.IBranchEditableAttributes |
116 | + lp.code.interfaces.branch.IBranchPublic |
117 | + lp.code.interfaces.branch.IBranchView |
118 | + "/> |
119 | <require |
120 | permission="launchpad.Edit" |
121 | - attributes="destroySelf destroySelfBreakReferences setPrivate |
122 | - setOwner setTarget requestUpgrade branchChanged" |
123 | - set_attributes="name url mirror_status_message |
124 | - description lifecycle_status |
125 | - last_mirrored last_mirrored_id last_mirror_attempt |
126 | - mirror_failures pull_disabled next_mirror_time |
127 | - last_scanned last_scanned_id revision_count branch_type |
128 | - reviewer branch_format repository_format |
129 | - control_format stacked_on merge_queue |
130 | - merge_control_status"/> |
131 | + interface="lp.code.interfaces.branch.IBranchEdit" |
132 | + set_schema="lp.code.interfaces.branch.IBranchEditableAttributes" |
133 | + attributes="setPrivate" |
134 | + set_attributes="branch_format control_format repository_format |
135 | + branch_type |
136 | + last_scanned last_scanned_id |
137 | + last_mirrored last_mirrored_id next_mirror_time |
138 | + revision_count merge_queue mirror_failures |
139 | + stacked_on mirror_status_message"/> |
140 | <require |
141 | permission="launchpad.AnyPerson" |
142 | - set_attributes="whiteboard"/> |
143 | + set_schema="lp.code.interfaces.branch.IBranchAnyone"/> |
144 | <require |
145 | permission="zope.Public" |
146 | - set_attributes="date_last_modified"/> |
147 | + set_schema="lp.code.interfaces.branch.IBranchPublic"/> |
148 | </class> |
149 | <adapter |
150 | for="lp.code.interfaces.branch.IBranch" |
151 | |
152 | === modified file 'lib/lp/code/interfaces/branch.py' |
153 | --- lib/lp/code/interfaces/branch.py 2010-07-09 10:22:32 +0000 |
154 | +++ lib/lp/code/interfaces/branch.py 2010-07-22 09:28:53 +0000 |
155 | @@ -57,12 +57,17 @@ |
156 | from canonical.launchpad import _ |
157 | from canonical.launchpad.fields import ( |
158 | ParticipatingPersonChoice, PublicPersonChoice, URIField, Whiteboard) |
159 | +from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
160 | from canonical.launchpad.validators import LaunchpadValidationError |
161 | +from canonical.launchpad.webapp.interfaces import ( |
162 | + ITableBatchNavigator, NameLookupFailed) |
163 | +from canonical.launchpad.webapp.menu import structured |
164 | from lp.code.bzr import BranchFormat, ControlFormat, RepositoryFormat |
165 | from lp.code.enums import ( |
166 | BranchLifecycleStatus, |
167 | BranchMergeControlStatus, |
168 | - BranchSubscriptionNotificationLevel, BranchSubscriptionDiffSize, |
169 | + BranchSubscriptionDiffSize, |
170 | + BranchSubscriptionNotificationLevel, |
171 | CodeReviewNotificationLevel, |
172 | UICreatableBranchType, |
173 | ) |
174 | @@ -71,14 +76,9 @@ |
175 | from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch |
176 | from lp.code.interfaces.hasbranches import IHasMergeProposals |
177 | from lp.code.interfaces.hasrecipes import IHasRecipes |
178 | -from canonical.launchpad.interfaces.launchpad import ( |
179 | - ILaunchpadCelebrities, IPrivacy) |
180 | from lp.registry.interfaces.role import IHasOwner |
181 | from lp.registry.interfaces.person import IPerson |
182 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
183 | -from canonical.launchpad.webapp.interfaces import ( |
184 | - ITableBatchNavigator, NameLookupFailed) |
185 | -from canonical.launchpad.webapp.menu import structured |
186 | |
187 | |
188 | DEFAULT_BRANCH_STATUS_IN_LISTING = ( |
189 | @@ -317,50 +317,31 @@ |
190 | """A marker interface to indicate the need to show the branch menu.""" |
191 | |
192 | |
193 | -class IBranch(IHasOwner, IPrivacy, IHasBranchTarget, IHasMergeProposals, |
194 | - IHasRecipes): |
195 | - """A Bazaar branch.""" |
196 | - |
197 | - # Mark branches as exported entries for the Launchpad API. |
198 | - export_as_webservice_entry(plural_name='branches') |
199 | +class IBranchPublic(Interface): |
200 | + """Public attributes for a branch.""" |
201 | + |
202 | + date_last_modified = exported( |
203 | + Datetime( |
204 | + title=_('Date Last Modified'), |
205 | + required=True, |
206 | + readonly=False)) |
207 | + |
208 | + |
209 | +class IBranchAnyone(Interface): |
210 | + """Attributes of IBranch that can be changed by launchpad.AnyPerson.""" |
211 | + |
212 | + whiteboard = exported( |
213 | + Whiteboard( |
214 | + title=_('Whiteboard'), required=False, |
215 | + description=_('Notes on the current status of the branch.'))) |
216 | + |
217 | + |
218 | +class IBranchView(IHasOwner, IHasBranchTarget, IHasMergeProposals, |
219 | + IHasRecipes): |
220 | + """IBranch attributes that require launchpad.View permission.""" |
221 | |
222 | id = Int(title=_('ID'), readonly=True, required=True) |
223 | |
224 | - # XXX: TimPenhey 2007-08-31 |
225 | - # The vocabulary set for branch_type is only used for the creation |
226 | - # of branches through the automatically generated forms, and doesn't |
227 | - # actually represent the complete range of real values that branch_type |
228 | - # may actually hold. Import branches are not created in the same |
229 | - # way as Hosted, Mirrored or Remote branches. |
230 | - # There are two option: |
231 | - # 1) define a separate schema to use in the UI (sledgehammer solution) |
232 | - # 2) work out some way to specify a restricted vocabulary in the view |
233 | - # Personally I'd like a LAZR way to do number 2. |
234 | - branch_type = exported( |
235 | - Choice( |
236 | - title=_("Branch Type"), required=True, readonly=True, |
237 | - vocabulary=UICreatableBranchType)) |
238 | - |
239 | - name = exported( |
240 | - TextLine( |
241 | - title=_('Name'), required=True, constraint=branch_name_validator, |
242 | - description=_( |
243 | - "Keep very short, unique, and descriptive, because it will " |
244 | - "be used in URLs. " |
245 | - "Examples: main, devel, release-1.0, gnome-vfs."))) |
246 | - |
247 | - url = exported( |
248 | - BranchURIField( |
249 | - title=_('Branch URL'), required=False, |
250 | - allowed_schemes=['http', 'https', 'ftp', 'sftp', 'bzr+ssh'], |
251 | - allow_userinfo=False, |
252 | - allow_query=False, |
253 | - allow_fragment=False, |
254 | - trailing_slash=False, |
255 | - description=_( |
256 | - "This is the external location where the Bazaar " |
257 | - "branch is hosted."))) |
258 | - |
259 | @operation_parameters( |
260 | scheme=TextLine(title=_("URL scheme"), default=u'http')) |
261 | @export_read_operation() |
262 | @@ -372,57 +353,6 @@ |
263 | accepted). |
264 | """ |
265 | |
266 | - description = exported( |
267 | - Text( |
268 | - title=_('Description'), required=False, |
269 | - description=_( |
270 | - 'A short description of the changes in this branch.'))) |
271 | - |
272 | - branch_format = exported( |
273 | - Choice( |
274 | - title=_("Branch Format"), |
275 | - required=False, readonly=True, |
276 | - vocabulary=BranchFormat)) |
277 | - |
278 | - repository_format = exported( |
279 | - Choice( |
280 | - title=_("Repository Format"), |
281 | - required=False, readonly=True, |
282 | - vocabulary=RepositoryFormat)) |
283 | - |
284 | - control_format = exported( |
285 | - Choice( |
286 | - title=_("Control Directory"), |
287 | - required=False, readonly=True, |
288 | - vocabulary=ControlFormat)) |
289 | - |
290 | - whiteboard = exported( |
291 | - Whiteboard( |
292 | - title=_('Whiteboard'), required=False, |
293 | - description=_('Notes on the current status of the branch.'))) |
294 | - |
295 | - mirror_status_message = exported( |
296 | - Text( |
297 | - title=_('The last message we got when mirroring this branch.'), |
298 | - required=False, readonly=True)) |
299 | - |
300 | - # This is redefined from IPrivacy.private because the attribute is |
301 | - # read-only. The value is guarded by setPrivate(). |
302 | - private = exported( |
303 | - Bool( |
304 | - title=_("Keep branch confidential"), required=False, |
305 | - readonly=True, default=False, |
306 | - description=_( |
307 | - "Make this branch visible only to its subscribers."))) |
308 | - |
309 | - @mutator_for(private) |
310 | - @call_with(user=REQUEST_USER) |
311 | - @operation_parameters( |
312 | - private=Bool(title=_("Keep branch confidential"))) |
313 | - @export_write_operation() |
314 | - def setPrivate(private, user): |
315 | - """Set the branch privacy for this branch.""" |
316 | - |
317 | # People attributes |
318 | registrant = exported( |
319 | PublicPersonChoice( |
320 | @@ -438,44 +368,6 @@ |
321 | description=_("Either yourself or a team you are a member of. " |
322 | "This controls who can modify the branch."))) |
323 | |
324 | - @call_with(user=REQUEST_USER) |
325 | - @operation_parameters( |
326 | - new_owner=Reference( |
327 | - title=_("The new owner of the branch."), |
328 | - schema=IPerson)) |
329 | - @export_write_operation() |
330 | - def setOwner(new_owner, user): |
331 | - """Set the owner of the branch to be `new_owner`.""" |
332 | - |
333 | - @call_with(user=REQUEST_USER) |
334 | - @operation_parameters( |
335 | - project=Reference( |
336 | - title=_("The project the branch belongs to."), |
337 | - schema=Interface, required=False), # Really IProduct |
338 | - source_package=Reference( |
339 | - title=_("The source package the branch belongs to."), |
340 | - schema=Interface, required=False)) # Really ISourcePackage |
341 | - @export_write_operation() |
342 | - def setTarget(user, project=None, source_package=None): |
343 | - """Set the target of the branch to be `project` or `source_package`. |
344 | - |
345 | - Only one of `project` or `source_package` can be set, and if neither |
346 | - is set, the branch gets moved into the junk namespace of the branch |
347 | - owner. |
348 | - |
349 | - :raise: `BranchTargetError` if both project and source_package are set, |
350 | - or if either the project or source_package fail to be adapted to an |
351 | - IBranchTarget. |
352 | - """ |
353 | - |
354 | - reviewer = exported( |
355 | - PublicPersonChoice( |
356 | - title=_('Review Team'), |
357 | - required=False, |
358 | - vocabulary='ValidPersonOrTeam', |
359 | - description=_("The reviewer of a branch is the person or team " |
360 | - "that is responsible for reviewing proposals and " |
361 | - "merging into this branch."))) |
362 | |
363 | # Distroseries and sourcepackagename are exported together as |
364 | # the sourcepackage. |
365 | @@ -505,22 +397,6 @@ |
366 | "None if not a package branch."), |
367 | schema=Interface, required=False, readonly=True)) |
368 | |
369 | - code_reviewer = Attribute( |
370 | - "The reviewer if set, otherwise the owner of the branch.") |
371 | - |
372 | - @operation_parameters( |
373 | - reviewer=Reference( |
374 | - title=_("A person for which the reviewer status is in question."), |
375 | - schema=IPerson)) |
376 | - @export_read_operation() |
377 | - def isPersonTrustedReviewer(reviewer): |
378 | - """Return true if the `reviewer` is a trusted reviewer. |
379 | - |
380 | - The reviewer is trusted if they are either own the branch, or are in |
381 | - the team that owns the branch, or they are in the review team for the |
382 | - branch. |
383 | - """ |
384 | - |
385 | namespace = Attribute( |
386 | "The namespace of this branch, as an `IBranchNamespace`.") |
387 | |
388 | @@ -549,29 +425,38 @@ |
389 | "The branch unique_name.")), |
390 | exported_as='display_name') |
391 | |
392 | - # Stats and status attributes |
393 | - lifecycle_status = exported( |
394 | - Choice( |
395 | - title=_('Status'), vocabulary=BranchLifecycleStatus, |
396 | - default=BranchLifecycleStatus.DEVELOPMENT)) |
397 | - |
398 | - # Mirroring attributes. For more information about how these all relate to |
399 | - # each other, look at |
400 | - # 'lib/canonical/launchpad/doc/puller-state-table.ods'. |
401 | + code_reviewer = Attribute( |
402 | + "The reviewer if set, otherwise the owner of the branch.") |
403 | + |
404 | + @operation_parameters( |
405 | + reviewer=Reference( |
406 | + title=_("A person for which the reviewer status is in question."), |
407 | + schema=IPerson)) |
408 | + @export_read_operation() |
409 | + def isPersonTrustedReviewer(reviewer): |
410 | + """Return true if the `reviewer` is a trusted reviewer. |
411 | + |
412 | + The reviewer is trusted if they are either own the branch, or are in |
413 | + the team that owns the branch, or they are in the review team for the |
414 | + branch. |
415 | + """ |
416 | + |
417 | last_mirrored = exported( |
418 | Datetime( |
419 | title=_("Last time this branch was successfully mirrored."), |
420 | required=False, readonly=True)) |
421 | last_mirrored_id = Text( |
422 | - title=_("Last mirrored revision ID"), required=False, |
423 | + title=_("Last mirrored revision ID"), required=False, readonly=True, |
424 | description=_("The head revision ID of the branch when last " |
425 | "successfully mirrored.")) |
426 | last_mirror_attempt = exported( |
427 | Datetime( |
428 | title=_("Last time a mirror of this branch was attempted."), |
429 | required=False, readonly=True)) |
430 | + |
431 | mirror_failures = Attribute( |
432 | "Number of failed mirror attempts since the last successful mirror.") |
433 | + |
434 | next_mirror_time = Datetime( |
435 | title=_("If this value is more recent than the last mirror attempt, " |
436 | "then the branch will be mirrored on the next mirror run."), |
437 | @@ -596,6 +481,9 @@ |
438 | |
439 | stacked_on = Attribute('Stacked-on branch') |
440 | |
441 | + merge_queue = Attribute( |
442 | + "The queue that contains the QUEUED proposals for this branch.") |
443 | + |
444 | # Bug attributes |
445 | bug_branches = CollectionField( |
446 | title=_("The bug-branch link objects that link this branch " |
447 | @@ -663,9 +551,6 @@ |
448 | :param user: IPerson unlinking the spec. |
449 | """ |
450 | |
451 | - pending_writes = Attribute( |
452 | - "Whether there is new Bazaar data for this branch.") |
453 | - |
454 | # Joins |
455 | revision_history = Attribute( |
456 | """The sequence of BranchRevision for the mainline of that branch. |
457 | @@ -693,30 +578,8 @@ |
458 | required=True, |
459 | readonly=True)) |
460 | |
461 | - date_last_modified = exported( |
462 | - Datetime( |
463 | - title=_('Date Last Modified'), |
464 | - required=True, |
465 | - readonly=False)) |
466 | - |
467 | - @export_destructor_operation() |
468 | - def destroySelfBreakReferences(): |
469 | - """Delete the specified branch. |
470 | - |
471 | - BranchRevisions associated with this branch will also be deleted as |
472 | - well as any items with mandatory references. |
473 | - """ |
474 | - |
475 | - def destroySelf(break_references=False): |
476 | - """Delete the specified branch. |
477 | - |
478 | - BranchRevisions associated with this branch will also be deleted. |
479 | - |
480 | - :param break_references: If supplied, break any references to this |
481 | - branch by deleting items with mandatory references and |
482 | - NULLing other references. |
483 | - :raise: CannotDeleteBranch if the branch cannot be deleted. |
484 | - """ |
485 | + pending_writes = Attribute( |
486 | + "Whether there is new Bazaar data for this branch.") |
487 | |
488 | def latest_revisions(quantity=10): |
489 | """A specific number of the latest revisions in that branch.""" |
490 | @@ -815,14 +678,6 @@ |
491 | def getStackedBranches(): |
492 | """The branches that are stacked on this one.""" |
493 | |
494 | - merge_queue = Attribute( |
495 | - "The queue that contains the QUEUED proposals for this branch.") |
496 | - |
497 | - merge_control_status = Choice( |
498 | - title=_('Merge Control Status'), required=True, |
499 | - vocabulary=BranchMergeControlStatus, |
500 | - default=BranchMergeControlStatus.NO_QUEUE) |
501 | - |
502 | def getMergeQueue(): |
503 | """The proposals that are QUEUED to land on this branch.""" |
504 | |
505 | @@ -1111,23 +966,6 @@ |
506 | def startMirroring(): |
507 | """Signal that this branch is being mirrored.""" |
508 | |
509 | - def branchChanged(stacked_on_url, last_revision_id, control_format, |
510 | - branch_format, repository_format): |
511 | - """Record that a branch has been changed. |
512 | - |
513 | - This method records the stacked on branch tip revision id and format |
514 | - or the branch and creates a scan job if the tip revision id has |
515 | - changed. |
516 | - |
517 | - :param stacked_on_url: The unique name of the branch this branch is |
518 | - stacked on, or '' if this branch is not stacked. |
519 | - :param last_revision_id: The tip revision ID of the branch. |
520 | - :param control_format: The entry from ControlFormat for the branch. |
521 | - :param branch_format: The entry from BranchFormat for the branch. |
522 | - :param repository_format: The entry from RepositoryFormat for the |
523 | - branch. |
524 | - """ |
525 | - |
526 | def mirrorFailed(reason): |
527 | """Signal that a mirror attempt failed. |
528 | |
529 | @@ -1148,11 +986,196 @@ |
530 | upgrade_pending = Attribute( |
531 | "Whether a branch has had an upgrade requested.") |
532 | |
533 | + def visibleByUser(user): |
534 | + """Can the specified user see this branch?""" |
535 | + |
536 | + |
537 | +class IBranchEditableAttributes(Interface): |
538 | + """IBranch attributes that can be edited. |
539 | + |
540 | + These attributes need launchpad.View to see, and launchpad.Edit to change. |
541 | + """ |
542 | + |
543 | + name = exported( |
544 | + TextLine( |
545 | + title=_('Name'), required=True, constraint=branch_name_validator, |
546 | + description=_( |
547 | + "Keep very short, unique, and descriptive, because it will " |
548 | + "be used in URLs. " |
549 | + "Examples: main, devel, release-1.0, gnome-vfs."))) |
550 | + |
551 | + reviewer = exported( |
552 | + PublicPersonChoice( |
553 | + title=_('Review Team'), |
554 | + required=False, |
555 | + vocabulary='ValidPersonOrTeam', |
556 | + description=_("The reviewer of a branch is the person or team " |
557 | + "that is responsible for reviewing proposals and " |
558 | + "merging into this branch."))) |
559 | + |
560 | + url = exported( |
561 | + BranchURIField( |
562 | + title=_('Branch URL'), required=False, |
563 | + allowed_schemes=['http', 'https', 'ftp', 'sftp', 'bzr+ssh'], |
564 | + allow_userinfo=False, |
565 | + allow_query=False, |
566 | + allow_fragment=False, |
567 | + trailing_slash=False, |
568 | + description=_( |
569 | + "This is the external location where the Bazaar " |
570 | + "branch is hosted."))) |
571 | + |
572 | + mirror_status_message = exported( |
573 | + Text( |
574 | + title=_('The last message we got when mirroring this branch.'), |
575 | + required=False, readonly=True)) |
576 | + |
577 | + # XXX: TimPenhey 2007-08-31 |
578 | + # The vocabulary set for branch_type is only used for the creation |
579 | + # of branches through the automatically generated forms, and doesn't |
580 | + # actually represent the complete range of real values that branch_type |
581 | + # may actually hold. Import branches are not created in the same |
582 | + # way as Hosted, Mirrored or Remote branches. |
583 | + # There are two option: |
584 | + # 1) define a separate schema to use in the UI (sledgehammer solution) |
585 | + # 2) work out some way to specify a restricted vocabulary in the view |
586 | + # Personally I'd like a LAZR way to do number 2. |
587 | + branch_type = exported( |
588 | + Choice( |
589 | + title=_("Branch Type"), required=True, readonly=True, |
590 | + vocabulary=UICreatableBranchType)) |
591 | + |
592 | + description = exported( |
593 | + Text( |
594 | + title=_('Description'), required=False, |
595 | + description=_( |
596 | + 'A short description of the changes in this branch.'))) |
597 | + |
598 | + lifecycle_status = exported( |
599 | + Choice( |
600 | + title=_('Status'), vocabulary=BranchLifecycleStatus, |
601 | + default=BranchLifecycleStatus.DEVELOPMENT)) |
602 | + |
603 | + branch_format = exported( |
604 | + Choice( |
605 | + title=_("Branch Format"), |
606 | + required=False, readonly=True, |
607 | + vocabulary=BranchFormat)) |
608 | + |
609 | + repository_format = exported( |
610 | + Choice( |
611 | + title=_("Repository Format"), |
612 | + required=False, readonly=True, |
613 | + vocabulary=RepositoryFormat)) |
614 | + |
615 | + control_format = exported( |
616 | + Choice( |
617 | + title=_("Control Directory"), |
618 | + required=False, readonly=True, |
619 | + vocabulary=ControlFormat)) |
620 | + |
621 | + merge_control_status = Choice( |
622 | + title=_('Merge Control Status'), required=True, |
623 | + vocabulary=BranchMergeControlStatus, |
624 | + default=BranchMergeControlStatus.NO_QUEUE) |
625 | + |
626 | + |
627 | +class IBranchEdit(Interface): |
628 | + """IBranch attributes that require launchpad.Edit permission.""" |
629 | + |
630 | + @call_with(user=REQUEST_USER) |
631 | + @operation_parameters( |
632 | + new_owner=Reference( |
633 | + title=_("The new owner of the branch."), |
634 | + schema=IPerson)) |
635 | + @export_write_operation() |
636 | + def setOwner(new_owner, user): |
637 | + """Set the owner of the branch to be `new_owner`.""" |
638 | + |
639 | + @call_with(user=REQUEST_USER) |
640 | + @operation_parameters( |
641 | + project=Reference( |
642 | + title=_("The project the branch belongs to."), |
643 | + schema=Interface, required=False), # Really IProduct |
644 | + source_package=Reference( |
645 | + title=_("The source package the branch belongs to."), |
646 | + schema=Interface, required=False)) # Really ISourcePackage |
647 | + @export_write_operation() |
648 | + def setTarget(user, project=None, source_package=None): |
649 | + """Set the target of the branch to be `project` or `source_package`. |
650 | + |
651 | + Only one of `project` or `source_package` can be set, and if neither |
652 | + is set, the branch gets moved into the junk namespace of the branch |
653 | + owner. |
654 | + |
655 | + :raise: `BranchTargetError` if both project and source_package are set, |
656 | + or if either the project or source_package fail to be adapted to an |
657 | + IBranchTarget. |
658 | + """ |
659 | + |
660 | def requestUpgrade(): |
661 | """Create an IBranchUpgradeJob to upgrade this branch.""" |
662 | |
663 | - def visibleByUser(user): |
664 | - """Can the specified user see this branch?""" |
665 | + def branchChanged(stacked_on_url, last_revision_id, control_format, |
666 | + branch_format, repository_format): |
667 | + """Record that a branch has been changed. |
668 | + |
669 | + This method records the stacked on branch tip revision id and format |
670 | + or the branch and creates a scan job if the tip revision id has |
671 | + changed. |
672 | + |
673 | + :param stacked_on_url: The unique name of the branch this branch is |
674 | + stacked on, or '' if this branch is not stacked. |
675 | + :param last_revision_id: The tip revision ID of the branch. |
676 | + :param control_format: The entry from ControlFormat for the branch. |
677 | + :param branch_format: The entry from BranchFormat for the branch. |
678 | + :param repository_format: The entry from RepositoryFormat for the |
679 | + branch. |
680 | + """ |
681 | + |
682 | + @export_destructor_operation() |
683 | + def destroySelfBreakReferences(): |
684 | + """Delete the specified branch. |
685 | + |
686 | + BranchRevisions associated with this branch will also be deleted as |
687 | + well as any items with mandatory references. |
688 | + """ |
689 | + |
690 | + def destroySelf(break_references=False): |
691 | + """Delete the specified branch. |
692 | + |
693 | + BranchRevisions associated with this branch will also be deleted. |
694 | + |
695 | + :param break_references: If supplied, break any references to this |
696 | + branch by deleting items with mandatory references and |
697 | + NULLing other references. |
698 | + :raise: CannotDeleteBranch if the branch cannot be deleted. |
699 | + """ |
700 | + |
701 | + |
702 | +class IBranch(IBranchPublic, IBranchView, IBranchEdit, |
703 | + IBranchEditableAttributes, IBranchAnyone): |
704 | + """A Bazaar branch.""" |
705 | + |
706 | + # Mark branches as exported entries for the Launchpad API. |
707 | + export_as_webservice_entry(plural_name='branches') |
708 | + |
709 | + # This is redefined from IPrivacy.private because the attribute is |
710 | + # read-only. The value is guarded by setPrivate(). |
711 | + private = exported( |
712 | + Bool( |
713 | + title=_("Keep branch confidential"), required=False, |
714 | + readonly=True, default=False, |
715 | + description=_( |
716 | + "Make this branch visible only to its subscribers."))) |
717 | + |
718 | + @mutator_for(private) |
719 | + @call_with(user=REQUEST_USER) |
720 | + @operation_parameters( |
721 | + private=Bool(title=_("Keep branch confidential"))) |
722 | + @export_write_operation() |
723 | + def setPrivate(private, user): |
724 | + """Set the branch privacy for this branch.""" |
725 | |
726 | |
727 | class IBranchSet(Interface): |
728 | |
729 | === modified file 'lib/lp/code/model/branch.py' |
730 | --- lib/lp/code/model/branch.py 2010-07-17 22:49:11 +0000 |
731 | +++ lib/lp/code/model/branch.py 2010-07-22 09:28:53 +0000 |
732 | @@ -40,7 +40,8 @@ |
733 | |
734 | from canonical.launchpad import _ |
735 | from lp.services.job.model.job import Job |
736 | -from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities |
737 | +from canonical.launchpad.interfaces.launchpad import ( |
738 | + ILaunchpadCelebrities, IPrivacy) |
739 | from canonical.launchpad.webapp import urlappend |
740 | from canonical.launchpad.webapp.interfaces import ( |
741 | IStoreSelector, MAIN_STORE, SLAVE_FLAVOR) |
742 | @@ -88,7 +89,7 @@ |
743 | class Branch(SQLBase, BzrIdentityMixin): |
744 | """A sequence of ordered revisions in Bazaar.""" |
745 | |
746 | - implements(IBranch, IBranchNavigationMenu) |
747 | + implements(IBranch, IBranchNavigationMenu, IPrivacy) |
748 | _table = 'Branch' |
749 | |
750 | branch_type = EnumCol(enum=BranchType, notNull=True) |
boring