feat: build and sign RPM packages

Passing files to Dom0 is always dangerous:

- Passing a git repository is dangerous as it can have ignored modified
  files and signature verification will pass.
- Passing an archive is troublesome for updates.
- Passing an RPM package depends on the RPM verification to be correct,
  some times it is not.
- Passing a RPM repository definition is less troublesome for the user,
  as it is a small file to verify the contents and update mechanism is
  via the package manager. Trust in RPM verification is still required.

Many improvements were made to the build scripts:

- requires-program: Single function to check if program is installed;
- spec-get: Sort project names for the usage message;
- spec-get: Only running commands that are necessary;
- spec-get: Fix empty summary when readme has copyright header;
- spec-gen: Fix grep warning of escaped symbol;
- spec-build: Sign RPM and verify signature;
- spec-build: Only lint the first SPEC for faster runtime;
- yumrepo-gen: Generate a local yum repository with signed metadata;
- qubesbuilder-gen: Generate a .qubesbuilder based on tracked projects;
- release: Build, sign and push all RPMs to repository.

Goal is to be able to build with qubes-builderv2 Qubes Executor.

For: https://github.com/ben-grande/qusal/issues/37
This commit is contained in:
Ben Grande 2024-06-12 14:44:04 +02:00
parent 10200f609e
commit fc22726ee8
No known key found for this signature in database
GPG Key ID: 00C64E14F51F9E56
15 changed files with 339 additions and 115 deletions

View File

@ -43,3 +43,9 @@ repos:
args: [--staged, --msg-filename] args: [--staged, --msg-filename]
stages: [commit-msg] stages: [commit-msg]
description: Lint Git commits description: Lint Git commits
- id: qubesbuilder
name: qubesbuilder
entry: scripts/qubesbuilder-gen.sh test
language: script
description: Check if .qubesbuilder is up to date

59
.qubesbuilder Normal file
View File

@ -0,0 +1,59 @@
# SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. <ben.grande.b@gmail.com>
#
# SPDX-License-Identifier: MIT
# vim: ft=yaml
---
host:
rpm:
build:
- rpm_spec/qusal-ansible.spec
- rpm_spec/qusal-browser.spec
- rpm_spec/qusal-debian.spec
- rpm_spec/qusal-debian-minimal.spec
- rpm_spec/qusal-debian-xfce.spec
- rpm_spec/qusal-dev.spec
- rpm_spec/qusal-docker.spec
- rpm_spec/qusal-dom0.spec
- rpm_spec/qusal-dotfiles.spec
- rpm_spec/qusal-electrum.spec
- rpm_spec/qusal-element.spec
- rpm_spec/qusal-fedora.spec
- rpm_spec/qusal-fedora-minimal.spec
- rpm_spec/qusal-fedora-xfce.spec
- rpm_spec/qusal-fetcher.spec
- rpm_spec/qusal-kicksecure-minimal.spec
- rpm_spec/qusal-mail.spec
- rpm_spec/qusal-media.spec
- rpm_spec/qusal-mgmt.spec
- rpm_spec/qusal-mirage-builder.spec
- rpm_spec/qusal-opentofu.spec
- rpm_spec/qusal-qubes-builder.spec
- rpm_spec/qusal-reader.spec
- rpm_spec/qusal-remmina.spec
- rpm_spec/qusal-signal.spec
- rpm_spec/qusal-ssh.spec
- rpm_spec/qusal-sys-audio.spec
- rpm_spec/qusal-sys-bitcoin.spec
- rpm_spec/qusal-sys-cacher.spec
- rpm_spec/qusal-sys-electrs.spec
- rpm_spec/qusal-sys-electrumx.spec
- rpm_spec/qusal-sys-firewall.spec
- rpm_spec/qusal-sys-git.spec
- rpm_spec/qusal-sys-mirage-firewall.spec
- rpm_spec/qusal-sys-net.spec
- rpm_spec/qusal-sys-pgp.spec
- rpm_spec/qusal-sys-pihole.spec
- rpm_spec/qusal-sys-print.spec
- rpm_spec/qusal-sys-rsync.spec
- rpm_spec/qusal-sys-ssh.spec
- rpm_spec/qusal-sys-ssh-agent.spec
- rpm_spec/qusal-sys-syncthing.spec
- rpm_spec/qusal-sys-usb.spec
- rpm_spec/qusal-sys-wireguard.spec
- rpm_spec/qusal-terraform.spec
- rpm_spec/qusal-usb.spec
- rpm_spec/qusal-utils.spec
- rpm_spec/qusal-vault.spec
- rpm_spec/qusal-video-companion.spec
- rpm_spec/qusal-whonix-gateway.spec
- rpm_spec/qusal-whonix-workstation.spec

