280 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			280 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
| #!/bin/bash
 | |
| 
 | |
| shopt -s extglob
 | |
| 
 | |
| array_build() {
 | |
|   local dest=$1 src=$2 i keys values
 | |
| 
 | |
|   # it's an error to try to copy a value which doesn't exist.
 | |
|   declare -p "$2" &>/dev/null || return 1
 | |
| 
 | |
|   # Build an array of the indicies of the source array.
 | |
|   eval "keys=(\"\${!$2[@]}\")"
 | |
| 
 | |
|   # Clear the destination array
 | |
|   eval "$dest=()"
 | |
| 
 | |
|   # Read values indirectly via their index. This approach gives us support
 | |
|   # for associative arrays, sparse arrays, and empty strings as elements.
 | |
|   for i in "${keys[@]}"; do
 | |
|     values+=("printf -v '$dest[$i]' %s \"\${$src[$i]}\";")
 | |
|   done
 | |
| 
 | |
|   eval "${values[*]}"
 | |
| }
 | |
| 
 | |
| funcgrep() {
 | |
|   { declare -f "$1" || declare -f package; } 2>/dev/null | grep -E "$2"
 | |
| }
 | |
| 
 | |
| # extract_global_var function compatible with bash 4.2
 | |
| extract_global_var() {
 | |
| 	# $1: variable name
 | |
| 	# $2: multivalued
 | |
| 	# $3: name of output var
 | |
| 
 | |
| 	local attr=$1 isarray=$2 outputvar=$3 ref
 | |
| 
 | |
| 	if (( isarray )); then
 | |
| 		array_build ref "$attr"
 | |
| 		[[ ${ref[@]} ]] && array_build "$outputvar" "$attr"
 | |
| 	else
 | |
| 		[[ ${!attr} ]] && printf -v "$outputvar" %s "${!attr}"
 | |
| 	fi
 | |
| }
 | |
| 
 | |
| # extract global_var function compatible with bash 4.3+
 | |
| old_extract_global_var() {
 | |
|   # $1: variable name
 | |
|   # $2: multivalued
 | |
|   # $3: name of output var
 | |
| 
 | |
|   local attr=$1 isarray=$2 outputvar=$3
 | |
| 
 | |
|   if (( isarray )); then
 | |
|     declare -n ref=$attr
 | |
|     # Still need to use array_build here because we can't handle the scoping
 | |
|     # semantics that would be included with the use of 'declare -n'.
 | |
|     [[ ${ref[@]} ]] && array_build "$outputvar" "$attr"
 | |
|   else
 | |
|     [[ ${!attr} ]] && printf -v "$outputvar" %s "${!attr}"
 | |
|   fi
 | |
| }
 | |
| 
 | |
