mirror of
https://git.launchpad.net/ubuntu-dev-tools
synced 2025-03-13 08:01:09 +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)
|