Merge changes from my devel branch:

- ubuntutools/lp/lpapicache.py, ubuntutools/lp/libsupport.py: Add support
  for different LP API versions.
- ubuntutools/lp/__init__.py: Set the '1.0' LP API version as default.
- massfile: Updated to 1.0 LP API.
- doc/requestsync.1: Update the paragraph about sponsoring (lp: #538990).
- pull-lp-source: Use (anonymously) the LP API to get the URL for the .dsc
  file instead of screen scraping.
- ubuntutools/requestsync/mail.py: Fix some more encoding issues.
- Apply patch from Julian Andres Klode for the python-apt 0.8 API transition
  (Closes: #572091)
This commit is contained in:
Michael Bienia 2010-03-25 22:16:20 +01:00
commit 28f7abc2d4
14 changed files with 136 additions and 124 deletions

16
404main
View File

@ -88,19 +88,19 @@ def find_main(cache, pack):
# attribute on version for this, so unfortunately we have to
# do a lot of messing about with apt.
deps = []
src_records = apt_pkg.GetPkgSrcRecords()
src_records = apt_pkg.SourceRecords()
got_src = False
while src_records.Lookup(version.source_name):
if pack in src_records.Binaries:
while src_records.lookup(version.source_name):
if pack in src_records.binaries:
got_src = True
break
if got_src:
base_deps = []
for (name, ver, op, deptype) in src_records.BuildDepends:
base_deps.append(apt.package.BaseDependency(name, comp_type_deb(op), ver, False))
if (op & 16) != 16:
deps.append(apt.package.Dependency(base_deps))
for deptype, all_deps in src_records.build_depends.iteritems():
for or_deps in all_deps:
base_deps = []
for (name, ver, op) in or_deps:
base_deps.append(apt.package.BaseDependency(name, op, ver, False))
deps.append(apt.package.Dependency(base_deps))
process_deps(cache, deps)

11
debian/changelog vendored
View File

@ -3,8 +3,17 @@ ubuntu-dev-tools (0.97) UNRELEASED; urgency=low
[ Michael Bienia ]
* lp-shell: Support all to the launchpadlib Python module known service
names.
* ubuntutools/lp/lpapicache.py, ubuntutools/lp/libsupport.py: Add support
for different LP API versions.
* ubuntutools/lp/__init__.py: Set the '1.0' LP API version as default.
* massfile: Updated to 1.0 LP API.
* doc/requestsync.1: Update the paragraph about sponsoring (lp: #538990).
* pull-lp-source: Use (anonymously) the LP API to get the URL for the .dsc
file instead of screen scraping.
* Apply patch from Julian Andres Klode for the python-apt 0.8 API transition
(Closes: #572091)
-- Michael Bienia <geser@ubuntu.com> Thu, 18 Mar 2010 11:01:21 +0100
-- Michael Bienia <geser@ubuntu.com> Thu, 25 Mar 2010 21:58:47 +0100
ubuntu-dev-tools (0.96) lucid; urgency=low

2
debian/control vendored
View File

@ -14,7 +14,7 @@ Package: ubuntu-dev-tools
Architecture: all
Depends: ${python:Depends}, ${misc:Depends}, binutils, devscripts, sudo,
python-debian, python-launchpadlib (>= 1.5.4), dctrl-tools, lsb-release, diffstat,
dpkg-dev, python-apt (>= 0.7.9), python-lazr.restfulclient
dpkg-dev, python-apt (>= 0.7.93~), python-lazr.restfulclient
Recommends: bzr, pbuilder | cowdancer | sbuild, reportbug (>= 3.39ubuntu1),
ca-certificates, debootstrap, genisoimage, perl-modules, libwww-perl,
libapt-pkg-perl

View File

@ -2,7 +2,7 @@
.SH NAME
requestsync \- helper to file sync requests for Ubuntu
.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 \fIdistro\fR] [\fB\-nse\fR] [\fB\-k \fIkeyid\fR] <\fBsource package\fR> [\fBtarget release\fR] [\fIbase version\fR]
.br
.B requestsync \-\-lp\fR [\fB\-nse\fR] <\fBsource package\fR> <\fBtarget release\fR> [\fIbase version\fR]
.br
@ -22,10 +22,15 @@ the launchpadlib module fails.
.PP
\fBrequestsync\fR checks if you have the permissions to request the sync from
the archive administrators directly by checking if you are a member of the
\fI~ubuntu\-dev\fR team on Launchpad.
If you are not a member of the team, the script will subscribe
the necessary team with approval rights to the bug report for you.
the archive administrators directly by checking if you have upload permissions
for that package through package set permissions or component permissions. If
you don't have upload permissions, the script will subscribe the necessary
team with approval rights to the bug report for you.
This check is only performed if \fBrequestsync\fR is allowed to use the LP API
(option \fB\-\-lp\fR). In the other case \fBrequestsync\fR relies on that you
answer the question about upload permissions honestly to determine if a team
with approval rights is to be subscribed to the bug.
.PP
\fBrequestsync\fR uses launchpadlib authentication to file its requests. Please
@ -57,8 +62,8 @@ file the sync request in Launchpad.
.TP
.B \-s
Specifies that you require sponsorship.
You need this option if you are not a member of ubuntu-dev. This shall disable the
Launchpad team membership checking described above.
You need this option if you don't have upload permissions for that package.
This disables the upload permissions check described above.
.TP
.B \-e
Use this flag after FeatureFreeze for non-bug fix syncs. \fBrequestsync\fR will
@ -96,7 +101,7 @@ If unspecified this defaults to fiordland.ubuntu.com.
.B DEBSMTP_PORT
Sets which port of the SMTP server to use. Default is 25.
.TP
.B DEBSMTP_USER and DEBSMTP_PASS
.B DEBSMTP_USER \fRand\fB DEBSMTP_PASS
Sets the username and password to use when authenticating to the SMTP server.
.SH SEE ALSO

View File

@ -106,12 +106,13 @@ def file_bug(config):
status = config["status"].capitalize()
else:
status = "Confirmed"
task.transitionToStatus(status=status)
task.status = status
assignee = config["assignee"]
if assignee:
assignee_url = "%s~%s" %(launchpad._root_uri, assignee)
bug.transitionToAssignee(assignee=assignee_url)
task.assignee = assignee_url
task.lp_save()
except:
"Bug for '%s' was not filed." % config["sourcepackage"]

View File

@ -26,84 +26,60 @@
import os
import re
import subprocess
import sys
import urllib2
import subprocess
from optparse import OptionParser
# ubuntu-dev-tools modules.
from ubuntutools.lp.lpapicache import Distribution
from ubuntutools.lp.udtexceptions import SeriesNotFoundException, PackageNotFoundException
from ubuntutools.lp.lpapicache import Distribution, Launchpad
from ubuntutools.lp.udtexceptions import (SeriesNotFoundException,
PackageNotFoundException, PocketDoesNotExistError)
from ubuntutools.misc import splitReleasePocket
if not os.path.exists("/usr/bin/dget"):
print "dget is not installed - please install the 'devscripts' package" \
print "E: dget is not installed - please install the 'devscripts' package" \
" and rerun this script again."
sys.exit(1)
class BackportFromLP:
def __getitem__(self, name):
return getattr(self, name)
def __init__(self, package, target_release):
self.package = package
self.target_release = target_release
self.__prepare_sources()
def __prepare_sources(self):
# Scrape the source package from Launchpad :)
try:
contents = urllib2.urlopen('https://launchpad.net/ubuntu/%(target_release)s/+source/%(package)s' % self).read()
links = re.findall('href=\"(.*\.dsc)\"', contents)
if len(links) == 1 and \
subprocess.call(['dget', '-xu', 'https://launchpad.net%s' % links[0]]) == 0:
print '\nSuccess!'
else:
raise ValueError, '\nFailed to fetch and extract the source. ' +\
'Ensure that the package specified is a valid source ' +\
'package name and that Launchpad is not down.'
except urllib2.HTTPError:
raise ValueError, '\nFailed to fetch and extract the source. ' +\
'Ensure that the package specified is a valid source ' +\
'package name and that Launchpad is not down.'
if __name__ == '__main__':
usage = "Usage: %prog <package> [release]"
optParser = OptionParser(usage)
(options, args) = optParser.parse_args()
release = None
if not args: optParser.error("Arguments required.")
package = str(args[0]).lower()
try:
if len(args) == 2: # Custom distribution specified.
release = str(args[1]).lower()
else:
release = os.getenv('DIST') or Distribution('ubuntu').getDevelopmentSeries().name
# Arguments are correct, proceed.
# Check that the Ubuntu release and package specified exists.
Distribution('ubuntu').getArchive().getSourcePackage(package, release)
except IOError, e:
print "This is non-fatal, continuing..."
except (SeriesNotFoundException, PackageNotFoundException), e:
print e
if not args:
optParser.print_help()
sys.exit(1)
# We won't have been able to get the release if there are no LP credentials, hardcode it
# also could bail out here if others think that is better
if release is None:
release = 'lucid'
# Login anonymously to LP
Launchpad.login_anonymously()
package = str(args[0]).lower()
if len(args) >= 2: # Custom distribution specified.
release = str(args[1]).lower()
else:
release = os.getenv('DIST') or Distribution('ubuntu').getDevelopmentSeries().name
try:
(release, pocket) = splitReleasePocket(release)
except PocketDoesNotExistError, e:
print 'E: %s' % e
sys.exit(1)
try:
spph = Distribution('ubuntu').getArchive().getSourcePackage(package, release, pocket)
except (SeriesNotFoundException, PackageNotFoundException), e:
print 'E: %s' % e
sys.exit(1)
dsc_url = [url for url in spph.sourceFileUrls() if url.endswith('.dsc')]
assert dsc_url, 'No .dsc file found'
# All good - start downloading...
try:
print 'Attempting to get %s from release %s...' % \
(package, release.capitalize())
BackportFromLP(package, release)
except ValueError, e:
print 'Error when downloading package %s from release %s: %s.' % \
(package, release, e)
print 'Fetching the source for %s from %s (%s)...' % (
package, release.capitalize(), pocket)
if subprocess.call(['/usr/bin/dget', '-xu', dsc_url[0]]) == 0:
print 'Success!'
else:
print 'Failed to fetch and extrace the source.', \
'Please check the output for the error.'

View File

@ -26,8 +26,10 @@
import sys
from optparse import OptionGroup
from optparse import OptionParser
from ubuntutools.lp.udtexceptions import SeriesNotFoundException, PackageNotFoundException
from ubuntutools.lp.udtexceptions import (SeriesNotFoundException,
PackageNotFoundException, PocketDoesNotExistError,)
from ubuntutools.lp.lpapicache import Distribution, PersonTeam
from ubuntutools.misc import splitReleasePocket
# Usage.
usage = "%prog <srcpackage> <release> <operation>\n\n"
@ -114,13 +116,10 @@ if not options.batch:
oneArch = False
# split release and pocket
if '-' in release:
(release, pocket) = release.split('-')
else:
pocket = 'Release'
pocket = pocket.capitalize()
if pocket not in ('Release', 'Security', 'Updates', 'Proposed', 'Backports'):
print 'Unknown pocket: %s' % pocket
try:
(release, pocket) = splitReleasePocket(release)
except PocketDoesNotExistError, e:
print 'E: %s' % e
sys.exit(1)
# Get the ubuntu archive
@ -205,15 +204,11 @@ else:
archs.intersection_update(valid_archs)
release = options.series or Distribution('ubuntu').getDevelopmentSeries().name
pocket = 'Release'
if release and '-' in release:
# split release and pocket
(release, pocket) = options.series.split('-')
pocket = pocket.capitalize()
if pocket not in ('Release', 'Security', 'Updates', 'Proposed', 'Backports'):
print 'Unknown pocket: %s' % pocket
sys.exit(1)
try:
(release, pocket) = splitReleasePocket(release)
except PocketDoesNotExistError, e:
print 'E: %s' % e
sys.exit(1)
ubuntu_archive = Distribution('ubuntu').getArchive()
try:

View File

@ -3,3 +3,4 @@
##
service = 'edge'
api_version = '1.0'

View File

@ -37,7 +37,7 @@ except:
Credentials = None
Launchpad = None
from ubuntutools.lp import service
from ubuntutools.lp import (service, api_version)
def find_credentials(consumer, files, level=None):
""" search for credentials matching 'consumer' in path for given access level. """
@ -79,7 +79,7 @@ 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)
return Launchpad(credentials, server, cache)
return Launchpad(credentials, server, cache, version=api_version)
def query_to_dict(query_string):
result = dict()
@ -106,7 +106,7 @@ def translate_web_api(url, launchpad):
return url
def translate_api_web(self_url):
return self_url.replace("api.", "").replace("beta/", "")
return self_url.replace("api.", "").replace("%s/" % (api_version), "")
LEVEL = {
0: "UNAUTHORIZED",

View File

@ -32,7 +32,7 @@ from launchpadlib.uris import lookup_service_root
from lazr.restfulclient.resource import Entry
import ubuntutools.lp.libsupport as libsupport
from ubuntutools.lp import service
from ubuntutools.lp import (service, api_version)
from ubuntutools.lp.udtexceptions import *
__all__ = [
@ -63,7 +63,8 @@ class Launchpad(object):
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)
self.__lp = launchpad.Launchpad.login_anonymously('ubuntu-dev-tools',
service_root=service, version=api_version)
else:
raise AlreadyLoggedInError('Already logged in to Launchpad.')
@ -96,7 +97,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(lookup_service_root(service) + 'beta/'):
if isinstance(data, basestring) and data.startswith('%s%s/' % (lookup_service_root(service), api_version)):
# looks like a LP API URL
# check if it's already cached
cached = cls._cache.get(data)
@ -151,7 +152,7 @@ class Distribution(BaseWrapper):
'''
Wrapper class around a LP distribution object.
'''
resource_type = lookup_service_root(service) + 'beta/#distribution'
resource_type = lookup_service_root(service) + api_version + '/#distribution'
def __init__(self, *args):
# Don't share _series and _archives between different Distributions
@ -214,7 +215,7 @@ class Distribution(BaseWrapper):
self._series[series.name] = series
self._series[series.version] = series
except HTTPError:
raise SeriesNotFoundException("Error: Release '%s' is unknown in '%s'." % (name_or_version, self.display_name))
raise SeriesNotFoundException("Release '%s' is unknown in '%s'." % (name_or_version, self.display_name))
return self._series[name_or_version]
def getDevelopmentSeries(self):
@ -233,14 +234,14 @@ class DistroSeries(BaseWrapper):
'''
Wrapper class around a LP distro series object.
'''
resource_type = lookup_service_root(service) + 'beta/#distro_series'
resource_type = lookup_service_root(service) + api_version + '/#distro_series'
class Archive(BaseWrapper):
'''
Wrapper class around a LP archive object.
'''
resource_type = lookup_service_root(service) + 'beta/#archive'
resource_type = lookup_service_root(service) + api_version + '/#archive'
def __init__(self, *args):
# Don't share _srcpkgs between different Archives
@ -260,7 +261,7 @@ class Archive(BaseWrapper):
'''
# Check if pocket has a valid value
if pocket not in ('Release', 'Security', 'Updates', 'Proposed', 'Backports'):
raise PocketDoesNotExistException("Pocket '%s' does not exist." % pocket)
raise PocketDoesNotExistError("Pocket '%s' does not exist." % pocket)
dist = Distribution(self.distribution_link)
# Check if series is already a DistoSeries object or not
@ -301,7 +302,7 @@ class SourcePackagePublishingHistory(BaseWrapper):
'''
Wrapper class around a LP source package object.
'''
resource_type = lookup_service_root(service) + 'beta/#source_package_publishing_history'
resource_type = lookup_service_root(service) + api_version + '/#source_package_publishing_history'
def __init__(self, *args):
# Don't share _builds between different SourcePackagePublishingHistory objects
@ -334,7 +335,7 @@ class SourcePackagePublishingHistory(BaseWrapper):
def getBuildStates(self, archs):
res = list()
if not self._builds:
self._fetch_builds()
@ -402,8 +403,8 @@ class PersonTeam(BaseWrapper):
__metaclass__ = MetaPersonTeam
resource_type = (
lookup_service_root(service) + 'beta/#person',
lookup_service_root(service) + 'beta/#team',
lookup_service_root(service) + api_version + '/#person',
lookup_service_root(service) + api_version + '/#team',
)
def __init__(self, *args):
@ -434,7 +435,7 @@ class PersonTeam(BaseWrapper):
def isLpTeamMember(self, team):
'''
Checks if the user is a member of a certain team on Launchpad.
Returns True if the user is a member of the team otherwise False.
'''
return any(t.name == team for t in self.super_teams)
@ -493,7 +494,7 @@ class Build(BaseWrapper):
'''
Wrapper class around a build object.
'''
resource_type = lookup_service_root(service) + 'beta/#build'
resource_type = lookup_service_root(service) + api_version + '/#build'
def __str__(self):
return u'%s: %s' % (self.arch_tag, self.buildstate)
@ -515,4 +516,4 @@ class DistributionSourcePackage(BaseWrapper):
'''
Caching class for distribution_source_package objects.
'''
resource_type = lookup_service_root(service) + 'beta/#distribution_source_package'
resource_type = lookup_service_root(service) + api_version + '/#distribution_source_package'

View File

@ -6,8 +6,8 @@ class SeriesNotFoundException(BaseException):
""" Thrown when a distroseries is not found """
pass
class PocketDoesNotExistException(BaseException):
""" Thrown when a invalid pocket is passed """
class PocketDoesNotExistError(Exception):
'''Raised when a invalid pocket is used.'''
pass
class ArchiveNotFoundException(BaseException):

View File

@ -23,6 +23,8 @@
# Modules.
import os
from ubuntutools.lp.udtexceptions import PocketDoesNotExistError
def system_distribution():
""" system_distro() -> string
@ -90,3 +92,26 @@ def readlist(filename, uniq=True):
items = list(set(items))
return items
def splitReleasePocket(release):
'''Splits the release and pocket name.
If the argument doesn't contain a pocket name then the 'Release' pocket
is assumed.
Returns the release and pocket name.
'''
pocket = 'Release'
if release is None:
raise ValueError('No release name specified')
if '-' in release:
(release, pocket) = release.split('-')
pocket = pocket.capitalize()
if pocket not in ('Release', 'Security', 'Updates', 'Proposed',
'Backports'):
raise PocketDoesNotExistError("Pocket '%s' does not exist." % pocket)
return (release, pocket)

View File

@ -22,7 +22,6 @@
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):

View File

@ -180,11 +180,11 @@ def mailBug(srcpkg, subscribe, status, bugtitle, bugtext, keyid = None):
# sign the mail body
gpg = subprocess.Popen(gpg_command, stdin = subprocess.PIPE, stdout = subprocess.PIPE)
signed_report = gpg.communicate(mailbody.encode('utf-8'))[0]
signed_report = gpg.communicate(mailbody.encode('utf-8'))[0].decode('utf-8')
assert gpg.returncode == 0
# generate email
mail = '''\
mail = u'''\
From: %s
To: %s
Subject: %s
@ -223,6 +223,6 @@ Content-Type: text/plain; charset=UTF-8
s.quit()
return
s.sendmail(myemailaddr, to, mail)
s.sendmail(myemailaddr, to, mail.encode('utf-8'))
s.quit()
print 'Sync request mailed.'