Adding srpm build process

This commit is contained in:
2026-04-27 10:45:48 -04:00
parent 137ab08d22
commit cf3c8cd005
9 changed files with 737 additions and 806 deletions
+21
View File
@@ -0,0 +1,21 @@
FEDORA_BRANCH ?= f43
FEDORA_DIST ?= .fc43
FEDORA_NAMESPACE ?= rpms
LOOKASIDE_BASEURL ?= https://src.fedoraproject.org/repo/pkgs
PYTHON ?= python3
REPO_ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..)
SPEC_REF := $(strip $(if $(spec),$(spec),$(COPR_PACKAGE)))
.PHONY: srpm
srpm:
test -n "$(SPEC_REF)"
test -n "$(outdir)"
mkdir -p "$(outdir)"
cd "$(REPO_ROOT)" && "$(PYTHON)" ci/copr-distgit-make-srpm.py \
--spec-ref "$(SPEC_REF)" \
--outdir "$(outdir)" \
--branch "$(FEDORA_BRANCH)" \
--dist "$(FEDORA_DIST)" \
--namespace "$(FEDORA_NAMESPACE)" \
--lookaside-baseurl "$(LOOKASIDE_BASEURL)"
+93 -316
View File
@@ -1,359 +1,136 @@
name: Build Fedora x86_64-v3 RPMs (Gitea) name: Validate Fedora x86_64-v3 Copr SRPMs (Gitea)
on: on:
workflow_dispatch: workflow_dispatch:
inputs:
package_input:
description: "Optional comma, space, or newline separated package list. Leave blank to use packages.txt."
required: false
default: ""
type: string
push: push:
paths: paths:
- 'packages.txt' - '.copr/Makefile'
- 'ci/assemble-dnf-repo.py'
- '.gitea/workflows/build-v3-rpms.yml' - '.gitea/workflows/build-v3-rpms.yml'
- 'ci/copr-distgit-make-srpm.py'
- 'packages.txt'
- 'packaging/copr-rpm-macros-x86-64-v3.spec'
jobs: jobs:
build: prepare:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: outputs:
image: ghcr.io/funkemunky/kde-x86_64-v4-fedora-rpm-builder:latest matrix: ${{ steps.select.outputs.matrix }}
strategy: package_count: ${{ steps.select.outputs.package_count }}
fail-fast: false
matrix:
arch: [x86-64-v3]
shard:
- "001"
- "002"
- "003"
- "004"
- "005"
- "006"
- "007"
- "008"
- "009"
- "010"
- "011"
- "012"
- "013"
- "014"
- "015"
- "016"
- "017"
- "018"
- "019"
- "020"
- "021"
- "022"
- "023"
- "024"
- "025"
- "026"
- "027"
- "028"
- "029"
- "030"
- "031"
- "032"
- "033"
- "034"
- "035"
- "036"
- "037"
- "038"
- "039"
- "040"
- "041"
- "042"
- "043"
- "044"
- "045"
- "046"
- "047"
- "048"
- "049"
- "050"
- "051"
- "052"
- "053"
- "054"
- "055"
- "056"
- "057"
- "058"
- "059"
- "060"
- "061"
- "062"
- "063"
- "064"
- "065"
- "066"
- "067"
- "068"
- "069"
- "070"
- "071"
- "072"
- "073"
- "074"
- "075"
- "076"
- "077"
- "078"
- "079"
- "080"
- "081"
- "082"
- "083"
- "084"
- "085"
- "086"
- "087"
- "088"
- "089"
- "090"
- "091"
- "092"
- "093"
- "094"
- "095"
- "096"
- "097"
- "098"
- "099"
- "100"
- "101"
- "102"
- "103"
- "104"
- "105"
- "106"
- "107"
- "108"
- "109"
- "110"
- "111"
- "112"
- "113"
- "114"
- "115"
- "116"
- "117"
- "118"
- "119"
- "120"
- "121"
- "122"
- "123"
- "124"
- "125"
- "126"
- "127"
- "128"
steps: steps:
- name: Pre-install Node.js and Git
run: |
if command -v node >/dev/null 2>&1 && command -v git >/dev/null 2>&1
then
echo "Node.js and Git already present; skipping install."
exit 0
fi
mkdir -p /etc/dnf/dnf.conf.d
printf '%s\n' 'keepcache=True' 'max_parallel_downloads=10' > /etc/dnf/dnf.conf.d/99-ci-cache.conf
dnf -y install nodejs git
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install build tools
run: |
if command -v fedpkg >/dev/null 2>&1 \
&& command -v rpmbuild >/dev/null 2>&1 \
&& command -v rpmdev-setuptree >/dev/null 2>&1 \
&& command -v git >/dev/null 2>&1 \
&& command -v python3 >/dev/null 2>&1 \
&& rpm -q dnf-plugins-core >/dev/null 2>&1
then
echo "Build tools already present; skipping install."
exit 0
fi
mkdir -p /etc/dnf/dnf.conf.d - id: select
printf '%s\n' 'keepcache=True' 'max_parallel_downloads=10' > /etc/dnf/dnf.conf.d/99-ci-cache.conf
dnf -y install 'dnf-command(builddep)' fedpkg rpm-build rpmdevtools git python3
- name: Build shard packages
env: env:
SHARD_INDEX: ${{ matrix.shard }} PACKAGE_INPUT: ${{ inputs.package_input }}
FEDORA_BRANCH: f43
TARGET_MARCH: ${{ matrix.arch }}
run: | run: |
python3 <<'PY' python3 <<'PY'
import json
import os import os
import shutil import re
import subprocess
import time
from pathlib import Path from pathlib import Path
workspace = Path(os.environ["GITHUB_WORKSPACE"]) packages_file = Path("packages.txt")
shard_index = int(os.environ["SHARD_INDEX"]) package_input = os.environ.get("PACKAGE_INPUT", "")
fedora_branch = os.environ["FEDORA_BRANCH"] if not package_input.strip() and not packages_file.exists():
target_march = os.environ["TARGET_MARCH"]
packages_file = workspace / "packages.txt"
if not packages_file.exists():
print("packages.txt not found") print("packages.txt not found")
raise SystemExit(1) raise SystemExit(1)
all_packages = [ if package_input.strip():
packages = [
entry
for entry in re.split(r"[\s,]+", package_input.strip())
if entry
]
else:
packages = [
line.strip() line.strip()
for line in packages_file.read_text(encoding="utf-8").splitlines() for line in packages_file.read_text(encoding="utf-8").splitlines()
if line.strip() and not line.startswith("#") if line.strip() and not line.startswith("#")
] ]
max_shards = 128 max_matrix = 128
shard_count = min(len(all_packages), max_shards) matrix = []
if shard_count == 0 or shard_index > shard_count: if packages:
print( shard_size = max(1, -(-len(packages) // max_matrix))
f"Skipping shard {shard_index:03d} for {target_march}; " shards = [
f"package_count={len(all_packages)} shard_count={shard_count}" packages[index:index + shard_size]
) for index in range(0, len(packages), shard_size)
raise SystemExit(0) ]
matrix = [
{
"shard_label": f"{shard_index + 1:03d}",
"packages": shard,
}
for shard_index, shard in enumerate(shards)
]
shard_size = max(1, -(-len(all_packages) // shard_count)) with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as handle:
start_index = (shard_index - 1) * shard_size handle.write(f"matrix={json.dumps(matrix)}\n")
end_index = start_index + shard_size handle.write(f"package_count={len(packages)}\n")
packages = all_packages[start_index:end_index]
# Standard Fedora optflags with march override
# We'll use a simplified version of the override from the other workflow
optflags_override = (
f"-O2 -flto=auto -ffat-lto-objects -fexceptions -g "
"-grecord-gcc-switches -pipe -Wall -Werror=format-security "
"-Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 "
"-Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 "
"-fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 "
f"-m64 -march={target_march} -mtune=generic -fasynchronous-unwind-tables "
"-fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 "
"-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"
)
shard_root = workspace / "artifacts" / f"{target_march}-shard-{shard_index:03d}"
shard_root.mkdir(parents=True, exist_ok=True)
rpmbuild_root = workspace / ".rpmbuild"
rpmbuild_root.mkdir(parents=True, exist_ok=True)
def run_with_retry(command, *, cwd=None, cleanup_path=None, attempts=3):
for attempt in range(1, attempts + 1):
if cleanup_path is not None and cleanup_path.exists():
shutil.rmtree(cleanup_path)
try:
subprocess.run(command, cwd=cwd, check=True)
return
except subprocess.CalledProcessError:
if attempt == attempts:
raise
time.sleep(5 * attempt)
for package_name in packages:
package_dir = workspace / package_name
run_with_retry(
[
"git", "clone", "--depth", "1", "--branch", fedora_branch,
f"https://src.fedoraproject.org/rpms/{package_name}.git",
str(package_dir),
],
cleanup_path=package_dir,
)
run_with_retry(["fedpkg", "sources"], cwd=package_dir)
spec_file = next(package_dir.glob("*.spec"), None)
if not spec_file:
print(f"No spec file for {package_name}")
continue
subprocess.run(["dnf", "-y", "builddep", str(spec_file)], check=True)
topdir = rpmbuild_root / package_name
for subdir in ("BUILD", "BUILDROOT", "RPMS", "SOURCES", "SPECS", "SRPMS"):
(topdir / subdir).mkdir(parents=True, exist_ok=True)
subprocess.run(
[
"rpmbuild", "-ba", str(spec_file),
"--define", f"optflags {optflags_override}",
"--define", f"_topdir {topdir}",
"--define", f"_builddir {topdir / 'BUILD'}",
"--define", f"_buildrootdir {topdir / 'BUILDROOT'}",
"--define", f"_rpmdir {topdir / 'RPMS'}",
"--define", f"_srcrpmdir {topdir / 'SRPMS'}",
"--define", f"_sourcedir {package_dir}",
"--define", f"_specdir {package_dir}",
],
check=True,
)
for rpm_path in (topdir / "RPMS").rglob("*.rpm"):
shutil.copy2(rpm_path, shard_root / rpm_path.name)
for src_path in (topdir / "SRPMS").rglob("*.src.rpm"):
shutil.copy2(src_path, shard_root / src_path.name)
print(f"Built {package_name}")
PY PY
- name: Upload RPM artifacts validate-srpms:
uses: actions/upload-artifact@v3 needs: prepare
with: if: ${{ needs.prepare.outputs.package_count != '0' }}
name: rpm-${{ matrix.arch }}-shard-${{ matrix.shard }}
path: artifacts/${{ matrix.arch }}-shard-${{ matrix.shard }}/
if-no-files-found: ignore
assemble-repo:
needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/funkemunky/kde-x86_64-v4-fedora-rpm-builder:latest image: fedora:43
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: include: ${{ fromJSON(needs.prepare.outputs.matrix) }}
- arch: x86-64-v3
repo_id: fedora43-kde-x86-64-v3
- arch: x86-64-v4
repo_id: fedora43-kde-x86-64-v4
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Download RPM shard artifacts - name: Install SRPM validation tools
uses: actions/download-artifact@v3
with:
path: downloaded-rpms
- name: Stage matching shard artifacts
run: | run: |
mkdir -p filtered-rpms dnf -y install git make python3 rpm-build ca-certificates curl
shopt -s nullglob
for artifact_dir in downloaded-rpms/rpm-${{ matrix.arch }}-shard-*; do
cp -a "$artifact_dir"/. filtered-rpms/
done
- name: Install repo assembly tools - name: Generate shard SRPMs
env:
PACKAGES_JSON: ${{ toJSON(matrix.packages) }}
SHARD_LABEL: ${{ matrix.shard_label }}
run: | run: |
if command -v createrepo_c >/dev/null 2>&1 python3 <<'PY'
then import json
echo "createrepo_c already present; skipping install." import os
exit 0 import subprocess
fi from pathlib import Path
mkdir -p /etc/dnf/dnf.conf.d workspace = Path(os.environ["GITHUB_WORKSPACE"])
printf '%s\n' 'keepcache=True' 'max_parallel_downloads=10' > /etc/dnf/dnf.conf.d/99-ci-cache.conf outdir = workspace / "artifacts" / f"srpm-shard-{os.environ['SHARD_LABEL']}"
dnf -y install createrepo_c outdir.mkdir(parents=True, exist_ok=True)
- name: Assemble DNF repository subprocess.run(
run: | [
python3 ci/assemble-dnf-repo.py \ "make",
--input-dir filtered-rpms \ "-f",
--output-dir repo/${{ matrix.arch }} \ ".copr/Makefile",
--repo-id ${{ matrix.repo_id }} \ "srpm",
--repo-name 'Fedora 43 KDE ${{ matrix.arch }}' f"outdir={outdir}",
"spec=packaging/copr-rpm-macros-x86-64-v3.spec",
],
check=True,
cwd=workspace,
)
- name: Upload DNF repository artifact for package_name in json.loads(os.environ["PACKAGES_JSON"]):
uses: actions/upload-artifact@v3 subprocess.run(
with: [
name: dnf-repo-${{ matrix.arch }} "make",
path: repo/${{ matrix.arch }}/ "-f",
if-no-files-found: error ".copr/Makefile",
"srpm",
f"outdir={outdir}",
f"spec={package_name}",
],
check=True,
cwd=workspace,
)
PY
+91 -158
View File
@@ -1,4 +1,4 @@
name: Build Fedora x86_64-v3 RPMs name: Validate Fedora x86_64-v3 Copr SRPMs
on: on:
workflow_dispatch: workflow_dispatch:
@@ -8,11 +8,29 @@ on:
required: false required: false
default: "" default: ""
type: string type: string
copr_project:
description: "Optional Copr project in owner/project form for syncing SCM package definitions."
required: false
default: ""
type: string
submit_to_copr:
description: "Sync package definitions to Copr after validation."
required: false
default: false
type: boolean
submit_package_builds:
description: "Queue package builds after the x86_64-v3 macro package build succeeds."
required: false
default: false
type: boolean
push: push:
paths: paths:
- 'packages.txt' - '.copr/Makefile'
- 'ci/assemble-dnf-repo.py'
- '.github/workflows/build-v3-rpms.yml' - '.github/workflows/build-v3-rpms.yml'
- 'ci/copr-distgit-make-srpm.py'
- 'ci/sync-copr-packages.py'
- 'packages.txt'
- 'packaging/copr-rpm-macros-x86-64-v3.spec'
permissions: permissions:
contents: read contents: read
@@ -40,7 +58,7 @@ jobs:
package_input = os.environ.get("PACKAGE_INPUT", "") package_input = os.environ.get("PACKAGE_INPUT", "")
if not package_input.strip() and not packages_file.exists(): if not package_input.strip() and not packages_file.exists():
print("::error::packages.txt not found") print("::error::packages.txt not found")
exit(1) raise SystemExit(1)
if package_input.strip(): if package_input.strip():
packages = [ packages = [
@@ -55,8 +73,7 @@ jobs:
if line.strip() and not line.startswith("#") if line.strip() and not line.startswith("#")
] ]
# Limit matrix size to avoid GitHub Actions limits max_matrix = 128
max_matrix = 256
matrix = [] matrix = []
if packages: if packages:
shard_size = max(1, -(-len(packages) // max_matrix)) shard_size = max(1, -(-len(packages) // max_matrix))
@@ -73,201 +90,117 @@ jobs:
for shard_index, shard in enumerate(shards) for shard_index, shard in enumerate(shards)
] ]
with open(os.environ["GITHUB_OUTPUT"], "a") as fh: with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as handle:
fh.write(f"matrix={json.dumps(matrix)}\n") handle.write(f"matrix={json.dumps(matrix)}\n")
fh.write(f"package_count={len(packages)}\n") handle.write(f"package_count={len(packages)}\n")
PY PY
build: validate-srpms:
needs: prepare needs: prepare
if: ${{ needs.prepare.outputs.package_count != '0' }} if: ${{ needs.prepare.outputs.package_count != '0' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/funkemunky/kde-x86_64-v4-fedora-rpm-builder:latest image: fedora:43
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: ${{ fromJSON(needs.prepare.outputs.matrix) }} include: ${{ fromJSON(needs.prepare.outputs.matrix) }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Restore DNF cache
uses: actions/cache@v4 - name: Install SRPM validation tools
with:
path: /var/cache/dnf
key: fedora43-dnf-${{ hashFiles('.github/workflows/build-v3-rpms.yml', 'ci/fedora-rpm-builder.Containerfile') }}
restore-keys: |
fedora43-dnf-
- name: Install build tools
run: | run: |
if command -v fedpkg >/dev/null 2>&1 \ dnf -y install git make python3 rpm-build ca-certificates curl
&& command -v rpmbuild >/dev/null 2>&1 \
&& command -v rpmdev-setuptree >/dev/null 2>&1 \
&& command -v git >/dev/null 2>&1 \
&& command -v python3 >/dev/null 2>&1 \
&& rpm -q dnf-plugins-core >/dev/null 2>&1
then
echo "Build tools already present; skipping install."
exit 0
fi
mkdir -p /etc/dnf/dnf.conf.d - name: Generate shard SRPMs
printf '%s\n' 'keepcache=True' 'max_parallel_downloads=10' > /etc/dnf/dnf.conf.d/99-ci-cache.conf
dnf -y install 'dnf-command(builddep)' fedpkg rpm-build rpmdevtools git python3
- name: Build shard packages
env: env:
SHARD_INDEX: ${{ matrix.shard }}
PACKAGES_JSON: ${{ toJSON(matrix.packages) }} PACKAGES_JSON: ${{ toJSON(matrix.packages) }}
FEDORA_BRANCH: f43 SHARD_LABEL: ${{ matrix.shard_label }}
TARGET_MARCH: x86-64-v3
run: | run: |
python3 <<'PY' python3 <<'PY'
import json import json
import os import os
import shutil
import subprocess import subprocess
import time
from pathlib import Path from pathlib import Path
workspace = Path(os.environ["GITHUB_WORKSPACE"]) workspace = Path(os.environ["GITHUB_WORKSPACE"])
shard_index = int(os.environ["SHARD_INDEX"]) outdir = workspace / "artifacts" / f"srpm-shard-{os.environ['SHARD_LABEL']}"
packages = json.loads(os.environ["PACKAGES_JSON"]) outdir.mkdir(parents=True, exist_ok=True)
fedora_branch = os.environ["FEDORA_BRANCH"]
target_march = os.environ["TARGET_MARCH"]
# Standard Fedora optflags with march override
# We'll use a simplified version of the override from the other workflow
optflags_override = (
f"-O2 -flto=auto -ffat-lto-objects -fexceptions -g "
"-grecord-gcc-switches -pipe -Wall -Werror=format-security "
"-Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 "
"-Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 "
"-fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 "
f"-m64 -march={target_march} -mtune=generic -fasynchronous-unwind-tables "
"-fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 "
"-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"
)
shard_root = workspace / "artifacts" / f"shard-{shard_index:03d}"
shard_root.mkdir(parents=True, exist_ok=True)
rpmbuild_root = workspace / ".rpmbuild"
rpmbuild_root.mkdir(parents=True, exist_ok=True)
def run_with_retry(command, *, cwd=None, cleanup_path=None, attempts=3):
for attempt in range(1, attempts + 1):
if cleanup_path is not None and cleanup_path.exists():
shutil.rmtree(cleanup_path)
try:
subprocess.run(command, cwd=cwd, check=True)
return
except subprocess.CalledProcessError:
if attempt == attempts:
raise
time.sleep(5 * attempt)
for package_name in packages:
package_dir = workspace / package_name
run_with_retry(
[
"git", "clone", "--depth", "1", "--branch", fedora_branch,
f"https://src.fedoraproject.org/rpms/{package_name}.git",
str(package_dir),
],
cleanup_path=package_dir,
)
run_with_retry(["fedpkg", "sources"], cwd=package_dir)
spec_file = next(package_dir.glob("*.spec"), None)
if not spec_file:
print(f"No spec file for {package_name}")
continue
subprocess.run(["dnf", "-y", "builddep", str(spec_file)], check=True)
topdir = rpmbuild_root / package_name
for subdir in ("BUILD", "BUILDROOT", "RPMS", "SOURCES", "SPECS", "SRPMS"):
(topdir / subdir).mkdir(parents=True, exist_ok=True)
subprocess.run( subprocess.run(
[ [
"rpmbuild", "-ba", str(spec_file), "make",
"--define", f"optflags {optflags_override}", "-f",
"--define", f"_topdir {topdir}", ".copr/Makefile",
"--define", f"_builddir {topdir / 'BUILD'}", "srpm",
"--define", f"_buildrootdir {topdir / 'BUILDROOT'}", f"outdir={outdir}",
"--define", f"_rpmdir {topdir / 'RPMS'}", "spec=packaging/copr-rpm-macros-x86-64-v3.spec",
"--define", f"_srcrpmdir {topdir / 'SRPMS'}",
"--define", f"_sourcedir {package_dir}",
"--define", f"_specdir {package_dir}",
], ],
check=True, check=True,
cwd=workspace,
) )
for rpm_path in (topdir / "RPMS").rglob("*.rpm"): for package_name in json.loads(os.environ["PACKAGES_JSON"]):
shutil.copy2(rpm_path, shard_root / rpm_path.name) subprocess.run(
for src_path in (topdir / "SRPMS").rglob("*.src.rpm"): [
shutil.copy2(src_path, shard_root / src_path.name) "make",
print(f"Built {package_name}") "-f",
".copr/Makefile",
"srpm",
f"outdir={outdir}",
f"spec={package_name}",
],
check=True,
cwd=workspace,
)
PY PY
- name: Upload RPM artifacts - name: Upload SRPM artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: rpm-shard-${{ matrix.shard_label }} name: srpm-shard-${{ matrix.shard_label }}
path: artifacts/shard-${{ matrix.shard_label }}/ path: artifacts/srpm-shard-${{ matrix.shard_label }}/
if-no-files-found: error if-no-files-found: error
assemble-repo: sync-copr:
needs: build needs:
- prepare
- validate-srpms
if: ${{ github.event_name == 'workflow_dispatch' && inputs.submit_to_copr && inputs.copr_project != '' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/funkemunky/kde-x86_64-v4-fedora-rpm-builder:latest image: fedora:43
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Download RPM shard artifacts - name: Install Copr sync tools
uses: actions/download-artifact@v4
with:
pattern: rpm-shard-*
path: downloaded-rpms
- name: Install repo assembly tools
run: | run: |
if command -v createrepo_c >/dev/null 2>&1 dnf -y install copr-cli git make python3 rpm-build ca-certificates curl
then
echo "createrepo_c already present; skipping install."
exit 0
fi
mkdir -p /etc/dnf/dnf.conf.d - name: Configure copr-cli
printf '%s\n' 'keepcache=True' 'max_parallel_downloads=10' > /etc/dnf/dnf.conf.d/99-ci-cache.conf
dnf -y install createrepo_c
- name: Assemble DNF repository
run: |
python3 ci/assemble-dnf-repo.py \
--input-dir downloaded-rpms \
--output-dir repo/fedora43-x86-64-v3 \
--repo-id fedora43-kde-x86-64-v3 \
--repo-name 'Fedora 43 KDE x86_64-v3'
- name: Upload RPMs to Nexus YUM repository
env: env:
NEXUS_BASE_URL: https://nexus.funkemunky.cc COPR_CONFIG: ${{ secrets.COPR_CONFIG }}
NEXUS_REPOSITORY: dnf-repo-x86-64-v3
NEXUS_USER: ${{ secrets.nexusUser }}
NEXUS_PASSWORD: ${{ secrets.nexusPassword }}
run: | run: |
test -n "${NEXUS_USER}" test -n "${COPR_CONFIG}"
test -n "${NEXUS_PASSWORD}" mkdir -p ~/.config
PACKAGE_ROOT="repo/fedora43-x86-64-v3/packages" printf '%s\n' "${COPR_CONFIG}" > ~/.config/copr
find "${PACKAGE_ROOT}" -type f -name '*.rpm' | while read -r FILEPATH; do chmod 0600 ~/.config/copr
FILENAME="$(basename "${FILEPATH}")"
curl --fail --show-error --silent \ - name: Sync Copr SCM package definitions
--user "${NEXUS_USER}:${NEXUS_PASSWORD}" \ env:
-X POST "${NEXUS_BASE_URL}/service/rest/v1/components?repository=${NEXUS_REPOSITORY}" \ COPR_PROJECT: ${{ inputs.copr_project }}
-H "Content-Type: multipart/form-data" \ PACKAGE_INPUT: ${{ inputs.package_input }}
-F "yum.asset=@${FILEPATH};type=application/x-rpm" \ SUBMIT_PACKAGE_BUILDS: ${{ inputs.submit_package_builds }}
-F "yum.asset.filename=${FILENAME}" run: |
done set -euo pipefail
ARGS=(
--project "${COPR_PROJECT}"
--clone-url "https://github.com/${GITHUB_REPOSITORY}.git"
--commit "${GITHUB_SHA}"
--package-input "${PACKAGE_INPUT}"
--submit-macro-build
)
if [ "${SUBMIT_PACKAGE_BUILDS}" = "true" ]; then
ARGS+=(--submit-package-builds --nowait-package-builds)
fi
python3 ci/sync-copr-packages.py "${ARGS[@]}"
-305
View File
@@ -1,305 +0,0 @@
.rpmbuild/
*.src.rpm
__pycache__/
.dnf/
scripts/__pycache__/
# Created by https://www.toptal.com/developers/gitignore/api/windows,macos,linux,maven,java,intellij,eclipse,netbeans
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,macos,linux,maven,java,intellij,eclipse,netbeans
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
*.iml
.idea/
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
.apt_generated_test/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
# Uncomment this line if you wish to ignore the project description file.
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
### Eclipse Patch ###
# Spring Boot Tooling
.sts4-cache/
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/
# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/
# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$
# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
!gradle/wrapper/gradle-wrapper.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
.flattened-pom.xml
### NetBeans ###
**/nbproject/private/
**/nbproject/Makefile-*.mk
**/nbproject/Package-*.bash
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
.dnf/*
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/windows,macos,linux,maven,java,intellij,eclipse,netbeans
/.gradle/
+59 -17
View File
@@ -1,22 +1,64 @@
# Fedora 43 KDE Actions RPM Builder # Fedora 43 KDE Copr x86_64-v3 Builder
This repository provides CI workflows for both GitHub Actions and Gitea Actions to rebuild Fedora 43 This repository now targets Copr rather than doing local `rpmbuild -ba` work inside CI.
KDE packages from Fedora dist-git with `x86-64-v3` and `x86-64-v4` code generation and `-O3` It uses Copr's SCM `make_srpm` flow to generate SRPMs from Fedora dist-git content and installs
optimization. a dedicated buildroot macro package so Copr's Fedora 43 `x86_64` builders compile with an
`x86-64-v3` ISA baseline.
## Workflows ## What changed
- **GitHub Actions**: `.github/workflows/build-v3-rpms.yml` - `.copr/Makefile` is the Copr entrypoint used by the SCM `make_srpm` method.
- **Gitea Actions**: `.gitea/workflows/build-v3-rpms.yml` - `ci/copr-distgit-make-srpm.py` clones Fedora dist-git, downloads lookaside sources, and builds SRPMs.
- `packaging/copr-rpm-macros-x86-64-v3.spec` produces the buildroot macro package that changes Fedora's
`%__cflags_arch_x86_64_level` to `-v3` while keeping the rest of `redhat-rpm-config` intact.
- `ci/sync-copr-packages.py` registers or updates Copr SCM package definitions and can queue builds.
Each build workflow now finishes with a repository assembly job that collects the shard artifacts, ## Why the macro package exists
generates `repodata/` with `createrepo_c`, and uploads a ready-to-serve DNF repository artifact.
## Repository artifacts Copr does not expose a generic `rpmbuild --define` interface for package builds. The supported way to
- **GitHub Actions** uploads `dnf-repo-x86-64-v3` change buildroot macros is to build a small RPM that drops a file into `%{rpmmacrodir}` and then add
- **Gitea Actions** uploads `dnf-repo-x86-64-v3` and `dnf-repo-x86-64-v4` that package to the Copr chroot's additional packages list. This repo does that with
`copr-rpm-macros-x86-64-v3`.
Each repository artifact contains: With that package installed in the buildroot, packages that honor Fedora's standard `%optflags` /
- `packages/` with the built binary RPMs `%set_build_flags` path will compile with `-march=x86-64-v3` on Copr builders.
- `repodata/` generated for DNF
- a `.repo` template with a placeholder `baseurl` ## Local validation
- `README.txt` with Fedora 43 install instructions
Generate the macro SRPM:
```bash
make -f .copr/Makefile srpm outdir=dist-srpms spec=packaging/copr-rpm-macros-x86-64-v3.spec
```
Generate a Fedora dist-git package SRPM the same way Copr will:
```bash
make -f .copr/Makefile srpm outdir=dist-srpms spec=konsole
```
## Copr setup
1. Create or reuse a Copr project with the `fedora-43-x86_64` chroot enabled.
2. Sync this repository's SCM package definitions into that project:
```bash
python3 ci/sync-copr-packages.py \
--project yourname/kde-x86-64-v3 \
--clone-url https://github.com/<owner>/<repo>.git \
--commit <git-ref> \
--submit-macro-build
```
3. After the macro package build succeeds, queue the package builds:
```bash
python3 ci/sync-copr-packages.py \
--project yourname/kde-x86-64-v3 \
--clone-url https://github.com/<owner>/<repo>.git \
--commit <git-ref> \
--submit-package-builds \
--nowait-package-builds
```
The sync step also sets the Copr chroot's additional packages list to `copr-rpm-macros-x86-64-v3`,
which is the piece that makes the `x86-64-v3` compile target apply on Copr builders.
+244
View File
@@ -0,0 +1,244 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import hashlib
import re
import shutil
import subprocess
import tempfile
import time
import urllib.parse
import urllib.request
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
SOURCE_LINE_PATTERN = re.compile(
r"^(?P<algo>[A-Za-z0-9_+-]+)\s+\((?P<filename>.+)\)\s+=\s+(?P<checksum>[0-9A-Fa-f]+)$"
)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=(
"Create an SRPM either from a local spec in this repository or by "
"cloning a Fedora dist-git package and downloading its lookaside sources."
)
)
parser.add_argument("--spec-ref", required=True, help="Local .spec path or Fedora dist-git package name")
parser.add_argument("--outdir", required=True, help="Directory where the generated SRPM should be written")
parser.add_argument("--branch", default="f43", help="Fedora dist-git branch to clone when spec-ref is a package")
parser.add_argument("--dist", default=".fc43", help="RPM dist suffix to define while generating the SRPM")
parser.add_argument("--namespace", default="rpms", help="Fedora dist-git namespace")
parser.add_argument(
"--lookaside-baseurl",
default="https://src.fedoraproject.org/repo/pkgs",
help="Base URL for the Fedora lookaside cache",
)
parser.add_argument("--retry-count", type=int, default=3, help="Number of retries for network operations")
return parser.parse_args()
def run(command: list[str], *, cwd: Path | None = None) -> None:
subprocess.run(command, cwd=cwd, check=True)
def ensure_within_repo(path: Path) -> Path | None:
candidate = (REPO_ROOT / path).resolve()
try:
candidate.relative_to(REPO_ROOT)
except ValueError:
return None
if candidate.is_file() and candidate.suffix == ".spec":
return candidate
return None
def hash_file(path: Path, algorithm: str) -> str:
digest = hashlib.new(algorithm.lower())
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def download_file(url: str, destination: Path, *, algorithm: str, checksum: str, attempts: int) -> None:
destination.parent.mkdir(parents=True, exist_ok=True)
for attempt in range(1, attempts + 1):
if destination.exists() and hash_file(destination, algorithm) == checksum.lower():
return
try:
with urllib.request.urlopen(url) as response, destination.open("wb") as handle:
shutil.copyfileobj(response, handle)
except Exception:
if destination.exists():
destination.unlink()
if attempt == attempts:
raise
time.sleep(attempt * 3)
continue
if hash_file(destination, algorithm) == checksum.lower():
return
destination.unlink(missing_ok=True)
if attempt == attempts:
raise RuntimeError(f"checksum mismatch for {destination.name} from {url}")
time.sleep(attempt * 3)
def build_srpm(spec_path: Path, *, source_dir: Path, outdir: Path, dist: str) -> Path:
outdir.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory(prefix="copr-srpm-topdir-") as topdir_name:
topdir = Path(topdir_name)
command = [
"rpmbuild",
"-bs",
str(spec_path),
"--define",
f"_topdir {topdir}",
"--define",
f"_builddir {topdir / 'BUILD'}",
"--define",
f"_buildrootdir {topdir / 'BUILDROOT'}",
"--define",
f"_rpmdir {topdir / 'RPMS'}",
"--define",
f"_srcrpmdir {outdir}",
"--define",
f"_sourcedir {source_dir}",
"--define",
f"_specdir {spec_path.parent}",
]
if dist:
command.extend(["--define", f"dist {dist}"])
run(command, cwd=source_dir)
srpms = sorted(outdir.glob("*.src.rpm"), key=lambda path: path.stat().st_mtime, reverse=True)
if not srpms:
raise RuntimeError(f"rpmbuild did not produce an SRPM in {outdir}")
return srpms[0]
def parse_sources_file(path: Path) -> list[tuple[str, str, str]]:
entries: list[tuple[str, str, str]] = []
if not path.exists():
return entries
for raw_line in path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line:
continue
match = SOURCE_LINE_PATTERN.match(line)
if not match:
raise RuntimeError(f"unsupported lookaside source format: {line}")
entries.append(
(
match.group("algo").lower(),
match.group("filename"),
match.group("checksum").lower(),
)
)
return entries
def download_lookaside_sources(
package_name: str,
source_dir: Path,
*,
namespace: str,
lookaside_baseurl: str,
attempts: int,
) -> None:
for algorithm, filename, checksum in parse_sources_file(source_dir / "sources"):
encoded_filename = urllib.parse.quote(filename)
url = (
f"{lookaside_baseurl}/{namespace}/{package_name}/"
f"{encoded_filename}/{algorithm}/{checksum}/{encoded_filename}"
)
download_file(
url,
source_dir / filename,
algorithm=algorithm,
checksum=checksum,
attempts=attempts,
)
def build_from_distgit(
package_name: str,
*,
branch: str,
dist: str,
namespace: str,
lookaside_baseurl: str,
attempts: int,
outdir: Path,
) -> Path:
clone_url = f"https://src.fedoraproject.org/{namespace}/{package_name}.git"
with tempfile.TemporaryDirectory(prefix=f"{package_name}-distgit-") as tempdir_name:
tempdir = Path(tempdir_name)
package_dir = tempdir / package_name
for attempt in range(1, attempts + 1):
try:
if package_dir.exists():
shutil.rmtree(package_dir)
run(
[
"git",
"clone",
"--depth",
"1",
"--branch",
branch,
clone_url,
str(package_dir),
]
)
break
except subprocess.CalledProcessError:
if attempt == attempts:
raise
time.sleep(attempt * 3)
spec_files = sorted(package_dir.glob("*.spec"))
if not spec_files:
raise RuntimeError(f"no spec file found in {clone_url} branch {branch}")
spec_path = spec_files[0]
download_lookaside_sources(
package_name,
package_dir,
namespace=namespace,
lookaside_baseurl=lookaside_baseurl,
attempts=attempts,
)
return build_srpm(spec_path, source_dir=package_dir, outdir=outdir, dist=dist)
def main() -> int:
args = parse_args()
outdir = Path(args.outdir).resolve()
local_spec = ensure_within_repo(Path(args.spec_ref))
if local_spec is not None:
srpm = build_srpm(local_spec, source_dir=local_spec.parent, outdir=outdir, dist=args.dist)
print(f"built local SRPM {srpm.name}")
return 0
srpm = build_from_distgit(
args.spec_ref,
branch=args.branch,
dist=args.dist,
namespace=args.namespace,
lookaside_baseurl=args.lookaside_baseurl.rstrip("/"),
attempts=args.retry_count,
outdir=outdir,
)
print(f"built dist-git SRPM {srpm.name}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+4 -6
View File
@@ -6,13 +6,11 @@ RUN mkdir -p /etc/dnf/dnf.conf.d \
RUN dnf -y upgrade --refresh \ RUN dnf -y upgrade --refresh \
&& dnf -y install \ && dnf -y install \
'dnf-command(builddep)' \
fedpkg \
git \ git \
nodejs \ make \
python3 \ python3 \
rpm-build \ rpm-build \
rpmdevtools \ copr-cli \
@kde-desktop \ ca-certificates \
@development-tools \ curl \
&& dnf clean all && dnf clean all
+192
View File
@@ -0,0 +1,192 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import re
import subprocess
from pathlib import Path
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=(
"Register or update Copr SCM package definitions that use this "
"repository's .copr/Makefile and optionally submit builds."
)
)
parser.add_argument("--project", required=True, help="Copr project, e.g. user/project")
parser.add_argument("--clone-url", required=True, help="Git clone URL Copr should use for this repository")
parser.add_argument("--commit", default="HEAD", help="Git ref Copr should build from")
parser.add_argument("--chroot", default="fedora-43-x86_64", help="Copr chroot to configure and build for")
parser.add_argument("--packages-file", default="packages.txt", help="Package list to register")
parser.add_argument(
"--package-input",
default="",
help="Optional comma, space, or newline separated package list. Overrides --packages-file when set.",
)
parser.add_argument(
"--macro-package-name",
default="copr-rpm-macros-x86-64-v3",
help="Name of the buildroot macro package in Copr",
)
parser.add_argument(
"--macro-package-spec",
default="packaging/copr-rpm-macros-x86-64-v3.spec",
help="Local spec reference for the buildroot macro package",
)
parser.add_argument("--webhook-rebuild", choices=("on", "off"), default="off")
parser.add_argument("--max-builds", type=int, default=0)
parser.add_argument("--timeout", type=int, default=18000)
parser.add_argument("--skip-chroot-update", action="store_true")
parser.add_argument("--submit-macro-build", action="store_true")
parser.add_argument("--submit-package-builds", action="store_true")
parser.add_argument("--nowait-package-builds", action="store_true")
return parser.parse_args()
def run(command: list[str], *, quiet: bool = False) -> subprocess.CompletedProcess[str]:
kwargs: dict[str, object] = {
"check": True,
"text": True,
}
if quiet:
kwargs["stdout"] = subprocess.DEVNULL
kwargs["stderr"] = subprocess.DEVNULL
return subprocess.run(command, **kwargs)
def package_exists(project: str, package_name: str) -> bool:
result = subprocess.run(
["copr", "get-package", project, "--name", package_name],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
text=True,
)
return result.returncode == 0
def load_packages(packages_file: Path, package_input: str) -> list[str]:
if package_input.strip():
packages = [entry for entry in re.split(r"[\s,]+", package_input.strip()) if entry]
else:
packages = [
line.strip()
for line in packages_file.read_text(encoding="utf-8").splitlines()
if line.strip() and not line.lstrip().startswith("#")
]
deduped: list[str] = []
seen: set[str] = set()
for package in packages:
if package not in seen:
deduped.append(package)
seen.add(package)
return deduped
def upsert_scm_package(
*,
project: str,
package_name: str,
spec_ref: str,
clone_url: str,
commit: str,
webhook_rebuild: str,
max_builds: int,
timeout: int,
) -> None:
action = "edit-package-scm" if package_exists(project, package_name) else "add-package-scm"
command = [
"copr",
action,
project,
"--name",
package_name,
"--clone-url",
clone_url,
"--commit",
commit,
"--method",
"make_srpm",
"--spec",
spec_ref,
"--webhook-rebuild",
webhook_rebuild,
"--max-builds",
str(max_builds),
"--timeout",
str(timeout),
]
run(command)
def submit_build(project: str, package_name: str, chroot: str, *, nowait: bool) -> None:
command = [
"copr",
"build-package",
project,
"--name",
package_name,
"--chroot",
chroot,
]
if nowait:
command.append("--nowait")
run(command)
def main() -> int:
args = parse_args()
packages = load_packages(Path(args.packages_file), args.package_input)
upsert_scm_package(
project=args.project,
package_name=args.macro_package_name,
spec_ref=args.macro_package_spec,
clone_url=args.clone_url,
commit=args.commit,
webhook_rebuild=args.webhook_rebuild,
max_builds=args.max_builds,
timeout=args.timeout,
)
for package_name in packages:
upsert_scm_package(
project=args.project,
package_name=package_name,
spec_ref=package_name,
clone_url=args.clone_url,
commit=args.commit,
webhook_rebuild=args.webhook_rebuild,
max_builds=args.max_builds,
timeout=args.timeout,
)
if not args.skip_chroot_update:
run(
[
"copr",
"edit-chroot",
f"{args.project}/{args.chroot}",
"--packages",
args.macro_package_name,
]
)
if args.submit_macro_build:
submit_build(args.project, args.macro_package_name, args.chroot, nowait=False)
if args.submit_package_builds:
for package_name in packages:
submit_build(
args.project,
package_name,
args.chroot,
nowait=args.nowait_package_builds,
)
return 0
if __name__ == "__main__":
raise SystemExit(main())
+29
View File
@@ -0,0 +1,29 @@
Name: copr-rpm-macros-x86-64-v3
Version: 1
Release: 1%{?dist}
Summary: Copr buildroot macros for x86_64-v3 rebuilds
License: MIT
BuildArch: noarch
%description
This package installs a small RPM macro override for Copr buildroots.
It keeps Fedora's standard compiler and linker flag stack intact while
raising the x86_64 ISA baseline from x86-64 to x86-64-v3.
%prep
%build
%install
mkdir -p %{buildroot}%{rpmmacrodir}
cat > %{buildroot}%{rpmmacrodir}/macros.copr-x86-64-v3 <<'EOF'
%__cflags_arch_x86_64_level -v3
EOF
%files
%{rpmmacrodir}/macros.copr-x86-64-v3
%changelog
* Mon Apr 27 2026 OpenAI Codex <codex@openai.com> - 1-1
- Install a Copr buildroot macro override for x86_64-v3