From 03ee5c7c991c4641d6a6f47fc7bfb34fbdd0b9ab Mon Sep 17 00:00:00 2001
From: John McQuah <jquah@mx.sdf.org>
Date: Sun, 12 Jun 2022 15:38:35 -0400
Subject: [PATCH] pkgmeek: allow git to checkout a branch other than master

---
 scripts/pkgmeek | 112 ++++++++++++++++++++++++------------------------
 1 file changed, 57 insertions(+), 55 deletions(-)

diff --git a/scripts/pkgmeek b/scripts/pkgmeek
index 943b5d2..c04011a 100755
--- a/scripts/pkgmeek
+++ b/scripts/pkgmeek
@@ -46,14 +46,17 @@ validate_pkgfile || exit $E_PKGFILE
 package="${name}#${version}-${release}.pkg.tar.${PKGMK_COMPRESSION_MODE}"
 declare -a _local_
 for (( s=0; s<${#source[@]}; s++ )); do
-	[[ ${source[$s]} =~ ^(http|https|ftp|ssh|git)://.*/(.+) ]] && \
-			_local_[$s]="${BASH_REMATCH[2]%%.git}" || _local_[$s]="${source[$s]}"
+	[[ ${source[$s]} =~ ^(http|https|ssh|ftp|git)://.*/(.+)$ ]] && \
+		_local_[$s]="${BASH_REMATCH[2]%.git*}" || _local_[$s]="${source[$s]}"
 	[ -z "${renames[$s]}" ] || [ "${renames[$s]}" = "SKIP" ] || \
 		_local_[$s]="${renames[$s]}"
 done
-# Example: _local_ = ( some-git-repo/
-#                      upstream-ball-v12.tgz
-#                      random.patch )
+# Example: source = ( https://gitlab.com/demo-user/cool-project.git#0.4.9
+#                     https://dev.big-corp.com/src/needed-library.tgz
+#                     random.patch )
+#         _local_ = ( cool-project
+#                     needed-library.zgt  <-- renamed to prevent automatic unpacking
+#                     random.patch )
 
 # The effective user should at least have write permissions on $PWD
 [ -w "$(dirname "$work")" ] || work="$(pwd)"/work
@@ -81,7 +84,8 @@ done ; }
 
 # If the user only asked for '-utd', perform the check using the sources that do exist.
 check_pkg_mtime; pkg_utd=$?
-[ "$PKGMK_MTIME_ONLY" = "no" ] || [ "$PKGMK_CHECK_SIG" = "yes" ] || exit $pkg_utd
+[ "$PKGMK_MTIME_ONLY" = "no" ] || [ "$PKGMK_CHECK_SIG" = "yes" ] || \
+		[ "$PKGMK_FORCE" = "yes" ] || exit $pkg_utd
 
 # Take into account all the actions that can be done with a previously built package,
 # or with a full set of sources
@@ -133,10 +137,7 @@ case $? in
 esac; }
 [ "$PKGMK_CHECK_SIG" = "no" ] || exit 0 # no need to continue if the user only requested -cs
 
-if [ "$pkg_utd" = 0 ] || [ "$PKGMK_FORCE" = "yes" ]; then # Skip the extract, build steps.
-	# What used to be called unpack_source() is now hard-coded into the main routine.
-	# If you need to shield specific source files from unpacking, use the "renames"
-	# feature of Pkgfile(5) to avoid matching any of the following patterns.
+if [ "$pkg_utd" = 0 ] || [ "$PKGMK_FORCE" = "yes" ]; then
 	for (( u=0; u<${#_local_[@]}; u++ )) ; do
 	here="${_local_[$u]}"
 	case "$here" in
@@ -188,15 +189,16 @@ if [ "$pkg_utd" = 0 ] || [ "$PKGMK_FORCE" = "yes" ]; then # Skip the extract, bu
 	find . -maxdepth 1 -mindepth 1 -type l -delete; cleanup_work
 fi  # Continue from here if the extract and build were skipped
 
-# Install if requested
-# First find out how the effective user will invoke pkgadd
+# Install if requested. For non-root builds, only sudo and doas are supported.
+# Avoid falling back on su -c! It gobbles up the options intended for pkgadd.
 [ $UID = 0 ] || PKGMK_SU="sudo";
 [ -z "$PKGMK_SU" ] || [ -x "$(command -v $PKGMK_SU)" ] || PKGMK_SU="/usr/bin/doas";
-[ -x "$(command -v $PKGMK_SU)" ] || PKGMK_SU="su -c";
+[ -z "$PKGMK_SU" ] || [ -x "$(command -v $PKGMK_SU)" ] \
+		|| { error "Cannot run pkgadd as a non-root user."; exit "$E_INSTALL"; }
 
 [ -z "$PKGMK_INSTALL_COMMAND" ] || { $PKGMK_SU $PKGMK_INSTALL_COMMAND "$pkg_dir$package" \
 	&& info "$(basename $PKGMK_INSTALL_COMMAND) $package succeeded."; } || \
-	{ error "Unable to install $package using pkgadd."; exit "$E_INSTALL"; }
+	{ error "$(basename $PKGMK_INSTALL_COMMAND) $package failed."; exit "$E_INSTALL"; }
 
 # Done!
 }
@@ -217,31 +219,21 @@ readonly PKGMK_COMMAND="$0"
 readonly PKGMK_ROOT="$PWD"
 readonly PRTWASH_COMMAND="/usr/bin/prtwash"
 PKGMK_DOWNLOAD_PROG="/usr/bin/wget"
-
+PKGMK_GIT_COMMAND="/usr/bin/git"
 PKGMK_CONF="/etc/pkgmk.conf"
-PKGMK_SOURCE_DIR="$PWD"
-PKGMK_PACKAGE_DIR="$PWD"
-PKGMK_WORK_DIR="$PWD/work"
-PKGMK_COMPRESSION_MODE="gz"
 
-PKGMK_INSTALL_COMMAND=""
-PKGMK_CLEAN="no"
-PKGMK_RECURSIVE="no"
-PKGMK_DOWNLOAD_ONLY="no"
-PKGMK_EXTRACT_ONLY="no"
-PKGMK_MTIME_ONLY="no"
-PKGMK_UPDATE_FOOTPRINT="no"
-PKGMK_IGNORE_FOOTPRINT="no"
-PKGMK_IGNORE_NEW="no"
-PKGMK_FORCE="no"
-PKGMK_KEEP_WORK="no"
-PKGMK_UPDATE_MD5="no"
-PKGMK_IGNORE_MD5="no"
-PKGMK_UPDATE_SIG="no"
-PKGMK_IGNORE_SIG="no"
-PKGMK_REFRESH_SIG="no"
-PKGMK_CHECK_SIG="no"
-PKGMK_PRIVATEKEY=""
+PKGMK_SOURCE_DIR="$PWD";          PKGMK_WORK_DIR="$PWD/work"
+PKGMK_PACKAGE_DIR="$PWD";         PKGMK_COMPRESSION_MODE="gz"
+
+PKGMK_INSTALL_COMMAND="";         PKGMK_FORCE="no"
+PKGMK_CLEAN="no";                 PKGMK_KEEP_WORK="no"
+PKGMK_RECURSIVE="no";             PKGMK_UPDATE_MD5="no"
+PKGMK_DOWNLOAD_ONLY="no";         PKGMK_IGNORE_MD5="no"
+PKGMK_EXTRACT_ONLY="no";          PKGMK_UPDATE_SIG="no"
+PKGMK_MTIME_ONLY="no";            PKGMK_IGNORE_SIG="no"
+PKGMK_UPDATE_FOOTPRINT="no";      PKGMK_REFRESH_SIG="no"
+PKGMK_IGNORE_FOOTPRINT="no";      PKGMK_CHECK_SIG="no"
+PKGMK_IGNORE_NEW="no";            PKGMK_PRIVATEKEY=""
 
 ######################## subroutines ################################
 parse_options() {
@@ -366,33 +358,44 @@ check_pkg_mtime() { # can be called even if some sources are missing
 }
 
 fetch_source() {
-	local u="$1"; local h="$2"; local finished=0; local REPO SAVE_AS OCONTINUE OOUT
-
-	# Determine whether the source should be obtained by git
-	local PKGMK_GIT_COMMAND="/usr/bin/git"
+	local u="$1"; local h="$2"; local finished=0; local gitsrc tag CLONE_ARGS
+	local REPO SAVE_AS OCONTINUE OOUT; local m=0
 	[ -x "$PKGMK_GIT_COMMAND" ] || PKGMK_GIT_COMMAND="/bin/false"
-	if [[ $u =~ ^(https|http|ssh|git)://.*/(.+)\.git$ ]]; then
-		[ -d "$src_dir/$h.partial" ] && { ln -s "$src_dir/$h.partial" "$h"; cd "$h";
-			"$PKGMK_GIT_COMMAND" pull; finished=$?; cd ..; }
-		[ -d "$src_dir/$h.partial" ] || \
-			{ "$PKGMK_GIT_COMMAND" clone "$u" "$h.partial"; finished=$?;
+
+	# Is this a url that requires git?
+	if [[ $u =~ ^(https|http|ssh|git)://.*/(.+)\.git(.*)$ ]]; then
+		# Did the port maintainer specify a branch other than 'master'?
+		tag=${BASH_REMATCH[3]#\#}; gitsrc="${u%.git*}.git"
+		[ -z "$tag" ] || CLONE_ARGS="--branch $tag"
+
+		# If git is not installed, this source cannot be obtained at present
+		[ "$PKGMK_GIT_COMMAND" != "/bin/false" ] || return 1;
+
+		# Is it our first attempt to download this repository?
+		if [ ! -d "$src_dir/$h.partial" ]; then
+			"$PKGMK_GIT_COMMAND" clone "$gitsrc" $CLONE_ARGS "$h.partial"
+			finished=$?
 			[ "$src_dir" = "" ] || { mv "$h.partial" "$src_dir";
-					ln -s "$src_dir/$h.partial" "$h"; };
-			[ "$src_dir" = "" ] && ln -s "$h.partial" "$h"; }
+					ln -s "$src_dir/$h.partial" "$h"; }
+		else
+			ln -s "$src_dir/$h.partial" "$h"; cd "$h"
+			"$PKGMK_GIT_COMMAND" pull $gitsrc $tag
+			finished=$?; cd ..
+		fi
 		return $finished;
 	fi
 
+	# haven't returned yet, so a different transport protocol must be in effect
 	[[ "$PKGMK_DOWNLOAD_PROG" =~ wget$ ]] && { OCONTINUE="-c"; OOUT="$PKGMK_WGET_OPTIONS -O"; }
 	[[ "$PKGMK_DOWNLOAD_PROG" =~ curl$ ]] && { OCONTINUE="-C -"; OOUT="$PKGMK_CURL_OPTIONS -o"; }
 	[[ "$PKGMK_DOWNLOAD_PROG" =~ (wget|curl)$ ]] || SAVE_AS=/bin/false
 	
- 	local m=${#PKGMK_SOURCE_MIRRORS[@]}
-	# start with the url in the Pkgfile, then hit the mirrors until a download succeeds
-	while [ $m -ge 0 ] && [ $finished = 0 ] && [[ ! $SAVE_AS =~ false$ ]]; do
+	# start with the mirrors defined in pkgmk.conf, then go to the url found in the Pkgfile
+	while [ $m -le ${#PKGMK_SOURCE_MIRRORS[@]} ] && [ $finished = 0 ] && [[ ! $SAVE_AS =~ false$ ]]; do
 		[ "${PKGMK_SOURCE_MIRRORS[m]}" = "" ] && um=$u || \
 			{ REPO=$(echo ${PKGMK_SOURCE_MIRRORS[m]} | sed 's,/$,,');
 				um=$REPO/$(echo $u | sed 's,.*/,,'); }
-		m=$(( m-1 ))
+		m=$(( m+1 ))
 
 	# interrupted downloads from a previous run should be put where wget or curl will find them
 		[ -s "$src_dir/$h.partial" ] && { ln -s "$src_dir/$h.partial" . ;
@@ -478,13 +481,12 @@ check_signature() { # called from $PKGMK_ROOT in the case "when"="pre-Pkgfile",
 	# otherwise called from within $work. Pass control to
 	# check_manifest() if the signature is missing and "ignore-md5"
 	# has not been requested.
-	# Remember to clean up the soft links that get left behind!
-	local reqfiles=(Pkgfile); local s=0; local when="$1"
+	local reqfiles=(Pkgfile); local s=0; local when="$1";
 
 	if [ -f "$PKGMK_ROOT/.signature" ]; then
 		[ "$when" = "pre-Pkgfile" ] || reqfiles=(.footprint)
 		while [ "$when" = "pre-build" ] && [ "$s" -lt ${#_local_[@]} ]; do 
-			[[ "${source[$s]}" =~ ^(http|https|ssh|git).*/\.git ]] || \
+			[[ "${source[$s]}" =~ ^(http|https|ssh|git)://(.+)\.git ]] || \
 					reqfiles+=("${_local_[$s]}")
 			s=$(( s+1 ))
 		done