9
.qubesbuilder.template Normal file
View File

@ -0,0 +1,9 @@
# SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. <ben.grande.b@gmail.com>
#
# SPDX-License-Identifier: MIT
# vim: ft=yaml
---
host:
rpm:
build:
@SPEC@

View File

@ -6,7 +6,6 @@
%define my_name %(./scripts/spec-get.sh @PROJECT@ name) %define my_name %(./scripts/spec-get.sh @PROJECT@ name)
%define branch %(./scripts/spec-get.sh @PROJECT@ branch) %define branch %(./scripts/spec-get.sh @PROJECT@ branch)
%define project %(./scripts/spec-get.sh @PROJECT@ project) %define project %(./scripts/spec-get.sh @PROJECT@ project)
%define release %(./scripts/spec-get.sh @PROJECT@ release)
%define summary %(./scripts/spec-get.sh @PROJECT@ summary) %define summary %(./scripts/spec-get.sh @PROJECT@ summary)
%define group %(./scripts/spec-get.sh @PROJECT@ group) %define group %(./scripts/spec-get.sh @PROJECT@ group)
%define vendor %(./scripts/spec-get.sh @PROJECT@ vendor) %define vendor %(./scripts/spec-get.sh @PROJECT@ vendor)
@ -17,7 +16,7 @@
Name: %{project} Name: %{project}
Version: @VERSION@ Version: @VERSION@
Release: %autorelease Release: 1%{?dist}
Summary: %{summary} Summary: %{summary}
Group: %{group} Group: %{group}
@ -25,7 +24,10 @@ Vendor: %{vendor}
License: %{license} License: %{license}
URL: %{url} URL: %{url}
Source0: %{project} Source0: %{project}
BuildArch: noarch
Requires: qubes-mgmt-salt
Requires: qubes-mgmt-salt-dom0
@REQUIRES@ @REQUIRES@
%description %description
@ -37,7 +39,9 @@ Source0: %{project}
%install %install
rm -rf %{buildroot} rm -rf %{buildroot}
mkdir -p %{buildroot}%{file_roots} mkdir -p %{buildroot}%{file_roots} %{buildroot}/usr/share/licenses/%{project}
mv -v %{project}/LICENSES/* %{buildroot}/usr/share/licenses/%{project}/
rm -rv %{project}/LICENSES
cp -rv %{project} %{buildroot}%{file_roots}/%{my_name} cp -rv %{project} %{buildroot}%{file_roots}/%{my_name}
%check %check
@ -73,10 +77,11 @@ fi
%files %files
%defattr(-,root,root,-) %defattr(-,root,root,-)
%license %{file_roots}/%{my_name}/LICENSES/%{license_csv} %license /usr/share/licenses/%{project}/*
%dir %{file_roots}/%{my_name}
%doc %{file_roots}/%{my_name}/README.md %doc %{file_roots}/%{my_name}/README.md
%dir %{file_roots}/%{my_name}/* %exclude %{file_roots}/%{my_name}/README.md
%dnl %{file_roots}/%{my_name}/* %{file_roots}/%{my_name}/*
%changelog %changelog
%dnl %autochangelog @CHANGELOG@

View File

@ -1,4 +1,4 @@
# debian # debian-xfce
Debian Xfce Template in Qubes OS. Debian Xfce Template in Qubes OS.

View File

@ -1,4 +1,4 @@
# fedora # fedora-xfce
Fedora Xfce Template in Qubes OS. Fedora Xfce Template in Qubes OS.

View File

@ -8,6 +8,10 @@ set -eu
now="$(date +%s)" now="$(date +%s)"
fail="0" fail="0"
if test -z "${1-}"; then
echo "No file provided" >&2
exit 1
fi
for key in "${@}"; do for key in "${@}"; do
data="$(gpg --no-keyring --no-auto-check-trustdb --no-autostart \ data="$(gpg --no-keyring --no-auto-check-trustdb --no-autostart \
--with-colons --show-keys "${key}")" --with-colons --show-keys "${key}")"

36
scripts/qubesbuilder-gen.sh Executable file
View File

@ -0,0 +1,36 @@
#!/bin/sh
## SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. <ben.grande.b@gmail.com>
##
## SPDX-License-Identifier: AGPL-3.0-or-later
set -eu
template=".qubesbuilder.template"
target=".qubesbuilder"
intended_target="${target}"
if test "${1-}" = "test"; then
tmpdir="$(mktemp -d)"
target="${tmpdir}/.qubesbuilder"
trap 'rm -rf -- "${tmpdir}"' EXIT INT HUP QUIT ABRT
fi
ignored="$(git ls-files --exclude-standard --others --ignored)"
untracked="$(git ls-files --exclude-standard --others)"
unwanted="$(echo "${ignored}" "${untracked}" | grep "^salt/" \
| cut -d "/" -f2 | sort -u)"
group="$(./scripts/spec-get.sh dom0 group)"
projects="$(find salt/ -mindepth 1 -maxdepth 1 -type d \
| sort -d | sed "s|^salt/\(\S\+\)| - rpm_spec/${group}-\1.spec|")"
for unwanted_project in ${unwanted}; do
projects="$(echo "${projects}" | sed "\@rpm_spec/${group}-${unwanted_project}.spec@d")"
done
sed -e "/@SPEC@/d" "${template}" | tee "${target}" >/dev/null
echo "${projects}" | tee -a "${target}" >/dev/null
if test "${1-}" = "test"; then
if ! cmp -s "${target}" "${intended_target}"; then
echo "${0##*/}: error: File ${intended_target} is not up to date" >&2
echo "${0##*/}: error: Please run '${0##/*}' to update the file" >&2
exit 1
fi
fi

