This repository contains the source files and scripts required to build an RPM (Red Hat Package Manager) package for Hyphanet (formerly Freenet).
The build process is fully automated using Gradle, ensuring reproducibility and security through checksum verification of all external assets.
You need a Linux system (Fedora, RHEL, CentOS, AlmaLinux, RockyLinux, etc.) with the following installed:
- Java 21 (Max required for Gradle 8.14+)
- rpm-build (Required to build the RPM)
# Fedora / RHEL / CentOS
sudo dnf install java-21-openjdk rpm-build
# Verify Java version
java -versionThe entire build process (downloading dependencies, verifying signatures, preparing sources, and building the RPM) is handled by a single command.
-
Clone the repository:
git clone https://github.com/hyphanet/rpm-packaging.git cd rpm-packaging -
Build the RPM:
./gradlew clean buildRpm
Note: The first run will download Gradle and all necessary dependencies.
-
Locate the RPM: Once the build is successful, the RPM file will be available in:
RPMS/x86_64/hyphanet-*.rpm
To install the generated package:
sudo dnf install ./RPMS/x86_64/hyphanet-*.rpmHyphanet runs as a systemd service.
# Start Hyphanet
sudo systemctl start hyphanet
# Stop Hyphanet
sudo systemctl stop hyphanet
# Check Status
sudo systemctl status hyphanet
# Enable at boot
sudo systemctl enable hyphanetAfter installation, you will find Hyphanet in your application menu.
- Hyphanet: Opens the web interface (http://127.0.0.1:8888)
- Start Hyphanet: Starts the background service (requires authentication)
- Stop Hyphanet: Stops the background service (requires authentication)
build.gradle.kts: Main build script defining dependencies and tasks.prepare_sources.sh: Script called by Gradle to assemble the source tarball.hyphanet.spec: The RPM specification file.inputs/wrapper.conf,freenet.ini: Default configuration files.inputs/hyphanet-service: Control script for the service.inputs/*.desktop: Desktop entry files for the application menu.inputs/org.hyphanet.service.policy: PolicyKit configuration for GUI management.
The CI workflow, defined in .github/workflows/ci.yml, automates the build and signing of the RPM package whenever changes are pushed to the master branch.
- Setup: Checks out the code, sets up Java and Gradle, and installs
rpmandgnupg2. - Build: Runs
./gradlew buildRpmto generate the RPM. - GPG Signing:
- If run on the
masterbranch (or manually triggered), the workflow attempts to sign the RPM. - It first tries to import a GPG private key from the
GPG_PRIVATE_KEYrepository secret. - If the secret is missing or the key is invalid, it generates a temporary, ephemeral GPG key for signing.
- If run on the
- Sign RPM: Uses
rpmsignto sign the generated package. - Upload Artifacts: Uploads the signed RPM and the public GPG key as build artifacts.
-
GPG Non-Interactive Mode:
- The workflow configures GPG to run in a non-interactive (loopback) mode. This is necessary because a CI runner cannot prompt for a passphrase.
- The passphrase is provided via a pipe to the
rpmsigncommand.
-
Ephemeral GPG Key:
- The ability to auto-generate a GPG key ensures that the build can succeed even without access to repository secrets (e.g., in a fork). This allows for testing the complete build and sign process in any environment.
-
Custom RPM Sign Command:
- A custom
~/.rpmmacrosfile is created to override the defaultrpmsigncommand. This ensures that GPG is called with the correct parameters for a non-interactive environment (--pinentry-mode loopback,--passphrase-fd 0).
- A custom
When a new version of Hyphanet is released, follow this procedure to update the RPM package:
- Open
build.gradle.kts. - Update Version Variables:
- Change
appVersionto the new version number (e.g.,"0.7.6"). - Change
buildIdto the new build tag (e.g.,"01507").
- Change
- Update Checksums:
- The URLs for
freenet.jar,freenet.jar.sig, andfreenet-ext.jarare automatically constructed using thebuildId. - However, you must update the
sha256hash for these artifacts in theartifactslist. - Tip: You can temporarily set the hash to an empty string
""or a dummy value, run the build, and copy the calculated hash from the error message or warning in the console output.
- The URLs for
- Verify Dependencies:
- If other dependencies (like
wrapper,bcprov, etc.) have changed, update their URLs and hashes as well.
- If other dependencies (like
- Update SPEC Defaults:
- Open
hyphanet.spec. - Update the default values to match the new version. This ensures the spec file is valid even if used without Gradle.
- Look for:
%{!?version: %define version 0.7.5} %{!?build_id: %define build_id 1506}
- Open
- Run the Build:
./gradlew clean buildRpm
- Test: Install the generated RPM and verify that Hyphanet starts correctly.
To ensure consistency between the Gradle build script and the RPM specification, we use a specific mechanism to pass version variables:
- Definition in Gradle: The
appVersionandbuildIdvariables are defined at the top ofbuild.gradle.kts. - Passing to rpmbuild: When the
buildRpmtask executesrpmbuild, it passes these values using the--defineflag:commandLine( "/usr/bin/rpmbuild", "-ba", // ... "--define", "version ${appVersion}", "--define", "build_id ${buildId}", // ... specFile.absolutePath ) - Usage in SPEC file: The
hyphanet.specfile uses these definitions to set the package version and release, ensuring the RPM metadata always matches the build configuration.
On some systems or configurations, rpmbuild may output the generated RPMs into a directory named RPMS.x86_64 (with a dot) instead of the standard RPMS/x86_64 (nested directory).
To handle this inconsistency:
- The
buildRpmtask checks for the existence ofRPMS.x86_64after the build completes. - If found, it moves the contents to the standard
RPMS/x86_64directory. - It then deletes the non-standard
RPMS.x86_64directory.
This ensures that the final artifact is always located in RPMS/x86_64/, regardless of the underlying rpmbuild behavior.
The hyphanet.spec file starts with several %global definitions. These are important for ensuring a clean and consistent build, especially in automated environments:
-
Debug Packages:
%global debug_package %{nil} %global _debugsource_template %{nil} %undefine _debugsource_packages %undefine _debuginfo_packages
This block disables the automatic generation of
debuginfoanddebugsourcepackages. Since this project packages pre-compiled Java binaries, these debug packages are unnecessary and can cause issues on certain build systems (like Fedora/RHEL). -
Post-install Scripts:
%global __os_install_post %{nil}
This line disables the automatic post-install scripts that
rpmbuildmight run. This gives us full control over the installation process in the%postsection of the spec file.