~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/interfaces/archive.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-05-23 18:43:31 UTC
  • mfrom: (13084.2.6 page-match-rewrite-url)
  • Revision ID: launchpad@pqm.canonical.com-20110523184331-dhd2c7cgfuu49epw
[r=sinzui][bug=784273] Adds facility to the PageMatch to handle bad
        URIs

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
    'IDistributionArchive',
33
33
    'InsufficientUploadRights',
34
34
    'InvalidComponent',
35
 
    'InvalidExternalDependencies',
36
35
    'InvalidPocketForPartnerArchive',
37
36
    'InvalidPocketForPPA',
38
37
    'IPPA',
44
43
    'PocketNotFound',
45
44
    'VersionRequiresName',
46
45
    'default_name_by_purpose',
47
 
    'validate_external_dependencies',
48
46
    ]
49
47
 
50
 
 
51
 
from urlparse import urlparse
52
 
 
53
48
from lazr.enum import DBEnumeratedType
54
49
from lazr.restful.declarations import (
55
50
    call_with,
59
54
    export_read_operation,
60
55
    export_write_operation,
61
56
    exported,
62
 
    operation_for_version,
63
57
    operation_parameters,
64
58
    operation_returns_collection_of,
65
59
    operation_returns_entry,
120
114
 
121
115
class CannotCopy(Exception):
122
116
    """Exception raised when a copy cannot be performed."""
123
 
    webservice_error(400)  # Bad request.
 
117
    webservice_error(400) #Bad request.
124
118
 
125
119
 
126
120
class CannotSwitchPrivacy(Exception):
127
121
    """Raised when switching the privacy of an archive that has
128
122
    publishing records."""
129
 
    webservice_error(400)  # Bad request.
 
123
    webservice_error(400) # Bad request.
130
124
 
131
125
 
132
126
class PocketNotFound(Exception):
133
127
    """Invalid pocket."""
134
 
    webservice_error(400)  # Bad request.
 
128
    webservice_error(400) #Bad request.
135
129
 
136
130
 
137
131
class DistroSeriesNotFound(Exception):
138
132
    """Invalid distroseries."""
139
 
    webservice_error(400)  # Bad request.
 
133
    webservice_error(400) #Bad request.
140
134
 
141
135
 
142
136
class AlreadySubscribed(Exception):
143
137
    """Raised when creating a subscription for a subscribed person."""
144
 
    webservice_error(400)  # Bad request.
 
138
    webservice_error(400) # Bad request.
145
139
 
146
140
 
147
141
class ArchiveNotPrivate(Exception):
148
142
    """Raised when creating an archive subscription for a public archive."""
149
 
    webservice_error(400)  # Bad request.
 
143
    webservice_error(400) # Bad request.
150
144
 
151
145
 
152
146
class NoTokensForTeams(Exception):
153
147
    """Raised when creating a token for a team, rather than a person."""
154
 
    webservice_error(400)  # Bad request.
 
148
    webservice_error(400) # Bad request.
155
149
 
156
150
 
157
151
class ComponentNotFound(Exception):
158
152
    """Invalid source name."""
159
 
    webservice_error(400)  # Bad request.
 
153
    webservice_error(400) #Bad request.
160
154
 
161
155
 
162
156
class InvalidComponent(Exception):
163
157
    """Invalid component name."""
164
 
    webservice_error(400)  # Bad request.
 
158
    webservice_error(400) #Bad request.
165
159
 
166
160
 
167
161
class NoSuchPPA(NameLookupFailed):
168
162
    """Raised when we try to look up an PPA that doesn't exist."""
169
 
    webservice_error(400)  # Bad request.
 
163
    webservice_error(400) #Bad request.
170
164
    _message_prefix = "No such ppa"
171
165
 
172
166
 
173
167
class VersionRequiresName(Exception):
174
168
    """Raised on some queries when version is specified but name is not."""
175
 
    webservice_error(400)  # Bad request.
 
169
    webservice_error(400) # Bad request.
176
170
 
177
171
 
178
172
class CannotRestrictArchitectures(Exception):
181
175
 
182
176
class CannotUploadToArchive(Exception):
183
177
    """A reason for not being able to upload to an archive."""
184
 
    webservice_error(403)  # Forbidden.
 
178
    webservice_error(403) # Forbidden.
185
179
 
186
180
    _fmt = '%(person)s has no upload rights to %(archive)s.'
187
181
 
198
192
 
199
193
class CannotUploadToPocket(Exception):
200
194
    """Returned when a pocket is closed for uploads."""
201
 
    webservice_error(403)  # Forbidden.
 
195
    webservice_error(403) # Forbidden.
202
196
 
203
197
    def __init__(self, distroseries, pocket):
204
198
        Exception.__init__(self,
254
248
        CannotUploadToArchive.__init__(self, archive_name=archive_name)
255
249
 
256
250
 
257
 
class InvalidExternalDependencies(Exception):
258
 
    """Tried to set external dependencies to an invalid value."""
259
 
 
260
 
    webservice_error(400)  # Bad request.
261
 
 
262
 
    def __init__(self, errors):
263
 
        error_msg = 'Invalid external dependencies:\n%s\n' % '\n'.join(errors)
264
 
        super(Exception, self).__init__(self, error_msg)
265
 
        self.errors = errors
266
 
 
267
 
 
268
251
class IArchivePublic(IHasOwner, IPrivacy):
269
252
    """An Archive interface for publicly available operations."""
270
253
    id = Attribute("The archive ID.")
349
332
 
350
333
    distribution = exported(
351
334
        Reference(
352
 
            Interface,  # Redefined to IDistribution later.
 
335
            Interface, # Redefined to IDistribution later.
353
336
            title=_("The distribution that uses or is used by this "
354
337
                    "archive.")))
355
338
 
429
412
            "A delta to apply to all build scores for the archive. Builds "
430
413
            "with a higher score will build sooner."))
