~brian-murray/ubuntu-archive-tools/pup-raring

82 by Martin Pitt
edit_acl.py: Fix shebang to use default python
1
#!/usr/bin/python
358 by Colin Watson
add coding: line where necessary
2
# -*- coding: utf-8 -*-
1 by Julian Edwards
new script to edit uploader ACLs
3
355 by Colin Watson
Apply GPLv3 to anything not already licensed; ok slangasek, broder, laney, kitterman, geser
4
# Copyright (C) 2008, 2009, 2010, 2011, 2012  Canonical Ltd.
5
# Copyright (C) 2010  Stéphane Graber <stgraber@stgraber.org>
6
# Copyright (C) 2010  Michael Bienia <geser@ubuntu.com>
7
# Copyright (C) 2011  Iain Lane <laney@ubuntu.com>
8
# Copyright (C) 2011  Soren Hansen <soren@linux2go.dk>
607.1.3 by Stefano Rivera
Add myself as a copyright holder
9
# Copyright (C) 2012  Stefano Rivera <stefanor@ubuntu.com>
355 by Colin Watson
Apply GPLv3 to anything not already licensed; ok slangasek, broder, laney, kitterman, geser
10
11
# This program is free software: you can redistribute it and/or modify
12
# it under the terms of the GNU General Public License as published by
13
# the Free Software Foundation; version 3 of the License.
14
#
15
# This program is distributed in the hope that it will be useful,
16
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
# GNU General Public License for more details.
19
#
20
# You should have received a copy of the GNU General Public License
21
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1 by Julian Edwards
new script to edit uploader ACLs
22
23
"""Edit uploader permissions for the Ubuntu distro in Launchpad."""
24
359 by Colin Watson
Use Python 3-style print functions.
25
from __future__ import print_function
26
492 by Colin Watson
sort imports
27
from optparse import OptionParser
13 by Colin Watson
PEP-8 import ordering
28
import sys
29
61 by Colin Watson
import launchpadlib.errors
30
import launchpadlib.errors
178.1.1 by Michael Bienia
Add basic support for anonymous LP login for "query" and "check"
31
from launchpadlib.launchpad import Launchpad
13 by Colin Watson
PEP-8 import ordering
32
492 by Colin Watson
sort imports
33
422 by Colin Watson
backport-helper.py, edit_acl.py: use input() rather than raw_input() when running under Python 3
34
if sys.version < '3':
35
    input = raw_input
36
11 by Colin Watson
split launchpadlib boilerplate out to new lputils module (whose functions take the consumer key as an argument)
37
486 by Colin Watson
Remove .py suffixes from all scripts. edit_acl.py gets a compatibility symlink for the time being since some non-archive-admins use it.
38
CONSUMER_KEY = "edit-acl"
1 by Julian Edwards
new script to edit uploader ACLs
39
40
101 by Colin Watson
look up component permissions as well when querying a source package
41
def print_perms(perms, series=None):
1 by Julian Edwards
new script to edit uploader ACLs
42
    for perm in perms:
115 by Colin Watson
edit_acl.py: ensure queried permissions are always filtered by requested series
43
        if (series is not None and perm.distro_series_name is not None and
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
44
                series != perm.distro_series_name):
115 by Colin Watson
edit_acl.py: ensure queried permissions are always filtered by requested series
45
            continue
77 by Colin Watson
more legible query output
46
        desc = []
108 by Colin Watson
edit_acl.py: add per-archive handling
47
        desc.append("archive '%s'" % perm.archive.name)
77 by Colin Watson
more legible query output
48
        if perm.component_name:
49
            desc.append("component '%s'" % perm.component_name)
101 by Colin Watson
look up component permissions as well when querying a source package
50
            if series:
51
                desc[-1] += ' in %s' % series
77 by Colin Watson
more legible query output
52
        if perm.package_set_name:
53
            desc.append("package set '%s' in %s" % (perm.package_set_name,
54
                                                    perm.distro_series_name))
55
        if perm.source_package_name:
56
            desc.append("source package '%s'" % perm.source_package_name)
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
57
        if perm.pocket:
58
            desc.append("pocket '%s'" % perm.pocket)
593 by Colin Watson
edit-acl: support per-series pocket queue admin permissions
59
            if perm.distro_series_name is not None:
60
                desc[-1] += " in %s" % perm.distro_series_name
359 by Colin Watson
Use Python 3-style print functions.
61
        print("%s for %s: %s" % (perm.permission, perm.person.name,
62
                                 ', '.join(desc)))
1 by Julian Edwards
new script to edit uploader ACLs
63
64
607.1.4 by Stefano Rivera
Multi-line descriptions
65
def multiline_input(prompt):
66
    print(prompt)
67
    print("End with a line containing only a full-stop '.'")
68
    buf = []
69
    while True:
70
        line = input()
71
        if line == '.':
72
            return '\n'.join(buf)
73
        buf.append(line)
74
75
108 by Colin Watson
edit_acl.py: add per-archive handling
76
def get_archive(options, launchpad):
77
    if options.archive is None:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
78
        return options.distro.main_archive
108 by Colin Watson
edit_acl.py: add per-archive handling
79
    else:
253.1.1 by Soren Hansen
Allow edit_acl.py's --archive to accept PPA names.
80
        if '/' in options.archive:
