46

I have a complex project where there are many directories that have POM files, but only some of which are sub-modules (possibly transitively) of a particular parent project.

Obviously, Maven knows the list of relevant files because it parses all the <module> tags to find them. But, I only see a list of the <name>s in the [INFO] comments, not the paths to those modules.

Is there a way to have Maven output a list of all the POM files that provided references to projects that are part of the reactor build for a given project?

Emil Sit
  • 22,894
  • 7
  • 53
  • 75

11 Answers11

34

This is quite simple but it only gets the artifactId, from the root (or parent) module:

mvn --also-make dependency:tree | grep maven-dependency-plugin | awk '{ print $(NF-1) }'

If you want the directories

mvn -q --also-make exec:exec -Dexec.executable="pwd"
Bonaparte
  • 459
  • 4
  • 4
  • `mvn -q --also-make exec:exec -Dexec.executable="pwd"` Gives `[ERROR] No plugin found for prefix 'exec' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories` – Loner May 07 '23 at 07:59
23

The following command prints artifactId's of all sub-modules:

mvn -Dexec.executable='echo' -Dexec.args='${project.artifactId}' exec:exec -q

Example output:

build-tools
aws-sdk-java-pom
core
annotations
utils
http-client-spi
http-client-tests
http-clients
apache-client
test-utils
sdk-core
...
hisener
  • 1,431
  • 1
  • 17
  • 23
  • 5
    it's INSANE how slow this in, we have 40 modules, it takes 30 seconds to get that list. That's why I dislike maven very much when it comes to CI/CD. – Eugene Jul 30 '22 at 10:11
14
mvn help:evaluate -Dexpression=project.modules

mvn help:evaluate -Dexpression=project.modules[0]
mvn help:evaluate -Dexpression=project.modules[1]

IFS=$'\n'
modules=($(mvn help:evaluate -Dexpression=project.modules | grep -v "^\[" | grep -v "<\/*strings>" | sed 's/<\/*string>//g' | sed 's/[[:space:]]//'))
for module in "${modules[@]}"
do
    echo "$module"
done
Laurent Picquet
  • 1,147
  • 11
  • 12
  • Sorry to comment on a old one but `mvn help:evaluate -Dexpression=project.modules ` works for me to list the main modules, but not submodules, have you ever figured how to do that, or is it simply not possible? – Mikec Jan 11 '22 at 19:46
6

Here's a way to do this on Linux outside of Maven, by using strace.

$ strace -o opens.txt -f -e open mvn dependency:tree > /dev/null
$ perl -lne 'print $1 if /"(.*pom\.xml)"/' opens.txt 

The first line runs mvn dependency:tree under strace, asking strace to output to the file opens.txt all the calls to the open(2) system call, following any forks (because Java is threaded). This file looks something like:

9690  open("/etc/ld.so.cache", O_RDONLY) = 3
9690  open("/lib/libncurses.so.5", O_RDONLY) = 3
9690  open("/lib/libdl.so.2", O_RDONLY) = 3

The second line asks Perl to print any text inside quotes that happens to end in pom.xml. (The -l flag handles printing newlines, the -n wraps the code single quotes in a loop that simply reads any files on the command line, and the -e handles the script itself which uses a regex to find interesting calls to open.)

It'd be nice to have a maven-native way of doing this :-)

Emil Sit
  • 22,894
  • 7
  • 53
  • 75
4

The solution I found is quite simple:

mvn -B -f "$pom_file" org.codehaus.mojo:exec-maven-plugin:1.4.0:exec \
    -Dexec.executable=/usr/bin/echo \
    -Dexec.args='${basedir}/pom.xml'| \
    grep -v '\['

This is a little bit tricky due to the need to grep out the [INFO|WARNING|ERROR] lines and make it usable for scripting but saved me a lot of time since you can put any expression there.

teoincontatto
  • 1,565
  • 1
  • 9
  • 8
  • 3
    Good one, I needed that. It can be a bit simplified, and it's not so tricky if you add a special string in the echo argument, and then grep for that: `mvn -B exec:exec -Dexec.executable=echo -Dexec.args='###MODULE_GAV### ${project.groupId}:${project.artifactId}:${project.version}' | grep '###MODULE_GAV### ' | cut -f2 -d' '` – Hugues M. Jun 01 '17 at 11:09
  • Excellent, this worked for me. Generates a list of GAVs for the root pom and child modules – nickboldt Jul 05 '18 at 16:42
  • 1
    Adding `-q` as a argument to `mvn` removes the need to grep out the noise. – Pawel Veselov Apr 21 '21 at 00:57
2

Get exactly name. Not ID. Result is appropriate for mvn -pl.

mvn help:evaluate -Dexpression=project.modules -q -DforceStdout | tail -n +2 | head -n -1 | sed 's/\s*<.*>\(.*\)<.*>/\1/'

or with main pom.xml

cat pom.xml | grep "<module>" | sed 's/\s*<.*>\(.*\)<.*>/\1/'
Eugene Lopatkin
  • 2,351
  • 1
  • 22
  • 34
1

