From 95487419e7f9a749c789f81287fcb5e1a4eeb503 Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Thu, 4 Feb 2010 00:37:02 +0100 Subject: [PATCH 01/11] ubuntutools/requestsync/{lp,mail}.py: Replace the relative imports with absolute ones (follow PEP8) --- ubuntutools/requestsync/lp.py | 8 ++++---- ubuntutools/requestsync/mail.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ubuntutools/requestsync/lp.py b/ubuntutools/requestsync/lp.py index e20d0ac..efd5abc 100644 --- a/ubuntutools/requestsync/lp.py +++ b/ubuntutools/requestsync/lp.py @@ -20,10 +20,10 @@ # Please see the /usr/share/common-licenses/GPL-2 file for the full text # of the GNU General Public License license. -from .common import raw_input_exit_on_ctrlc -from ..lp.lpapicache import Launchpad, Distribution, PersonTeam, DistributionSourcePackage -from ..lp.udtexceptions import PackageNotFoundException, SeriesNotFoundException, PocketDoesNotExistException, ArchiveNotFoundException -from ..lp.libsupport import translate_api_web +from ubuntutools.requestsync.common import raw_input_exit_on_ctrlc +from ubuntutools.lp.lpapicache import Launchpad, Distribution, PersonTeam, DistributionSourcePackage +from ubuntutools.lp.udtexceptions import PackageNotFoundException, SeriesNotFoundException, PocketDoesNotExistException, ArchiveNotFoundException +from ubuntutools.lp.libsupport import translate_api_web def getDebianSrcPkg(name, release): debian = Distribution('debian') diff --git a/ubuntutools/requestsync/mail.py b/ubuntutools/requestsync/mail.py index 2e2d2b1..7b8b101 100644 --- a/ubuntutools/requestsync/mail.py +++ b/ubuntutools/requestsync/mail.py @@ -25,8 +25,8 @@ import subprocess import smtplib import socket from debian_bundle.changelog import Version -from .common import raw_input_exit_on_ctrlc -from ..lp.udtexceptions import PackageNotFoundException +from ubuntutools.requestsync.common import raw_input_exit_on_ctrlc +from ubuntutools.lp.udtexceptions import PackageNotFoundException __all__ = [ 'getDebianSrcPkg', From a33a5c106b12c1589a2345bc12d1f9bcf89efcc2 Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Sat, 6 Feb 2010 01:53:29 +0100 Subject: [PATCH 02/11] ubuntutools/lp/__init__.py: Define the default LP service to use (default: edge) ubuntutools/lp/__init__.py: Don't hardcode the LP service root but look it up instead debian/control: Depend on python-launchpadlib >= 1.5.4 because of this --- debian/control | 2 +- ubuntutools/lp/__init__.py | 2 ++ ubuntutools/lp/lpapicache.py | 24 ++++++++++++++---------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/debian/control b/debian/control index ad7766f..50df308 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,7 @@ Standards-Version: 3.8.3 Package: ubuntu-dev-tools Architecture: all Depends: ${python:Depends}, ${misc:Depends}, binutils, devscripts, sudo, - python-debian, python-launchpadlib, dctrl-tools, lsb-release, diffstat, + python-debian, python-launchpadlib (>= 1.5.4), dctrl-tools, lsb-release, diffstat, dpkg-dev, python-apt (>= 0.7.9), python-lazr.restfulclient Recommends: bzr, pbuilder | cowdancer | sbuild, reportbug (>= 3.39ubuntu1), ca-certificates, debootstrap, genisoimage, perl-modules, libwww-perl, diff --git a/ubuntutools/lp/__init__.py b/ubuntutools/lp/__init__.py index 17f4f3d..e3aabb3 100644 --- a/ubuntutools/lp/__init__.py +++ b/ubuntutools/lp/__init__.py @@ -1,3 +1,5 @@ ## ## ubuntu-dev-tools Launchpad Python modules. ## + +service = 'edge' diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py index 2c8c626..6ad7b4e 100644 --- a/ubuntutools/lp/lpapicache.py +++ b/ubuntutools/lp/lpapicache.py @@ -3,7 +3,7 @@ # lpapicache.py - wrapper classes around the LP API implementing caching # for usage in the ubuntu-dev-tools package # -# Copyright © 2009 Michael Bienia +# Copyright © 2009-2010 Michael Bienia # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -25,10 +25,14 @@ #httplib2.debuglevel = 1 import sys -import libsupport + from launchpadlib.errors import HTTPError +from launchpadlib.uris import lookup_service_root from lazr.restfulclient.resource import Entry -from udtexceptions import * + +import ubuntutools.lp.libsupport as libsupport +from ubuntutools.lp import service +from ubuntutools.lp.udtexceptions import * class Launchpad(object): ''' Singleton for LP API access. ''' @@ -125,7 +129,7 @@ class Distribution(BaseWrapper): ''' Wrapper class around a LP distribution object. ''' - resource_type = 'https://api.edge.launchpad.net/beta/#distribution' + resource_type = lookup_service_root(service) + '#distribution' def __init__(self, *args): # Don't share _series and _archives between different Distributions @@ -207,14 +211,14 @@ class DistroSeries(BaseWrapper): ''' Wrapper class around a LP distro series object. ''' - resource_type = 'https://api.edge.launchpad.net/beta/#distro_series' + resource_type = lookup_service_root(service) + '#distro_series' class Archive(BaseWrapper): ''' Wrapper class around a LP archive object. ''' - resource_type = 'https://api.edge.launchpad.net/beta/#archive' + resource_type = lookup_service_root(service) + '#archive' def __init__(self, *args): # Don't share _srcpkgs between different Archives @@ -275,7 +279,7 @@ class SourcePackagePublishingHistory(BaseWrapper): ''' Wrapper class around a LP source package object. ''' - resource_type = 'https://api.edge.launchpad.net/beta/#source_package_publishing_history' + resource_type = lookup_service_root(service) + '#source_package_publishing_history' def __init__(self, *args): # Don't share _builds between different SourcePackagePublishingHistory objects @@ -356,7 +360,7 @@ class PersonTeam(BaseWrapper): ''' Wrapper class around a LP person or team object. ''' - resource_type = ('https://api.edge.launchpad.net/beta/#person', 'https://api.edge.launchpad.net/beta/#team') + resource_type = (lookup_service_root(service) + '#person', lookup_service_root(service) + '#team') _me = None # the PersonTeam object of the currently authenticated LP user @@ -459,7 +463,7 @@ class Build(BaseWrapper): ''' Wrapper class around a build object. ''' - resource_type = 'https://api.edge.launchpad.net/beta/#build' + resource_type = lookup_service_root(service) + '#build' def __str__(self): return u'%s: %s' % (self.arch_tag, self.buildstate) @@ -481,4 +485,4 @@ class DistributionSourcePackage(BaseWrapper): ''' Caching class for distribution_source_package objects. ''' - resource_type = 'https://api.edge.launchpad.net/beta/#distribution_source_package' + resource_type = lookup_service_root(service) + '#distribution_source_package' From 4f21ae1cd0b835b160d5e2ef89d59da83cbab7e1 Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Fri, 12 Feb 2010 18:47:02 +0100 Subject: [PATCH 03/11] Replace translate_service() from ubuntutools.lp.libsupport with calls to lookup_service_root() from launchpadlib.uris. --- manage-credentials | 3 ++- ubuntutools/lp/libsupport.py | 17 ++++------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/manage-credentials b/manage-credentials index fa303e2..679d714 100755 --- a/manage-credentials +++ b/manage-credentials @@ -22,6 +22,7 @@ import os import sys from optparse import OptionParser, make_option +from launchpadlib.uris import lookup_service_root from ubuntutools.lp.libsupport import * class CmdOptions(OptionParser): @@ -77,7 +78,7 @@ class CmdOptions(OptionParser): optional_options = given_options - set(sum(self.TOOLS[tool], ())) if optional_options: self.error("The following options are not allowed for this tool: %s" %", ".join(optional_options)) - options.service = translate_service(options.service) + options.service = lookup_service_root(options.service) if options.level in LEVEL: options.level = LEVEL[options.level] elif options.level.upper() in LEVEL.values(): diff --git a/ubuntutools/lp/libsupport.py b/ubuntutools/lp/libsupport.py index 319b713..c42753e 100644 --- a/ubuntutools/lp/libsupport.py +++ b/ubuntutools/lp/libsupport.py @@ -28,7 +28,7 @@ import httplib2 try: from launchpadlib.credentials import Credentials - from launchpadlib.launchpad import Launchpad, STAGING_SERVICE_ROOT, EDGE_SERVICE_ROOT + from launchpadlib.launchpad import Launchpad from launchpadlib.errors import HTTPError except ImportError: print "Unable to import launchpadlib module, is python-launchpadlib installed?" @@ -37,6 +37,8 @@ except: Credentials = None Launchpad = None +from ubuntutools.lp import service + def find_credentials(consumer, files, level=None): """ search for credentials matching 'consumer' in path for given access level. """ if Credentials is None: @@ -73,7 +75,7 @@ def get_credentials(consumer, cred_file=None, level=None): return find_credentials(consumer, files, level) -def get_launchpad(consumer, server=EDGE_SERVICE_ROOT, cache=None, +def get_launchpad(consumer, server=service, cache=None, cred_file=None, level=None): credentials = get_credentials(consumer, cred_file, level) cache = cache or os.environ.get("LPCACHE", None) @@ -140,14 +142,3 @@ def approve_application(credentials, email, password, level, web_root, raise HTTPError(response, content) credentials.exchange_request_token_for_access_token(web_root) return credentials - -def translate_service(service): - _service = service.lower() - if _service in (STAGING_SERVICE_ROOT, EDGE_SERVICE_ROOT): - return _service - elif _service == "edge": - return EDGE_SERVICE_ROOT - elif _service == "staging": - return STAGING_SERVICE_ROOT - else: - raise ValueError("unknown service '%s'" %service) From b1017120096398a6faa3bfee8c929169407348ee Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Fri, 12 Feb 2010 19:36:08 +0100 Subject: [PATCH 04/11] ubuntutools/lp/lpapicache.py: Add __repr__() to the BaseWrapper class --- ubuntutools/lp/lpapicache.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py index 6ad7b4e..fbd807d 100644 --- a/ubuntutools/lp/lpapicache.py +++ b/ubuntutools/lp/lpapicache.py @@ -124,6 +124,11 @@ class BaseWrapper(object): def __getattr__(self, attr): return getattr(self._lpobject, attr) + def __repr__(self): + if hasattr(str, 'format'): + return '<{0}: {1!r}>'.format(self.__class__.__name__, self._lpobject) + else: + return '<%s: %r>' % (self.__class__.__name__, self._lpobject) class Distribution(BaseWrapper): ''' From caafd18fb9b659ff483e12cca21df2bd29b58ed6 Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Sat, 20 Feb 2010 15:18:52 +0100 Subject: [PATCH 05/11] ubuntutools/lp/lpapicache.py: Re-add dropped "beta/" to the resource type URLs Use lookup_service_root() when checking for LP API URLs --- ubuntutools/lp/lpapicache.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py index fbd807d..0ba5661 100644 --- a/ubuntutools/lp/lpapicache.py +++ b/ubuntutools/lp/lpapicache.py @@ -79,7 +79,7 @@ class BaseWrapper(object): resource_type = None # it's a base class after all def __new__(cls, data): - if isinstance(data, basestring) and data.startswith('https://api.edge.launchpad.net/beta/'): + if isinstance(data, basestring) and data.startswith(lookup_service_root(service) + 'beta/'): # looks like a LP API URL # check if it's already cached cached = cls._cache.get(data) @@ -134,7 +134,7 @@ class Distribution(BaseWrapper): ''' Wrapper class around a LP distribution object. ''' - resource_type = lookup_service_root(service) + '#distribution' + resource_type = lookup_service_root(service) + 'beta/#distribution' def __init__(self, *args): # Don't share _series and _archives between different Distributions @@ -216,14 +216,14 @@ class DistroSeries(BaseWrapper): ''' Wrapper class around a LP distro series object. ''' - resource_type = lookup_service_root(service) + '#distro_series' + resource_type = lookup_service_root(service) + 'beta/#distro_series' class Archive(BaseWrapper): ''' Wrapper class around a LP archive object. ''' - resource_type = lookup_service_root(service) + '#archive' + resource_type = lookup_service_root(service) + 'beta/#archive' def __init__(self, *args): # Don't share _srcpkgs between different Archives @@ -284,7 +284,7 @@ class SourcePackagePublishingHistory(BaseWrapper): ''' Wrapper class around a LP source package object. ''' - resource_type = lookup_service_root(service) + '#source_package_publishing_history' + resource_type = lookup_service_root(service) + 'beta/#source_package_publishing_history' def __init__(self, *args): # Don't share _builds between different SourcePackagePublishingHistory objects @@ -365,7 +365,10 @@ class PersonTeam(BaseWrapper): ''' Wrapper class around a LP person or team object. ''' - resource_type = (lookup_service_root(service) + '#person', lookup_service_root(service) + '#team') + resource_type = ( + lookup_service_root(service) + 'beta/#person', + lookup_service_root(service) + 'beta/#team', + ) _me = None # the PersonTeam object of the currently authenticated LP user @@ -468,7 +471,7 @@ class Build(BaseWrapper): ''' Wrapper class around a build object. ''' - resource_type = lookup_service_root(service) + '#build' + resource_type = lookup_service_root(service) + 'beta/#build' def __str__(self): return u'%s: %s' % (self.arch_tag, self.buildstate) @@ -490,4 +493,4 @@ class DistributionSourcePackage(BaseWrapper): ''' Caching class for distribution_source_package objects. ''' - resource_type = lookup_service_root(service) + '#distribution_source_package' + resource_type = lookup_service_root(service) + 'beta/#distribution_source_package' From 0dfe4b473162076ba7d53c6caf095df0d3bfd085 Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Sat, 20 Feb 2010 15:48:48 +0100 Subject: [PATCH 06/11] ubuntutools/lp/lpapicache.py: * PersonTeam.canUploadPackage() can now also check package sets for upload permissions. This requires now to also pass the distroseries as package sets are per distroseries. * Drop PersonTeam.isPerPackageUploader() as it's also handled by canUploadPackage() ubuntu-build: Update for the PersonTeam.canUploadChange(). ubuntutools/requestsync/{lp,mail}.py: * needSponsorship() now also expects a release name because of the above mentioned change to PersonTeam.canUploadPackage(). requestsync: Update for needSponsorship() change. --- requestsync | 8 +------ ubuntu-build | 3 ++- ubuntutools/lp/lpapicache.py | 41 +++++++++++++++------------------ ubuntutools/requestsync/lp.py | 5 ++-- ubuntutools/requestsync/mail.py | 4 ++-- 5 files changed, 27 insertions(+), 34 deletions(-) diff --git a/requestsync b/requestsync index 355d434..bc276f7 100755 --- a/requestsync +++ b/requestsync @@ -148,7 +148,7 @@ if __name__ == '__main__': # -s flag not specified - check if we do need sponsorship if not sponsorship: - sponsorship = needSponsorship(srcpkg, ubuntu_component) + sponsorship = needSponsorship(srcpkg, ubuntu_component, release) # Check for existing package reports if not newsource: @@ -183,12 +183,6 @@ if __name__ == '__main__': if need_interaction: raw_input_exit_on_ctrlc('Press [Enter] to continue. Press [Ctrl-C] to abort now. ') - # Check if they have a per-package upload permission. - if lpapi: - ubuntu_archive = Distribution('ubuntu').getArchive() - if PersonTeam.getMe().isPerPackageUploader(ubuntu_archive, srcpkg): - report += 'Note that I have per-package upload permissions for %s.\n\n' % srcpkg - base_version = force_base_version or ubuntu_version if newsource: diff --git a/ubuntu-build b/ubuntu-build index cef3b1c..93fa7de 100755 --- a/ubuntu-build +++ b/ubuntu-build @@ -132,6 +132,7 @@ if not options.batch: # Get list of published sources for package in question. try: sources = ubuntu_archive.getSourcePackage(package, release, pocket) + distroseries = Distribution('ubuntu').getSeries(release) except (SeriesNotFoundException, PackageNotFoundException), e: print e sys.exit(1) @@ -147,7 +148,7 @@ if not options.batch: me = PersonTeam.getMe() if op == "rescore": necessaryPrivs = me.isLpTeamMember('launchpad-buildd-admins') if op == "retry": necessaryPrivs = me.canUploadPackage( - ubuntu_archive, sources.getPackageName(), sources.getComponent()) + ubuntu_archive, distroseries, sources.getPackageName(), sources.getComponent()) if op in ('rescore', 'retry') and not necessaryPrivs: print >> sys.stderr, "You cannot perform the %s operation on a %s package " \ diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py index 0ba5661..f85decc 100644 --- a/ubuntutools/lp/lpapicache.py +++ b/ubuntutools/lp/lpapicache.py @@ -414,29 +414,38 @@ class PersonTeam(BaseWrapper): ''' return any(t.name == team for t in self.super_teams) - def canUploadPackage(self, archive, package, component): - ''' - Check if the person or team has upload rights for the source package - to the specified 'archive' either through component upload - rights or per-package upload rights. + def canUploadPackage(self, archive, distroseries, package, component): + '''Check if the person or team has upload rights for the source + package to the specified 'archive' and 'distrorelease' either + through package sets, component or or per-package upload rights. Either a source package name or a component has the specified. 'archive' has to be a Archive object. + 'distroseries' has to be an DistroSeries object. ''' if not isinstance(archive, Archive): raise TypeError("'%r' is not an Archive object." % archive) - if package and not isinstance(package, basestring): + if not isinstance(distroseries, DistroSeries): + raise TypeError("'%r' is not a DistroSeries object." % distroseries) + if package is not None and not isinstance(package, basestring): raise TypeError('A source package name expected.') - if component and not isinstance(component, basestring): + if component is not None and not isinstance(component, basestring): raise TypeError('A component name expected.') - if not package and not component: + if package is None and component is None: raise ValueError('Either a source package name or a component has to be specified.') upload_comp = self._upload_comp.get((archive, component)) upload_pkg = self._upload_pkg.get((archive, package)) - if upload_comp == None and upload_pkg == None: - for perm in archive.getPermissionsForPerson(person = self()): + if upload_comp is None and upload_pkg is None: + # archive.isSourceUploadAllowed() checks only package sets permission + if package is not None and archive.isSourceUploadAllowed( + distroseries=distroseries(), person=self(), sourcepackagename=package): + # TODO: also cache the release it applies to + self._upload_pkg[(archive, package)] = True + return True + # check for component or per-package upload rights + for perm in archive.getPermissionsForPerson(person=self()): if perm.permission != 'Archive Upload Rights': continue if component and perm.component_name == component: @@ -454,18 +463,6 @@ class PersonTeam(BaseWrapper): else: return upload_comp or upload_pkg - # TODO: check if this is still needed after ArchiveReorg (or at all) - def isPerPackageUploader(self, archive, package): - ''' - Check if the user has PerPackageUpload rights for package. - ''' - if isinstance(package, SourcePackagePublishingHistory): - pkg = package.getPackageName() - else: - pkg = package - - return self.canUploadPackage(archive, pkg, None) - class Build(BaseWrapper): ''' diff --git a/ubuntutools/requestsync/lp.py b/ubuntutools/requestsync/lp.py index efd5abc..1a97dac 100644 --- a/ubuntutools/requestsync/lp.py +++ b/ubuntutools/requestsync/lp.py @@ -44,14 +44,15 @@ def getUbuntuSrcPkg(name, release): return ubuntu_archive.getSourcePackage(name, release) -def needSponsorship(name, component): +def needSponsorship(name, component, release): ''' Check if the user has upload permissions for either the package itself or the component ''' archive = Distribution('ubuntu').getArchive() + distroseries = Distribution('ubuntu').getSeries(release) - need_sponsor = not PersonTeam.getMe().canUploadPackage(archive, name, component) + need_sponsor = not PersonTeam.getMe().canUploadPackage(archive, distroseries, name, component) if need_sponsor: print '''You are not able to upload this package directly to Ubuntu. Your sync request shall require an approval by a member of the appropriate diff --git a/ubuntutools/requestsync/mail.py b/ubuntutools/requestsync/mail.py index 6a4cd07..a155731 100644 --- a/ubuntutools/requestsync/mail.py +++ b/ubuntutools/requestsync/mail.py @@ -118,7 +118,7 @@ def getEmailAddress(): 'mail the sync request.' return myemailaddr -def needSponsorship(name, component): +def needSponsorship(name, component, release): ''' Ask the user if he has upload permissions for the package or the component. @@ -126,7 +126,7 @@ def needSponsorship(name, component): while True: print "Do you have upload permissions for the '%s' component " \ - "or the package '%s'?" % (component, name) + "or the package '%s' in Ubuntu %s?" % (component, name, release) val = raw_input_exit_on_ctrlc("If in doubt answer 'n'. [y/N]? ") if val.lower() in ('y', 'yes'): return False From 8c114519e87288728ade9372d702c25906d2dc53 Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Sat, 20 Feb 2010 17:07:03 +0100 Subject: [PATCH 07/11] ubuntutools/lp/lpapicache.py: * Add support for anonymous login to the Launchpad singleton. ubuntutools/lp/udtexceptions.py: * Add AlreadyLoggedInError --- ubuntutools/lp/lpapicache.py | 44 +++++++++++++++++++-------------- ubuntutools/lp/udtexceptions.py | 4 +++ 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py index f85decc..5c5a42a 100644 --- a/ubuntutools/lp/lpapicache.py +++ b/ubuntutools/lp/lpapicache.py @@ -26,6 +26,7 @@ import sys +import launchpadlib.launchpad as launchpad from launchpadlib.errors import HTTPError from launchpadlib.uris import lookup_service_root from lazr.restfulclient.resource import Entry @@ -35,28 +36,33 @@ from ubuntutools.lp import service from ubuntutools.lp.udtexceptions import * class Launchpad(object): - ''' Singleton for LP API access. ''' - __lp = None + '''Singleton for LP API access.''' - def login(self): - ''' - Enforce a login through the LP API. - ''' - if not self.__lp: - try: - self.__lp = libsupport.get_launchpad('ubuntu-dev-tools') - except IOError, error: - print >> sys.stderr, 'E: %s' % error - raise error - return self + def login(self): + '''Enforce a non-anonymous login.''' + if '_Launchpad__lp' not in self.__dict__: + try: + self.__lp = libsupport.get_launchpad('ubuntu-dev-tools') + except IOError, error: + print >> sys.stderr, 'E: %s' % error + raise + else: + raise AlreadyLoggedInError('Already logged in to Launchpad.') - def __getattr__(self, attr): - if not self.__lp: - self.login() - return getattr(self.__lp, attr) + def login_anonymously(self): + '''Enforce an anonymous login.''' + if '_Launchpad__lp' not in self.__dict__: + self.__lp = launchpad.Launchpad.login_anonymously('ubuntu-dev-tools', service) + else: + raise AlreadyLoggedInError('Already logged in to Launchpad.') - def __call__(self): - return self + def __getattr__(self, attr): + if '_Launchpad__lp' not in self.__dict__: + self.login() + return getattr(self.__lp, attr) + + def __call__(self): + return self Launchpad = Launchpad() diff --git a/ubuntutools/lp/udtexceptions.py b/ubuntutools/lp/udtexceptions.py index 5864d09..afe0892 100644 --- a/ubuntutools/lp/udtexceptions.py +++ b/ubuntutools/lp/udtexceptions.py @@ -13,3 +13,7 @@ class PocketDoesNotExistException(BaseException): class ArchiveNotFoundException(BaseException): """ Thrown when an archive for a distibution is not found """ pass + +class AlreadyLoggedInError(Exception): + '''Raised when a second login is attempted.''' + pass From f5c6695e13d1b7ed1b45036f0c853255ca4e4e3c Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Sat, 20 Feb 2010 18:13:15 +0100 Subject: [PATCH 08/11] ubuntutools/lp/lpapicache.py: * Make PersonTeam.getMe() a class property (PersonTeam.me). ubuntutools/requestsync/lp.py, ubuntu-build: * Update for the above mentioned change. --- ubuntu-build | 4 ++-- ubuntutools/lp/lpapicache.py | 32 ++++++++++++++++++++------------ ubuntutools/requestsync/lp.py | 4 ++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/ubuntu-build b/ubuntu-build index 93fa7de..cc7f93d 100755 --- a/ubuntu-build +++ b/ubuntu-build @@ -145,7 +145,7 @@ if not options.batch: # Operations that are remaining may only be done by Ubuntu developers (retry) # or buildd admins (rescore). Check if the proper permissions are in place. - me = PersonTeam.getMe() + me = PersonTeam.me if op == "rescore": necessaryPrivs = me.isLpTeamMember('launchpad-buildd-admins') if op == "retry": necessaryPrivs = me.canUploadPackage( ubuntu_archive, distroseries, sources.getPackageName(), sources.getComponent()) @@ -216,7 +216,7 @@ if release and '-' in release: sys.exit(1) ubuntu_archive = Distribution('ubuntu').getArchive() -me = PersonTeam.getMe() +me = PersonTeam.me # Check permisions (part 1): Rescoring can only be done by buildd admins can_rescore = options.priority and me.isLpTeamMember('launchpad-buildd-admins') or False diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py index 5c5a42a..da7ee31 100644 --- a/ubuntutools/lp/lpapicache.py +++ b/ubuntutools/lp/lpapicache.py @@ -73,7 +73,7 @@ class MetaWrapper(type): def __init__(cls, name, bases, attrd): super(MetaWrapper, cls).__init__(name, bases, attrd) if 'resource_type' not in attrd: - raise TypeError('Class needs an associated resource type') + raise TypeError('Class "%s" needs an associated resource type' % name) cls._cache = dict() @@ -367,17 +367,34 @@ class SourcePackagePublishingHistory(BaseWrapper): self.getPackageName(), '\n'.join(res)) +class MetaPersonTeam(MetaWrapper): + @property + def me(cls): + '''The PersonTeam object of the currently authenticated LP user or + None when anonymously logged in. + ''' + if '_me' not in cls.__dict__: + try: + cls._me = PersonTeam(Launchpad.me) + except HTTPError, error: + if error.response.status == 401: + # Anonymous login + cls._me = None + else: + raise + return cls._me + class PersonTeam(BaseWrapper): ''' Wrapper class around a LP person or team object. ''' + __metaclass__ = MetaPersonTeam + resource_type = ( lookup_service_root(service) + 'beta/#person', lookup_service_root(service) + 'beta/#team', ) - _me = None # the PersonTeam object of the currently authenticated LP user - def __init__(self, *args): # Don't share _upload_{pkg,comp} between different PersonTeams if '_upload_pkg' not in self.__dict__: @@ -403,15 +420,6 @@ class PersonTeam(BaseWrapper): cached = PersonTeam(Launchpad.people[person_or_team]) return cached - @classmethod - def getMe(cls): - ''' - Returns a PersonTeam object of the currently authenticated LP user. - ''' - if not cls._me: - cls._me = PersonTeam(Launchpad.me) - return cls._me - def isLpTeamMember(self, team): ''' Checks if the user is a member of a certain team on Launchpad. diff --git a/ubuntutools/requestsync/lp.py b/ubuntutools/requestsync/lp.py index 1a97dac..5256836 100644 --- a/ubuntutools/requestsync/lp.py +++ b/ubuntutools/requestsync/lp.py @@ -52,7 +52,7 @@ def needSponsorship(name, component, release): archive = Distribution('ubuntu').getArchive() distroseries = Distribution('ubuntu').getSeries(release) - need_sponsor = not PersonTeam.getMe().canUploadPackage(archive, distroseries, name, component) + need_sponsor = not PersonTeam.me.canUploadPackage(archive, distroseries, name, component) if need_sponsor: print '''You are not able to upload this package directly to Ubuntu. Your sync request shall require an approval by a member of the appropriate @@ -105,7 +105,7 @@ def postBug(srcpkg, subscribe, status, bugtitle, bugtext): # newly created bugreports have only one task task = bug.bug_tasks[0] # only members of ubuntu-bugcontrol can set importance - if PersonTeam.getMe().isLpTeamMember('ubuntu-bugcontrol'): + if PersonTeam.me.isLpTeamMember('ubuntu-bugcontrol'): task.importance = 'Wishlist' task.status = status task.lp_save() From 8377c6bfa31bc54206e9ad3a5399bcb7042ae2c6 Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Sat, 20 Feb 2010 18:19:44 +0100 Subject: [PATCH 09/11] ubuntutools/lp/lpapicache.py: * Specify __all__ --- ubuntutools/lp/lpapicache.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ubuntutools/lp/lpapicache.py b/ubuntutools/lp/lpapicache.py index da7ee31..8e53528 100644 --- a/ubuntutools/lp/lpapicache.py +++ b/ubuntutools/lp/lpapicache.py @@ -35,6 +35,17 @@ import ubuntutools.lp.libsupport as libsupport from ubuntutools.lp import service from ubuntutools.lp.udtexceptions import * +__all__ = [ + 'Archive', + 'Build', + 'Distribution', + 'DistributionSourcePackage', + 'DistroSeries', + 'Launchpad', + 'PersonTeam', + 'SourcePackagePublishingHistory', + ] + class Launchpad(object): '''Singleton for LP API access.''' From 1cfe684420be269afbd0c2a9b1978b2595a1a085 Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Sat, 20 Feb 2010 18:36:12 +0100 Subject: [PATCH 10/11] requestsync: * Add an error message when Ubuntu has a newer version than Debian. --- requestsync | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/requestsync b/requestsync index bc276f7..c1dc074 100755 --- a/requestsync +++ b/requestsync @@ -78,7 +78,7 @@ if __name__ == '__main__': # import the needed requestsync module if options.lpapi: from ubuntutools.requestsync.lp import * - from ubuntutools.lp.lpapicache import Distribution, PersonTeam + from ubuntutools.lp.lpapicache import Distribution # See if we have LP credentials and exit if we don't - cannot continue in this case try: Launchpad.login() @@ -140,11 +140,15 @@ if __name__ == '__main__': print >> sys.stderr, "E: %s" % e sys.exit(1) - # Debian and Ubuntu versions are the same - stop + # Stop if Ubuntu has already the version from Debian or a newer version if ubuntu_version == debian_version: print >> sys.stderr, \ 'E: The versions in Debian and Ubuntu are the same already (%s). Aborting.' % ubuntu_version sys.exit(1) + if ubuntu_version > debian_version: + print >> sys.stderr, \ + 'E: The version in Ubuntu (%s) is newer than the version in Debian (%s). Aborting.' % (ubuntu_version, debian_version) + sys.exit(1) # -s flag not specified - check if we do need sponsorship if not sponsorship: From e3eaaab7552d8dca12e549739c323f89b44e86bb Mon Sep 17 00:00:00 2001 From: Michael Bienia Date: Sat, 20 Feb 2010 18:44:14 +0100 Subject: [PATCH 11/11] Document important changes in debian/changelog --- debian/changelog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index df0c434..0b44ca8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -25,8 +25,11 @@ ubuntu-dev-tools (0.93) UNRELEASED; urgency=low [ Michael Bienia ] * ubuntutools/requestsync/mail.py: Encode the report to utf-8 before passing it to gpg for signing (lp: #522316). + * Add support for the other LP service roots (edge is still default) + * Depend on python-launchpadlib >= 1.5.4 + * Also check package sets for upload permissions. - -- Michael Bienia Mon, 15 Feb 2010 22:37:59 +0100 + -- Michael Bienia Sat, 20 Feb 2010 18:38:17 +0100 ubuntu-dev-tools (0.92) lucid; urgency=low