#!@@SHELL@@
#
# DEB - Download, Edit, Build!
# src/deb.sh
# Main program script.
#
# Copyright (C) 2012 Patrick "P. J." McDermott
#
# 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 3 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
COMMANDS='init config update download edit builddsc build push'
CONFIG_NAMES='mirror distribution component remote buildcmd'
main()
{
SCRIPT_NAME="${0}"
if [ ${#} -lt 1 ]; then
print_usage >&2
exit 1
fi
COMMAND_NAME="${1}"
shift
if ! echo " ${COMMANDS} " | grep " ${COMMAND_NAME} " > /dev/null 2>&1; then
print_usage >&2
exit 1
fi
CWD="${PWD}"
cmd_run "${@}"
}
print_usage()
{
cat <
Where is one of:
init Initialize a DEB work area
config Get or set a configuration value
update Update the list of source packages
download Download a source package
edit Unpack a source package for editing
builddsc Build an edited source package and debdiff
build Build binary packages
push Synchronize changes with a remote tree
EOF
}
error()
{
_msg="${1}"
shift
printf "Error: ${_msg}\n" ${@} >&2
exit 2
}
find_deb_dir()
{
until [ "${PWD}" = '/' ]; do
if [ -d '.deb' ]; then
DEB_DIR="${PWD}/.deb"
DEB_TREE="${PWD}"
return 0
fi
cd ..
done
[ ${#} -ge 1 ] && "${1}" && error 'No DEB work area found'
return 1
}
config_load()
{
. "${DEB_DIR}/config"
}
config_save()
{
for _name in ${CONFIG_NAMES}; do
printf "CONFIG_%s='%s'\n" "${_name}" "$(eval echo \$\{CONFIG_${_name}\})"
done > "${DEB_DIR}/config"
}
get_dsc_url()
{
[ ! -f "${DEB_DIR}/dsc.list" ] && error 'No source package list found'
_pkg="${1}"
_dscurl=$(grep "^${_pkg} " "${DEB_DIR}/dsc.list" | tail -n 1) || \
error 'Package "%s" not found' "${pkg}"
echo "${_dscurl#${_pkg} }"
}
get_dsc_name()
{
_pkg="${1}"
_dscurl="$(get_dsc_url "${pkg}")"
echo "${_dscurl##*/}"
}
prompt_bool()
{
_def="${1}"
_prompt="${2}"
shift 2
[ "${_def}" = y ] && _yn='[Y/n]' || _yn='[y/N]'
printf "${_prompt} ${_yn} " $@
read _val
[ "${_val}" = y ] && return 0
[ "${_val}" = n ] && return 1
[ "${_def}" = y ] && return 0 || return 1
}
cmd_run()
{
"cmd_${COMMAND_NAME}" "${@}"
}
cmd_init()
{
find_deb_dir false || {
DEB_DIR="${CWD}/.deb"
DEB_TREE="${CWD}"
}
CONFIG_mirror='http://ftp.debian.org/debian'
CONFIG_distribution='sid'
CONFIG_component='main'
CONFIG_buildcmd='sbuild -d %distribution% %opts% %dsc%'
cd "${DEB_TREE}"
if [ -d .deb ]; then
prompt_bool n 'DEB work area exists. Reinitialize?' || exit
rm -Rf .deb dsc builds pkgs work
mkdir .deb dsc builds pkgs work
config_save
printf 'Reinitialized DEB work area in %s.\n' "${DEB_TREE}"
else
mkdir .deb dsc builds pkgs work
config_save
printf 'Initialized DEB work area in %s.\n' "${DEB_TREE}"
fi
}
cmd_config()
{
find_deb_dir
config_load
if [ ${#} -ne 1 -a ${#} -ne 2 ]; then
cat >&2 < []
EOF
exit 1
fi
echo " ${CONFIG_NAMES} " | grep " ${1} " > /dev/null 2>&1 || \
error 'Invalid configuration name "%s"' "${1}"
config_name="CONFIG_${1}"
if [ ${#} -eq 1 ]; then
printf '%s\n' "$(eval echo \$\{${config_name}\})"
else
eval "${config_name}=\"${2}\""
config_save
fi
}
cmd_update()
{
find_deb_dir
config_load
if [ ${#} -ne 0 ]; then
cat >&2 < "${DEB_DIR}/.dsc.list~"
while read line; do
if [ -z "${line}" ]; then
printf '%s %s\n' "${pkg}" "${dir}/${dsc}" >> "${DEB_DIR}/.dsc.list~"
count=$(($count + 1))
printf "\rFound %${#total}d/%d source packages.%s" \
"${count}" "${total}" \
"$([ ${count} -eq ${total} ] && printf ' ' || printf '..')"
continue
fi
if [ "${line#Package: }" != "${line}" ]; then
pkg="${line#Package: }"
continue
fi
if [ "${line#Directory: }" != "${line}" ]; then
dir="${line#Directory: }"
continue
fi
if [ "${line#Files:}" != "${line}" ]; then
while read sum size file; do
if [ "${file%.dsc}" != "${file}" ]; then
dsc="${file}"
break
fi
done
continue
fi
done < "${DEB_DIR}/.Sources"
printf '\n'
rm "${DEB_DIR}/.Sources"
mv "${DEB_DIR}/.dsc.list~" "${DEB_DIR}/dsc.list"
printf '\nDone.\n'
}
cmd_download()
{
find_deb_dir
config_load
if [ ${#} -ne 1 ]; then
cat >&2 <
EOF
exit 1
fi
pkg="${1}"
# Get URL to DSC file.
dscurl="$(get_dsc_url "${pkg}")"
# Create clean destination for source package files.
rm -Rf "${DEB_TREE}/dsc/${pkg}"
mkdir -p "${DEB_TREE}/dsc/${pkg}"
cd "${DEB_TREE}/dsc/${pkg}"
# Download source package files.
printf 'Downloading source package "%s"...\n' "${pkg}"
dget -d "${CONFIG_mirror}/${dscurl}" || error 'Cannot download source package'
printf '\nDone.\n'
}
cmd_edit()
{
find_deb_dir
config_load
if [ ${#} -ne 1 ]; then
cat >&2 <
EOF
exit 1
fi
pkg="${1}"
# Get name of DSC file.
dsc="$(get_dsc_name "${pkg}")"
# Ensure that source package is downloaded.
[ ! -f "${DEB_TREE}/dsc/${pkg}/${dsc}" ] && \
error 'Source package "%s" not downloaded' "${pkg}"
ver="${dsc%.dsc}"
ver="${ver#${pkg}_}"
ver="${ver%-*}"
# Check if source package is already unpacked.
if [ -d "${DEB_TREE}/work/${pkg}/${pkg}-${ver}" ]; then
prompt_bool n \
'Source package "%s" already unpacked for editing. Remove?' \
"${pkg}" || exit
fi
# Create clean work area for source package.
rm -Rf "${DEB_TREE}/work/${pkg}"
mkdir -p "${DEB_TREE}/work/${pkg}"
# Unpack source package.
dpkg-source -x "${DEB_TREE}/dsc/${pkg}/${dsc}" \
"${DEB_TREE}/work/${pkg}/${pkg}-${ver}"
}
cmd_builddsc()
{
find_deb_dir
config_load
if [ ${#} -ne 1 ]; then
cat >&2 <
EOF
exit 1
fi
pkg="${1}"
# Find source package in internal list.
dsc="$(get_dsc_name "${pkg}")"
# Ensure that source package is unpacked.
[ ! -d "${DEB_TREE}/work/${pkg}/${pkg}-"* ] && \
error 'Source package "%s" not unpacked for editing' "${pkg}"
cd "${DEB_TREE}/work/${pkg}/${pkg}-"*
# Get source package version from internal list.
oldverrev="${dsc%.dsc}"
oldverrev="${oldverrev#${pkg}_}"
# Get source package version from work area.
verrev="$(dpkg-parsechangelog | sed -n 's/^Version: \(.*\)$/\1/p')"
pkgverrev="${pkg}_${verrev#*:}"
ver="${verrev%-*}"
rev="${verrev#*-}"
# Ensure that an NMU was made.
dpkg --compare-versions "${verrev}" gt "${oldverrev}" || \
error 'Version not incremented'
# Build source package.
dpkg-buildpackage -S -us -uc
# Make a clean source package destination.
cd ..
rm -Rf "${DEB_TREE}/pkgs/${pkg}"
mkdir -p "${DEB_TREE}/pkgs/${pkg}"
# Copy source package files.
while read line; do
if [ "${line#Files:}" != "${line}" ]; then
while read sum size file; do
case "${file}" in
*.orig.tar.*)
cp -p "${file}" "${DEB_TREE}/pkgs/${pkg}"
;;
*)
mv "${file}" "${DEB_TREE}/pkgs/${pkg}"
;;
esac
done
fi
done < "${pkgverrev}.dsc"
mv "${pkgverrev}.dsc" "${pkgverrev}_source.changes" "${DEB_TREE}/pkgs/${pkg}"
# Generate patch.
debdiff \
"${DEB_TREE}/dsc/${pkg}/${dsc}" "${DEB_TREE}/pkgs/${pkg}/${pkgverrev}.dsc" \
> "${DEB_TREE}/pkgs/${pkg}/${pkg}.debdiff"
}
cmd_build()
{
find_deb_dir
config_load
if [ ${#} -lt 1 ]; then
cat >&2 < [...]
EOF
exit 1
fi
pkg="${1}"
shift
opts="${@}"
# Ensure that source package is built.
[ ! -f "${DEB_TREE}/pkgs/${pkg}/"*.dsc ] && \
error 'Source package "%s" not built' "${pkg}"
# Find DSC file and make the build command.
dsc="$(ls "${DEB_TREE}/pkgs/${pkg}/"*.dsc)"
buildcmd="$(echo "${CONFIG_buildcmd}" | \
sed -e "s@%distribution%@${CONFIG_distribution}@g" \
-e "s@%opts%@${opts}@g;s@%dsc%@${dsc##*/}@g")"
# Create build directory if it doesn't exist.
mkdir -p "${DEB_TREE}/builds/${pkg}"
# Get list of source package files.
files="${dsc##*/}"
while read line; do
if [ "${line#Files:}" != "${line}" ]; then
while read sum size file; do
files="${files} ${file}"
done
fi
done < "${dsc}"
# Copy source package files.
cd "${DEB_TREE}/pkgs/${pkg}"
cp -p ${files} "${DEB_TREE}/builds/${pkg}"
# Build.
cd "${DEB_TREE}/builds/${pkg}"
${buildcmd}
# Remove source package files from build directory.
rm -f ${files}
}
cmd_push()
{
find_deb_dir
config_load
if [ ${#} -ne 0 ]; then
cat >&2 <