81
            owner, ppa_name = options.archive.split('/')
82
            return launchpad.people[owner].getPPAByName(name=ppa_name)
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
83
        for archive in options.distro.archives:
108 by Colin Watson
edit_acl.py: add per-archive handling
84
            if archive.name == options.archive:
85
                return archive
86
    raise AssertionError("No such archive in Ubuntu: %s" % options.archive)
87
88
89
def get_source_components(options, launchpad, archive, source):
122.1.1 by Michael Bienia
'debian_bundle' got renamed to 'debian'. Try importing it first before falling
90
    try:
91
        from debian import debian_support
92
    except ImportError:
93
        from debian_bundle import debian_support
101 by Colin Watson
look up component permissions as well when querying a source package
94
95
    args = {}
96
    if options.series:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
97
        args['distro_series'] = options.distro.getSeries(
101 by Colin Watson
look up component permissions as well when querying a source package
98
            name_or_version=options.series)
99
100
    newest = {}
108 by Colin Watson
edit_acl.py: add per-archive handling
101
    for spph in archive.getPublishedSources(
101 by Colin Watson
look up component permissions as well when querying a source package
102
            source_name=source, exact_match=True, status='Published', **args):
103
        if not spph.distro_series.active:
104
            continue
105
        new_version = debian_support.Version(spph.source_package_version)
106
        if (spph.distro_series.name not in newest or
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
107
                new_version > newest[spph.distro_series.name][0]):
101 by Colin Watson
look up component permissions as well when querying a source package
108
            newest[spph.distro_series.name] = (new_version,
109
                                               spph.component_name)
110
556 by Colin Watson
Rely on default iterator for mappings iterating over keys.
111
    for series in sorted(newest, key=lambda s: newest[s][0]):
101 by Colin Watson
look up component permissions as well when querying a source package
112
        yield series, newest[series][1]
113
114
5 by Colin Watson
allow specifying an ACL type
115
permission_names = dict(upload='Archive Upload Rights',
116
                        admin='Queue Administration Rights')
117
118
1 by Julian Edwards
new script to edit uploader ACLs
119
def do_query(options):
120
    """Query existing permissions and show on stdout."""
108 by Colin Watson
edit_acl.py: add per-archive handling
121
    if options.archive is None:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
122
        archives = options.distro.archives
108 by Colin Watson
edit_acl.py: add per-archive handling
123
    else:
124
        archives = [get_archive(options, launchpad)]
1 by Julian Edwards
new script to edit uploader ACLs
125
126
    if options.person:
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
127
        for person in options.person:
128
            if '@' in person:
129
                lp_person = launchpad.people.getByEmail(email=person)
130
            else:
131
                try:
132
                    lp_person = launchpad.people[person]
133
                except KeyError:
359 by Colin Watson
Use Python 3-style print functions.
134
                    print("Person '%s' doesn't exist." % person)
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
135
                    sys.exit(1)
136
            perms = []
137
            for archive in archives:
138
                perms.extend(archive.getPermissionsForPerson(
139
                    person=lp_person))
140
            if options.acl_type:
141
                perm_name = permission_names[options.acl_type]
142
                perms = [p for p in perms if p.permission == perm_name]
359 by Colin Watson
Use Python 3-style print functions.
143
            print("== All rights for %s ==" % lp_person.name)
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
144
            print_perms(perms, options.series)
1 by Julian Edwards
new script to edit uploader ACLs
145
146
    if options.component:
5 by Colin Watson
allow specifying an ACL type
147
        perms = []
148
        if not options.acl_type or options.acl_type == 'upload':
108 by Colin Watson
edit_acl.py: add per-archive handling
149
            for archive in archives:
150
                perms.extend(archive.getUploadersForComponent(
151
                    component_name=options.component))
5 by Colin Watson
allow specifying an ACL type
152
        if not options.acl_type or options.acl_type == 'admin':
108 by Colin Watson
edit_acl.py: add per-archive handling
153
            for archive in archives:
154
                perms.extend(archive.getQueueAdminsForComponent(
155
                    component_name=options.component))
359 by Colin Watson
Use Python 3-style print functions.
156
        print("== All rights for component '%s' ==" % options.component)
115 by Colin Watson
edit_acl.py: ensure queried permissions are always filtered by requested series
157
        print_perms(perms, options.series)
1 by Julian Edwards
new script to edit uploader ACLs
158
60 by Colin Watson
add package set manipulation option
159
    if options.packageset:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
160
        lp_series = options.distro.getSeries(name_or_version=options.series)
60 by Colin Watson
add package set manipulation option
161
        for packageset in options.packageset:
76 by Colin Watson
better fixes for new package set schema
162
            lp_set = launchpad.packagesets.getByName(name=packageset,
163
                                                     distroseries=lp_series)
75 by Colin Watson
support new per-series package set schema
164
108 by Colin Watson
edit_acl.py: add per-archive handling
165
            perms = []
166
            for archive in archives:
167
                perms.extend(archive.getUploadersForPackageset(
168
                    packageset=lp_set))
545 by Colin Watson
Make all scripts pass pep8(1).
169
            print(("== All uploaders for package set '%s' in '%s' "
170
                   "(owned by '%s') ==" %
359 by Colin Watson
Use Python 3-style print functions.
171
                  (packageset, options.series, lp_set.owner.display_name)))