14
scripts/release.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
## SPDX-FileCopyrightText: 2023 - 2024 Benjamin Grande M. S. <ben.grande.b@gmail.com>
##
## SPDX-License-Identifier: AGPL-3.0-or-later
set -eu
command -v git >/dev/null || { echo "Missing program: git" >&2; exit 1; }
cd "$(git rev-parse --show-toplevel)" || exit 1
./scripts/qubesbuilder-gen.sh
./scripts/spec-build.sh
./scripts/yumrepo-gen.sh

19
scripts/requires-program.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/sh
## SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. <ben.grande.b@gmail.com>
##
## SPDX-License-Identifier: AGPL-3.0-or-later
set -eu
missing_program=0
for pkg in "${@}"; do
if ! command -v "${pkg}" >/dev/null; then
missing_program=1
echo "Missing program: ${pkg}" >&2
continue
fi
done
if test "${missing_program}" = "1"; then
exit 1
fi

View File

@ -39,8 +39,8 @@ if test -n "${1-}"; then
fi fi
case "${find_tool}" in case "${find_tool}" in
fd|fdfind) files="$(${find_tool} . minion.d/ --extension=conf) $(${find_tool} . salt/ --max-depth=2 --type=f --extension=sls --extension=top)";; fd|fdfind) files="$(${find_tool} . minion.d/ --extension=conf) $(${find_tool} . salt/ --max-depth=2 --type=f --extension=sls --extension=top | sort -d)";;
find) files="$(find minion.d/ -type f -name "*.conf") $(find salt/* -maxdepth 2 -type f \( -name '*.sls' -o -name '*.top' \))";; find) files="$(find minion.d/ -type f -name "*.conf") $(find salt/* -maxdepth 2 -type f \( -name '*.sls' -o -name '*.top' \) | sort -d)";;
esac esac
exec salt-lint ${conf} ${files} exec salt-lint ${conf} ${files}

View File

