mirror of
				https://git.launchpad.net/ubuntu-dev-tools
				synced 2025-11-04 07:54:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			350 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			350 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#! /usr/bin/env python
 | 
						|
# -*- coding: utf-8 -*-
 | 
						|
#
 | 
						|
# Copyright (C) 2007-2010 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/cowbuilder 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
 | 
						|
 | 
						|
import ubuntutools.misc
 | 
						|
 | 
						|
debian_distros = ['etch', 'lenny', 'squeeze', '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)
 | 
						|
		
 | 
						|
		##############################################################
 | 
						|
		
 | 
						|
		self.base = os.path.expanduser(os.environ.get('PBUILDFOLDER', '~/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 = ubuntutools.misc.host_architecture()
 | 
						|
		self.system_distro = ubuntutools.misc.system_distribution()
 | 
						|
		if not self.system_architecture or not self.system_distro:
 | 
						|
			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 and self.operation != 'login':
 | 
						|
			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,
 | 
						|
			'--aptcache "/var/cache/apt/archives/"',
 | 
						|
			'--override-config',
 | 
						|
			]
 | 
						|
 | 
						|
		if self.logfile:
 | 
						|
			arguments.append('--logfile %s' % self.logfile)
 | 
						|
		
 | 
						|
		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:
 | 
						|
			arguments.append('--mirror "http://mirrors.kernel.org/ubuntu/"')
 | 
						|
			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)
 | 
						|
		
 | 
						|
		apt_conf_dir = os.path.join(self.base, 'etc/%(target_distro)s/apt.conf' % self)
 | 
						|
		if os.path.exists(apt_conf_dir):
 | 
						|
			arguments.append('--aptconfdir "%s"' % apt_conf_dir)
 | 
						|
		
 | 
						|
		# Append remaining arguments
 | 
						|
		if remaining_arguments:
 | 
						|
			arguments.extend(remaining_arguments)
 | 
						|
		
 | 
						|
		return '%s /usr/sbin/%s %s' % (self.auth, self.builder,
 | 
						|
			' '.join(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 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 len(args) > 0 and 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
 | 
						|
	if not '--debug-echo' in args:
 | 
						|
		sys.exit(os.system(app.get_command(args)))
 | 
						|
	else:
 | 
						|
		print app.get_command((arg for arg in args if arg)).replace(
 | 
						|
			' --debug-echo', '')
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
	
 | 
						|
	try:
 | 
						|
		main()
 | 
						|
	except KeyboardInterrupt:
 | 
						|
		print 'Manually aborted.'
 | 
						|
		sys.exit(1)
 |