mirror of
				https://git.launchpad.net/ubuntu-dev-tools
				synced 2025-11-04 07:54:03 +00:00 
			
		
		
		
	Merge trunk.
This commit is contained in:
		
						commit
						8627e0a626
					
				
							
								
								
									
										165
									
								
								backportpackage
									
									
									
									
									
								
							
							
						
						
									
										165
									
								
								backportpackage
									
									
									
									
									
								
							@ -21,16 +21,15 @@ import shutil
 | 
			
		||||
import subprocess
 | 
			
		||||
import sys
 | 
			
		||||
import tempfile
 | 
			
		||||
import urllib
 | 
			
		||||
 | 
			
		||||
from debian.deb822 import Dsc
 | 
			
		||||
import launchpadlib.launchpad
 | 
			
		||||
import lsb_release
 | 
			
		||||
 | 
			
		||||
from ubuntutools.builder import getBuilder
 | 
			
		||||
from ubuntutools.logger import Logger
 | 
			
		||||
 | 
			
		||||
devnull = open('/dev/null', 'r+')
 | 
			
		||||
lp = None
 | 
			
		||||
 | 
			
		||||
def error(msg):
 | 
			
		||||
    Logger.error(msg)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
@ -42,15 +41,15 @@ def check_call(cmd, *args, **kwargs):
 | 
			
		||||
        error('%s returned %d' % (cmd, ret))
 | 
			
		||||
 | 
			
		||||
def parse(args):
 | 
			
		||||
    usage = 'Usage: %prog [options] <source package>'
 | 
			
		||||
    usage = 'Usage: %prog [options] <source package name or .dsc URL/file>'
 | 
			
		||||
    p = optparse.OptionParser(usage)
 | 
			
		||||
    p.add_option('-t', '--to',
 | 
			
		||||
    p.add_option('-d', '--destination',
 | 
			
		||||
                 dest='dest_releases',
 | 
			
		||||
                 default=[],
 | 
			
		||||
                 action='append',
 | 
			
		||||
                 help='Backport to DEST release (required)',
 | 
			
		||||
                 help='Backport to DEST release (default: current release)',
 | 
			
		||||
                 metavar='DEST')
 | 
			
		||||
    p.add_option('-f', '--from',
 | 
			
		||||
    p.add_option('-s', '--source',
 | 
			
		||||
                 dest='source_release',
 | 
			
		||||
                 default=None,
 | 
			
		||||
                 help='Backport from SOURCE release (default: devel release)',
 | 
			
		||||
@ -79,6 +78,11 @@ def parse(args):
 | 
			
		||||
                 default=None,
 | 
			
		||||
                 help='Package version to backport (or verify)',
 | 
			
		||||
                 metavar='VERSION')
 | 
			
		||||
    p.add_option('-w', '--workdir',
 | 
			
		||||
                 dest='workdir',
 | 
			
		||||
                 default=None,
 | 
			
		||||
                 help='Specify a working directory (default: temporary dir)',
 | 
			
		||||
                 metavar='WORKDIR')
 | 
			
		||||
    p.add_option('-l', '--launchpad',
 | 
			
		||||
                 dest='launchpad',
 | 
			
		||||
                 default='production',
 | 
			
		||||
@ -87,16 +91,16 @@ def parse(args):
 | 
			
		||||
 | 
			
		||||
    opts, args = p.parse_args(args)
 | 
			
		||||
    if len(args) != 1:
 | 
			
		||||
        p.error('You must specify a source package')
 | 
			
		||||
    if not opts.dest_releases:
 | 
			
		||||
        p.error('You must specify at least one destination release')
 | 
			
		||||
        p.error('You must specify a single source package or a .dsc URL/path')
 | 
			
		||||
    if not opts.upload and not opts.build:
 | 
			
		||||
        p.error('Nothing to do')
 | 
			
		||||
 | 
			
		||||
    return opts, args
 | 
			
		||||
 | 
			
		||||
def find_release_package(package, opts):
 | 
			
		||||
def find_release_package(lp, package, version, source_release):
 | 
			
		||||
    ubuntu = lp.distributions['ubuntu']
 | 
			
		||||
    archive = ubuntu.main_archive
 | 
			
		||||
    series = ubuntu.getSeries(name_or_version=opts.source_release)
 | 
			
		||||
    series = ubuntu.getSeries(name_or_version=source_release)
 | 
			
		||||
    status = 'Published'
 | 
			
		||||
    for pocket in ('Updates', 'Security', 'Release'):
 | 
			
		||||
        try:
 | 
			
		||||
@ -110,50 +114,67 @@ def find_release_package(package, opts):
 | 
			
		||||
            continue
 | 
			
		||||
    else:
 | 
			
		||||
        error('Unable to find package %s in release %s' %
 | 
			
		||||
              (package, opts.source_release))
 | 
			
		||||
              (package, source_release))
 | 
			
		||||
 | 
			
		||||
    if opts.version and opts.version != srcpkg.source_package_version:
 | 
			
		||||
    if version and version != srcpkg.source_package_version:
 | 
			
		||||
        error('Requested backport of version %s but %s is at version %s' %
 | 
			
		||||
              (opts.version, package, srcpkg.source_package_version))
 | 
			
		||||
              (version, package, srcpkg.source_package_version))
 | 
			
		||||
 | 
			
		||||
    return srcpkg
 | 
			
		||||
 | 
			
		||||
def find_version_package(package, opts):
 | 
			
		||||
def find_version_package(lp, package, version):
 | 
			
		||||
    ubuntu = lp.distributions['ubuntu']
 | 
			
		||||
    archive = ubuntu.main_archive
 | 
			
		||||
    try:
 | 
			
		||||
        # Might get more than one (i.e. same version in multiple
 | 
			
		||||
        # releases), but they should all be identical
 | 
			
		||||
        return archive.getPublishedSources(source_name=package,
 | 
			
		||||
                                           version=opts.version)[0]
 | 
			
		||||
                                           version=version)[0]
 | 
			
		||||
    except IndexError:
 | 
			
		||||
        error('Package %s was never published with version %s in Ubuntu' %
 | 
			
		||||
              (package, opts.version))
 | 
			
		||||
        error('Version %s of package %s was never published in Ubuntu' %
 | 
			
		||||
              (version, package))
 | 
			
		||||
 | 
			
		||||