| extract_function_var() {
 | |
|   # $1: function name
 | |
|   # $2: variable name
 | |
|   # $3: multivalued
 | |
|   # $4: name of output var
 | |
| 
 | |
|   local funcname=$1 attr=$2 isarray=$3 outputvar=$4 attr_regex= decl= r=1
 | |
| 
 | |
|   if (( isarray )); then
 | |
|     printf -v attr_regex '^[[:space:]]* %s\+?=\(' "$2"
 | |
|   else
 | |
|     printf -v attr_regex '^[[:space:]]* %s\+?=[^(]' "$2"
 | |
|   fi
 | |
| 
 | |
|   while read -r; do
 | |
|     # strip leading whitespace and any usage of declare
 | |
|     decl=${REPLY##*([[:space:]])}
 | |
|     eval "${decl/#$attr/$outputvar}"
 | |
| 
 | |
|     # entering this loop at all means we found a match, so notify the caller.
 | |
|     r=0
 | |
|   done < <(funcgrep "$funcname" "$attr_regex")
 | |
| 
 | |
|   return $r
 | |
| }
 | |
| 
 | |
| pkgbuild_get_attribute() {
 | |
|   # $1: package name
 | |
|   # $2: attribute name
 | |
|   # $3: multivalued
 | |
|   # $4: name of output var
 | |
| 
 | |
|   local pkgname=$1 attrname=$2 isarray=$3 outputvar=$4
 | |
| 
 | |
|   printf -v "$outputvar" %s ''
 | |
| 
 | |
|   if [[ $pkgname ]]; then
 | |
|     extract_global_var "$attrname" "$isarray" "$outputvar"
 | |
|     extract_function_var "package_$pkgname" "$attrname" "$isarray" "$outputvar"
 | |
|   else
 | |
|     extract_global_var "$attrname" "$isarray" "$outputvar"
 | |
|   fi
 | |
| }
 | |
| 
 | |
| srcinfo_open_section() {
 | |
|   printf '%s = %s\n' "$1" "$2"
 | |
| }
 | |
| 
 | |
| srcinfo_close_section() {
 | |
|   echo
 | |
| }
 | |
| 
 | |
| srcinfo_write_attr() {
 | |
|   # $1: attr name
 | |
|   # $2: attr values
 | |
| 
 | |
|   local attrname=$1 attrvalues=("${@:2}")
 | |
| 
 | |
|   # normalize whitespace, strip leading and trailing
 | |
|   attrvalues=("${attrvalues[@]//+([[:space:]])/ }")
 | |
|   attrvalues=("${attrvalues[@]#[[:space:]]}")
 | |
|   attrvalues=("${attrvalues[@]%[[:space:]]}")
 | |
| 
 | |
|   printf "\t$attrname = %s\n" "${attrvalues[@]}"
 | |
| }
 | |
| 
 | |
| pkgbuild_extract_to_srcinfo() {
 | |
|   # $1: pkgname
 | |
|   # $2: attr name
 | |
|   # $3: multivalued
 | |
| 
 | |
|   local pkgname=$1 attrname=$2 isarray=$3 outvalue=
 | |
| 
 | |
|   if pkgbuild_get_attribute "$pkgname" "$attrname" "$isarray" 'outvalue'; then
 | |
|     srcinfo_write_attr "$attrname" "${outvalue[@]}"
 | |
|   fi
 | |
| }
 | |
| 
 | |
| srcinfo_write_section_details() {
 | |
|   local attr package_arch a
 | |
|   local multivalued_arch_attrs=(source provides conflicts depends replaces
 | |
|                                 optdepends makedepends checkdepends
 | |
|                                 {md5,sha{1,224,256,384,512}}sums)
 | |
| 
 | |
|   for attr in "${singlevalued[@]}"; do
 | |
|     pkgbuild_extract_to_srcinfo "$1" "$attr" 0
 | |
|   done
 | |
| 
 | |
|   for attr in "${multivalued[@]}"; do
 | |
|     pkgbuild_extract_to_srcinfo "$1" "$attr" 1
 | |
|   done
 | |
| 
 | |
|   pkgbuild_get_attribute "$1" 'arch' 1 'package_arch'
 | |
|   for a in "${package_arch[@]}"; do
 | |
|     # 'any' is special. there's no support for, e.g. depends_any.
 | |
|     [[ $a = any ]] && continue
 | |
| 
 | |
|     for attr in "${multivalued_arch_attrs[@]}"; do
 | |
|       pkgbuild_extract_to_srcinfo "$1" "${attr}_$a" 1
 | |
|     done
 | |
|   done
 | |
| }
 | |
| 
 | |
| srcinfo_write_global() {
 | |
|   local singlevalued=(pkgdesc pkgver pkgrel epoch url install changelog)
 | |
|   local multivalued=(arch groups license checkdepends makedepends
 | |
|                      depends optdepends provides conflicts replaces
 | |
|                      noextract options backup
 | |
|                      source {md5,sha{1,224,256,384,512}}sums)
 | |
| 
 | |
|   srcinfo_open_section 'pkgbase' "${pkgbase:-$pkgname}"
 | |
|   srcinfo_write_section_details ''
 | |
|   srcinfo_close_section
 | |
| }
 | |
| 
 | |
| srcinfo_write_package() {
 | |
|   local singlevalued=(pkgdesc url install changelog)
 | |
|   local multivalued=(arch groups license checkdepends depends optdepends
 | |
|                      provides conflicts replaces options backup)
 | |
| 
 | |
|   srcinfo_open_section 'pkgname' "$1"
 | |
|   srcinfo_write_section_details "$1"
 | |
|   srcinfo_close_section
 | |
| }
 | |
| 
 | |
| srcinfo_write() {
 | |
|   local pkg
 | |
| 
 | |
|   srcinfo_write_global
 | |
| 
 | |
|   for pkg in "${pkgname[@]}"; do
 | |
|     srcinfo_write_package "$pkg"
 | |
|   done
 | |
| }
 | |
| 
 | |
| clear_environment() {
 | |
|   local environ
 | |
| 
 | |
|   mapfile -t environ < <(compgen -A variable |
 | |
|       grep -xvF "$(printf '%s\n' "$@")")
 | |
| 
 | |
|   # expect that some variables marked read only will complain here
 | |
|   unset -v "${environ[@]}" 2>/dev/null
 | |
| }
 | |
| 
 | |
| srcinfo_write_from_pkgbuild() {(
 | |
|   clear_environment PATH
 | |
| 
 | |
|   shopt -u extglob
 | |
|   . "$1" || exit 1
 | |
|   shopt -s extglob
 | |
|   srcinfo_write
 | |
| )}
 | |
| 
 | |
| 
 | |
| usage() {
 | |
|   printf '%s\n' \
 | |
|       'mksrcinfo v8' \
 | |
|       '' \
 | |
|       'mksrcinfo reads the target PKGBUILD and writes an equivalent .SRCINFO.' \
 | |
|       'Without passing any arguments, mksrcinfo will read from $PWD/PKGBUILD' \
 | |
|       'and write to $PWD/.SRCINFO.' \
 | |
|       '' \
 | |
|       'Usage: mksrcinfo [/path/to/pkgbuild]' \
 | |
|       '    -h                display this help message and exit' \
 | |
|       '    -o <file>         write output to <file>'
 | |
| }
 | |
| 
 | |
| error() {
 | |
|   printf "==> ERROR: $1\n" "${@:2}" >&2
 | |
| }
 | |
| 
 | |
| die() {
 | |
|   error "$@"
 | |
|   exit 1
 | |
| }
 | |
| 
 | |
| write_srcinfo_header() {
 | |
|   local timefmt='%a %b %e %H:%M:%S %Z %Y'
 | |
| 
 | |
|   # fiddle with the environment to ensure we get the a consistent language and
 | |
|   # timezone.
 | |
|   TZ=UTC LC_TIME=C \
 | |
|     printf "# Generated by mksrcinfo %s\n# %($timefmt)T\n" 'v8' -1
 | |
| }
 | |
| 
 | |
| srcinfo_dest=$PWD/.SRCINFO
 | |
| 
 | |
| while getopts ':o:h' flag; do
 | |
|   case $flag in
 | |
|     o)
 | |
|       srcinfo_dest=$OPTARG
 | |
|       ;;
 | |
|     :)
 | |
|       die "option '-%s' requires an argument" "$OPTARG"
 | |
|       ;;
 | |
|     h)
 | |
|       usage
 | |
|       exit 0
 | |
|       ;;
 | |
|     \?)
 | |
|       die "invalid option -- '-%s' (use -h for help)" "$OPTARG"
 | |
|       ;;
 | |
|   esac
 | |
| done
 | |
| shift $(( OPTIND - 1 ))
 | |
| 
 | |
| [[ -f PKGBUILD ]] || die 'PKGBUILD not found in current directory'
 | |
| 
 | |
| # TODO: replace this with 'makepkg --printsrcinfo' once makepkg>=4.3 is released.
 | |
| {
 | |
|   write_srcinfo_header
 | |
|   srcinfo_write_from_pkgbuild "${1:-$PWD/PKGBUILD}"
 | |
| } >"$srcinfo_dest"
 | |
| 
 | |
| # vim: set et ts=2 sw=2:
 |