mirror of
				https://git.launchpad.net/ubuntu-dev-tools
				synced 2025-11-03 23:44:19 +00:00 
			
		
		
		
	* pbuilder-dist:
   - Fixed a bug which broke pbuilder-dist when "build" was omited; just
     giving a .dsc works now.
   - {p,cow}builder-dist will now complain if you try to build a .changes
     file (or anything else that isn't a .dsc).
		
	
			
		
			
				
	
	
		
			348 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			348 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#! /usr/bin/env python
 | 
						|
# -*- coding: utf-8 -*-
 | 
						|
#
 | 
						|
# Copyright (C) 2007-2008 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
 | 
						|
		
 | 
						|
		##############################################################
 | 
						|
		
 | 
						|
		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)):
 | 
						|
			answer = ask('Warning: Unknown distribution «%s». Do you want to continue [y/N]? ' % distro)
 | 
						|
			if answer not in ('y', 'Y'):
 | 
						|
				sys.exit(0)
 | 
						|
		
 | 
						|
		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
 | 
						|
		
 | 
						|
		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)
 |