diff --git a/common.lua b/common.lua index 1191c1f..e087a1c 100644 --- a/common.lua +++ b/common.lua @@ -120,7 +120,7 @@ end -- @@FOO@@ with the rpm evaluation of %{foo} and -- @@BAR@@ with the rpm evaluation of %{bar} -- in myfile -local function writevars(macrofile,rpmvars) +local function writevars(macrofile, rpmvars) for _, rpmvar in ipairs(rpmvars) do print("sed -i 's\029" .. string.upper("@@" .. rpmvar .. "@@") .. "\029" .. rpm.expand( "%{" .. rpmvar .. "}" ) .. @@ -128,6 +128,58 @@ local function writevars(macrofile,rpmvars) end end +-- https://github.com/rpm-software-management/rpm/issues/566 +-- Reformat a text intended to be used used in a package description, removing +-- rpm macro generation artefacts. +-- – remove leading and ending empty lines +-- – trim intermediary empty lines to a single line +-- – fold on spaces +-- Should really be a %%{wordwrap:…} verb +local function wordwrap(text) + text = rpm.expand(text .. "\n") + text = string.gsub(text, "\t", " ") + text = string.gsub(text, " +\n", "\n") + text = string.gsub(text, "\n+\n", "\n\n") + text = string.gsub(text, "^\n", "") + text = string.gsub(text, "\n( *)[-*—][  ]+", "\n%1– ") + output = "" + for line in string.gmatch(text, "[^\n]*\n") do + local pos = 0 + local advance = "" + for word in string.gmatch(line, "%s*[^%s]*\n?") do + local wl, bad = utf8.len(word) + if not wl then + print("%{warn: Invalid UTF-8 sequence detected in:\n" .. + word .. "\nIt may produce unexpected results.\n}") + wl = bad + end + if (pos == 0) then + advance, n = string.gsub(word, "^(%s*– ).*", "%1") + if (n == 0) then + advance = string.gsub(word, "^(%s*).*", "%1") + end + advance = string.gsub(advance, "– ", " ") + pos = pos + wl + elseif (pos + wl < 81) then + pos = pos + wl + else + word = advance .. string.gsub(word, "^%s*", "") + output = output .. "\n" + pos = utf8.len(word) + end + output = output .. word + if pos > 80 then + pos = 0 + if not string.match(word, "\n$") then + output = output .. "\n" + end + end + end + end + output = string.gsub(output, "\n*$", "\n") + return output +end + return { explicitset = explicitset, explicitunset = explicitunset, @@ -139,4 +191,5 @@ return { getsuffixes = getsuffixes, getbestsuffix = getbestsuffix, writevars = writevars, + wordwrap = wordwrap, } diff --git a/forge.lua b/forge.lua index 950e345..96852f7 100644 --- a/forge.lua +++ b/forge.lua @@ -19,6 +19,18 @@ local function checkforgeurl(url, id, silent) gitlab = { pattern = 'https://[^/]+/[^/]+/[^/#?]+', description = 'https://(…[-.])gitlab[-.]…/owner/repo'}, + pagure = { + pattern = 'https://[^/]+/[^/#?]+', + description = 'https://pagure.io/repo'}, + pagure_ns = { + pattern = 'https://[^/]+/[^/]+/[^/#?]+', + description = 'https://pagure.io/namespace/repo'}, + pagure_fork = { + pattern = 'https://[^/]+/fork/[^/]+/[^/#?]+', + description = 'https://pagure.io/fork/owner/repo'}, + pagure_ns_fork = { + pattern = 'https://[^/]+/fork/[^/]+/[^/]+/[^/#?]+', + description = 'https://pagure.io/fork/owner/namespace/repo'}, github = { pattern = 'https://[^/]+/[^/]+/[^/#?]+', description = 'https://(…[-.])github[-.]…/owner/repo'}, @@ -52,7 +64,17 @@ local function idforge(url, silent) rpm.expand("%{error:URLs must include a protocol such as https:// and a path starting with / !}") end else - if (string.match(forge, "^gitlab[%.-]") or string.match(forge, "[%.-]gitlab[%.]")) then + if (forge == "pagure.io") then + if string.match(url, "[^:]+://pagure.io/fork/[^/]+/[^/]+/[^/]+") then + forge = "pagure_ns_fork" + elseif string.match(url, "[^:]+://pagure.io/fork/[^/]+/[^/]+") then + forge = "pagure_fork" + elseif string.match(url, "[^:]+://pagure.io/[^/]+/[^/]+") then + forge = "pagure_ns" + elseif string.match(url, "[^:]+://pagure.io/[^/]+") then + forge = "pagure" + end + elseif (string.match(forge, "^gitlab[%.-]") or string.match(forge, "[%.-]gitlab[%.]")) then forge = "gitlab" elseif (string.match(forge, "^github[%.-]") or string.match(forge, "[%.-]github[%.]")) then forge = "github" @@ -72,7 +94,7 @@ local function meta(suffix, verbose, informative, silent) if ismain then fedora.zalias({"forgeurl", "forgesource", "forgesetupargs", "archivename", "archiveext", "archiveurl", - "topdir", "extractdir", "repo", "owner", + "topdir", "extractdir", "repo", "owner", "namespace", "scm", "tag", "commit", "shortcommit", "branch", "version", "date", "distprefix"}, verbose) end @@ -80,11 +102,33 @@ local function meta(suffix, verbose, informative, silent) default = { scm = "git", archiveext = "tar.bz2", - repo = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/[^/]+/([^/]+)"))}', + repo = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/[^/]+/([^/?#]+)"))}', archivename = "%{repo" .. suffix .. "}-%{ref" .. suffix .. "}", topdir = "%{archivename" .. suffix .. "}" }, gitlab = { archiveurl = "%{forgeurl" .. suffix .. "}/-/archive/%{ref" .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" }, + pagure = { + archiveext = "tar.gz", + repo = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/([^/?#]+)"))}', + archiveurl = "%{forgeurl" .. suffix .. "}/archive/%{ref" .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" }, + pagure_ns = { + archiveext = "tar.gz", + namespace = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/([^/]+)/[^/?#]+"))}', + repo = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/[^/]+/([^/?#]+)"))}', + archivename = "%{namespace" .. suffix .. "}-%{repo" .. suffix .. "}-%{ref" .. suffix .. "}", + archiveurl = "%{forgeurl" .. suffix .. "}/archive/%{ref" .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" }, + pagure_fork = { + archiveext = "tar.gz", + owner = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/([^/]+)/[^/?#]+"))}', + repo = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/[^/]+/([^/?#]+)"))}', + archivename = "%{owner" .. suffix .. "}-%{repo" .. suffix .. "}-%{ref" .. suffix .. "}", + archiveurl = "%{forgeurl" .. suffix .. "}/archive/%{ref" .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" }, + pagure_ns_fork = { + owner = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/([^/]+)/[^/]+/[^/?#]+"))}', + namespace = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/[^/]+/([^/]+)/[^/?#]+")}', + repo = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "https://[^/]+/fork/[^/]+/[^/]+/([^/?#]+)")}', + archivename = "%{owner" .. suffix .. "}-%{namespace" .. suffix .. "}-%{repo" .. suffix .. "}-%{ref" .. suffix .. "}", + archiveurl = "%{forgeurl" .. suffix .. "}/archive/%{ref" .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}" }, github = { archiveext = "tar.gz", archivename = "%{repo" .. suffix .. "}-%{fileref" .. suffix .. "}", @@ -96,7 +140,7 @@ local function meta(suffix, verbose, informative, silent) topdir = "" }, ["bitbucket.org"] = { shortcommit = '%{lua:print(string.sub(rpm.expand("%{commit' .. suffix .. '}"), 1, 12))}', - owner = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/([^/]+)"))}', + owner = '%{lua:print(string.match(rpm.expand("%{forgeurl' .. suffix .. '}"), "^[^:]+://[^/]+/([^/?#]+)"))}', archivename = "%{owner" .. suffix .. "}-%{repo" .. suffix .. "}-%{shortcommit" .. suffix .. "}", archiveurl = "%{forgeurl" .. suffix .. "}/get/%{ref" .. suffix .. "}.%{archiveext" .. suffix .. "}" } } -- Packaging a moving branch is quite a bad idea, but since at least Gitlab @@ -233,7 +277,7 @@ local function meta(suffix, verbose, informative, silent) if ismain then fedora.zalias({"forgeurl", "forgesource", "forgesetupargs", "archivename", "archiveext", "archiveurl", - "topdir", "extractdir", "repo", "owner", + "topdir", "extractdir", "repo", "owner", "namespace", "scm", "shortcommit", "distprefix"}, verbose) end -- Final spec variable summary if the macro was called with -i @@ -241,7 +285,7 @@ local function meta(suffix, verbose, informative, silent) rpm.expand("%{echo:Packaging variables read or set by %%forgemeta}") fedora.echovars({"forgeurl", "forgesource", "forgesetupargs", "archivename", "archiveext", "archiveurl", - "topdir", "extractdir", "repo", "owner", + "topdir", "extractdir", "repo", "owner", "namespace", "scm", "tag", "commit", "shortcommit", "branch", "version", "date", "distprefix"}, suffix) fedora.echovars({"dist"},"") diff --git a/gpgverify b/gpgverify new file mode 100755 index 0000000..524a396 --- /dev/null +++ b/gpgverify @@ -0,0 +1,111 @@ +#!/bin/bash + +# Copyright 2018 B. Persson, Bjorn@Rombobeorn.se +# +# This material is provided as is, with absolutely no warranty expressed +# or implied. Any use is at your own risk. +# +# Permission is hereby granted to use or copy this shellscript +# for any purpose, provided the above notices are retained on all copies. +# Permission to modify the code and to distribute modified code is granted, +# provided the above notices are retained, and a notice that the code was +# modified is included with the above copyright notice. + + +function print_help { + cat <<'EOF' +Usage: gpgverify --keyring= --signature= --data= + +gpgverify is a wrapper around gpgv designed for easy and safe scripting. It +verifies a file against a detached OpenPGP signature and a keyring. The keyring +shall contain all the keys that are trusted to certify the authenticity of the +file, and must not contain any untrusted keys. + +The differences, compared to invoking gpgv directly, are that gpgverify accepts +the keyring in either ASCII-armored or unarmored form, and that it will not +accidentally use a default keyring in addition to the specified one. + +Parameters: + --keyring= keyring with all the trusted keys and no others + --signature= detached signature to verify + --data= file to verify against the signature +EOF +} + + +fatal_error() { + message="$1" # an error message + status=$2 # a number to use as the exit code + echo "gpgverify: $message" >&2 + exit $status +} + + +require_parameter() { + term="$1" # a term for a required parameter + value="$2" # Complain and terminate if this value is empty. + if test -z "${value}" ; then + fatal_error "No ${term} was provided." 2 + fi +} + + +check_status() { + action="$1" # a string that describes the action that was attempted + status=$2 # the exit code of the command + if test $status -ne 0 ; then + fatal_error "$action failed." $status + fi +} + + +# Parse the command line. +keyring= +signature= +data= +for parameter in "$@" ; do + case "${parameter}" in + (--help) + print_help + exit + ;; + (--keyring=*) + keyring="${parameter#*=}" + ;; + (--signature=*) + signature="${parameter#*=}" + ;; + (--data=*) + data="${parameter#*=}" + ;; + (*) + fatal_error "Unknown parameter: \"${parameter}\"" 2 + ;; + esac +done +require_parameter 'keyring' "${keyring}" +require_parameter 'signature' "${signature}" +require_parameter 'data file' "${data}" + +# Make a temporary working directory. +workdir="$(mktemp --directory)" +check_status 'Making a temporary directory' $? +workring="${workdir}/keyring.gpg" + +# Decode any ASCII armor on the keyring. This is harmless if the keyring isn't +# ASCII-armored. +gpg2 --homedir="${workdir}" --yes --output="${workring}" --dearmor "${keyring}" +check_status 'Decoding the keyring' $? + +# Verify the signature using the decoded keyring. +gpgv2 --homedir="${workdir}" --keyring="${workring}" "${signature}" "${data}" +check_status 'Signature verification' $? + +# (--homedir isn't actually necessary. --dearmor processes only the input file, +# and if --keyring is used and contains a slash, then gpgv2 uses only that +# keyring. Thus neither command will look for a default keyring, but --homedir +# makes extra double sure that no default keyring will be touched in case +# another version of GPG works differently.) + +# Clean up. (This is not done in case of an error that may need inspection.) +rm --recursive --force ${workdir} diff --git a/macros b/macros index 067a476..a9f65cc 100644 --- a/macros +++ b/macros @@ -18,6 +18,8 @@ %_fmoddir %{_libdir}/gfortran/modules +%source_date_epoch_from_changelog 1 + %_enable_debug_packages 1 %_include_minidebuginfo 1 %_include_gdb_index 1 @@ -193,8 +195,8 @@ print(result) %_source_filedigest_algorithm 8 %_binary_filedigest_algorithm 8 -# Use XZ compression for binary payloads -%_binary_payload w2.xzdio +# Use Zstandard compression for binary payloads +%_binary_payload w19.zstdio %_hardening_cflags -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 # we don't escape symbols '~', '"', etc. so be careful when changing this @@ -264,6 +266,9 @@ print(result) %global __find_requires /bin/sh -c "%{?__filter_req_cmd} %{__deploop R} %{?__filter_from_req}" \ } +# Temporary shelter for rpm 4.15 refugees +%requires_eq() %(LC_ALL="C" echo '%*' | xargs -r rpm -q --qf 'Requires: %%{name} = %%{epoch}:%%{version}\\n' | sed -e 's/ (none):/ /' -e 's/ 0:/ /' | grep -v "is not") + # override %check sections and disable them (exit 0) while we are # bootstrapping Fedora RISC-V %__spec_check_pre exit 0 diff --git a/macros.fedora-misc b/macros.fedora-misc index ca54197..83e455a 100644 --- a/macros.fedora-misc +++ b/macros.fedora-misc @@ -1,15 +1,28 @@ # Some miscellaneous Fedora-related macros # List files matching inclusion globs, excluding files matching exclusion blogs -# Parameters: -# -i "" include shell globs (also takes all other macro arguments) -# -x "" exclude shell globs +# Optional parameters: +# – -i "" inclusion globs +# – -x "" exclusion globs +# Globs are space-separated lists of shell globs. Such lists require %{quote:} +# use for safe rpm argument passing. +# Alternatively, set the following rpm variables before calling the macro: +# – “listfiles_include” inclusion globs +# — “listfiles_exclude” exclusion globs +# Arguments passed to the macro without flags will be interpreted as inclusion +# globs. %listfiles(i:x:) %{expand: -while IFS= read -r -d $'\\n' finc ; do - printf "%s\\n" %{?-x*} \\ - | xargs -i realpath --relative-base=. '{}' \\ - | grep "${finc}" >/dev/null || echo "${finc}" -done <<< $(printf "%s\\n" %{?-i*} %* | xargs -i realpath --relative-base=. '{}' | sort -u) +%if %{lua: print(string.len(rpm.expand("%{?-i*}%{?listfiles_include}%*")))} + listfiles_include=$(realpath -e --relative-base=. %{?-i*} %{?listfiles_include} %* | sort -u) + %if %{lua: print(string.len(rpm.expand("%{?-x*}%{?listfiles_exclude}")))} + while IFS= read -r finc ; do + realpath -qe --relative-base=. %{?-x*} %{?listfiles_exclude} \\ + | sort -u | grep -q "${finc}" || echo "${finc}" + done <<< "${listfiles_include}" + %else + echo "${listfiles_include}" + %endif +%endif } # https://github.com/rpm-software-management/rpm/issues/581 @@ -28,3 +41,6 @@ for i = 1, rpm.expand("%#") do end fedora.writevars(macrofile,rpmvars) } + +# gpgverify verifies signed sources. There is documentation in the script. +%gpgverify %{_rpmconfigdir}/redhat/gpgverify diff --git a/macros.fedora-misc-srpm b/macros.fedora-misc-srpm index 98aa6c2..3431190 100644 --- a/macros.fedora-misc-srpm +++ b/macros.fedora-misc-srpm @@ -9,3 +9,14 @@ # A directory for SWID tag files describing the installation %_swidtagdir %{_prefix}/lib/swidtag/fedoraproject.org + +# A helper to apply the fedora.wordwrap filter to the content of an rpm +# variable, and print the result. Optional parameter: +# – -v (default value: _description) +# Putting multiple lines of UTF-8 text inside a variable is usually +# accomplished with a %%{expand: some_text}. +%wordwrap(v:) %{lua: +local fedora = require "fedora.common" +local variable = "%{" .. rpm.expand("%{-v*}%{!-v:_description}") .. "}" +print(fedora.wordwrap(variable)) +} diff --git a/redhat-rpm-config.spec b/redhat-rpm-config.spec index a2c7128..d9a62f5 100644 --- a/redhat-rpm-config.spec +++ b/redhat-rpm-config.spec @@ -6,7 +6,7 @@ Summary: Red Hat specific rpm configuration files Name: redhat-rpm-config -Version: 128 +Version: 137 Release: 1.0.riscv64%{?dist} # No version specified. License: GPL+ @@ -61,6 +61,7 @@ Source400: dist.sh Source401: rpmsort Source402: symset-table Source403: kmodtool +Source404: gpgverify # 2016-10-02 snapshots from http://git.savannah.gnu.org/gitweb/?p=config.git Source500: config.guess @@ -140,6 +141,7 @@ install -p -m 444 -t %{buildroot}%{rrcdir} redhat-hardened-* install -p -m 444 -t %{buildroot}%{rrcdir} redhat-annobin-* install -p -m 755 -t %{buildroot}%{rrcdir} config.* install -p -m 755 -t %{buildroot}%{rrcdir} dist.sh rpmsort symset-table kmodtool +install -p -m 755 -t %{buildroot}%{rrcdir} gpgverify install -p -m 755 -t %{buildroot}%{rrcdir} brp-* install -p -m 755 -t %{buildroot}%{rrcdir} find-* @@ -165,6 +167,7 @@ install -p -m 644 -t %{buildroot}%{_rpmluadir}/fedora/srpm forge.lua %{rrcdir}/rpmrc %{rrcdir}/brp-* %{rrcdir}/dist.sh +%{rrcdir}/gpgverify %{rrcdir}/redhat-hardened-* %{rrcdir}/redhat-annobin-* %{rrcdir}/config.* @@ -199,12 +202,45 @@ install -p -m 644 -t %{buildroot}%{_rpmluadir}/fedora/srpm forge.lua %{_rpmconfigdir}/macros.d/macros.kmp %changelog -* Thu Mar 14 2019 David Abdurachmanov - 128-1.0.riscv64 +* Wed Jul 10 2019 David Abdurachmanov - 137-1.0.riscv64 - Disable perl_default_subpackage_tests (test suite subpackage for perl packages) - Disable %check for riscv64 - Add -fasynchronous-unwind-tables -fstack-clash-protection to riscv64 (other arches seem to have them now) +* Mon Jul 08 2019 Nicolas Mailhot - 137-1 +- listfiles: make it robust against all kinds of “interesting” inputs +- wordwrap: make list indenting smarter, to produce something with enough + structure that it can be converted into AppStream metadata + +* Mon Jul 08 2019 Robert-André Mauchin - 136-1 +- Revert "Fix expansion in listfiles_exclude/listfiles_include" + +* Mon Jul 08 2019 Nicolas Mailhot - 135-1 +- Fix expansion in listfiles_exclude/listfiles_include + +* Mon Jul 01 2019 Florian Festi - 134-1 +- Switch binary payload compression to Zstandard level 19 + +* Thu Jun 27 2019 Vít Ondruch - 133-2 +- Enable RPM to set SOURCE_DATE_EPOCH environment variable. + +* Tue Jun 25 08:13:50 CEST 2019 Igor Gnatenko - 133-1 +- Expand listfiles_exclude/listfiles_include + +* Tue Jun 11 2019 Jitka Plesnikova - 132-1 +- Remove perl macro refugees + +* Mon Jun 10 2019 Panu Matilainen - 131-1 +- Provide temporary shelter for rpm 4.15 perl macro refugees + +* Tue Jun 04 2019 Igor Gnatenko - 130-1 +- New macro for wrapping text — %%wordwrap +- Smal fix for %%listfiles with no arguments + +* Thu May 30 2019 Björn Persson - 129-1 +- Added gpgverify. + * Tue Jan 15 2019 Panu Matilainen - 128-1 - Drop redundant _smp_mflag re-definition, use the one from rpm instead