431
414
 
432
 
    external_dependencies = exported(
433
 
        Text(title=_("External dependencies"), required=False,
434
 
        readonly=False, description=_(
 
415
    external_dependencies = Text(
 
416
        title=_("External dependencies"), required=False, readonly=False,
 
417
        description=_(
435
418
            "Newline-separated list of repositories to be used to retrieve "
436
419
            "any external build dependencies when building packages in the "
437
420
            "archive, in the format:\n"
439
422
                "[components]\n"
440
423
            "The series variable is replaced with the series name of the "
441
424
            "context build.\n"
442
 
            "NOTE: This is for migration of OEM PPAs only!")))
 
425
            "NOTE: This is for migration of OEM PPAs only!"))
443
426
 
444
427
    enabled_restricted_families = CollectionField(
445
428
            title=_("Enabled restricted families"),
537
520
            records.
538
521
        """
539
522
 
 
523
    def removeArchiveDependency(dependency):
 
524
        """Remove the `IArchiveDependency` record for the given dependency.
 
525
 
 
526
        :param dependency: is an `IArchive` object.
 
527
        """
 
528
 
 
529
    def addArchiveDependency(dependency, pocket, component=None):
 
530
        """Record an archive dependency record for the context archive.
 
531
 
 
532
        :param dependency: is an `IArchive` object.
 
533
        :param pocket: is an `PackagePublishingPocket` enum.
 
534
        :param component: is an optional `IComponent` object, if not given
 
535
            the archive dependency will be tied to the component used
 
536
            for a corresponding source in primary archive.
 
537
 
 
538
        :raise: `ArchiveDependencyError` if given 'dependency' does not fit
 
539
            the context archive.
 
540
        :return: a `IArchiveDependency` object targeted to the context
 
541
            `IArchive` requiring 'dependency' `IArchive`.
 
542
        """
 
543
 
540
544
    def getPermissions(person, item, perm_type):
541
545
        """Get the `IArchivePermission` record with the supplied details.
542
546
 
888
892
        :return: True if the person is allowed to upload the source package.
889
893
        """
890
894
 
891
 
    num_pkgs_building = Attribute(
892
 
        "Tuple of packages building and waiting to build")
 
895
    num_pkgs_building = Attribute("Tuple of packages building and waiting to build")
893
896
 
894
897
    def getSourcePackageReleases(build_status=None):
895
898
        """Return the releases for this archive.
926
929
    def getPockets():
927
930
        """Return iterable containing valid pocket names for this archive."""
928
931
 
929
 
    def getOverridePolicy():
930
 
        """Returns an instantiated `IOverridePolicy` for the archive."""
931
 
 
932
932
 
933
933
class IArchiveView(IHasBuildRecords):
934
934
    """Archive interface for operations restricted by view privilege."""
941
941
    dependencies = exported(
942
942
        CollectionField(
943
943
            title=_("Archive dependencies recorded for this archive."),
944
 
            value_type=Reference(schema=Interface),
945
 
            # Really IArchiveDependency
 
944
            value_type=Reference(schema=Interface), #Really IArchiveDependency
946
945
            readonly=True))
947
946
 
948
947
    description = exported(
1109
1108
        """
1110
1109
 
1111
1110
    @operation_parameters(
1112
 
        dependency=Reference(schema=Interface))  # Really IArchive. See below.
1113
 
    @operation_returns_entry(schema=Interface)  # Really IArchiveDependency.
 
1111
        dependency=Reference(schema=Interface)) #Really IArchive. See below.
 
1112
    @operation_returns_entry(schema=Interface) #Really IArchiveDependency.
1114
1113
    @export_read_operation()
1115
1114
    def getArchiveDependency(dependency):
1116
1115
        """Return the `IArchiveDependency` object for the given dependency.
1231
1230
        source_names=List(
1232
1231
            title=_("Source package names"),
1233
1232
            value_type=TextLine()),
1234
 
        from_archive=Reference(schema=Interface),
1235
 
        #Really IArchive, see below
 
1233
        from_archive=Reference(schema=Interface), #Really IArchive, see below
1236
1234
        to_pocket=TextLine(title=_("Pocket name")),
1237
1235
        to_series=TextLine(title=_("Distroseries name"), required=False),
1238
1236
        include_binaries=Bool(
1274
1272
    @operation_parameters(
1275
1273
        source_name=TextLine(title=_("Source package name")),
1276
1274
        version=TextLine(title=_("Version")),
1277
 
        from_archive=Reference(schema=Interface),
1278
 
        # Really IArchive, see below
 
1275
        from_archive=Reference(schema=Interface), #Really IArchive, see below
1279
1276
        to_pocket=TextLine(title=_("Pocket name")),
1280
1277
        to_series=TextLine(title=_("Distroseries name"), required=False),
1281
1278
        include_binaries=Bool(
1314
1311
 
1315
1312
    @call_with(registrant=REQUEST_USER)
1316
1313
    @operation_parameters(
1317
 
        subscriber=PublicPersonChoice(
 
1314
        subscriber = PublicPersonChoice(
1318
1315
            title=_("Subscriber"),
1319
1316
            required=True,
1320
1317
            vocabulary='ValidPersonOrTeam',
1458
1455
        processed.
1459
1456
        """
1460
1457
 
1461
 
    def addArchiveDependency(dependency, pocket, component=None):
1462
 
        """Record an archive dependency record for the context archive.
1463
 
 
1464
 
        :param dependency: is an `IArchive` object.
1465
 
        :param pocket: is an `PackagePublishingPocket` enum.
1466
 
        :param component: is an optional `IComponent` object, if not given
1467
 
            the archive dependency will be tied to the component used
1468
 
            for a corresponding source in primary archive.
1469
 
 
1470
 
        :raise: `ArchiveDependencyError` if given 'dependency' does not fit
1471
 
            the context archive.
1472
 
        :return: a `IArchiveDependency` object targeted to the context
1473
 
            `IArchive` requiring 'dependency' `IArchive`.
1474
 
        """
1475
 
 
1476
 
    @operation_parameters(
1477
 
        dependency=Reference(schema=Interface, required=True),
1478
 
        #  Really IArchive
1479
 
        pocket=Choice(
1480
 
            title=_("Pocket"),
1481
 
            description=_("The pocket into which this entry is published"),
1482
 
            # Really PackagePublishingPocket.
1483
 
            vocabulary=DBEnumeratedType,
1484
 
            required=True),
1485
 
        component=TextLine(title=_("Component"), required=False),
1486
 
        )
1487
 
    @export_operation_as('addArchiveDependency')
1488
 
    @export_factory_operation(Interface, [])  # Really IArchiveDependency
1489
 
    @operation_for_version('devel')
1490
 
    def _addArchiveDependency(dependency, pocket, component=None):
1491
 
        """Record an archive dependency record for the context archive.
1492
 
 
1493
 
        :param dependency: is an `IArchive` object.
1494
 
        :param pocket: is an `PackagePublishingPocket` enum.
1495
 
        :param component: is the name of a component.  If not given,
1496
 
            the archive dependency will be tied to the component used
1497
 
            for a corresponding source in primary archive.
1498
 
 
1499
 
        :raise: `ArchiveDependencyError` if given 'dependency' does not fit
1500
 
            the context archive.
1501
 
        :return: a `IArchiveDependency` object targeted to the context
1502
 
            `IArchive` requiring 'dependency' `IArchive`.
1503
 
        """
1504
 
    @operation_parameters(
1505
 
        dependency=Reference(schema=Interface, required=True),
1506
 
        # Really IArchive
1507
 
    )
1508
 
    @export_write_operation()
1509
 
    @operation_for_version('devel')
1510
 
    def removeArchiveDependency(dependency):
1511
 
        """Remove the `IArchiveDependency` record for the given dependency.
1512
 
 
1513
 
        :param dependency: is an `IArchive` object.
1514
 
        """
1515
 
 
1516
1458
 
1517
1459
class IArchive(IArchivePublic, IArchiveAppend, IArchiveEdit, IArchiveView):
1518
1460
    """Main Archive interface."""
1745
1687
    )
1746
1688
 
1747
1689
# Circular dependency issues fixed in _schema_circular_imports.py
1748
 
 
1749
 
 
1750
 
def validate_external_dependencies(ext_deps):
1751
 
    """Validate the external_dependencies field.
1752
 
 
1753
 
    :param ext_deps: The dependencies form field to check.
1754
 
    """
1755
 
    errors = []
1756
 
    # The field can consist of multiple entries separated by
1757
 
    # newlines, so process each in turn.
1758
 
    for dep in ext_deps.splitlines():
1759
 
        try:
1760
 
            deb, url, suite, components = dep.split(" ", 3)
1761
 
        except ValueError:
1762
 
            errors.append(
1763
 
                "'%s' is not a complete and valid sources.list entry"
1764
 
                    % dep)
1765
 
            continue
1766
 
 
1767
 
        if deb != "deb":
1768
 
            errors.append("%s: Must start with 'deb'" % dep)
1769
 
        url_components = urlparse(url)
1770
 
        if not url_components[0] or not url_components[1]:
1771
 
            errors.append("%s: Invalid URL" % dep)
1772
 
 
1773
 
    return errors