install: Build Dangerzone RPMs using our SPEC file

Replace the deprecated `bdist_rpm` method of creating RPMs for
Dangerzone. Instead, update our `install/linux/build-rpm.py` script, to
build Dangerzone RPMs using our SPEC file under
`install/linux/dangerzone.spec`. The script now essentially creates a
source distribution (sdist) using `poetry build`, and then uses
`rpmbuild` to create binary and source RPMs.

Fixes #298
This commit is contained in:
Alex Pyrgiotis 2023-08-31 13:34:04 +03:00
parent 6cc2a953ff
commit 01d63e4eda
No known key found for this signature in database
GPG key ID: B6C15EBA0357C9AA
3 changed files with 117 additions and 46 deletions

View file

@ -468,7 +468,7 @@ class Env:
version = dz_version()
if self.distro == "fedora":
install_deps = DOCKERFILE_BUILD_FEDORA_DEPS
package = f"dangerzone-{version}-1.noarch.rpm"
package = f"dangerzone-{version}-1.fc{self.version}.x86_64.rpm"
package_src = git_root() / "dist" / package
package_dst = build_dir / package
install_cmd = "dnf install -y"

View file

@ -3,20 +3,105 @@
import argparse
import inspect
import os
import pathlib
import shutil
import subprocess
import sys
import tempfile
root = os.path.dirname(
os.path.dirname(
os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
)
)
root = pathlib.Path(__file__).parent.parent.parent
with open(os.path.join(root, "share", "version.txt")) as f:
version = f.read().strip()
def remove_contents(d):
"""Remove all the contents of a directory."""
for p in d.iterdir():
if p.is_file() or p.is_symlink():
p.unlink()
else:
shutil.rmtree(p)
def build(qubes=False):
"""Build an RPM package in a temporary directory.
The build process is the following:
1. Clean up any stale data from previous runs under ./dist. Note that this directory
is used by `poetry build` and `rpmbuild`.
2. Create the necessary RPM project structure under ./install/linux/rpm-build, and
use symlinks to point to ./dist, so that we don't need to move files explicitly.
3. Create a Python source distribution using `poetry build`. If we are building a
Qubes package and there is a container image under `share/`, stash it temporarily
under a different directory.
4. Build both binary and source RPMs using rpmbuild. Optionally, pass to the SPEC
`_qubes` flag, that denotes we want to build a package for Qubes.
"""
build_dir = root / "install" / "linux" / "rpm-build"
dist_path = root / "dist"
specfile_name = "dangerzone.spec"
specfile_path = root / "install" / "linux" / specfile_name
sdist_name = f"dangerzone-{version}.tar.gz"
print("* Deleting old dist")
if os.path.exists(dist_path):
remove_contents(dist_path)
else:
dist_path.mkdir()
print(f"* Creating RPM project structure under {build_dir}")
for d in ["BUILD", "BUILDROOT", "RPMS", "SOURCES", "SPECS"]:
subdir = build_dir / d
subdir.mkdir(exist_ok=True)
remove_contents(subdir)
shutil.copy2(specfile_path, build_dir / "SPECS")
rpm_dir = build_dir / "RPMS" / "x86_64"
srpm_dir = build_dir / "SRPMS"
if srpm_dir.exists():
os.unlink(srpm_dir)
os.symlink(dist_path, rpm_dir)
os.symlink(dist_path, srpm_dir)
print("* Creating a Python sdist")
container_tar_gz = root / "share" / "container.tar.gz"
container_tar_gz_bak = root / "container.tar.gz.bak"
stash_container = qubes and container_tar_gz.exists()
if stash_container:
container_tar_gz.rename(container_tar_gz_bak)
try:
subprocess.run(["poetry", "build", "-f", "sdist"], cwd=root, check=True)
os.rename(dist_path / sdist_name, build_dir / "SOURCES" / sdist_name)
finally:
if stash_container:
container_tar_gz_bak.rename(container_tar_gz)
print("* Building RPM package")
cmd = [
"rpmbuild",
"-v",
"--define",
f"_topdir {build_dir}",
"-ba",
"--nodebuginfo",
f"{build_dir}/SPECS/dangerzone.spec",
]
# In case of qubes, set the `%{_qubes}` SPEC variable to 1. See the dangerzone.spec
# file for more details on how that's used.
if qubes:
cmd += [
"--define",
f"_qubes 1",
]
subprocess.run(cmd, check=True)
print("")
print("The following files have been created:")
print("\n".join([str(p) for p in dist_path.iterdir()]))
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
@ -24,45 +109,7 @@ def main():
)
args = parser.parse_args()
build_path = os.path.join(root, "build")
dist_path = os.path.join(root, "dist")
print("* Deleting old build and dist")
if os.path.exists(build_path):
shutil.rmtree(build_path)
if os.path.exists(dist_path):
shutil.rmtree(dist_path)
if args.qubes:
print("> Building for a Qubes system")
os.environ["QUBES_TARGET"] = "1"
# Server and Client package requirements are bundled together since
# we assume the server and client qubes are installed on the same
# template
platform_dependant_packages = ",".join(
[
# Server package requirements
"python3-magic",
"libreoffice",
# Client package requirements
"tesseract", # FIXME add other languages
]
)
else:
platform_dependant_packages = "podman"
print("* Building RPM package")
subprocess.run(
f"python3 setup.py bdist_rpm --requires='{platform_dependant_packages},python3-pyside2,python3-appdirs,python3-click,python3-pyxdg,python3-colorama,python3-requests,python3-markdown,python3-packaging'",
shell=True,
cwd=root,
check=True,
)
print("")
print("* To install run:")
print("sudo dnf install dist/dangerzone-{}-1.noarch.rpm".format(version))
build(args.qubes)
if __name__ == "__main__":

View file

@ -77,6 +77,7 @@ convert the documents within a secure sandbox.
%prep
%autosetup -p1 -n dangerzone-%{version}
# XXX: Replace the PySide6 dependency in the pyproject.toml file with PySide2,
# since the former does not exist in Fedora. Once we can completely migrate to
# Qt6, we should remove this. For more details, see:
@ -84,6 +85,29 @@ convert the documents within a secure sandbox.
# https://github.com/freedomofpress/dangerzone/issues/211
sed -i 's/^PySide6.*$/PySide2 = "*"/' pyproject.toml
# XXX: Replace all [tool.poetry.group.*] references in pyproject.toml with
# [tool.poetry.dev-dependencies], **ONLY** for Fedora 37.
#
# Fedora 37 ships python3-poetry-core v1.0.8. This version does not understand
# the dependency groups that were added in v1.2.0 [1]. Therefore, we need to
# dumb down the pyproject.toml file a bit, so that poetry-core can parse it.
# Note that the dev dependencies are not consulted for the creation of the RPM
# file, so doing so should be safe.
#
# The following sed invocations turn the various [tool.poetry.group.*] sections
# into one large [tool.poetry.dev-dependencies] section. Then, they patch the
# minimum required poetry-core version in pyproject.toml, to one that can be
# satisfied from the Fedora 37 repos.
#
# TODO: Remove this workaround once Fedora 37 (fedora-37) is EOL.
#
# [1]: https://python-poetry.org/docs/managing-dependencies/#dependency-groups
%if 0%{?fedora} == 37
sed -i 's/^\[tool.poetry.group.package.*$/[tool.poetry.dev-dependencies]/' pyproject.toml
sed -i '/^\[tool.poetry.group.*$/d' pyproject.toml
sed -i 's/poetry-core>=1.2.0/poetry-core>=1.0.0/' pyproject.toml
%endif
%generate_buildrequires
%pyproject_buildrequires -R