#!/usr/bin/env zsh # Automatically make .deb package from a commit or a tag. # # Prerequisites: # zsh, build-essential, devscripts, debhelper (>= 9) # # Reference: https://wiki.debian.org/IntroDebianPackaging. setopt errexit noshwordsplit nobashrematch [[ -n $DEBUG ]] && setopt xtrace ################### SET UP ENVIRONMENT AND BASE DIRECTORIES #################### [[ -z $DEBFULLNAME ]] && DEBFULLNAME='Arun Prakash Jana' [[ -z $DEBEMAIL ]] && DEBEMAIL='engineerarun@gmail.com' [[ -z $TZ ]] && TZ='Asia/Kolkata' export DEBFULLNAME DEBEMAIL TZ here=$0:A:h repodir=$here/.. builddir=$here/../build distdir=$here/../dist export GIT_DIR=$repodir/.git ################################# SET UP TRAPS ################################# # Trap SIGUSR1: Abort program when functions called from within command # substitutions in heredocs fail. trap 'print_error "Encountered problem inside cmdsubst at line $LINENO."; exit 1' SIGUSR1 export NOTIFY_PID=$$ ############################### HELPER FUNCTIONS ############################### print_error () print -R $'\e[31m'"Error: $*"$'\e[0m' >&2 print_warning () print -R $'\e[33m'"Warning: $*"$'\e[0m' >&2 # Usage: apt_package_version apt_package_version () { local version="${$(apt-cache show $1 | grep '^Version')#Version: }" || { print_error "Version info not available for package ${(q-)1}." [[ -n $NOTIFY_PID ]] && kill -SIGUSR1 $NOTIFY_PID exit 1 } printf %s $version } debian_policy_version () { local full_version="$(apt_package_version debian-policy)" local match [[ $full_version =~ ^(([0-9]+\.){2}[0-9]+) ]] || { print_error "Invalid debian-policy version ${(q-)full_version}." [[ -n $NOTIFY_PID ]] && kill -SIGUSR1 $NOTIFY_PID exit 1 } printf %s $match[1] } # Git helpers # Usage: git_normalize_commitish # # Normalize a commit-ish to a tag name if the commit-ish refers to a tag or # tagged commit; otherwise to a SHA (via git-rev-parse). git_normalize_commitish () { local tagname commitsha if tagname=$(git describe --exact --tags $1 2>/dev/null); then printf %s $tagname else commitsha=$(git rev-parse --verify --quite $1) || { print_error "Unable to parse ${(q-)1} as a git commit." [[ -n $NOTIFY_PID ]] && kill -SIGUSR1 $NOTIFY_PID exit 1 } printf %s $commitsha fi } # Usage: git_ref_is_tag # # Returns 0 (is tag) or 1 (not tag). git_ref_is_tag () { git show-ref --quiet --verify refs/tags/$1 } # Usage: git_commitish_timestamp # # Expects a normalized commit-ish (see git_normalize_commitish) as input, and # outputs a timestamp. For a tag, the timestamp is the tagger date. For a # commit, the timestamp is the committer date. git_commitish_timestamp () { if git_ref_is_tag $1; then local date="$(git for-each-ref --format='%(taggerdate)' refs/tags/$1)" # The date returned by git-for-each-ref looks like `Sat Apr 23 10:38:27 # 2016 +0530', which isn't recognized by date(1) from coreutils. Need a # hack to turn `+0530' into `U+0530' (same for -). # # Note that date will be empty if the tag at question is a lightweight # tag (i.e., non-annotated) because they don't carry any tagger # information; in that case we simply fall back to the committer. if [[ -n $date ]]; then date -d ${${date// -/ U-}// +/ U+} +%s return fi fi git rev-list --format=format:%ct --max-count=1 $1 | tail -n1 } ######################### PARSE COMMAND LINE ARGUMENTS ######################### tag_only=0 while [[ $1 == -* ]]; do case $1 in -h|--help) cat >&2 <] Make a deb package from a git commit-ish, which defaults to HEAD. Options: -h, --help Print this help and exit. --tag-only Only make deb if HEAD (or , if specified) is a tag or a tagged commit. EOF exit 1 ;; --tag-only) tag_only=1 ;; --) shift break ;; *) print_error "Unknown option ${(q-)1}." exit 1 ;; esac shift done [[ -n $1 ]] && { commitish=$1; shift } || commitish=HEAD (( $# > 0 )) && { print_error 'Unrecognized arguments' ${(q-)@} exit 1 } ##################################### MAIN ##################################### mkdir -p $builddir $distdir cd $builddir normalized_commitish=$(git_normalize_commitish $commitish) git_ref_is_tag $normalized_commitish && commitish_is_tag=1 || commitish_is_tag=0 (( tag_only && !commitish_is_tag )) && { print_warning "${(q-)commitish} is not a tag or tagged commit, skipping build." exit } pkgname=buku version="${$(git describe --tags $commitish)#v}" # Quoting just to make sh-mode happy [[ -n $version ]] || { print_error 'Failed to extract version information.' exit 1 } debrevision=1 creation_timestamp=$(git_commitish_timestamp $normalized_commitish) upstream_tarball=$builddir/${pkgname}_${version}.orig.tar.gz buildsubdirname=${pkgname}-${version} git -C $repodir archive --format=tar.gz --prefix=$buildsubdirname/ --output=$upstream_tarball $commitish . rm -rf $buildsubdirname tar xf $upstream_tarball cd $buildsubdirname mkdir debian # Write debian/changelog if (( commitish_is_tag )); then # Tag -- point to the release changelog_url=https://github.com/jarun/Buku/releases/tag/$normalized_commitish else # Just a commit -- point to the list of commits in the tree changelog_url=https://github.com/jarun/Buku/commits/$normalized_commitish fi cat >debian/changelog < $(date --rfc-2822 --date=@$creation_timestamp) EOF # Alternatively, use dch to create changelog interactively: # dch --create -v ${version}-${debrevision} --package $pkgname # Write debian/compat cat >debian/compat <<'EOF' 9 EOF # Write debian/control cat >debian/control < Section: misc Priority: optional Standards-Version: $(debian_policy_version) Build-Depends: debhelper (>= 9) Package: $pkgname Architecture: all Depends: \${shlibs:Depends}, \${misc:Depends}, python3 (>= 3.3), python3-urllib3, python3-cryptography, python3-bs4, python3-requests Description: Powerful command-line bookmark manager See https://github.com/jarun/Buku#readme. EOF # Write debian/copyright copyright_file=$builddir/$buildsubdirname/debian/copyright cat >debian/copyright < Source: https://github.com/jarun/Buku Files: * Copyright: 2015-2017 Arun Prakash Jana License: GPL-3 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. . 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 . . On Debian systems, the full text of the GNU General Public License version 3 can be found in the file '/usr/share/common-licenses/GPL-3'. EOF # Write debian/rules cat >debian/rules <debian/source/format <<'EOF' 3.0 (quilt) EOF # Build binary package debuild -us -uc # Copying deb to dist binary_package=$builddir/${pkgname}_${version}-${debrevision}_all.deb cp -p $binary_package $distdir