~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/browser/queue.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-06-21 22:17:38 UTC
  • mfrom: (13228.4.8 set-ppa-private)
  • Revision ID: launchpad@pqm.canonical.com-20110621221738-l68s7zrnalblik8l
[r=jcsackett][bug=724740] Provides facility to set a PPA private via
        the API

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
    'QueueItemsView',
10
10
    ]
11
11
 
12
 
import cgi
13
12
import operator
14
13
 
15
14
from lazr.delegates import delegates
23
22
    NotFoundError,
24
23
    UnexpectedFormData,
25
24
    )
26
 
from lp.services.database.bulk import (
27
 
    load_referencing,
28
 
    load_related,
29
 
    )
30
25
from lp.soyuz.enums import (
31
26
    PackagePublishingPriority,
32
27
    PackageUploadStatus,
46
41
    QueueInconsistentStateError,
47
42
    )
48
43
from lp.soyuz.interfaces.section import ISectionSet
49
 
from lp.soyuz.model.queue import PackageUploadSource
50
44
 
51
45
 
52
46
QUEUE_SIZE = 30
182
176
        # Listify to avoid repeated queries.
183
177
        return list(old_binary_packages)
184
178
 
185
 
    def getPackagesetsFor(self, source_package_releases):
186
 
        """Find associated `Packagesets`.
187
 
 
188
 
        :param source_package_releases: A sequence of `SourcePackageRelease`s.
189
 
        """
190
 
        sprs = [spr for spr in source_package_releases if spr is not None]
191
 
        return getUtility(IPackagesetSet).getForPackages(
192
 
            self.context, set(spr.sourcepackagenameID for spr in sprs))
193
 
 
194
179
    def decoratedQueueBatch(self):
195
180
        """Return the current batch, converted to decorated objects.
196
181
 
198
183
        CompletePackageUpload.  This avoids many additional SQL queries
199
184
        in the +queue template.
200
185
        """
201
 
        # Avoid circular imports.
202
 
        from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
203
 
 
204
186
        uploads = list(self.batchnav.currentBatch())
205
187
 
206
188
        if len(uploads) == 0:
214
196
                    upload.status != PackageUploadStatus.DONE)]
215
197
        binary_file_set = getUtility(IBinaryPackageFileSet)
216
198
        binary_files = binary_file_set.getByPackageUploadIDs(upload_ids)
217
 
        packageuploadsources = load_referencing(
218
 
            PackageUploadSource, uploads, ['packageuploadID'])
219
199
        source_file_set = getUtility(ISourcePackageReleaseFileSet)
220
200
        source_files = source_file_set.getByPackageUploadIDs(upload_ids)
221
201
 
222
 
        source_sprs = load_related(
223
 
            SourcePackageRelease, packageuploadsources,
224
 
            ['sourcepackagereleaseID'])
225
 
 
226
202
        # Get a dictionary of lists of binary files keyed by upload ID.
227
203
        package_upload_builds_dict = self.builds_dict(
228
204
            upload_ids, binary_files)
241
217
        self.old_binary_packages = self.calculateOldBinaries(
242
218
            binary_package_names)
243
219
 
244
 
        package_sets = self.getPackagesetsFor(source_sprs)
245
 
 
246
220
        return [
247
221
            CompletePackageUpload(
248
 
                item, build_upload_files, source_upload_files, package_sets)
 
222
                item, build_upload_files, source_upload_files)
249
223
            for item in uploads]
250
224
 
251
225
    def is_new(self, binarypackagerelease):
441
415
class CompletePackageUpload:
442
416
    """A decorated `PackageUpload` including sources, builds and packages.
443
417
 
444
 
    This acts effectively as a view for package uploads.  Some properties of
445
 
    the class are cached here to reduce the number of queries that the +queue
446
 
    template has to make.  Others are added here exclusively.
 
418
    Some properties of PackageUpload are cached here to reduce the number
 
419
    of queries that the +queue template has to make.
447
420
    """
448
421
    # These need to be predeclared to avoid delegates taking them over.
449
422
    # Would be nice if there was a way of allowing writes to just work
460
433
    delegates(IPackageUpload)
461
434
 
462
435
    def __init__(self, packageupload, build_upload_files,
463
 
                 source_upload_files, package_sets):
 
436
                 source_upload_files):
464
437
        self.pocket = packageupload.pocket
465
438
        self.date_created = packageupload.date_created
466
439
        self.context = packageupload
