#!/bin/busybox ash
# shellcheck shell=ash
remove_line() {
	[ -z "$1" ] || [ -z "$2" ] && return 0
	# path to file first, lines as a whitespace delimited string second
	for l in $2; do
		sed -i "${l}d" "$1"
		[ -z "$3" ] && return 0
		# While the line we get is not empty, remove it, this serves to
		# remove any follow-up lines after we remove the first one.
		# We certainly don't want stray empty lines
		while ! sed -n "${l}p" "$1" | grep -q '.'; do
			sed -i "${l}d" "$1"
		done
	done
}

remove_return_1() {
	[ -z "$1" ] || [ -z "$2" ] && return 0
	# path to file first, lines as a whitespace delimited string second
	for l in $2; do
		prev_line=$(( l - 1 )) # The line before the one we should delete

		# Check if the line we were given contains only || return 1
		if sed -n "${l}p" "$1" | grep -q '^[[:blank:]]*|| return 1[[:blank:]]*$'; then
			# If that is true then delete the line outright, no point in keeping
			# an empty line around
			sed -i "${l}d" "$1"

			# Remove backslash of previous line, this is to deal with cases
			# where return is in a line of its own and the command is in the
			# previous line, commonly used in autoconf scripts, as an example:
			# autoconf \
			#	--prefix=/usr \
			#	|| return 1
			sed -i "${prev_line}s/\\\\$//g" "$1"
			remove_trailing_whitespace "$1" "$prev_line"
		else
			# Remove the || return 1 from the specific line
			sed -i "${l}s/|| return 1//g" "$1"
			remove_trailing_whitespace "$1" "$l"
		fi
	done
}

# Rename _builddir to builddir, both the variable in the global scope
# and any other occurrences
rename__builddir() {
	[ -z "$1" ] || [ -z "$2" ] && return 0
	for l in $2; do
		sed -i "{$l s/_builddir/builddir/g }" "$1"
	done
}

# Self-explanatory, remove any whitespace after ending text
remove_trailing_whitespace() {
	[ -z "$1" ] || [ -z "$2" ] && return 0
	for l in $2; do
		sed -i "{$l s/[[:space:]]\+$// }" "$1"
	done
}

# Given a file $1 and lines $2, rewrite the function which is composed of
# letters and numbers
rewrite_function() {
	[ -z "$1" ] || [ -z "$2" ] && return 0
	for l in $2; do
		sed -ri " {$l s|^([A-Za-z0-9]*).*|\\1() {|g }" "$1"
	done
}

# Remove braces from a variable in a line
remove_braces() {
	[ -z "$1" ] || [ -z "$2" ] && return 0
	printf "%s\\n" "$2" | while read -r line variable; do
		# Make variable without braces
		unbraced_variable="$(printf "%s\\n" "$variable" | sed 's|[{}]||g')"
		sed -i "{$line s|$variable|$unbraced_variable|g }" "$1"
	done
}

remove_pkgname_from_source() {
	[ -z "$1" ] || [ -z "$2" ] && return 0
	for l in $2; do
		sed -i "{$l s|\$pkgname|$pkgname|g }" "$1"
		# The command above might replace the $pkgname in
		# '$pkgname-$pkgver.tar.gz::' which should not be
		# replaced, so re-add it if that is the case
		sed -r -i "{$l s|$pkgname-\\\$pkgver(.*)::|\$pkgname-\$pkgver\1::|g }" "$1"
	done
}

insert() {
	[ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] && return 0
	for l in $3; do
		l=$((l + 1))
		sed -i "${l}i\\$2" "$1"
	done
}

set_cmake_none() {
	[ -z "$1" ] || [ -z "$2" ] && return 0
	for l in $2; do
		sed -i "${l}s/-DCMAKE_BUILD_TYPE=[^ ]* /-DCMAKE_BUILD_TYPE=None /" "$1"
		remove_trailing_whitespace "$1" "$l"
	done
}

