mirror of
				https://git.launchpad.net/ubuntu-dev-tools
				synced 2025-10-31 05:54:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			365 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			365 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #! /usr/bin/env python
 | |
| # -*- coding: utf-8 -*-
 | |
| #
 | |
| # Copyright (C) 2007-2009 Siegfried-A. Gevatter <rainct@ubuntu.com>
 | |
| # With some changes by Iain Lane <iain@orangesquash.org.uk>
 | |
| # Based upon pbuilder-dist-simple by Jamin Collins and Jordan Mantha.
 | |
| #
 | |
| # ##################################################################
 | |
| #
 | |
| # 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.
 | |
| # 
 | |
| # See file /usr/share/common-licenses/GPL for more details.
 | |
| #
 | |
| # ##################################################################
 | |
| #
 | |
| # This script is a wrapper to be able to easily use pbuilder for
 | |
| # different distributions (eg, Gutsy, Hardy, Debian unstable, etc).
 | |
| #
 | |
| # You can create symlinks to a pbuilder-dist executable to get different
 | |
| # configurations. For example, a symlink called pbuilder-hardy will assume
 | |
| # that the target distribution is always meant to be Ubuntu Hardy.
 | |
| 
 | |
| import sys
 | |
| import os
 | |
| 
 | |
| debian_distros = ['etch', 'lenny', 'sid', 'stable', 'testing', 'unstable', 'experimental']
 | |
| 
 | |
| class pbuilder_dist:
 | |
| 	
 | |
| 	def __init__(self, builder):
 | |
| 		
 | |
| 		# Base directory where pbuilder will put all the files it creates.
 | |
| 		self.base = None
 | |
| 		
 | |
| 		# Name of the operation which pbuilder should perform.
 | |
| 		self.operation = None
 | |
| 		
 | |
| 		# Wheter additional components should be used or not. That is,
 | |
| 		# 'universe' and 'multiverse' for Ubuntu chroots and 'contrib'
 | |
| 		# and 'non-free' for Debian.
 | |
| 		self.extra_components = True
 | |
| 		
 | |
| 		# File where the log of the last operation will be saved.
 | |
| 		self.logfile = None
 | |
| 		
 | |
| 		# System architecture
 | |
| 		self.system_architecture = None
 | |
| 		
 | |
| 		# Build architecture
 | |
| 		self.build_architecture = None
 | |
| 		
 | |
| 		# System's distribution
 | |
| 		self.system_distro = None
 | |
| 		
 | |
| 		# Target distribution
 | |
| 		self.target_distro = None
 | |
| 		
 | |
| 		# This is an identificative string which will either take the form
 | |
| 		# 'distribution' or 'distribution-architecture'.
 | |
| 		self.chroot_string = None
 | |
| 		
 | |
| 		# Authentication method
 | |
| 		self.auth = 'sudo'
 | |
| 		
 | |
| 		# Builder
 | |
| 		self.builder = builder
 | |
| 		
 | |
| 		# Ensure that the used builder is installed
 | |
| 		for file in os.environ['PATH'].split(':'):
 | |
| 			if os.path.exists(os.path.join(file, builder)):
 | |
| 				builder = ''
 | |
| 				break
 | |
| 		if builder:
 | |
| 			print 'Error: Could not find "%s".' % builder
 | |
| 			sys.exit(1)
 | |
| 		
 | |
| 		##############################################################
 | |
| 		
 | |
| 		if 'PBUILDFOLDER' in os.environ:
 | |
| 			self.base = os.environ['PBUILDFOLDER']
 | |
| 		else:
 | |
| 			self.base = os.path.expanduser('~/pbuilder/')
 | |
| 
 | |
| 		if not os.path.exists(self.base):
 | |
| 			os.makedirs(self.base)
 | |
| 		
 | |
| 		if 'PBUILDAUTH' in os.environ:
 | |
| 			self.auth = os.environ['PBUILDAUTH']
 | |
