263 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
		
		
			
		
	
	
			263 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
|  | #!/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() { | ||
|  |   # $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: |