* ubuntutools/lp/lp_functions.py,

ubuntutools/lp/udtexceptions.py:
  - Add new public functions that expose features from LP API
  - Modify isLPTeamMember to use LP API
* requestsync
  - Use new functions to check if user can upload requested package directly
    instead of checking team membership
  - Default to current development release if no release is specified on
    commandline
* buildd
  - Check if user has upload privileges instead of checking for team
    membership when seeing if operations are permitted
This commit is contained in:
Iain Lane 2009-05-09 20:09:56 +01:00
parent dc4750eb91
commit b4cd975dc8
6 changed files with 176 additions and 69 deletions

11
buildd
View File

@ -116,7 +116,7 @@ packages.checkReleaseExists(release)
(page, version) = packages.checkSourceExists(package, release) (page, version) = packages.checkSourceExists(package, release)
# Get the component the package is in. # Get the component the package is in.
component = packages.packageComponent(package, release) component = lp_functions.packageComponent(package, release)
# Output details. # Output details.
print "The source version for '%s' in %s (%s) is at %s." % (package, print "The source version for '%s' in %s (%s) is at %s." % (package,
@ -156,14 +156,9 @@ if len(buildstats) == 1 and options.architecture != "i386":
# Operations that are remaining may only be done by Ubuntu developers (retry) # Operations that are remaining may only be done by Ubuntu developers (retry)
# or buildd admins (rescore). Check if the proper permissions are in place. # or buildd admins (rescore). Check if the proper permissions are in place.
if op == "rescore": teamNeeded = "launchpad-buildd-admins" if op == "rescore": necessaryPrivs = lp_functions.isLPTeamMember('launchpad-buildd-admins')
if op == "retry": if op == "retry":
if component in ("main", "restricted"): necessaryPrivs = lp_functions.canUploadPackage(package, release)
teamNeeded = "ubuntu-core-dev"
else:
teamNeeded = "ubuntu-dev"
necessaryPrivs = lp_functions.isLPTeamMember(teamNeeded)
if not necessaryPrivs: if not necessaryPrivs:
print >> sys.stderr, "You cannot perform the %s operation on a %s package " \ print >> sys.stderr, "You cannot perform the %s operation on a %s package " \

16
debian/changelog vendored
View File

@ -13,7 +13,21 @@ ubuntu-dev-tools (0.74) UNRELEASED; urgency=low
- Delete the directory just after creating it if the package - Delete the directory just after creating it if the package
doesn't exist. doesn't exist.
-- Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com> Wed, 06 May 2009 23:14:33 +0200 [ Iain Lane ]
* ubuntutools/lp/lp_functions.py,
ubuntutools/lp/udtexceptions.py:
- Add new public functions that expose features from LP API
- Modify isLPTeamMember to use LP API
* requestsync
- Use new functions to check if user can upload requested package directly
instead of checking team membership
- Default to current development release if no release is specified on
commandline
* buildd
- Check if user has upload privileges instead of checking for team
membership when seeing if operations are permitted
-- Iain Lane <laney@ubuntu.com> Sat, 09 May 2009 20:09:28 +0100
ubuntu-dev-tools (0.73) karmic; urgency=low ubuntu-dev-tools (0.73) karmic; urgency=low

View File

@ -2,7 +2,7 @@
.SH NAME .SH NAME
requestsync \- helper to file sync requests for Ubuntu requestsync \- helper to file sync requests for Ubuntu
.SH SYNOPSIS .SH SYNOPSIS
.B requestsync\fR [\fB\-d distro\fR] [\fB\-nse\fR] [\fB\-k \fIkeyid\fR] <\fBsource package\fR> <\fBtarget release\fR> [\fIbase version\fR] .B requestsync\fR [\fB\-d distro\fR] [\fB\-nse\fR] [\fB\-k \fIkeyid\fR] <\fBsource package\fR> [\fBtarget release\fR] [\fIbase version\fR]
.br .br
.B requestsync \-\-lp\fR [\fB\-nse\fR] <\fBsource package\fR> <\fBtarget release\fR> [\fIbase version\fR] .B requestsync \-\-lp\fR [\fB\-nse\fR] <\fBsource package\fR> <\fBtarget release\fR> [\fIbase version\fR]
.br .br

View File

@ -40,12 +40,13 @@ import ubuntutools.lp.cookie as lp_cookie
import ubuntutools.lp.functions as lp_functions import ubuntutools.lp.functions as lp_functions
import ubuntutools.lp.libsupport as lp_libsupport import ubuntutools.lp.libsupport as lp_libsupport
import ubuntutools.lp.urlopener as lp_urlopener import ubuntutools.lp.urlopener as lp_urlopener
import ubuntutools.lp.udtexceptions as udtexceptions
# https_proxy fix # https_proxy fix
import ubuntutools.common import ubuntutools.common
launchpad_cookiefile = lp_cookie.prepareLaunchpadCookie() launchpad_cookiefile = lp_cookie.prepareLaunchpadCookie()
def checkNeedsSponsorship(component): def checkNeedsSponsorship(srcpkg):
""" """
Check that the user has the appropriate permissions by checking what Check that the user has the appropriate permissions by checking what
Launchpad returns while authenticating with their cookie. Launchpad returns while authenticating with their cookie.
@ -59,25 +60,14 @@ def checkNeedsSponsorship(component):
The prepareLaunchpadCookie function above shall ensure that a cookie The prepareLaunchpadCookie function above shall ensure that a cookie
file exists first. file exists first.
""" """
# TODO: use launchpadlib here
# Once LP: #313233 has been fixed this can be implemented by either:
# >>> me = launchpad.me
# >>> me.inTeam(<TEAM>) #or
# >>> me in <TEAM>
urlopener = lp_urlopener.setupLaunchpadUrlOpener(launchpad_cookiefile)
# Check where the package is and assign the appropriate variables.
if component in ['main', 'restricted']: if component in ['main', 'restricted']:
team = "ubuntu-core-dev" team = "ubuntu-core-dev"
sponsor = "ubuntu-main-sponsors" sponsor = "ubuntu-main-sponsors"
else: else:
team = "ubuntu-dev" team = "motu"
sponsor = "ubuntu-universe-sponsors" sponsor = "ubuntu-universe-sponsors"
# Check if they are a member of the team. if not lp_functions.canUploadPackage(srcpkg):
teamMember = lp_functions.isLPTeamMember(team)
if not teamMember:
# Check if they have a per-package upload permission. # Check if they have a per-package upload permission.
if lp_functions.isPerPackageUploader(args[0]): if lp_functions.isPerPackageUploader(args[0]):
@ -89,11 +79,7 @@ def checkNeedsSponsorship(component):
"the '%s'\nteam, who shall be subscribed to this bug report." % sponsor "the '%s'\nteam, who shall be subscribed to this bug report." % sponsor
print "This must be done before it can be processed by a member of " \ print "This must be done before it can be processed by a member of " \
"the Ubuntu Archive team." "the Ubuntu Archive team."
print "If the above is correct please press Enter, otherwise please " \ print "If the above is correct please press Enter."
"press Ctrl-C to stop this script now\nand check the cookie file " \
"at:", launchpad_cookiefile
print "Logging into Launchpad, deleting the above and rerunning this " \
"script should be enough to generate the cookie."
raw_input_exit_on_ctrlc() # Abort if necessary. raw_input_exit_on_ctrlc() # Abort if necessary.
return True # Sponsorship required. return True # Sponsorship required.
@ -150,18 +136,14 @@ def checkExistingReports(package):
raw_input_exit_on_ctrlc() raw_input_exit_on_ctrlc()
def cur_version_component(sourcepkg, release): def cur_version_component(sourcepkg, release):
'''Determine current package version in ubuntu.'''
madison = subprocess.Popen(['rmadison', '-u', 'ubuntu', '-a', 'source', \
'-s', release, sourcepkg], stdout=subprocess.PIPE)
out = madison.communicate()[0]
assert (madison.returncode == 0)
for l in out.splitlines(): try:
(pkg, version, rel, builds) = l.split('|') version = lp_functions.packageVersion(sourcepkg, release)
component = 'main' component = lp_functions.packageComponent(sourcepkg, release)
if rel.find('/') != -1:
component = rel.split('/')[1] return (version, component)
return (version.strip(), component.strip())
except udtexceptions.PackageNotFoundException:
print "%s doesn't appear to exist in %s, specify -n for a package not in Ubuntu." % (sourcepkg, release) print "%s doesn't appear to exist in %s, specify -n for a package not in Ubuntu." % (sourcepkg, release)
sys.exit(1) sys.exit(1)
@ -505,15 +487,17 @@ if __name__ == '__main__':
distro = options.dist distro = options.dist
ffe = options.ffe ffe = options.ffe
if len(args) not in (2, 3): if len(args) not in (2, 3): # no release specified, assume development release
optParser.error("Source package / target release missing - please " \ release = lp_functions.ubuntuDevelopmentSeries()
"specify.") print >> sys.stderr, ("Source package / target release missing - assuming %s " %
release)
else:
release = args[1]
if not use_lp_bugs and not get_email_address(): if not use_lp_bugs and not get_email_address():
sys.exit(1) sys.exit(1)
srcpkg = args[0] srcpkg = args[0]
release = args[1]
force_base_ver = None force_base_ver = None
# Base version specified. # Base version specified.
@ -534,7 +518,7 @@ if __name__ == '__main__':
sys.exit(1) sys.exit(1)
# -s flag not specified - check if we do need sponsorship. # -s flag not specified - check if we do need sponsorship.
if not sponsorship: sponsorship = checkNeedsSponsorship(component) if not sponsorship: sponsorship = checkNeedsSponsorship(srcpkg)
# Check for existing package reports. # Check for existing package reports.
if not newsource and use_lp_bugs: checkExistingReports(srcpkg) if not newsource and use_lp_bugs: checkExistingReports(srcpkg)

View File

@ -22,45 +22,148 @@ import cookie
import urlopener as lp_urlopener import urlopener as lp_urlopener
import urllib2 import urllib2
import sys import sys
from udtexceptions import PackageNotFoundException, TeamNotFoundException, SeriesNotFoundException
import libsupport as lp_libsupport import libsupport as lp_libsupport
import launchpadlib import launchpadlib
from re import findall from re import findall
# Takes time to initialise - move to top level so we only pay the penalty
# once. Should probably make this a proper class so we can instansiate
# singleton-style (lazily).
launchpad = lp_libsupport.get_launchpad("ubuntu-dev-tools")
def ubuntuDevelopmentSeries():
""" Get the string repr of the current Ubuntu development series """
ubuntu = launchpad.distributions['ubuntu']
return ubuntu.current_series.name
def _ubuntuSeries(name):
""" Get the LP representation of a series
returns the LP API repr of a series passed by name (e.g. 'karmic')
If the series is not found: raise SeriesNotFoundException
"""
ubuntu = launchpad.distributions['ubuntu']
try:
return ubuntu.getSeries(name_or_version=name)
except launchpadlib.errors.HTTPError:
raise SeriesNotFoundException('The series %s was not found' % name)
def _ubuntuSourcePackage(package, series):
""" Finds an Ubuntu source package on LP
returns LP API repr of the source package
If the package does not exist: raise PackageNotFoundException
"""
try:
lpseries = _ubuntuSeries(series)
ubuntu = launchpad.distributions['ubuntu']
u_archive = ubuntu.main_archive
component = u_archive.getPublishedSources(source_name=package, status="Published",
exact_match=True, distro_series=lpseries)[0]
return component
except IndexError:
raise PackageNotFoundException("The package %s does not exist in the Ubuntu main archive" %
package)
def packageVersion(package, series=ubuntuDevelopmentSeries()):
""" Retrieves the version of a given source package in the current
development distroseries
returns unicode string repr of source package version
If the package does not exist: raise PackageNotFoundException
"""
return _ubuntuSourcePackage(package, series).source_package_version
def packageComponent(package, series=ubuntuDevelopmentSeries()):
""" Retrieves the component for a given source package
returns unicode string representation of component
If the package does not exist: raise PackageNotFoundException
"""
return _ubuntuSourcePackage(package, series).component_name
def canUploadPackage(package, series=ubuntuDevelopmentSeries()):
""" Checks whether the user can upload package to Ubuntu's main archive
Uses LP API to do this.
If the user can upload the package: return True.
If the user cannot upload the package: return False.
If the package does not exist: raise PackageNotFoundException
"""
ubuntu = launchpad.distributions['ubuntu']
u_archive = ubuntu.main_archive
uploaders = u_archive.getUploadersForComponent(component_name=packageComponent(package, series))
for permission in uploaders:
current_uploader = permission.person
if _findMember(current_uploader, launchpad.me):
return True
return False
def _findMember(haystack, needle):
""" Find a person in a haystack. A haystack can consist of either people or teams.
If the needle is in the haystack: return True
If the needle is not in the haystack: return False
"""
if not haystack.is_team:
return (str(haystack) == str(needle))
else: # is a team
members = haystack.members
for m in members:
if _findMember(m, needle):
return True
return False
def isLPTeamMember(team): def isLPTeamMember(team):
""" Checks if the user is a member of a certain team on Launchpad. """ Checks if the user is a member of a certain team on Launchpad.
We do this by opening the team page on Launchpad and checking if the Uses the LP API.
text "You are not a member of this team" is present using the
user's cookie file for authentication.
If the user is a member of the team: return True. If the user is a member of the team: return True.
If the user is not a member of the team: return False. If the user is not a member of the team: return False.
If the team is not found: raise a TeamNotFoundException.
""" """
# TODO: Check if launchpadlib may be a better way of doing this.
# Prepare cookie.
cookieFile = cookie.prepareLaunchpadCookie()
# Prepare URL opener.
urlopener = lp_urlopener.setupLaunchpadUrlOpener(cookieFile)
# Try to open the Launchpad team page:
try: try:
lpTeamPage = urlopener.open("https://launchpad.net/~%s" % team).read()
except urllib2.HTTPError, error:
print >> sys.stderr, "Unable to connect to Launchpad. Received a %s." % error.code
sys.exit(1)
# Check if text is present in page. lpteam = launchpad.people[team]
if ("You are not a member of this team") in lpTeamPage:
return False
return True if not lpteam.is_team:
raise KeyError
return _findMember(lpteam, launchpad.me)
except KeyError:
raise TeamNotFoundException("The team %s does not exist on Launchpad" %
team)
def isPerPackageUploader(package): def isPerPackageUploader(package):
# Checks if the user has upload privileges for a certain package. # Checks if the user has upload privileges for a certain package.
launchpad = lp_libsupport.get_launchpad("ubuntu-dev-tools")
me = findall('~(\S+)', '%s' % launchpad.me)[0] me = findall('~(\S+)', '%s' % launchpad.me)[0]
main_archive = launchpad.distributions["ubuntu"].main_archive main_archive = launchpad.distributions["ubuntu"].main_archive
try: try:

View File

@ -0,0 +1,11 @@
class PackageNotFoundException(BaseException):
""" Thrown when a package is not found """
pass
class TeamNotFoundException(BaseException):
""" Thrown when a team is not found """
pass
class SeriesNotFoundException(BaseException):
""" Thrown when a distroseries is not found """
pass