def fetch_package(workdir, package, opts):
 | 
			
		||||
    # Returns the path to the .dsc file that was fetched
 | 
			
		||||
 | 
			
		||||
    if not opts.source_release and not opts.version:
 | 
			
		||||
        opts.source_release = lp.distributions['ubuntu'].current_series.name
 | 
			
		||||
def dscurl_from_package(lp, workdir, package, version, source_release):
 | 
			
		||||
    if not source_release and not version:
 | 
			
		||||
        source_release = lp.distributions['ubuntu'].current_series.name
 | 
			
		||||
 | 
			
		||||
    # If source_release is specified, then version is just for
 | 
			
		||||
    # verification
 | 
			
		||||
    if opts.source_release:
 | 
			
		||||
        srcpkg = find_release_package(package, opts)
 | 
			
		||||
    if source_release:
 | 
			
		||||
        srcpkg = find_release_package(lp, package, version, source_release)
 | 
			
		||||
    else:
 | 
			
		||||
        srcpkg = find_version_package(package, opts)
 | 
			
		||||
        srcpkg = find_version_package(lp, package, version)
 | 
			
		||||
 | 
			
		||||
    for f in srcpkg.sourceFileUrls():
 | 
			
		||||
        if f.endswith('.dsc'):
 | 
			
		||||
            check_call(['dget',
 | 
			
		||||
                        '--download-only',
 | 
			
		||||
                        '--allow-unauthenticated',
 | 
			
		||||
                        f],
 | 
			
		||||
                       cwd=workdir)
 | 
			
		||||
            return os.path.join(workdir, os.path.basename(f))
 | 
			
		||||
            return urllib.unquote(f)
 | 
			
		||||
    else:
 | 
			
		||||
        error('Package %s contains no .dsc file' % package)
 | 
			
		||||
 | 
			
		||||