pluck_word() {
	[ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] && return 0
	local word="$1" line="$2" apkbuild="$3"
	# Match everything but comments up to the word, then match everything
	# after the word and add them back
	sed -r -e "{$line s|(^[^#]*)$word(.*)|\1\2| }" -i "$apkbuild"
	# Post-pluck quick fixes, this removes extra whitespace when we remove
	# a word starting just after the double quotes, just before the ending
	# of a double-quoted variable and also removes duplicate spaces created
	# by removing a word between 2 words
	sed -r -e "{$line s|\" ([^#])|\"\1|g }" \
		   -e "{$line s| \"|\"|g }" \
		   -e "{$line s|  | |g }" \
		   -i "$apkbuild"
}

APKBUILD_LINT="apkbuild-lint"

help() {
	cat <<__EOF__
usage: ${0##*/} [-sh] [-p path] <APKBUILD...>

keys:
  -s 			
    don't try to fix violations that we are not certain of
  -h			
    print this message
  -p path	
    path to apkbuild-lint binary used to find violations
__EOF__
}

for arg; do
	case "$arg" in
		-h) # Print help message and exit
			help
			exit 0
			;;
		-s) # Only fix policy violations with the Certainity of Certain
			APKBUILD_STRICT=true
			shift
			;;
		-p) # Set the binary location to a value given to us by the user
			APKBUILD_LINT="$2"
			shift
			shift
			;;
		--) # End of options
			shift
			break
			;;
		*) # No more options after the file file is given
			shift
			set -- "$@" "$arg"
			;;
	esac
done

ret=0
for apkbuild; do
	if [ -f "$apkbuild" ]; then
		original_sum="$(sha512sum "$apkbuild" | cut -d ' ' -f1)"

        case "$apkbuild" in
            /*|./*);;
            *) apkbuild=./"$apkbuild"
        esac
        
		# Source the apkbuild, required to get pkgname
		srcdir="" . "$apkbuild" || {
			echo "Failed to source APKBUILD in '$apkbuild'" ;
			exit 1;
		}

		# Store all violations we have. Sort all them by the line in reverse
		# order
		violations="$("$APKBUILD_LINT" "$apkbuild" | sort -r -V -k 4 -t :)"
		[ -z "$violations" ] && return 0

		# If the user asked for strictness then only provide then remove all violations
		# that have Certainty of Possible
		if [ -n "$APKBUILD_STRICT" ]; then
			violations="$(printf "%s\\n" "$violations" | grep -v '^.P')"
		fi

		# Violations have by default 5, but a sixth can be added to have an extra value
		# that can be passed, one case is remove_braces which needs the variable that
		# will have its braces removed
		printf "%s\\n" "$violations" | while IFS=: read -r _ tag _ line msg extra; do
			case "$(printf "%s\\n" "$tag" | tr -d '[' | tr -d ']')" in
				AL1)
					remove_line "$apkbuild" "$line"
					;;
				AL2)
					remove_return_1 "$apkbuild" "$line"
					;;
				AL5|AL13)
					remove_line "$apkbuild" "$line" greedy
					;;
				AL8)
					remove_trailing_whitespace "$apkbuild" "$line"
					;;
				AL10|AL11)
					rewrite_function "$apkbuild" "$line"
					;;
				AL26)
					rename__builddir "$apkbuild" "$line"
					;;
				AL29)
					remove_pkgname_from_source "$apkbuild" "$line"
					;;
				AL32)
					remove_braces "$apkbuild" "$line $extra"
					;;
				AL49)
					pluck_word "$(printf "%s\\n" "$msg" | grep -o "'.*'" | tr -d "'")" "$line" "$apkbuild"
					;;
				AL55)
					set_cmake_none "$apkbuild" "$line"
					;;
				AL57)
					pluck_word "$(printf "%s\\n" "$msg" | grep -o "'.*'" | tr -d "'")" "$line" "$apkbuild"
					;;
			esac
		done

		if [ "$original_sum" != "$(sha512sum "$apkbuild" | cut -d ' ' -f1)" ]; then
			ret=$((ret + 1))
		fi
	fi
done
exit $ret