115 by Colin Watson
edit_acl.py: ensure queried permissions are always filtered by requested series
172
            print_perms(perms, options.series)
60 by Colin Watson
add package set manipulation option
173
64 by Colin Watson
bodge in some options to manage package set contents
174
            sources = sorted(lp_set.getSourcesIncluded(direct_inclusion=True))
175
            if sources:
359 by Colin Watson
Use Python 3-style print functions.
176
                print()
177
                print("== All source packages in package set '%s' "
178
                      "in '%s' ==" % (packageset, options.series))
64 by Colin Watson
bodge in some options to manage package set contents
179
                for source in sources:
359 by Colin Watson
Use Python 3-style print functions.
180
                    print(source)
64 by Colin Watson
bodge in some options to manage package set contents
181
            child_sets = list(lp_set.setsIncluded(direct_inclusion=True))
182
            if child_sets:
359 by Colin Watson
Use Python 3-style print functions.
183
                print()
184
                print("== All package sets in package set '%s' in '%s' ==" %
185
                      (packageset, options.series))
64 by Colin Watson
bodge in some options to manage package set contents
186
                for child_set in child_sets:
359 by Colin Watson
Use Python 3-style print functions.
187
                    print(child_set.name)
64 by Colin Watson
bodge in some options to manage package set contents
188
1 by Julian Edwards
new script to edit uploader ACLs
189
    if options.source:
14 by Colin Watson
allow operating on multiple source packages in a single run
190
        for source in options.source:
108 by Colin Watson
edit_acl.py: add per-archive handling
191
            perms = []
192
            perms_set = []
193
            for archive in archives:
114 by Colin Watson
edit_acl.py: fix single-package queries following multi-archive work
194
                perms.extend(archive.getUploadersForPackage(
195
                    source_package_name=source))
196
                perms_set.extend(archive.getPackagesetsForSource(
197
                    sourcepackagename=source))
359 by Colin Watson
Use Python 3-style print functions.
198
            print("== All uploaders for package '%s' ==" % source)
115 by Colin Watson
edit_acl.py: ensure queried permissions are always filtered by requested series
199
            print_perms(perms, options.series)
200
            print_perms(perms_set, options.series)
108 by Colin Watson
edit_acl.py: add per-archive handling
201
            for archive in archives:
202
                for series, component in get_source_components(
203
                        options, launchpad, archive, source):
204
                    perms_component = archive.getUploadersForComponent(
205
                        component_name=component)
206
                    print_perms(perms_component, series=series)
1 by Julian Edwards
new script to edit uploader ACLs
207
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
208
    if options.pocket:
209
        perms = []
583 by Colin Watson
edit-acl: support pocket queue admin permissions
210
        if not options.acl_type or options.acl_type == 'upload':
211
            for archive in archives:
212
                perms.extend(archive.getUploadersForPocket(
213
                    pocket=options.pocket))
214
        if not options.acl_type or options.acl_type == 'admin':
215
            for archive in archives:
216
                perms.extend(archive.getQueueAdminsForPocket(
217
                    pocket=options.pocket))
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
218
        print("== All rights for pocket '%s' ==" % options.pocket)
219
        print_perms(perms, options.series)
