amphibient
amphibient

Reputation: 31308

How to list the Maven build/compilation sequence based on dependencies?

If I have a pom hierarchy in which the superpom calls multiple submodules which depend on one another, how can I list the build/compilation sequence based on dependencies? IOW, if the superpom has modules mod1, mod2, and mod3 and mod2 depends on mod3 and mod3 depends on mod1, then the sequence is mod1, mod3, then mod2. How can I list that order without complex XML parsing of data hierarchies from pom?

Upvotes: 28

Views: 16595

Answers (6)

splatch
splatch

Reputation: 1599

I've recently got same issue while trying to speed up CI/CD pipeline by use of -pl :<artifactId> -am -amd switches.

For me solution to list groupId/artifactId as they appear in maven poms is: mvn validate | grep '<'| cut -d ' ' -f 3

Above gives me output such this:

org.connectorio:addons
org.connectorio.addons:parent
org.connectorio.addons:bddhab
org.connectorio.bddhab:org.connectorio.bddhab.rest
org.connectorio.addons:bundles
org.connectorio.addons:org.connectorio.addons.binding

Upvotes: 0

Francesco Silvani
Francesco Silvani

Reputation: 1

A way to get to the order is using the help:evaluate plugin as an actual plugin for your modules. Include the following in a pom.xml and let all modules inherit from that pom. Most times, the modules of a project have their parent set to the pom one folder above anyway. Otherwise, you can copy and paste this to whatever module doesn't follow your inheritence structure.

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-help-plugin</artifactId>
                    <version>3.3.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-help-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>EvaluateReactorBuildOrder</id>
            <build>
                <pluginManagement>
                    <plugins>
                        <plugin>
                            <groupId>org.apache.maven.plugins</groupId>
                            <artifactId>maven-help-plugin</artifactId>
                            <inherited>true</inherited>
                            <executions>
                                <execution>
                                    <id>echo-basedir</id>
                                    <phase>validate</phase>
                                    <goals>
                                        <goal>evaluate</goal>
                                    </goals>
                                </execution>
                            </executions>
                            <configuration>
                                <expression>project.basedir/${path.separator}</expression>
                            </configuration>
                        </plugin>
                    </plugins>
                </pluginManagement>
            </build>
        </profile>
    </profiles>

This enables evaluating the build order with this command:

$>mvn -PEvaluateReactorBuildOrder validate -q -DforceStdout
/root/:/root/module1/:/root/module2/:

The plugins will output the path of the module in the reactor build order. I think this output is much better machine-readable than whatever maven prints in the "Reactor Build Order" section.

Note that the path seperator is included in the <expression> tag. This only works because there is a special case for project variables. -q -DforceStdout will not output any seperator between the output of the different paths of the modules. Adding a linefeed (\n) at the end was difficult, because somewhere in the process, the start and end of the expression gets trimmed of whitespace, so i gave up and used ${path.separator} which gets evaluated when parsing the xml to ":" or ";" depending on your platform.

Using a separate profile for the configuration enables you to run the help:evaluate plugin as usual and keeps the log of normal builds free from the path output. The plugin prefers the expression in the pom to the one, you set with the parameter.

$> mvn help:evaluate -Dexpression=project.version -q -DforceStdout
1.0.0.0

Note, the plugin still has to be included in the regular <build> tag, the profile can only override its configuration.

Upvotes: 0

rhinoceros.xn
rhinoceros.xn

Reputation: 822

shell script

mvn validate >validate.log

project_name=$(mvn org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate -Dexpression=project.name -q -DforceStdout)

sed '1,/^\[INFO\] Reactor Build Order:/ d' validate.log | awk "/\[INFO\] ${project_name} +/ {exit} {print}" | awk '{ print $2 }'

python script


def write_multi_module_pom(sub_module_path_list):
    head_text = '''<?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>org.sonatype.mavenbook.multi</groupId>
    <artifactId>simple-parent</artifactId>
    <packaging>pom</packaging>
    <version>1.0</version>
    <name>Multi Chapter Simple Parent Project</name>
<modules>'''
    tail_text = '''</modules>
</project>
        '''
    pom_content = head_text + '\n'.join(['<module>{}</module>'.format(p) for p in sub_module_path_list]) + tail_text
    with open('pom.xml', 'w') as fw:
        fw.write(pom_content)



def mvn_validate_and_get_orders():
    process = subprocess.Popen('mvn clean validate -Denforcer.skip', shell=True, stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
    output, error = process.communicate()
    result = process.wait()

    if result != 0:
        logging.error(error)
        logging.error("mvn error")
        exit(1)

    text_regex = re.compile(
        r'\[INFO\] Reactor Build Order:((?:.|\n)*?)\[INFO\] Multi Chapter Simple Parent Project')

    if sys.version_info.major == 2:
        text_matched_list = text_regex.findall(output)
    else:
        text_matched_list = text_regex.findall(output.decode('utf8'))
    if len(text_matched_list) == 0:
        return
    projects = [item.strip() for item in text_matched_list[0].replace('[INFO] ', '').splitlines() if
                len(item.strip()) > 0]
    return projects






write_multi_module_pom(["sub-module-1","sub-module-2","sub-module-3"])
mvn_validate_and_get_orders()






Upvotes: 0

happy_marmoset
happy_marmoset

Reputation: 2215

Improved version of @rhinoceros.xn:

mvn validate > validate.log

project_name=$(mvn org.apache.maven.plugins:maven-help-plugin:3.1.0:evaluate -Dexpression=project.name -q -DforceStdout)

sed '1,/^\[INFO\] Reactor Build Order:/ d' validate.log | awk '/\[INFO\] -+</ {exit} {print}' | awk '{ print $2 }' | awk \!/^"$project_name"$/ | awk 'NF'

Upvotes: 1

Behe
Behe

Reputation: 7940

What you want to know is the so called reactor build order.

The reactor determines the correct build order from the dependencies stated by each project in their respective project descriptors, and will then execute a stated set of goals. It can be used for both building projects and other goals, such as site generation. (Source: old multi-module documentation)

It collects all modules to build, sorts the projects and builds them in order. It guarantees that any module is build, before it is required by other modules.

As far as I know, there is no direct way of creating only a list of these items, but the closest thing to just get the information is:

mvn validate

It will show your reactor build order on top:

~/parent$ mvn validate
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] simple.parent
[INFO] simple.child
[INFO] simple.anotherchild
[...]                                                                        

No additional work is performed, besides validating the project for correctness and that all necessary information is available.

For more information, see also the guide to working with multiple modules and this answer about what the maven reactor is.

Upvotes: 65

brokethebuildagain
brokethebuildagain

Reputation: 2191

Perhaps you're looking for the Maven dependency:tree option? You'll probably have to adjust the includes to include only your modules. http://maven.apache.org/plugins/maven-dependency-plugin/tree-mojo.html

mvn dependency:tree -Dverbose -DoutputFile=tree.txt -DoutputType=text -Dincludes=com.mycompany.*

Upvotes: 8

Related Questions