Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/it/test21-modifyversion/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>de.dentrassi.maven.rpm.test</groupId>
<artifactId>test21-modifyversion</artifactId>
<version>1.0.1.redhat-00001</version>
<packaging>jar</packaging>

<name>Test Package #21</name>
<description>Test modify version generation</description>

<url>https://dentrassi.de</url>

<organization>
<name>Jens Reimann</name>
<url>http://dentrassi.de</url>
</organization>

<licenses>
<license>
<name>Eclipse Public License - v 1.0</name>
<distribution>repo</distribution>
<url>https://www.eclipse.org/legal/epl-v10.html</url>
</license>
</licenses>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<skipSigning>true</skipSigning>
</properties>

<build>

<plugins>
<plugin>
<groupId>de.dentrassi.maven</groupId>
<artifactId>rpm</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<goals>
<goal>rpm</goal>
</goals>
<configuration>
<attach>false</attach>
<group>Application/Misc</group>

<modifyVersion>true</modifyVersion>
<versionReplacements>
<versionReplacement>
<search>-</search>
<replace>_</replace>
</versionReplacement>
</versionReplacements>

<signature>
<keyId>${keyId}</keyId>
<keyringFile>${user.home}/.gnupg/secring.gpg</keyringFile>
<passphrase>${passphrase}</passphrase>
<hashAlgorithm>SHA1</hashAlgorithm>
<skip>${skipSigning}</skip>
</signature>

</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>sign</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<skipSigning>false</skipSigning>
</properties>
</profile>
</profiles>

</project>
8 changes: 8 additions & 0 deletions src/it/test21-modifyversion/verify.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

def log () {
Process proc = ['rpm', '-q', '--queryformat', '[%{VERSION} %{SOURCERPM}]', basedir.toString() + "/target/test21-modifyversion-1.0.1.redhat-00001-1.noarch.rpm"].execute();
return proc.in.getText().trim();
}