| 		
 | |
| 		self.system_architecture = host_architecture()
 | |
| 		
 | |
| 		if not self.system_architecture or 'not found' in self.system_architecture:
 | |
| 			print 'Error: Not running on a Debian based system; could not detect its architecture.'
 | |
| 		
 | |
| 		if not os.path.isfile('/etc/lsb-release'):
 | |
| 			print 'Error: Not running on a Debian based system; could not find /etc/lsb-release.'
 | |
| 			exit(1)
 | |
| 		
 | |
| 		for line in open('/etc/lsb-release'):
 | |
| 			line = line.strip()
 | |
| 			if line.startswith('DISTRIB_CODENAME'):
 | |
| 				self.system_distro = line[17:]
 | |
| 				break
 | |
| 		
 | |
| 		if not self.system_distro:
 | |
| 			print 'Error: Could not determine what distribution you are running.'
 | |
| 			exit(1)
 | |
| 		
 | |
| 		self.target_distro = self.system_distro
 | |
| 		
 | |
| 		##############################################################
 | |
| 	
 | |
| 	def __getitem__(self, name):
 | |
| 		
 | |
| 		return getattr(self, name)
 | |
| 	
 | |
| 	def set_target_distro(self, distro):
 | |
| 		""" pbuilder_dist.set_target_distro(distro) -> None
 | |
| 		
 | |
| 		Check if the given target distribution name is correct, if it
 | |
| 		isn't know to the system ask the user for confirmation before
 | |
| 		proceeding, and finally either save the value into the appropiate
 | |
| 		variable or finalize pbuilder-dist's execution.
 | |
| 		
 | |
| 		"""
 | |
| 		
 | |
| 		if not distro.isalpha():
 | |
| 			print 'Error: «%s» is an invalid distribution codename.' % distro
 | |
| 			sys.exit(1)
 | |
| 		
 | |
| 		if not os.path.isfile(os.path.join('/usr/share/debootstrap/scripts/', distro)):
 | |
| 			if os.path.isdir('/usr/share/debootstrap/scripts/'):
 | |
| 				answer = ask('Warning: Unknown distribution «%s». Do you '\
 | |
| 					'want to continue [y/N]? ' % distro)
 | |
| 				if answer not in ('y', 'Y'):
 | |
| 					sys.exit(0)
 | |
| 			else:
 | |
| 				print 'Please install package "debootstrap".'
 | |
| 				sys.exit(1)
 | |
| 		
 | |
| 		self.target_distro = distro
 | |
| 	
 | |
| 	def set_operation(self, operation):
 | |
| 		""" pbuilder_dist.set_operation -> None
 | |
| 		
 | |
| 		Check if the given string is a valid pbuilder operation and
 | |
| 		depending on this either save it into the appropiate variable
 | |
| 		or finalize pbuilder-dist's execution.
 | |
| 		
 | |
| 		"""
 | |
| 		
 | |
| 		arguments = ('create', 'update', 'build', 'clean', 'login', 'execute')
 | |
| 		
 | |
| 		if operation not in arguments:
 | |
| 			if operation.endswith('.dsc'):
 | |
| 				if os.path.isfile(operation):
 | |
| 					self.operation = 'build'
 | |
| 					return operation
 | |
| 				else:
 | |
| 					print 'Error: Could not find file «%s».' % operation
 | |
| 					sys.exit(1)
 | |
| 			else:
 | |
| 				print 'Error: «%s» is not a recognized argument.' % operation
 | |
| 				print 'Please use one of those: ' + ', '.join(arguments) + '.'
 | |
| 				sys.exit(1)
 | |
| 		else:
 | |
| 			self.operation = operation
 | |
| 			return ''
 | |
| 	
 | |
| 	def get_command(self, remaining_arguments = None):
 | |