def dscurl_from_dsc(package):
 | 
			
		||||
    path = os.path.abspath(os.path.expanduser(package))
 | 
			
		||||
    if os.path.exists(path):
 | 
			
		||||
        return 'file://%s' % path
 | 
			
		||||
    else:
 | 
			
		||||
        # Can't resolve it as a local path? Let's just hope it's good
 | 
			
		||||
        # as-is
 | 
			
		||||
        return package
 | 
			
		||||
 | 
			
		||||
def fetch_package(lp, workdir, package, version, source_release):
 | 
			
		||||
    # Returns the path to the .dsc file that was fetched
 | 
			
		||||
 | 
			
		||||
    if package.endswith('.dsc'):
 | 
			
		||||
        dsc = dscurl_from_dsc(package)
 | 
			
		||||
    else:
 | 
			
		||||
        dsc = dscurl_from_package(lp, workdir, package, version, source_release)
 | 
			
		||||
 | 
			
		||||
    check_call(['dget',
 | 
			
		||||
                '--download-only',
 | 
			
		||||
                '--allow-unauthenticated',
 | 
			
		||||
                dsc],
 | 
			
		||||
               cwd=workdir)
 | 
			
		||||
    return os.path.join(workdir, os.path.basename(dsc))
 | 
			
		||||
 | 
			
		||||
def get_backport_version(version, upload, release):
 | 
			
		||||
    v = version + ('~%s1' % release)
 | 
			
		||||
    if upload and upload.startswith('ppa:'):
 | 
			
		||||
@ -166,21 +187,21 @@ def get_backport_dist(upload, release):
 | 
			
		||||
    else:
 | 
			
		||||
        return release
 | 
			
		||||
 | 
			
		||||
def do_build(workdir, package, release, bp_version, opts):
 | 
			
		||||
    builder = getBuilder(opts.builder)
 | 
			
		||||
def do_build(workdir, package, release, bp_version, builder):
 | 
			
		||||
    builder = getBuilder(builder)
 | 
			
		||||
    if not builder:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    if opts.update:
 | 
			
		||||
        builder.update(release)
 | 
			
		||||
 | 
			
		||||
    builder.build(os.path.join(workdir,
 | 
			
		||||
                               '%s_%s.dsc' % (package, bp_version)),
 | 
			
		||||
                  release,
 | 
			
		||||
                  workdir)
 | 
			
		||||
    return builder.build(os.path.join(workdir,
 | 
			
		||||
                                      '%s_%s.dsc' % (package, bp_version)),
 | 
			
		||||
                         release,
 | 
			
		||||
                         workdir)
 | 
			
		||||
 | 
			
		||||
def do_upload(workdir, package, bp_version, opts):
 | 
			
		||||
    prompt = 'Do you want to upload this to %s? [Y/n]' % opts.upload
 | 
			
		||||
def do_upload(workdir, package, bp_version, upload):
 | 
			
		||||
    prompt = 'Do you want to upload this to %s? [Y/n]' % upload
 | 
			
		||||
    while True:
 | 
			
		||||
        answer = raw_input(prompt).strip().lower()
 | 
			
		||||
        if answer in ('', 'y', 'yes'):
 | 
			
		||||
@ -189,16 +210,13 @@ def do_upload(workdir, package, bp_version, opts):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
    check_call(['dput',
 | 
			
		||||
                opts.upload,
 | 
			
		||||
                upload,
 | 
			
		||||
                '%s_%s_source.changes' %
 | 
			
		||||
                (package, bp_version)],
 | 
			
		||||
               cwd=workdir)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def do_backport(workdir, package, dscfile, release, opts):
 | 
			
		||||
    dsc = Dsc(open(os.path.join(workdir, dscfile)))
 | 
			
		||||
    v = dsc['Version']
 | 
			
		||||
 | 
			
		||||
