#!/bin/sh ## SPDX-FileCopyrightText: 2023 - 2024 Benjamin Grande M. S. ## ## SPDX-License-Identifier: AGPL-3.0-or-later set -eu usage(){ echo "Usage: ${0##*/} PROJECT [PROJECT ...]" } ## Escape multiline strings for sed. escape_key(){ key_type="${1}" if test "${key_type}" = "scriptlet"; then echo "${2}" | sed ':a;N;$!ba;s/\n/\\n /g' | sed 's/\$/\\$/' elif test "${key_type}" = "text"; then echo "${2}" | sed ':a;N;$!ba;s/\n/\\n/g' | sed 's/\$/\\$/' else return 1 fi } # get_scriptlet scriptlet-action # [pre|post]-[install|upgrade], [pre|post]un-[uninstall|upgrade] ## Get scriptlet command, else fail safe. get_scriptlet(){ scriptlet="$1" scriptlet_begin="-- pkg:begin:${scriptlet} --" scriptlet_end="-- pkg:end:${scriptlet} --" scriptlet="$(sed -n \ "/^<\!${scriptlet_begin}>$/,/^<\!${scriptlet_end}>$/p" \ "${readme}" | sed '/^```.*/d;/^\S*$/d;/^<\!-- pkg:/d;s/^sudo //')" if test -z "${scriptlet}"; then echo true return 0 fi escape_key scriptlet "${scriptlet}" } get_spec(){ "${spec_get}" "${project}" "${1}" } gen_spec(){ project="$(echo "${1}" | sed "s|salt/||;s|/.*||")" if echo "${projects_seen}" | grep -qF " ${project} "; then return fi projects_seen="${projects_seen} ${project} " if echo "${unwanted}" | grep -q "^${project}$"; then echo "warn: skipping spec generation of untracked formula: ${project}" >&2 return 0 fi ## Test if a standard option works without error. get_spec name >/dev/null group="$(get_spec group)" template="rpm_spec/template/template.spec" target="rpm_spec/${group}-${project}.spec" intended_target="${target}" if test "${2-}" = "test"; then tmpdir="$(mktemp -d)" target="${tmpdir}/${group}-${project}.spec" trap 'rm -rf -- "${tmpdir}"' EXIT INT HUP QUIT ABRT fi readme="$(get_spec readme)" project_name="$(get_spec project)" version="$(get_spec version)" license_csv="$(get_spec license_csv)" ## Ideally we would query the license, but it is a heavy call. license="$(echo "${license_csv}" | sed "s/\,/ AND /g")" vendor="$(get_spec vendor)" packager="$(get_spec packager)" url="$(get_spec url)" bug_url="$(get_spec bug_url)" requires="$(get_spec requires)" summary="$(get_spec summary)" description="$(get_spec description)" description="$(escape_key text "${description}")" file_roots="$(get_spec file_roots)" changelog="$(get_spec changelog)" pre_install="$(get_scriptlet pre-install)" pre_upgrade="$(get_scriptlet pre-upgrade)" post_install="$(get_scriptlet post-install)" post_upgrade="$(get_scriptlet post-upgrade)" preun_uninstall="$(get_scriptlet preun-uninstall)" preun_upgrade="$(get_scriptlet preun-upgrade)" postun_uninstall="$(get_scriptlet postun-uninstall)" postun_upgrade="$(get_scriptlet postun-upgrade)" sed \ -e "s/@PRE_INSTALL@/${pre_install}/" \ -e "s/@PRE_UPGRADE@/${pre_upgrade}/" \ -e "s/@POST_INSTALL@/${post_install}/" \ -e "s/@POST_UPGRADE@/${post_upgrade}/" \ -e "s/@PREUN_UNINSTALL@/${preun_uninstall}/" \ -e "s/@PREUN_UPGRADE@/${preun_upgrade}/" \ -e "s/@POSTUN_UNINSTALL@/${postun_uninstall}/" \ -e "s/@POSTUN_UPGRADE@/${postun_upgrade}/" \ -e "s|@FILE_ROOTS@|${file_roots}|" \ -e "s/@NAME@/${project}/" \ -e "s/@PROJECT@/${project_name}/" \ -e "s/@VERSION@/${version}/" \ -e "s/@SUMMARY@/${summary}/" \ -e "s/@GROUP@/${group}/" \ -e "s/@PACKAGER@/${packager}/" \ -e "s/@VENDOR@/${vendor}/" \ -e "s/@LICENSE@/${license}/" \ -e "s/@LICENSE_CSV@/${license_csv}/" \ -e "s|@BUG_URL@|${bug_url}|" \ -e "s|@URL@|${url}|" \ -e "s|@DESCRIPTION@|${description}|" \ -e "/@CHANGELOG@/d" \ "${template}" | tee "${target}" >/dev/null requires_key="" for r in $(printf %s"${requires}" | tr " " "\n" | sort -u); do requires_key="${requires_key:-}Requires: ${group}-${r}\n" done sed -i "s/@REQUIRES@/${requires_key}/" "${target}" >/dev/null echo "${changelog}" | tee -a "${target}" >/dev/null if test "${2-}" = "test"; then if ! cmp -s "${target}" "${intended_target}"; then echo "error: ${intended_target} is not up to date" >&2 diff --color=auto "${intended_target}" "${target}" || true fail=1 else unstaged_target="$(git diff --name-only "${intended_target}")" || true if test -n "${unstaged_target}"; then echo "warn: ${intended_target} is up to date but it is not staged" >&2 fi fi fi } case "${1-}" in -h|--?help) usage; exit 1;; *) ;; esac command -v git >/dev/null || { echo "Missing program: git" >&2; exit 1; } repo_toplevel="$(git rev-parse --show-toplevel)" test -d "${repo_toplevel}" || exit 1 unset repo_toplevel spec_get="./scripts/spec-get.sh" ignored="$(git ls-files --exclude-standard --others --ignored salt/)" untracked="$(git ls-files --exclude-standard --others salt/)" unwanted="$(printf %s"${ignored}\n${untracked}\n" \ | grep "^salt/\S\+/README.md" | cut -d "/" -f2 | sort -u)" fail="" gen_mode="" if test "${1-}" = "test"; then gen_mode="test" shift fi if echo "${@}" | grep -qE "(^scripts/| scripts/|/template.spec)" || test -z "${1-}" then # shellcheck disable=SC2046,SC2312 set -- $(find salt/ -mindepth 1 -maxdepth 1 -type d -printf '%f\n' \ | sort -d | tr "\n" " ") fi projects_seen="" for p in "${@}"; do gen_spec "${p}" "${gen_mode}" done if test "${fail}" = "1" && test "${gen_mode}" = "test"; then exit 1 fi