Reimplement pbuilder-dist in python.

This commit is contained in:
Siegfried-Angel Gevatter Pujals 2008-03-12 00:40:45 +01:00
parent 670db8f99d
commit eb67a7bbac

View File

@ -1,8 +1,8 @@
#!/bin/sh #! /usr/bin/env python
# -*- coding: utf-8 -*-
# #
# Copyright (C) Jamin W. Collins <jcollins@asgardsrealm.net>
# Copyright (C) Jordan Mantha <mantha@ubuntu.com>
# Copyright (C) 2007-2008 Siegfried-A. Gevatter <rainct@ubuntu.com> # Copyright (C) 2007-2008 Siegfried-A. Gevatter <rainct@ubuntu.com>
# Based upon pbuilder-dist-simple by Jamin Collins and Jordan Mantha.
# #
# License: GPLv2 or later # License: GPLv2 or later
# #
@ -11,300 +11,297 @@
# #
# You can create symlinks to a pbuilder-dist executable to get different # You can create symlinks to a pbuilder-dist executable to get different
# configurations. For example, a symlink called pbuilder-hardy will assume # configurations. For example, a symlink called pbuilder-hardy will assume
# that the target distribution is always Ubuntu Hardy. # that the target distribution is always meant to be Ubuntu Hardy.
###################################################################### import sys
import os
# Base directory where pbuilder will put all the files it creates. class pbuilder_dist:
# This is overriden by the global variable $PBUILDFOLDER
BASE_DIR="$HOME/pbuilder"
# Change this to 0 if you don't want additional components to be used. def __init__(self):
# That is, 'universe' and 'multiverse' for Ubuntu chroots and 'contrib'
# and 'non-free' for Debian. (This option can be overwriten at runtime).
EXTRACOMP=1
# Change this to 1 if you want the log for the last operation to be saved # Base directory where pbuilder will put all the files it creates.
# in the base directory by default (it will be named '.lastlog'). self.base = None
SAVELOG=0
# Allow this script to use /var/cache/apt/archives/ when possible. # Name of the operation which pbuilder should perform.
if [ -z $SYSCACHE ] self.operation = None
then
SYSCACHE=1
fi
###################################################################### # 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
# Detect system architecture # Wheter the log for the last operation should be saved in the
REALARCH=$(dpkg-architecture -qDEB_HOST_ARCH) # base directory by default. If False, it will be saved in /tmp.
self.save_log = False
# Detect Ubuntu distribution (wheter it is gutsy, hardy, etc.) # File where the log of the last operation will be saved.
SYSDIST=$(lsb_release -cs 2>/dev/null) self.logfile = None
# Overwrite hardcoded base directory by that one in the global variable # System architecture
if [ $PBUILDFOLDER ] && [ $PBUILDFOLDER != "" ] self.system_architecture = None
then
BASE_DIR=$PBUILDFOLDER
fi
###################################################################### # Build architecture
self.build_architecture = None
# Abort if the name of the executable has hypens but it doesn't # System's distribution
# start with "pbuilder-". self.system_distro = None
if [ -n $(basename $0 | grep '-') ] && [ $(basename $0 | cut -d'-' -f1) != 'pbuilder' ]
then
echo "Error: " $(basename $0) " is not a valid name for a pbuilder-dist executable."
exit 1
fi
# Detect if the script has it's original name or if a symlink is being used, # Target distribution
# and if it's a symlink extract the information that it contains. self.target_distro = None
if [ -n $(basename $0 | grep '-') ] && [ `basename $0` != 'pbuilder-dist' ]
then
ORIGINAL_NAME=0
DISTRIBUTION=$(basename $0 | cut -d'-' -f2)
ARCHITECTURE=$(basename $0 | cut -d'-' -f3)
else
ORIGINAL_NAME=1
DISTRIBUTION=$1
shift 1
fi
# Check if the choosen architecture is supported on the user's system. # This is an identificative string which will either take the form
if [ "$1" = 'i386' ] || [ "$1" = 'amd64' ] # 'distribution' or 'distribution-architecture'.
then self.chroot_string = None
if [ $REALARCH = 'amd64' ]; then
ARCHITECTURE=$1
else
echo "Warning: Architecture switching is not supported on your system; ignoring argument '$1'."
fi
shift 1 # Proxy
fi self.proxy = None
# If architecture hasn't been set yet, use the system's one. # Authentication method
if [ -z "$ARCHITECTURE" ] self.auth = 'sudo'
then
ARCHITECTURE=$REALARCH
fi
# Check if there's a component modifier ##############################################################
if [ "$1" = 'mainonly' ]; then
EXTRACOMP=0
shift 1
elif [ "$1" = 'allcomp' ]; then
EXTRACOMP=1
shift 1
fi
# Check if the default logging preferences should be overwriten if 'PBUILDFOLDER' in os.environ:
if [ "$1" = 'withlog' ]; then self.base = os.environ['PBUILDFOLDER']
SAVELOG=1 else:
shift 1 self.base = os.path.expanduser('~/pbuilder/')
elif [ "$1" = 'nolog' ]; then
SAVELOG=0
shift 1
fi
# Check if some proxy should be used. if 'PBUILDAUTH' in os.environ:
if [ -n "$http_proxy" ] self.auth = os.environ['PBUILDAUTH']
then
PROXY=$http_proxy
fi
if [ -z "$PROXY" ] && [ -n "$HTTP_PROXY" ] self.system_architecture = host_architecture()
then
PROXY=$HTTP_PROXY
fi
###################################################################### 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.'
usage() if not os.path.isfile('/etc/lsb-release'):
{ print 'Error: Not running on a Debian based system; could not find /etc/lsb-release.'
echo "Usage: $0 "$( [ $ORIGINAL_NAME = 0 ] || echo "<distribution> " )$( [ $ARCHITECTURE != "amd64" ] || echo "[i386|amd64] " )"[mainonly|allcomp] [withlog|nolog] <operation>" exit(1)
}
distdata() for line in open('/etc/lsb-release'):
{ line = line.strip()
# Populate variables with Debian / Ubuntu specific data if line.startswith('DISTRIB_CODENAME'):
if [ "$1" = "debian" ] self.system_distro = line[17:]
then break
# Set Debian specific data
ISDEBIAN=True if not self.system_distro:
print 'Error: Could not determine what distribution you are running.'
exit(1)
if [ -z $ARCHIVE ] self.target_distro = self.system_distro
then
ARCHIVE="http://ftp.debian.org"
fi
COMPONENTS="main"$( [ $EXTRACOMP = 0 ] || echo " contrib non-free" ) if 'http_proxy' in os.environ:
else self.base = os.environ['http_proxy']
# Set Ubuntu specific data elif 'HTTP_PROXY' in os.environ:
self.base = os.environ['HTTP_PROXY']
ISDEBIAN=False ##############################################################
if [ -z $ARCHIVE ] def __getitem__(self, name):
then
ARCHIVE="http://archive.ubuntu.com/ubuntu"
fi
COMPONENTS="main restricted"$( [ $EXTRACOMP = 0 ] || echo " universe multiverse" ) return getattr(self, name)
fi
}
###################################################################### def _calculate(self):
""" pbuilder_dist.calculate(distro) -> None
# Check if there is at least one argument remaining. Do all necessary variable changes (and therefore required checks)
if [ $# -lt 1 ] before the string that will be executed is generated. At this
then point it's expected that no more variables will be modified
echo "You provided an insufficent number of arguments." outside this class.
usage
exit 1
fi
###################################################################### """
# Check if the distribution exists, and fill the variables that change if not self.build_architecture:
# depending on wheter the target distribution is Ubuntu or Debian. self.chroot_string = self.target_distro
case $DISTRIBUTION in self.build_architecture = self.system_architecture
dapper|edgy|feisty|gutsy|hardy) else:
distdata ubuntu self.chroot_string = '%(target_distro)s-%(build_architecture)s' % self
;;
oldstable|sarge|stable|etch|testing|lenny|unstable|sid|experimental) if not self.logfile:
distdata debian self.logfile = '/etc/pbuilder-%(chroot_string)s.log' % self
;; else:
self.logfile = '%(base)s/.%(chroot_string)s.log' % self
*) def set_target_distro(self, distro):
if [ ! -d $BASE_DIR/${DISTRIBUTION}-* ] """ pbuilder_dist.set_target_distro(distro) -> None
then
echo -n "Warning: Unknown distribution «$DISTRIBUTION». Do you want to continue [y/N]? "
read continue
if [ "$continue" != 'y' ] && [ "$continue" != 'Y' ] Check if the given target distribution name is correct, if it
then isn't know to the system ask the user for confirmation before
echo "Aborting..." proceeding, and finally either save the value into the appropiate
exit 1 variable or finalize pbuilder-dist's execution.
fi
fi
distdata ubuntu """
;;
esac
# Save the selected operation in a variable. if not distro.isalpha():
OPERATION=$1 print 'Error: «%s» is an invalid distribution codename.'
shift 1 sys.exit(1)
# Check if the selected operation is an alias for another one. if not os.path.isfile(os.path.join('/usr/share/debootstrap/scripts/', distro)):
case "$OPERATION" in answer = ask('Warning: Unknown distribution «%s». Do you want to continue [y/N]? ' % distro)
upgrade) if answer not in ('y', 'Y'):
OPERATION=update sys.exit(0)
;;
esac
# Check if the selected operation is correct, or if it is an alias for self.target_distro = distro
# another one.
case "$OPERATION" in
create|update|build|clean|login|execute)
# Allright.
;;
upgrade) def set_operation(self, operation):
OPERATION=update """ pbuilder_dist.set_operation -> None
;;
*) Check if the given string is a valid pbuilder operation and
if [ ${OPERATION##*.} = 'dsc' ] depending on this either save it into the appropiate variable
then or finalize pbuilder-dist's execution.
OPERATION=build
else
echo "Unrecognized argument '$OPERATION'. Please use one of those:"
echo " create"
echo " update"
echo " build"
echo " clean"
echo " login"
echo " execute"
exit 1
fi
;;
esac
# Determine the base name for the chroot tarball and the folder where the """
# resulting files will be stored.
FOLDERBASE="${DISTRIBUTION}-$ARCHITECTURE"
# Create the folder where the resulting files will be placed (if the arguments = ('create', 'update', 'build', 'clean', 'login', 'execute')
# option is build), if it doesn't exist yet.
if [ ! -d $BASE_DIR/${FOLDERBASE}_result ]
then
mkdir -p $BASE_DIR/${FOLDERBASE}_result
fi
# Determine wheter system cache should be used or not. if operation not in arguments:
if [ $SYSCACHE = 1 ] && [ "$SYSDIST" = "$DISTRIBUTION" ] && [ "$REALARCH" = "$ARCHITECTURE"] print 'Error: «%s» is not a recognized argument.' % operation
then print 'Please use one of those: ' + ', '.join(arguments) + '.'
DEBCACHE='/var/cache/apt/archives/' sys.exit(1)
fi
# If it's an Ubuntu system, create an editable configuration file, self.operation = operation
# and if it's a stable release add the -security and -updates repositories.
if [ $ISDEBIAN = "False" ]
then
if [ ! -d $BASE_DIR/etc/$DISTRIBUTION/apt.conf/ ]
then
mkdir -p $BASE_DIR/etc/$DISTRIBUTION/apt.conf
fi
if [ ! -e $BASE_DIR/etc/$DISTRIBUTION/apt.conf/sources.list ]
then
echo "deb $ARCHIVE $DISTRIBUTION $COMPONENTS" > $BASE_DIR/etc/$DISTRIBUTION/apt.conf/sources.list
case $DISTRIBUTION in
dapper|edgy|feisty|gutsy )
cat >> $BASE_DIR/etc/$DISTRIBUTION/apt.conf/sources.list <<EOF
deb $ARCHIVE $DISTRIBUTION-security $COMPONENTS
deb $ARCHIVE $DISTRIBUTION-updates $COMPONENTS
EOF
;;
* )
;;
esac
fi
fi
#if [ -z "$PBUILDAUTH" ] def get_command(self, remaining_arguments = None):
#then """ pbuilder_dist.get_command -> string
# if [ -n "$DESKTOP_SESSION" ]
# then
# case $DESKTOP_SESSION in
# gnome )
# SUDOREPLACE="gksudo -D \"Pbuilder\""
# ;;
# kde|kde4 )
# SUDOREPLACE="kdesudo -d --comment \"Pbuilder\""
# ;;
# * )
# SUDOREPLACE="sudo"
# ;;
# esac
# else
# SUDOREPLACE=sudo
# fi
#else
# SUDOREPLACE=$PBUILDAUTH
#fi
sudo pbuilder $OPERATION \ Generate the pbuilder command which matches the given configuration
--basetgz "$BASE_DIR/${FOLDERBASE}-base.tgz" \ and return it as a string.
--distribution "$DISTRIBUTION" \
--debootstrapopts --arch \ """
--debootstrapopts "$ARCHITECTURE" \
$( [ "$SAVELOG" = 0 ] || echo "--logfile ${BASE_DIR}/.lastlog" ) \ # Calculate variables which depend on arguments given at runtime.
$( [ -z "$PROXY" ] || echo "--http-proxy ${PROXY}" ) \ self._calculate()
$( [ -z "$DEBCACHE" ] || echo "--aptcache ${DEBCACHE}" ) \
--buildresult "${BASE_DIR}/${FOLDERBASE}_result" \ arguments = [
--mirror "${ARCHIVE}" \ self.operation,
$( [ $ISDEBIAN != "False" ] || echo "--aptconfdir \"${BASE_DIR}/etc/${DISTRIBUTION}/apt.conf/\"" ) \ '--basetgz "%(base)s/%(chroot_string)s-base.tgz"' % self,
$@ '--distribution "%(target_distro)s"' % self,
'--buildresult "%(base)s/%(chroot_string)s_result/"' % self,
'--logfile "%(logfile)s"' % self,
'--aptcache "/var/cache/apt/archives/"',
]
if self.build_architecture != self.system_architecture:
arguments.append('--debootstrapopts --arch')
arguments.append('--debootstrapopts "%(build_architecture)s"' % self)
if self.proxy:
arguments.append('--http-proxy "%(proxy)s"' % self)
return self.auth + ' /usr/sbin/pbuilder ' + ' '.join(arguments)
"""
--mirror "${ARCHIVE}" \
$( [ $ISDEBIAN != "False" ] || echo "--aptconfdir \"${BASE_DIR}/etc/${DISTRIBUTION}/apt.conf/\"" ) \
$@"""
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 'Bad...'
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(__name__ or 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' 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()
if len(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 'withlog' in sys.argv:
app.save_log = True
args.remove('withlog')
if len(args) < 1:
print 'Insufficient number of arguments.'
help(1)
app.set_operation(args.pop(0))
sys.exit(os.system(app.get_command(args)))
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print 'Manually aborted.'
sys.exit(1)