| 		""" pbuilder_dist.get_command -> string
 | |
| 		
 | |
| 		Generate the pbuilder command which matches the given configuration
 | |
| 		and return it as a string.
 | |
| 		
 | |
| 		"""
 | |
| 		
 | |
| 		if not self.build_architecture:
 | |
| 			self.chroot_string = self.target_distro
 | |
| 			self.build_architecture = self.system_architecture
 | |
| 		else:
 | |
| 			self.chroot_string = '%(target_distro)s-%(build_architecture)s' % self
 | |
| 		
 | |
| 		prefix = os.path.join(self.base, self.chroot_string)
 | |
| 		result = '%s_result/' % prefix
 | |
| 		
 | |
| 		if not self.logfile:
 | |
| 			self.logfile = os.path.normpath('%s/last_operation.log' % result)
 | |
| 		
 | |
| 		if not os.path.isdir(result):
 | |
| 			# Create the results directory, if it doesn't exist.
 | |
| 			os.makedirs(result)
 | |
| 		
 | |
| 		if self.builder == 'pbuilder':
 | |
| 			base = '--basetgz "%s-base.tgz"' % prefix
 | |
| 		elif self.builder == 'cowbuilder':
 | |
| 			base = '--basepath "%s-base.cow"' % prefix
 | |
| 		else:
 | |
| 			print 'Error: Unrecognized builder "%s".' % self.builder
 | |
| 			sys.exit(1)
 | |
| 		
 | |
| 		arguments = [
 | |
| 			'--%s' % self.operation,
 | |
| 			base,
 | |
| 			'--distribution "%(target_distro)s"' % self,
 | |
| 			'--buildresult "%s"' % result,
 | |
| 			'--logfile "%s"' % self.logfile,
 | |
| 			'--aptcache "/var/cache/apt/archives/"',
 | |
| 			### --mirror "${ARCHIVE}" \
 | |
| 			'--override-config',
 | |
| 			]
 | |
| 		
 | |
| 		if os.path.exists('/var/cache/archive/'):
 | |
| 			arguments.append('--bindmounts "/var/cache/archive/"')		
 | |
| 
 | |
| 		localrepo = '/var/cache/archive/%(target_distro)s' % self
 | |
| 		if os.path.exists(localrepo):
 | |
| 			arguments.append('--othermirror ' +\
 | |
| 				'"deb file:///var/cache/archive/ %(target_distro)s/"' % self)
 | |
| 		
 | |
| 		if self.target_distro in debian_distros:
 | |
| 			arguments.append('--mirror "ftp://ftp.debian.org/debian"')
 | |
| 			components = 'main'
 | |
| 			if self.extra_components:
 | |
| 				components += ' contrib non-free'
 | |
| 		else:
 | |
| 			components = 'main restricted'
 | |
| 			if self.extra_components:
 | |
| 				components += ' universe multiverse'
 | |
| 
 | |
| 		arguments.append('--components "%s"' % components)
 | |
| 		
 | |
| 		if self.build_architecture != self.system_architecture:
 | |
| 			arguments.append('--debootstrapopts --arch')
 | |
| 			arguments.append('--debootstrapopts "%(build_architecture)s"' % self)
 | |
| 		
 | |
| 		### $( [ $ISDEBIAN != "False" ] || echo "--aptconfdir \"${BASE_DIR}/etc/${DISTRIBUTION}/apt.conf/\"" ) \
 | |
| 		
 | |
| 		# Append remaining arguments
 | |
| 		if remaining_arguments:
 | |
| 			arguments.extend(remaining_arguments)
 | |
| 		
 | |
| 		return self.auth + ' /usr/sbin/' + self.builder + ' ' + ' '.join(arguments)
 | |
| 
 | |
| def host_architecture():
 | |
| 	""" host_architecture -> string
 | |
| 	
 | |
| 	Detect the host's architecture and return it as a string
 | |
| 	(i386/amd64/other values).
 | |
| 	
 | |
| 	"""
 | |
| 	
 | |