220
1 by Julian Edwards
new script to edit uploader ACLs
221
607.1.1 by Stefano Rivera
Add support for packageset deletion (urgh, packageset management really doesn't fit well in here)
222
def validate_add_delete_options(options, requires_person=True):
64 by Colin Watson
bodge in some options to manage package set contents
223
    if options.packageset and options.source:
224
        # Special options to manage package sets, bodged into this tool
225
        # since they aren't entirely inconvenient here.
226
        if options.component or options.person:
359 by Colin Watson
Use Python 3-style print functions.
227
            print("-P <packageset> -s <source> cannot be used with a "
228
                  "component or person as well")
64 by Colin Watson
bodge in some options to manage package set contents
229
            return False
230
        return True
231
607.1.1 by Stefano Rivera
Add support for packageset deletion (urgh, packageset management really doesn't fit well in here)
232
    if requires_person and not options.person:
233
        print("You must specify at least one person to (de-)authorise.")
1 by Julian Edwards
new script to edit uploader ACLs
234
        return False
235
60 by Colin Watson
add package set manipulation option
236
    count = 0
237
    if options.component:
238
        count += 1
239
    if options.packageset:
240
        count += 1
241
    if options.source:
242
        count += 1
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
243
    if options.pocket:
244
        count += 1
60 by Colin Watson
add package set manipulation option
245
    if count > 1:
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
246
        print("You can only specify one of package set, source, component, "
247
              "or pocket")
1 by Julian Edwards
new script to edit uploader ACLs
248
        return False
249
60 by Colin Watson
add package set manipulation option
250
    if count == 0:
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
251
        print("You must specify one of package set, source, component, or "
252
              "pocket")
1 by Julian Edwards
new script to edit uploader ACLs
253
        return False
254
255
    return True
256
257
258
def do_add(options):
259
    """Add a new permission."""
8 by Matt Zimmerman
fix validate_add_delete_options calls
260
    if not validate_add_delete_options(options):
1 by Julian Edwards
new script to edit uploader ACLs
261
        return False
262
108 by Colin Watson
edit_acl.py: add per-archive handling
263
    archive = get_archive(options, launchpad)
64 by Colin Watson
bodge in some options to manage package set contents
264
265
    if options.packageset and options.source:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
266
        lp_series = options.distro.getSeries(name_or_version=options.series)
64 by Colin Watson
bodge in some options to manage package set contents
267
        for packageset in options.packageset:
76 by Colin Watson
better fixes for new package set schema
268
            lp_set = launchpad.packagesets.getByName(name=packageset,
269
                                                     distroseries=lp_series)
64 by Colin Watson
bodge in some options to manage package set contents
270
            lp_set.addSources(names=options.source)
359 by Colin Watson
Use Python 3-style print functions.
271
            print("Added:")
64 by Colin Watson
bodge in some options to manage package set contents
272
            for source in options.source:
359 by Colin Watson
Use Python 3-style print functions.
273
                print(source)
64 by Colin Watson
bodge in some options to manage package set contents
274
        return
275
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
276
    people = [launchpad.people[person] for person in options.person]
1 by Julian Edwards
new script to edit uploader ACLs
277
278
    if options.source:
14 by Colin Watson
allow operating on multiple source packages in a single run
279
        for source in options.source:
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
280
            for person in people:
281
                perm = archive.newPackageUploader(
282
                    person=person, source_package_name=source)
359 by Colin Watson
Use Python 3-style print functions.
283
                print("Added:")
545 by Colin Watson
Make all scripts pass pep8(1).
284
                print_perms([perm])
1 by Julian Edwards
new script to edit uploader ACLs
285
        return
286
60 by Colin Watson
add package set manipulation option
287
    if options.packageset:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
288
        lp_series = options.distro.getSeries(name_or_version=options.series)
60 by Colin Watson
add package set manipulation option
289
        for packageset in options.packageset:
79 by Colin Watson
fix add/delete to support per-series package sets
290
            lp_set = launchpad.packagesets.getByName(name=packageset,
291
                                                     distroseries=lp_series)
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
292
            for person in people:
293
                perm = archive.newPackagesetUploader(
294
                    person=person, packageset=lp_set)
359 by Colin Watson
Use Python 3-style print functions.
295
                print("Added:")
545 by Colin Watson
Make all scripts pass pep8(1).
296
                print_perms([perm])
60 by Colin Watson
add package set manipulation option
297
        return
298
1 by Julian Edwards
new script to edit uploader ACLs
299
    if options.component:
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
300
        for person in people:
301
            if not options.acl_type or options.acl_type == 'upload':
302
                perm = archive.newComponentUploader(
303
                    person=person, component_name=options.component)
304
            else:
305
                perm = archive.newQueueAdmin(
306
                    person=person, component_name=options.component)
359 by Colin Watson
Use Python 3-style print functions.
307
            print("Added:")
545 by Colin Watson
Make all scripts pass pep8(1).
308
            print_perms([perm])
1 by Julian Edwards
new script to edit uploader ACLs
309
        return
310
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
311
    if options.pocket:
593 by Colin Watson
edit-acl: support per-series pocket queue admin permissions
312
        admin_kwargs = {}
313
        if options.series:
314
            admin_kwargs["distroseries"] = options.distro.getSeries(
315
                name_or_version=options.series)
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
316
        for person in people:
583 by Colin Watson
edit-acl: support pocket queue admin permissions
317
            if not options.acl_type or options.acl_type == 'upload':
318
                perm = archive.newPocketUploader(
319
                    person=person, pocket=options.pocket)
320
            else:
321
                perm = archive.newPocketQueueAdmin(
593 by Colin Watson
edit-acl: support per-series pocket queue admin permissions
322
                    person=person, pocket=options.pocket, **admin_kwargs)
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
323
            print("Added:")
545 by Colin Watson
Make all scripts pass pep8(1).
324
            print_perms([perm])
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
325
        return
326
1 by Julian Edwards
new script to edit uploader ACLs
327
328
def do_delete(options):
329
    """Delete a permission."""
607.1.1 by Stefano Rivera
Add support for packageset deletion (urgh, packageset management really doesn't fit well in here)
330
    # We kind of hacked packageset management into here.
331
    # Deleting packagesets doesn't require a person...
332
    requires_person = not (options.packageset and not options.source)
333
    if not validate_add_delete_options(options, requires_person):
1 by Julian Edwards
new script to edit uploader ACLs
334
        return False
102 by Colin Watson
whitespace
335
108 by Colin Watson
edit_acl.py: add per-archive handling
336
    archive = get_archive(options, launchpad)
64 by Colin Watson
bodge in some options to manage package set contents
337
338
    if options.packageset and options.source:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
339
        lp_series = options.distro.getSeries(name_or_version=options.series)
64 by Colin Watson
bodge in some options to manage package set contents
340
        for packageset in options.packageset:
76 by Colin Watson
better fixes for new package set schema
341
            lp_set = launchpad.packagesets.getByName(name=packageset,
342
                                                     distroseries=lp_series)
64 by Colin Watson
bodge in some options to manage package set contents
343
            lp_set.removeSources(names=options.source)
359 by Colin Watson
Use Python 3-style print functions.
344
            print("Deleted:")
64 by Colin Watson
bodge in some options to manage package set contents
345
            for source in options.source:
359 by Colin Watson
Use Python 3-style print functions.
346
                print(source)
64 by Colin Watson
bodge in some options to manage package set contents
347
        return
348
607.1.1 by Stefano Rivera
Add support for packageset deletion (urgh, packageset management really doesn't fit well in here)
349
    if options.packageset and not options.person:
350
        lp_series = options.distro.getSeries(name_or_version=options.series)
351
        for packageset in options.packageset:
352
            lp_set = launchpad.packagesets.getByName(name=packageset,
353
                                                     distroseries=lp_series)
607.1.6 by Stefano Rivera
Check for uploaders before allowing packageset deletion
354
            uploaders = archive.getUploadersForPackageset(
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
355
                direct_permissions=True, packageset=lp_set)
607.1.6 by Stefano Rivera
Check for uploaders before allowing packageset deletion
356
            if len(uploaders) > 0:
357
                print("Cannot delete packageset with defined uploaders")
358
                print("Current uploaders:")
359
                for permission in uploaders:
360
                    print(" %s" % permission.person.name)
361
                continue
607.1.1 by Stefano Rivera
Add support for packageset deletion (urgh, packageset management really doesn't fit well in here)
362
            print("Confirm removal of packageset '%s'" % lp_set.name)
607.1.4 by Stefano Rivera
Multi-line descriptions
363
            print("Description:")
364
            print("  " + lp_set.description.replace("\n", "\n  "))
607.1.5 by Stefano Rivera
Display LP set details before confirming deletion
365
            print("Containing Sources:")
366
            for member in lp_set.getSourcesIncluded():
607.1.7 by Stefano Rivera
Line up output
367
                print("  %s" % member)
607.1.5 by Stefano Rivera
Display LP set details before confirming deletion
368
            print("Containing packagesets:")
369
            for member in lp_set.setsIncluded():
607.1.7 by Stefano Rivera
Line up output
370
                print("  %s" % member.name)
607.1.1 by Stefano Rivera
Add support for packageset deletion (urgh, packageset management really doesn't fit well in here)
371
            ack = input("Remove? (y/N): ")
372
            if ack.lower() == 'y':
607.1.9 by Stefano Rivera
Use the destructor, rather than calling a delete method
373
                lp_set.lp_delete()
607.1.1 by Stefano Rivera
Add support for packageset deletion (urgh, packageset management really doesn't fit well in here)
374
                print("Deleted %s/%s" % (lp_set.name, lp_series.name))
375
        return
376
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
377
    lp_people = [launchpad.people[person] for person in options.person]
1 by Julian Edwards
new script to edit uploader ACLs
378
379
    if options.source:
14 by Colin Watson
allow operating on multiple source packages in a single run
380
        for source in options.source:
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
381
            for lp_person in lp_people:
299 by Colin Watson
edit_acl.py: handle failure to delete upload permission more gracefully
382
                try:
383
                    archive.deletePackageUploader(
384
                        person=lp_person, source_package_name=source)
359 by Colin Watson
Use Python 3-style print functions.
385
                    print("Deleted %s/%s" % (lp_person.name, source))
299 by Colin Watson
edit_acl.py: handle failure to delete upload permission more gracefully
386
                except Exception:
359 by Colin Watson
Use Python 3-style print functions.
387
                    print("Failed to delete %s/%s" % (lp_person.name, source))
1 by Julian Edwards
new script to edit uploader ACLs
388
        return
389
60 by Colin Watson
add package set manipulation option
390
    if options.packageset:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
391
        lp_series = options.distro.getSeries(name_or_version=options.series)
60 by Colin Watson
add package set manipulation option
392
        for packageset in options.packageset:
79 by Colin Watson
fix add/delete to support per-series package sets
393
            lp_set = launchpad.packagesets.getByName(name=packageset,
394
                                                     distroseries=lp_series)
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
395
            for lp_person in lp_people:
396
                archive.deletePackagesetUploader(person=lp_person,
397
                                                 packageset=lp_set)
359 by Colin Watson
Use Python 3-style print functions.
398
                print("Deleted %s/%s/%s" % (lp_person.name, packageset,
399
                                            options.series))
60 by Colin Watson
add package set manipulation option
400
        return
401
1 by Julian Edwards
new script to edit uploader ACLs
402
    if options.component:
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
403
        for lp_person in lp_people:
404
            if not options.acl_type or options.acl_type == 'upload':
405
                archive.deleteComponentUploader(
406
                    person=lp_person, component_name=options.component)
359 by Colin Watson
Use Python 3-style print functions.
407
                print("Deleted %s/%s" % (lp_person.name, options.component))
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
408
            else:
409
                archive.deleteQueueAdmin(
410
                    person=lp_person, component_name=options.component)
359 by Colin Watson
Use Python 3-style print functions.
411
                print("Deleted %s/%s (admin)" % (lp_person.name,
412
                                                 options.component))
1 by Julian Edwards
new script to edit uploader ACLs
413
        return
414
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
415
    if options.pocket:
593 by Colin Watson
edit-acl: support per-series pocket queue admin permissions
416
        admin_kwargs = {}
417
        if options.series:
418
            admin_kwargs["distroseries"] = options.distro.getSeries(
419
                name_or_version=options.series)
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
420
        for lp_person in lp_people:
583 by Colin Watson
edit-acl: support pocket queue admin permissions
421
            if not options.acl_type or options.acl_type == 'upload':
422
                archive.deletePocketUploader(
423
                    person=lp_person, pocket=options.pocket)
424
                print("Deleted %s/%s" % (lp_person.name, options.pocket))
425
            else:
426
                archive.deletePocketQueueAdmin(
593 by Colin Watson
edit-acl: support per-series pocket queue admin permissions
427
                    person=lp_person, pocket=options.pocket, **admin_kwargs)
428
                if options.series:
429
                    print("Deleted %s/%s/%s (admin)" %
430
                          (lp_person.name, options.pocket, options.series))
431
                else:
432
                    print("Deleted %s/%s (admin)" %
433
                          (lp_person.name, options.pocket))
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
434
        return
435
1 by Julian Edwards
new script to edit uploader ACLs
436
70 by Colin Watson
new option to create package sets
437
def do_create(options):
438
    if not options.packageset:
359 by Colin Watson
Use Python 3-style print functions.
439
        print("You can only create a package set, not something else.")
70 by Colin Watson
new option to create package sets
440
        return False
441
232 by Colin Watson
edit_acl.py: improve create checks
442
    if not options.person or len(options.person) != 1:
545 by Colin Watson
Make all scripts pass pep8(1).
443
        print("You must specify exactly one person to own the new package "
444
              "set.")
233 by Colin Watson
edit_acl.py: return False as well as printing an error
445
        return False
446
397.1.1 by Stéphane Graber
edit_acl: Fix create function to accept a distroseries
447
    if options.series:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
448
        distro_series = options.distro.getSeries(
449
            name_or_version=options.series)
397.1.1 by Stéphane Graber
edit_acl: Fix create function to accept a distroseries
450
    else:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
451
        distro_series = options.distro.getDevelopmentSeries()[0]
397.1.1 by Stéphane Graber
edit_acl: Fix create function to accept a distroseries
452
127 by Colin Watson
edit_acl.py: fix person handling when creating a package set
453
    lp_person = launchpad.people[options.person[0]]
70 by Colin Watson
new option to create package sets
454
455
    for packageset in options.packageset:
456
        try:
397.1.1 by Stéphane Graber
edit_acl: Fix create function to accept a distroseries
457
            if launchpad.packagesets.getByName(
458
                    name=packageset, distroseries=distro_series):
359 by Colin Watson
Use Python 3-style print functions.
459
                print("Package set %s already exists" % packageset)
70 by Colin Watson
new option to create package sets
460
                continue
461
        except (TypeError, launchpadlib.errors.HTTPError):
462
            pass
607.1.4 by Stefano Rivera
Multi-line descriptions
463
        desc = multiline_input("Description for new package set %s:"
464
                               % packageset)
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
465
        ps = launchpad.packagesets.new(
466
            name=packageset, description=desc, distroseries=distro_series,
467
            owner=lp_person)
359 by Colin Watson
Use Python 3-style print functions.
468
        print(ps)
70 by Colin Watson
new option to create package sets
469
470
607.1.2 by Stefano Rivera
Add packageset modification to edit-acl
471
def do_modify(options):
472
    if not options.packageset:
473
        print("You can only modify a package set, not something else.")
474
        return False
475
476
    if options.person and len(options.person) > 1:
477
        print("You can only specify one person as the new packageset owner.")
478
        return False
479
480
    if options.series:
481
        distro_series = options.distro.getSeries(
482
            name_or_version=options.series)
483
    else:
484
        distro_series = options.distro.getDevelopmentSeries()[0]
485
486
    lp_person = None
487
    if options.person:
488
        lp_person = launchpad.people[options.person[0]]
489
490
    for packageset in options.packageset:
491
        lp_set = launchpad.packagesets.getByName(
492
            name=packageset, distroseries=distro_series)
493
        if lp_person:
494
            print("Making %s the owner of %s/%s"
495
                  % (lp_person.name, lp_set.name, distro_series.name))
496
            lp_set.owner = lp_person
497
            lp_set.lp_save()
498
            continue
499
607.1.4 by Stefano Rivera
Multi-line descriptions
500
        print("Current description of %s:" % lp_set.name)
501
        print("  " + lp_set.description.replace("\n", "\n  "))
502
        desc = multiline_input("New description [blank=leave unmodified]:")
607.1.2 by Stefano Rivera
Add packageset modification to edit-acl
503
        if desc:
504
            print("Modifying description of %s/%s"
505
                  % (lp_set.name, distro_series.name))
506
            lp_set.description = desc
507
            lp_set.lp_save()
508
            continue
509
510
        rename = input("Rename %s to? [blank=don't rename]: " % lp_set.name)
511
        if rename:
512
            print("Renaming %s/%s -> %s"
513
                  % (lp_set.name, distro_series.name, rename))
514
            lp_set.name = rename
515
            lp_set.lp_save()
516
            continue
517
518
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
519
def do_copy(options):
520
    if options.archive is None:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
521
        archives = options.distro.archives
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
522
    else:
523
        archives = [get_archive(options, launchpad)]
524
525
    if not options.packageset:
526
        print("You can only copy a package set, not something else.")
527
        return False
528
529
    if options.series:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
530
        distro_series = options.distro.getSeries(
531
            name_or_version=options.series)
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
532
    else:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
533
        distro_series = options.distro.getDevelopmentSeries()[0]
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
534
455 by Colin Watson
edit_acl.py: tweak to restore Python 3 compatibility
535
    dst = input("Name of the destination series: ")
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
536
    dst_series = options.distro.getSeries(name_or_version=dst)
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
537
538
    for packageset in options.packageset:
539
        src_pkgset = launchpad.packagesets.getByName(
545 by Colin Watson
Make all scripts pass pep8(1).
540
            name=packageset, distroseries=distro_series)
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
541
        if not src_pkgset:
542
            print("Package set %s doesn't exist" % packageset)
543
545 by Colin Watson
Make all scripts pass pep8(1).
544
        ps = launchpad.packagesets.new(
545
            name=packageset, description=src_pkgset.description,
673 by Stéphane Graber
edit-acl: On copy, set the related_set property to the source packageset.
546
            distroseries=dst_series, owner=src_pkgset.owner_link,
547
            related_set=src_pkgset)
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
548
        print(ps)
549
550
        ps.addSources(names=src_pkgset.getSourcesIncluded())
551
552
        perms = []
553
        for archive in archives:
554
            perms.extend(archive.getUploadersForPackageset(
555
                packageset=src_pkgset))
556
557
        for perm in perms:
672 by Stéphane Graber
edit-acl: When copying a packageset, add the upload permission to the same archive as the source, instead of the last one in the list.
558
            perm.archive.newPackagesetUploader(
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
559
                person=perm.person_link, packageset=ps)
560
561
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
562
def do_check(options):
563
    """Check if a person can upload a package."""
564
    if not options.person:
359 by Colin Watson
Use Python 3-style print functions.
565
        print("A person needs to be specified to check.")
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
566
        return False
567
    if not options.source:
359 by Colin Watson
Use Python 3-style print functions.
568
        print("A source package needs to be specified to check.")
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
569
        return False
570
571
    archive = get_archive(options, launchpad)
572
    people = [launchpad.people[person] for person in options.person]
573
574
    if options.series:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
575
        distro_series = options.distro.getSeries(
576
            name_or_version=options.series)
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
577
    else:
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
578
        distro_series = options.distro.getDevelopmentSeries()[0]
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
579
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
580
    if options.pocket:
581
        pocket = options.pocket
582
    else:
583
        pocket = 'Release'
584
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
585
    for person in people:
586
        for srcpkg in options.source:
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
587
            try:
588
                spph = archive.getPublishedSources(
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
589
                    distro_series=distro_series,
590
                    exact_match=True,
591
                    pocket=pocket,
592
                    source_name=srcpkg,
593
                    status='Published',
594
                )[0]
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
595
            except IndexError:
596
                if not options.pocket:
597
                    raise
598
                # Not yet in options.pocket, but maybe in Release?
599
                spph = archive.getPublishedSources(
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
600
                    distro_series=distro_series,
601
                    exact_match=True,
602
                    pocket='Release',
603
                    source_name=srcpkg,
604
                    status='Published',
605
                )[0]
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
606
            try:
607
                archive.checkUpload(
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
608
                    component=spph.component_name,
609
                    distroseries=distro_series,
610
                    person=person,
611
                    pocket=pocket,
612
                    sourcepackagename=srcpkg,
613
                )
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
614
                print("%s (%s) can upload %s to %s/%s" % (
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
615
                    person.display_name, person.name,
616
                    srcpkg, distro_series.displayname, pocket))
360 by Colin Watson
Use "except Exception as e" syntax rather than the old-style "except Exception, e".
617
            except launchpadlib.errors.HTTPError as e:
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
618
                if e.response.status == 403:
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
619
                    print("%s (%s) cannot upload %s to %s/%s" % (
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
620
                        person.display_name, person.name,
621
                        srcpkg, distro_series.displayname, pocket))
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
622
                else:
359 by Colin Watson
Use Python 3-style print functions.
623
                    print("There was a %s error:" % e.response.status)
624
                    print(e.content)
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
625
626
1 by Julian Edwards
new script to edit uploader ACLs
627
def main(options, action):
628
629
    if action == "query":
630
        do_query(options)
631
    elif action == "add":
632
        do_add(options)
63 by Colin Watson
make "remove" a synonym for "delete"
633
    elif action in ("delete", "remove"):
1 by Julian Edwards
new script to edit uploader ACLs
634
        do_delete(options)
70 by Colin Watson
new option to create package sets
635
    elif action == "create":
636
        do_create(options)
607.1.2 by Stefano Rivera
Add packageset modification to edit-acl
637
    elif action == "modify":
638
        do_modify(options)
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
639
    elif action == "copy":
640
        do_copy(options)
122.1.3 by Michael Bienia
Add an option to edit_acl.py to check if a person has upload permissions for a
641
    elif action == "check":
642
        do_check(options)
1 by Julian Edwards
new script to edit uploader ACLs
643
    else:
644
        raise AssertionError("Invalid action %s" % action)
645
646
    return
647
648
649
if __name__ == '__main__':
545 by Colin Watson
Make all scripts pass pep8(1).
650
    parser = OptionParser(
607.1.2 by Stefano Rivera
Add packageset modification to edit-acl
651
        usage="usage: %prog [options] "
652
              "query|add|delete|create|modify|copy|check")
1 by Julian Edwards
new script to edit uploader ACLs
653
654
    parser.add_option(
179 by Colin Watson
switch to production by default (http://blog.launchpad.net/general/edge-is-deprecated)
655
        "-l", "--launchpad", dest="launchpad_instance", default="production")
108 by Colin Watson
edit_acl.py: add per-archive handling
656
    parser.add_option("-A", "--archive", dest="archive")
122 by Colin Watson
edit_acl.py: allow operating on multiple people at once
657
    parser.add_option("-p", "--person", dest="person", action="append")
1 by Julian Edwards
new script to edit uploader ACLs
658
    parser.add_option("-c", "--component", dest="component")
60 by Colin Watson
add package set manipulation option
659
    parser.add_option("-P", "--packageset", dest="packageset", action="append")
76 by Colin Watson
better fixes for new package set schema
660
    parser.add_option("-S", "--series", dest="series")
14 by Colin Watson
allow operating on multiple source packages in a single run
661
    parser.add_option("-s", "--source", dest="source", action="append")
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
662
    parser.add_option("--pocket", dest="pocket")
5 by Colin Watson
allow specifying an ACL type
663
    parser.add_option("-t", "--acl-type", dest="acl_type",
664
                      help="ACL type: upload or admin")
178.1.1 by Michael Bienia
Add basic support for anonymous LP login for "query" and "check"
665
    parser.add_option("--anon", dest="anon_login", action="store_true",
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
666
                      default=False, help="Login anonymously to Launchpad")
1 by Julian Edwards
new script to edit uploader ACLs
667
668
    options, args = parser.parse_args()
669
397.1.2 by Stéphane Graber
edit_acl: Add initial copy function for package sets
670
    possible_actions = ('query', 'add', 'delete', 'create', 'copy', 'check')
1 by Julian Edwards
new script to edit uploader ACLs
671
672
    if len(args) != 1:
673
        parser.error(
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
674
            "You must specify an action, one of:\n%s" %
675
            ", ".join(possible_actions))
1 by Julian Edwards
new script to edit uploader ACLs
676
178.1.1 by Michael Bienia
Add basic support for anonymous LP login for "query" and "check"
677
    if options.anon_login and args[0] not in ('query', 'check'):
359 by Colin Watson
Use Python 3-style print functions.
678
        print("E: Anonymous login not supported for this action.")
178.1.1 by Michael Bienia
Add basic support for anonymous LP login for "query" and "check"
679
        sys.exit(1)
680
60 by Colin Watson
add package set manipulation option
681
    if (not options.person and not options.component and
677 by Colin Watson
make all scripts pass current stricter pep8(1) in raring
682
            not options.packageset and not options.source and
683
            not options.pocket):
60 by Colin Watson
add package set manipulation option
684
        parser.error("Provide at least one of "
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
685
                     "person/component/packageset/source/pocket")
76 by Colin Watson
better fixes for new package set schema
686
    if options.packageset and not options.series:
687
        parser.error("Package set requires an associated series")
5 by Colin Watson
allow specifying an ACL type
688
    if options.acl_type and options.acl_type not in ('upload', 'admin'):
689
        parser.error("Invalid ACL type '%s' (valid: 'upload', 'admin')" %
690
                     options.acl_type)
60 by Colin Watson
add package set manipulation option
691
    if options.acl_type == 'admin' and options.packageset:
692
        parser.error("ACL type admin not allowed for package sets")
5 by Colin Watson
allow specifying an ACL type
693
    if options.acl_type == 'admin' and options.source:
694
        parser.error("ACL type admin not allowed for source packages")
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
695
    if options.pocket:
696
        options.pocket = options.pocket.title()
1 by Julian Edwards
new script to edit uploader ACLs
697
178.1.1 by Michael Bienia
Add basic support for anonymous LP login for "query" and "check"
698
    if options.anon_login:
351 by Colin Watson
Replace lputils with direct calls to Launchpad.login_with or Launchpad.login_anonymously as appropriate.
699
        launchpad = Launchpad.login_anonymously(
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
700
            CONSUMER_KEY, options.launchpad_instance, version="devel")
178.1.1 by Michael Bienia
Add basic support for anonymous LP login for "query" and "check"
701
    else:
351 by Colin Watson
Replace lputils with direct calls to Launchpad.login_with or Launchpad.login_anonymously as appropriate.
702
        launchpad = Launchpad.login_with(
475 by Colin Watson
edit_acl.py: Handle pocket upload permissions.
703
            CONSUMER_KEY, options.launchpad_instance, version="devel")
573 by Colin Watson
edit-acl: look up launchpad.distributions["ubuntu"] in just one place
704
    options.distro = launchpad.distributions["ubuntu"]
178.1.1 by Michael Bienia
Add basic support for anonymous LP login for "query" and "check"
705
1 by Julian Edwards
new script to edit uploader ACLs
706
    try:
707
        main(options, args[0])
360 by Colin Watson
Use "except Exception as e" syntax rather than the old-style "except Exception, e".
708
    except launchpadlib.errors.HTTPError as err:
359 by Colin Watson
Use Python 3-style print functions.
709
        print("There was a %s error:" % err.response.status)
710
        print(err.content)