Merge lp://staging/~jml/launchpad/ubuntu-package-bug-345737 into lp://staging/launchpad

Proposed by Jonathan Lange
Status: Merged
Merged at revision: not available
Proposed branch: lp://staging/~jml/launchpad/ubuntu-package-bug-345737
Merge into: lp://staging/launchpad
Diff against target: None lines
To merge this branch: bzr merge lp://staging/~jml/launchpad/ubuntu-package-bug-345737
Reviewer Review Type Date Requested Status
Tim Penhey (community) Approve
Review via email: mp+8868@code.staging.launchpad.net
To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :

This branch makes lp:ubuntu/foo resolve to the branch associated with the development version of the 'foo' package on Ubuntu, defined as the branch linked to the Release pocket of that package of the current series of that distribution.

To do this, I've registered a new adapter from DistributionSourcePackage to ICanHasLinkedBranch. While I was there, I also added a bzr_identity attribute to ICanHasLinkedBranch, as well as a setBranch method. Neither of these are deeply associated with the change, but they are both things that are related & I've wanted to do for a while.

bazaar_identity has been changed to return 'lp:ubuntu/package' for source package branches associated to the development focus package.

I had to change the linked branch traversal code to pass segments into the traversable adapters. This was so I could raise context-aware errors in the case of 'ubuntu/doesntexist' and 'ubuntu/doesntexist/openssh'.

I've also increased the interlinking of distro-related registry objects. In particular, SourcePackage now links to DistributionSourcePackage (the latter being conceptually a parent of the former), and DistributionSourcePackage links to the development source package.

There are a lot of pyflakes & pep8 cleanups along the way, inflating the size of the diff.

I've also based this branch on lp:~jml/launchpad/remove-getitem. This was necessary in order to get the adapt() method behaving correctly with DistributionSourcePackage.

Revision history for this message
Tim Penhey (thumper) wrote :
Download full text (16.6 KiB)

> bazaar_identity has been changed to return 'lp:ubuntu/package' for source
> package branches associated to the development focus package.

My first thought on reading this was "for just the release pocket?", but I
guess we'll see.

> === modified file 'lib/lp/code/interfaces/branch.py'
> --- lib/lp/code/interfaces/branch.py 2009-07-15 01:45:35 +0000
> +++ lib/lp/code/interfaces/branch.py 2009-07-16 04:47:24 +0000
> @@ -1131,6 +1130,10 @@
> 'series': use_series.name}
>
> if branch.sourcepackage is not None:
> + distro_package = branch.sourcepackage.distribution_sourcepackage
> + linked_branch = ICanHasLinkedBranch(distro_package)
> + if linked_branch.branch == branch:
> + return lp_prefix + linked_branch.bzr_identity

What object traversal is really going on here? And how will it impact getting
bazaar_identities for branch listings?

branch.sourcepackage -> No other queries
.distribution_sourcepackage -> Other queries?
Adaption -> other queries?

> === modified file 'lib/lp/code/model/linkedbranch.py'
> --- lib/lp/code/model/linkedbranch.py 2009-05-15 03:16:18 +0000
> +++ lib/lp/code/model/linkedbranch.py 2009-07-16 05:38:41 +0000
> @@ -30,6 +33,16 @@
> """See `ICanHasLinkedBranch`."""
> return self.product_series.branch
>
> + @property
> + def bzr_identity(self):
> + """See `ICanHasLinkedBranch`."""
> + return '/'.join(
> + [self.product_series.product.name, self.product_series.name])

I think that the bzr_identity here (and in following adapters) should really
have the lp: prefix too (from the config variable). Otherwise bzr_identity
functions in different places return different types of strings.

Also, it shouldn't really return anything if there is not a branch set.

> @@ -45,6 +58,15 @@
> """See `ICanHasLinkedBranch`."""
> return ICanHasLinkedBranch(self.product.development_focus).branch
>
> + @property
> + def bzr_identity(self):
> + """See `ICanHasLinkedBranch`."""
> + return self.product.name
> +
> + def setBranch(self, branch, registrant=None):
> + """See `ICanHasLinkedBranch`."""
> +
ICanHasLinkedBranch(self.product.development_focus).setBranch(branch)

I think you should also pass the registrant through. If we start to record
it, it'll save changing this later.

> +
>
> class PackageLinkedBranch:
> """Implement a linked branch for a source package pocket."""
> @@ -61,3 +83,50 @@
> package = self.suite_sourcepackage.sourcepackage
> pocket = self.suite_sourcepackage.pocket
> return package.getBranch(pocket)
> +
> + @property
> + def bzr_identity(self):
> + """See `ICanHasLinkedBranch`."""
> + return self.suite_sourcepackage.path
> +
> + def setBranch(self, branch, registrant):
> + """See `ICanHasLinkedBranch`."""
> + package = self.suite_sourcepackage.sourcepackage
> + pocket = self.suite_sourcepackage.pocket
> + package.setBranch(pocket, branch, registrant)
> +
> +
> +class DistributionPackageLinkedBranch:
> + """Implement a linked branch for an `IDistributionSourcePackage`."""
> +
...

review: Needs Information
Revision history for this message
Jonathan Lange (jml) wrote :
Download full text (19.2 KiB)

On Fri, Jul 17, 2009 at 11:00 AM, Tim Penhey<email address hidden> wrote:
> Review: Needs Information
>> bazaar_identity has been changed to return 'lp:ubuntu/package' for source
>> package branches associated to the development focus package.
>
> My first thought on reading this was "for just the release pocket?", but I
> guess we'll see.
>

Yeah, just for the release pocket.

>> === modified file 'lib/lp/code/interfaces/branch.py'
>> --- lib/lp/code/interfaces/branch.py  2009-07-15 01:45:35 +0000
>> +++ lib/lp/code/interfaces/branch.py  2009-07-16 04:47:24 +0000
>> @@ -1131,6 +1130,10 @@
>>              'series': use_series.name}
>>
>>      if branch.sourcepackage is not None:
>> +        distro_package = branch.sourcepackage.distribution_sourcepackage
>> +        linked_branch = ICanHasLinkedBranch(distro_package)
>> +        if linked_branch.branch == branch:
>> +            return lp_prefix + linked_branch.bzr_identity
>
> What object traversal is really going on here?  And how will it impact getting
> bazaar_identities for branch listings?
>
> branch.sourcepackage -> No other queries
> .distribution_sourcepackage -> Other queries?

No queries, it's a virtual object.

> Adaption -> other queries?
>

No queries in adaptation either.

However, getting the bzr_identity from the adapted object requires
loading the currentseries from the DistroSeries table. You probably
want to have a look at Distribution.currentseries anyway to resolve
some of your other questions.

If possible, I'd rather land this branch now with some performance
issues than in 2 months time.

>> === modified file 'lib/lp/code/model/linkedbranch.py'
>> --- lib/lp/code/model/linkedbranch.py 2009-05-15 03:16:18 +0000
>> +++ lib/lp/code/model/linkedbranch.py 2009-07-16 05:38:41 +0000
>> @@ -30,6 +33,16 @@
>>          """See `ICanHasLinkedBranch`."""
>>          return self.product_series.branch
>>
>> +    @property
>> +    def bzr_identity(self):
>> +        """See `ICanHasLinkedBranch`."""
>> +        return '/'.join(
>> +            [self.product_series.product.name, self.product_series.name])
>
> I think that the bzr_identity here (and in following adapters) should really
> have the lp: prefix too (from the config variable).  Otherwise bzr_identity
> functions in different places return different types of strings.
>

Fair enough, although in some ways I'd prefer keeping the current
behaviour and picking a different name. It seems wrong to imbue this
code with knowledge of the name of the server.

Oh, I see later on you suggest the names 'bzr_path' and
'bzr_identity_path' for a property with the current behaviour. I like
that.

Changed.

> Also, it shouldn't really return anything if there is not a branch set.
>

Why do you say that?