486
459
        else:
487
460
            self.sourcepackagerelease = None
488
461
 
489
 
        if self.contains_source:
490
 
            self.package_sets = package_sets.get(
491
 
                self.sourcepackagerelease.sourcepackagenameID, [])
492
 
        else:
493
 
            self.package_sets = []
494
 
 
495
462
    @property
496
463
    def pending_delayed_copy(self):
497
464
        """Whether the context is a delayed-copy pending processing."""
511
478
        return self.context.changesfile
512
479
 
513
480
    @property
514
 
    def display_package_sets(self):
515
 
        """Package sets, if any, for display on the +queue page."""
516
 
        if self.contains_source:
517
 
            return ' '.join(sorted(
518
 
                packageset.name for packageset in self.package_sets))
519
 
        else:
520
 
            return ""
521
 
 
522
 
    @property
523
 
    def display_component(self):
524
 
        """Component name, if any, for display on the +queue page."""
525
 
        if self.contains_source:
526
 
            return self.component_name.lower()
527
 
        else:
528
 
            return ""
529
 
 
530
 
    @property
531
 
    def display_section(self):
532
 
        """Section name, if any, for display on the +queue page."""
533
 
        if self.contains_source:
534
 
            return self.section_name.lower()
535
 
        else:
536
 
            return ""
537
 
 
538
 
    @property
539
 
    def display_priority(self):
540
 
        """Priority name, if any, for display on the +queue page."""
541
 
        if self.contains_source:
542
 
            return self.sourcepackagerelease.urgency.name.lower()
543
 
        else:
544
 
            return ""
545
 
 
546
 
    def composeIcon(self, alt, icon, title=None):
547
 
        """Compose an icon for the package's icon list."""
548
 
        # These should really be sprites!
549
 
        if title is None:
550
 
            title = alt
551
 
        return '<img alt="[%s]" src="/@@/%s" title="%s" />' % (
552
 
            cgi.escape(alt, quote=True),
553
 
            icon,
554
 
            cgi.escape(title, quote=True),
555
 
            )
556
 
 
557
 
    def composeIconList(self):
558
 
        """List icons that should be shown for this upload."""
559
 
        ddtp = "Debian Description Translation Project Indexes"
560
 
        potential_icons = [
561
 
            (self.contains_source, ("Source", 'package-source')),
562
 
            (self.contains_build, ("Build", 'package-binary', "Binary")),
563
 
            (self.contains_translation, ("Translation", 'translation-file')),
564
 
            (self.contains_installer, ("Installer", 'ubuntu-icon')),
565
 
            (self.contains_upgrader, ("Upgrader", 'ubuntu-icon')),
566
 
            (self.contains_ddtp, (ddtp, 'ubuntu-icon')),
567
 
            ]
568
 
        return [
569
 
            self.composeIcon(*details)
570
 
            for condition, details in potential_icons
571
 
                if condition]
572
 
 
573
 
    def composeNameAndChangesLink(self):
574
 
        """Compose HTML: upload name and link to changes file."""
575
 
        raw_displayname = self.displayname
576
 
        displayname = cgi.escape(raw_displayname)
577
 
        if self.pending_delayed_copy or self.changesfile is None:
578
 
            return displayname
579
 
        else:
580
 
            return '<a href="%s" title="Changes file for %s">%s</a>' % (
581
 
                self.changesfile.http_url,
582
 
                cgi.escape(self.displayname, quote=True),
583
 
                displayname)
584
 
 
585
 
    @property
586
 
    def icons_and_name(self):
587
 
        """Icon list and name, linked to changes file if appropriate."""
588
 
        iconlist_id = "queue%d-iconlist" % self.id
589
 
        icons = self.composeIconList()
590
 
        link = self.composeNameAndChangesLink()
591
 
        return """
592
 
            <div id="%s">
593
 
              %s
594
 
              %s
595
 
              (%s)
596
 
            </div>
597
 
            """ % (iconlist_id, '\n'.join(icons), link, self.displayarchs)
 
481
    def package_sets(self):
 
482
        assert self.sourcepackagerelease, \
 
483
            "Can only be used on a source upload."
 
484
        return ' '.join(sorted(ps.name for ps in
 
485
            getUtility(IPackagesetSet).setsIncludingSource(
 
486
                self.sourcepackagerelease.sourcepackagename,
 
487
                distroseries=self.distroseries,
 
488
                direct_inclusion=True)))