def do_backport(workdir, package, dscfile, version, release, build, builder, upload):
 | 
			
		||||
    check_call(['dpkg-source',
 | 
			
		||||
                '-x',
 | 
			
		||||
                dscfile,
 | 
			
		||||
@ -206,8 +224,8 @@ def do_backport(workdir, package, dscfile, release, opts):
 | 
			
		||||
               cwd=workdir)
 | 
			
		||||
    srcdir = os.path.join(workdir, package)
 | 
			
		||||
 | 
			
		||||
    bp_version = get_backport_version(v, opts.upload, release)
 | 
			
		||||
    bp_dist = get_backport_dist(opts.upload, release)
 | 
			
		||||
    bp_version = get_backport_version(version, upload, release)
 | 
			
		||||
    bp_dist = get_backport_dist(upload, release)
 | 
			
		||||
 | 
			
		||||
    check_call(['dch',
 | 
			
		||||
                '--force-bad-version',
 | 
			
		||||
@ -223,32 +241,61 @@ def do_backport(workdir, package, dscfile, release, opts):
 | 
			
		||||
        bp_version = bp_version[bp_version.find(':')+1:]
 | 
			
		||||
 | 
			
		||||
    print 'Please check the package in file://%s carefully' % workdir
 | 
			
		||||
    if opts.build:
 | 
			
		||||
        do_build(workdir, package, release, bp_version, opts)
 | 
			
		||||
    if opts.upload:
 | 
			
		||||
        do_upload(workdir, package, bp_version, opts)
 | 
			
		||||
    if build:
 | 
			
		||||
        if 0 != do_build(workdir, package, release, bp_version, builder):
 | 
			
		||||
            error('Package failed to build; aborting')
 | 
			
		||||
    if upload:
 | 
			
		||||
        do_upload(workdir, package, bp_version, upload)
 | 
			
		||||
 | 
			
		||||
    shutil.rmtree(srcdir)
 | 
			
		||||
 | 
			
		||||
def main(args):
 | 
			
		||||
    global lp
 | 
			
		||||
 | 
			
		||||
    os.environ['DEB_VENDOR'] = 'Ubuntu'
 | 
			
		||||
 | 
			
		||||
    opts, (package,) = parse(args[1:])
 | 
			
		||||
    opts, (package_or_dsc,) = parse(args[1:])
 | 
			
		||||
 | 
			
		||||
    script_name = os.path.basename(sys.argv[0])
 | 
			
		||||
    lp = launchpadlib.launchpad.Launchpad.login_anonymously(script_name,
 | 
			
		||||
                                                            opts.launchpad)
 | 
			
		||||
 | 
			
		||||
    workdir = tempfile.mkdtemp(prefix='backportpackage-')
 | 
			
		||||
    if not opts.dest_releases:
 | 
			
		||||
        try:
 | 
			
		||||
            distinfo = lsb_release.get_distro_information()
 | 
			
		||||
            opts.dest_releases = [distinfo['CODENAME']]
 | 
			
		||||
        except:
 | 
			
		||||
            error('No destination release specified and unable to guess yours')
 | 
			
		||||
 | 
			
		||||
    if opts.workdir:
 | 
			
		||||
        workdir = os.path.expanduser(opts.workdir)
 | 
			
		||||
    else:
 | 
			
		||||
        workdir = tempfile.mkdtemp(prefix='backportpackage-')
 | 
			
		||||
 | 
			
		||||
    if not os.path.exists(workdir):
 | 
			
		||||
        os.makedirs(workdir)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        dscfile = fetch_package(workdir, package, opts)
 | 
			
		||||
        dscfile = fetch_package(lp,
 | 
			
		||||
                                workdir,
 | 
			
		||||
                                package_or_dsc,
 | 
			
		||||
                                opts.version,
 | 
			
		||||
                                opts.source_release)
 | 
			
		||||
 | 
			
		||||
        dsc = Dsc(open(os.path.join(workdir, dscfile)))
 | 
			
		||||
        package = dsc['Source']
 | 
			
		||||
        version = dsc['Version']
 | 
			
		||||
 | 
			
		||||
        for release in opts.dest_releases:
 | 
			
		||||
            do_backport(workdir, package, dscfile, release, opts)
 | 
			
		||||
            do_backport(workdir,
 | 
			
		||||
                        package,
 | 
			
		||||
                        dscfile,
 | 
			
		||||
                        version,
 | 
			
		||||
                        release,
 | 
			
		||||
                        opts.build,
 | 
			
		||||
                        opts.builder,
 | 
			
		||||
                        opts.upload)
 | 
			
		||||
    finally:
 | 
			
		||||
        shutil.rmtree(workdir)
 | 
			
		||||
        if not opts.workdir:
 | 
			
		||||
            shutil.rmtree(workdir)
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    sys.exit(main(sys.argv))
 | 
			
		||||
 | 
			
		||||
@ -4,21 +4,19 @@ backportpackage \- helper to test package backports
 | 
			
		||||
.SH SYNOPSIS
 | 
			
		||||
.TP
 | 
			
		||||
.B backportpackage \fR[\fIadditional options\fR]
 | 
			
		||||
\-\-to <\fIdest release\fR>
 | 
			
		||||
.br
 | 
			
		||||
\-\-upload <\fIupload target\fR>
 | 
			
		||||
.br
 | 
			
		||||
<\fIsource package\fR>
 | 
			
		||||
<\fIsource package name or .dsc URL/file\fR>
 | 
			
		||||
.PP
 | 
			
		||||
.B backportpackage \-h
 | 
			
		||||
.SH OPTIONS
 | 
			
		||||
.TP
 | 
			
		||||
.B \-t \fIDEST\fR, \-\-to=\fIDEST\fR
 | 
			
		||||
.B \-d \fIDEST\fR, \-\-destination=\fIDEST\fR
 | 
			
		||||
\fBRequired\fR. Backport the package to the specified Ubuntu
 | 
			
		||||
release. This option may be specified multiple times, but must be
 | 
			
		||||
specified at least once.
 | 
			
		||||
release. If this option is unspecified, then \fBbackportpackage\fR
 | 
			
		||||
defaults to the release on which it is currently running.
 | 
			
		||||
.TP
 | 
			
		||||
.B \-f \fISOURCE\fR, \-\-from=\fISOURCE\fR
 | 
			
		||||
.B \-s \fISOURCE\fR, \-\-source=\fISOURCE\fR
 | 
			
		||||
Backport the package from the specified Ubuntu release. If neither
 | 
			
		||||
this option nor \fB\-\-version\fR are specified, then
 | 
			
		||||
\fBbackportpackage\fR defaults to the current Ubuntu development
 | 
			
		||||
@ -42,24 +40,32 @@ Update the builder environment before attempting to build.
 | 
			
		||||
Upload to \fIUPLOAD\fR with \fBdput\fR(1) (after confirmation).
 | 
			
		||||
.TP
 | 
			
		||||
.B \-v \fIVERSION\fR, \-\-version=\fIVERSION\fR
 | 
			
		||||
If the \fB\-\-from\fR option is specified, then \fBbackportpackage\fR
 | 
			
		||||
verifies that the current version of \fIsource package\fR in
 | 
			
		||||
\fISOURCE\fR is the same as \fIVERSION\fR. Otherwise,
 | 
			
		||||
If the \fB\-\-source\fR option is specified, then
 | 
			
		||||
\fBbackportpackage\fR verifies that the current version of \fIsource
 | 
			
		||||
package\fR in \fISOURCE\fR is the same as \fIVERSION\fR. Otherwise,
 | 
			
		||||
\fBbackportpackage\fR finds version \fIVERSION\fR of \fIsource
 | 
			
		||||
package\fR, regardless of the release in which it was published (or if
 | 
			
		||||
that version is still current).
 | 
			
		||||
that version is still current). This option is ignored if a .dsc URL
 | 
			
		||||
or path is passed in instead of a source package name.
 | 
			
		||||
.TP
 | 
			
		||||
.B \-w \fIWORKDIR\fR, \-\-workdir=\fIWORKDIR\fR
 | 
			
		||||
If \fIWORKDIR\fR is specified, then all files are downloaded,
 | 
			
		||||
unpacked, built into, and otherwise manipulated in
 | 
			
		||||
\fIWORKDIR\fR. Otherwise, a temporary directory is created, which is
 | 
			
		||||
deleted before \fIbackportpackage\fR exits.
 | 
			
		||||
.TP
 | 
			
		||||
.B \-l \fIINSTANCE\fR, \-\-launchpad=\fIINSTANCE\fR
 | 
			
		||||
Use the specified instance of Launchpad (e.g. "staging"), instead of
 | 
			
		||||
the default of "production".
 | 
			
		||||
.SH DESCRIPTION
 | 
			
		||||
\fBbackportpackage\fR fetches a package from one Ubuntu release and
 | 
			
		||||
creates a no-change backport of that package to a previous release,
 | 
			
		||||
optionally doing a test build of the package and/or uploading the
 | 
			
		||||
resulting backport for testing.
 | 
			
		||||
\fBbackportpackage\fR fetches a package from one Ubuntu release or
 | 
			
		||||
from a specified .dsc path or URL and creates a no-change backport of
 | 
			
		||||
that package to a previous release, optionally doing a test build of
 | 
			
		||||
the package and/or uploading the resulting backport for testing.
 | 
			
		||||
.PP
 | 
			
		||||
The backported package is fetched and built in a temporary directory
 | 
			
		||||
in \fB/tmp\fR, which is removed once the script finishes running.
 | 
			
		||||
Unless a working directory is specified, the backported package is
 | 
			
		||||
fetched and built in a temporary directory in \fB/tmp\fR, which is
 | 
			
		||||
removed once the script finishes running.
 | 
			
		||||
.PP
 | 
			
		||||
\fBbackportpackage\fR is only recommended for testing backports in a
 | 
			
		||||
PPA, not uploading backports to the Ubuntu archive.
 | 
			
		||||
@ -67,9 +73,34 @@ PPA, not uploading backports to the Ubuntu archive.
 | 
			
		||||
.TP
 | 
			
		||||
.B UBUNTUTOOLS_BUILDER
 | 
			
		||||
The default builder for Ubuntu development tools that support it
 | 
			
		||||
(including \fBbackportpackage\fR. Supported are \fBpbuilder\fR(8) and
 | 
			
		||||
(including \fBbackportpackage\fR). Supported are \fBpbuilder\fR(8) and
 | 
			
		||||
\fBsbuild\fR(1). If unset and not provided on the command line,
 | 
			
		||||
\fBpbuilder\fR(8) is used.
 | 
			
		||||
.SH EXAMPLES
 | 
			
		||||
Test-build in your PPA a backport of znc from the current development
 | 
			
		||||
release to your workstation's release, deleting the build products
 | 
			
		||||
afterwards:
 | 
			
		||||
.IP
 | 
			
		||||
.nf
 | 
			
		||||
.B backportpackage -u ppa:\fIuser\fR/\fIppa\fB znc
 | 
			
		||||
.fi
 | 
			
		||||
.PP
 | 
			
		||||
Backport squashfs-tools from Maverick to both Karmic and Lucid and
 | 
			
		||||
test-build both locally, leaving all build products in the current
 | 
			
		||||
working directory:
 | 
			
		||||
.IP
 | 
			
		||||
.nf
 | 
			
		||||
.B backportpackage -b -s maverick -d karmic -d lucid -w . \\\\
 | 
			
		||||
.B "  "squashfs-tools
 | 
			
		||||
.fi
 | 
			
		||||
.PP
 | 
			
		||||
Fetch a package from a PPA, backport it to Hardy, then upload it back
 | 
			
		||||
to the same PPA:
 | 
			
		||||
.IP
 | 
			
		||||
.nf
 | 
			
		||||
.B backportpackage -d hardy -u ppa:\fIuser\fR/\fIppa\fR \\\\
 | 
			
		||||
.B "  "https://launchpad.net/\fIsome/file.dsc\fR
 | 
			
		||||
.fi
 | 
			
		||||
.SH AUTHOR
 | 
			
		||||
\fBbackportpackage\fR and this manpage were written by Evan Broder
 | 
			
		||||
<evan@ebroder.net>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user