@ -1,67 +1,96 @@
#!/bin/sh #!/bin/sh
## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. <ben.grande.b@gmail.com> ## SPDX-FileCopyrightText: 2023 - 2024 Benjamin Grande M. S. <ben.grande.b@gmail.com>
## ##
## SPDX-License-Identifier: AGPL-3.0-or-later ## SPDX-License-Identifier: AGPL-3.0-or-later
set -eu set -eu
usage(){ usage(){
printf '%s\n' "Usage: ${0##*/} PROJECT [release]" >&2 echo "Usage: ${0##*/} PROJECT [PROJECT ...]" >&2
exit 1 exit 1
} }
build_rpm(){
counter=$((counter+1))
project="${1}"
group="$(${spec_get} "${project}" group)"
version="$(${spec_get} "${project}" version)"
license_csv="$(${spec_get} "${project}" license_csv)"
spec="rpm_spec/${group}-${project}.spec"
"${spec_gen}" "${project}"
## All specs have the same format, only lint the first one.
if test "${counter}" = "1"; then
rpmlint "${spec}"
fi
if grep -q "^BuildRequires: " "${spec}"; then
sudo dnf build-dep "${spec}"
fi
mkdir -p \
"${build_dir}/BUILD/${group}-${project}/LICENSES/" \
"${build_dir}/SOURCES/${group}-${project}/LICENSES"
cp -r "salt/${project}/"* "${build_dir}/BUILD/${group}-${project}/"
cp -r "salt/${project}/"* "${build_dir}/SOURCES/${group}-${project}/"
for license in $(echo "${license_csv}" | tr "," " "); do
license_dir="LICENSES"
if test -d "salt/${project}/LICENSES"; then
license_dir="salt/${project}/LICENSES"
fi
cp "${license_dir}/${license}.txt" "${build_dir}/BUILD/${group}-${project}/LICENSES/"
done
## TODO: use qubes-builderv2 with mock or qubes executor
rpmbuild -ba -- "${spec}"
if test -n "${key_id}"; then
rpm_basename="${build_dir}/RPMS/noarch/${group}-${project}-${version}-"
rpm_suffix=".noarch.rpm"
## TODO: target only the latest release
rpmsign --key-id="${key_id}" --digest-algo=sha512 --addsign \
-- "${rpm_basename}"*"${rpm_suffix}" </dev/null
gpg="$(git config --get gpg.program)" || gpg="gpg"
dbpath="$(mktemp -d)"
trap 'rm -rf -- "${dbpath}"' EXIT INT HUP QUIT ABRT
tmp_file="${dbpath}/${key_id}.asc"
"${gpg}" --export --armor "${key_id}" | tee "${tmp_file}" >/dev/null
rpmkeys --dbpath="${dbpath}" --import "${tmp_file}"
## TODO: target only the latest relase
rpm --dbpath="${dbpath}" --checksig --verbose \
-- "${rpm_basename}"*"${rpm_suffix}"
fi
}
case "${1-}" in case "${1-}" in
""|-*) usage;; -h|--?help) usage;;
esac esac
release="" command -v git >/dev/null || { echo "Missing program: git" >&2; exit 1; }
case "${2-}" in
release) release="1";;
"") ;;
*) usage;;
esac
command -v dnf >/dev/null ||
{ printf "Missing program: dnf\n" >&2; exit 1; }
command -v rpmlint >/dev/null ||
{ printf "Missing program: rpmlint\n" >&2; exit 1; }
## command -v rpmdev-setuptree >/dev/null ||
## { printf "Missing program: rpmdev-setuptree\n" >&2; exit 1; }
command -v rpmbuild >/dev/null ||
{ printf "Missing program: rpmbuild\n" >&2; exit 1; }
command -v git >/dev/null ||
{ printf "Missing program: git\n" >&2; exit 1; }
cd "$(git rev-parse --show-toplevel)" || exit 1 cd "$(git rev-parse --show-toplevel)" || exit 1
./scripts/requires-program.sh dnf rpmlint rpmbuild rpmsign
project="${1}" build_dir="${HOME}/rpmbuild"
spec_gen="./scripts/spec-gen.sh"
spec_get="./scripts/spec-get.sh"
group="$(${spec_get} "${project}" group)"
spec="rpm_spec/${group}-${project}.spec"
"${spec_gen}" "${project}"
rpmlint "${spec}"
if grep -q "^BuildRequires: " "${spec}"; then
sudo dnf build-dep "${spec}"
fi
if command -v rpmdev-setuptree >/dev/null; then if command -v rpmdev-setuptree >/dev/null; then
rpmdev-setuptree rpmdev-setuptree
else else
mkdir -p ~/rpmbuild/BUILD ~/rpmbuild/BUILDROOT ~/rpmbuild/RPMS mkdir -p \
mkdir -p ~/rpmbuild/SOURCES ~/rpmbuild/SPECS ~/rpmbuild/SRPMS "${build_dir}/BUILD" "${build_dir}/BUILDROOT" "${build_dir}/RPMS" \
"${build_dir}/SOURCES" "${build_dir}/SPECS" "${build_dir}/SRPMS"
fi fi
mkdir ~/rpmbuild/BUILD/"${group}-${project}" key_id="$(git config --get user.signingKey)" || true
mkdir ~/rpmbuild/SOURCES/"${group}-${project}" spec_gen="./scripts/spec-gen.sh"
spec_get="./scripts/spec-get.sh"
cp -r "salt/${project}"/* ~/rpmbuild/BUILD/"${group}-${project}"/ if test -z "${1-}"; then
cp -r "salt/${project}"/* ~/rpmbuild/SOURCES/"${group}-${project}"/ # shellcheck disable=SC2046
set -- $(find salt/ -mindepth 1 -maxdepth 1 -type d -printf '%f\n' \
if test -n "${release}"; then | sort -d | tr "\n" " ")
rpmbuild -ba --sign "${spec}"
else
rpmbuild -ba "${spec}"
fi fi
counter=0
for p in "$@"; do
build_rpm "${p}"
done

View File

@ -15,8 +15,8 @@ usage(){
## Get scriptlet command, else fail safe. ## Get scriptlet command, else fail safe.
get_scriptlet(){ get_scriptlet(){
scriptlet="$1" scriptlet="$1"
sed -n "/^<\!-- pkg:begin:${scriptlet} -->$/,/^<\!-- pkg:end:${scriptlet} -->$/p" "${readme}" \ sed -n "/^<\!-- pkg:begin:${scriptlet} -->$/,/^<\!-- pkg:end:${scriptlet} -->$/p" \
| grep -v -e '^```\S*$' -e "^<\!-- " | sed "s/^sudo //" || echo "true" "${readme}" | sed '/^```.*/d;/^<\!-- pkg:/d;s/^sudo //' || echo "true"
} }
get_spec(){ get_spec(){
@ -68,7 +68,7 @@ gen_spec(){
"${template}" | tee "${target}" >/dev/null "${template}" | tee "${target}" >/dev/null
requires_key="" requires_key=""
for r in $(printf %s"${requires}" | tr " " "\n"); do for r in $(printf %s"${requires}" | tr " " "\n" | sort -u); do
requires_key="${requires_key}\nRequires: ${group}-${r}" requires_key="${requires_key}\nRequires: ${group}-${r}"
done done
sed -i "s/@REQUIRES@/${requires_key}/" "${target}" >/dev/null sed -i "s/@REQUIRES@/${requires_key}/" "${target}" >/dev/null
@ -76,15 +76,19 @@ gen_spec(){
} }
case "${1-}" in case "${1-}" in
""|-h|--?help) usage; exit 1;; -h|--?help) usage; exit 1;;
esac esac
command -v git >/dev/null || command -v git >/dev/null || { echo "Missing program: git" >&2; exit 1; }
{ printf "Missing program: git\n" >&2; exit 1; }
cd "$(git rev-parse --show-toplevel)" cd "$(git rev-parse --show-toplevel)"
spec_get="./scripts/spec-get.sh" spec_get="./scripts/spec-get.sh"
if test -z "${1-}"; then
# shellcheck disable=SC2046
set -- $(find salt/ -mindepth 1 -maxdepth 1 -type d -printf '%f\n' \
| sort -d | tr "\n" " ")
fi
for p in "$@"; do for p in "$@"; do
gen_spec "${p}" gen_spec "${p}"
done done

