mirror of
				https://git.launchpad.net/ubuntu-dev-tools
				synced 2025-10-31 05:54:03 +00:00 
			
		
		
		
	* ubuntutools.misc: Add a new "system_distribution_chain", which returns
a list starting with the current distribution and working its way up each distribution's parent. * ubuntutools.misc: Add a function to find the distribution that used a given release codename. * backportpackage, doc/backportpackage.1: Accept codenames from any distribution in the parenting chain. Makes it possible to, e.g., backport from Debian. (LP: #703099)
This commit is contained in:
		
						commit
						be202b94d5
					
				
							
								
								
									
										114
									
								
								backportpackage
									
									
									
									
									
								
							
							
						
						
									
										114
									
								
								backportpackage
									
									
									
									
									
								
							| @ -2,7 +2,7 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| # ################################################################## | ||||
| # | ||||
| # Copyright (C) 2010, Evan Broder <evan@ebroder.net> | ||||
| # Copyright (C) 2010-2011, Evan Broder <evan@ebroder.net> | ||||
| # Copyright (C) 2010, Benjamin Drung <bdrung@ubuntu.com> | ||||
| # | ||||
| # This program is free software; you can redistribute it and/or | ||||
| @ -28,11 +28,16 @@ import tempfile | ||||
| from launchpadlib.launchpad import Launchpad | ||||
| import lsb_release | ||||
| 
 | ||||
| from debian.debian_support import Version | ||||
| 
 | ||||
| from devscripts.logger import Logger | ||||
| 
 | ||||
| from ubuntutools.archive import UbuntuSourcePackage, DownloadError | ||||
| from ubuntutools.archive import SourcePackage, DebianSourcePackage, \ | ||||
|     UbuntuSourcePackage, DownloadError, rmadison | ||||
| from ubuntutools.config import UDTConfig, ubu_email | ||||
| from ubuntutools.builder import get_builder | ||||
| from ubuntutools.misc import system_distribution, vendor_to_distroinfo, \ | ||||
|     codename_to_distribution | ||||
| from ubuntutools.question import YesNoQuestion | ||||
| 
 | ||||
