Merge lp:~michael.nelson/launchpad/536700-present-packagebuilds-in-ppa-context into lp:launchpad/db-devel
- 536700-present-packagebuilds-in-ppa-context
- Merge into db-devel
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 9485 | ||||
Proposed branch: | lp:~michael.nelson/launchpad/536700-present-packagebuilds-in-ppa-context | ||||
Merge into: | lp:launchpad/db-devel | ||||
Diff against target: |
1137 lines (+424/-145) (has conflicts) 28 files modified
lib/canonical/buildd/apply-ogre-model (+0/-39) lib/canonical/buildd/binarypackage.py (+7/-17) lib/canonical/buildd/debian.py (+1/-40) lib/canonical/buildd/debian/changelog (+7/-0) lib/canonical/buildd/debian/rules (+2/-2) lib/canonical/buildd/debian/upgrade-config (+11/-0) lib/canonical/buildd/template-buildd-slave.conf (+0/-1) lib/canonical/buildd/tests/buildd-slave-test.conf (+0/-1) lib/canonical/launchpad/templates/launchpad-form.pt (+6/-3) lib/canonical/widgets/product.py (+3/-1) lib/lp/buildmaster/configure.zcml (+6/-0) lib/lp/buildmaster/interfaces/packagebuild.py (+26/-1) lib/lp/buildmaster/model/packagebuild.py (+45/-2) lib/lp/buildmaster/tests/test_packagebuild.py (+49/-6) lib/lp/code/browser/sourcepackagerecipe.py (+12/-3) lib/lp/code/browser/tests/test_sourcepackagerecipe.py (+56/-7) lib/lp/code/model/sourcepackagerecipedata.py (+2/-0) lib/lp/registry/doc/product-widgets.txt (+45/-2) lib/lp/registry/model/sourcepackage.py (+5/-3) lib/lp/soyuz/configure.zcml (+5/-0) lib/lp/soyuz/interfaces/archive.py (+6/-0) lib/lp/soyuz/interfaces/buildrecords.py (+11/-6) lib/lp/soyuz/model/archive.py (+14/-4) lib/lp/soyuz/model/binarypackagebuild.py (+21/-0) lib/lp/soyuz/tests/test_archive.py (+1/-1) lib/lp/soyuz/tests/test_binarypackagebuild.py (+37/-0) lib/lp/soyuz/tests/test_hasbuildrecords.py (+31/-0) lib/lp/testing/factory.py (+15/-6) Text conflict in lib/lp/code/browser/tests/test_sourcepackagerecipe.py |
||||
To merge this branch: | bzr merge lp:~michael.nelson/launchpad/536700-present-packagebuilds-in-ppa-context | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Henning Eggers (community) | code | Approve | |
Review via email: mp+27477@code.launchpad.net |
Commit message
Description of the change
Please review my branch:
bzr+
revision 11006.
Test command: bin/test -vv -m test_packagebuild -m test_binarypack
test_hasbuildre
This branch does some initial work to enable PPA's to present general
IPackageBuilds rather than IBinaryPackageB
It adds and tests an IPackageBuildSe
optional param to the getBuildRecords() method - binary_only - which defaults
to true (current behaivour). It then updates IArchive.
support binary_only=False.
Additionally, it adds an adapter for IBuildFarmJob-
preparation for the UI (so each build can present its title correctly).
Michael Nelson (michael.nelson) wrote : | # |
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi Michael,
> thank you for your fix and sorry for the delay...
No problem... it was worth all the improvements below :)
>
> Am 14.06.2010 10:35, schrieb Michael Nelson:
> > Test command: bin/test -vv -m test_packagebuild -m test_binarypack
> -m
> > test_hasbuildre
>
> Yup, they pass. Thanks.
>
> > This branch does some initial work to enable PPA's to present general
> > IPackageBuilds rather than IBinaryPackageB
>
> So, I assume that is the reason that no bug is attached to this branch?
There are two now :P
>
> >
> > It adds and tests an IPackageBuildSe
> > optional param to the getBuildRecords() method - binary_only - which
> defaults
> > to true (current behaivour). It then updates IArchive.
> > support binary_only=False.
> >
> > Additionally, it adds an adapter for IBuildFarmJob-
> > preparation for the UI (so each build can present its title correctly).
> >
>
> Very clever. ;-)
>
> Here are my comments:
>
...
> > === modified file 'lib/lp/
> > --- lib/lp/
> > +++ lib/lp/
> > @@ -214,3 +218,40 @@
> > def _handleStatus_
> > return BuildBase.
> > self, librarian, slave_status, logger)
> > +
> > +
> > +class PackageBuildSet:
> > + implements(
> > +
> > + def getBuildsForArc
> > + """See `IPackageBuildS
> > +
> > + extra_exprs = []
> > +
> > + # Add query clause that filters on build status if the latter is
> > + # provided.
>
> I had been told that comments are not there to reiterate what the code is
> doing - the code should speak for itself. This looks like such a case, does it
> not?
/me must stop doing that. Removed.
>
> > + if status is not None:
> > + extra_exprs.
> > +
> > + # Add query clause that filters on pocket if the latter is
> provided.
>
> Same here. The comment is just chatter. Maybe its pseudo code that you forgot
> in here?
Ditto.
>
> > + if pocket:
> > + extra_exprs.
> > +
> > + store = getUtility(
> > + result_set = store.find(
> > + PackageBuild.
> > + PackageBuild.
> > + *extra_exprs)
> > +
> > + # Ordering according status
> > + # * SUPERSEDED & All by -datecreated
>
> What does "& All" refer to"?
I updated this to: When we have a set of builds that may include pending or superseded builds, we order by -date_created (as we won't always have a date_finished), otherwise we can order by -date_finished.
>
> > + # * FULLYBUILT & FAILURES by -datebuilt
> I would put this near the "else" to expla...
Henning Eggers (henninge) wrote : | # |
As discussed on mumble:
- Please make sure the indention is less confusing by using an intermediate variable for the states, e.g. "unfinished_
+ if status is None or status in [
+ BuildStatus.
+ BuildStatus.
+ BuildStatus.
- AFAICT PackageBuildSet is missing from __all__ (not TestPackageBuil
Thanks for you good work and patience with me. ;-)
Preview Diff
1 | === removed file 'lib/canonical/buildd/apply-ogre-model' | |||
2 | --- lib/canonical/buildd/apply-ogre-model 2009-06-30 21:06:27 +0000 | |||
3 | +++ lib/canonical/buildd/apply-ogre-model 1970-01-01 00:00:00 +0000 | |||
4 | @@ -1,39 +0,0 @@ | |||
5 | 1 | #!/bin/sh | ||
6 | 2 | # | ||
7 | 3 | # Copyright 2009 Canonical Ltd. This software is licensed under the | ||
8 | 4 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
9 | 5 | # | ||
10 | 6 | # Author: Daniel Silverstone <daniel.silverstone@canonical.com> | ||
11 | 7 | |||
12 | 8 | # Buildd Slave tool to apply the ogre model to the chroot | ||
13 | 9 | |||
14 | 10 | # Expects build id as arg 1, makes build-id to contain the build | ||
15 | 11 | # Expects ogre component name as arg 2 | ||
16 | 12 | |||
17 | 13 | # Needs SUDO to be set to a sudo instance for passwordless access | ||
18 | 14 | # LN must be an ln instance which can take -s and -f at the same time | ||
19 | 15 | |||
20 | 16 | SUDO=/usr/bin/sudo | ||
21 | 17 | |||
22 | 18 | BUILDID="$1" | ||
23 | 19 | COMPONENT="$2" | ||
24 | 20 | |||
25 | 21 | set -e | ||
26 | 22 | |||
27 | 23 | exec 2>&1 | ||
28 | 24 | |||
29 | 25 | cd $HOME | ||
30 | 26 | cd "build-$BUILDID/chroot-autobuild/etc/apt" | ||
31 | 27 | |||
32 | 28 | echo "Attempting OGRE for $COMPONENT in build-$BUILDID" | ||
33 | 29 | |||
34 | 30 | if [ -e "sources.list.$COMPONENT" ]; then | ||
35 | 31 | if [ -h "sources.list" ]; then | ||
36 | 32 | $SUDO ln -sf "sources.list.$COMPONENT" sources.list | ||
37 | 33 | else | ||
38 | 34 | echo "OGRE sources.list found, but sources.list is not a symlink" | ||
39 | 35 | fi | ||
40 | 36 | else | ||
41 | 37 | echo "No OGRE sources.list found." | ||
42 | 38 | fi | ||
43 | 39 | |||
44 | 40 | 0 | ||
45 | === modified file 'lib/canonical/buildd/binarypackage.py' | |||
46 | --- lib/canonical/buildd/binarypackage.py 2010-01-14 02:55:22 +0000 | |||
47 | +++ lib/canonical/buildd/binarypackage.py 2010-06-16 14:06:25 +0000 | |||
48 | @@ -55,22 +55,12 @@ | |||
49 | 55 | self._dscfile = f | 55 | self._dscfile = f |
50 | 56 | if self._dscfile is None: | 56 | if self._dscfile is None: |
51 | 57 | raise ValueError, files | 57 | raise ValueError, files |
68 | 58 | if 'arch_indep' in extra_args: | 58 | |
69 | 59 | self.arch_indep = extra_args['arch_indep'] | 59 | self.archive_purpose = extra_args.get('archive_purpose') |
70 | 60 | else: | 60 | self.suite = extra_args.get('suite') |
71 | 61 | self.arch_indep = False | 61 | self.component = extra_args['ogrecomponent'] |
72 | 62 | if 'suite' in extra_args: | 62 | self.arch_indep = extra_args.get('arch_indep', False) |
73 | 63 | self.suite = extra_args['suite'] | 63 | self.build_debug_symbols = extra_args.get('build_debug_symbols', False) |
58 | 64 | else: | ||
59 | 65 | self.suite = False | ||
60 | 66 | if 'archive_purpose' in extra_args: | ||
61 | 67 | self.archive_purpose = extra_args['archive_purpose'] | ||
62 | 68 | else: | ||
63 | 69 | self.archive_purpose = False | ||
64 | 70 | if 'build_debug_symbols' in extra_args: | ||
65 | 71 | self.build_debug_symbols = extra_args['build_debug_symbols'] | ||
66 | 72 | else: | ||
67 | 73 | self.build_debug_symbols = False | ||
74 | 74 | 64 | ||
75 | 75 | super(BinaryPackageBuildManager, self).initiate( | 65 | super(BinaryPackageBuildManager, self).initiate( |
76 | 76 | files, chroot, extra_args) | 66 | files, chroot, extra_args) |
77 | @@ -92,7 +82,7 @@ | |||
78 | 92 | args.extend(["--purpose=" + self.archive_purpose]) | 82 | args.extend(["--purpose=" + self.archive_purpose]) |
79 | 93 | if self.build_debug_symbols: | 83 | if self.build_debug_symbols: |
80 | 94 | args.extend(["--build-debug-symbols"]) | 84 | args.extend(["--build-debug-symbols"]) |
82 | 95 | args.extend(["--comp=" + self.ogre]) | 85 | args.extend(["--comp=" + self.component]) |
83 | 96 | args.extend([self._dscfile]) | 86 | args.extend([self._dscfile]) |
84 | 97 | self.runSubProcess( self._sbuildpath, args ) | 87 | self.runSubProcess( self._sbuildpath, args ) |
85 | 98 | 88 | ||
86 | 99 | 89 | ||
87 | === modified file 'lib/canonical/buildd/debian.py' | |||
88 | --- lib/canonical/buildd/debian.py 2010-01-14 20:19:27 +0000 | |||
89 | +++ lib/canonical/buildd/debian.py 2010-06-16 14:06:25 +0000 | |||
90 | @@ -20,7 +20,6 @@ | |||
91 | 20 | INIT = "INIT" | 20 | INIT = "INIT" |
92 | 21 | UNPACK = "UNPACK" | 21 | UNPACK = "UNPACK" |
93 | 22 | MOUNT = "MOUNT" | 22 | MOUNT = "MOUNT" |
94 | 23 | OGRE = "OGRE" | ||
95 | 24 | SOURCES = "SOURCES" | 23 | SOURCES = "SOURCES" |
96 | 25 | UPDATE = "UPDATE" | 24 | UPDATE = "UPDATE" |
97 | 26 | REAP = "REAP" | 25 | REAP = "REAP" |
98 | @@ -35,7 +34,6 @@ | |||
99 | 35 | BuildManager.__init__(self, slave, buildid) | 34 | BuildManager.__init__(self, slave, buildid) |
100 | 36 | self._updatepath = slave._config.get("debianmanager", "updatepath") | 35 | self._updatepath = slave._config.get("debianmanager", "updatepath") |
101 | 37 | self._scanpath = slave._config.get("debianmanager", "processscanpath") | 36 | self._scanpath = slave._config.get("debianmanager", "processscanpath") |
102 | 38 | self._ogrepath = slave._config.get("debianmanager", "ogrepath") | ||
103 | 39 | self._sourcespath = slave._config.get("debianmanager", "sourcespath") | 37 | self._sourcespath = slave._config.get("debianmanager", "sourcespath") |
104 | 40 | self._cachepath = slave._config.get("slave","filecache") | 38 | self._cachepath = slave._config.get("slave","filecache") |
105 | 41 | self._state = DebianBuildState.INIT | 39 | self._state = DebianBuildState.INIT |
106 | @@ -49,32 +47,15 @@ | |||
107 | 49 | def initiate(self, files, chroot, extra_args): | 47 | def initiate(self, files, chroot, extra_args): |
108 | 50 | """Initiate a build with a given set of files and chroot.""" | 48 | """Initiate a build with a given set of files and chroot.""" |
109 | 51 | 49 | ||
121 | 52 | if 'ogrecomponent' in extra_args: | 50 | self.sources_list = extra_args.get('archives') |
111 | 53 | # Ubuntu refers to the concept that "main sees only main | ||
112 | 54 | # while building" etc as "The Ogre Model" (onions, layers | ||
113 | 55 | # and all). If we're given an ogre component, use it | ||
114 | 56 | self.ogre = extra_args['ogrecomponent'] | ||
115 | 57 | else: | ||
116 | 58 | self.ogre = False | ||
117 | 59 | if 'archives' in extra_args and extra_args['archives']: | ||
118 | 60 | self.sources_list = extra_args['archives'] | ||
119 | 61 | else: | ||
120 | 62 | self.sources_list = None | ||
122 | 63 | 51 | ||
123 | 64 | BuildManager.initiate(self, files, chroot, extra_args) | 52 | BuildManager.initiate(self, files, chroot, extra_args) |
124 | 65 | 53 | ||
125 | 66 | def doOgreModel(self): | ||
126 | 67 | """Perform the ogre model activation.""" | ||
127 | 68 | self.runSubProcess(self._ogrepath, | ||
128 | 69 | ["apply-ogre-model", self._buildid, self.ogre]) | ||
129 | 70 | |||
130 | 71 | def doSourcesList(self): | 54 | def doSourcesList(self): |
131 | 72 | """Override apt/sources.list. | 55 | """Override apt/sources.list. |
132 | 73 | 56 | ||
133 | 74 | Mainly used for PPA builds. | 57 | Mainly used for PPA builds. |
134 | 75 | """ | 58 | """ |
135 | 76 | # XXX cprov 2007-05-17: It 'undo' ogre-component changes. | ||
136 | 77 | # for PPAs it must be re-implemented on builddmaster side. | ||
137 | 78 | args = ["override-sources-list", self._buildid] | 59 | args = ["override-sources-list", self._buildid] |
138 | 79 | args.extend(self.sources_list) | 60 | args.extend(self.sources_list) |
139 | 80 | self.runSubProcess(self._sourcespath, args) | 61 | self.runSubProcess(self._sourcespath, args) |
140 | @@ -181,26 +162,6 @@ | |||
141 | 181 | self._state = DebianBuildState.UMOUNT | 162 | self._state = DebianBuildState.UMOUNT |
142 | 182 | self.doUnmounting() | 163 | self.doUnmounting() |
143 | 183 | else: | 164 | else: |
144 | 184 | # Run OGRE if we need to, else run UPDATE | ||
145 | 185 | if self.ogre: | ||
146 | 186 | self._state = DebianBuildState.OGRE | ||
147 | 187 | self.doOgreModel() | ||
148 | 188 | elif self.sources_list is not None: | ||
149 | 189 | self._state = DebianBuildState.SOURCES | ||
150 | 190 | self.doSourcesList() | ||
151 | 191 | else: | ||
152 | 192 | self._state = DebianBuildState.UPDATE | ||
153 | 193 | self.doUpdateChroot() | ||
154 | 194 | |||
155 | 195 | def iterate_OGRE(self, success): | ||
156 | 196 | """Just finished running the ogre applicator.""" | ||
157 | 197 | if success != 0: | ||
158 | 198 | if not self.alreadyfailed: | ||
159 | 199 | self._slave.chrootFail() | ||
160 | 200 | self.alreadyfailed = True | ||
161 | 201 | self._state = DebianBuildState.REAP | ||
162 | 202 | self.doReapProcesses() | ||
163 | 203 | else: | ||
164 | 204 | if self.sources_list is not None: | 165 | if self.sources_list is not None: |
165 | 205 | self._state = DebianBuildState.SOURCES | 166 | self._state = DebianBuildState.SOURCES |
166 | 206 | self.doSourcesList() | 167 | self.doSourcesList() |
167 | 207 | 168 | ||
168 | === modified file 'lib/canonical/buildd/debian/changelog' | |||
169 | --- lib/canonical/buildd/debian/changelog 2010-06-10 16:52:04 +0000 | |||
170 | +++ lib/canonical/buildd/debian/changelog 2010-06-16 14:06:25 +0000 | |||
171 | @@ -1,3 +1,10 @@ | |||
172 | 1 | launchpad-buildd (63) hardy-cat; urgency=low | ||
173 | 2 | |||
174 | 3 | * Drop apply-ogre-model, since override-sources-list replaced it three years | ||
175 | 4 | ago. Also clean up extra_args parsing a bit. | ||
176 | 5 | |||
177 | 6 | -- William Grant <wgrant@ubuntu.com> Sat, 12 Jun 2010 11:33:11 +1000 | ||
178 | 7 | |||
179 | 1 | launchpad-buildd (62) hardy-cat; urgency=low | 8 | launchpad-buildd (62) hardy-cat; urgency=low |
180 | 2 | 9 | ||
181 | 3 | * Make the buildds cope with not having a sourcepackagename LP#587109 | 10 | * Make the buildds cope with not having a sourcepackagename LP#587109 |
182 | 4 | 11 | ||
183 | === modified file 'lib/canonical/buildd/debian/rules' | |||
184 | --- lib/canonical/buildd/debian/rules 2010-03-10 21:23:17 +0000 | |||
185 | +++ lib/canonical/buildd/debian/rules 2010-06-16 14:06:25 +0000 | |||
186 | @@ -24,8 +24,8 @@ | |||
187 | 24 | pyfiles = debian.py slave.py binarypackage.py utils.py __init__.py \ | 24 | pyfiles = debian.py slave.py binarypackage.py utils.py __init__.py \ |
188 | 25 | sourcepackagerecipe.py translationtemplates.py | 25 | sourcepackagerecipe.py translationtemplates.py |
189 | 26 | slavebins = unpack-chroot mount-chroot update-debian-chroot sbuild-package \ | 26 | slavebins = unpack-chroot mount-chroot update-debian-chroot sbuild-package \ |
192 | 27 | scan-for-processes umount-chroot remove-build apply-ogre-model \ | 27 | scan-for-processes umount-chroot remove-build override-sources-list \ |
193 | 28 | override-sources-list buildrecipe generate-translation-templates | 28 | buildrecipe generate-translation-templates |
194 | 29 | 29 | ||
195 | 30 | BUILDDUID=65500 | 30 | BUILDDUID=65500 |
196 | 31 | BUILDDGID=65500 | 31 | BUILDDGID=65500 |
197 | 32 | 32 | ||
198 | === modified file 'lib/canonical/buildd/debian/upgrade-config' | |||
199 | --- lib/canonical/buildd/debian/upgrade-config 2010-04-01 03:47:51 +0000 | |||
200 | +++ lib/canonical/buildd/debian/upgrade-config 2010-06-16 14:06:25 +0000 | |||
201 | @@ -92,6 +92,15 @@ | |||
202 | 92 | 'generatepath = /usr/share/launchpad-buildd/slavebin/generate-translation-templates\n' | 92 | 'generatepath = /usr/share/launchpad-buildd/slavebin/generate-translation-templates\n' |
203 | 93 | 'resultarchive = translation-templates.tar.gz\n') | 93 | 'resultarchive = translation-templates.tar.gz\n') |
204 | 94 | 94 | ||
205 | 95 | def upgrade_to_63(): | ||
206 | 96 | print "Upgrading %s to version 63" % conf_file | ||
207 | 97 | subprocess.call(["mv", conf_file, conf_file+"-prev63~"]) | ||
208 | 98 | in_file = open(conf_file+"-prev63~", "r") | ||
209 | 99 | out_file = open(conf_file, "w") | ||
210 | 100 | for line in in_file: | ||
211 | 101 | if not line.startswith('ogrepath'): | ||
212 | 102 | out_file.write(line) | ||
213 | 103 | |||
214 | 95 | 104 | ||
215 | 96 | if __name__ == "__main__": | 105 | if __name__ == "__main__": |
216 | 97 | if old_version.find("~") > 0: | 106 | if old_version.find("~") > 0: |
217 | @@ -108,4 +117,6 @@ | |||
218 | 108 | upgrade_to_58() | 117 | upgrade_to_58() |
219 | 109 | if int(old_version) < 59: | 118 | if int(old_version) < 59: |
220 | 110 | upgrade_to_59() | 119 | upgrade_to_59() |
221 | 120 | if int(old_version) < 63: | ||
222 | 121 | upgrade_to_63() | ||
223 | 111 | 122 | ||
224 | 112 | 123 | ||
225 | === modified file 'lib/canonical/buildd/template-buildd-slave.conf' | |||
226 | --- lib/canonical/buildd/template-buildd-slave.conf 2010-03-12 08:32:39 +0000 | |||
227 | +++ lib/canonical/buildd/template-buildd-slave.conf 2010-06-16 14:06:25 +0000 | |||
228 | @@ -18,7 +18,6 @@ | |||
229 | 18 | [debianmanager] | 18 | [debianmanager] |
230 | 19 | updatepath = /usr/share/launchpad-buildd/slavebin/update-debian-chroot | 19 | updatepath = /usr/share/launchpad-buildd/slavebin/update-debian-chroot |
231 | 20 | processscanpath = /usr/share/launchpad-buildd/slavebin/scan-for-processes | 20 | processscanpath = /usr/share/launchpad-buildd/slavebin/scan-for-processes |
232 | 21 | ogrepath = /usr/share/launchpad-buildd/slavebin/apply-ogre-model | ||
233 | 22 | sourcespath = /usr/share/launchpad-buildd/slavebin/override-sources-list | 21 | sourcespath = /usr/share/launchpad-buildd/slavebin/override-sources-list |
234 | 23 | 22 | ||
235 | 24 | [binarypackagemanager] | 23 | [binarypackagemanager] |
236 | 25 | 24 | ||
237 | === modified file 'lib/canonical/buildd/tests/buildd-slave-test.conf' | |||
238 | --- lib/canonical/buildd/tests/buildd-slave-test.conf 2007-06-05 00:53:06 +0000 | |||
239 | +++ lib/canonical/buildd/tests/buildd-slave-test.conf 2010-06-16 14:06:25 +0000 | |||
240 | @@ -17,5 +17,4 @@ | |||
241 | 17 | sbuildargs = -dautobuild --nolog --batch | 17 | sbuildargs = -dautobuild --nolog --batch |
242 | 18 | updatepath = /var/tmp/buildd/slavebin/update-debian-chroot | 18 | updatepath = /var/tmp/buildd/slavebin/update-debian-chroot |
243 | 19 | processscanpath = /var/tmp/buildd/slavebin/scan-for-processes | 19 | processscanpath = /var/tmp/buildd/slavebin/scan-for-processes |
244 | 20 | ogrepath = /var/tmp/buildd/slavebin/apply-ogre-model | ||
245 | 21 | sourcespath = /usr/share/launchpad-buildd/slavebin/override-sources-list | 20 | sourcespath = /usr/share/launchpad-buildd/slavebin/override-sources-list |
246 | 22 | 21 | ||
247 | === modified file 'lib/canonical/launchpad/templates/launchpad-form.pt' | |||
248 | --- lib/canonical/launchpad/templates/launchpad-form.pt 2010-03-15 16:58:49 +0000 | |||
249 | +++ lib/canonical/launchpad/templates/launchpad-form.pt 2010-06-16 14:06:25 +0000 | |||
250 | @@ -171,9 +171,12 @@ | |||
251 | 171 | </td> | 171 | </td> |
252 | 172 | </tr> | 172 | </tr> |
253 | 173 | </tal:is-visible> | 173 | </tal:is-visible> |
257 | 174 | <tal:not-visible condition="not: widget/visible"> | 174 | <tal:not-visible |
258 | 175 | <tr> | 175 | condition="not: widget/visible"> |
259 | 176 | <td tal:content="structure widget/hidden" /> | 176 | <tr |
260 | 177 | tal:define="markup widget/hidden" | ||
261 | 178 | tal:condition="markup"> | ||
262 | 179 | <td tal:content="structure markup" /> | ||
263 | 177 | </tr> | 180 | </tr> |
264 | 178 | </tal:not-visible> | 181 | </tal:not-visible> |
265 | 179 | </metal:macro> | 182 | </metal:macro> |
266 | 180 | 183 | ||
267 | === modified file 'lib/canonical/widgets/product.py' | |||
268 | --- lib/canonical/widgets/product.py 2009-07-21 03:56:03 +0000 | |||
269 | +++ lib/canonical/widgets/product.py 2010-06-16 14:06:25 +0000 | |||
270 | @@ -408,7 +408,7 @@ | |||
271 | 408 | 408 | ||
272 | 409 | class GhostWidget(TextWidget): | 409 | class GhostWidget(TextWidget): |
273 | 410 | """A simple widget that has no HTML.""" | 410 | """A simple widget that has no HTML.""" |
275 | 411 | 411 | visible = False | |
276 | 412 | # This suppresses the stuff above the widget. | 412 | # This suppresses the stuff above the widget. |
277 | 413 | display_label = False | 413 | display_label = False |
278 | 414 | # This suppresses the stuff underneath the widget. | 414 | # This suppresses the stuff underneath the widget. |
279 | @@ -418,3 +418,5 @@ | |||
280 | 418 | def __call__(self): | 418 | def __call__(self): |
281 | 419 | """See `SimpleInputWidget`.""" | 419 | """See `SimpleInputWidget`.""" |
282 | 420 | return '' | 420 | return '' |
283 | 421 | |||
284 | 422 | hidden = __call__ | ||
285 | 421 | 423 | ||
286 | === modified file 'lib/lp/buildmaster/configure.zcml' | |||
287 | --- lib/lp/buildmaster/configure.zcml 2010-05-20 13:12:04 +0000 | |||
288 | +++ lib/lp/buildmaster/configure.zcml 2010-06-16 14:06:25 +0000 | |||
289 | @@ -75,6 +75,12 @@ | |||
290 | 75 | <allow | 75 | <allow |
291 | 76 | interface="lp.buildmaster.interfaces.packagebuild.IPackageBuildSource" /> | 76 | interface="lp.buildmaster.interfaces.packagebuild.IPackageBuildSource" /> |
292 | 77 | </securedutility> | 77 | </securedutility> |
293 | 78 | <securedutility | ||
294 | 79 | class="lp.buildmaster.model.packagebuild.PackageBuildSet" | ||
295 | 80 | provides="lp.buildmaster.interfaces.packagebuild.IPackageBuildSet"> | ||
296 | 81 | <allow | ||
297 | 82 | interface="lp.buildmaster.interfaces.packagebuild.IPackageBuildSet" /> | ||
298 | 83 | </securedutility> | ||
299 | 78 | 84 | ||
300 | 79 | <!-- BuildQueue --> | 85 | <!-- BuildQueue --> |
301 | 80 | <class | 86 | <class |
302 | 81 | 87 | ||
303 | === modified file 'lib/lp/buildmaster/interfaces/packagebuild.py' | |||
304 | --- lib/lp/buildmaster/interfaces/packagebuild.py 2010-05-21 09:42:21 +0000 | |||
305 | +++ lib/lp/buildmaster/interfaces/packagebuild.py 2010-06-16 14:06:25 +0000 | |||
306 | @@ -6,6 +6,7 @@ | |||
307 | 6 | __all__ = [ | 6 | __all__ = [ |
308 | 7 | 'IPackageBuild', | 7 | 'IPackageBuild', |
309 | 8 | 'IPackageBuildSource', | 8 | 'IPackageBuildSource', |
310 | 9 | 'IPackageBuildSet', | ||
311 | 9 | ] | 10 | ] |
312 | 10 | 11 | ||
313 | 11 | 12 | ||
314 | @@ -16,6 +17,7 @@ | |||
315 | 16 | 17 | ||
316 | 17 | from canonical.launchpad import _ | 18 | from canonical.launchpad import _ |
317 | 18 | from canonical.launchpad.interfaces.librarian import ILibraryFileAlias | 19 | from canonical.launchpad.interfaces.librarian import ILibraryFileAlias |
318 | 20 | from lp.buildmaster.interfaces.buildbase import BuildStatus | ||
319 | 19 | from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob | 21 | from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJob |
320 | 20 | from lp.registry.interfaces.distribution import IDistribution | 22 | from lp.registry.interfaces.distribution import IDistribution |
321 | 21 | from lp.registry.interfaces.distroseries import IDistroSeries | 23 | from lp.registry.interfaces.distroseries import IDistroSeries |
322 | @@ -162,10 +164,33 @@ | |||
323 | 162 | class IPackageBuildSource(Interface): | 164 | class IPackageBuildSource(Interface): |
324 | 163 | """A utility of this interface used to create _things_.""" | 165 | """A utility of this interface used to create _things_.""" |
325 | 164 | 166 | ||
327 | 165 | def new(archive, pocket, dependencies=None): | 167 | def new(job_type, virtualized, archive, pocket, processor=None, |
328 | 168 | status=BuildStatus.NEEDSBUILD, dependencies=None): | ||
329 | 166 | """Create a new `IPackageBuild`. | 169 | """Create a new `IPackageBuild`. |
330 | 167 | 170 | ||
331 | 171 | :param job_type: A `BuildFarmJobType` item. | ||
332 | 172 | :param virtualized: A boolean indicating whether this build was | ||
333 | 173 | virtualized. | ||
334 | 168 | :param archive: An `IArchive`. | 174 | :param archive: An `IArchive`. |
335 | 169 | :param pocket: An item of `PackagePublishingPocket`. | 175 | :param pocket: An item of `PackagePublishingPocket`. |
336 | 176 | :param processor: An `IProcessor` required to run this build farm | ||
337 | 177 | job. Default is None (processor-independent). | ||
338 | 178 | :param status: A `BuildStatus` item defaulting to NEEDSBUILD. | ||
339 | 170 | :param dependencies: An optional debian-like dependency line. | 179 | :param dependencies: An optional debian-like dependency line. |
340 | 171 | """ | 180 | """ |
341 | 181 | |||
342 | 182 | |||
343 | 183 | class IPackageBuildSet(Interface): | ||
344 | 184 | """A utility representing a set of package builds.""" | ||
345 | 185 | |||
346 | 186 | def getBuildsForArchive(archive, status=None, pocket=None): | ||
347 | 187 | """Return package build records targeted to a given IArchive. | ||
348 | 188 | |||
349 | 189 | :param archive: The archive for which builds will be returned. | ||
350 | 190 | :param status: If status is provided, only builders with that | ||
351 | 191 | status will be returned. | ||
352 | 192 | :param pocket: If pocket is provided only builds for that pocket | ||
353 | 193 | will be returned. | ||
354 | 194 | :return: a `ResultSet` representing the requested package builds. | ||
355 | 195 | """ | ||
356 | 196 | |||
357 | 172 | 197 | ||
358 | === modified file 'lib/lp/buildmaster/model/packagebuild.py' | |||
359 | --- lib/lp/buildmaster/model/packagebuild.py 2010-06-07 10:43:01 +0000 | |||
360 | +++ lib/lp/buildmaster/model/packagebuild.py 2010-06-16 14:06:25 +0000 | |||
361 | @@ -5,12 +5,14 @@ | |||
362 | 5 | __all__ = [ | 5 | __all__ = [ |
363 | 6 | 'PackageBuild', | 6 | 'PackageBuild', |
364 | 7 | 'PackageBuildDerived', | 7 | 'PackageBuildDerived', |
365 | 8 | 'PackageBuildSet', | ||
366 | 8 | ] | 9 | ] |
367 | 9 | 10 | ||
368 | 10 | 11 | ||
369 | 11 | from lazr.delegates import delegates | 12 | from lazr.delegates import delegates |
370 | 12 | 13 | ||
371 | 13 | from storm.locals import Int, Reference, Storm, Unicode | 14 | from storm.locals import Int, Reference, Storm, Unicode |
372 | 15 | from storm.expr import Desc | ||
373 | 14 | 16 | ||
374 | 15 | from zope.component import getUtility | 17 | from zope.component import getUtility |
375 | 16 | from zope.interface import classProvides, implements | 18 | from zope.interface import classProvides, implements |
376 | @@ -19,13 +21,16 @@ | |||
377 | 19 | from canonical.launchpad.browser.librarian import ( | 21 | from canonical.launchpad.browser.librarian import ( |
378 | 20 | ProxiedLibraryFileAlias) | 22 | ProxiedLibraryFileAlias) |
379 | 21 | from canonical.launchpad.interfaces.lpstorm import IMasterStore | 23 | from canonical.launchpad.interfaces.lpstorm import IMasterStore |
380 | 24 | from canonical.launchpad.webapp.interfaces import ( | ||
381 | 25 | IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR) | ||
382 | 22 | 26 | ||
383 | 23 | from lp.buildmaster.interfaces.buildbase import BuildStatus | 27 | from lp.buildmaster.interfaces.buildbase import BuildStatus |
384 | 24 | from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource | 28 | from lp.buildmaster.interfaces.buildfarmjob import IBuildFarmJobSource |
385 | 25 | from lp.buildmaster.interfaces.packagebuild import ( | 29 | from lp.buildmaster.interfaces.packagebuild import ( |
387 | 26 | IPackageBuild, IPackageBuildSource) | 30 | IPackageBuild, IPackageBuildSet, IPackageBuildSource) |
388 | 27 | from lp.buildmaster.model.buildbase import handle_status_for_build, BuildBase | 31 | from lp.buildmaster.model.buildbase import handle_status_for_build, BuildBase |
390 | 28 | from lp.buildmaster.model.buildfarmjob import BuildFarmJobDerived | 32 | from lp.buildmaster.model.buildfarmjob import ( |
391 | 33 | BuildFarmJob, BuildFarmJobDerived) | ||
392 | 29 | from lp.registry.interfaces.pocket import PackagePublishingPocket | 34 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
393 | 30 | from lp.soyuz.adapters.archivedependencies import ( | 35 | from lp.soyuz.adapters.archivedependencies import ( |
394 | 31 | default_component_dependency_name) | 36 | default_component_dependency_name) |
395 | @@ -214,3 +219,41 @@ | |||
396 | 214 | def _handleStatus_GIVENBACK(self, librarian, slave_status, logger): | 219 | def _handleStatus_GIVENBACK(self, librarian, slave_status, logger): |
397 | 215 | return BuildBase._handleStatus_GIVENBACK( | 220 | return BuildBase._handleStatus_GIVENBACK( |
398 | 216 | self, librarian, slave_status, logger) | 221 | self, librarian, slave_status, logger) |
399 | 222 | |||
400 | 223 | |||
401 | 224 | class PackageBuildSet: | ||
402 | 225 | implements(IPackageBuildSet) | ||
403 | 226 | |||
404 | 227 | def getBuildsForArchive(self, archive, status=None, pocket=None): | ||
405 | 228 | """See `IPackageBuildSet`.""" | ||
406 | 229 | |||
407 | 230 | extra_exprs = [] | ||
408 | 231 | |||
409 | 232 | if status is not None: | ||
410 | 233 | extra_exprs.append(BuildFarmJob.status == status) | ||
411 | 234 | |||
412 | 235 | if pocket: | ||
413 | 236 | extra_exprs.append(PackageBuild.pocket == pocket) | ||
414 | 237 | |||
415 | 238 | store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) | ||
416 | 239 | result_set = store.find(PackageBuild, | ||
417 | 240 | PackageBuild.archive == archive, | ||
418 | 241 | PackageBuild.build_farm_job == BuildFarmJob.id, | ||
419 | 242 | *extra_exprs) | ||
420 | 243 | |||
421 | 244 | # When we have a set of builds that may include pending or | ||
422 | 245 | # superseded builds, we order by -date_created (as we won't | ||
423 | 246 | # always have a date_finished). Otherwise we can order by | ||
424 | 247 | # -date_finished. | ||
425 | 248 | unfinished_states = [ | ||
426 | 249 | BuildStatus.NEEDSBUILD, | ||
427 | 250 | BuildStatus.BUILDING, | ||
428 | 251 | BuildStatus.SUPERSEDED] | ||
429 | 252 | if status is None or status in unfinished_states: | ||
430 | 253 | result_set.order_by( | ||
431 | 254 | Desc(BuildFarmJob.date_created), BuildFarmJob.id) | ||
432 | 255 | else: | ||
433 | 256 | result_set.order_by( | ||
434 | 257 | Desc(BuildFarmJob.date_finished), BuildFarmJob.id) | ||
435 | 258 | |||
436 | 259 | return result_set | ||
437 | 217 | 260 | ||
438 | === modified file 'lib/lp/buildmaster/tests/test_packagebuild.py' | |||
439 | --- lib/lp/buildmaster/tests/test_packagebuild.py 2010-05-21 12:48:44 +0000 | |||
440 | +++ lib/lp/buildmaster/tests/test_packagebuild.py 2010-06-16 14:06:25 +0000 | |||
441 | @@ -15,9 +15,10 @@ | |||
442 | 15 | 15 | ||
443 | 16 | from canonical.testing.layers import LaunchpadFunctionalLayer | 16 | from canonical.testing.layers import LaunchpadFunctionalLayer |
444 | 17 | 17 | ||
445 | 18 | from lp.buildmaster.interfaces.buildbase import BuildStatus | ||
446 | 18 | from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType | 19 | from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType |
447 | 19 | from lp.buildmaster.interfaces.packagebuild import ( | 20 | from lp.buildmaster.interfaces.packagebuild import ( |
449 | 20 | IPackageBuild, IPackageBuildSource) | 21 | IPackageBuild, IPackageBuildSet, IPackageBuildSource) |
450 | 21 | from lp.buildmaster.model.packagebuild import PackageBuild | 22 | from lp.buildmaster.model.packagebuild import PackageBuild |
451 | 22 | from lp.buildmaster.tests.test_buildbase import TestBuildBaseMixin | 23 | from lp.buildmaster.tests.test_buildbase import TestBuildBaseMixin |
452 | 23 | from lp.registry.interfaces.pocket import PackagePublishingPocket | 24 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
453 | @@ -31,15 +32,16 @@ | |||
454 | 31 | only classes deriving from PackageBuild should be used. | 32 | only classes deriving from PackageBuild should be used. |
455 | 32 | """ | 33 | """ |
456 | 33 | 34 | ||
458 | 34 | def makePackageBuild(self, archive=None): | 35 | def makePackageBuild( |
459 | 36 | self, archive=None, job_type=BuildFarmJobType.PACKAGEBUILD, | ||
460 | 37 | status=BuildStatus.NEEDSBUILD, | ||
461 | 38 | pocket=PackagePublishingPocket.RELEASE): | ||
462 | 35 | if archive is None: | 39 | if archive is None: |
463 | 36 | archive = self.factory.makeArchive() | 40 | archive = self.factory.makeArchive() |
464 | 37 | 41 | ||
465 | 38 | return getUtility(IPackageBuildSource).new( | 42 | return getUtility(IPackageBuildSource).new( |
470 | 39 | job_type=BuildFarmJobType.PACKAGEBUILD, | 43 | job_type=job_type, virtualized=True, archive=archive, |
471 | 40 | virtualized=True, | 44 | status=status, pocket=pocket) |
468 | 41 | archive=archive, | ||
469 | 42 | pocket=PackagePublishingPocket.RELEASE) | ||
472 | 43 | 45 | ||
473 | 44 | 46 | ||
474 | 45 | class TestBuildBaseMethods(TestPackageBuildBase, TestBuildBaseMixin): | 47 | class TestBuildBaseMethods(TestPackageBuildBase, TestBuildBaseMixin): |
475 | @@ -176,5 +178,46 @@ | |||
476 | 176 | u'My deps', self.package_build.dependencies) | 178 | u'My deps', self.package_build.dependencies) |
477 | 177 | 179 | ||
478 | 178 | 180 | ||
479 | 181 | class TestPackageBuildSet(TestPackageBuildBase): | ||
480 | 182 | |||
481 | 183 | layer = LaunchpadFunctionalLayer | ||
482 | 184 | |||
483 | 185 | def setUp(self): | ||
484 | 186 | super(TestPackageBuildSet, self).setUp() | ||
485 | 187 | person = self.factory.makePerson() | ||
486 | 188 | self.archive = self.factory.makeArchive(owner=person) | ||
487 | 189 | self.package_builds = [] | ||
488 | 190 | self.package_builds.append( | ||
489 | 191 | self.makePackageBuild(archive=self.archive, | ||
490 | 192 | pocket=PackagePublishingPocket.UPDATES)) | ||
491 | 193 | self.package_builds.append( | ||
492 | 194 | self.makePackageBuild(archive=self.archive, | ||
493 | 195 | status=BuildStatus.BUILDING)) | ||
494 | 196 | self.package_build_set = getUtility(IPackageBuildSet) | ||
495 | 197 | |||
496 | 198 | def test_getBuildsForArchive_all(self): | ||
497 | 199 | # The default call without arguments returns all builds for the | ||
498 | 200 | # archive. | ||
499 | 201 | self.assertContentEqual( | ||
500 | 202 | self.package_builds, self.package_build_set.getBuildsForArchive( | ||
501 | 203 | self.archive)) | ||
502 | 204 | |||
503 | 205 | def test_getBuildsForArchive_by_status(self): | ||
504 | 206 | # If the status arg is used, the results will be filtered by | ||
505 | 207 | # status. | ||
506 | 208 | self.assertContentEqual( | ||
507 | 209 | self.package_builds[1:], | ||
508 | 210 | self.package_build_set.getBuildsForArchive( | ||
509 | 211 | self.archive, status=BuildStatus.BUILDING)) | ||
510 | 212 | |||
511 | 213 | def test_getBuildsForArchive_by_pocket(self): | ||
512 | 214 | # If the pocket arg is used, the results will be filtered by | ||
513 | 215 | # pocket. | ||
514 | 216 | self.assertContentEqual( | ||
515 | 217 | self.package_builds[:1], | ||
516 | 218 | self.package_build_set.getBuildsForArchive( | ||
517 | 219 | self.archive, pocket=PackagePublishingPocket.UPDATES)) | ||
518 | 220 | |||
519 | 221 | |||
520 | 179 | def test_suite(): | 222 | def test_suite(): |
521 | 180 | return unittest.TestLoader().loadTestsFromName(__name__) | 223 | return unittest.TestLoader().loadTestsFromName(__name__) |
522 | 181 | 224 | ||
523 | === modified file 'lib/lp/code/browser/sourcepackagerecipe.py' | |||
524 | --- lib/lp/code/browser/sourcepackagerecipe.py 2010-06-12 13:39:48 +0000 | |||
525 | +++ lib/lp/code/browser/sourcepackagerecipe.py 2010-06-16 14:06:25 +0000 | |||
526 | @@ -37,9 +37,11 @@ | |||
527 | 37 | LaunchpadView, Link, Navigation, NavigationMenu, stepthrough) | 37 | LaunchpadView, Link, Navigation, NavigationMenu, stepthrough) |
528 | 38 | from canonical.launchpad.webapp.authorization import check_permission | 38 | from canonical.launchpad.webapp.authorization import check_permission |
529 | 39 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb | 39 | from canonical.launchpad.webapp.breadcrumb import Breadcrumb |
530 | 40 | from canonical.launchpad.webapp.sorting import sorted_dotted_numbers | ||
531 | 40 | from canonical.widgets.itemswidgets import LabeledMultiCheckBoxWidget | 41 | from canonical.widgets.itemswidgets import LabeledMultiCheckBoxWidget |
532 | 41 | from lp.buildmaster.interfaces.buildbase import BuildStatus | 42 | from lp.buildmaster.interfaces.buildbase import BuildStatus |
533 | 42 | from lp.code.errors import ForbiddenInstruction | 43 | from lp.code.errors import ForbiddenInstruction |
534 | 44 | from lp.code.interfaces.branch import NoSuchBranch | ||
535 | 43 | from lp.code.interfaces.sourcepackagerecipe import ( | 45 | from lp.code.interfaces.sourcepackagerecipe import ( |
536 | 44 | ISourcePackageRecipe, ISourcePackageRecipeSource, MINIMAL_RECIPE_TEXT) | 46 | ISourcePackageRecipe, ISourcePackageRecipeSource, MINIMAL_RECIPE_TEXT) |
537 | 45 | from lp.code.interfaces.sourcepackagerecipebuild import ( | 47 | from lp.code.interfaces.sourcepackagerecipebuild import ( |
538 | @@ -170,9 +172,12 @@ | |||
539 | 170 | ppas = getUtility(IArchiveSet).getPPAsForUser(getUtility(ILaunchBag).user) | 172 | ppas = getUtility(IArchiveSet).getPPAsForUser(getUtility(ILaunchBag).user) |
540 | 171 | supported_distros = [ppa.distribution for ppa in ppas] | 173 | supported_distros = [ppa.distribution for ppa in ppas] |
541 | 172 | dsset = getUtility(IDistroSeriesSet).search() | 174 | dsset = getUtility(IDistroSeriesSet).search() |
545 | 173 | terms = [SimpleTerm(distro, distro.id, distro.displayname) | 175 | terms = sorted_dotted_numbers( |
546 | 174 | for distro in dsset if ( | 176 | [SimpleTerm(distro, distro.id, distro.displayname) |
547 | 175 | distro.active and distro.distribution in supported_distros)] | 177 | for distro in dsset if ( |
548 | 178 | distro.active and distro.distribution in supported_distros)], | ||
549 | 179 | key=lambda term: term.value.version) | ||
550 | 180 | terms.reverse() | ||
551 | 176 | return SimpleVocabulary(terms) | 181 | return SimpleVocabulary(terms) |
552 | 177 | 182 | ||
553 | 178 | def target_ppas_vocabulary(context): | 183 | def target_ppas_vocabulary(context): |
554 | @@ -375,6 +380,10 @@ | |||
555 | 375 | 'recipe_text', | 380 | 'recipe_text', |
556 | 376 | 'The bzr-builder instruction "run" is not permitted here.') | 381 | 'The bzr-builder instruction "run" is not permitted here.') |
557 | 377 | return | 382 | return |
558 | 383 | except NoSuchBranch, e: | ||
559 | 384 | self.setFieldError( | ||
560 | 385 | 'recipe_text', '%s is not a branch on Launchpad.' % e.name) | ||
561 | 386 | return | ||
562 | 378 | 387 | ||
563 | 379 | self.next_url = canonical_url(source_package_recipe) | 388 | self.next_url = canonical_url(source_package_recipe) |
564 | 380 | 389 | ||
565 | 381 | 390 | ||
566 | === modified file 'lib/lp/code/browser/tests/test_sourcepackagerecipe.py' | |||
567 | --- lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-06-14 20:14:15 +0000 | |||
568 | +++ lib/lp/code/browser/tests/test_sourcepackagerecipe.py 2010-06-16 14:06:25 +0000 | |||
569 | @@ -42,7 +42,7 @@ | |||
570 | 42 | self.ppa = self.factory.makeArchive( | 42 | self.ppa = self.factory.makeArchive( |
571 | 43 | displayname='Secret PPA', owner=self.chef, name='ppa') | 43 | displayname='Secret PPA', owner=self.chef, name='ppa') |
572 | 44 | self.squirrel = self.factory.makeDistroSeries( | 44 | self.squirrel = self.factory.makeDistroSeries( |
574 | 45 | displayname='Secret Squirrel', name='secret', | 45 | displayname='Secret Squirrel', name='secret', version='100.04', |
575 | 46 | distribution=self.ppa.distribution) | 46 | distribution=self.ppa.distribution) |
576 | 47 | self.squirrel.nominatedarchindep = self.squirrel.newArch( | 47 | self.squirrel.nominatedarchindep = self.squirrel.newArch( |
577 | 48 | 'i386', ProcessorFamily.get(1), False, self.chef, | 48 | 'i386', ProcessorFamily.get(1), False, self.chef, |
578 | @@ -65,6 +65,12 @@ | |||
579 | 65 | return extract_text(find_main_content(browser.contents)) | 65 | return extract_text(find_main_content(browser.contents)) |
580 | 66 | 66 | ||
581 | 67 | 67 | ||
582 | 68 | def get_message_text(browser, index): | ||
583 | 69 | """Return the text of a message, specified by index.""" | ||
584 | 70 | tags = find_tags_by_class(browser.contents, 'message')[index] | ||
585 | 71 | return extract_text(tags) | ||
586 | 72 | |||
587 | 73 | |||
588 | 68 | class TestSourcePackageRecipeAddView(TestCaseForRecipe): | 74 | class TestSourcePackageRecipeAddView(TestCaseForRecipe): |
589 | 69 | 75 | ||
590 | 70 | layer = DatabaseFunctionalLayer | 76 | layer = DatabaseFunctionalLayer |
591 | @@ -149,7 +155,7 @@ | |||
592 | 149 | browser.getControl('Create Recipe').click() | 155 | browser.getControl('Create Recipe').click() |
593 | 150 | 156 | ||
594 | 151 | self.assertEqual( | 157 | self.assertEqual( |
596 | 152 | extract_text(find_tags_by_class(browser.contents, 'message')[1]), | 158 | get_message_text(browser, 1), |
597 | 153 | 'The bzr-builder instruction "run" is not permitted here.') | 159 | 'The bzr-builder instruction "run" is not permitted here.') |
598 | 154 | 160 | ||
599 | 155 | def test_create_new_recipe_empty_name(self): | 161 | def test_create_new_recipe_empty_name(self): |
600 | @@ -169,12 +175,29 @@ | |||
601 | 169 | browser.getControl('Create Recipe').click() | 175 | browser.getControl('Create Recipe').click() |
602 | 170 | 176 | ||
603 | 171 | self.assertEqual( | 177 | self.assertEqual( |
606 | 172 | extract_text(find_tags_by_class(browser.contents, 'message')[1]), | 178 | get_message_text(browser, 1), 'Required input is missing.') |
607 | 173 | 'Required input is missing.') | 179 | |
608 | 180 | def createRecipe(self, recipe_text, branch=None): | ||
609 | 181 | if branch is None: | ||
610 | 182 | product = self.factory.makeProduct( | ||
611 | 183 | name='ratatouille', displayname='Ratatouille') | ||
612 | 184 | branch = self.factory.makeBranch( | ||
613 | 185 | owner=self.chef, product=product, name='veggies') | ||
614 | 186 | |||
615 | 187 | # A new recipe can be created from the branch page. | ||
616 | 188 | browser = self.getUserBrowser(canonical_url(branch), user=self.chef) | ||
617 | 189 | browser.getLink('Create packaging recipe').click() | ||
618 | 190 | |||
619 | 191 | browser.getControl(name='field.name').value = 'daily' | ||
620 | 192 | browser.getControl('Description').value = 'Make some food!' | ||
621 | 193 | browser.getControl('Recipe text').value = recipe_text | ||
622 | 194 | browser.getControl('Create Recipe').click() | ||
623 | 195 | return browser | ||
624 | 174 | 196 | ||
625 | 175 | def test_create_recipe_bad_text(self): | 197 | def test_create_recipe_bad_text(self): |
626 | 176 | # If a user tries to create source package recipe with bad text, they | 198 | # If a user tries to create source package recipe with bad text, they |
627 | 177 | # should get an error. | 199 | # should get an error. |
628 | 200 | <<<<<<< TREE | ||
629 | 178 | branch = self.makeBranch() | 201 | branch = self.makeBranch() |
630 | 179 | 202 | ||
631 | 180 | # A new recipe can be created from the branch page. | 203 | # A new recipe can be created from the branch page. |
632 | @@ -186,10 +209,14 @@ | |||
633 | 186 | browser.getControl('Recipe text').value = 'Foo bar baz' | 209 | browser.getControl('Recipe text').value = 'Foo bar baz' |
634 | 187 | browser.getControl('Create Recipe').click() | 210 | browser.getControl('Create Recipe').click() |
635 | 188 | 211 | ||
636 | 212 | ======= | ||
637 | 213 | browser = self.createRecipe('Foo bar baz') | ||
638 | 214 | >>>>>>> MERGE-SOURCE | ||
639 | 189 | self.assertEqual( | 215 | self.assertEqual( |
641 | 190 | extract_text(find_tags_by_class(browser.contents, 'message')[1]), | 216 | get_message_text(browser, 1), |
642 | 191 | 'The recipe text is not a valid bzr-builder recipe.') | 217 | 'The recipe text is not a valid bzr-builder recipe.') |
643 | 192 | 218 | ||
644 | 219 | <<<<<<< TREE | ||
645 | 193 | def test_create_recipe_no_distroseries(self): | 220 | def test_create_recipe_no_distroseries(self): |
646 | 194 | browser = self.getViewBrowser(self.makeBranch(), '+new-recipe') | 221 | browser = self.getViewBrowser(self.makeBranch(), '+new-recipe') |
647 | 195 | browser.getControl(name='field.name').value = 'daily' | 222 | browser.getControl(name='field.name').value = 'daily' |
648 | @@ -201,6 +228,28 @@ | |||
649 | 201 | extract_text(find_tags_by_class(browser.contents, 'message')[1]), | 228 | extract_text(find_tags_by_class(browser.contents, 'message')[1]), |
650 | 202 | 'You must specify at least one series for daily builds.') | 229 | 'You must specify at least one series for daily builds.') |
651 | 203 | 230 | ||
652 | 231 | ======= | ||
653 | 232 | def test_create_recipe_bad_base_branch(self): | ||
654 | 233 | # If a user tries to create source package recipe with a bad base | ||
655 | 234 | # branch location, they should get an error. | ||
656 | 235 | browser = self.createRecipe(MINIMAL_RECIPE_TEXT % 'foo') | ||
657 | 236 | self.assertEqual( | ||
658 | 237 | get_message_text(browser, 1), 'foo is not a branch on Launchpad.') | ||
659 | 238 | |||
660 | 239 | def test_create_recipe_bad_instruction_branch(self): | ||
661 | 240 | # If a user tries to create source package recipe with a bad | ||
662 | 241 | # instruction branch location, they should get an error. | ||
663 | 242 | product = self.factory.makeProduct( | ||
664 | 243 | name='ratatouille', displayname='Ratatouille') | ||
665 | 244 | branch = self.factory.makeBranch( | ||
666 | 245 | owner=self.chef, product=product, name='veggies') | ||
667 | 246 | recipe = MINIMAL_RECIPE_TEXT % branch.bzr_identity | ||
668 | 247 | recipe += 'nest packaging foo debian' | ||
669 | 248 | browser = self.createRecipe(recipe, branch) | ||
670 | 249 | self.assertEqual( | ||
671 | 250 | get_message_text(browser, 1), 'foo is not a branch on Launchpad.') | ||
672 | 251 | |||
673 | 252 | >>>>>>> MERGE-SOURCE | ||
674 | 204 | def test_create_dupe_recipe(self): | 253 | def test_create_dupe_recipe(self): |
675 | 205 | # You shouldn't be able to create a duplicate recipe owned by the same | 254 | # You shouldn't be able to create a duplicate recipe owned by the same |
676 | 206 | # person with the same name. | 255 | # person with the same name. |
677 | @@ -221,7 +270,7 @@ | |||
678 | 221 | browser.getControl('Create Recipe').click() | 270 | browser.getControl('Create Recipe').click() |
679 | 222 | 271 | ||
680 | 223 | self.assertEqual( | 272 | self.assertEqual( |
682 | 224 | extract_text(find_tags_by_class(browser.contents, 'message')[1]), | 273 | get_message_text(browser, 1), |
683 | 225 | 'There is already a recipe owned by Master Chef with this name.') | 274 | 'There is already a recipe owned by Master Chef with this name.') |
684 | 226 | 275 | ||
685 | 227 | 276 | ||
686 | @@ -516,8 +565,8 @@ | |||
687 | 516 | Secret PPA (chef/ppa) | 565 | Secret PPA (chef/ppa) |
688 | 517 | Distribution series: | 566 | Distribution series: |
689 | 518 | Secret Squirrel | 567 | Secret Squirrel |
690 | 568 | Hoary | ||
691 | 519 | Warty | 569 | Warty |
692 | 520 | Hoary | ||
693 | 521 | or | 570 | or |
694 | 522 | Cancel""") | 571 | Cancel""") |
695 | 523 | main_text = self.getMainText(recipe, '+request-builds') | 572 | main_text = self.getMainText(recipe, '+request-builds') |
696 | 524 | 573 | ||
697 | === modified file 'lib/lp/code/model/sourcepackagerecipedata.py' | |||
698 | --- lib/lp/code/model/sourcepackagerecipedata.py 2010-06-11 04:28:38 +0000 | |||
699 | +++ lib/lp/code/model/sourcepackagerecipedata.py 2010-06-16 14:06:25 +0000 | |||
700 | @@ -211,6 +211,8 @@ | |||
701 | 211 | line_number += 1 | 211 | line_number += 1 |
702 | 212 | comment = None | 212 | comment = None |
703 | 213 | db_branch = branch_map[instruction.recipe_branch.url] | 213 | db_branch = branch_map[instruction.recipe_branch.url] |
704 | 214 | if db_branch is None: | ||
705 | 215 | raise NoSuchBranch(instruction.recipe_branch.url) | ||
706 | 214 | insn = _SourcePackageRecipeDataInstruction( | 216 | insn = _SourcePackageRecipeDataInstruction( |
707 | 215 | instruction.recipe_branch.name, type, comment, | 217 | instruction.recipe_branch.name, type, comment, |
708 | 216 | line_number, db_branch, instruction.recipe_branch.revspec, | 218 | line_number, db_branch, instruction.recipe_branch.revspec, |
709 | 217 | 219 | ||
710 | === modified file 'lib/lp/registry/doc/product-widgets.txt' | |||
711 | --- lib/lp/registry/doc/product-widgets.txt 2009-08-13 19:36:01 +0000 | |||
712 | +++ lib/lp/registry/doc/product-widgets.txt 2010-06-16 14:06:25 +0000 | |||
713 | @@ -216,7 +216,6 @@ | |||
714 | 216 | 216 | ||
715 | 217 | A custom widget is used to display a link to the license policy. | 217 | A custom widget is used to display a link to the license policy. |
716 | 218 | 218 | ||
717 | 219 | >>> from canonical.launchpad.interfaces import License | ||
718 | 220 | >>> from canonical.widgets.product import LicenseWidget | 219 | >>> from canonical.widgets.product import LicenseWidget |
719 | 221 | 220 | ||
720 | 222 | >>> form = {'field.licenses': []} | 221 | >>> form = {'field.licenses': []} |
721 | @@ -414,7 +413,7 @@ | |||
722 | 414 | >>> print_checked_items(license_widget(), links=True) | 413 | >>> print_checked_items(license_widget(), links=True) |
723 | 415 | [ ] Apache License ... <http://www.opensource.org/licenses/apache2.0.php> | 414 | [ ] Apache License ... <http://www.opensource.org/licenses/apache2.0.php> |
724 | 416 | [ ] GNU LGPL v2.1 ... <http://www.opensource.org/licenses/lgpl-2.1.php> | 415 | [ ] GNU LGPL v2.1 ... <http://www.opensource.org/licenses/lgpl-2.1.php> |
726 | 417 | [ ] GNU Affero GPL v3 ... <http://www.opensource.org/licenses/agpl-v3.html> | 416 | [ ] GNU Affero GPL v3 ... <http://www.opensource.org/licenses/agpl-v3...> |
727 | 418 | ... | 417 | ... |
728 | 419 | 418 | ||
729 | 420 | But not all of them. | 419 | But not all of them. |
730 | @@ -425,3 +424,47 @@ | |||
731 | 425 | [ ] I don't know yet | 424 | [ ] I don't know yet |
732 | 426 | [ ] Other/Proprietary | 425 | [ ] Other/Proprietary |
733 | 427 | [ ] Other/Open Source | 426 | [ ] Other/Open Source |
734 | 427 | |||
735 | 428 | |||
736 | 429 | GhostWidget | ||
737 | 430 | ----------- | ||
738 | 431 | |||
739 | 432 | The GhostWidget is used to suppress the markup of a field in cases where | ||
740 | 433 | another mechanism is used to insert the field's markup into the page. Some | ||
741 | 434 | widget for example generate the markup for subordinate fields, but they | ||
742 | 435 | do not manage the field itself. The LicenseWidget widget for example | ||
743 | 436 | generates the markup for the license_info field; the view must use a | ||
744 | 437 | GhostWidget to suppress the markup. | ||
745 | 438 | |||
746 | 439 | >>> from canonical.widgets.product import GhostWidget | ||
747 | 440 | |||
748 | 441 | >>> license_info = IProduct['license_info'].bind(firefox) | ||
749 | 442 | >>> ghost_widget = GhostWidget(license_info, LaunchpadTestRequest()) | ||
750 | 443 | >>> ghost_widget.visible | ||
751 | 444 | False | ||
752 | 445 | >>> ghost_widget.hidden() | ||
753 | 446 | '' | ||
754 | 447 | >>> ghost_widget() | ||
755 | 448 | '' | ||
756 | 449 | |||
757 | 450 | Launchpad form macros do not generate table rows for the GhostWidget. | ||
758 | 451 | |||
759 | 452 | >>> from z3c.ptcompat import ViewPageTemplateFile | ||
760 | 453 | >>> from canonical.config import config | ||
761 | 454 | >>> from canonical.launchpad.webapp.launchpadform import ( | ||
762 | 455 | ... custom_widget, LaunchpadFormView) | ||
763 | 456 | |||
764 | 457 | >>> class GhostWidgetView(LaunchpadFormView): | ||
765 | 458 | ... page_title = 'Test' | ||
766 | 459 | ... template = ViewPageTemplateFile( | ||
767 | 460 | ... config.root + '/lib/lp/app/templates/generic-edit.pt') | ||
768 | 461 | ... schema = IProduct | ||
769 | 462 | ... field_names = ['license_info'] | ||
770 | 463 | ... custom_widget('license_info', GhostWidget) | ||
771 | 464 | |||
772 | 465 | >>> request = LaunchpadTestRequest() | ||
773 | 466 | >>> request.setPrincipal(factory.makePerson()) | ||
774 | 467 | >>> view = GhostWidgetView(firefox, request) | ||
775 | 468 | >>> view.initialize() | ||
776 | 469 | >>> extract_text(find_tag_by_id(view.render(), 'launchpad-form-widgets')) | ||
777 | 470 | u'' | ||
778 | 428 | 471 | ||
779 | === modified file 'lib/lp/registry/model/sourcepackage.py' | |||
780 | --- lib/lp/registry/model/sourcepackage.py 2010-06-09 08:26:26 +0000 | |||
781 | +++ lib/lp/registry/model/sourcepackage.py 2010-06-16 14:06:25 +0000 | |||
782 | @@ -508,15 +508,17 @@ | |||
783 | 508 | return not self.__eq__(other) | 508 | return not self.__eq__(other) |
784 | 509 | 509 | ||
785 | 510 | def getBuildRecords(self, build_state=None, name=None, pocket=None, | 510 | def getBuildRecords(self, build_state=None, name=None, pocket=None, |
787 | 511 | arch_tag=None, user=None): | 511 | arch_tag=None, user=None, binary_only=True): |
788 | 512 | """See `IHasBuildRecords`""" | ||
789 | 512 | # Ignore "user", since it would not make any difference to the | 513 | # Ignore "user", since it would not make any difference to the |
790 | 513 | # records returned here (private builds are only in PPA right | 514 | # records returned here (private builds are only in PPA right |
791 | 514 | # now and this method only returns records for SPRs in a | 515 | # now and this method only returns records for SPRs in a |
792 | 515 | # distribution). | 516 | # distribution). |
793 | 516 | # We also ignore the name parameter (required as part of the | 517 | # We also ignore the name parameter (required as part of the |
795 | 517 | # IHasBuildRecords interface) and use our own name. | 518 | # IHasBuildRecords interface) and use our own name and the |
796 | 519 | # binary_only parameter as a source package can only have | ||
797 | 520 | # binary builds. | ||
798 | 518 | 521 | ||
799 | 519 | """See `IHasBuildRecords`""" | ||
800 | 520 | clauseTables = ['SourcePackageRelease', | 522 | clauseTables = ['SourcePackageRelease', |
801 | 521 | 'SourcePackagePublishingHistory'] | 523 | 'SourcePackagePublishingHistory'] |
802 | 522 | 524 | ||
803 | 523 | 525 | ||
804 | === modified file 'lib/lp/soyuz/configure.zcml' | |||
805 | --- lib/lp/soyuz/configure.zcml 2010-06-14 15:58:46 +0000 | |||
806 | +++ lib/lp/soyuz/configure.zcml 2010-06-16 14:06:25 +0000 | |||
807 | @@ -515,6 +515,11 @@ | |||
808 | 515 | for="lp.soyuz.interfaces.binarypackagebuild.IBinaryPackageBuild" | 515 | for="lp.soyuz.interfaces.binarypackagebuild.IBinaryPackageBuild" |
809 | 516 | factory="lp.soyuz.browser.build.BuildBreadcrumb" | 516 | factory="lp.soyuz.browser.build.BuildBreadcrumb" |
810 | 517 | permission="zope.Public"/> | 517 | permission="zope.Public"/> |
811 | 518 | <adapter | ||
812 | 519 | provides="lp.soyuz.interfaces.binarypackagebuild.IBinaryPackageBuild" | ||
813 | 520 | for="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob" | ||
814 | 521 | factory="lp.soyuz.model.binarypackagebuild.get_binary_build_for_build_farm_job" | ||
815 | 522 | permission="zope.Public"/> | ||
816 | 518 | 523 | ||
817 | 519 | <!-- BinaryPackageBuildSet --> | 524 | <!-- BinaryPackageBuildSet --> |
818 | 520 | 525 | ||
819 | 521 | 526 | ||
820 | === modified file 'lib/lp/soyuz/interfaces/archive.py' | |||
821 | --- lib/lp/soyuz/interfaces/archive.py 2010-06-15 14:36:47 +0000 | |||
822 | +++ lib/lp/soyuz/interfaces/archive.py 2010-06-16 14:06:25 +0000 | |||
823 | @@ -29,6 +29,7 @@ | |||
824 | 29 | 'IArchivePublic', | 29 | 'IArchivePublic', |
825 | 30 | 'IArchiveSet', | 30 | 'IArchiveSet', |
826 | 31 | 'IDistributionArchive', | 31 | 'IDistributionArchive', |
827 | 32 | 'IncompatibleArguments', | ||
828 | 32 | 'InsufficientUploadRights', | 33 | 'InsufficientUploadRights', |
829 | 33 | 'InvalidComponent', | 34 | 'InvalidComponent', |
830 | 34 | 'InvalidPocketForPartnerArchive', | 35 | 'InvalidPocketForPartnerArchive', |
831 | @@ -89,6 +90,11 @@ | |||
832 | 89 | webservice_error(400) #Bad request. | 90 | webservice_error(400) #Bad request. |
833 | 90 | 91 | ||
834 | 91 | 92 | ||
835 | 93 | class IncompatibleArguments(Exception): | ||
836 | 94 | """Raised when incompatible arguments are passed to a method.""" | ||
837 | 95 | webservice_error(400) # Bad request. | ||
838 | 96 | |||
839 | 97 | |||
840 | 92 | class CannotSwitchPrivacy(Exception): | 98 | class CannotSwitchPrivacy(Exception): |
841 | 93 | """Raised when switching the privacy of an archive that has | 99 | """Raised when switching the privacy of an archive that has |
842 | 94 | publishing records.""" | 100 | publishing records.""" |
843 | 95 | 101 | ||
844 | === modified file 'lib/lp/soyuz/interfaces/buildrecords.py' | |||
845 | --- lib/lp/soyuz/interfaces/buildrecords.py 2009-07-17 00:26:05 +0000 | |||
846 | +++ lib/lp/soyuz/interfaces/buildrecords.py 2010-06-16 14:06:25 +0000 | |||
847 | @@ -5,7 +5,7 @@ | |||
848 | 5 | 5 | ||
849 | 6 | """IHasBuildRecords interface. | 6 | """IHasBuildRecords interface. |
850 | 7 | 7 | ||
852 | 8 | Implemented by any object that can have `IBuild` records related to it. | 8 | Implemented by any object that can have `IPackageBuild` records related to it. |
853 | 9 | """ | 9 | """ |
854 | 10 | 10 | ||
855 | 11 | __metaclass__ = type | 11 | __metaclass__ = type |
856 | @@ -45,7 +45,7 @@ | |||
857 | 45 | @operation_returns_collection_of(Interface) | 45 | @operation_returns_collection_of(Interface) |
858 | 46 | @export_read_operation() | 46 | @export_read_operation() |
859 | 47 | def getBuildRecords(build_state=None, name=None, pocket=None, | 47 | def getBuildRecords(build_state=None, name=None, pocket=None, |
861 | 48 | arch_tag=None, user=None): | 48 | arch_tag=None, user=None, binary_only=True): |
862 | 49 | """Return build records in the context it is implemented. | 49 | """Return build records in the context it is implemented. |
863 | 50 | 50 | ||
864 | 51 | It excludes build records generated by Gina (imported from a external | 51 | It excludes build records generated by Gina (imported from a external |
865 | @@ -66,9 +66,14 @@ | |||
866 | 66 | :param user: optional `IPerson` corresponding to the user performing | 66 | :param user: optional `IPerson` corresponding to the user performing |
867 | 67 | the request. It will filter out build records for which the user | 67 | the request. It will filter out build records for which the user |
868 | 68 | have no 'view' permission. | 68 | have no 'view' permission. |
869 | 69 | :param binary_only: optional boolean indicating whether only | ||
870 | 70 | `BinaryPackageBuild` objects should be returned, or more general | ||
871 | 71 | `PackageBuild` objects (which may include, for example, | ||
872 | 72 | `SourcePackageRecipeBuild` objects. | ||
873 | 69 | 73 | ||
878 | 70 | :return: a result set containing `IBuild` records ordered by descending | 74 | :return: a result set containing `IPackageBuild` records ordered by |
879 | 71 | `IBuild.datebuilt` except when builds are filtered by | 75 | descending `IPackageBuild.date_finished` except when builds are |
880 | 72 | `BuildStatus.NEEDSBUILD`, in this case records are ordered by | 76 | filtered by `BuildStatus.NEEDSBUILD`, in this case records |
881 | 73 | descending `BuildQueue.lastscore` (dispatching order). | 77 | are ordered by descending `BuildQueue.lastscore` |
882 | 78 | (dispatching order). | ||
883 | 74 | """ | 79 | """ |
884 | 75 | 80 | ||
885 | === modified file 'lib/lp/soyuz/model/archive.py' | |||
886 | --- lib/lp/soyuz/model/archive.py 2010-06-14 12:19:10 +0000 | |||
887 | +++ lib/lp/soyuz/model/archive.py 2010-06-16 14:06:25 +0000 | |||
888 | @@ -34,6 +34,7 @@ | |||
889 | 34 | cursor, quote, quote_like, sqlvalues, SQLBase) | 34 | cursor, quote, quote_like, sqlvalues, SQLBase) |
890 | 35 | from canonical.launchpad.interfaces.lpstorm import ISlaveStore | 35 | from canonical.launchpad.interfaces.lpstorm import ISlaveStore |
891 | 36 | from lp.buildmaster.interfaces.buildbase import BuildStatus | 36 | from lp.buildmaster.interfaces.buildbase import BuildStatus |
892 | 37 | from lp.buildmaster.interfaces.packagebuild import IPackageBuildSet | ||
893 | 37 | from lp.buildmaster.model.buildfarmjob import BuildFarmJob | 38 | from lp.buildmaster.model.buildfarmjob import BuildFarmJob |
894 | 38 | from lp.buildmaster.model.packagebuild import PackageBuild | 39 | from lp.buildmaster.model.packagebuild import PackageBuild |
895 | 39 | from lp.services.job.interfaces.job import JobStatus | 40 | from lp.services.job.interfaces.job import JobStatus |
896 | @@ -65,7 +66,7 @@ | |||
897 | 65 | ArchiveNotPrivate, ArchivePurpose, ArchiveStatus, CannotCopy, | 66 | ArchiveNotPrivate, ArchivePurpose, ArchiveStatus, CannotCopy, |
898 | 66 | CannotSwitchPrivacy, CannotUploadToPPA, CannotUploadToPocket, | 67 | CannotSwitchPrivacy, CannotUploadToPPA, CannotUploadToPocket, |
899 | 67 | DistroSeriesNotFound, IArchive, IArchiveSet, IDistributionArchive, | 68 | DistroSeriesNotFound, IArchive, IArchiveSet, IDistributionArchive, |
901 | 68 | InsufficientUploadRights, InvalidPocketForPPA, | 69 | IncompatibleArguments, InsufficientUploadRights, InvalidPocketForPPA, |
902 | 69 | InvalidPocketForPartnerArchive, InvalidComponent, IPPA, | 70 | InvalidPocketForPartnerArchive, InvalidComponent, IPPA, |
903 | 70 | MAIN_ARCHIVE_PURPOSES, NoRightsForArchive, NoRightsForComponent, | 71 | MAIN_ARCHIVE_PURPOSES, NoRightsForArchive, NoRightsForComponent, |
904 | 71 | NoSuchPPA, NoTokensForTeams, PocketNotFound, VersionRequiresName, | 72 | NoSuchPPA, NoTokensForTeams, PocketNotFound, VersionRequiresName, |
905 | @@ -369,12 +370,21 @@ | |||
906 | 369 | return None | 370 | return None |
907 | 370 | 371 | ||
908 | 371 | def getBuildRecords(self, build_state=None, name=None, pocket=None, | 372 | def getBuildRecords(self, build_state=None, name=None, pocket=None, |
910 | 372 | arch_tag=None, user=None): | 373 | arch_tag=None, user=None, binary_only=True): |
911 | 373 | """See IHasBuildRecords""" | 374 | """See IHasBuildRecords""" |
912 | 374 | # Ignore "user", since anyone already accessing this archive | 375 | # Ignore "user", since anyone already accessing this archive |
913 | 375 | # will implicitly have permission to see it. | 376 | # will implicitly have permission to see it. |
916 | 376 | return getUtility(IBinaryPackageBuildSet).getBuildsForArchive( | 377 | |
917 | 377 | self, build_state, name, pocket, arch_tag) | 378 | if binary_only: |
918 | 379 | return getUtility(IBinaryPackageBuildSet).getBuildsForArchive( | ||
919 | 380 | self, build_state, name, pocket, arch_tag) | ||
920 | 381 | else: | ||
921 | 382 | if arch_tag is not None or name is not None: | ||
922 | 383 | raise IncompatibleArguments( | ||
923 | 384 | "The 'arch_tag' and 'name' parameters can be used only " | ||
924 | 385 | "with binary_only=True.") | ||
925 | 386 | return getUtility(IPackageBuildSet).getBuildsForArchive( | ||
926 | 387 | self, status=build_state, pocket=pocket) | ||
927 | 378 | 388 | ||
928 | 379 | def getPublishedSources(self, name=None, version=None, status=None, | 389 | def getPublishedSources(self, name=None, version=None, status=None, |
929 | 380 | distroseries=None, pocket=None, | 390 | distroseries=None, pocket=None, |
930 | 381 | 391 | ||
931 | === modified file 'lib/lp/soyuz/model/binarypackagebuild.py' | |||
932 | --- lib/lp/soyuz/model/binarypackagebuild.py 2010-06-09 12:13:53 +0000 | |||
933 | +++ lib/lp/soyuz/model/binarypackagebuild.py 2010-06-16 14:06:25 +0000 | |||
934 | @@ -65,6 +65,27 @@ | |||
935 | 65 | PackageUpload, PackageUploadBuild) | 65 | PackageUpload, PackageUploadBuild) |
936 | 66 | 66 | ||
937 | 67 | 67 | ||
938 | 68 | def get_binary_build_for_build_farm_job(build_farm_job): | ||
939 | 69 | """Factory method to returning a binary for a build farm job.""" | ||
940 | 70 | # No need to query the db if the build_farm_job doesn't have | ||
941 | 71 | # the correct job type. | ||
942 | 72 | if build_farm_job.job_type != BuildFarmJobType.PACKAGEBUILD: | ||
943 | 73 | return None | ||
944 | 74 | |||
945 | 75 | store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) | ||
946 | 76 | find_spec = (BinaryPackageBuild, PackageBuild, BuildFarmJob) | ||
947 | 77 | resulting_tuple = store.find( | ||
948 | 78 | find_spec, | ||
949 | 79 | BinaryPackageBuild.package_build == PackageBuild.id, | ||
950 | 80 | PackageBuild.build_farm_job == BuildFarmJob.id, | ||
951 | 81 | BuildFarmJob.id == build_farm_job.id).one() | ||
952 | 82 | |||
953 | 83 | if resulting_tuple is None: | ||
954 | 84 | return None | ||
955 | 85 | |||
956 | 86 | return resulting_tuple[0] | ||
957 | 87 | |||
958 | 88 | |||
959 | 68 | class BinaryPackageBuild(PackageBuildDerived, SQLBase): | 89 | class BinaryPackageBuild(PackageBuildDerived, SQLBase): |
960 | 69 | implements(IBinaryPackageBuild) | 90 | implements(IBinaryPackageBuild) |
961 | 70 | _table = 'BinaryPackageBuild' | 91 | _table = 'BinaryPackageBuild' |
962 | 71 | 92 | ||
963 | === modified file 'lib/lp/soyuz/tests/test_archive.py' | |||
964 | --- lib/lp/soyuz/tests/test_archive.py 2010-06-14 15:58:46 +0000 | |||
965 | +++ lib/lp/soyuz/tests/test_archive.py 2010-06-16 14:06:25 +0000 | |||
966 | @@ -240,7 +240,7 @@ | |||
967 | 240 | ubuntu_test = breezy_autotest.distribution | 240 | ubuntu_test = breezy_autotest.distribution |
968 | 241 | self.series = [breezy_autotest] | 241 | self.series = [breezy_autotest] |
969 | 242 | self.series.append(self.factory.makeDistroRelease( | 242 | self.series.append(self.factory.makeDistroRelease( |
971 | 243 | distribution=ubuntu_test, name="foo-series")) | 243 | distribution=ubuntu_test, name="foo-series", version='1.0')) |
972 | 244 | 244 | ||
973 | 245 | self.sources = [] | 245 | self.sources = [] |
974 | 246 | gedit_src_hist = self.publisher.getPubSource( | 246 | gedit_src_hist = self.publisher.getPubSource( |
975 | 247 | 247 | ||
976 | === modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py' | |||
977 | --- lib/lp/soyuz/tests/test_binarypackagebuild.py 2010-06-09 12:07:58 +0000 | |||
978 | +++ lib/lp/soyuz/tests/test_binarypackagebuild.py 2010-06-16 14:06:25 +0000 | |||
979 | @@ -15,6 +15,7 @@ | |||
980 | 15 | from canonical.testing import LaunchpadZopelessLayer | 15 | from canonical.testing import LaunchpadZopelessLayer |
981 | 16 | from lp.services.job.model.job import Job | 16 | from lp.services.job.model.job import Job |
982 | 17 | from lp.buildmaster.interfaces.buildbase import BuildStatus | 17 | from lp.buildmaster.interfaces.buildbase import BuildStatus |
983 | 18 | from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType | ||
984 | 18 | from lp.buildmaster.interfaces.builder import IBuilderSet | 19 | from lp.buildmaster.interfaces.builder import IBuilderSet |
985 | 19 | from lp.buildmaster.interfaces.buildqueue import IBuildQueue | 20 | from lp.buildmaster.interfaces.buildqueue import IBuildQueue |
986 | 20 | from lp.buildmaster.interfaces.packagebuild import IPackageBuild | 21 | from lp.buildmaster.interfaces.packagebuild import IPackageBuild |
987 | @@ -120,6 +121,42 @@ | |||
988 | 120 | self.build.build_farm_job.id), | 121 | self.build.build_farm_job.id), |
989 | 121 | self.build.log_url) | 122 | self.build.log_url) |
990 | 122 | 123 | ||
991 | 124 | def test_adapt_from_build_farm_job(self): | ||
992 | 125 | # An `IBuildFarmJob` can be adapted to an IBinaryPackageBuild | ||
993 | 126 | # if it has the correct job type. | ||
994 | 127 | build_farm_job = self.build.build_farm_job | ||
995 | 128 | store = Store.of(build_farm_job) | ||
996 | 129 | store.flush() | ||
997 | 130 | |||
998 | 131 | binary_package_build = IBinaryPackageBuild(build_farm_job) | ||
999 | 132 | self.failUnlessEqual(self.build, binary_package_build) | ||
1000 | 133 | |||
1001 | 134 | def test_adapt_from_build_farm_job_wrong_type(self): | ||
1002 | 135 | # An `IBuildFarmJob` of the wrong type results is None. | ||
1003 | 136 | build_farm_job = self.build.build_farm_job | ||
1004 | 137 | removeSecurityProxy(build_farm_job).job_type = ( | ||
1005 | 138 | BuildFarmJobType.RECIPEBRANCHBUILD) | ||
1006 | 139 | |||
1007 | 140 | binary_package_build = IBinaryPackageBuild(build_farm_job) | ||
1008 | 141 | self.failUnlessEqual(None, binary_package_build) | ||
1009 | 142 | |||
1010 | 143 | def test_adapt_from_build_farm_job_prefetching(self): | ||
1011 | 144 | # The package_build is prefetched for efficiency. | ||
1012 | 145 | build_farm_job = self.build.build_farm_job | ||
1013 | 146 | |||
1014 | 147 | # We clear the cache to avoid getting cached objects where | ||
1015 | 148 | # they would normally be queries. | ||
1016 | 149 | store = Store.of(build_farm_job) | ||
1017 | 150 | store.flush() | ||
1018 | 151 | store.reset() | ||
1019 | 152 | |||
1020 | 153 | binary_package_build = IBinaryPackageBuild(build_farm_job) | ||
1021 | 154 | |||
1022 | 155 | self.assertStatementCount( | ||
1023 | 156 | 0, getattr, binary_package_build, "package_build") | ||
1024 | 157 | self.assertStatementCount( | ||
1025 | 158 | 0, getattr, binary_package_build, "build_farm_job") | ||
1026 | 159 | |||
1027 | 123 | 160 | ||
1028 | 124 | class TestBuildUpdateDependencies(TestCaseWithFactory): | 161 | class TestBuildUpdateDependencies(TestCaseWithFactory): |
1029 | 125 | 162 | ||
1030 | 126 | 163 | ||
1031 | === modified file 'lib/lp/soyuz/tests/test_hasbuildrecords.py' | |||
1032 | --- lib/lp/soyuz/tests/test_hasbuildrecords.py 2010-05-06 10:35:17 +0000 | |||
1033 | +++ lib/lp/soyuz/tests/test_hasbuildrecords.py 2010-06-16 14:06:25 +0000 | |||
1034 | @@ -12,6 +12,11 @@ | |||
1035 | 12 | 12 | ||
1036 | 13 | from lp.registry.model.sourcepackage import SourcePackage | 13 | from lp.registry.model.sourcepackage import SourcePackage |
1037 | 14 | from lp.buildmaster.interfaces.builder import IBuilderSet | 14 | from lp.buildmaster.interfaces.builder import IBuilderSet |
1038 | 15 | from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType | ||
1039 | 16 | from lp.buildmaster.interfaces.packagebuild import ( | ||
1040 | 17 | IPackageBuildSource) | ||
1041 | 18 | from lp.registry.interfaces.pocket import PackagePublishingPocket | ||
1042 | 19 | from lp.soyuz.interfaces.archive import IncompatibleArguments | ||
1043 | 15 | from lp.soyuz.interfaces.buildrecords import IHasBuildRecords | 20 | from lp.soyuz.interfaces.buildrecords import IHasBuildRecords |
1044 | 16 | from lp.soyuz.model.processor import ProcessorFamilySet | 21 | from lp.soyuz.model.processor import ProcessorFamilySet |
1045 | 17 | from lp.soyuz.tests.test_binarypackagebuild import ( | 22 | from lp.soyuz.tests.test_binarypackagebuild import ( |
1046 | @@ -81,6 +86,32 @@ | |||
1047 | 81 | 86 | ||
1048 | 82 | self.context = self.publisher.distroseries.main_archive | 87 | self.context = self.publisher.distroseries.main_archive |
1049 | 83 | 88 | ||
1050 | 89 | def test_binary_only_false(self): | ||
1051 | 90 | # An archive can optionally return the more general | ||
1052 | 91 | # package build objects. | ||
1053 | 92 | |||
1054 | 93 | # Until we have different IBuildFarmJob types implemented, we | ||
1055 | 94 | # can only test this by creating a lone PackageBuild of a | ||
1056 | 95 | # different type. | ||
1057 | 96 | getUtility(IPackageBuildSource).new( | ||
1058 | 97 | job_type=BuildFarmJobType.RECIPEBRANCHBUILD, virtualized=True, | ||
1059 | 98 | archive=self.context, pocket=PackagePublishingPocket.RELEASE) | ||
1060 | 99 | |||
1061 | 100 | builds = self.context.getBuildRecords(binary_only=True) | ||
1062 | 101 | self.failUnlessEqual(3, builds.count()) | ||
1063 | 102 | |||
1064 | 103 | builds = self.context.getBuildRecords(binary_only=False) | ||
1065 | 104 | self.failUnlessEqual(4, builds.count()) | ||
1066 | 105 | |||
1067 | 106 | def test_incompatible_arguments(self): | ||
1068 | 107 | # binary_only=False is incompatible with arch_tag and name. | ||
1069 | 108 | self.failUnlessRaises( | ||
1070 | 109 | IncompatibleArguments, self.context.getBuildRecords, | ||
1071 | 110 | binary_only=False, arch_tag="anything") | ||
1072 | 111 | self.failUnlessRaises( | ||
1073 | 112 | IncompatibleArguments, self.context.getBuildRecords, | ||
1074 | 113 | binary_only=False, name="anything") | ||
1075 | 114 | |||
1076 | 84 | 115 | ||
1077 | 85 | class TestBuilderHasBuildRecords(TestHasBuildRecordsInterface): | 116 | class TestBuilderHasBuildRecords(TestHasBuildRecordsInterface): |
1078 | 86 | """Test the Builder implementation of IHasBuildRecords.""" | 117 | """Test the Builder implementation of IHasBuildRecords.""" |
1079 | 87 | 118 | ||
1080 | === modified file 'lib/lp/testing/factory.py' | |||
1081 | --- lib/lp/testing/factory.py 2010-06-13 05:56:31 +0000 | |||
1082 | +++ lib/lp/testing/factory.py 2010-06-16 14:06:25 +0000 | |||
1083 | @@ -22,8 +22,10 @@ | |||
1084 | 22 | from email.mime.text import MIMEText | 22 | from email.mime.text import MIMEText |
1085 | 23 | from email.mime.multipart import MIMEMultipart | 23 | from email.mime.multipart import MIMEMultipart |
1086 | 24 | from itertools import count | 24 | from itertools import count |
1087 | 25 | import os.path | ||
1088 | 26 | from random import randint | ||
1089 | 25 | from StringIO import StringIO | 27 | from StringIO import StringIO |
1091 | 26 | import os.path | 28 | from threading import local |
1092 | 27 | 29 | ||
1093 | 28 | import pytz | 30 | import pytz |
1094 | 29 | 31 | ||
1095 | @@ -56,7 +58,6 @@ | |||
1096 | 56 | from canonical.launchpad.webapp.dbpolicy import MasterDatabasePolicy | 58 | from canonical.launchpad.webapp.dbpolicy import MasterDatabasePolicy |
1097 | 57 | from canonical.launchpad.webapp.interfaces import ( | 59 | from canonical.launchpad.webapp.interfaces import ( |
1098 | 58 | IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR) | 60 | IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR) |
1099 | 59 | from canonical.uuid import generate_uuid | ||
1100 | 60 | 61 | ||
1101 | 61 | from lp.blueprints.interfaces.specification import ( | 62 | from lp.blueprints.interfaces.specification import ( |
1102 | 62 | ISpecificationSet, SpecificationDefinitionStatus) | 63 | ISpecificationSet, SpecificationDefinitionStatus) |
1103 | @@ -213,14 +214,22 @@ | |||
1104 | 213 | 214 | ||
1105 | 214 | def __init__(self): | 215 | def __init__(self): |
1106 | 215 | # Initialise the unique identifier. | 216 | # Initialise the unique identifier. |
1108 | 216 | self._integer = count(1) | 217 | self._local = local() |
1109 | 217 | 218 | ||
1110 | 218 | def getUniqueEmailAddress(self): | 219 | def getUniqueEmailAddress(self): |
1111 | 219 | return "%s@example.com" % self.getUniqueString('email') | 220 | return "%s@example.com" % self.getUniqueString('email') |
1112 | 220 | 221 | ||
1113 | 221 | def getUniqueInteger(self): | 222 | def getUniqueInteger(self): |
1116 | 222 | """Return an integer unique to this factory instance.""" | 223 | """Return an integer unique to this factory instance. |
1117 | 223 | return self._integer.next() | 224 | |
1118 | 225 | For each thread, this will be a series of increasing numbers, but the | ||
1119 | 226 | starting point will be unique per thread. | ||
1120 | 227 | """ | ||
1121 | 228 | counter = getattr(self._local, 'integer', None) | ||
1122 | 229 | if counter is None: | ||
1123 | 230 | counter = count(randint(0, 1000000)) | ||
1124 | 231 | self._local.integer = counter | ||
1125 | 232 | return counter.next() | ||
1126 | 224 | 233 | ||
1127 | 225 | def getUniqueHexString(self, digits=None): | 234 | def getUniqueHexString(self, digits=None): |
1128 | 226 | """Return a unique hexadecimal string. | 235 | """Return a unique hexadecimal string. |
1129 | @@ -245,7 +254,7 @@ | |||
1130 | 245 | """ | 254 | """ |
1131 | 246 | if prefix is None: | 255 | if prefix is None: |
1132 | 247 | prefix = "generic-string" | 256 | prefix = "generic-string" |
1134 | 248 | string = "%s%s" % (prefix, generate_uuid()) | 257 | string = "%s%s" % (prefix, self.getUniqueInteger()) |
1135 | 249 | return string.replace('_', '-').lower() | 258 | return string.replace('_', '-').lower() |
1136 | 250 | 259 | ||
1137 | 251 | def getUniqueUnicode(self): | 260 | def getUniqueUnicode(self): |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi Michael,
thank you for your fix and sorry for the delay...
Am 14.06.2010 10:35, schrieb Michael Nelson: agebuild -m cords
> Test command: bin/test -vv -m test_packagebuild -m test_binarypack
> test_hasbuildre
Yup, they pass. Thanks.
> This branch does some initial work to enable PPA's to present general uilds (bug 536700).
> IPackageBuilds rather than IBinaryPackageB
So, I assume that is the reason that no bug is attached to this branch?
> t.getBuildsForA rchive( ). It adds an getBuildRecords () to >IBinaryPackage Build in
> It adds and tests an IPackageBuildSe
> optional param to the getBuildRecords() method - binary_only - which defaults
> to true (current behaivour). It then updates IArchive.
> support binary_only=False.
>
> Additionally, it adds an adapter for IBuildFarmJob-
> preparation for the UI (so each build can present its title correctly).
>
Very clever. ;-)
Here are my comments:
> === modified file 'lib/lp/ buildmaster/ configure. zcml'
OK.
> === modified file 'lib/lp/ buildmaster/ interfaces/ packagebuild. py'
OK.
> === modified file 'lib/lp/ buildmaster/ model/packagebu ild.py' buildmaster/ model/packagebu ild.py 2010-06-07 10:43:01 +0000 buildmaster/ model/packagebu ild.py 2010-06-14 08:35:42 +0000 launchpad. browser. librarian import ( ileAlias) launchpad. interfaces. lpstorm import IMasterStore launchpad. webapp. interfaces import ( interfaces. buildbase import BuildStatus interfaces. buildfarmjob import IBuildFarmJobSource interfaces. packagebuild import ( urce) urce) model.buildbase import handle_ status_ for_build, BuildBase model.buildfarm job import BuildFarmJobDerived model.buildfarm job import ( ived) interfaces. pocket import PackagePublishi ngPocket adapters. archivedependen cies import ( component_ dependency_ name) GIVENBACK( self, librarian, slave_status, logger): _handleStatus_ GIVENBACK( IPackageBuildSe t) hive(self, archive, status=None, pocket=None): et`."""
> --- lib/lp/
> +++ lib/lp/
> @@ -11,6 +11,7 @@
> from lazr.delegates import delegates
>
> from storm.locals import Int, Reference, Storm, Unicode
> +from storm.expr import Desc
>
> from zope.component import getUtility
> from zope.interface import classProvides, implements
> @@ -19,13 +20,16 @@
> from canonical.
> ProxiedLibraryF
> from canonical.
> +from canonical.
> + IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)
>
> from lp.buildmaster.
> from lp.buildmaster.
> from lp.buildmaster.
> - IPackageBuild, IPackageBuildSo
> + IPackageBuild, IPackageBuildSet, IPackageBuildSo
> from lp.buildmaster.
> -from lp.buildmaster.
> +from lp.buildmaster.
> + BuildFarmJob, BuildFarmJobDer
> from lp.registry.
> from lp.soyuz.
> default_
> @@ -214,3 +218,40 @@
> def _handleStatus_
> return BuildBase.
> self, librarian, slave_status, logger)
> +
> +
> +class PackageBuildSet:
> + implements(
> +
> + def getBuildsForArc
> + """See `IPackageBuildS
> +
> + extra_exprs = []
> +
> + # Add query clause that filters on build status if the latter is
> + # provided.
I had been told that comments are not there to reiterate what the code is
doing - the code should speak for itself. Thi...