#!/bin/sh
# fkdep 2.0.1
# Copyright (C) Alexander Kozhevnikov <mentalisttraceur@gmail.com> 2015-02-19;
# First implementations of name_version_arch.deb naming, hard-faking, usage
# text, and printing errors to stderr properly, copyright (C) hxka 2014-02-12;
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public Licence as published by
# the Free Software Foundation, either version 3 of the licence 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 details.
# 
# You should've received a copy of the GNU General Public License
# with this program. If not, see <http://www.gnu.org/licences/>,
# or write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330 Boston MA 02111-1307 USA.

# Error return values.
ERR_NAME=1
ERR_VERSION=2
ERR_SECTION=3 # Unused: couldn't find a spec for valid "[area/]section" syntax.
ERR_WORKDIR=4

printUsage()
{
 printf '%s\n' \
  'Usage: '"$0"' [options] PACKAGE' \
  'Options:' \
  ' -h, --help            Prints this message - all other arguments ignored.' \
  ' -s, --section=SECTION Specify the deb section for this package.' \
  ' -H, --hard=VERSION    Hard-fake a specific version (the output package' \
  '                       will have to be named the same as the faked package)'
}

# Function to add a file to a 'common' format 'ar' archive.
# NO support for filenames longer than 16 characters; that is unneeded for deb.
# Assumes $DEB and $TIMESTAMP are within scope.
arAddFile()
{
 SIZE=`ls -l $1|awk '{print $5}'`

 printf '%-16s%-12s0     0     100644  %-10s`\n' $1 $TIMESTAMP $SIZE >> $DEB

 cat $1 >> $DEB

 # File entries must be 2-byte aligned, newline padded.
 if [ $((SIZE % 2)) = 1 ]
 then
  printf '\n' >> $DEB
 fi
}

# Set default package parameters.
HARD=false
VERSION=1.0
SECTION=metapackages

until [ $# = 0 ]
do
 if [ x"$1" = x-h ] || [ x"$1" = x--help ]
 then
  printUsage
  exit 0
 elif [ x"$1" = x-H ] || [ x"$1" = x--hard ]
 then 
  HARD=true
  VERSION=$2
  shift
 elif [ x"${1%%=*}" = x--hard ]
 then 
  HARD=true
  VERSION=${1#*=}
 elif [ x"$1" = x-s ] || [ x"$1" = x--section ]
 then
  SECTION=$2
  shift
 elif [ x"${1%%=*}" = x--section ]
 then
  SECTION=${1#*=}
 else
  PACKAGE_FAKED=$1
 fi
 shift
done

if ! printf %s "$PACKAGE_FAKED" | grep -q '^[a-z0-9][a-z0-9+.-]\{1,\}$'
then
 printf '"%s" is not a valid .deb package name.\n' "$PACKAGE_FAKED" 1>&2
 exit $ERR_NAME
fi

# Debian has very specific version string requirements, and regex has no good
# support for subsets/substrings being XOR with other subsets/substrings.
# https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version

VER_TMP=$VERSION

# If there's an 'epoch' portion, strip it off, and enable colons to be matched
# in the upstream-revision portion.
if EPOCH=`printf %s "$VER_TMP" | grep -o '^[0-9]\+:'`
then
 VER_TMP=${VER_TMP#"$EPOCH"}
 COLON=:
 unset EPOCH
fi
 
# If there's a 'debian-revision' portion, strip it off, and enable dashes to be
# matched in the upstream-revision portion.
if DEB_REV=`printf %s "$VER_TMP" | grep -o -- '-[a-zA-Z0-9+.~]\{1,\}$'`
then
 VER_TMP=${VER_TMP%"$DEB_REV"}
 DASH=-
 unset DEB_REV
fi

# Finally, check the upstream-revision portion. : and - are only conditionally
# allowed based on whether their respective variables were defined above.
if ! printf %s "$VER_TMP" | grep -q '^[0-9][a-zA-Z0-9+.~'"$COLON""$DASH"']*$'
then
 printf '"%s" is not a valid .deb package version.\n' "$VERSION" 1>&2
 exit $ERR_VERSION
fi

# If not hard-faking, then we don't want to literally match the package name.
if $HARD
then
 PACKAGE=$PACKAGE_FAKED
else
 PACKAGE=fkdep-$PACKAGE_FAKED
fi

# Make new /tmp folder. Assuming mktemp will print its own errors as needed.
WORKDIR=`mktemp -d /tmp/fkdep.XXXXXX` || exit $ERR_WORKDIR

SUBDIR=$WORKDIR/sub
mkdir "$SUBDIR"

# Using directory first as just a blank directory to generate data.tar.gz
cd "$SUBDIR"
tar -czf "$WORKDIR"/data.tar.gz .

# Now creating the actual DEBIAN files needed.
cat > "$SUBDIR"/changelog <<DELIM
$PACKAGE ($VERSION) unstable; urgency=low
  * Generated by fkdep!

 -- fkdep <fkdep@example.com>  `date -R`
DELIM

cat > "$SUBDIR"/control <<DELIM
Source: $PACKAGE
Section: $SECTION
Priority: extra
Maintainer: fkdep <fkdep@example.com>
Package: $PACKAGE
Architecture: all
Version: $VERSION
Depends: 
Description: Metapackage pretending to provide package $PACKAGE_FAKED
DELIM

# If we're not hard-faking, we want to add the "Provides:" line.
$HARD || printf 'Provides: %s\n' $PACKAGE_FAKED >> "$SUBDIR"/control

cat > "$SUBDIR"/copyright <<DELIM
            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
                    Version 2, December 2004

 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>

 Everyone is permitted to copy and distribute verbatim or modified
 copies of this license document, and changing it is allowed as long
 as the name is changed.

            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. You just DO WHAT THE FUCK YOU WANT TO.
DELIM

# Package the control files, then clean them up.
tar -czf "$WORKDIR"/control.tar.gz .
cd "$WORKDIR"
rm -r "$SUBDIR"

printf '2.0\n' > debian-binary

# Build .deb, emulating the common 'ar' format
DEB=${PACKAGE}_${VERSION}_all.deb
touch "$DEB"
# Grab current timestamp
TIMESTAMP=`date +%s -r "$DEB"`

printf '!<arch>\n' > $DEB
arAddFile debian-binary
arAddFile control.tar.gz
arAddFile data.tar.gz

rm data.tar.gz control.tar.gz debian-binary

# Point user to generated deb file.
printf '%s\n' "$WORKDIR"/"$DEB"
return 0