| def error(msg): | ||||
| @ -105,9 +110,9 @@ def parse(args): | ||||
|                            '(default: temporary dir)', | ||||
|                       metavar='WORKDIR') | ||||
|     parser.add_option('-m', '--mirror', | ||||
|                       dest='ubuntu_mirror', | ||||
|                       dest='mirror', | ||||
|                       default=None, | ||||
|                       help='Preferred Ubuntu mirror (default: Launchpad)', | ||||
|                       help='Preferred mirror (default: Launchpad)', | ||||
|                       metavar='INSTANCE') | ||||
|     parser.add_option('-l', '--lpinstance', | ||||
|                       dest='lpinstance', | ||||
| @ -134,58 +139,83 @@ def parse(args): | ||||
|         opts.workdir = config.get_value('WORKDIR') | ||||
|     if opts.lpinstance is None: | ||||
|         opts.lpinstance = config.get_value('LPINSTANCE') | ||||
|     if opts.ubuntu_mirror is None: | ||||
|         opts.ubuntu_mirror = config.get_value('UBUNTU_MIRROR') | ||||
|     if not opts.upload and not opts.workdir: | ||||
|         parser.error('Please specify either a working dir or an upload target!') | ||||
| 
 | ||||
|     return opts, args | ||||
|     return opts, args, config | ||||
| 
 | ||||
| def find_release_package(launchpad, package, version, source_release): | ||||
|     ubuntu = launchpad.distributions['ubuntu'] | ||||
|     archive = ubuntu.main_archive | ||||
|     series = ubuntu.getSeries(name_or_version=source_release) | ||||
|     status = 'Published' | ||||
|     for pocket in ('Updates', 'Security', 'Release'): | ||||
|         try: | ||||
|             srcpkg = archive.getPublishedSources(source_name=package, | ||||
|                                                  distro_series=series, | ||||
|                                                  pocket=pocket, | ||||
|                                                  status=status, | ||||
|                                                  exact_match=True)[0] | ||||
|             break | ||||
|         except IndexError: | ||||
| def get_current_version(package, distribution, source_release): | ||||
|     info = vendor_to_distroinfo(distribution) | ||||
|     source_release = info().codename(source_release, default=source_release) | ||||
| 
 | ||||
|     latest_version = None | ||||
| 
 | ||||
|     for record in rmadison(distribution.lower(), package, suite=source_release): | ||||
|         if 'source' not in record: | ||||
|             continue | ||||
| 
 | ||||
|         if (not latest_version or | ||||
|             Version(latest_version) < Version(record['version'])): | ||||
|             latest_version = record['version'] | ||||
| 
 | ||||
|     return latest_version | ||||
| 
 | ||||
| def find_release_package(launchpad, mirror, workdir, package, version, | ||||
|                          source_release, config): | ||||
|     srcpkg = None | ||||
| 
 | ||||
|     if source_release: | ||||
|         distribution = codename_to_distribution(source_release) | ||||
| 
 | ||||
|         if not distribution: | ||||
|             error('Unknown release codename %s' % source_release) | ||||
|     else: | ||||
|         distribution = system_distribution() | ||||
|     mirrors = [mirror] if mirror else [] | ||||
| 
 | ||||
|     mirrors.append(config.get_value('%s_MIRROR' % distribution.upper())) | ||||
| 
 | ||||
|     if not version: | ||||
|         version = get_current_version(package, distribution, source_release) | ||||
| 
 | ||||
|     if not version: | ||||
|         error('Unable to find package %s in release %s.' % | ||||
|               (package, source_release)) | ||||
| 
 | ||||
|     if version and version != srcpkg.source_package_version: | ||||
|         error('Requested backport of version %s but %s is at version %s.' % | ||||
|               (version, package, srcpkg.source_package_version)) | ||||
|     if distribution == 'Debian': | ||||
|         srcpkg = DebianSourcePackage(package, | ||||
|                                      version, | ||||
|                                      workdir=workdir, | ||||
|                                      lp=launchpad, | ||||
|                                      mirrors=mirrors) | ||||
|     elif distribution == 'Ubuntu': | ||||
|         srcpkg = UbuntuSourcePackage(package, | ||||
|                                      version, | ||||
|                                      workdir=workdir, | ||||
|                                      lp=launchpad, | ||||
|                                      mirrors=mirrors) | ||||
| 
 | ||||
|     return srcpkg | ||||
| 
 | ||||
| def find_package(launchpad, mirror, workdir, package, version, source_release): | ||||
| def find_package(launchpad, mirror, workdir, package, version, source_release, | ||||
|                  config): | ||||
|     "Returns the SourcePackage" | ||||
|     if package.endswith('.dsc'): | ||||
|         return UbuntuSourcePackage(version=version, dscfile=package, | ||||
|                                    workdir=workdir, lp=launchpad, | ||||
|                                    mirrors=[mirror]) | ||||
|         return SourcePackage(version=version, dscfile=package, | ||||
|                              workdir=workdir, lp=launchpad, | ||||
|                              mirrors=(mirror,)) | ||||
| 
 | ||||
|     if not source_release and not version: | ||||
|         source_release = launchpad.distributions['ubuntu'].current_series.name | ||||
|         info = vendor_to_distroinfo(system_distribution()) | ||||
|         source_release = info().devel() | ||||
| 
 | ||||
|     component = None | ||||
|     # If source_release is specified, then version is just for verification | ||||
|     if source_release: | ||||
|         srcpkg = find_release_package(launchpad, package, version, | ||||
|                                       source_release) | ||||
|         version = srcpkg.source_package_version | ||||
|         component = srcpkg.component_name | ||||
|     srcpkg = find_release_package(launchpad, mirror, workdir, package, version, | ||||
|                                   source_release, config) | ||||
|     if version and srcpkg.version != version: | ||||
|         error('Requested backport of version %s but version of %s in %s is %s' | ||||
|               % (version, package, source_release, srcpkg.version)) | ||||
| 
 | ||||
|     return UbuntuSourcePackage(package, version, component, workdir=workdir, | ||||
|                                lp=launchpad, mirrors=[mirror]) | ||||
|     return srcpkg | ||||
| 
 | ||||
| def get_backport_version(version, suffix, upload, release): | ||||
|     backport_version = version + ('~%s1' % release) | ||||
| @ -257,10 +287,9 @@ def do_backport(workdir, pkg, suffix, release, build, builder, update, upload, | ||||
|     shutil.rmtree(srcdir) | ||||
| 
 | ||||
| def main(args): | ||||
|     os.environ['DEB_VENDOR'] = 'Ubuntu' | ||||
|     ubu_email() | ||||
| 
 | ||||
|     opts, (package_or_dsc,) = parse(args[1:]) | ||||
|     opts, (package_or_dsc,), config = parse(args[1:]) | ||||
| 
 | ||||
|     script_name = os.path.basename(sys.argv[0]) | ||||
|     launchpad = Launchpad.login_anonymously(script_name, opts.lpinstance) | ||||
| @ -282,11 +311,12 @@ def main(args): | ||||
| 
 | ||||
|     try: | ||||
|         pkg = find_package(launchpad, | ||||
|                            opts.ubuntu_mirror, | ||||
|                            opts.mirror, | ||||
|                            workdir, | ||||
|                            package_or_dsc, | ||||
|                            opts.version, | ||||
|                            opts.source_release) | ||||
|                            opts.source_release, | ||||
|                            config) | ||||
|         pkg.pull() | ||||
| 
 | ||||
|         for release in opts.dest_releases: | ||||
|  | ||||
							
								
								
									
										14
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,17 @@ | ||||
| ubuntu-dev-tools (0.126) UNRELEASED; urgency=low | ||||
| 
 | ||||
|   [ Evan Broder ] | ||||
|   * ubuntutools.misc: Add a new "system_distribution_chain", which returns | ||||
|     a list starting with the current distribution and working its way up | ||||
|     each distribution's parent. | ||||
|   * ubuntutools.misc: Add a function to find the distribution that | ||||
|     used a given release codename. | ||||
|   * backportpackage, doc/backportpackage.1: Accept codenames from any | ||||
|     distribution in the parenting chain. Makes it possible to, e.g., | ||||
|     backport from Debian. (LP: #703099) | ||||
| 
 | ||||
|  -- Evan Broder <evan@ebroder.net>  Sat, 11 Jun 2011 05:11:23 -0700 | ||||
| 
 | ||||
| ubuntu-dev-tools (0.125ubuntu1) oneiric; urgency=low | ||||
| 
 | ||||
|   [ Benjamin Drung ] | ||||
|  | ||||
| @ -10,10 +10,11 @@ backportpackage \- helper to test package backports | ||||
| .PP | ||||
| .B backportpackage \-h | ||||
| .SH DESCRIPTION | ||||
| \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. | ||||
| \fBbackportpackage\fR fetches a package from one distribution release | ||||
| or from a specified .dsc path or URL and creates a no-change backport | ||||
| of that package to one or more Ubuntu releases release, optionally | ||||
| doing a test build of the package and/or uploading the resulting | ||||
| backport for testing. | ||||
| .PP | ||||
| Unless a working directory is specified, the backported package is | ||||
| fetched and built in a temporary directory in \fB/tmp\fR, which is | ||||
| @ -29,10 +30,11 @@ is unspecified, then \fBbackportpackage\fR defaults to the release on | ||||
| which it is currently running. | ||||
| .TP | ||||
| .B \-s \fISOURCE\fR, \fB\-\-source\fR=\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 | ||||
| release. | ||||
| Backport the package from the specified release, which can be any | ||||
| release of your distribution or any of your distribution's parent | ||||
| distributions. If neither this option nor \fB\-\-version\fR are | ||||
| specified, then \fBbackportpackage\fR defaults to the current | ||||
| development release for your distribution. | ||||
| .TP | ||||
| .B \-S \fISUFFIX\fR, \fB\-\-suffix\fR=\fISUFFIX\fR | ||||
| Add the specified suffix to the version number when | ||||
| @ -72,9 +74,10 @@ 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). This option is ignored if a .dsc URL | ||||
| or path is passed in instead of a source package name. | ||||
| package\fR in your distribution's publishing history, regardless of | ||||
| the release in which it was published (or if 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, \fB\-\-workdir\fR=\fIWORKDIR\fR | ||||
| If \fIWORKDIR\fR is specified, then all files are downloaded, | ||||
| @ -82,7 +85,7 @@ unpacked, built into, and otherwise manipulated in | ||||
| \fIWORKDIR\fR. Otherwise, a temporary directory is created, which is | ||||
| deleted before \fIbackportpackage\fR exits. | ||||
| .TP | ||||
| .B \-m \fIUBUNTU_MIRROR\fR, \fB\-\-mirror\fR=\fIUBUNTU_MIRROR\fR | ||||
| .B \-m \fIMIRROR\fR, \fB\-\-mirror\fR=\fIMIRROR\fR | ||||
| Use the specified mirror. | ||||
| Should be in the form \fBhttp://archive.ubuntu.com/ubuntu\fR. | ||||
| If the package isn't found on this mirror, \fBbackportpackage\fR | ||||
| @ -124,7 +127,12 @@ The default value for \fB--update\fR. | ||||
| The default value for \fB--workdir\fR. | ||||
| .TP | ||||
| .BR BACKPORTPACKAGE_UBUNTU_MIRROR ", " UBUNTUTOOLS_UBUNTU_MIRROR | ||||
| The default value for \fB\-\-mirror\fR. | ||||
| The default value for \fB\-\-mirror\fR if the specified \fISOURCE\fR | ||||
| release is an Ubuntu release. | ||||
| .TP | ||||
| .BR BACKPORTPACKAGE_DEBIAN_MIRROR ", " UBUNTUTOOLS_DEBIAN_MIRROR | ||||
| The default value for \fB\-\-mirror\fR if the specified \fISOURCE\fR | ||||
| release is a Debian release. | ||||
| .TP | ||||
| .BR BACKPORTPACKAGE_LPINSTANCE ", " UBUNTUTOOLS_LPINSTANCE | ||||
| The default value for \fB--lpinstance\fR. | ||||
|  | ||||
| @ -106,6 +106,14 @@ class DistroInfo(object): | ||||
|         """Get list of all supported distributions based on the given date.""" | ||||
|         raise NotImplementedError() | ||||
| 
 | ||||
|     def valid(self, codename): | ||||
|         """Check if the given codename is known.""" | ||||
|         return codename in self.all | ||||
| 
 | ||||
|     def codename(self, release, date=None, default=None): | ||||
|         """Map codename aliases to the codename they describe""" | ||||
|         return release | ||||
| 
 | ||||
|     def unsupported(self, date=None): | ||||
|         """Get list of all unsupported distributions based on the given date.""" | ||||
|         if date is None: | ||||
| @ -167,6 +175,11 @@ class DebianDistroInfo(DistroInfo): | ||||
|             raise DistroDataOutdated() | ||||
|         return distros[-2]["series"] | ||||
| 
 | ||||
|     def valid(self, codename): | ||||
|         """Check if the given codename is known.""" | ||||
|         return DistroInfo.valid(self, codename) or \ | ||||
|                codename in ["unstable", "testing", "stable", "old"] | ||||
| 
 | ||||
| 
 | ||||
| class UbuntuDistroInfo(DistroInfo): | ||||
|     """provides information about Ubuntu's distributions""" | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| # Copyright (C) 2008,      Jonathan Davies <jpds@ubuntu.com>, | ||||
| #               2008-2009, Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>, | ||||
| #               2010,      Stefano Rivera <stefanor@ubuntu.com> | ||||
| #               2011,      Evan Broder <evan@ebroder.net> | ||||
| # | ||||
| # ################################################################## | ||||
| # | ||||
| @ -28,9 +29,49 @@ import os.path | ||||
| from subprocess import Popen, PIPE | ||||
| import sys | ||||
| 
 | ||||
| from ubuntutools import distro_info | ||||
| from ubuntutools.lp.udtexceptions import PocketDoesNotExistError | ||||
| 
 | ||||
| _system_distribution = None | ||||
| _system_distribution_chain = [] | ||||
| def system_distribution_chain(): | ||||
|     """ system_distribution_chain() -> [string] | ||||
| 
 | ||||
|     Detect the system's distribution as well as all of its parent | ||||
|     distributions and return them as a list of strings, with the | ||||
|     system distribution first (and the greatest grandparent last). If | ||||
|     the distribution chain can't be determined, print an error message | ||||
|     and return an empty list. | ||||
|     """ | ||||
|     global _system_distribution_chain | ||||
|     if len(_system_distribution_chain) == 0: | ||||
|         try: | ||||
|             p = Popen(('dpkg-vendor', '--query', 'Vendor'), | ||||
|                       stdout=PIPE) | ||||
|             _system_distribution_chain.append(p.communicate()[0].strip()) | ||||
|         except OSError: | ||||
|             print ('Error: Could not determine what distribution you are ' | ||||
|                    'running.') | ||||
|             return [] | ||||
| 
 | ||||
|         while True: | ||||
|             try: | ||||
|                 p = Popen(('dpkg-vendor', | ||||
|                            '--vendor', _system_distribution_chain[-1], | ||||
|                            '--query', 'Parent'), | ||||
|                           stdout=PIPE) | ||||
|                 parent = p.communicate()[0].strip() | ||||
|                 # Don't check return code, because if a vendor has no | ||||
|                 # parent, dpkg-vendor returns 1 | ||||
|                 if not parent: | ||||
|                     break | ||||
|                 _system_distribution_chain.append(parent) | ||||
|             except Exception: | ||||
|                 print ('Error: Could not determine the parent of the ' | ||||
|                        'distribution %s' % _system_distribution_chain[-1]) | ||||
|                 return [] | ||||
| 
 | ||||
|     return _system_distribution_chain | ||||
| 
 | ||||
| def system_distribution(): | ||||
|     """ system_distro() -> string | ||||
| 
 | ||||
| @ -38,24 +79,7 @@ def system_distribution(): | ||||
|     name of the distribution can't be determined, print an error message | ||||
|     and return None. | ||||
|     """ | ||||
|     global _system_distribution | ||||
|     if _system_distribution is None: | ||||
|         try: | ||||
|             if os.path.isfile('/usr/bin/dpkg-vendor'): | ||||
|                 process = Popen(('dpkg-vendor', '--query', 'vendor'), | ||||
|                                 stdout=PIPE) | ||||
|             else: | ||||
|                 process = Popen(('lsb_release', '-cs'), stdout=PIPE) | ||||
|             output = process.communicate()[0] | ||||
|         except OSError: | ||||
|             print ('Error: Could not determine what distribution you are ' | ||||
|                    'running.') | ||||
|             return None | ||||
|         if process.returncode != 0: | ||||
|             print 'Error determininng system distribution' | ||||
|             return None | ||||
|         _system_distribution = output.strip() | ||||
|     return _system_distribution | ||||
|     return system_distribution_chain()[0] | ||||
| 
 | ||||
| def host_architecture(): | ||||
|     """ host_architecture -> string | ||||
| @ -128,3 +152,30 @@ def require_utf8(): | ||||
|         print >> sys.stderr, ("This program only functions in a UTF-8 locale. " | ||||
|                               "Aborting.") | ||||
|         sys.exit(1) | ||||
| 
 | ||||
| 
 | ||||
| _vendor_to_distroinfo = {"Debian": distro_info.DebianDistroInfo, | ||||
|                          "Ubuntu": distro_info.UbuntuDistroInfo} | ||||
| def vendor_to_distroinfo(vendor): | ||||
|     """ vendor_to_distroinfo(string) -> DistroInfo class | ||||
| 
 | ||||
|     Convert a string name of a distribution into a DistroInfo subclass | ||||
|     representing that distribution, or None if the distribution is | ||||
|     unknown. | ||||
|     """ | ||||
|     return _vendor_to_distroinfo.get(vendor) | ||||
| 
 | ||||
| def codename_to_distribution(codename): | ||||
|     """ codename_to_distribution(string) -> string | ||||
| 
 | ||||
|     Finds a given release codename in your distribution's genaology | ||||
|     (i.e. looking at the current distribution and its parents), or | ||||
|     print an error message and return None if it can't be found | ||||
|     """ | ||||
|     for distro in system_distribution_chain(): | ||||
|         info = vendor_to_distroinfo(distro) | ||||
|         if not info: | ||||
|             continue | ||||
| 
 | ||||
|         if info().valid(codename): | ||||
|             return distro | ||||
|  | ||||
| @ -58,6 +58,12 @@ class DebianDistroInfoTestCase(unittest.TestCase): | ||||
|         """Test: Get latest testing Debian distribution.""" | ||||
|         self.assertEqual(self._distro_info.testing(self._date), "squeeze") | ||||
| 
 | ||||
|     def test_valid(self): | ||||
|         """Test: Check for valid Debian distribution.""" | ||||
|         self.assertTrue(self._distro_info.valid("sid")) | ||||
|         self.assertTrue(self._distro_info.valid("stable")) | ||||
|         self.assertFalse(self._distro_info.valid("foobar")) | ||||
| 
 | ||||
|     def test_unsupported(self): | ||||
|         """Test: List all unsupported Debian distribution.""" | ||||
|         unsupported = ["buzz", "rex", "bo", "hamm", "slink", "potato", "woody", | ||||
| @ -111,3 +117,8 @@ class UbuntuDistroInfoTestCase(unittest.TestCase): | ||||
|                            "gutsy", "intrepid", "jaunty"]) | ||||
|         self.assertEqual(unsupported - | ||||
|                          set(self._distro_info.unsupported()), set()) | ||||
| 
 | ||||
|     def test_valid(self): | ||||
|         """Test: Check for valid Ubuntu distribution.""" | ||||
|         self.assertTrue(self._distro_info.valid("lucid")) | ||||
|         self.assertFalse(self._distro_info.valid("42")) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user