View File

@ -8,7 +8,8 @@
set -eu set -eu
usage(){ usage(){
names="$(find salt/ -maxdepth 1 -type d | cut -d "/" -f2 | tr "\n" " ")" names="$(find salt/ -mindepth 1 -maxdepth 1 -type d -printf '%f\n' \
| sort -d | tr "\n" " ")"
echo "Usage: ${0##*/} <NAME> <KEY>" echo "Usage: ${0##*/} <NAME> <KEY>"
echo "Example: ${0##*/} qubes-builder description" echo "Example: ${0##*/} qubes-builder description"
echo "Names: ${names}" echo "Names: ${names}"
@ -28,29 +29,34 @@ block_max_chars(){
keys="name branch group file_roots requires vendor url version project project_dir changelog readme license_csv license description summary saltfiles" keys="name branch group file_roots requires vendor url version project project_dir changelog readme license_csv license description summary saltfiles"
name=""
key=""
case "${1-}" in case "${1-}" in
"") usage; exit 1;; "") usage; exit 1;;
-h|--?help) usage; exit 0;; -h|--?help) usage; exit 0;;
*) name="${1}"; shift;;
esac esac
case "${2-}" in case "${1-}" in
"") usage; exit 1;; "") usage; exit 1;;
*) key="${1}"; shift;;
esac esac
if test -z "${key##* }"; then
echo "Key is emtpy: ${key}" >&2
exit 1
fi
command -v reuse >/dev/null || command -v git >/dev/null || { echo "Missing program: git" >&2; exit 1; }
{ printf "Missing program: reuse\n" >&2; exit 1; }
command -v git >/dev/null ||
{ printf "Missing program: git\n" >&2; exit 1; }
cd "$(git rev-parse --show-toplevel)" || exit 1 cd "$(git rev-parse --show-toplevel)" || exit 1
./scripts/requires-program.sh reuse
if test "${key}" = "branch"; then
branch="$(git branch --show-current)"
fi
name="${1}"
key="${2}"
branch="$(git branch --show-current)"
group="qusal" group="qusal"
block_max_chars group "${group}" 70 block_max_chars group "${group}" 70
file_roots="/srv/salt/${group}" file_roots="/srv/salt/${group}"
vendor="Benjamin Grande" vendor="Benjamin Grande"
url="https://github.com/ben-grande/qusal" url="https://github.com/ben-grande/qusal"
version="1.0" version="1.0"
@ -68,51 +74,53 @@ if ! test -f "${readme}"; then
exit 1 exit 1
fi fi
license_csv="$(reuse --root "${project_dir}" lint | if test "${key}" = "license" || test "${key}" = "license_csv"; then
awk -F ':' '/^* Used licenses:/{print $2}' | tr -d " ")" license_csv="$(reuse --root "${project_dir}" lint |
license="$(echo "$license_csv" | sed "s/,/ AND /g")" awk -F ':' '/^* Used licenses:/{print $2}' | tr -d " ")"
#license="$(reuse --root "${project_dir}" lint | license="$(echo "${license_csv}" | sed "s/,/ AND /g")"
# awk -F ':' '/^* Used licenses:/{print $2}' | sed "s|, | AND |g")"
## The problem with %autochangelog is that it will print logs of all projects
## and we separate a project per directory.
## The disadvantage of the changelog below is that it doesn't differentiate
## commits per package release.
changelog="$(TZ=UTC0 git log -n 50 --format=format:"* %cd %an <%ae> - %h%n- %s%n%n" --date=format:"%a %b %d %Y" -- "${project_dir}" | sed -re "s/^- +- */- /;/^$/d")"
#block_max_chars license "${license}" 70
description="$(sed -n '/^## Description/,/^## /p' "${readme}" |
sed '1d;$d' | sed "1{/^$/d}")"
summary="$(sed -n '3p' "${readme}")"
block_max_chars summary "${summary}" 70
saltfiles="$(find "${project_dir}" -maxdepth 1 -name "*.sls")"
# shellcheck disable=SC2086
if test -n "${saltfiles}"; then
requires="$(sed -n '/^include:$/,/^\s*$/p' ${saltfiles} | sed "/^\s*- \./d;/{/d" | grep "^\s*- " | cut -d "." -f1 | sort -u | sed "s/- //")"
if grep -qrn "{%-\? from \('\|\"\)utils" ${saltfiles}; then
if test -n "${requires}"; then
requires="${requires} utils"
else
requires="utils"
fi
fi
else
requires=""
fi fi
requires_valid=""
for r in $(printf %s"${requires}" | tr " " "\n"); do
if ! test -d "salt/${r}"; then
continue
fi
requires_valid="${requires_valid} ${r}"
done
requires="${requires_valid}"
unset requires_valid
if test -z "${key}" || test "$(echo "${key}" | sed "s/ //g")" = ""; then ## The macro %autochangelog prints logs of all projects and we separate a
echo "Key has no value: ${key}" >&2 ## project per directory. The disadvantage of the changelog below is it
exit 1 # #doesn't differentiate commits per version and release, but per commit id.
if test "${key}" = "changelog"; then
changelog="$(TZ=UTC0 git log -n 50 --format=format:"* %cd %an <%ae> - %h%n- %s%n%n" --date=format:"%a %b %d %Y" -- "${project_dir}" | sed -re "s/^- +- */- /;/^$/d")"
fi
if test "${key}" = "description"; then
description="$(sed -n '/^## Description/,/^## /p' "${readme}" |
sed '1d;$d' | sed "1{/^$/d}")"
fi
if test "${key}" = "summary"; then
summary="$(sed -n "/^# ${name}$/,/^## Table of Contents$/{/./!d;/^#/d;p}" "${readme}")"
block_max_chars summary "${summary}" 70
fi
if test "${key}" = "saltfiles" || test "${key}" = "requires"; then
saltfiles="$(find "${project_dir}" -maxdepth 1 -name "*.sls")"
# shellcheck disable=SC2086
if test -n "${saltfiles}"; then
requires="$(sed -n '/^include:$/,/^\s*$/p' ${saltfiles} | sed "/^\s*- \./d;/{/d" | grep "^\s*- " | cut -d "." -f1 | sort -u | sed "s/- //")"
if grep -qrn "{%-\? from \('\|\"\)utils" ${saltfiles}; then
if test -n "${requires}"; then
requires="${requires} utils"
else
requires="utils"
fi
fi
else
requires=""
fi
requires_valid=""
for r in $(printf %s"${requires}" | tr " " "\n"); do
if ! test -d "salt/${r}"; then
continue
fi
requires_valid="${requires_valid} ${r}"
done
requires="${requires_valid}"
unset requires_valid
fi fi
case "${key}" in case "${key}" in

31
scripts/yumrepo-gen.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/sh
## SPDX-FileCopyrightText: 2023 - 2024 Benjamin Grande M. S. <ben.grande.b@gmail.com>
##
## SPDX-License-Identifier: AGPL-3.0-or-later
set -eu
command -v git >/dev/null || { echo "Missing program: git" >&2; exit 1; }
cd "$(git rev-parse --show-toplevel)" || exit 1
./scripts/requires-program.sh createrepo_c gpg
key_id="$(git config --get user.signingKey)" || true
build_dir="${HOME}/rpmbuild"
qubes_release="r4.2"
repo="current"
dist="fc37"
yum_repo_root="$HOME/rpmrepo"
yum_repo="${yum_repo_root}/${qubes_release}/${repo}/host/${dist}"
mkdir -p "${yum_repo}/rpm"
find "${build_dir}/RPMS/" -type f -name "*.rpm" \
-exec cp {} "${yum_repo}/rpm/" \;
createrepo_c --checksum sha512 "${yum_repo}"
if test -n "${key_id}"; then
rm -f -- "${yum_repo}/repodata/repomd.xml.asc"
gpg --batch --no-tty --detach-sign --armor --local-user "${key_id}" \
-- "${yum_repo}/repodata/repomd.xml"
fi
## TODO: rsync to remote host