Macros for POM modification

Sometimes Maven pom.xml files need to be patched before they are used to build packages. One could use traditional patches to maintain changes, but package maintainers should use %pom_* macros developed specially to ease this task. Using %pom_* macros not only increases readability of the spec file, but also improves maintainability of the package as there are no patches that would need to be rebased with each upstream release.

There are two categories of macros:

  • POM-specific macros - used to manipulate dependencies, modules, etc. Some of them also work on ivy.xml files.

  • Generic XML manipulation macros - used to add / remove / replace XML nodes.

The macros are designed to be called from %prep section of spec files. All the macros also have their own manual page. This document provides an overview of how they are used. For the technical details, refer to their respective manpages.

File specfication

By default, a macro acts on a pom.xml file (or ivy.xml file) in the current directory. Different path can be explicitly specified via an argument (the last one, unless stated otherwise). Multiple paths can be specified as multiple arguments. If a path is a directory, it looks for a pom.xml file in that directory. For example:

# The following works on pom.xml file in the current directory
%pom_remove_parent

# The following works on submodule/pom.xml
%pom_remove_parent submodule

# The following works on submodule/pom.xml as well
%pom_remove_parent submodule/pom.xml

# The following works on submodule2/pom.xml and submodule2/pom.xml
%pom_remove_parent submodule1 submodule2
Recursive mode

Most macros also support recursive mode, where the change is applied to the pom.xml and all its modules recursively. This can be used, for example, to remove a dependency from the whole project. It is activated by -r switch.

Dependency manipulation macros

Removing dependencies

Often dependencies specified in Maven pom.xml files need to be removed because of different reasons. %pom_remove_dep macro can be used to ease this task:

# Removes dependency with groupId "foo" and artifactId "bar" from pom.xml
%pom_remove_dep foo:bar

# Removes dependency on all artifacts with groupId "foo" from pom.xml
%pom_remove_dep foo:

# Removes dependency on all artifacts with artifactId "bar" from pom.xml
%pom_remove_dep :bar

# Removes dependency on all artifacts with artifactId "bar" from submodule1/pom.xml
%pom_remove_dep :bar submodule1

# Removes dependency on all artifacts with artifactId "bar" from pom.xml
# and all its submodules
%pom_remove_dep -r :bar

# Removes all dependencies from pom.xml
%pom_remove_dep :
Adding dependencies

Dependencies can also be added to pom.xml with %pom_add_dep macro. Usage is very similar to %pom_remove_dep, see $ man pom_add_dep for more information.

Changing dependencies

Sometimes the artifact coordinates used in upstream pom.xml do not correspond to ones used in Fedora and you need to modify them. %pom_change_dep macro will modify all dependencies matching the first argument to artifact coordinates specified by the second argument. Note this macro also works in recursive mode.

# For all artifacts in pom.xml that have groupId 'example' change it to
# 'com.example' while leaving artifactId and other parts intact
%pom_change_dep example: com.example:

Adding / removing plugins

%pom_remove_plugin macro works exactly as %pom_remove_dep, except it removes Maven plugin invocations. Some examples:

Removing Maven plugins from pom.xml files
# Disables maven-jar-plugin so that classpath isn't included in manifests
%pom_remove_plugin :maven-jar-plugin

# Disable a proprietary plugin that isn't packaged for Fedora
%pom_remove_plugin com.example.mammon:useless-proprietary-plugin submodule

Like in previous case, there is also a macro for adding plugins to pom.xml. See its manual page for more information.

Disabling unneeded modules

Sometimes some submodules of upstream project cannot be built for various reasons and there is a need to disable them. This can be achieved by using %pom_disable_module, for example:

Disabling specific project modules
# Disables child-module-1, a submodule of the main pom.xml file
%pom_disable_module child-module-1

# Disables grandchild-module, a submodule of child-module-2/pom.xml
%pom_disable_module grandchild-module child-module-2

Working with parent POM references

Macro %pom_remove_parent removes reference to a parent POM from Maven POM files. This can be useful when parent POM is not yet packaged (e.g. because of licensing issues) and at the same time it is not really needed for building of the project. There are also macros for adding parent POM reference (%pom_add_parent) and replacing existing reference with new one (%pom_set_parent).

Manipulating parent POM references
# Remove reference to a parent POM from ./pom.xml
%pom_remove_parent

# Remove reference to a parent POM from ./submodule/pom.xml
%pom_remove_parent submodule

# Add parent POM reference to ./pom.xml
%pom_add_parent groupId:artifactId

# Replace existing parent POM reference in ./pom.xml
%pom_set_parent groupId:artifactId:version

Macros for performing generic modifications

The above macros cover the most common cases of modifying pom.xml files, however if there is a need to apply some less-common patches there are also three generic macros for modifying pom.xml files. These generic macros can also be applied to other XML files, such as Ant’s build.xml files.

They all take a XPath 1.0 expression that selects XML nodes to be acted on (removed, replaced, etc.).

Handling XML namespaces

POM files use a specific namespace - http://maven.apache.org/POM/4.0.0. The easiest way to respect this namespace in XPath expressions is prefixing all node names with pom:. For example, pom:environment/pom:os will work because it selects nodes from pom namespace, but environment/os won’t find anything because it looks for nodes that do not belong to any XML namespace. It is needed even if the original POM file didn’t contain proper POM namespace, since it will be added automatically. Note that this requirement is due to limitation of XPath 1.0 and we cannot work it around.

Removing nodes

%pom_xpath_remove can be used to remove arbitrary XML nodes.

# Removes extensions from the build
%pom_xpath_remove "pom:build/pom:extensions" module/pom.xml
Injecting nodes

%pom_xpath_inject macro is capable of injecting arbitrary XML code to any pom.xml file. The injected code is the last argument - optional file paths go before it (unlike most other macros). To pass a multiline snippet, quote the argument as in the following example.

# Add additional exclusion into maven-wagon dependency
%pom_xpath_inject "pom:dependency[pom:artifactId='maven-wagon']/pom:exclusions" "
<exclusion>
  <groupId>antlr</groupId>
  <artifactId>antlr</artifactId>
</exclusion>"
# The same thing, but with explicit file path
%pom_xpath_inject "pom:dependency[pom:artifactId='maven-wagon']/pom:exclusions" pom.xml "
<exclusion>
  <groupId>antlr</groupId>
  <artifactId>antlr</artifactId>
</exclusion>"
Changing nodes' content

%pom_xpath_set replaces content of the arbitrary XML nodes with specified value (can contain XML nodes).

# Change groupId of a parent
%pom_xpath_set "pom:parent/pom:groupId" "org.apache"
Replacing nodes

%pom_xpath_replace replaces a XML node with specified XML code.

# Change groupId of a parent (note the difference from %pom_xpath_set)
%pom_xpath_replace "pom:parent/pom:groupId" "<groupId>org.apache</groupId>"