I had the same problem but solved it without strace. The mvn exec:exec plugin is used to touch pom.xml in every project, and then find the recently modified pom.xml files:

ctimeref=`mktemp`
mvn --quiet exec:exec -Dexec.executable=/usr/bin/touch -Dexec.args=pom.xml
find . -mindepth 2 -type f -name pom.xml -cnewer "$ctimeref" > maven_projects_list.txt
rm "$ctimeref"

And you have your projects list in the maven_projects_list.txt file.

cbliard
  • 7,051
  • 5
  • 41
  • 47
1

I don't have a direct answer to the question. But using some kind of "module path" as naming convention for the <name> of my modules works for me. As you'll see, this convention is self explaining.

Given the following project structure:

.
├── pom
│   ├── pom.xml
│   └── release.properties
├── pom.xml
├── samples
│   ├── ejb-cargo-sample
│   │   ├── functests
│   │   │   ├── pom.xml
│   │   │   └── src
│   │   ├── pom.xml
│   │   └── services
│   │       ├── pom.xml
│   │       └── src
│   └── pom.xml
└── tools
    ├── pom.xml
    └── verification-resources
        ├── pom.xml
        └── src

Here is the output of a reactor build:

$ mvn compile
[INFO] Scanning for projects...
[INFO] Reactor build order: 
[INFO]   Personal Sandbox - Samples - Parent POM
[INFO]   Personal Sandbox - Samples - EJB3 and Cargo Sample
[INFO]   Personal Sandbox - Tools - Parent POM
[INFO]   Personal Sandbox - Tools - Shared Verification Resources
[INFO]   Personal Sandbox - Samples - EJB3 and Cargo Sample - Services
[INFO]   Personal Sandbox - Samples - EJB3 and Cargo Sample - Functests
[INFO]   Sandbox Externals POM
...

This gives IMHO a very decent overview of what is happening, scales correctly, and it's pretty easy to find any module in the file system in case of problems.

Not sure this does answer all your needs though.

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • It's true that some better naming would help visualize the structure. However, in this case, I want to construct a list of filenames that I can pass as a restriction to `git grep` so I actually need the paths to the POMs. – Emil Sit Sep 08 '10 at 14:21
  • @Emil Oh, I see. That's another story :) – Pascal Thivent Sep 08 '10 at 20:23
0

This is the command I use for listing all pom.xml files inside a project at the root of the project.

find -name pom.xml | grep -v target | sort

What the command do :

find -name pom.xml what I search

grep -v target avoid to list pom.xml inside target/ directory

sort list the result in alphabetical order

VictorRos
  • 11
  • 1
0

An example to list all modules and the parent of each

export REPO_DIR=$(pwd)
export REPO_NAME=$(basename ${REPO_DIR})

echo "${REPO_DIR} ==> ${REPO_NAME}"

mvn exec:exec -q \
  -Dexec.executable='echo' \
  -Dexec.args='${basedir}:${project.parent.groupId}:${project.parent.artifactId}:${project.parent.version}:${project.groupId}:${project.artifactId}:${project.version}:${project.packaging}' \
  | perl -pe "s/^${REPO_DIR//\//\\\/}/${REPO_NAME}/g" \
  | perl -pe 's/:/\t/g;'
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
TapakSakti
  • 11
  • 1
0

I prepared the script below as mvn exec:exec runs slow on gitlab. I couldn't find a free time to investigate it more but I'm suspicious about it tries to get a new runner as it needs a new Runtime. So, if you're working with quite limited runners, it affects the overall build time in an unpredictable way if you used mvn exec:exec to determine the modules.

The below snippet gives you the module name, packaging and path to the module

#!/bin/bash
set -e;
mvnOptions='--add-opens java.base/java.lang=ALL-UNNAMED';

string=$(MAVEN_OPTS="$mvnOptions" mvn help:active-profiles)
delimiter='Active Profiles for Project*';
modules=()
while read -r line; do
  if [[ $line == $delimiter ]]; then
      module=$(echo $line | sed -E "s/.*'(.*):(.*):(.*):(.*)'.*/\2/");
      packaging=$(echo $line | sed -E "s/.*'(.*):(.*):(.*):(.*)'.*/\3/");
      path=$(MAVEN_OPTS="$mvnOptions" mvn help:evaluate -Dexpression=project.basedir -pl "$module" -q -DforceStdout || true);
      if [[ $path == *" $module "* ]]; then
        path=$(pwd);
      fi
      modules+=("$module" "$packaging" "$path")
  fi;
done <<< "$string"

size="$(echo ${#modules[@]})";
moduleCount=$(( $size / 3 ));

# prints the found modules
if [ $moduleCount -gt 0 ]; then
  echo "$moduleCount module(s) found"
  for (( i=0; i<$moduleCount; ++i)); do
    line=$(($i + 1));
    moduleIndex=$(($i * 3));
    pathIndex=$(($i * 3+2));
    module=${modules[moduleIndex]};
    path=${modules[pathIndex]};
    echo "  $line. '$module' at '$path'";
  done;
fi;
Zana Simsek
  • 89
  • 1
  • 1
  • 7