String text = log()
return text.contains("1.0.1.redhat_00001 test21-modifyversion-1.0.1.redhat_00001-1.src.rpm")
47 changes: 38 additions & 9 deletions src/main/java/de/dentrassi/rpm/builder/RpmMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ public void setGenerateDefaultSourcePackage(final boolean generateDefaultSourceP
/**
* Whether the plugin should try to evaluate to hostname
* <p>
* If set to {@code false}, then he build hostname {@code localhost} will be
* If set to {@code false}, then the build hostname {@code localhost} will be
* used instead of the actual hostname
* </p>
*/
Expand Down Expand Up @@ -793,6 +793,25 @@ public void setSignatureConfiguration(final String signatureConfiguration) {
@Parameter(defaultValue = "SHA-256", property = "rpm.fileDigestAlgorithm")
String fileDigestAlgorithm;


/**
* Whether the plugin should modify internal RPM version for compliance.
* <p>
* If set to {@code true}, then any replacements specified in the {@code versionReplacements}
* property will be applied.
*/
@Parameter(property = "rpm.modifyVersion", defaultValue = "false")
boolean modifyVersion = false;

/**
* A list of potential version substitutions to perform on the RPM internal version. This will
* not affect the filename; just the version inside the generated RPM. This allows a user
* to customise the version if the Maven version does not match RPM requirements e.g. it contains
* a '-' (which would need to be replaced by an '_'). The 'search' string is a regex.
*/
@Parameter(property = "rpm.versionReplacements")
List<VersionSubstitution> versionReplacements = new ArrayList<>();

private Instant outputTimestampInstant;

@Component(role = SignatureConfiguration.class)
Expand Down Expand Up @@ -845,7 +864,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
this.logger.debug("Default ruleset: %s", this.defaultRuleset);

final String packageName = makePackageName();
final RpmVersion version = makeVersion();
final RpmVersion version = makeVersion(modifyVersion);

this.logger.info("RPM base information - name: %s, version: %s, arch: %s", packageName, version, this.architecture);

Expand Down Expand Up @@ -951,9 +970,9 @@ private String makeTargetFilename() {

if (outputFileName == null || outputFileName.isEmpty()) {
if (this.naming.getDefaultFormat() == Naming.DefaultFormat.LEGACY) {
outputFileName = RpmFileNameProvider.LEGACY_FILENAME_PROVIDER.getRpmFileName(makePackageName(), makeVersion(), this.architecture);
outputFileName = RpmFileNameProvider.LEGACY_FILENAME_PROVIDER.getRpmFileName(makePackageName(), makeVersion(false), this.architecture);
} else {
outputFileName = RpmFileNameProvider.DEFAULT_FILENAME_PROVIDER.getRpmFileName(makePackageName(), makeVersion(), this.architecture);
outputFileName = RpmFileNameProvider.DEFAULT_FILENAME_PROVIDER.getRpmFileName(makePackageName(), makeVersion(false), this.architecture);
}
this.logger.debug("Using generated file name - %s", outputFileName, outputFileName);
}
Expand Down Expand Up @@ -1312,7 +1331,7 @@ private String makePackageName() {
}
}

private RpmVersion makeVersion() {
private RpmVersion makeVersion(boolean modifyVersion) {
if (!this.forceRelease && isSnapshotVersion()) {
if (this.snapshotVersion != null && !this.snapshotVersion.isEmpty()) {
this.logger.info("Building with SNAPSHOT version from <snapshotVersion> parameter: %s", this.snapshotVersion);
Expand All @@ -1323,7 +1342,14 @@ private RpmVersion makeVersion() {
this.logger.info("Building with SNAPSHOT version from project: %s", baseVersion);
return new RpmVersion(this.epoch, baseVersion, makeSnapshotReleaseString());
}
return new RpmVersion(this.epoch, this.version, this.release);
String version = this.version;
if (modifyVersion) {
for (VersionSubstitution versionSubstitution : versionReplacements) {
logger.info("For version %s looking for %s to replace with %s", version, versionSubstitution.search, versionSubstitution.replace);
version = version.replaceAll(versionSubstitution.search, versionSubstitution.replace);
}
}
return new RpmVersion(this.epoch, version, this.release);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the version is invalid, it could eventually be detected here. Technically, the output filename doesn't have to be a valid RpmVersion, which means we would have to change RpmFileNameProvider to use String instead of RpmVersion, or it would fail at that point with using the non-transformed version (since makeVersion called with false there).

Copy link
Collaborator Author

@rnc rnc May 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to change the output file name as that is what is used in maven storage (and is legal). I'm guessing you're referring to eclipse/packager#76 which would break rpm-builder here if an invalid version is used ; I'm beginning to think the validation might actually cause more problems that it solves. Note also RpmFileNameProvider uses the RpmVersion to extract the release as well as the version.

}

private boolean isSnapshotVersion() {
Expand Down Expand Up @@ -1369,7 +1395,7 @@ protected void fillPackageInformation(final RpmBuilder builder) {
}

private String generateDefaultSourcePackageName() {
return RpmLead.toLeadName(makePackageName(), makeVersion()) + ".src.rpm";
return RpmLead.toLeadName(makePackageName(), makeVersion(modifyVersion)) + ".src.rpm";
}

private String makeVendor() {
Expand Down Expand Up @@ -1452,13 +1478,16 @@ private static void ifSet(final Consumer<String> setter, final String value, fin
}
}


public static class Changelog extends RpmInformation.Changelog {

private String date;

public String getDate() {
return date;
}
}

public static class VersionSubstitution {
private String search;
private String replace;
}
}
16 changes: 16 additions & 0 deletions src/site/markdown/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ of `1.0.0-SNAPSHOT` will result in `1.0.0-0.201604250101` (depending on the actu
The result of these rules are SNAPSHOT releases which is always lower than the final release.
Unless you override using `forceRelease` or `snapshotBuildId`.

### Version Modification

Beyond the above version specification, there is a facility to modify the version _within_ the RPM. This does not affect the file name of the produced RPM. This is useful if the Maven version is non-compliant with RPM versioning. For example if the Maven version is 1.1.rebuild-00001, the `-` could be replaced by `_` (See https://fedoraproject.org/wiki/PackagingDrafts/TildeVersioning#Basic_versioning_rules)

~~~xml
<modifyVersion>true</modifyVersion>
<versionReplacements>
<versionReplacement>
<search>-</search>
<replace>_</replace>
</versionReplacement>
</versionReplacements>
~~~

Multiple version replacements may be specified and they will be applied in sequence.

## Contributing

All contributions are welcome!
Expand Down