| 	return os.uname()[4].replace('x86_64', 'amd64').replace('i586', 'i386').replace('i686', 'i386')
 | |
| 
 | |
| 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 help(exit_code = 0):
 | |
| 	""" help() -> None
 | |
| 	
 | |
| 	Print a help message for pbuilder-dist, and exit with the given code.
 | |
| 	
 | |
| 	"""
 | |
| 	
 | |
| 	print 'See  man pbuilder-dist  for more information.'
 | |
| 	
 | |
| 	sys.exit(exit_code)
 | |
| 
 | |
| def main():
 | |
| 	""" main() -> None
 | |
| 	
 | |
| 	This is pbuilder-dist's main function. It creates a pbuilder_dist
 | |
| 	object, modifies all necessary settings taking data from the
 | |
| 	executable's name and command line options and finally either ends
 | |
| 	the script and runs pbuilder itself or exists with an error message.
 | |
| 	
 | |
| 	"""
 | |
| 	
 | |
| 	script_name = os.path.basename(sys.argv[0])
 | |
| 	parts = script_name.split('-')
 | |
| 	
 | |
| 	# Copy arguments into another list for save manipulation
 | |
| 	args = sys.argv[1:]
 | |
| 	
 | |
| 	if '-' in script_name and (parts[0] != 'pbuilder' and \
 | |
| 	parts[0] != 'cowbuilder') or len(parts) > 3:
 | |
| 		print 'Error: «%s» is not a valid name for a «pbuilder-dist» executable.' % script_name
 | |
| 		sys.exit(1)
 | |
| 	
 | |
| 	if len(args) < 1:
 | |
| 		print 'Insufficient number of arguments.'
 | |
| 		help(1)
 | |
| 	
 | |
| 	if args[0] in ('-h', '--help', 'help'):
 | |
| 		help(0)
 | |
| 	
 | |
| 	app = pbuilder_dist(parts[0])
 | |
| 	
 | |
| 	if len(parts) > 1 and parts[1] != 'dist' and '.' not in parts[1]:
 | |
| 		app.set_target_distro(parts[1])
 | |
| 	else:
 | |
| 		app.set_target_distro(args.pop(0))
 | |
| 	
 | |
| 	if len(parts) > 2:
 | |
| 		requested_arch = parts[2]
 | |
| 	elif args[0] in ('i386', 'amd64'):
 | |
| 		requested_arch = args.pop(0)
 | |
| 	else:
 | |
| 		requested_arch = None
 | |
| 	
 | |
| 	if requested_arch:
 | |
| 		if requested_arch in ('i386', 'amd64') and app.system_architecture == 'amd64':
 | |
| 			app.build_architecture = requested_arch
 | |
| 		else:
 | |
| 			print 'Error: Architecture switching is not supported on your system; wrong filename.'
 | |
| 			sys.exit(1)
 | |
| 	
 | |
| 	if 'mainonly' in sys.argv:
 | |
| 		app.extra_components = False
 | |
| 		args.remove('mainonly')
 | |
| 	
 | |
| 	if len(args) < 1:
 | |
| 		print 'Insufficient number of arguments.'
 | |
| 		help(1)
 | |
| 	
 | |
| 	# Parse the operation
 | |
| 	args = [app.set_operation(args.pop(0))] + args
 | |
| 	
 | |
| 	if app.operation == 'build' and not '.dsc' in ' '.join(args):
 | |
| 		print 'Error: You have to specify a .dsc file if you want to build.'
 | |
| 		sys.exit(1)
 | |
| 	
 | |
| 	# Execute the pbuilder command
 | |
| 	sys.exit(os.system(app.get_command(args)))
 | |
| 
 | |
| if __name__ == '__main__':
 | |
| 	
 | |
| 	try:
 | |
| 		main()
 | |
| 	except KeyboardInterrupt:
 | |
| 		print 'Manually aborted.'
 | |
| 		sys.exit(1)
 |