* New scripts:

- reverse-depends: Replaces reverse-build-depends. Uses an UbuntuWire
    webservice for determining all reverse(-build)-dependencies for a
    package. (LP: #696373)
  - requestbackport: Files a backport request bug report, including a full
    testing checklist.
* Don't allow boilerplate prompts through in submittodebian and requestsync
  (LP: #887336)
This commit is contained in:
Stefano Rivera 2011-11-13 21:31:01 +02:00
commit cefbe3ccc2
19 changed files with 771 additions and 600 deletions

7
debian/NEWS vendored
View File

@ -1,3 +1,10 @@
ubuntu-dev-tools (0.135) unstable; urgency=low
reverse-build-depends was removed from ubuntu-dev-tools. reverse-depends -b
is equivalent.
-- Stefano Rivera <stefanor@debian.org> Sat, 12 Nov 2011 13:11:21 +0200
ubuntu-dev-tools (0.131) unstable; urgency=low
get-build-deps was removed from ubuntu-dev-tools. The newer mk-build-deps in

12
debian/changelog vendored
View File

@ -1,4 +1,4 @@
ubuntu-dev-tools (0.136) UNRELEASED; urgency=low
ubuntu-dev-tools (0.135) UNRELEASED; urgency=low
* grab-merge: Use wget -nv rather than -q, so that we see error messages
(LP: #881967)
@ -10,8 +10,16 @@ ubuntu-dev-tools (0.136) UNRELEASED; urgency=low
- Add --eatmydata flag (LP: #888440)
* pbuilder-dist: Support using non-master mirrors. Thanks Mathieu Parent.
(LP: #824285)
* New scripts:
- reverse-depends: Replaces reverse-build-depends. Uses an UbuntuWire
webservice for determining all reverse(-build)-dependencies for a
package. (LP: #696373)
- requestbackport: Files a backport request bug report, including a full
testing checklist.
* Don't allow boilerplate prompts through in submittodebian and requestsync
(LP: #887336)
-- Stefano Rivera <stefanor@debian.org> Sat, 12 Nov 2011 23:28:05 +0200
-- Stefano Rivera <stefanor@debian.org> Sat, 12 Nov 2011 13:09:05 +0200
ubuntu-dev-tools (0.134) unstable; urgency=low

5
debian/control vendored
View File

@ -93,9 +93,10 @@ Description: useful tools for Ubuntu developers
Debian of a package.
- pull-lp-source - downloads lastest source package from Launchpad.
- pull-revu-source - downloads the latest source package from REVU
- requestbackport - file a backporting request.
- requestsync - files a sync request with Debian changelog and rationale.
- reverse-build-depends - find the reverse build dependencies that a package
has.
- reverse-depends - find the reverse dependencies (or build dependencies) of
a package.
- setup-packaging-environment - assistant to get an Ubuntu installation
ready for packaging work.
- sponsor-patch - Downloads a patch from a Launchpad bug, patches the source

8
debian/copyright vendored
View File

@ -47,18 +47,15 @@ Files: 404main
doc/import-bug-from-debian.1
doc/pbuilder-dist-simple.1
doc/pbuilder-dist.1
doc/reverse-build-depends.1
doc/submittodebian.1
import-bug-from-debian
pbuilder-dist
pbuilder-dist-simple
reverse-build-depends
submittodebian
Copyright: 2007-2010, Canonical Ltd.
2009, James Westby <james.westby@ubuntu.com>
2008, Jamin W. Collins <jcollins@asgardsrealm.net>
2008, Jordan Mantha <mantha@ubuntu.com>
2008-2009, Patrick Schoenfeld <schoenfeld@in-medias-res.com>
2006-2007, Pete Savage <petesavage@ubuntu.com>
2009, Ryan Kavanagh <ryanakca@kubuntu.org>
2007, Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>
@ -152,17 +149,22 @@ License: GPL-3+
Files: doc/pull-debian-debdiff.1
doc/pull-debian-source.1
doc/requestbackport.1
doc/reverse-depends.1
doc/sponsor-patch.1
doc/ubuntu-dev-tools.5
doc/update-maintainer.1
pull-debian-debdiff
pull-debian-source
requestbackport
reverse-depends
sponsor-patch
test-data/*
ubuntutools/archive.py
ubuntutools/builder.py
ubuntutools/config.py
ubuntutools/question.py
ubuntutools/rdepends.py
ubuntutools/sponsor_patch/*
ubuntutools/test/*
ubuntutools/update_maintainer.py

56
doc/requestbackport.1 Normal file
View File

@ -0,0 +1,56 @@
.\" Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
.\"
.\" Permission to use, copy, modify, and/or distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
.\" AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
.\" OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
.\" PERFORMANCE OF THIS SOFTWARE.
.TH requestbackport 1 "November 2011" ubuntu\-dev\-tools
.SH NAME
requestbackport \- File a backport request bug
.SH SYNOPSIS
.B requestbackport \fR[\fIoptions\fR] \fIpackage\fR
.SH DESCRIPTION
Determine the intermediate releases that \fIpackage\fR needs to be
backported to, list all reverse\-dependencies, and file the backporting
request.
\fBrequestbackport\fR will include a testing checklist in the bug.
.SH OPTIONS
.TP
\fB\-d\fR \fIDEST\fR, \fB\-\-destination\fR=\fIDEST\fR
Backport to \fIDEST\fR release and necessary intermediate
releases. Default: current stable release.
.TP
\fB\-s\fR \fISOURCE\fR, \fB\-\-source\fR=\fISOURCE\fR
Backport from \fISOURCE\fR release.
Default: current development release.
.TP
\fB\-l\fR \fIINSTANCE\fR, \fB\-\-lpinstance\fR=\fIINSTANCE\fR
Launchpad instance to connect to.
Default: \fBproduction\fR.
.TP
\fB\-\-no\-conf\fR
Don't read config files or environment variables
.TP
\fB\-h\fR, \fB\-\-help\fR
Display a help message and exit.
.SH SEE ALSO
.BR backportpackage (1),
.BR reverse\-depends (1).
.SH AUTHORS
\fBreverse\-depends\fR and this manpage were written by Stefano Rivera
<stefanor@ubuntu.com>.
.PP
Both are released under the terms of the ISC License.

View File

@ -1,172 +0,0 @@
.\" Automatically generated by Pod::Man 2.1801 (Pod::Simple 3.05)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\"
.\" If the F register is turned on, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.ie \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. nr % 0
. rr F
.\}
.el \{\
. de IX
..
.\}
.\"
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
.\" Fear. Run. Save yourself. No user-serviceable parts.
. \" fudge factors for nroff and troff
.if n \{\
. ds #H 0
. ds #V .8m
. ds #F .3m
. ds #[ \f1
. ds #] \fP
.\}
.if t \{\
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
. ds #V .6m
. ds #F 0
. ds #[ \&
. ds #] \&
.\}
. \" simple accents for nroff and troff
.if n \{\
. ds ' \&
. ds ` \&
. ds ^ \&
. ds , \&
. ds ~ ~
. ds /
.\}
.if t \{\
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
.\}
. \" troff and (daisy-wheel) nroff accents
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
.ds ae a\h'-(\w'a'u*4/10)'e
.ds Ae A\h'-(\w'A'u*4/10)'E
. \" corrections for vroff
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
. \" for low resolution devices (crt and lpr)
.if \n(.H>23 .if \n(.V>19 \
\{\
. ds : e
. ds 8 ss
. ds o a
. ds d- d\h'-1'\(ga
. ds D- D\h'-1'\(hy
. ds th \o'bp'
. ds Th \o'LP'
. ds ae ae
. ds Ae AE
.\}
.rm #[ #] #H #V #F C
.\" ========================================================================
.\"
.IX Title "BUILD-RDEPS 1"
.TH BUILD-RDEPS 1 "2008-08-14" "Debian Utilities" " "
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
build\-rdeps \- find packages that depend on a specific package to build (reverse build depends)
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
\&\fBubuild-rdeps\fR \fIpackage\fR
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
\&\fBubuild-rdeps\fR searches for all packages that build-depend on the specified package.
.SH "OPTIONS"
.IX Header "OPTIONS"
.IP "\fB\-u\fR \fB\-\-update\fR" 4
.IX Item "-u --update"
Run apt-get update before searching for build-depends.
.IP "\fB\-s\fR \fB\-\-sudo\fR" 4
.IX Item "-s --sudo"
Use sudo when running apt-get update. Has no effect if \-u is omitted.
.IP "\fB\-\-distribution\fR" 4
.IX Item "--distribution"
Select another distribution, which is searched for build-depends.
.IP "\fB\-m\fR \fB\-\-print\-maintainer\fR" 4
.IX Item "-m --print-maintainer"
Print the value of the maintainer field for each package.
.IP "\fB\-d\fR \fB\-\-debug\fR" 4
.IX Item "-d --debug"
Run the debug mode
.IP "\fB\-\-help\fR" 4
.IX Item "--help"
Show the usage information.
.IP "\fB\-\-version\fR" 4
.IX Item "--version"
Show the version information.
.SH "LICENSE"
.IX Header "LICENSE"
This code is copyright by Patrick Schoenfeld
<schoenfeld@in\-medias\-res.com>, all rights reserved.
This program comes with \s-1ABSOLUTELEY\s0 \s-1NO\s0 \s-1WARRANTY\s0.
You are free to redistribute this code under the terms of the
\&\s-1GNU\s0 General Public License, version 2 or later.
.SH "AUTHOR"
.IX Header "AUTHOR"
Patrick Schoenfeld <schoenfeld@in\-medias\-res.com>

81
doc/reverse-depends.1 Normal file
View File

@ -0,0 +1,81 @@
.\" Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
.\"
.\" Permission to use, copy, modify, and/or distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
.\" AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
.\" OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
.\" PERFORMANCE OF THIS SOFTWARE.
.TH reverse\-depends 1 "November 2011" ubuntu\-dev\-tools
.SH NAME
reverse\-depends \- List the reverse\-dependencies (or
build\-dependencies) of a package
.SH SYNOPSIS
.B reverse\-depends \fR[\fIoptions\fR] \fIpackage
.SH DESCRIPTION
List reverse\-dependencies (or build\-dependencies) of \fIpackage\fR.
If the package name is prefixed with \fBsrc:\fR then the
reverse\-dependencies of all the binary packages that the specified
source package builds will be listed.
.SH OPTIONS
.TP
\fB\-r\fR \fIRELEASE\fR, \fB\-\-release\fR=\fIRELEASE\fR
Query dependencies in \fIRELEASE\fR.
Default: current development release.
.TP
\fB\-R\fR, \fB\-\-without\-recommends\fR
Only consider Depends relationships, not Recommends.
.TP
\fB\-s\fR, \fB\-\-with\-suggests\fR
Also consider Suggests relationships.
.TP
\fB\-b\fR, \fB\-\-build\-depends\fR
Query build dependencies.
Synonym for \fB\-\-arch\fR=\fIsource\fR.
.TP
\fB\-a\fR \fIARCH\fR, \fB\-\-arch\fR=\fIARCH\fR
Query dependencies in \fIARCH\fR.
Besides valid architecture names, the special values \fBany\fR and
\fBsource\fR may be used.
\fBany\fR displays all reverse dependencies, the union across all
architecture.
\fBsource\fR displays build dependencies.
Default: \fBany\fR.
.TP
\fB\-c\fR \fICOMPONENT\fR, \fB\-\-component\fR=\fICOMPONENT\fR
Only consider reverse\-dependencies in \fICOMPONENT\fR. Can
be specified multiple times.
Default: all components.
.TP
\fB\-l\fR, \fB\-\-list\fR
Display a simple, machine\-readable list.
.TP
\fB\-u\fR \fIURL\fR, \fB\-\-service\-url\fR=\fIURL\fR
Reverse Dependencies web\-service \fIURL\fR.
Default: UbuntuWire's service at
\fBhttp://qa.ubuntuwire.org/rdepends/\fR.
.TP
\fB\-h\fR, \fB\-\-help\fR
Display a help message and exit
.SH EXAMPLES
All reverse dependencies of source package bash:
.IP
.nf
.B reverse\-depends src:bash
.fi
.SH AUTHORS
\fBreverse\-depends\fR and this manpage were written by Stefano Rivera
<stefanor@ubuntu.com>.
.PP
Both are released under the terms of the ISC License.

View File

@ -38,6 +38,8 @@ from distro_info import DebianDistroInfo
import ubuntutools.misc
from ubuntutools.config import UDTConfig
from ubuntutools import subprocess
from ubuntutools.question import YesNoQuestion
class PbuilderDist:
def __init__(self, builder):
@ -136,9 +138,10 @@ class PbuilderDist:
# Debian experimental doesn't have a debootstrap file but
# should work nevertheless.
if distro not in self._debian_distros:
answer = ask(('Warning: Unknown distribution "%s". Do you '
'want to continue [y/N]? ') % distro)
if answer not in ('y', 'Y'):
answer = YesNoQuestion().ask(
'Warning: Unknown distribution "%s". '
'Do you want to continue' % distro, 'no')
if answer == 'yes':
sys.exit(0)
else:
Logger.error('Please install package "debootstrap".')
@ -307,22 +310,6 @@ class PbuilderDist:
self.builder,
] + arguments
def ask(question):
""" ask(question) -> string
Ask the given question and return the answer. Also catch
KeyboardInterrupt (Ctrl+C) and EOFError (Ctrl+D) exceptions and
immediately return None if one of those is found.
"""
try:
answer = raw_input(question)
except (KeyboardInterrupt, EOFError):
print
answer = None
return answer
def show_help(exit_code = 0):
""" help() -> None

258
requestbackport Executable file
View File

@ -0,0 +1,258 @@
#!/usr/bin/python
#
# Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
from collections import defaultdict
import optparse
import sys
import apt
from devscripts.logger import Logger
from distro_info import UbuntuDistroInfo
from ubuntutools.lp.lpapicache import Launchpad, Distribution
from ubuntutools.lp.udtexceptions import PackageNotFoundException
from ubuntutools.config import UDTConfig
from ubuntutools.rdepends import query_rdepends, RDependsException
from ubuntutools.question import YesNoQuestion, EditBugReport
class DestinationException(Exception):
pass
def determine_destinations(source, destination):
ubuntu_info = UbuntuDistroInfo()
if destination is None:
destination = ubuntu_info.stable()
if source not in ubuntu_info.all:
raise DestinationException("Source release %s does not exist" % source)
if destination not in ubuntu_info.all:
raise DestinationException("Destination release %s does not exist"
% destination)
if destination not in ubuntu_info.supported():
raise DestinationException("Destination release %s is not supported"
% destination)
found = False
destinations = []
support_gap = False
for release in ubuntu_info.all:
if release == destination:
found = True
if release == source:
break
if found:
if support_gap:
if ubuntu_info.is_lts(release):
support_gap = False
else:
continue
if release not in ubuntu_info.supported():
support_gap = True
continue
destinations.append(release)
assert found
assert len(destinations) > 0
return destinations
def find_rdepends(package, releases, published_binaries):
intermediate = defaultdict(lambda: defaultdict(list))
# We want to display every pubilshed binary, even if it has no rdepends
for binpkg in published_binaries:
intermediate[binpkg]
for arch in ('any', 'source'):
for release in releases:
for binpkg in published_binaries:
try:
raw_rdeps = query_rdepends(binpkg, release, arch)
except RDependsException:
# Not published? TODO: Check
continue
for relationship, rdeps in raw_rdeps.iteritems():
for rdep in rdeps:
if rdep['Package'] in published_binaries:
continue
intermediate[binpkg][rdep['Package']] \
.append((release, relationship))
output = []
for binpkg, rdeps in intermediate.iteritems():
output += ['', binpkg, '-' * len(binpkg)]
for pkg, appearences in rdeps.iteritems():
output += ['* %s' % pkg]
for release, relationship in appearences:
output += [' [ ] %s (%s)' % (release, relationship)]
found_any = sum(len(rdeps) for rdeps in intermediate.itervalues())
if found_any:
output = [
"Reverse dependencies:",
"=====================",
"The following reverse-dependencies need to be tested against the "
"new version of %(package)s. "
"For reverse-build-dependencies (-Indep), please test that the "
"package still builds against the new %(package)s. "
"For reverse-dependencies, please test that the version of the "
"package currently in the release still works with the new "
"%(package)s installed. "
"Reverse- Recommends, Suggests, and Enhances don't need to be "
"tested, and are listed for completeness-sake."
] + output
else:
output = ["No reverse dependencies"]
return output
def locate_package(package, distribution):
archive = Distribution('ubuntu').getArchive()
for pass_ in ('source', 'binary'):
try:
package_spph = archive.getSourcePackage(package, distribution)
return package_spph
except PackageNotFoundException, e:
if pass_ == 'binary':
Logger.error(str(e))
sys.exit(1)
try:
apt_pkg = apt.Cache()[package]
except KeyError:
continue
package = apt_pkg.candidate.source_name
Logger.normal("Binary package specified, considering its source "
"package instead: %s", package)
def request_backport(package_spph, source, destinations):
published_binaries = set()
for bpph in package_spph._lpobject.getPublishedBinaries():
published_binaries.add(bpph.binary_package_name)
testing = []
testing += ["You can test-build the backport in your PPA with "
"backportpackage:"]
testing += ["$ backportpackage -u ppa:<lp username>/<ppa name> "
"-s %s -d %s %s"
% (source, dest, package_spph.getPackageName())
for dest in destinations]
testing += [""]
for dest in destinations:
testing += ['* %s:' % dest]
testing += ["[ ] Package builds without modification"]
testing += ["[ ] %s installs cleanly and runs" % binary
for binary in published_binaries]
subst = {
'package': package_spph.getPackageName(),
'version': package_spph.getVersion(),
'component': package_spph.getComponent(),
'source': source,
'destinations': ', '.join(destinations),
}
subject = ("Please backport %(package)s %(version)s (%(component)s) "
"from %(source)s" % subst)
body = ('\n'.join(
[
"Please backport %(package)s %(version)s (%(component)s) "
"from %(source)s to %(destinations)s.",
"",
"Reason for the backport:",
"========================",
"<<< Enter your reasoning here >>>",
"",
"Testing:",
"========",
"Mark off items in the checklist [X] as you test them, "
"but please leave the checklist so that backporters can quickly "
"evaluate the state of testing.",
""
]
+ testing
+ [""]
+ find_rdepends(package_spph, destinations, published_binaries)
+ [""]
) % subst)
editor = EditBugReport(subject, body)
editor.edit()
subject, body = editor.get_report()
Logger.normal('The final report is:\nSummary: %s\nDescription:\n%s\n',
subject, body)
if YesNoQuestion().ask("Request this backport", "yes") == "no":
sys.exit(1)
targets = [Launchpad.projects['%s-backports' % destination]
for destination in destinations]
bug = Launchpad.bugs.createBug(title=subject, description=body,
target=targets[0])
for target in targets[1:]:
bug.addTask(target=target)
Logger.normal("Backport request filed as %s", bug.web_link)
def main():
parser = optparse.OptionParser('%progname [options] package')
parser.add_option('-d', '--destination', metavar='DEST',
help='Backport to DEST release and necessary '
'intermediate releases '
'(default: current stable release)')
parser.add_option('-s', '--source', metavar='SOURCE',
help='Backport from SOURCE release '
'(default: current devel release)')
parser.add_option('-l', '--lpinstance', metavar='INSTANCE', default=None,
help='Launchpad instance to connect to '
'(default: production).')
parser.add_option('--no-conf', action='store_true',
dest='no_conf', default=False,
help="Don't read config files or environment variables")
options, args = parser.parse_args()
if len(args) != 1:
parser.error("One (and only one) package must be specified")
package = args[0]
config = UDTConfig(options.no_conf)
if options.lpinstance is None:
options.lpinstance = config.get_value('LPINSTANCE')
Launchpad.login(options.lpinstance)
if options.source is None:
options.source = Distribution('ubuntu').getDevelopmentSeries().name
try:
destinations = determine_destinations(options.source,
options.destination)
except DestinationException, e:
Logger.error(str(e))
sys.exit(1)
package_spph = locate_package(package, options.source)
request_backport(package_spph, options.source, destinations)
if __name__ == '__main__':
main()

View File

@ -36,8 +36,8 @@ from distro_info import UbuntuDistroInfo
from ubuntutools.config import UDTConfig, ubu_email
from ubuntutools.lp import udtexceptions
from ubuntutools.misc import require_utf8
from ubuntutools.requestsync.common import (edit_report, get_debian_changelog,
raw_input_exit_on_ctrlc)
from ubuntutools.question import confirmation_prompt, EditBugReport
from ubuntutools.requestsync.common import get_debian_changelog
#
# entry point
@ -212,8 +212,7 @@ def main():
print ("'%s' doesn't exist in 'Ubuntu %s'.\n"
"Do you want to sync a new package?"
% (srcpkg, release))
raw_input_exit_on_ctrlc('Press [Enter] to continue '
'or [Ctrl-C] to abort. ')
confirmation_prompt()
newsource = True
# Get the requested Debian source package
@ -290,8 +289,7 @@ def main():
'>>> ENTER_EXPLANATION_HERE <<<\n\n')
if need_interaction:
raw_input_exit_on_ctrlc('Press [Enter] to continue.'
'Press [Ctrl-C] to abort now. ')
confirmation_prompt()
base_version = force_base_version or ubuntu_version
@ -313,8 +311,10 @@ def main():
changelog = "XXX FIXME: add changelog here XXX"
report += changelog
(title, report) = edit_report(title, report,
changes_required=need_interaction)
editor = EditBugReport(title, report)
editor.edit(optional=not need_interaction)
title, report = editor.get_report()
if 'XXX FIXME' in report:
print >> sys.stderr, ("E: changelog boilerplate found in report, "
"please manually add changelog when using '-C'")

View File

@ -1,271 +0,0 @@
#!/usr/bin/perl
# Copyright (C) Patrick Schoenfeld
# Copyright (C) 2009 Ryan Kavanagh
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
=head1 NAME
build-rdeps - find packages that depend on a specific package to build (reverse build depends)
=head1 SYNOPSIS
B<build-rdeps> I<package>
=head1 DESCRIPTION
B<build-rdeps> searches for all packages that build-depend on the specified package.
=head1 OPTIONS
=over 4
=item B<-u> B<--update>
Run apt-get update before searching for build-depends.
=item B<-s> B<--sudo>
Use sudo when running apt-get update. Has no effect if -u is omitted.
=item B<--distribution>
Select another distribution, which is searched for build-depends.
=item B<-m> B<--print-maintainer>
Print the value of the maintainer field for each package.
=item B<-d> B<--debug>
Run the debug mode
=item B<--help>
Show the usage information.
=item B<--version>
Show the version information.
=back
=cut
use warnings;
use strict;
use File::Basename;
use File::Find;
use Getopt::Long;
use Pod::Usage;
use Data::Dumper;
my $progname = basename($0);
my $version = '1.0';
my $default_distribution = `ubuntu-distro-info --devel`;
chomp($default_distribution);
my $dctrl = "/usr/bin/grep-dctrl";
my $sources_path = "/var/lib/apt/lists/";
my $source_pattern = ".*_dists_${default_distribution}_.*Sources\$";
my @source_files;
my $sources_count=0;
my $opt_debug;
my $opt_update;
my $opt_sudo;
my $opt_maintainer;
my $opt_mainonly;
my $opt_distribution;
if (!(-x $dctrl)) {
die "$progname: Fatal error. grep-dctrl is not available.\nPlease install the 'dctrl-tools' package.\n";
}
sub version {
print <<"EOT";
This is $progname $version, from the Debian devscripts package, v. ###VERSION###
This code is copyright by Patrick Schoenfeld, all rights reserved.
It comes with ABSOLUTELY NO WARRANTY. You are free to redistribute this code
under the terms of the GNU General Public License, version 2 or later.
EOT
exit (0);
}
sub usage {
print <<"EOT";
usage: $progname packagename
$progname --help
$progname --version
Searches for all packages that build-depend on the specified package.
Options:
-u, --update Run apt-get update before searching for build-depends.
(needs root privileges)
-s, --sudo Use sudo when running apt-get update
(has no effect when -u is omitted)
-d, --debug Enable the debug mode
-m, --print-maintainer Print the maintainer information (experimental)
--distribution distribution Select a distribution to search for build-depends
(Default: $default_distribution)
--only-main Ignore universe and multiverse
EOT
version;
}
sub findsources {
if (/$source_pattern/ and $sources_count <= 3) {
unless ($opt_mainonly and /(universe|multiverse)/) {
push(@source_files, $_);
$sources_count+=1;
print STDERR "DEBUG: Added source file: $_ (#$sources_count)\n" if ($opt_debug);
}
}
}
sub findreversebuilddeps {
my ($package, $source_file) = @_;
my %packages;
my $depending_package;
my $count=0;
my $maintainer_info='';
open(PACKAGES, "$dctrl -F Build-Depends,Build-Depends-Indep $package -s Package,Build-Depends,Build-Depends-Indep,Maintainer $source_file|");
while(<PACKAGES>) {
chomp;
print STDERR "$_\n" if ($opt_debug);
if (/Package: (.*)$/) {
$depending_package = $1;
$packages{$depending_package}->{'Build-Depends'} = 0;
}
if (/Maintainer: (.*)$/) {
if ($depending_package) {
$packages{$depending_package}->{'Maintainer'} = $1;
}
}
if (/Build-Depends: (.*)$/ or /Build-Depends-Indep: (.*)$/) {
if ($depending_package) {
print STDERR "$1\n" if ($opt_debug);
if ($1 =~ /^(.*\s)?$package([\s,]|$)/) {
$packages{$depending_package}->{'Build-Depends'} = 1;
}
}
}
}
while($depending_package = each(%packages)) {
if ($packages{$depending_package}->{'Build-Depends'} != 1) {
print STDERR "Ignoring package $depending_package because its not really build depending on $package.\n" if ($opt_debug);
next;
}
if ($opt_maintainer) {
$maintainer_info = "($packages{$depending_package}->{'Maintainer'})";
}
$count+=1;
print "$depending_package $maintainer_info \n";
}
if ($count == 0) {
print "No reverse build-depends found for $package.\n\n"
}
else {
print "\nFound a total of $count reverse build-depend(s) for $package.\n\n";
}
}
if ($#ARGV < 0) { usage; exit(0); }
Getopt::Long::Configure('bundling');
GetOptions(
"u|update" => \$opt_update,
"s|sudo" => \$opt_sudo,
"m|print-maintainer" => \$opt_maintainer,
"distribution=s" => \$opt_distribution,
"only-main" => \$opt_mainonly,
"d|debug" => \$opt_debug,
"h|help" => sub { usage; },
"v|version" => sub { version; }
);
my $package = shift;
if (!$package) {
die "$progname: missing argument. expecting packagename\n";
}
print STDERR "DEBUG: Package => $package\n" if ($opt_debug);
if ($opt_update) {
print STDERR "DEBUG: Updating apt-cache before search\n" if ($opt_debug);
my @cmd;
if ($opt_sudo) {
print STDERR "DEBUG: Using sudo to become root\n" if ($opt_debug);
push(@cmd, 'sudo');
}
push(@cmd, 'apt-get', 'update');
system @cmd;
}
if ($opt_distribution) {
print STDERR "DEBUG: Setting distribution to $opt_distribution" if ($opt_debug);
$source_pattern = ".*_dists_" . $opt_distribution . "_.*Sources\$";
}
# Find sources files
find(\&findsources, $sources_path);
if (($#source_files+1) <= 0) {
die "$progname: unable to find sources files.\nDid you forget to run apt-get update (or add --update to this command)?";
}
foreach my $source_file (@source_files) {
if ($source_file =~ /main/) {
print "Reverse Build-depends in main:\n";
print "------------------------------\n\n";
findreversebuilddeps($package, "$sources_path/$source_file");
}
if ($source_file =~ /universe/) {
print "Reverse Build-depends in universe:\n";
print "---------------------------------\n\n";
findreversebuilddeps($package, "$sources_path/$source_file");
}
if ($source_file =~ /multiverse/) {
print "Reverse Build-depends in multiverse:\n";
print "----------------------------------\n\n";
findreversebuilddeps($package, "$sources_path/$source_file");
}
}
=head1 LICENSE
This code is copyright by Patrick Schoenfeld
<schoenfeld@in-medias-res.com>, all rights reserved.
This program comes with ABSOLUTELEY NO WARRANTY.
You are free to redistribute this code under the terms of the
GNU General Public License, version 2 or later.
=head1 AUTHOR
Patrick Schoenfeld <schoenfeld@in-medias-res.com>
=cut

148
reverse-depends Executable file
View File

@ -0,0 +1,148 @@
#!/usr/bin/python
#
# Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import optparse
import sys
from devscripts.logger import Logger
from distro_info import UbuntuDistroInfo
from ubuntutools.rdepends import query_rdepends, RDependsException
def main():
parser = optparse.OptionParser('%progname [options] package',
description="List reverse-dependencies of package. "
"If the package name is prefixed with src: then the "
"reverse-dependencies of all the binary packages that "
"the specified source package builds will be listed.")
parser.add_option('-r', '--release', metavar='RELEASE',
default=UbuntuDistroInfo().devel(),
help='Query dependencies in RELEASE. Default: devel')
parser.add_option('-R', '--without-recommends',
action='store_false', dest='recommends', default=True,
help='Only consider Depends relationships, '
'not Recommends')
parser.add_option('-s', '--with-suggests',
action='store_true', dest='suggests', default=False,
help='Also consider Suggests relationships')
parser.add_option('-b', '--build-depends',
action='store_const', dest='arch', const='source',
help='Query build dependencies (synonym for '
'--arch=source)')
parser.add_option('-a', '--arch', metavar='ARCH', default='any',
help='Query dependencies in ARCH. '
'Default: any')
parser.add_option('-c', '--component', metavar='COMPONENT',
action='append',
help='Only consider reverse-dependencies in COMPONENT. '
'Can be specified multiple times. Default: all')
parser.add_option('-l', '--list',
action='store_true', default=False,
help='Display a simple, machine-readable list')
parser.add_option('-u', '--service-url', metavar='URL',
dest='server', default=None,
help='Reverse Dependencies webservice URL. '
'Default: UbuntuWire')
options, args = parser.parse_args()
if len(args) != 1:
parser.error("One (and only one) package must be specified")
package = args[0]
opts = {}
if options.server is not None:
opts['server'] = options.server
try:
data = query_rdepends(package, options.release, options.arch, **opts)
except RDependsException, e:
Logger.error(str(e))
sys.exit(1)
if options.arch == 'source':
fields = ['Reverse-Build-Depends', 'Reverse-Build-Depends-Indep']
else:
fields = ['Reverse-Depends']
if options.recommends:
fields.append('Reverse-Recommends')
if options.suggests:
fields.append('Reverse-Suggests')
for field in data.keys():
if field not in fields:
del data[field]
if options.component:
for field, rdeps in data.items():
filtered = [rdep for rdep in rdeps
if rdep['Component'] in options.component]
if not filtered:
del data[field]
else:
data[field] = filtered
if options.list:
display_consise(data)
else:
display_verbose(data)
def display_verbose(data):
if not data:
print "No reverse dependencies found"
return
all_archs = set()
# This isn't accurate, but we make up for it by displaying what we found
for rdeps in data.itervalues():
for rdep in rdeps:
if 'Architectures' in rdep:
all_archs.update(rdep['Architectures'])
for field, rdeps in data.iteritems():
print field
print '=' * len(field)
rdeps.sort(key=lambda x: x['Package'])
for rdep in rdeps:
line = '* %s' % rdep['Package']
if all_archs and set(rdep['Architectures']) != all_archs:
line += ' [%s]' % ' '.join(sorted(rdep['Architectures']))
if 'Dependency' in rdep:
if len(line) < 30:
line += ' ' * (30 - len(line))
line += ' (for %s)' % rdep['Dependency']
print line
print
if all_archs:
print ("Packages without architectures listed are "
"reverse-dependencies in: %s"
% ', '.join(sorted(list(all_archs))))
def display_consise(data):
result = set()
for rdeps in data.itervalues():
for rdep in rdeps:
result.add(rdep['Package'])
print u'\n'.join(sorted(list(result)))
if __name__ == '__main__':
main()

View File

@ -33,8 +33,9 @@ scripts = ['404main',
'pull-debian-source',
'pull-lp-source',
'pull-revu-source',
'requestbackport',
'requestsync',
'reverse-build-depends',
'reverse-depends',
'setup-packaging-environment',
'sponsor-patch',
'submittodebian',

View File

@ -30,7 +30,8 @@ from tempfile import mkdtemp
from distro_info import UbuntuDistroInfo
from ubuntutools.config import ubu_email
from ubuntutools.question import YesNoQuestion
from ubuntutools.question import YesNoQuestion, EditFile
from ubuntutools.subprocess import call, check_call, Popen, PIPE
try:
from debian.changelog import Changelog
@ -76,11 +77,10 @@ def gen_debdiff(tmpdir, changelog):
debdiff = os.path.join(tmpdir, '%s_%s.debdiff' % (pkg, newver))
if os.system('bzr diff -r tag:%s > /dev/null 2>&1' % oldver) == 256:
devnull = open('/dev/null', 'w')
diff_cmd = ['bzr', 'diff', '-r', 'tag:' + str(oldver)]
if call(diff_cmd, stdout=devnull, stderr=devnull) == 1:
print "Extracting bzr diff between %s and %s" % (oldver, newver)
cmd = 'bzr diff -r tag:%s | filterdiff -x "*changelog*" > %s' % \
(oldver, debdiff)
run_cmd(cmd)
else:
if oldver.epoch is not None:
oldver = str(oldver)[str(oldver).index(":")+1:]
@ -94,9 +94,16 @@ def gen_debdiff(tmpdir, changelog):
check_file(newdsc)
print "Generating debdiff between %s and %s" % (oldver, newver)
cmd = 'debdiff %s %s | filterdiff -x "*changelog*" > %s' % \
(olddsc, newdsc, debdiff)
run_cmd(cmd)
diff_cmd = ['debdiff', olddsc, newdsc]
diff = Popen(diff_cmd, stdout=PIPE)
debdiff_f = open(debdiff, 'w')
filterdiff = Popen(['filterdiff', '-x', '*changelog*'],
stdin=diff.stdout, stdout=debdiff_f)
diff.stdout.close()
filterdiff.wait()
debdiff_f.close()
devnull.close()
return debdiff
@ -109,22 +116,13 @@ def check_file(fname, critical = True):
print u"Couldn't find «%s».\n" % fname
sys.exit(1)
def edit_debdiff(debdiff):
cmd = 'sensible-editor %s' % (debdiff)
run_cmd(cmd)
def submit_bugreport(body, debdiff, deb_version, changelog):
cmd = ('reportbug -P "User: ubuntu-devel@lists.ubuntu.com" '
'-P "Usertags: origin-ubuntu %s ubuntu-patch" -T patch -A %s '
'-B debian -i %s -V %s %s') % \
(UbuntuDistroInfo().devel(), debdiff, body, deb_version,
changelog.package)
run_cmd(cmd)
def run_cmd(cmd):
if os.getenv('DEBUG'):
print "%s\n" % cmd
os.system(cmd)
devel = UbuntuDistroInfo().devel()
cmd = ('reportbug', '-P', 'User: ubuntu-devel@lists.ubuntu.com',
'-P', 'Usertags: origin-ubuntu %s ubuntu-patch' % devel,
'-T', 'patch', '-A', debdiff, '-B', 'debian', '-i', body,
'-V', deb_version, changelog.package)
check_call(cmd)
def check_reportbug_config():
fn = os.path.expanduser('~/.reportbugrc')
@ -182,7 +180,12 @@ def main():
fp.close()
debdiff = gen_debdiff(tmpdir, changelog)
edit_debdiff(debdiff)
EditFile(debdiff, 'debdiff').edit(optional=True)
EditFile(body, 'bug report', [
re.compile('.*REPLACE THIS WITH ACTUAL INFORMATION.*')
]).edit()
submit_bugreport(body, debdiff, deb_version, changelog)
os.unlink(body)
os.unlink(debdiff)

View File

@ -1,7 +1,8 @@
#
# question.py - Helper class for asking questions
#
# Copyright (C) 2010, Benjamin Drung <bdrung@ubuntu.com>
# Copyright (C) 2010, Benjamin Drung <bdrung@ubuntu.com>,
# 2011, Stefano Rivera <stefanor@ubuntu.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@ -15,6 +16,14 @@
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import tempfile
import os
import re
import sys
import ubuntutools.subprocess
class Question(object):
def __init__(self, options, show_help=True):
assert len(options) >= 2
@ -85,3 +94,104 @@ def input_number(question, min_number, max_number, default=None):
print "Please input a number."
assert type(selected) == int
return selected
def confirmation_prompt(message=None, action=None):
'''Display message, or a stock message including action, and wait for the
user to press Enter
'''
if message is None:
if action is None:
action = 'continue'
message = 'Press [Enter] to %s. Press [Ctrl-C] to abort now.' % action
try:
raw_input(message)
except KeyboardInterrupt:
print '\nAborting as requested.'
sys.exit(1)
class EditFile(object):
def __init__(self, filename, description, placeholders=None):
self.filename = filename
self.description = description
if placeholders is None:
placeholders = (re.compile(r'^<<<.*>>>$', re.UNICODE),)
self.placeholders = placeholders
def edit(self, optional=False):
if optional:
print "Currently the %s looks like:" % self.description
with open(self.filename, 'r') as f:
print f.read()
if YesNoQuestion().ask("Edit", "no") == "no":
return
done = False
while not done:
old_mtime = os.stat(self.filename).st_mtime
ubuntutools.subprocess.check_call(['sensible-editor',
self.filename])
modified = old_mtime != os.stat(self.filename).st_mtime
placeholders_present = False
if self.placeholders:
with open(self.filename, 'r') as f:
for line in f:
for placeholder in self.placeholders:
if placeholder.search(line.strip()):
placeholders_present = True
if placeholders_present:
print ("Placeholders still present in the %s. "
"Please replace them with useful information."
% self.description)
confirmation_prompt(action='edit again')
elif not modified:
print "The %s was not modified" % self.description
if YesNoQuestion().ask("Edit again", "yes") == "no":
done = True
elif self.check_edit():
done = True
def check_edit(self):
'''Override this to implement extra checks on the edited report.
Should return False if another round of editing is needed,
and should prompt the user to confirm that, if necessary.
'''
return True
class EditBugReport(EditFile):
split_re = re.compile(r'^Summary.*?:\s+(.*)\s+'
r'Description:\s+(.*)$',
re.DOTALL | re.UNICODE)
def __init__(self, subject, body, placeholders=None):
tmpfile = tempfile.NamedTemporaryFile(prefix=sys.argv[0] + '_',
suffix='.txt',
delete=False)
tmpfile.write((u'Summary (one line):\n%s\n\nDescription:\n%s'
% (subject, body)).encode('utf-8'))
tmpfile.close()
super(EditBugReport, self).__init__(tmpfile.name, 'bug report',
placeholders)
def check_edit(self):
with open(self.filename, 'r') as f:
report = f.read().decode('utf-8')
if self.split_re.match(report) is None:
print ("The %s doesn't start with 'Summary:' and 'Description:' "
"blocks" % self.description)
confirmation_prompt('edit again')
return False
return True
def get_report(self):
with open(self.filename, 'r') as f:
report = f.read().decode('utf-8')
m = self.split_re.match(report)
report = (m.group(1), m.group(2))
os.unlink(self.filename)
return report

35
ubuntutools/rdepends.py Normal file
View File

@ -0,0 +1,35 @@
# Copyright (C) 2011, Stefano Rivera <stefanor@ubuntu.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import json
import os
import urllib2
class RDependsException(Exception):
pass
def query_rdepends(package, release, arch,
server='http://qa.ubuntuwire.org/rdepends'):
"""Look up a packages reverse-dependencies on the Ubuntuwire
Reverse- webservice
"""
url = os.path.join(server, 'v1', release, arch, package)
try:
return json.load(urllib2.urlopen(url))
except urllib2.HTTPError, e:
raise RDependsException(e.read().strip())

View File

@ -22,22 +22,10 @@
import os
import sys
import urllib2
import re
import tempfile
from debian.changelog import Changelog
from ubuntutools import subprocess
def raw_input_exit_on_ctrlc(*args, **kwargs):
'''
A wrapper around raw_input() to exit with a normalized message on Control-C
'''
try:
return raw_input(*args, **kwargs)
except KeyboardInterrupt:
print '\nAbort requested. No sync request filed.'
sys.exit(1)
def get_changelog(srcpkg, distro):
'''
Download and return a parsed changelog for srcpackage, from
@ -83,68 +71,3 @@ def get_debian_changelog(srcpkg, version):
break
new_entries.append(unicode(block))
return u''.join(new_entries)
def edit_report(subject, body, changes_required = False):
'''
Ask if the user wants to edit a report (consisting of subject and body)
in sensible-editor.
If changes_required is True then the file has to be edited before we
can proceed.
Returns (new_subject, new_body).
'''
editing_finished = False
while not editing_finished:
report = 'Summary (one line):\n%s\n\nDescription:\n%s' % (subject, body)
if not changes_required:
print 'Currently the report looks as follows:\n%s' % report
while True:
val = raw_input_exit_on_ctrlc('Do you want to edit the report '
'[y/N]? ')
if val.lower() in ('y', 'yes'):
break
elif val.lower() in ('n', 'no', ''):
editing_finished = True
break
else:
print 'Invalid answer.'
if not editing_finished:
# Create tempfile and remember mtime
report_file = tempfile.NamedTemporaryFile(prefix='requestsync_')
report_file.write(report.encode('utf-8'))
report_file.flush()
mtime_before = os.stat(report_file.name).st_mtime
# Launch editor
try:
subprocess.check_call(['sensible-editor', report_file.name])
except subprocess.CalledProcessError, e:
print >> sys.stderr, ('Error calling sensible-editor: %s\n'
'Aborting.' % e)
sys.exit(1)
# Check if the tempfile has been changed
if changes_required:
if mtime_before == os.stat(report_file.name).st_mtime:
print ('The report has not been changed, but you have to '
'explain why the Ubuntu changes can be dropped.')
raw_input_exit_on_ctrlc('Press [Enter] to retry or '
'[Control-C] to abort. ')
else:
changes_required = False
report_file.seek(0)
report = report_file.read().decode('utf-8')
report_file.close()
# Undecorate report again
(subject, body) = report.split("\nDescription:\n", 1)
# Remove prefix and whitespace from subject
subject = re.sub('^Summary \(one line\):\s*', '', subject,
1).strip()
return (subject, body)

View File

@ -26,9 +26,9 @@ import urllib2
from debian.deb822 import Changes
from distro_info import DebianDistroInfo
from ubuntutools.requestsync.common import raw_input_exit_on_ctrlc
from ubuntutools.lp.lpapicache import (Launchpad, Distribution, PersonTeam,
DistributionSourcePackage)
from ubuntutools.question import confirmation_prompt
def get_debian_srcpkg(name, release):
debian = Distribution('debian')
@ -60,7 +60,7 @@ Your sync request shall require an approval by a member of the appropriate
sponsorship team, who shall be subscribed to this bug report.
This must be done before it can be processed by a member of the Ubuntu Archive
team.'''
raw_input_exit_on_ctrlc('If the above is correct please press [Enter] ')
confirmation_prompt()
return need_sponsor
@ -88,8 +88,7 @@ def check_existing_reports(srcpkg):
'Please check the above URL to verify this before '
'continuing.'
% (bug.title, bug.web_link))
raw_input_exit_on_ctrlc('Press [Enter] to continue or [Ctrl-C] '
'to abort. ')
confirmation_prompt()
def get_ubuntu_delta_changelog(srcpkg):
'''
@ -133,7 +132,7 @@ def post_bug(srcpkg, subscribe, status, bugtitle, bugtext):
print ('The final report is:\nSummary: %s\nDescription:\n%s\n'
% (bugtitle, bugtext))
raw_input_exit_on_ctrlc('Press [Enter] to continue or [Ctrl-C] to abort. ')
confirmation_prompt()
if srcpkg:
bug_target = DistributionSourcePackage(

View File

@ -30,8 +30,8 @@ from devscripts.logger import Logger
from distro_info import DebianDistroInfo
from ubuntutools.archive import rmadison, FakeSPPH
from ubuntutools.requestsync.common import (get_changelog,
raw_input_exit_on_ctrlc)
from ubuntutools.requestsync.common import get_changelog
from ubuntutools.question import confirmation_prompt, YesNoQuestion
from ubuntutools import subprocess
from ubuntutools.lp.udtexceptions import PackageNotFoundException
@ -71,17 +71,12 @@ def need_sponsorship(name, component, release):
component.
'''
while True:
print ("Do you have upload permissions for the '%s' component "
"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
elif val.lower() in ('n', 'no', ''):
return True
else:
print 'Invalid answer'
val = YesNoQuestion().ask("Do you have upload permissions for the "
"'%s' component or the package '%s' in "
"Ubuntu %s?\n"
"If in doubt answer 'n'."
% (component, name, release), 'no')
return val == 'no'
def check_existing_reports(srcpkg):
'''
@ -90,7 +85,7 @@ def check_existing_reports(srcpkg):
print ('Please check on '
'https://bugs.launchpad.net/ubuntu/+source/%s/+bugs\n'
'for duplicate sync requests before continuing.' % srcpkg)
raw_input_exit_on_ctrlc('Press [Enter] to continue or [Ctrl-C] to abort. ')
confirmation_prompt()
def get_ubuntu_delta_changelog(srcpkg):
'''
@ -166,7 +161,7 @@ Content-Type: text/plain; charset=UTF-8
%s''' % (myemailaddr, to, bugtitle, signed_report)
print 'The final report is:\n%s' % mail
raw_input_exit_on_ctrlc('Press [Enter] to continue or [Ctrl-C] to abort. ')
confirmation_prompt()
# connect to the server
try: