From 08f6d3b491c833b5170d68de30e183ca6250ea74 Mon Sep 17 00:00:00 2001 From: oklopfer <104327997+oklopfer@users.noreply.github.com> Date: Mon, 8 Jul 2024 00:12:00 -0400 Subject: [PATCH] srcinfo revamp (#21) Co-authored-by: ook37 Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- pacup | 88 ++++--- scripts/srcinfo.sh | 588 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 601 insertions(+), 75 deletions(-) diff --git a/pacup b/pacup index d91168f..00941c9 100755 --- a/pacup +++ b/pacup @@ -4,7 +4,7 @@ package main; use strict; use warnings qw(all -experimental::signatures); use feature qw(say signatures); -our $VERSION = '3.2.0'; +our $VERSION = '3.3.0'; #use Data::Dumper; use open ':std', ':encoding(UTF-8)'; @@ -136,20 +136,17 @@ local $SIG{TERM} = sub { exit 1; }; -sub getvar ( $name, $lines ) { - for my $line (@$lines) { - my ( $key, $val ) = split / = /, $line; - return $val if $key eq $name; - } -} - -sub getarr ( $name, $lines ) { - my @arr; - for my $line (@$lines) { - my ( $key, $val ) = split / = /, $line; - push @arr, $val if $key eq $name; +sub getvar ( $file, $name, $isarr, $base = undef ) { + my $cmd = defined $base ? "$srcinfo_script read $file $name $base" : "$srcinfo_script read $file $name"; + if ( $isarr eq 1 ) { + my @result = qx($cmd); + chomp(@result); + return @result; + } else { + my $result = qx($cmd); + chomp($result); + return $result; } - return @arr; } sub geturl ($entry) { @@ -342,17 +339,17 @@ sub fetch_sources ( $ua, $pkgdir, $sources, $plines ) { return @collected_files; } -sub build_sourcelist ( $lines, $arch = '' ) { +sub build_sourcelist ( $srcinfo, $base, $arch = '' ) { my $source_var = $arch ? "source_$arch" : 'source'; my @sourceList; - my @source = getarr $source_var, $lines; + my @source = getvar($srcinfo, $source_var, 1, $base); while ( my ( $i, $entry ) = each @source ) { my %edict; $edict{'url'} = geturl $entry; for my $hashtype (@HASHTYPES) { my $hashtype_var = $arch ? "${hashtype}sums_$arch" : "${hashtype}sums"; - my @sums = getarr $hashtype_var, $lines; + my @sums = getvar($srcinfo, $hashtype_var, 1, $base); $edict{$hashtype} = $sums[$i]; } push @sourceList, \%edict; @@ -390,22 +387,34 @@ sub main ($pkg) { unless ( -f $srcinfo ) { info "Generating .SRCINFO for " . colored( $pacscript, 'underline' ); - system "srcinfo.sh", ($ppath); + system $srcinfo_script, "write", ($ppath); } my @lines; readlines( \@lines, $srcinfo ); info "Parsing .SRCINFO for " . colored( $pacscript, 'underline' ); - my $pkgname = getvar 'pkgname', \@lines; - throw 'Could not find pkgname' unless $pkgname; - subtext "Found pkgname: " . colored( $pkgname, 'cyan' ); + my $pkgbase = getvar($srcinfo, 'pkgbase', 0); + throw 'Could not find pkgbase' unless $pkgbase; + + my @pkgnames = getvar($srcinfo, 'pkgname', 1); + throw 'Could not find pkgname' unless @pkgnames; - my $pkgver = getvar 'pkgver', \@lines; + my $pkgname; + if (scalar @pkgnames eq 1) { + $pkgname = $pkgnames[0]; + subtext "Found pkgname: " . colored( $pkgname, 'cyan' ); + } else { + subtext "Found pkgbase: " . colored( $pkgbase, 'cyan' ); + subtext "Found pkgnames: " . colored( @pkgnames, 'cyan' ); + ($pkgname = $pkgbase) =~ s/^pkgbase://; + } + + my $pkgver = getvar($srcinfo, 'pkgver', 0, $pkgbase); throw 'Could not find pkgver' unless $pkgver; subtext "Found pkgver: " . colored( $pkgver, 'bright_yellow' ); - my @maintainer = getarr 'maintainer', \@lines; + my @maintainer = getvar($srcinfo, 'maintainer', 1, $pkgbase); if ( @maintainer + 0 > 0 ) { subtext 'Found maintainer: ' . colored( join( ', ', @maintainer ), 'bright_magenta' ); @@ -418,7 +427,7 @@ sub main ($pkg) { if ($opt_custom_version) { $newestver = $opt_custom_version; } else { - my @repology = getarr 'repology', \@lines; + my @repology = getvar($srcinfo, 'repology', 1, $pkgbase); throw 'Could not find repology' unless @repology + 0 > 0; subtext 'Found repology info: ' . colored( join( ', ', @repology ), 'bright_green' ); @@ -472,24 +481,24 @@ sub main ($pkg) { throw 'Could not fetch distrolist' unless $distrolist_res->is_success; $distrolist_cont = $distrolist_res->decoded_content; } - system $srcinfo_script, ($ppath_tmp); + system $srcinfo_script, "write", ($ppath_tmp); my $srcinfo_tmp = $pkgdir . '/.SRCINFO'; readlines( \@lines, $srcinfo_tmp ); - my @arches = getarr 'arch', \@lines; + my @arches = getvar($srcinfo_tmp, 'arch', 1, $pkgbase); my @distros = map { if (/\S/) { s/\/.*//; s/:$//; $_ } else { () } } split /\s+/, $distrolist_cont; my @allSources; - push @allSources, build_sourcelist \@lines; + push @allSources, build_sourcelist $srcinfo_tmp, $pkgbase; for my $arch (@arches) { - push @allSources, build_sourcelist \@lines, $arch; + push @allSources, build_sourcelist $srcinfo_tmp, $pkgbase, $arch; } for my $distro (@distros) { - push @allSources, build_sourcelist \@lines, $distro; + push @allSources, build_sourcelist $srcinfo_tmp, $pkgbase, $distro; for my $arch (@arches) { - push @allSources, build_sourcelist \@lines, $distro . '_' . $arch; + push @allSources, build_sourcelist $srcinfo_tmp, $pkgbase, $distro . '_' . $arch; } } throw 'Could not find sources' unless @allSources + 0 > 0; @@ -501,7 +510,7 @@ sub main ($pkg) { info "updating " . colored( $pacscript, 'bold yellow' ); copy $ppath_tmp, $ppath or throw "Could not copy $ppath_tmp to $ppath: $!"; - system $srcinfo_script, ($ppath_tmp); + system $srcinfo_script, "write", ($ppath_tmp); copy $srcinfo_tmp, $srcinfo or throw "Could not copy $srcinfo_tmp to $srcinfo: $!"; @@ -509,9 +518,18 @@ sub main ($pkg) { info "Installing from $pacscript"; my $payload = join( ';:', @collected_files ); local $ENV{'PACSTALL_PAYLOAD'} = $payload; - system 'pacstall', ( '--install', $ppath ); - if ($opt_ship) { - return unless ask_wait "Does $pkgname work?"; + if (scalar @pkgnames eq 1) { + system 'pacstall', ( '--install', $ppath ); + if ($opt_ship) { + return unless ask_wait "Does $pkgname work?"; + } + } else { + for my $pkg (@pkgnames) { + system 'pacstall', ( '--install', $ppath . ':' . $pkg ); + if ($opt_ship) { + return unless ask_wait "Does $pkg work?"; + } + } } } else { warner "Pacstall is not installed or not executable!"; @@ -639,7 +657,7 @@ Vigress - =head1 VERSION -Pacup (Perl edition) v3.2.0 +Pacup (Perl edition) v3.3.0 =cut diff --git a/scripts/srcinfo.sh b/scripts/srcinfo.sh index 7fffe4c..d9a34a0 100755 --- a/scripts/srcinfo.sh +++ b/scripts/srcinfo.sh @@ -20,34 +20,140 @@ # # You should have received a copy of the GNU General Public License # along with Pacstall. If not, see . +# +# @file srcinfo.sh +# @brief A library for parsing SRCINFO into native bash dictionaries. +# @description +# This library is used for parsing SRCINFO into native bash dictionaries. +# Since Bash as of now does not have multidimensional arrays, srcinfo_bash +# takes a lot of liberties with creating arrays, and tries its hardest to make +# them easy to access. +# +# @credits +# Based on Elsie19's srcinfo_bash +# https://github.com/Elsie19/srcinfo_bash +# +# Based on makepkg's pkgbuild.sh +# Copyright (C) 2009-2024 Pacman Development Team +# -shopt -s extglob +function srcinfo.is_array() { + [[ ${!1@a} == *a* ]] +} -function die() { +function srcinfo.die() { printf >&2 'ERROR: %s\n' "$@" exit 1 } -function vars.srcinfo() { - local _distros _vars _archs _sums distros listdir \ - vars="source depends makedepends optdepends pacdeps checkdepends provides conflicts breaks replaces enhances recommends makeconflicts checkconflicts" \ - archs="amd64 x86_64 arm64 aarch64 armel arm armhf armv7h i386 i686 mips64el ppc64el riscv64 s390x" \ - sums="b2 sha512 sha384 sha256 sha224 sha1 md5" - allvars=(pkgname gives pkgver pkgrel epoch pkgdesc url priority) - allars=(arch source depends makedepends checkdepends optdepends pacdeps conflicts makeconflicts checkconflicts breaks replaces provides enhances recommends incompatible compatible backup mask noextract nosubmodules license maintainer repology custom_fields) - if [[ -f "${PWD}/distrolist" ]]; then - listdir="file://${PWD}" +function srcinfo.array_build() { + local dest="${1}" src="${2}" i keys values + declare -p "$2" &> /dev/null || return 1 + eval "keys=(\"\${!$2[@]}\")" + eval "${dest}=()" + for i in "${keys[@]}"; do + values+=("printf -v '${dest}[${i}]' %s \"\${${src}[${i}]}\";") + done + eval "${values[*]}" +} + +function srcinfo.extr_globvar() { + local attr="${1}" isarray="${2}" outputvar="${3}" ref + if ((isarray)); then + srcinfo.array_build ref "${attr}" + ((${#ref[@]})) && srcinfo.array_build "${outputvar}" "${attr}" + else + [[ -n ${!attr} ]] && printf -v "${outputvar}" %s "${!attr}" + fi +} + +function srcinfo.extr_fnvar() { + local funcname="${1}" attr="${2}" isarray="${3}" outputvar="${4}" + local attr_regex decl r=1 + if ((isarray)); then + printf -v attr_regex '^[[:space:]]* %s\+?=\(' "${attr}" + else + printf -v attr_regex '^[[:space:]]* %s\+?=[^(]' "${attr}" + fi + local func_body + func_body=$(declare -f "${funcname}" 2> /dev/null) + [[ -z ${func_body} ]] && return 1 + IFS=$'\n' read -r -d '' -a lines <<< "${func_body}" + for line in "${lines[@]}"; do + [[ ${line} =~ ${attr_regex} ]] || continue + decl=${line##*([[:space:]])} + eval "${decl/#${attr}/${outputvar}}" + r=0 + done + return "${r}" +} + +function srcinfo.get_attr() { + local pkgname="${1}" attrname="${2}" isarray="${3}" outputvar="${4}" + if ((isarray)); then + eval "${outputvar}=()" + else + printf -v "${outputvar}" %s '' + fi + if [[ -n ${pkgname} ]]; then + srcinfo.extr_globvar "${attrname}" "${isarray}" "${outputvar}" + srcinfo.extr_fnvar "package_${pkgname}" "${attrname}" "${isarray}" "${outputvar}" else - listdir="https://raw.githubusercontent.com/pacstall/pacstall-programs/master" + srcinfo.extr_globvar "${attrname}" "${isarray}" "${outputvar}" fi - distros=$(curl -fsSL "${listdir}/distrolist" | awk '{sub(/\/.*/, "", $1); gsub(/:$/, "", $1); distros=distros $1 " "} END {sub(/ $/, "", distros); print distros}') - _distros="{${distros// /,}}" _vars="{${vars// /,}}" _archs="{${archs// /,}}" _sums="{${sums// /,}}" - eval "allars+=(${_vars}_${_distros} ${_vars}_${_archs} ${_vars}_${_distros}_${_archs} ${_sums}sums ${_sums}sums_${_distros} ${_sums}sums_${_archs} ${_sums}sums_${_distros}_${_archs})" - eval "allvars+=(gives_${_distros} gives_${_archs} gives_${_distros}_${_archs})" } -function gen.srcinfo() { - local CARCH='CARCH_REPLACE' DISTRO='DISTROBASE:DISTROVER' AARCH='AARCH_REPLACE' var ar aars bar ars rar rep seek +function srcinfo.write_attr() { + local attrname="${1}" attrvalues=("${@:2}") + attrvalues=("${attrvalues[@]//+([[:space:]])/ }") + attrvalues=("${attrvalues[@]#[[:space:]]}") + attrvalues=("${attrvalues[@]%[[:space:]]}") + printf "\t${attrname} = %s\n" "${attrvalues[@]}" +} + +function srcinfo.extract() { + local pkgname="${1}" attrname="${2}" isarray="${3}" outvalue + if srcinfo.get_attr "${pkgname}" "${attrname}" "${isarray}" 'outvalue'; then + srcinfo.write_attr "${attrname}" "${outvalue[@]}" + fi +} + +function srcinfo.write_details() { + local attr package_arch a + for attr in "${singlevalued[@]}"; do + srcinfo.extract "$1" "${attr}" 0 + done + + for attr in "${multivalued[@]}"; do + srcinfo.extract "$1" "${attr}" 1 + done + + srcinfo.get_attr "$1" 'arch' 1 'package_arch' || package_arch=("all") + for a in "${package_arch[@]}"; do + [[ ${a} == any || ${a} == all ]] && continue + + for attr in "${multivalued_arch_attrs[@]}"; do + srcinfo.extract "$1" "${attr}_${a}" 1 + done + done +} + +function srcinfo.vars() { + local _distros _vars _archs _sums distros \ + vars="depends makedepends optdepends pacdeps checkdepends provides conflicts breaks replaces enhances recommends makeconflicts checkconflicts source" \ + sums="b2 sha512 sha384 sha256 sha224 sha1 md5" + allvars=(pkgname gives pkgver pkgrel epoch pkgdesc url priority) + allars=(arch depends makedepends checkdepends optdepends pacdeps conflicts makeconflicts checkconflicts breaks replaces provides enhances recommends incompatible compatible backup mask noextract nosubmodules license maintainer repology custom_fields source) + distros=$(awk '{sub(/\/.*/, "", $1); gsub(/:$/, "", $1); distros=distros $1 " "} END {sub(/ $/, "", distros); print distros}' distrolist) + _distros="{${distros// /,}}" _vars="{${vars// /,}}" _sums="{${sums// /,}}" + eval "allars+=(${_sums}sums ${_vars}_${_distros} ${_sums}sums_${_distros})" + eval "allvars+=(gives_${_distros})" + eval "multivalued_arch_attrs=(${vars} ${_sums}sums ${_vars}_${_distros} ${_sums}sums_${_distros})" +} + +function srcinfo.write_global() { + unset "${allvars[@]}" "${allars[@]}" + local CARCH='CARCH_REPLACE' DISTRO='DISTROBASE:DISTROVER' CDISTRO='CDISTROBASE:CDISTROVER' AARCH='AARCH_REPLACE' var ar aars bar ars rar rep seek local -A AARCHS_MAP=( ["amd64"]="x86_64" ["arm64"]="aarch64" @@ -72,17 +178,9 @@ function gen.srcinfo() { ) # shellcheck disable=SC1090 source "${1}" - for var in "${allvars[@]}"; do - declare -n "rar=${var}" - if [[ -n ${rar} ]]; then - rar="${rar//+([[:space:]])/ }" - rar="${rar#[[:space:]]}" - rar="${rar%[[:space:]]}" - echo "${var} = ${rar}" - fi - done for ar in "${allars[@]}"; do - declare -n "bar=${ar}" + [[ ${ar} != "arch" ]] \ + && local -n bar="${ar}" if [[ -n ${bar[*]} ]]; then for ars in "${bar[@]}"; do ars="${ars//+([[:space:]])/ }" @@ -108,29 +206,439 @@ function gen.srcinfo() { fi # shellcheck disable=SC2076 if [[ " ${AARCHS_MAP[*]} " =~ " ${ar##*_} " || " ${!AARCHS_MAP[*]} " =~ " ${ar##*_} " || ${ar} == *"x86_64" ]]; then - : "${ar} = ${ars}" + : "${ar}=${ars}" [[ ${ar} != *"${aars}" ]] && continue else - : "${ar}_${aars} = ${ars}" + : "${ar}_${aars}=${ars}" fi - echo "${_//${seek}/${rep}}" + eval "${_//${seek}/${rep}}" done + unset "${ar}" + fi + done + fi + done + local singlevalued=("${allvars[@]}") + local multivalued=("${allars[@]}") + printf '%s = %s\n' 'pkgbase' "${pkgbase:-${pkgname}}" + srcinfo.write_details '' +} + +function srcinfo.write_package() { + local singlevalued=(gives pkgdesc url priority) + local multivalued=(arch license depends checkdepends optdepends pacdeps + provides checkconflicts conflicts breaks replaces enhances recommends backup repology) + printf '%s = %s\n' 'pkgname' "$1" + srcinfo.write_details "$1" +} + +function srcinfo.gen() { + local pkg + srcinfo.write_global "${1}" + for pkg in "${pkgname[@]}"; do + echo + srcinfo.write_package "${pkg}" + done +} + +function srcinfo.write_out() { + (($# <= 0)) && srcinfo.die "You failed to specify a pacscript" + # shellcheck disable=SC2064 + trap "$(shopt -p extglob)" RETURN + shopt -s extglob + srcinfo.vars + for i in "${@}"; do + [[ -f ${i} && -w ${i} ]] || srcinfo.die "Not a file: ${i}" + srcinfo.gen "${i}" > "${i%/*.pacscript*}"/.SRCINFO & + done + wait +} + +# @description Split a key value pair into an associated array. +# +# @example +# declare -A out +# srcinfo.parse_key_val 'foo = bar' out +# +# @arg $1 string Key value assignment +# @arg $2 string Name of associated array +function srcinfo.parse_key_val() { + local key value input="${1}" + declare -n out_array="${2}" + key="${input%%=*}" + value="${input#*=}" + key="${key#"${key%%[![:space:]]*}"}" + key="${key%"${key##*[![:space:]]}"}" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + # shellcheck disable=SC2034 + out_array=([key]="${key}" [value]="${value}") +} + +function srcinfo._basic_check() { + [[ ${1} == *"="* ]] +} + +function srcinfo._contains() { + local -n arr_name="${1}" + local key="${2}" z + for z in "${arr_name[@]}"; do + if [[ ${z} == "${key}" ]]; then + return 0 + fi + done + return 1 +} + +# @description Create array based on input +# +# @example +# srcinfo._create_array pkgbase var_name var_prefix +# +# @arg $1 string (optional) The pkgbase of the section +# @arg $2 string The variable name +# @arg $3 string (optional) The variable prefix +# +# @stdout Name of array created. +function srcinfo._create_array() { + local pkgbase="${1}" var_name="${2}" var_pref="${3}" + if [[ -n ${pkgbase} ]]; then + if ! [[ -v "${var_pref}_${pkgbase}_array_${var_name}" ]]; then + declare -ag "${var_pref}_${pkgbase}_array_${var_name}" + fi + echo "${var_pref}_${pkgbase}_array_${var_name}" + else + if ! [[ -v "${var_pref}_array_${var_name}" ]]; then + declare -ag "${var_pref}_array_${var_name}" + fi + echo "${var_pref}_array_${var_name}" + fi +} + +# @description Promote array to variable +# +# @example +# foo=('bar') +# srcinfo._promote_to_variable foo +# +# @arg $1 string Name of array to promote +function srcinfo._promote_to_variable() { + local var_name="${1}" key value + key="${var_name}" + value="${!var_name[0]}" + declare -g "${key}=${value}" +} + +function srcinfo.parse() { + # We need this for trimming whitespace without external tools. + # shellcheck disable=SC2064 + trap "$(shopt -p extglob)" RETURN + shopt -s extglob + local srcinfo_file var_prefix locbase temp_array ref total_list loop part i part_two split_up + srcinfo_file="${1:?No .SRCINFO passed to srcinfo.parse}" + var_prefix="${2:?Variable prefix not passed to srcinfo.parse}" + srcinfo.cleanup "${var_prefix}" + [[ ! -s ${srcinfo_file} ]] && return 5 + while IFS= read -r line; do + # Skip blank lines + [[ -z ${line} ]] && continue + [[ ${line} =~ ^\s*#.* ]] && continue + # Trim leading whitespace. + line="${line##+([[:space:]])}" + declare -A temp_line + if ! srcinfo._basic_check "${line}"; then + echo "Could not parse line: '${line}'" >&2 + return 3 + fi + srcinfo.parse_key_val "${line}" temp_line + if [[ -z ${temp_line[value]} ]]; then + echo "Empty value for: '${line}'" >&2 + return 4 + fi + # Define pkgbase first, it must be the first thing listed + if [[ -z ${globase} ]]; then + # Do we have pkgbase first? + if [[ ${temp_line[key]} == "pkgbase" ]]; then + locbase="pkgbase_${temp_line[value]//-/_}" + export globase="${temp_line[value]}" + else + locbase="${temp_line[value]//-/_}" + export globase="temporary_pacstall_pkgbase" + fi + elif [[ ${temp_line[key]} == *"pkgname" ]]; then + # Bash can't have dashes in variable names + locbase="${temp_line[value]//-/_}" + fi + # Next we need to parse out individual keys. + # So the strategy is to create arrays of every key and at the end, + # we can promote array.len() == 1 to variables instead. After that we + # can work back upwards. + temp_array="$(srcinfo._create_array "${locbase}" "${temp_line[key]}" "${var_prefix}")" + declare -n ref="${temp_array}" + ref+=("${temp_line[value]}") + if [[ ${locbase} == "pkgbase_"* ]] || ! srcinfo._contains total_list "${temp_array}"; then + total_list+=("${temp_array}") + fi + done < "${srcinfo_file}" + declare -Ag "${var_prefix}_access" + for loop in "${total_list[@]}"; do + declare -n part="${loop}" + # Are we at a new pkgname (pkgbase)? + if [[ ${loop} == *@(pkgname|pkgbase) ]]; then + declare -n var_name="${var_prefix}_access" + [[ ${loop} == "${var_prefix}_pkgbase"* ]] && global="pkgbase_" + for i in "${!part[@]}"; do + # Create our inner part + declare -ga "${var_prefix}_${global}${part[${i}]//-/_}" + # Declare that relationship + var_name["${var_prefix}_${global}${part[${i}]//-/_}"]="${var_prefix}_${global}${part[${i}]//-/_}" + done + unset global + fi + done + for part_two in "${total_list[@]}"; do + # Now we need to go and check every loop over, and parse it out so we get something like ("prefix", "key"), so we can then work with that. + # But first actually we should promote single element arrays to variables + declare -n referoo="${part_two}" + if (("${#referoo[@]}" == 1)); then + srcinfo._promote_to_variable "${part_two}" + fi + mapfile -t split_up <<< "${part_two/_array_/$'\n'}" + declare -n addarr="${split_up[0]}" + unset "${split_up[1]}" + # So now we need to check if the thing we're trying to insert is a variable, + # or an array. + if srcinfo.is_array "${part_two}"; then + declare -ga "${part_two}" + # shellcheck disable=SC2004 + addarr[${split_up[1]}]="${part_two}" + else + # shellcheck disable=SC2034,SC2004 + addarr[${split_up[1]}]="${!part_two}" + fi + done +} + +function srcinfo.cleanup() { + local var_prefix="${1:?No var_prefix passed to srcinfo.cleanup}" i z + local main_loop_template="${var_prefix}_access" compg + declare -n main_loop="${main_loop_template}" + for i in "${main_loop[@]}"; do + declare -n cleaner="${i}" + for z in "${cleaner[@]}"; do + unset "${var_prefix}_array_${z}" + done + unset cleaner + done + unset "${var_prefix}_access" globase global + # So now lets clean the stragglers that we can't reasonably infer + mapfile -t compg < <(compgen -v) + for i in "${compg[@]}"; do + if [[ ${i} == "${var_prefix}_"* ]]; then + unset -v "${i}" + fi + done +} + +# @description Reformat numbered associative array to indexed +# +# @example +# srcinfo_depends_vala_panel_appmenu_xfce_git=(["vala-panel-appmenu-valapanel-git-0"]="gtk3") +# srcinfo.reformat_assoc_arr "srcinfo_depends_vala_panel_appmenu_xfce_git" "eviler" +# +# converts to `srcinfo_depends_vala_panel_appmenu_valapanel_git=([0]="gtk3")` +# +# @arg $1 string Associative array to reformat +# @arg $2 string Ref string of indexed array to append conversion to (can be anything) +function srcinfo.reformat_assoc_arr() { + local pfx base ida new pfs in_name="${1}" + local -n in_arr="${in_name}" app="${2}" + IFS='_' read -r -a pfs <<< "${in_name}" + for pfx in "${!in_arr[@]}"; do + base="${pfx%-*}" ida="${pfx##*-}" new="${base//-/_}" + app+=("$(printf "%s[%s]=\"%s\"\n" "${pfs[0]}_${pfs[1]}_${new}" "${ida}" "${in_arr[${pfx}]}")") + done +} + +# @description Parse a specific variable from .SRCINFO +# +# @example +# +# srcinfo.print_var .SRCINFO source +# @arg $1 string .SRCINFO file path +# @arg $2 string Variable or Array to print +function srcinfo.print_var() { + local srcinfo_file="${1}" found="${2}" var_prefix="srcinfo" pkgbase output var name idx evil eviler e printed + local -n bases="${var_prefix}_access" + srcinfo.parse "${srcinfo_file}" "${var_prefix}" + if [[ ${found} == "pkgbase" ]]; then + if [[ -n ${globase} && ${globase} != "temporary_pacstall_pkgbase" ]]; then + pkgbase="${globase}" + declare -p pkgbase + return 0 + else + return 3 + fi + fi + for var in "${bases[@]}"; do + declare -n output="${var}_array_${found}" + declare -n name="${var}_array_pkgname" + if [[ -n ${output[*]} ]]; then + for idx in "${!output[@]}"; do + if ((${#bases[@]} > 1)); then + # shellcheck disable=SC2076 + if [[ ${var} =~ "pkgbase_${globase//-/_}" ]]; then + evil+=("$(printf "${var_prefix}_${found}_${globase//-/_}[\"${globase}-pkgbase-%d\"]=\"%s\"\n" "${idx}" "${output[${idx}]}")") + else + evil+=("$(printf "${var_prefix}_${found}_${globase//-/_}[\"${name}-%d\"]=\"%s\"\n" "${idx}" "${output[${idx}]}")") + fi else - echo "${ar} = ${ars}" + evil+=("$(printf "${var_prefix}_${found}_${name//-/_}[\"${name}-%d\"]=\"%s\"\n" "${idx}" "${output[${idx}]}")") fi done fi done - unset "${allars[@]}" "${allvars[@]}" + if [[ -n ${globase} && ${globase} != "temporary_pacstall_pkgbase" ]]; then + unset "${var_prefix}_${found}_${globase//-/_}" + declare -Ag "${var_prefix}_${found}_${globase//-/_}" + else + unset "${var_prefix}_${found}_${name//-/_}" + declare -Ag "${var_prefix}_${found}_${name//-/_}" + fi + # shellcheck disable=SC2294 + eval "${evil[@]}" + if [[ -n ${globase} && ${globase} != "temporary_pacstall_pkgbase" ]]; then + srcinfo.reformat_assoc_arr "${var_prefix}_${found}_${globase//-/_}" "eviler" + unset "${var_prefix}_${found}_${globase//-/_}" + # shellcheck disable=SC2294 + eval "${eviler[@]}" + else + srcinfo.reformat_assoc_arr "${var_prefix}_${found}_${name//-/_}" "eviler" + unset "${var_prefix}_${found}_${name//-/_}" + # shellcheck disable=SC2294 + eval "${eviler[@]}" + fi + for e in "${eviler[@]}"; do + if ! srcinfo._contains printed "${e%\[*}"; then + printed+=("${e%\[*}") + declare -p "${e%\[*}" + fi + unset "${e%\[*}" + done } -(($# <= 0)) && die "You failed to specify a pacscript" +# @description Output a specific variable from .SRCINFO +# +# @example +# +# srcinfo.match_pkg .SRCINFO pkgbase +# srcinfo.match_pkg .SRCINFO pkgdesc $(srcinfo.match_pkg .SRCINFO pkgbase) +# @arg $1 string .SRCINFO file path +# @arg $2 string Variable or Array to search +# @arg $3 string Package name or base to get output for +function srcinfo.match_pkg() { + local declares d bases b guy match out srcfile="${1}" search="${2}" pkg="${3}" + if [[ ${pkg} == "pkgbase:"* || ${search} == "pkgbase" ]]; then + pkg="${pkg/pkgbase:/}" + match="srcinfo_${search%%_*}_${pkg//-/_}_pkgbase" + else + match="srcinfo_${search%%_*}_${pkg//-/_}" + fi + mapfile -t declares < <(srcinfo.print_var "${srcfile}" "${search}" | awk '{sub(/^declare -a |^declare -- |^declare -x /, ""); print}') + [[ ${search} == "pkgbase" && -z ${declares[*]} ]] \ + && mapfile -t declares < <(srcinfo.print_var "${srcfile}" "pkgname" | awk '{sub(/^declare -a |^declare -- |^declare -x /, ""); print}') + for d in "${declares[@]}"; do + if [[ ${d%=\(*} =~ = ]]; then + declare -- "${d}" + bases+=("${d%=*}") + else + declare -a "${d}" + bases+=("${d%=\(*}") + fi + done + for b in "${bases[@]}"; do + guy="${b}[@]" + if [[ -z ${pkg} ]]; then + if [[ ${search} == "pkgname" || ${search} == "pkgbase" ]]; then + if [[ -n ${pkgbase} ]]; then + out="${pkgbase/\"/}" + out="${out/\"/}" + printf '%s\n' "pkgbase:${out}" + continue + fi + printf '%s\n' "${!guy}" + continue + else + printf '%s\n' "${guy}" + continue + fi + fi + if [[ ${b} == "${match}" ]]; then + printf '%s\n' "${!guy}" + fi + done +} + +function srcinfo.pkg_list() { + local origname outlist inlist pkgnames + mapfile -t inlist < <(ls -1 packages) + for i in "${inlist[@]}"; do + if [[ -n $(awk '/^pkgbase=/' "packages/${i}/${i}.pacscript") ]]; then + mapfile -t pkgnames < <(srcinfo.match_pkg packages/"${i}"/.SRCINFO pkgname) + outlist+=("${i}:pkgbase") + for j in "${pkgnames[@]}"; do + outlist+=("${i}:${j}") + done + else + outlist+=("${i}") + fi + done + printf '%s\n' "${outlist[@]}" +} + +function srcinfo.repo_check() { + mapfile -t tracked < <(git ls-files) + if ((${#@} < 1)); then + mapfile -t repolist < <(ls packages/*/*.pacscript) + else + repolist=("${@}") + fi + ret=0 + for i in "${repolist[@]}"; do + if ! [[ -f "${i%/*.pacscript}/.SRCINFO" ]]; then + printf '[\033[1;31mERR\033[0m]: no .SRCINFO found for %s\n' "${i##*/}" + printf ' [\033[1;34m>\033[0m]: run \033[1;37m./scripts/srcinfo.sh %s\033[0m\n' "${i}" + printf ' [\033[1;34m>\033[0m]: after, run \033[1;37mgit add %s\033[0m\n\n' "${i%/*.pacscript}/.SRCINFO" + ret=1 + elif ! srcinfo._contains tracked "${i%/*.pacscript}/.SRCINFO"; then + printf '[\033[1;31mERR\033[0m]: no .SRCINFO tracked by git for %s\n' "${i##*/}" + printf ' [\033[1;34m>\033[0m]: run \033[1;37mgit add %s\033[0m\n\n' "${i%/*.pacscript}/.SRCINFO" + ret=1 + fi + done + exit "${ret}" +} -vars.srcinfo -for i in "${@}"; do - [[ -f ${i} && -w ${i} ]] || die "Not a file: ${i}" - gen.srcinfo "${i}" > "${i%/*}"/.SRCINFO & -done -wait +function srcinfo.cmd() { + if [[ ${1} == "write" ]]; then + shift 1 + # list of packages to write to + srcinfo.write_out "${@}" + elif [[ ${1} == "check" ]]; then + shift 1 + # check if .SRCINFOs exist + srcinfo.repo_check "${@}" + elif [[ ${1} == "packagelist" ]]; then + # no args + srcinfo.pkg_list > packagelist + elif [[ ${1} == "read" ]]; then + # see srcinfo.match_pkg for description + # shellcheck disable=SC2086 + srcinfo.match_pkg "${2:?No SRCINFO file provided}" "${3:?No variable provided}" ${4} + else + srcinfo.die "options: read | write | packagelist | check" + fi +} +srcinfo.cmd "${@}" # vim:set ft=sh ts=2 sw=4 noet: