#!@@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 <