>> @@ -45,6 +58,15 @@
>>          """See `ICanHasLinkedBranch`."""
>>          return ICanHasLinkedBranch(self.product.development_focus).branch
>>
>> +    @property
>> +    def bzr_identity(self):
>> +        """See `ICanHasLinkedBranch`."""
>> +        return self.product.name
>> +
>> +    def setBranch(self, branch, registrant=None):
>> +        """See `ICanHasLinkedBranch`."""
>> +
> ICanHasLinkedBranch(self.product.development_focus).setBranch(...

Revision history for this message
Tim Penhey (thumper) wrote :

On Fri, 17 Jul 2009 20:03:07 Jonathan Lange wrote:
> If possible, I'd rather land this branch now with some performance
> issues than in 2 months time.

I agree.

> > Also, it shouldn't really return anything if there is not a branch set.
>
> Why do you say that?

OK, I guess not. As long as the documentation says that the bzr_path is the
path of the branch if there was a branch set.

> > ICanHasLinkedBranch(self.product.development_focus).setBranch(branch)
>
> Your wrapping here is very weird.

I blame my mail client.

> > This one has always bothered me. We should not allow junk branches to be
> > linked rather than just saying that their links don't show it. What do
> > you think?
>
> As a general principle, I think we should do as little special-casing
> of +junk as possible. It always comes back to bite us.
>
> I personally think that we can do without this special case at all.
> However, if pressed, I'd favour simply preventing junk branches from
> being linked. I think it's for another branch though.

Definitely another branch.

> > To save with the login, logout dance, how about we just remove the
> > security proxy as with the other tests, but still pass the registrant
> > through.
>
> Doesn't work. Internally, the link is made by code that looks like:
> getUtility(ISeriesSourcePackageBranchSet).new(branch, pocket,
> distroseries, sourcepackagename)
>
> getUtility guarantees that the object is secured, and 'new' requires
> lp.Edit permissions.

Aah, ok. I wish we had a nicer way to test this without the logins, but not
for this branch.

> > The main questions I have resolve around the currentseries for a
> > distribution, and the actual content of ICanHasLinkedBranch.bzr_identity.
>
> Cool. I hope they're addressed here.

Yes. I wish that distribution always had one series by default like a
Product, but I think you've done as well as you can given that "some"
distributions may well not have set any series.

  review approve

review: Approve
Revision history for this message
Jonathan Lange (jml) wrote :

On Mon, Jul 20, 2009 at 8:48 AM, Tim Penhey<email address hidden> wrote:
> Review: Approve
> On Fri, 17 Jul 2009 20:03:07 Jonathan Lange wrote:
>> If possible, I'd rather land this branch now with some performance
>> issues than in 2 months time.
>
> I agree.
>
>> > Also, it shouldn't really return anything if there is not a branch set.
>>
>> Why do you say that?
>
> OK, I guess not.  As long as the documentation says that the bzr_path is the
> path of the branch if there was a branch set.
>

Done.

Landing now.

jml

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml 2009-07-15 01:45:35 +0000
+++ lib/lp/code/configure.zcml 2009-07-16 04:47:24 +0000
@@ -801,6 +801,7 @@
801 <adapter factory="lp.code.model.linkedbranch.ProductSeriesLinkedBranch" />801 <adapter factory="lp.code.model.linkedbranch.ProductSeriesLinkedBranch" />
802 <adapter factory="lp.code.model.linkedbranch.ProductLinkedBranch" />802 <adapter factory="lp.code.model.linkedbranch.ProductLinkedBranch" />
803 <adapter factory="lp.code.model.linkedbranch.PackageLinkedBranch" />803 <adapter factory="lp.code.model.linkedbranch.PackageLinkedBranch" />
804 <adapter factory="lp.code.model.linkedbranch.DistributionPackageLinkedBranch" />
804805
805 <lp:help-folder806 <lp:help-folder
806 folder="help" type="canonical.launchpad.layers.CodeLayer" />807 folder="help" type="canonical.launchpad.layers.CodeLayer" />
807808
=== modified file 'lib/lp/code/interfaces/branch.py'
--- lib/lp/code/interfaces/branch.py 2009-07-15 01:45:35 +0000
+++ lib/lp/code/interfaces/branch.py 2009-07-16 04:47:24 +0000
@@ -64,6 +64,7 @@
64 )64 )
65from lp.code.interfaces.branchlookup import IBranchLookup65from lp.code.interfaces.branchlookup import IBranchLookup
66from lp.code.interfaces.branchtarget import IHasBranchTarget66from lp.code.interfaces.branchtarget import IHasBranchTarget
67from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
67from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities68from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
68from lp.registry.interfaces.role import IHasOwner69from lp.registry.interfaces.role import IHasOwner
69from lp.registry.interfaces.person import IPerson70from lp.registry.interfaces.person import IPerson
@@ -81,6 +82,7 @@
81class BranchCreationException(Exception):82class BranchCreationException(Exception):
82 """Base class for branch creation exceptions."""83 """Base class for branch creation exceptions."""
8384
85
84class BranchExists(BranchCreationException):86class BranchExists(BranchCreationException):
85 """Raised when creating a branch that already exists."""87 """Raised when creating a branch that already exists."""
8688
@@ -738,8 +740,7 @@
738 'development focus, then the result should be lp:product. '740 'development focus, then the result should be lp:product. '
739 'If the branch is related to a series, then '741 'If the branch is related to a series, then '
740 'lp:product/series. Otherwise the result is '742 'lp:product/series. Otherwise the result is '
741 'lp:~user/product/branch-name.'743 'lp:~user/product/branch-name.')))
742 )))
743744
744 def addToLaunchBag(launchbag):745 def addToLaunchBag(launchbag):
745 """Add information about this branch to `launchbag'.746 """Add information about this branch to `launchbag'.
@@ -1083,8 +1084,6 @@
1083 last_scanned_id = Attribute("The revision id of the tip revision.")1084 last_scanned_id = Attribute("The revision id of the tip revision.")
10841085
10851086
1086
1087
1088class IBranchCloud(Interface):1087class IBranchCloud(Interface):
1089 """A utility to generate data for branch clouds.1088 """A utility to generate data for branch clouds.
10901089
@@ -1131,6 +1130,10 @@
1131 'series': use_series.name}1130 'series': use_series.name}
11321131
1133 if branch.sourcepackage is not None:1132 if branch.sourcepackage is not None:
1133 distro_package = branch.sourcepackage.distribution_sourcepackage
1134 linked_branch = ICanHasLinkedBranch(distro_package)
1135 if linked_branch.branch == branch:
1136 return lp_prefix + linked_branch.bzr_identity
1134 suite_sourcepackages = branch.associatedSuiteSourcePackages()1137 suite_sourcepackages = branch.associatedSuiteSourcePackages()
1135 # Take the first link if there is one.1138 # Take the first link if there is one.
1136 if len(suite_sourcepackages) > 0:1139 if len(suite_sourcepackages) > 0:
11371140
=== modified file 'lib/lp/code/interfaces/branchlookup.py'
--- lib/lp/code/interfaces/branchlookup.py 2009-05-15 03:16:18 +0000
+++ lib/lp/code/interfaces/branchlookup.py 2009-07-16 05:00:18 +0000
@@ -16,8 +16,14 @@
16class ILinkedBranchTraversable(Interface):16class ILinkedBranchTraversable(Interface):
17 """A thing that can be traversed to find a thing linked to a branch."""17 """A thing that can be traversed to find a thing linked to a branch."""
1818
19 def traverse(self, name):19 def traverse(self, name, segments):
20 """Return the object beneath this one that matches 'name'."""20 """Return the object beneath this one that matches 'name'.
21
22 :param name: The name of the object being traversed to.
23 :param segments: Remaining path segments.
24 :return: An `ILinkedBranchTraversable` object if traversing should
25 continue, an `ICanHasLinkedBranch` object otherwise.
26 """
2127
2228
23class ILinkedBranchTraverser(Interface):29class ILinkedBranchTraverser(Interface):
@@ -40,7 +46,7 @@
40 :return: One of46 :return: One of
41 * `IProduct`47 * `IProduct`
42 * `IProductSeries`48 * `IProductSeries`
43 * (ISourcePackage, PackagePublishingPocket)49 * `ISuiteSourcePackage`
44 * `IDistributionSourcePackage`50 * `IDistributionSourcePackage`
45 """51 """
4652
4753
=== modified file 'lib/lp/code/interfaces/linkedbranch.py'
--- lib/lp/code/interfaces/linkedbranch.py 2009-05-24 18:09:51 +0000
+++ lib/lp/code/interfaces/linkedbranch.py 2009-07-16 01:58:59 +0000
@@ -23,6 +23,16 @@
23 """Something that has a linked branch."""23 """Something that has a linked branch."""
2424
25 branch = Attribute("The linked branch.")25 branch = Attribute("The linked branch.")
26 bzr_identity = Attribute('The Bazaar branch path for the linked branch.')
27
28 def setBranch(branch, registrant=None):
29 """Set the linked branch.
30
31 :param branch: An `IBranch`. After calling this,
32 `ICanHasLinkedBranch.branch` will be 'branch'.
33 :param registrant: The `IPerson` linking the branch. Not used by all
34 implementations.
35 """
2636
2737
28class CannotHaveLinkedBranch(Exception):38class CannotHaveLinkedBranch(Exception):
2939
=== modified file 'lib/lp/code/model/branchlookup.py'
--- lib/lp/code/model/branchlookup.py 2009-05-15 03:16:18 +0000
+++ lib/lp/code/model/branchlookup.py 2009-07-16 05:39:51 +0000
@@ -29,7 +29,7 @@
29from lp.code.interfaces.linkedbranch import get_linked_branch, NoLinkedBranch29from lp.code.interfaces.linkedbranch import get_linked_branch, NoLinkedBranch
30from lp.registry.interfaces.distribution import IDistribution30from lp.registry.interfaces.distribution import IDistribution
31from lp.registry.interfaces.distroseries import (31from lp.registry.interfaces.distroseries import (
32 IDistroSeries, IDistroSeriesSet)32 IDistroSeries, IDistroSeriesSet, NoSuchDistroSeries)
33from lp.registry.interfaces.pillar import IPillarNameSet33from lp.registry.interfaces.pillar import IPillarNameSet
34from lp.registry.interfaces.product import (34from lp.registry.interfaces.product import (
35 InvalidProductName, IProduct, NoSuchProduct)35 InvalidProductName, IProduct, NoSuchProduct)
@@ -65,7 +65,7 @@
6565
66 implements(ILinkedBranchTraversable)66 implements(ILinkedBranchTraversable)
6767
68 def traverse(self, name):68 def traverse(self, name, segments):
69 """See `ITraversable`.69 """See `ITraversable`.
7070
71 :raise NoSuchProduct: If 'name' doesn't match an existing pillar.71 :raise NoSuchProduct: If 'name' doesn't match an existing pillar.
@@ -102,7 +102,7 @@
102 adapts(IProduct)102 adapts(IProduct)
103 implements(ILinkedBranchTraversable)103 implements(ILinkedBranchTraversable)
104104
105 def traverse(self, name):105 def traverse(self, name, segments):
106 """See `ITraversable`.106 """See `ITraversable`.
107107
108 :raises NoSuchProductSeries: if 'name' doesn't match an existing108 :raises NoSuchProductSeries: if 'name' doesn't match an existing
@@ -124,12 +124,18 @@
124 adapts(IDistribution)124 adapts(IDistribution)
125 implements(ILinkedBranchTraversable)125 implements(ILinkedBranchTraversable)
126126
127 def traverse(self, name):127 def traverse(self, name, segments):
128 """See `ITraversable`."""128 """See `ITraversable`."""
129 # XXX: JonathanLange 2009-03-20 spec=package-branches bug=345737: This129 try:
130 # could also try to find a package and then return a reference to its130 return getUtility(IDistroSeriesSet).fromSuite(self.context, name)
131 # development focus.131 except NoSuchDistroSeries:
132 return getUtility(IDistroSeriesSet).fromSuite(self.context, name)132 sourcepackage = self.context.getSourcePackage(name)
133 if sourcepackage is None:
134 if segments:
135 raise
136 else:
137 raise NoSuchSourcePackageName(name)
138 return sourcepackage
133139
134140
135class DistroSeriesTraversable:141class DistroSeriesTraversable:
@@ -145,7 +151,7 @@
145 self.distroseries = distroseries151 self.distroseries = distroseries
146 self.pocket = pocket152 self.pocket = pocket
147153
148 def traverse(self, name):154 def traverse(self, name, segments):
149 """See `ITraversable`."""155 """See `ITraversable`."""
150 sourcepackage = self.distroseries.getSourcePackage(name)156 sourcepackage = self.distroseries.getSourcePackage(name)
151 if sourcepackage is None:157 if sourcepackage is None:
@@ -170,7 +176,7 @@
170 traversable = RootTraversable()176 traversable = RootTraversable()
171 while segments:177 while segments:
172 name = segments.pop(0)178 name = segments.pop(0)
173 context = traversable.traverse(name)179 context = traversable.traverse(name, segments)
174 traversable = adapt(context, ILinkedBranchTraversable)180 traversable = adapt(context, ILinkedBranchTraversable)
175 if traversable is None:181 if traversable is None:
176 break182 break
@@ -332,7 +338,7 @@
332 namespace_set = getUtility(IBranchNamespaceSet)338 namespace_set = getUtility(IBranchNamespaceSet)
333 segments = iter(path.lstrip('~').split('/'))339 segments = iter(path.lstrip('~').split('/'))
334 branch = namespace_set.traverse(segments)340 branch = namespace_set.traverse(segments)
335 suffix = '/'.join(segments)341 suffix = '/'.join(segments)
336 if not check_permission('launchpad.View', branch):342 if not check_permission('launchpad.View', branch):
337 raise NoSuchBranch(path)343 raise NoSuchBranch(path)
338 if suffix == '':344 if suffix == '':
339345
=== modified file 'lib/lp/code/model/linkedbranch.py'
--- lib/lp/code/model/linkedbranch.py 2009-05-15 03:16:18 +0000
+++ lib/lp/code/model/linkedbranch.py 2009-07-16 05:38:41 +0000
@@ -11,9 +11,12 @@
11from zope.interface import implements11from zope.interface import implements
1212
13from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch13from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
14from lp.registry.interfaces.distributionsourcepackage import (
15 IDistributionSourcePackage)
14from lp.registry.interfaces.product import IProduct16from lp.registry.interfaces.product import IProduct
15from lp.registry.interfaces.productseries import IProductSeries17from lp.registry.interfaces.productseries import IProductSeries
16from lp.registry.interfaces.suitesourcepackage import ISuiteSourcePackage18from lp.registry.interfaces.suitesourcepackage import ISuiteSourcePackage
19from lp.soyuz.interfaces.publishing import PackagePublishingPocket
1720
1821
19class ProductSeriesLinkedBranch:22class ProductSeriesLinkedBranch:
@@ -30,6 +33,16 @@
30 """See `ICanHasLinkedBranch`."""33 """See `ICanHasLinkedBranch`."""
31 return self.product_series.branch34 return self.product_series.branch
3235
36 @property
37 def bzr_identity(self):
38 """See `ICanHasLinkedBranch`."""
39 return '/'.join(
40 [self.product_series.product.name, self.product_series.name])
41
42 def setBranch(self, branch, registrant=None):
43 """See `ICanHasLinkedBranch`."""
44 self.product_series.branch = branch
45
3346
34class ProductLinkedBranch:47class ProductLinkedBranch:
35 """Implement a linked branch for a product."""48 """Implement a linked branch for a product."""
@@ -45,6 +58,15 @@
45 """See `ICanHasLinkedBranch`."""58 """See `ICanHasLinkedBranch`."""
46 return ICanHasLinkedBranch(self.product.development_focus).branch59 return ICanHasLinkedBranch(self.product.development_focus).branch
4760
61 @property
62 def bzr_identity(self):
63 """See `ICanHasLinkedBranch`."""
64 return self.product.name
65
66 def setBranch(self, branch, registrant=None):
67 """See `ICanHasLinkedBranch`."""
68 ICanHasLinkedBranch(self.product.development_focus).setBranch(branch)
69
4870
49class PackageLinkedBranch:71class PackageLinkedBranch:
50 """Implement a linked branch for a source package pocket."""72 """Implement a linked branch for a source package pocket."""
@@ -61,3 +83,50 @@
61 package = self.suite_sourcepackage.sourcepackage83 package = self.suite_sourcepackage.sourcepackage
62 pocket = self.suite_sourcepackage.pocket84 pocket = self.suite_sourcepackage.pocket
63 return package.getBranch(pocket)85 return package.getBranch(pocket)
86
87 @property
88 def bzr_identity(self):
89 """See `ICanHasLinkedBranch`."""
90 return self.suite_sourcepackage.path
91
92 def setBranch(self, branch, registrant):
93 """See `ICanHasLinkedBranch`."""
94 package = self.suite_sourcepackage.sourcepackage
95 pocket = self.suite_sourcepackage.pocket
96 package.setBranch(pocket, branch, registrant)
97
98
99class DistributionPackageLinkedBranch:
100 """Implement a linked branch for an `IDistributionSourcePackage`."""
101
102 adapts(IDistributionSourcePackage)
103 implements(ICanHasLinkedBranch)
104
105 def __init__(self, distribution_sourcepackage):
106 self._distribution_sourcepackage = distribution_sourcepackage
107
108 @property
109 def branch(self):
110 """See `ICanHasLinkedBranch`."""
111 development_package = (
112 self._distribution_sourcepackage.development_version)
113 if development_package is None:
114 return None
115 suite_sourcepackage = development_package.getSuiteSourcePackage(
116 PackagePublishingPocket.RELEASE)
117 return ICanHasLinkedBranch(suite_sourcepackage).branch
118
119 @property
120 def bzr_identity(self):
121 """See `ICanHasLinkedBranch`."""
122 return '/'.join(
123 [self._distribution_sourcepackage.distribution.name,
124 self._distribution_sourcepackage.sourcepackagename.name])
125
126 def setBranch(self, branch, registrant):
127 """See `ICanHasLinkedBranch`."""
128 development_package = (
129 self._distribution_sourcepackage.development_version)
130 suite_sourcepackage = development_package.getSuiteSourcePackage(
131 PackagePublishingPocket.RELEASE)
132 ICanHasLinkedBranch(suite_sourcepackage).setBranch(branch, registrant)
64133
=== modified file 'lib/lp/code/model/tests/test_branch.py'
--- lib/lp/code/model/tests/test_branch.py 2009-07-08 04:57:51 +0000
+++ lib/lp/code/model/tests/test_branch.py 2009-07-16 03:22:24 +0000
@@ -20,49 +20,49 @@
20from canonical.config import config20from canonical.config import config
21from canonical.database.constants import UTC_NOW21from canonical.database.constants import UTC_NOW
22from canonical.launchpad import _22from canonical.launchpad import _
23from lp.code.model.branch import (
24 ClearDependentBranch, ClearOfficialPackageBranch, ClearSeriesBranch,
25 DeleteCodeImport, DeletionCallable, DeletionOperation,
26 update_trigger_modified_fields)
27from lp.code.model.branchjob import (
28 BranchDiffJob, BranchJob, BranchJobType, ReclaimBranchSpaceJob)
29from lp.code.model.branchmergeproposal import (
30 BranchMergeProposal)
31from lp.bugs.model.bugbranch import BugBranch
32from lp.code.model.codeimport import CodeImport, CodeImportSet
33from lp.code.model.codereviewcomment import CodeReviewComment
34from lp.registry.model.product import ProductSet
35from lp.blueprints.model.specificationbranch import (
36 SpecificationBranch)
37from lp.registry.model.sourcepackage import SourcePackage
38from canonical.launchpad.ftests import (23from canonical.launchpad.ftests import (
39 ANONYMOUS, login, login_person, logout, syncUpdate)24 ANONYMOUS, login, login_person, logout, syncUpdate)
40from lp.bugs.interfaces.bug import CreateBugParams, IBugSet25from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
26from canonical.launchpad.webapp.interfaces import IOpenLaunchBag
27from canonical.testing import DatabaseFunctionalLayer, LaunchpadZopelessLayer
28
41from lp.blueprints.interfaces.specification import (29from lp.blueprints.interfaces.specification import (
42 ISpecificationSet, SpecificationDefinitionStatus)30 ISpecificationSet, SpecificationDefinitionStatus)
31from lp.blueprints.model.specificationbranch import (
32 SpecificationBranch)
33from lp.bugs.interfaces.bug import CreateBugParams, IBugSet
34from lp.bugs.model.bugbranch import BugBranch
43from lp.code.bzr import BranchFormat, RepositoryFormat35from lp.code.bzr import BranchFormat, RepositoryFormat
44from lp.code.enums import (36from lp.code.enums import (
45 BranchLifecycleStatus, BranchSubscriptionNotificationLevel, BranchType,37 BranchLifecycleStatus, BranchSubscriptionNotificationLevel, BranchType,
46 BranchVisibilityRule, CodeReviewNotificationLevel)38 BranchVisibilityRule, CodeReviewNotificationLevel)
47from lp.code.interfaces.branch import (39from lp.code.interfaces.branch import (
48 BranchCannotBePrivate, BranchCannotBePublic,40 BranchCannotBePrivate, BranchCannotBePublic,
49 CannotDeleteBranch)41 CannotDeleteBranch, DEFAULT_BRANCH_STATUS_IN_LISTING)
42from lp.code.interfaces.branchlookup import IBranchLookup
43from lp.code.interfaces.branchnamespace import IBranchNamespaceSet
50from lp.code.interfaces.branchmergeproposal import InvalidBranchMergeProposal44from lp.code.interfaces.branchmergeproposal import InvalidBranchMergeProposal
45from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
51from lp.code.interfaces.seriessourcepackagebranch import (46from lp.code.interfaces.seriessourcepackagebranch import (
52 IFindOfficialBranchLinks)47 IFindOfficialBranchLinks)
48from lp.code.model.branch import (
49 ClearDependentBranch, ClearOfficialPackageBranch, ClearSeriesBranch,
50 DeleteCodeImport, DeletionCallable, DeletionOperation,
51 update_trigger_modified_fields)
52from lp.code.model.branchjob import (
53 BranchDiffJob, BranchJob, BranchJobType, ReclaimBranchSpaceJob)
54from lp.code.model.branchmergeproposal import (
55 BranchMergeProposal)
56from lp.code.model.codeimport import CodeImport, CodeImportSet
57from lp.code.model.codereviewcomment import CodeReviewComment
53from lp.registry.interfaces.person import IPersonSet58from lp.registry.interfaces.person import IPersonSet
54from lp.registry.interfaces.product import IProductSet59from lp.registry.interfaces.product import IProductSet
55from lp.code.interfaces.branch import DEFAULT_BRANCH_STATUS_IN_LISTING60from lp.registry.model.product import ProductSet
56from lp.code.interfaces.branchlookup import IBranchLookup61from lp.registry.model.sourcepackage import SourcePackage
57from lp.code.interfaces.branchnamespace import IBranchNamespaceSet
58from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
59from lp.soyuz.interfaces.publishing import PackagePublishingPocket62from lp.soyuz.interfaces.publishing import PackagePublishingPocket
60from lp.testing import (63from lp.testing import (
61 run_with_login, TestCase, TestCaseWithFactory, time_counter)64 run_with_login, TestCase, TestCaseWithFactory, time_counter)
62from lp.testing.factory import LaunchpadObjectFactory65from lp.testing.factory import LaunchpadObjectFactory
63from canonical.launchpad.webapp.interfaces import IOpenLaunchBag
64
65from canonical.testing import DatabaseFunctionalLayer, LaunchpadZopelessLayer
6666
6767
68class TestCodeImport(TestCase):68class TestCodeImport(TestCase):
@@ -94,7 +94,7 @@
94 def _makeRevision(self, revno):94 def _makeRevision(self, revno):
95 # Make a revision and add it to the branch.95 # Make a revision and add it to the branch.
96 rev = self.factory.makeRevision()96 rev = self.factory.makeRevision()
97 br = self.branch.createBranchRevision(revno, rev)97 self.branch.createBranchRevision(revno, rev)
98 return rev98 return rev
9999
100 def testGetBySequenceNumber(self):100 def testGetBySequenceNumber(self):
@@ -117,7 +117,7 @@
117 self.assertEqual(1, branch_revision.sequence)117 self.assertEqual(1, branch_revision.sequence)
118118
119 def testNonExistant(self):119 def testNonExistant(self):
120 rev1 = self._makeRevision(1)120 self._makeRevision(1)
121 self.assertTrue(self.branch.getBranchRevision(sequence=2) is None)121 self.assertTrue(self.branch.getBranchRevision(sequence=2) is None)
122 rev2 = self.factory.makeRevision()122 rev2 = self.factory.makeRevision()
123 self.assertTrue(self.branch.getBranchRevision(revision=rev2) is None)123 self.assertTrue(self.branch.getBranchRevision(revision=rev2) is None)
@@ -418,9 +418,10 @@
418 # If a branch is the development focus branch for a product, then it's418 # If a branch is the development focus branch for a product, then it's
419 # bzr identity is lp:product.419 # bzr identity is lp:product.
420 branch = self.factory.makeProductBranch()420 branch = self.factory.makeProductBranch()
421 product = branch.product421 product = removeSecurityProxy(branch.product)
422 removeSecurityProxy(product).development_focus.branch = branch422 linked_branch = ICanHasLinkedBranch(product)
423 self.assertBzrIdentity(branch, product.name)423 linked_branch.setBranch(branch)
424 self.assertBzrIdentity(branch, linked_branch.bzr_identity)
424425
425 def test_linked_to_product_series(self):426 def test_linked_to_product_series(self):
426 # If a branch is the development focus branch for a product series,427 # If a branch is the development focus branch for a product series,
@@ -428,8 +429,9 @@
428 branch = self.factory.makeProductBranch()429 branch = self.factory.makeProductBranch()
429 product = branch.product430 product = branch.product
430 series = self.factory.makeProductSeries(product=product)431 series = self.factory.makeProductSeries(product=product)
431 series.branch = branch432 linked_branch = ICanHasLinkedBranch(series)
432 self.assertBzrIdentity(branch, '%s/%s' % (product.name, series.name))433 linked_branch.setBranch(branch)
434 self.assertBzrIdentity(branch, linked_branch.bzr_identity)
433435
434 def test_private_linked_to_product(self):436 def test_private_linked_to_product(self):
435 # If a branch is private, then the bzr identity is the unique name,437 # If a branch is private, then the bzr identity is the unique name,
@@ -439,8 +441,8 @@
439 owner = removeSecurityProxy(branch).owner441 owner = removeSecurityProxy(branch).owner
440 login_person(owner)442 login_person(owner)
441 self.addCleanup(logout)443 self.addCleanup(logout)
442 product = branch.product444 product = removeSecurityProxy(branch.product)
443 removeSecurityProxy(product).development_focus.branch = branch445 ICanHasLinkedBranch(product).setBranch(branch)
444 self.assertBzrIdentity(branch, branch.unique_name)446 self.assertBzrIdentity(branch, branch.unique_name)
445447
446 def test_linked_to_series_and_dev_focus(self):448 def test_linked_to_series_and_dev_focus(self):
@@ -448,33 +450,54 @@
448 # branch for a series, the bzr identity will be the storter of the two450 # branch for a series, the bzr identity will be the storter of the two
449 # URLs.451 # URLs.
450 branch = self.factory.makeProductBranch()452 branch = self.factory.makeProductBranch()
451 product = branch.product453 series = self.factory.makeProductSeries(product=branch.product)
452 removeSecurityProxy(product).development_focus.branch = branch454 product_link = ICanHasLinkedBranch(
453 series = self.factory.makeProductSeries(product=product)455 removeSecurityProxy(branch.product))
454 series.branch = branch456 series_link = ICanHasLinkedBranch(series)
455 self.assertBzrIdentity(branch, product.name)457 product_link.setBranch(branch)
458 series_link.setBranch(branch)
459 self.assertBzrIdentity(branch, product_link.bzr_identity)
456460
457 def test_junk_branch_always_unique_name(self):461 def test_junk_branch_always_unique_name(self):
458 # For junk branches, the bzr identity is always based on the unique462 # For junk branches, the bzr identity is always based on the unique
459 # name of the branch, even if it's linked to a product, product series463 # name of the branch, even if it's linked to a product, product series
460 # or whatever.464 # or whatever.
461 branch = self.factory.makePersonalBranch()465 branch = self.factory.makePersonalBranch()
462 product = self.factory.makeProduct()466 product = removeSecurityProxy(self.factory.makeProduct())
463 removeSecurityProxy(product).development_focus.branch = branch467 ICanHasLinkedBranch(product).setBranch(branch)
464 self.assertBzrIdentity(branch, branch.unique_name)468 self.assertBzrIdentity(branch, branch.unique_name)
465469
466 def test_linked_to_package_release(self):470 def test_linked_to_package(self):
467 # If a branch is linked to the release pocket of a package, then the471 # If a branch is linked to a pocket of a package, then the
468 # bzr identity is the path to that package.472 # bzr identity is the path to that package.
469 branch = self.factory.makePackageBranch()473 branch = self.factory.makePackageBranch()
474 # Have to pick something that's not RELEASE in order to guarantee that
475 # it's not the dev focus source package.
476 pocket = PackagePublishingPocket.BACKPORTS
477 linked_branch = ICanHasLinkedBranch(
478 branch.sourcepackage.getSuiteSourcePackage(pocket))
470 registrant = getUtility(479 registrant = getUtility(
471 ILaunchpadCelebrities).ubuntu_branches.teamowner480 ILaunchpadCelebrities).ubuntu_branches.teamowner
472 login_person(registrant)481 login_person(registrant)
473 branch.sourcepackage.setBranch(482 linked_branch.setBranch(branch, registrant)
474 PackagePublishingPocket.RELEASE, branch, registrant)
475 logout()483 logout()
476 login(ANONYMOUS)484 login(ANONYMOUS)
477 self.assertBzrIdentity(branch, branch.sourcepackage.path)485 self.assertBzrIdentity(branch, linked_branch.bzr_identity)
486
487 def test_linked_to_dev_package(self):
488 # If a branch is linked to the development focus version of a package
489 # then the bzr identity is distro/package.
490 sourcepackage = self.factory.makeSourcePackage()
491 distro_package = sourcepackage.distribution_sourcepackage
492 branch = self.factory.makePackageBranch(
493 sourcepackage=distro_package.development_version)
494 linked_branch = ICanHasLinkedBranch(distro_package)
495 registrant = getUtility(
496 ILaunchpadCelebrities).ubuntu_branches.teamowner
497 run_with_login(
498 registrant,
499 linked_branch.setBranch, branch, registrant)
500 self.assertBzrIdentity(branch, linked_branch.bzr_identity)
478501
479502
480class TestBranchDeletion(TestCaseWithFactory):503class TestBranchDeletion(TestCaseWithFactory):
@@ -506,7 +529,7 @@
506529
507 def test_stackedBranchDisablesDeletion(self):530 def test_stackedBranchDisablesDeletion(self):
508 # A branch that is stacked upon cannot be deleted.531 # A branch that is stacked upon cannot be deleted.
509 branch = self.factory.makeAnyBranch(stacked_on=self.branch)532 self.factory.makeAnyBranch(stacked_on=self.branch)
510 self.assertFalse(self.branch.canBeDeleted())533 self.assertFalse(self.branch.canBeDeleted())
511534
512 def test_subscriptionDoesntDisableDeletion(self):535 def test_subscriptionDoesntDisableDeletion(self):
@@ -679,8 +702,7 @@
679 ' proposal.')),702 ' proposal.')),
680 merge_proposal2:703 merge_proposal2:
681 ('delete', _('This branch is the source branch of this merge'704 ('delete', _('This branch is the source branch of this merge'
682 ' proposal.'))705 ' proposal.'))},
683 },
684 self.branch.deletionRequirements())706 self.branch.deletionRequirements())
685 self.assertEqual({707 self.assertEqual({
686 merge_proposal1:708 merge_proposal1:
@@ -688,8 +710,7 @@
688 ' proposal.')),710 ' proposal.')),
689 merge_proposal2:711 merge_proposal2:
690 ('delete', _('This branch is the target branch of this merge'712 ('delete', _('This branch is the target branch of this merge'
691 ' proposal.'))713 ' proposal.'))},
692 },
693 merge_proposal1.target_branch.deletionRequirements())714 merge_proposal1.target_branch.deletionRequirements())
694 self.assertEqual({715 self.assertEqual({
695 merge_proposal1:716 merge_proposal1:
@@ -697,8 +718,7 @@
697 ' proposal.')),718 ' proposal.')),
698 merge_proposal2:719 merge_proposal2:
699 ('alter', _('This branch is the dependent branch of this merge'720 ('alter', _('This branch is the dependent branch of this merge'
700 ' proposal.'))721 ' proposal.'))},
701 },
702 merge_proposal1.dependent_branch.deletionRequirements())722 merge_proposal1.dependent_branch.deletionRequirements())
703723
704 def test_deleteMergeProposalSource(self):724 def test_deleteMergeProposalSource(self):
@@ -722,7 +742,6 @@
722 def test_deleteMergeProposalDependent(self):742 def test_deleteMergeProposalDependent(self):
723 """break_links enables deleting merge proposal dependant branches."""743 """break_links enables deleting merge proposal dependant branches."""
724 merge_proposal1, merge_proposal2 = self.makeMergeProposals()744 merge_proposal1, merge_proposal2 = self.makeMergeProposals()
725 merge_proposal1_id = merge_proposal1.id
726 merge_proposal1.dependent_branch.destroySelf(break_references=True)745 merge_proposal1.dependent_branch.destroySelf(break_references=True)
727 self.assertEqual(None, merge_proposal1.dependent_branch)746 self.assertEqual(None, merge_proposal1.dependent_branch)
728747
@@ -755,7 +774,6 @@
755 def test_branchWithBugDeletion(self):774 def test_branchWithBugDeletion(self):
756 """break_links allows deleting a branch with a bug."""775 """break_links allows deleting a branch with a bug."""
757 bug1 = self.factory.makeBug()776 bug1 = self.factory.makeBug()
758 bug2 = self.factory.makeBug()
759 bug1.linkBranch(self.branch, self.branch.owner)777 bug1.linkBranch(self.branch, self.branch.owner)
760 bug_branch1 = bug1.linked_branches[0]778 bug_branch1 = bug1.linked_branches[0]
761 bug_branch1_id = bug_branch1.id779 bug_branch1_id = bug_branch1.id
@@ -951,7 +969,7 @@
951 # some_branch.getStackedBranchesWithIncompleteMirrors does not include969 # some_branch.getStackedBranchesWithIncompleteMirrors does not include
952 # stacked branches that haven't been mirrored at all.970 # stacked branches that haven't been mirrored at all.
953 branch = self.factory.makeAnyBranch()971 branch = self.factory.makeAnyBranch()
954 stacked_a = self.factory.makeAnyBranch(stacked_on=branch)972 self.factory.makeAnyBranch(stacked_on=branch)
955 self.assertEqual(973 self.assertEqual(
956 set(), set(branch.getStackedBranchesWithIncompleteMirrors()))974 set(), set(branch.getStackedBranchesWithIncompleteMirrors()))
957975
@@ -1097,8 +1115,7 @@
1097 branch pair, then another landing target specifying the same pair1115 branch pair, then another landing target specifying the same pair
1098 raises.1116 raises.
1099 """1117 """
1100 proposal = self.source.addLandingTarget(1118 self.source.addLandingTarget(self.user, self.target, self.dependent)
1101 self.user, self.target, self.dependent)
11021119
1103 self.assertRaises(1120 self.assertRaises(
1104 InvalidBranchMergeProposal, self.source.addLandingTarget,1121 InvalidBranchMergeProposal, self.source.addLandingTarget,
@@ -1113,8 +1130,7 @@
1113 self.user, self.target, self.dependent)1130 self.user, self.target, self.dependent)
1114 proposal.rejectBranch(self.user, 'some_revision')1131 proposal.rejectBranch(self.user, 'some_revision')
1115 syncUpdate(proposal)1132 syncUpdate(proposal)
1116 new_proposal = self.source.addLandingTarget(1133 self.source.addLandingTarget(self.user, self.target, self.dependent)
1117 self.user, self.target, self.dependent)
11181134
1119 def test_attributeAssignment(self):1135 def test_attributeAssignment(self):
1120 """Smoke test to make sure the assignments are there."""1136 """Smoke test to make sure the assignments are there."""
@@ -1614,7 +1630,6 @@
16141630
1615 def test_spec_unlink(self):1631 def test_spec_unlink(self):
1616 # Branches can be unlinked from the spec as well.1632 # Branches can be unlinked from the spec as well.
1617 user = getUtility(IPersonSet).getByEmail('test@canonical.com')
1618 branch = self.factory.makeAnyBranch()1633 branch = self.factory.makeAnyBranch()
1619 spec = self.factory.makeSpecification()1634 spec = self.factory.makeSpecification()
1620 branch.linkSpecification(spec, self.user)1635 branch.linkSpecification(spec, self.user)
16211636
=== modified file 'lib/lp/code/model/tests/test_branchlookup.py'
--- lib/lp/code/model/tests/test_branchlookup.py 2009-06-02 13:52:48 +0000
+++ lib/lp/code/model/tests/test_branchlookup.py 2009-07-16 05:52:44 +0000
@@ -18,7 +18,7 @@
18from lp.code.interfaces.branchnamespace import (18from lp.code.interfaces.branchnamespace import (
19 get_branch_namespace, InvalidNamespace)19 get_branch_namespace, InvalidNamespace)
20from lp.code.interfaces.linkedbranch import (20from lp.code.interfaces.linkedbranch import (
21 CannotHaveLinkedBranch, NoLinkedBranch)21 CannotHaveLinkedBranch, ICanHasLinkedBranch, NoLinkedBranch)
22from lp.registry.interfaces.distroseries import NoSuchDistroSeries22from lp.registry.interfaces.distroseries import NoSuchDistroSeries
23from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities23from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
24from lp.registry.interfaces.person import NoSuchPerson24from lp.registry.interfaces.person import NoSuchPerson
@@ -230,7 +230,7 @@
230230
231 This is because Launchpad doesn't currently support ftp.231 This is because Launchpad doesn't currently support ftp.
232 """232 """
233 branch = self.makeProductBranch()233 self.makeProductBranch()
234 branch_set = getUtility(IBranchLookup)234 branch_set = getUtility(IBranchLookup)
235 branch2 = branch_set.getByUrl('ftp://bazaar.launchpad.dev/~aa/b/c')235 branch2 = branch_set.getByUrl('ftp://bazaar.launchpad.dev/~aa/b/c')
236 self.assertIs(None, branch2)236 self.assertIs(None, branch2)
@@ -311,7 +311,7 @@
311 # a non-existent series.311 # a non-existent series.
312 self.assertRaises(312 self.assertRaises(
313 NoSuchProduct, self.traverser.traverse, 'bb/dd')313 NoSuchProduct, self.traverser.traverse, 'bb/dd')
314 product = self.factory.makeProduct(name='bb')314 self.factory.makeProduct(name='bb')
315 self.assertRaises(315 self.assertRaises(
316 NoSuchProductSeries, self.traverser.traverse, 'bb/dd')316 NoSuchProductSeries, self.traverser.traverse, 'bb/dd')
317317
@@ -345,6 +345,13 @@
345 ssp = package.getSuiteSourcePackage(PackagePublishingPocket.RELEASE)345 ssp = package.getSuiteSourcePackage(PackagePublishingPocket.RELEASE)
346 self.assertTraverses(package.path, ssp)346 self.assertTraverses(package.path, ssp)
347347
348 def test_distribution_source_package(self):
349 # `traverse` resolves 'distro/package' to the distribution source
350 # package.
351 dsp = self.factory.makeDistributionSourcePackage()
352 path = '%s/%s' % (dsp.distribution.name, dsp.sourcepackagename.name)
353 self.assertTraverses(path, dsp)
354
348 def test_traverse_source_package_pocket(self):355 def test_traverse_source_package_pocket(self):
349 # `traverse` resolves 'distro/series-pocket/package' to the official356 # `traverse` resolves 'distro/series-pocket/package' to the official
350 # branch for 'pocket' on that package.357 # branch for 'pocket' on that package.
@@ -366,7 +373,7 @@
366 def test_no_such_distro_series(self):373 def test_no_such_distro_series(self):
367 # `traverse` raises `NoSuchDistroSeries` if the distro series doesn't374 # `traverse` raises `NoSuchDistroSeries` if the distro series doesn't
368 # exist.375 # exist.
369 distro = self.factory.makeDistribution(name='distro')376 self.factory.makeDistribution(name='distro')
370 self.assertRaises(377 self.assertRaises(
371 NoSuchDistroSeries, self.traverser.traverse,378 NoSuchDistroSeries, self.traverser.traverse,
372 'distro/series/package')379 'distro/series/package')
@@ -380,6 +387,14 @@
380 self.assertRaises(387 self.assertRaises(
381 NoSuchSourcePackageName, self.traverser.traverse, path)388 NoSuchSourcePackageName, self.traverser.traverse, path)
382389
390 def test_no_such_distribution_sourcepackage(self):
391 # `traverse` raises `NoSuchSourcePackageName` if the package in
392 # distro/package doesn't exist.
393 distribution = self.factory.makeDistribution()
394 path = '%s/doesntexist' % distribution.name
395 self.assertRaises(
396 NoSuchSourcePackageName, self.traverser.traverse, path)
397
383398
384class TestGetByLPPath(TestCaseWithFactory):399class TestGetByLPPath(TestCaseWithFactory):
385 """Ensure URLs are correctly expanded."""400 """Ensure URLs are correctly expanded."""
@@ -397,10 +412,10 @@
397 # components are found.412 # components are found.
398 self.assertRaises(413 self.assertRaises(
399 NoSuchPerson, self.branch_lookup.getByLPPath, '~aa/bb/c')414 NoSuchPerson, self.branch_lookup.getByLPPath, '~aa/bb/c')
400 owner = self.factory.makePerson(name='aa')415 self.factory.makePerson(name='aa')
401 self.assertRaises(416 self.assertRaises(
402 NoSuchProduct, self.branch_lookup.getByLPPath, '~aa/bb/c')417 NoSuchProduct, self.branch_lookup.getByLPPath, '~aa/bb/c')
403 product = self.factory.makeProduct(name='bb')418 self.factory.makeProduct(name='bb')
404 self.assertRaises(419 self.assertRaises(
405 NoSuchBranch, self.branch_lookup.getByLPPath, '~aa/bb/c')420 NoSuchBranch, self.branch_lookup.getByLPPath, '~aa/bb/c')
406421
@@ -434,7 +449,7 @@
434 # doesn't match an existing branch.449 # doesn't match an existing branch.
435 self.assertRaises(450 self.assertRaises(
436 NoSuchPerson, self.branch_lookup.getByLPPath, '~aa/+junk/c')451 NoSuchPerson, self.branch_lookup.getByLPPath, '~aa/+junk/c')
437 owner = self.factory.makePerson(name='aa')452 self.factory.makePerson(name='aa')
438 self.assertRaises(453 self.assertRaises(
439 NoSuchBranch, self.branch_lookup.getByLPPath, '~aa/+junk/c')454 NoSuchBranch, self.branch_lookup.getByLPPath, '~aa/+junk/c')
440455
@@ -455,6 +470,24 @@
455 (branch, 'foo/bar/baz'),470 (branch, 'foo/bar/baz'),
456 self.branch_lookup.getByLPPath(path))471 self.branch_lookup.getByLPPath(path))
457472
473 def test_resolve_distro_package_branch(self):
474 # getByLPPath returns the branch associated with the distribution
475 # source package referred to by the path.
476 sourcepackage = self.factory.makeSourcePackage()
477 branch = self.factory.makePackageBranch(sourcepackage=sourcepackage)
478 distro_package = sourcepackage.distribution_sourcepackage
479 ubuntu_branches = getUtility(ILaunchpadCelebrities).ubuntu_branches
480 registrant = ubuntu_branches.teamowner
481 run_with_login(
482 registrant,
483 ICanHasLinkedBranch(distro_package).setBranch, branch, registrant)
484 self.assertEqual(
485 (branch, None),
486 self.branch_lookup.getByLPPath(
487 '%s/%s' % (
488 distro_package.distribution.name,
489 distro_package.sourcepackagename.name)))
490
458 def test_no_product_series_branch(self):491 def test_no_product_series_branch(self):
459 # getByLPPath raises `NoLinkedBranch` if there's no branch registered492 # getByLPPath raises `NoLinkedBranch` if there's no branch registered
460 # linked to the requested series.493 # linked to the requested series.
@@ -501,6 +534,12 @@
501 self.branch_lookup.getByLPPath, distribution.name)534 self.branch_lookup.getByLPPath, distribution.name)
502 self.assertEqual(distribution, exception.component)535 self.assertEqual(distribution, exception.component)
503536
537 def test_distribution_with_no_series(self):
538 distro_package = self.factory.makeDistributionSourcePackage()
539 path = ICanHasLinkedBranch(distro_package).bzr_identity
540 self.assertRaises(
541 NoLinkedBranch, self.branch_lookup.getByLPPath, path)
542
504 def test_project_linked_branch(self):543 def test_project_linked_branch(self):
505 # Projects cannot have linked branches, so `getByLPPath` raises a544 # Projects cannot have linked branches, so `getByLPPath` raises a
506 # `CannotHaveLinkedBranch` error if we try to get the linked branch545 # `CannotHaveLinkedBranch` error if we try to get the linked branch
507546
=== modified file 'lib/lp/code/model/tests/test_linkedbranch.py'
--- lib/lp/code/model/tests/test_linkedbranch.py 2009-05-24 18:09:51 +0000
+++ lib/lp/code/model/tests/test_linkedbranch.py 2009-07-16 05:38:41 +0000
@@ -18,11 +18,11 @@
18from lp.testing import run_with_login, TestCaseWithFactory18from lp.testing import run_with_login, TestCaseWithFactory
1919
2020
21class TestLinkedBranch(TestCaseWithFactory):21class TestProductSeriesLinkedBranch(TestCaseWithFactory):
2222
23 layer = DatabaseFunctionalLayer23 layer = DatabaseFunctionalLayer
2424
25 def test_product_series(self):25 def test_branch(self):
26 # The linked branch of a product series is its branch attribute.26 # The linked branch of a product series is its branch attribute.
27 product_series = self.factory.makeProductSeries()27 product_series = self.factory.makeProductSeries()
28 product_series.branch = self.factory.makeProductBranch(28 product_series.branch = self.factory.makeProductBranch(
@@ -30,7 +30,29 @@
30 self.assertEqual(30 self.assertEqual(
31 product_series.branch, ICanHasLinkedBranch(product_series).branch)31 product_series.branch, ICanHasLinkedBranch(product_series).branch)
3232
33 def test_product(self):33 def test_setBranch(self):
34 # setBranch sets the linked branch of the product series.
35 product_series = self.factory.makeProductSeries()
36 branch = self.factory.makeProductBranch(
37 product=product_series.product)
38 ICanHasLinkedBranch(product_series).setBranch(branch)
39 self.assertEqual(branch, product_series.branch)
40
41 def test_bzr_identity(self):
42 # The bzr_identity of a product series linked branch is
43 # product/product_series.
44 product_series = self.factory.makeProductSeries()
45 bzr_identity = '%s/%s' % (
46 product_series.product.name, product_series.name)
47 self.assertEqual(
48 bzr_identity, ICanHasLinkedBranch(product_series).bzr_identity)
49
50
51class TestProductLinkedBranch(TestCaseWithFactory):
52
53 layer = DatabaseFunctionalLayer
54
55 def test_branch(self):
34 # The linked branch of a product is the linked branch of its56 # The linked branch of a product is the linked branch of its
35 # development focus product series.57 # development focus product series.
36 branch = self.factory.makeProductBranch()58 branch = self.factory.makeProductBranch()
@@ -38,22 +60,130 @@
38 removeSecurityProxy(product).development_focus.branch = branch60 removeSecurityProxy(product).development_focus.branch = branch
39 self.assertEqual(branch, ICanHasLinkedBranch(product).branch)61 self.assertEqual(branch, ICanHasLinkedBranch(product).branch)
4062
41 def test_suitesourcepackage(self):63 def test_setBranch(self):
64 # setBranch sets the linked branch of the development focus product
65 # series.
66 branch = self.factory.makeProductBranch()
67 product = removeSecurityProxy(branch.product)
68 ICanHasLinkedBranch(product).setBranch(branch)
69 self.assertEqual(branch, product.development_focus.branch)
70
71 def test_bzr_identity(self):
72 # The bzr_identity of a product linked branch is the product name.
73 product = self.factory.makeProduct()
74 self.assertEqual(
75 product.name, ICanHasLinkedBranch(product).bzr_identity)
76
77
78class TestSuiteSourcePackageLinkedBranch(TestCaseWithFactory):
79
80 layer = DatabaseFunctionalLayer
81
82 def test_branch(self):
42 # The linked branch of a suite source package is the official branch83 # The linked branch of a suite source package is the official branch
43 # for the pocket of that source package.84 # for the pocket of that source package.
44 branch = self.factory.makeAnyBranch()85 branch = self.factory.makeAnyBranch()
86 suite_sourcepackage = self.factory.makeSuiteSourcePackage()
87 ubuntu_branches = getUtility(ILaunchpadCelebrities).ubuntu_branches
88 registrant = ubuntu_branches.teamowner
89 run_with_login(
90 registrant,
91 suite_sourcepackage.sourcepackage.setBranch,
92 suite_sourcepackage.pocket, branch, registrant)
93 self.assertEqual(
94 branch, ICanHasLinkedBranch(suite_sourcepackage).branch)
95
96 def test_setBranch(self):
97 # setBranch sets the official branch for the appropriate pocket of the
98 # source package.
99 branch = self.factory.makeAnyBranch()
100 suite_sourcepackage = self.factory.makeSuiteSourcePackage()
101 ubuntu_branches = getUtility(ILaunchpadCelebrities).ubuntu_branches
102 registrant = ubuntu_branches.teamowner
103 run_with_login(
104 registrant,
105 ICanHasLinkedBranch(suite_sourcepackage).setBranch,
106 branch, registrant)
107 self.assertEqual(
108 branch,
109 suite_sourcepackage.sourcepackage.getBranch(
110 suite_sourcepackage.pocket))
111
112 def test_bzr_identity(self):
113 # The bzr_identity of a suite source package linked branch is the path
114 # of that suite source package.
115 suite_sourcepackage = self.factory.makeSuiteSourcePackage()
116 self.assertEqual(
117 suite_sourcepackage.path,
118 ICanHasLinkedBranch(suite_sourcepackage).bzr_identity)
119
120
121class TestDistributionSourcePackageLinkedBranch(TestCaseWithFactory):
122
123 layer = DatabaseFunctionalLayer
124
125 def test_branch(self):
126 # The linked branch of a distribution source package is the official
127 # branch for the release pocket of the development focus series for
128 # that package. Phew.
129 branch = self.factory.makeAnyBranch()
45 sourcepackage = self.factory.makeSourcePackage()130 sourcepackage = self.factory.makeSourcePackage()
131 dev_sourcepackage = sourcepackage.development_version
46 pocket = PackagePublishingPocket.RELEASE132 pocket = PackagePublishingPocket.RELEASE
133
47 ubuntu_branches = getUtility(ILaunchpadCelebrities).ubuntu_branches134 ubuntu_branches = getUtility(ILaunchpadCelebrities).ubuntu_branches
48 registrant = ubuntu_branches.teamowner135 registrant = ubuntu_branches.teamowner
49 run_with_login(136 run_with_login(
50 ubuntu_branches.teamowner,137 ubuntu_branches.teamowner,
51 sourcepackage.setBranch, pocket, branch, registrant)138 dev_sourcepackage.setBranch, pocket, branch, registrant)
52 suite_sourcepackage = sourcepackage.getSuiteSourcePackage(pocket)139
53 self.assertEqual(140 distribution_sourcepackage = sourcepackage.distribution_sourcepackage
54 branch, ICanHasLinkedBranch(suite_sourcepackage).branch)141 self.assertEqual(
55142 branch, ICanHasLinkedBranch(distribution_sourcepackage).branch)
56 def test_project(self):143
144 def test_branch_when_no_series(self):
145 # Our data model allows distributions that have no series. The linked
146 # branch for a package in such a distribution is always None.
147 distro_package = self.factory.makeDistributionSourcePackage()
148 self.assertIs(None, ICanHasLinkedBranch(distro_package).branch)
149
150 def test_setBranch(self):
151 # Setting the linked branch for a distribution source package links
152 # the branch to the release pocket of the development focus series for
153 # that package.
154 branch = self.factory.makeAnyBranch()
155 sourcepackage = self.factory.makeSourcePackage()
156 distribution_sourcepackage = sourcepackage.distribution_sourcepackage
157
158 ubuntu_branches = getUtility(ILaunchpadCelebrities).ubuntu_branches
159 registrant = ubuntu_branches.teamowner
160 run_with_login(
161 registrant,
162 ICanHasLinkedBranch(distribution_sourcepackage).setBranch,
163 branch, registrant)
164
165 dev_sourcepackage = sourcepackage.development_version
166 pocket = PackagePublishingPocket.RELEASE
167 self.assertEqual(branch, dev_sourcepackage.getBranch(pocket))
168
169 def test_bzr_identity(self):
170 # The bzr_identity of a distribution source package linked branch is
171 # distro/package.
172 distribution_sourcepackage = (
173 self.factory.makeDistributionSourcePackage())
174 self.assertEqual(
175 '%s/%s' % (
176 distribution_sourcepackage.distribution.name,
177 distribution_sourcepackage.sourcepackagename.name),
178 ICanHasLinkedBranch(distribution_sourcepackage).bzr_identity)
179
180
181class TestProjectLinkedBranch(TestCaseWithFactory):
182
183 layer = DatabaseFunctionalLayer
184
185 def test_cannot_have_linked_branch(self):
186 # Projects cannot have linked branches.
57 project = self.factory.makeProject()187 project = self.factory.makeProject()
58 self.assertRaises(188 self.assertRaises(
59 CannotHaveLinkedBranch, get_linked_branch, project)189 CannotHaveLinkedBranch, get_linked_branch, project)
60190
=== modified file 'lib/lp/registry/browser/distributionsourcepackage.py'
--- lib/lp/registry/browser/distributionsourcepackage.py 2009-07-10 12:34:49 +0000
+++ lib/lp/registry/browser/distributionsourcepackage.py 2009-07-16 03:53:20 +0000
@@ -31,9 +31,8 @@
31from lp.answers.browser.questiontarget import (31from lp.answers.browser.questiontarget import (
32 QuestionTargetFacetMixin, QuestionTargetTraversalMixin)32 QuestionTargetFacetMixin, QuestionTargetTraversalMixin)
33from canonical.launchpad.webapp import (33from canonical.launchpad.webapp import (
34 ApplicationMenu, GetitemNavigation, LaunchpadEditFormView,34 ApplicationMenu, LaunchpadEditFormView, LaunchpadFormView, Link,
35 LaunchpadFormView, Link, StandardLaunchpadFacets, action, canonical_url,35 Navigation, StandardLaunchpadFacets, action, canonical_url, redirection)
36 redirection)
37from canonical.launchpad.webapp.menu import enabled_with_permission36from canonical.launchpad.webapp.menu import enabled_with_permission
38from canonical.launchpad.webapp.breadcrumb import BreadcrumbBuilder37from canonical.launchpad.webapp.breadcrumb import BreadcrumbBuilder
3938
@@ -88,13 +87,16 @@
88 return Link('+filebug', text, icon='bug')87 return Link('+filebug', text, icon='bug')
8988
9089
91class DistributionSourcePackageNavigation(GetitemNavigation,90class DistributionSourcePackageNavigation(Navigation,
92 BugTargetTraversalMixin, QuestionTargetTraversalMixin):91 BugTargetTraversalMixin, QuestionTargetTraversalMixin):
9392
94 usedfor = IDistributionSourcePackage93 usedfor = IDistributionSourcePackage
9594
96 redirection("+editbugcontact", "+subscribe")95 redirection("+editbugcontact", "+subscribe")
9796
97 def traverse(self, name):
98 return self.context.getVersion(name)
99
98100
99class DecoratedDistributionSourcePackageRelease:101class DecoratedDistributionSourcePackageRelease:
100 """A decorated DistributionSourcePackageRelease.102 """A decorated DistributionSourcePackageRelease.
101103
=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml 2009-07-13 14:13:07 +0000
+++ lib/lp/registry/configure.zcml 2009-07-16 04:47:24 +0000
@@ -357,6 +357,7 @@
357 <allow357 <allow
358 attributes="358 attributes="
359 distribution359 distribution
360 development_version
360 sourcepackagename361 sourcepackagename
361 name362 name
362 displayname363 displayname
363364
=== modified file 'lib/lp/registry/interfaces/distributionsourcepackage.py'
--- lib/lp/registry/interfaces/distributionsourcepackage.py 2009-07-10 15:38:46 +0000
+++ lib/lp/registry/interfaces/distributionsourcepackage.py 2009-07-16 04:48:10 +0000
@@ -68,6 +68,10 @@
68 "The list of all releases of this source package "68 "The list of all releases of this source package "
69 "in this distribution.")69 "in this distribution.")
7070
71 development_version = Attribute(
72 'The development version of this source package. None if there is no '
73 'such package.')
74
71 def getReleasesAndPublishingHistory():75 def getReleasesAndPublishingHistory():
72 """Return a list of all releases of this source package in this76 """Return a list of all releases of this source package in this
73 distribution and their correspodning publishing history.77 distribution and their correspodning publishing history.
@@ -85,9 +89,6 @@
85 "Return a list of CURRENT publishing records for this source "89 "Return a list of CURRENT publishing records for this source "
86 "package in this distribution.")90 "package in this distribution.")
8791
88 def __getitem__(version):
89 """Should map to getVersion."""
90
91 def getVersion(version):92 def getVersion(version):
92 """Return the a DistributionSourcePackageRelease with the given93 """Return the a DistributionSourcePackageRelease with the given
93 version, or None if there has never been a release with that94 version, or None if there has never been a release with that
9495
=== modified file 'lib/lp/registry/interfaces/sourcepackage.py'
--- lib/lp/registry/interfaces/sourcepackage.py 2009-06-12 16:36:02 +0000
+++ lib/lp/registry/interfaces/sourcepackage.py 2009-07-15 07:25:04 +0000
@@ -125,6 +125,9 @@
125 development_version = Attribute(125 development_version = Attribute(
126 "This package on the distro's current series.")126 "This package on the distro's current series.")
127127
128 distribution_sourcepackage = Attribute(
129 "The IDistributionSourcePackage for this source package.")
130
128 def __getitem__(version):131 def __getitem__(version):
129 """Return the source package release with the given version in this132 """Return the source package release with the given version in this
130 distro series, or None."""133 distro series, or None."""
131134
=== modified file 'lib/lp/registry/model/distributionsourcepackage.py'
--- lib/lp/registry/model/distributionsourcepackage.py 2009-07-10 15:38:46 +0000
+++ lib/lp/registry/model/distributionsourcepackage.py 2009-07-16 04:48:10 +0000
@@ -89,6 +89,14 @@
89 self.sourcepackagename.name, self.distribution.displayname)89 self.sourcepackagename.name, self.distribution.displayname)
9090
91 @property91 @property
92 def development_version(self):
93 """See `IDistributionSourcePackage`."""
94 series = self.distribution.currentseries
95 if series is None:
96 return None
97 return series.getSourcePackage(self.sourcepackagename)
98
99 @property
92 def _self_in_database(self):100 def _self_in_database(self):
93 """Return the equivalent database-backed record of self."""101 """Return the equivalent database-backed record of self."""
94 # XXX: allenap 2008-11-13 bug=297736: This is a temporary102 # XXX: allenap 2008-11-13 bug=297736: This is a temporary
@@ -124,9 +132,6 @@
124 _get_bug_reporting_guidelines,132 _get_bug_reporting_guidelines,
125 _set_bug_reporting_guidelines)133 _set_bug_reporting_guidelines)
126134
127 def __getitem__(self, version):
128 return self.getVersion(version)
129
130 @property135 @property
131 def latest_overall_publication(self):136 def latest_overall_publication(self):
132 """See `IDistributionSourcePackage`."""137 """See `IDistributionSourcePackage`."""
133138
=== modified file 'lib/lp/registry/model/sourcepackage.py'
--- lib/lp/registry/model/sourcepackage.py 2009-07-11 09:33:12 +0000
+++ lib/lp/registry/model/sourcepackage.py 2009-07-15 07:25:04 +0000
@@ -424,6 +424,11 @@
424 self.sourcepackagename, self.distribution.currentseries)424 self.sourcepackagename, self.distribution.currentseries)
425425
426 @property426 @property
427 def distribution_sourcepackage(self):
428 """See `ISourcePackage`."""
429 return self.distribution.getSourcePackage(self.sourcepackagename)
430
431 @property
427 def bug_reporting_guidelines(self):432 def bug_reporting_guidelines(self):
428 """See `IBugTarget`."""433 """See `IBugTarget`."""
429 return self.distribution.bug_reporting_guidelines434 return self.distribution.bug_reporting_guidelines
430435
=== modified file 'lib/lp/registry/tests/test_distributionsourcepackage.py'
--- lib/lp/registry/tests/test_distributionsourcepackage.py 2009-07-10 15:38:46 +0000
+++ lib/lp/registry/tests/test_distributionsourcepackage.py 2009-07-15 07:55:56 +0000
@@ -109,5 +109,25 @@
109109
110 self.assertEqual(related_archive_names, ['gedit-nightly'])110 self.assertEqual(related_archive_names, ['gedit-nightly'])
111111
112 def test_development_version(self):
113 # IDistributionSourcePackage.development_version is the ISourcePackage
114 # for the current series of the distribution.
115 dsp = self.factory.makeDistributionSourcePackage()
116 series = self.factory.makeDistroRelease(distribution=dsp.distribution)
117 self.assertEqual(series, dsp.distribution.currentseries)
118 development_version = dsp.distribution.currentseries.getSourcePackage(
119 dsp.sourcepackagename)
120 self.assertEqual(development_version, dsp.development_version)
121
122 def test_development_version_no_current_series(self):
123 # IDistributionSourcePackage.development_version is the ISourcePackage
124 # for the current series of the distribution.
125 dsp = self.factory.makeDistributionSourcePackage()
126 currentseries = dsp.distribution.currentseries
127 # The current series is None by default.
128 self.assertIs(None, currentseries)
129 self.assertEqual(None, dsp.development_version)
130
131
112def test_suite():132def test_suite():
113 return unittest.TestLoader().loadTestsFromName(__name__)133 return unittest.TestLoader().loadTestsFromName(__name__)
114134
=== modified file 'lib/lp/registry/tests/test_sourcepackage.py'
--- lib/lp/registry/tests/test_sourcepackage.py 2009-06-02 13:52:48 +0000
+++ lib/lp/registry/tests/test_sourcepackage.py 2009-07-15 07:25:04 +0000
@@ -154,6 +154,17 @@
154 self.assertEqual(154 self.assertEqual(
155 dev_sourcepackage, dev_sourcepackage.development_version)155 dev_sourcepackage, dev_sourcepackage.development_version)
156156
157 def test_distribution_sourcepackage(self):
158 # ISourcePackage.distribution_sourcepackage is the distribution source
159 # package for the ISourcePackage.
160 sourcepackage = self.factory.makeSourcePackage()
161 distribution = sourcepackage.distribution
162 distribution_sourcepackage = distribution.getSourcePackage(
163 sourcepackage.sourcepackagename)
164 self.assertEqual(
165 distribution_sourcepackage,
166 sourcepackage.distribution_sourcepackage)
167
157168
158class TestSourcePackageSecurity(TestCaseWithFactory):169class TestSourcePackageSecurity(TestCaseWithFactory):
159 """Tests for source package branch linking security."""170 """Tests for source package branch linking security."""
160171
=== modified file 'lib/lp/soyuz/doc/buildd-queuebuilder-lookup.txt'
--- lib/lp/soyuz/doc/buildd-queuebuilder-lookup.txt 2009-04-29 20:27:44 +0000
+++ lib/lp/soyuz/doc/buildd-queuebuilder-lookup.txt 2009-07-16 03:31:45 +0000
@@ -31,7 +31,7 @@
31 >>> partner_archive = getUtility(IArchiveSet).getByDistroPurpose(31 >>> partner_archive = getUtility(IArchiveSet).getByDistroPurpose(
32 ... distribution=ubuntu, purpose=ArchivePurpose.PARTNER)32 ... distribution=ubuntu, purpose=ArchivePurpose.PARTNER)
3333
34 >>> dspr = ubuntu.getSourcePackage('mozilla-firefox')['0.9']34 >>> dspr = ubuntu.getSourcePackage('mozilla-firefox').getVersion('0.9')
35 >>> the_spr = dspr.sourcepackagerelease35 >>> the_spr = dspr.sourcepackagerelease
3636
37 >>> initial_candidates = []37 >>> initial_candidates = []
3838
=== modified file 'lib/lp/soyuz/doc/distroseriesqueue.txt'
--- lib/lp/soyuz/doc/distroseriesqueue.txt 2009-07-03 09:49:13 +0000
+++ lib/lp/soyuz/doc/distroseriesqueue.txt 2009-07-16 03:31:45 +0000
@@ -712,7 +712,8 @@
712have in the sampledata.712have in the sampledata.
713713
714 >>> [binary_queue] = queue_items714 >>> [binary_queue] = queue_items
715 >>> non_matching_pmount = ubuntu.getSourcePackage('pmount')['0.1-2']715 >>> pmount = ubuntu.getSourcePackage('pmount')
716 >>> non_matching_pmount = pmount.getVersion('0.1-2')
716 >>> unused = binary_queue.addSource(717 >>> unused = binary_queue.addSource(
717 ... non_matching_pmount.sourcepackagerelease)718 ... non_matching_pmount.sourcepackagerelease)
718719
@@ -732,7 +733,7 @@
732 ... PackagePublishingPocket.RELEASE,733 ... PackagePublishingPocket.RELEASE,
733 ... 'pmount_0.1-1_source.changes', 'some content',734 ... 'pmount_0.1-1_source.changes', 'some content',
734 ... breezy_autotest.main_archive)735 ... breezy_autotest.main_archive)
735 >>> matching_pmount = ubuntu.getSourcePackage('pmount')['0.1-1']736 >>> matching_pmount = pmount.getVersion('0.1-1')
736 >>> unused = candidate_queue.addSource(737 >>> unused = candidate_queue.addSource(
737 ... matching_pmount.sourcepackagerelease)738 ... matching_pmount.sourcepackagerelease)
738739
@@ -1087,7 +1088,7 @@
1087are. Contents can be attached to it.1088are. Contents can be attached to it.
10881089
1089 # Retrieve a SourcePackageRelease from the sampledata.1090 # Retrieve a SourcePackageRelease from the sampledata.
1090 >>> a_source_package = ubuntu.getSourcePackage('pmount')['0.1-2']1091 >>> a_source_package = pmount.getVersion('0.1-2')
1091 >>> a_source_release = a_source_package.sourcepackagerelease1092 >>> a_source_release = a_source_package.sourcepackagerelease
10921093
1093 >>> unused = delayed_copy.addSource(a_source_release)1094 >>> unused = delayed_copy.addSource(a_source_release)
10941095
=== modified file 'lib/lp/soyuz/doc/package-diff.txt'
--- lib/lp/soyuz/doc/package-diff.txt 2009-05-06 20:53:05 +0000
+++ lib/lp/soyuz/doc/package-diff.txt 2009-07-16 03:31:45 +0000
@@ -18,8 +18,8 @@
18 >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')18 >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
19 >>> pmount = ubuntu.getSourcePackage('pmount')19 >>> pmount = ubuntu.getSourcePackage('pmount')
2020
21 >>> pmount_from = pmount['0.1-1'].sourcepackagerelease21 >>> pmount_from = pmount.getVersion('0.1-1').sourcepackagerelease
22 >>> pmount_to = pmount['0.1-2'].sourcepackagerelease22 >>> pmount_to = pmount.getVersion('0.1-2').sourcepackagerelease
2323
24A packageDiff can be created from the two packages by calling24A packageDiff can be created from the two packages by calling
25requestDiffTo(). It takes two arguments: the user requesting the25requestDiffTo(). It takes two arguments: the user requesting the