├── .gitignore ├── .java-version ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .travis.yml ├── LICENSE.txt ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── it ├── both-it │ ├── .mvn │ │ └── extensions.xml │ ├── pom.xml │ ├── src │ │ └── main │ │ │ └── Nop.java │ ├── test.properties │ └── verify.groovy ├── csv-it │ ├── .mvn │ │ └── extensions.xml │ ├── pom.xml │ ├── src │ │ └── main │ │ │ └── Nop.java │ ├── test.properties │ └── verify.groovy ├── logging-it │ ├── .mvn │ │ └── extensions.xml │ ├── pom.xml │ ├── src │ │ └── main │ │ │ └── Nop.java │ ├── test.properties │ └── verify.groovy └── settings.xml ├── main └── java │ ├── co │ └── leantechniques │ │ └── maven │ │ └── buildtime │ │ ├── AbstractTimerVisitor.java │ │ ├── Constants.java │ │ ├── LogOutput.java │ │ ├── MavenHelper.java │ │ ├── MojoExecutionName.java │ │ ├── MojoTimer.java │ │ ├── ProjectTimer.java │ │ ├── SessionTimer.java │ │ ├── SystemClock.java │ │ ├── TimerVisitor.java │ │ └── output │ │ ├── CsvReporter.java │ │ ├── LogReporter.java │ │ └── Reporter.java │ └── org │ └── apache │ └── maven │ └── cli │ └── BuildTimeEventSpy.java └── test └── java ├── co └── leantechniques │ └── maven │ └── buildtime │ ├── MavenHelperTest.java │ ├── MojoExecutionNameTest.java │ ├── MojoTimerTest.java │ └── SessionTimerTest.java └── org └── apache └── maven └── cli └── BuildTimeEventSpyTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | target/ 3 | *.iml 4 | -------------------------------------------------------------------------------- /.java-version: -------------------------------------------------------------------------------- 1 | 1.8 2 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timgifford/maven-buildtime-extension/ddb9406f86d843d586e8abb493d9709e9004f5b9/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | cache: 2 | directories: 3 | - $HOME/.m2 4 | language: java 5 | jdk: 6 | - openjdk7 7 | - oraclejdk8 8 | install: true # skip default maven install since we use maven wrapper 9 | script: 10 | - ./mvnw install 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Tim Gifford 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/timgifford/maven-buildtime-extension.svg?branch=master)](https://travis-ci.org/timgifford/maven-buildtime-extension) 2 | # Overview 3 | Maven doesn't give you detailed information about where your build is taking the most time. This build time extension 4 | displays the duration for each goal that is run during your build. 5 | 6 | # Usage 7 | Put this in your pom.xml to find out why you are slow. 8 | By default this will log only to maven debug `-X,--debug`, however debug is quite noisy, so you can enable output to normal log 9 | via the property `buildtime.output.log` in your pom or via commandline `-Dbuildtime.output.log=true`. 10 | 11 | ## Capture the results to a CSV file 12 | Thanks to [@leonard84](https://github.com/leonard84) for the contribution. You'll need to set a property to enable this feature. 13 | Eventually, we can enhance this functionality to include other output formats. 14 | I personally would like to publish the results to an InfluxDb instance. 15 | 16 | ``` 17 | mvn compile -Dbuildtime.output.csv=true -Dbuildtime.output.csv.file=classes\out.csv 18 | ``` 19 | 20 | Maven introduced slf4j in version 3.2 which broke this build extension for Maven 3.0 users. 21 | Version 2.0+ will work with the latest version of Maven. 22 | 23 | ## Maven 3.3 - Use version 3.0+ 24 | 25 | With version 3.0.0 we switched to Maven's `EventSpy` API which increases the compatibility with other tools, e.g. Jenkins which 26 | also use this API to instrument Maven. However this requires a different way of loading the extension. This also requires at 27 | least Maven 3.3+. 28 | 29 | Create the following file `/.mvn/extensions.xml` with this as content 30 | 31 | ``` 32 | 33 | 34 | 35 | co.leantechniques 36 | maven-buildtime-extension 37 | 3.0.0 38 | 39 | 40 | ``` 41 | Due to [MNG-5786](https://issues.apache.org/jira/browse/MNG-5786) you might need to use Maven 3.3.9 if 42 | `/.mvn/extensions.xml` is not picked up. You can also check the build log for the presence of the string 43 | `BuildTimeEventSpy is registered.` which is logged if the extension was successfully activated. 44 | 45 | ## Maven 3.2 - Use version 2.0+ ```Deprecated``` 46 | 47 | 48 | ``` 49 | 50 | 51 | 52 | co.leantechniques 53 | maven-buildtime-extension 54 | 2.0.3 55 | 56 | 57 | 58 | ``` 59 | 60 | ## Maven 3.0 - Use version 1.0 ```Deprecated``` 61 | Version 1 works with Maven 3.0. All future improvements and bug fixes will occur on the 2.0 version 62 | of this build extension 63 | 64 | ``` 65 | 66 | 67 | 68 | co.leantechniques 69 | maven-buildtime-extension 70 | 1.0.1 71 | 72 | 73 | 74 | ``` 75 | 76 | ## One-off execution 77 | 78 | Instead of modifying the POM you can also perform a one-off execution. In this 79 | case you must manually download the extension (only once, before the first 80 | execution) and then explicitly provide it as a command line argument: 81 | 82 | ``` 83 | VERSION=2.0.3 84 | mvn -q dependency:get -Dartifact="co.leantechniques:maven-buildtime-extension:$VERSION" 85 | mvn compile -Dmaven.ext.class.path="$HOME/.m2/repository/co/leantechniques/maven-buildtime-extension/$VERSION/maven-buildtime-extension-$VERSION.jar" 86 | ``` 87 | 88 | # Example 89 | 90 | ``` 91 | [INFO] Reactor Summary: 92 | [INFO] 93 | [INFO] CoEfficient ....................................... SUCCESS [0.103s] 94 | [INFO] coefficient-core .................................. SUCCESS [0.903s] 95 | [INFO] coefficient-scm ................................... SUCCESS [0.314s] 96 | [INFO] coefficient-heatmap ............................... SUCCESS [0.202s] 97 | [INFO] coefficient-test-ratios ........................... SUCCESS [0.114s] 98 | [INFO] coefficient-mvn ................................... SUCCESS [0.769s] 99 | [INFO] coefficient-acceptance-test ....................... SUCCESS [0.305s] 100 | [INFO] ------------------------------------------------------------------------ 101 | [INFO] BUILD SUCCESS 102 | [INFO] ------------------------------------------------------------------------ 103 | [INFO] Total time: 3.490s 104 | [INFO] Finished at: Sun Jul 14 16:10:34 CDT 2013 105 | [INFO] Final Memory: 12M/81M 106 | [INFO] ------------------------------------------------------------------------ 107 | [INFO] Build Time Summary: 108 | [INFO] 109 | [INFO] coefficient 110 | [INFO] maven-clean-plugin:clean ................................. [0.079s] 111 | [INFO] coefficient-core 112 | [INFO] maven-clean-plugin:clean ................................. [0.007s] 113 | [INFO] maven-resources-plugin:resources ......................... [0.261s] 114 | [INFO] maven-compiler-plugin:compile ............................ [0.569s] 115 | [INFO] coefficient-scm 116 | [INFO] maven-clean-plugin:clean ................................. [0.007s] 117 | [INFO] maven-resources-plugin:resources ......................... [0.002s] 118 | [INFO] maven-compiler-plugin:compile ............................ [0.281s] 119 | [INFO] coefficient-heatmap 120 | [INFO] maven-clean-plugin:clean ................................. [0.003s] 121 | [INFO] maven-resources-plugin:resources ......................... [0.002s] 122 | [INFO] maven-compiler-plugin:compile ............................ [0.172s] 123 | [INFO] coefficient-test-ratios 124 | [INFO] maven-clean-plugin:clean ................................. [0.005s] 125 | [INFO] maven-resources-plugin:resources ......................... [0.002s] 126 | [INFO] maven-compiler-plugin:compile ............................ [0.085s] 127 | [INFO] coefficient-mvn 128 | [INFO] maven-clean-plugin:clean ................................. [0.005s] 129 | [INFO] maven-plugin-plugin:descriptor ........................... [0.628s] 130 | [INFO] maven-resources-plugin:resources ......................... [0.002s] 131 | [INFO] maven-compiler-plugin:compile ............................ [0.099s] 132 | [INFO] coefficient-acceptance-test 133 | [INFO] maven-clean-plugin:clean ................................. [0.002s] 134 | [INFO] maven-resources-plugin:resources ......................... [0.002s] 135 | [INFO] maven-compiler-plugin:compile ............................ [0.002s] 136 | [INFO] ------------------------------------------------------------------------ 137 | ``` 138 | 139 | # Release Process 140 | Sonatype requires all published components to be signed. These commands prompt for a `gpg passphase`. (Reminder for me: It is in your password vault) 141 | ``` 142 | ./mvnw release:prepare 143 | 144 | ./mvnw release:perform 145 | ``` 146 | 147 | 2018-05-30 148 | Had to add this command to the my console to get it signed: 149 | ```bash 150 | GPG_TTY=$(tty) 151 | export GPG_TTY 152 | ``` 153 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} $MAVEN_CMD_LINE_ARGS 234 | 235 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% 146 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | co.leantechniques 4 | maven-buildtime-extension 5 | 3.0.7-SNAPSHOT 6 | jar 7 | 8 | 9 | org.sonatype.oss 10 | oss-parent 11 | 7 12 | 13 | 14 | Maven Buildtime Extension 15 | 16 | This extension displays the duration of each plugin 17 | to discover why your build is slow. 18 | 19 | https://github.com/timgifford/maven-buildtime-extension 20 | 21 | https://github.com/timgifford/maven-buildtime-extension/issues 22 | GitHub Issues 23 | 24 | 25 | 26 | MIT License 27 | http://www.opensource.org/licenses/mit-license.php 28 | repo 29 | 30 | 31 | 32 | https://github.com/timgifford/maven-buildtime-extension 33 | scm:git:git@github.com:timgifford/maven-buildtime-extension.git 34 | scm:git:git@github.com:timgifford/maven-buildtime-extension.git 35 | HEAD 36 | 37 | 38 | 39 | 40 | tgifford@gmail.com 41 | Tim Gifford 42 | https://github.com/timgifford 43 | timgifford 44 | 45 | 46 | 47 | 48 | UTF-8 49 | 50 | 3.2.1 51 | 52 | true 53 | 1.8 54 | 1.8 55 | 56 | 57 | 58 | 59 | org.apache.maven 60 | maven-core 61 | ${mavenVersion} 62 | 63 | 64 | org.apache.maven 65 | maven-embedder 66 | ${mavenVersion} 67 | 68 | 69 | junit 70 | junit 71 | 4.8.2 72 | test 73 | 74 | 80 | 81 | org.mockito 82 | mockito-core 83 | 5.6.0 84 | test 85 | 86 | 87 | 92 | 93 | 94 | ossrh 95 | https://oss.sonatype.org/content/repositories/snapshots 96 | 97 | 98 | ossrh 99 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 100 | 101 | 102 | 103 | 104 | 105 | org.sonatype.plugins 106 | nexus-staging-maven-plugin 107 | 1.6.3 108 | true 109 | 110 | ossrh 111 | https://oss.sonatype.org/ 112 | true 113 | 114 | 115 | 116 | 117 | org.codehaus.plexus 118 | plexus-component-metadata 119 | 1.5.5 120 | 121 | 122 | 123 | generate-metadata 124 | generate-test-metadata 125 | 126 | 127 | 128 | 129 | 130 | org.apache.maven.plugins 131 | maven-release-plugin 132 | 2.5.2 133 | 134 | v@{project.version} 135 | 136 | 137 | 138 | maven-invoker-plugin 139 | 3.6.0 140 | 141 | ${project.build.directory}/it 142 | true 143 | src/it/settings.xml 144 | ${project.build.directory}/local-repo 145 | verify 146 | 147 | package -V 148 | 149 | 150 | 151 | 152 | integration-test 153 | 154 | install 155 | run 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/it/both-it/.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @project.groupId@ 5 | @project.artifactId@ 6 | @project.version@ 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/it/both-it/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | it.test 7 | minimal-pom 8 | 1.0-SNAPSHOT 9 | jar 10 | 11 | minimal-pom 12 | http://maven.apache.org 13 | 14 | 15 | UTF-8 16 | 1.7 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/it/both-it/src/main/Nop.java: -------------------------------------------------------------------------------- 1 | public class Nop { 2 | public static void main( String[] args ) 3 | { 4 | System.out.println( "Hello World!" ); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/it/both-it/test.properties: -------------------------------------------------------------------------------- 1 | buildtime.output.log=true 2 | buildtime.output.csv=true 3 | -------------------------------------------------------------------------------- /src/it/both-it/verify.groovy: -------------------------------------------------------------------------------- 1 | def buildLogText = new File(basedir, 'build.log').text 2 | assert buildLogText.contains('BuildTimeEventSpy is registered.') 3 | assert buildLogText.contains('maven-compiler-plugin:testCompile (default-testCompile) ..') 4 | assert buildLogText.contains('maven-surefire-plugin:test (default-test) ................') 5 | assert buildLogText.contains('maven-jar-plugin:jar (default-jar) .......................') 6 | assert buildLogText.contains('maven-compiler-plugin:compile (default-compile) ..........') 7 | assert buildLogText.contains('maven-resources-plugin:resources (default-resources) .....') 8 | assert buildLogText.contains('maven-resources-plugin:testResources (default-testResource') 9 | 10 | def buildTimeCsv = new File(basedir, 'target/buildtime.csv') 11 | assert buildTimeCsv.exists() 12 | def buildTimeCsvText = buildTimeCsv.text 13 | 14 | assert buildTimeCsvText ==~ $/(?ms)\s*"Module";"Mojo";"Time".*/$ 15 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-compiler-plugin:testCompile \(default-testCompile\)";"\d{1,3}\.\d{3}".*/$ 16 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-surefire-plugin:test \(default-test\)";"\d{1,3}\.\d{3}".*/$ 17 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-jar-plugin:jar \(default-jar\)";"\d{1,3}\.\d{3}".*/$ 18 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-compiler-plugin:compile \(default-compile\)";"\d{1,3}\.\d{3}".*/$ 19 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-resources-plugin:resources \(default-resources\)";"\d{1,3}\.\d{3}".*/$ 20 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-resources-plugin:testResources \(default-testResources\)";"\d{1,3}\.\d{3}".*/$ 21 | 22 | -------------------------------------------------------------------------------- /src/it/csv-it/.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @project.groupId@ 5 | @project.artifactId@ 6 | @project.version@ 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/it/csv-it/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | it.test 7 | minimal-pom 8 | 1.0-SNAPSHOT 9 | jar 10 | 11 | minimal-pom 12 | http://maven.apache.org 13 | 14 | 15 | UTF-8 16 | 1.7 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/it/csv-it/src/main/Nop.java: -------------------------------------------------------------------------------- 1 | public class Nop { 2 | public static void main( String[] args ) 3 | { 4 | System.out.println( "Hello World!" ); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/it/csv-it/test.properties: -------------------------------------------------------------------------------- 1 | buildtime.output.csv=true 2 | -------------------------------------------------------------------------------- /src/it/csv-it/verify.groovy: -------------------------------------------------------------------------------- 1 | def buildLogText = new File(basedir, 'build.log').text 2 | assert buildLogText.contains('BuildTimeEventSpy is registered.') 3 | 4 | def buildTimeCsv = new File(basedir, 'target/buildtime.csv') 5 | assert buildTimeCsv.exists() 6 | def buildTimeCsvText = buildTimeCsv.text 7 | 8 | assert buildTimeCsvText ==~ $/(?ms)\s*"Module";"Mojo";"Time".*/$ 9 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-compiler-plugin:testCompile \(default-testCompile\)";"\d{1,3}\.\d{3}".*/$ 10 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-surefire-plugin:test \(default-test\)";"\d{1,3}\.\d{3}".*/$ 11 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-jar-plugin:jar \(default-jar\)";"\d{1,3}\.\d{3}".*/$ 12 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-compiler-plugin:compile \(default-compile\)";"\d{1,3}\.\d{3}".*/$ 13 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-resources-plugin:resources \(default-resources\)";"\d{1,3}\.\d{3}".*/$ 14 | assert buildTimeCsvText ==~ $/(?ms).*"minimal-pom";"maven-resources-plugin:testResources \(default-testResources\)";"\d{1,3}\.\d{3}".*/$ 15 | -------------------------------------------------------------------------------- /src/it/logging-it/.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @project.groupId@ 5 | @project.artifactId@ 6 | @project.version@ 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/it/logging-it/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | it.test 7 | minimal-pom 8 | 1.0-SNAPSHOT 9 | jar 10 | 11 | minimal-pom 12 | http://maven.apache.org 13 | 14 | 15 | UTF-8 16 | 1.7 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/it/logging-it/src/main/Nop.java: -------------------------------------------------------------------------------- 1 | public class Nop { 2 | public static void main( String[] args ) 3 | { 4 | System.out.println( "Hello World!" ); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/it/logging-it/test.properties: -------------------------------------------------------------------------------- 1 | buildtime.output.log=true 2 | -------------------------------------------------------------------------------- /src/it/logging-it/verify.groovy: -------------------------------------------------------------------------------- 1 | def buildLogText = new File(basedir, 'build.log').text 2 | assert buildLogText.contains('BuildTimeEventSpy is registered.') 3 | assert buildLogText.contains('maven-compiler-plugin:testCompile (default-testCompile) ..') 4 | assert buildLogText.contains('maven-surefire-plugin:test (default-test) ................') 5 | assert buildLogText.contains('maven-jar-plugin:jar (default-jar) .......................') 6 | assert buildLogText.contains('maven-compiler-plugin:compile (default-compile) ..........') 7 | assert buildLogText.contains('maven-resources-plugin:resources (default-resources) .....') 8 | assert buildLogText.contains('maven-resources-plugin:testResources (default-testResource') 9 | -------------------------------------------------------------------------------- /src/it/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | it-repo 6 | 7 | true 8 | 9 | 10 | 11 | local.central 12 | @localRepositoryUrl@ 13 | 14 | true 15 | 16 | 17 | true 18 | 19 | 20 | 21 | 22 | 23 | local.central 24 | @localRepositoryUrl@ 25 | 26 | true 27 | 28 | 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/AbstractTimerVisitor.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | /** 4 | * Simple abstract implementation of {@link TimerVisitor} extend this 5 | * class instead of {@link TimerVisitor} to be safe for future extensions. 6 | */ 7 | public class AbstractTimerVisitor implements TimerVisitor { 8 | public void visit(SessionTimer sessionTimer) { 9 | 10 | } 11 | 12 | public void visit(ProjectTimer projectTimer) { 13 | 14 | } 15 | 16 | public void visit(MojoTimer mojoTimer) { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/Constants.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | public class Constants { 4 | private Constants(){} 5 | 6 | public static final String BUILDTIME_OUTPUT_CSV_FILE_PROPERTY = "buildtime.output.csv.file"; 7 | public static final String BUILDTIME_OUTPUT_CSV_FILE = "buildtime.csv"; 8 | public static final String BUILDTIME_OUTPUT_CSV_PROPERTY = "buildtime.output.csv"; 9 | public static final String BUILDTIME_OUTPUT_LOG_PROPERTY = "buildtime.output.log"; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/LogOutput.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import org.slf4j.Logger; 4 | 5 | public class LogOutput { 6 | 7 | private Logger logger; 8 | private boolean logToInfo; 9 | 10 | public LogOutput(Logger logger, boolean logToInfo) { 11 | this.logger = logger; 12 | this.logToInfo = logToInfo; 13 | } 14 | 15 | public void log(String string) { 16 | if (logToInfo) { 17 | logger.info(string); 18 | } else { 19 | logger.debug(string); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/MavenHelper.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import java.util.Properties; 4 | 5 | import org.apache.maven.execution.ExecutionEvent; 6 | import org.apache.maven.execution.MavenSession; 7 | 8 | public class MavenHelper { 9 | private MavenHelper(){} 10 | 11 | public static String getExecutionProperty(final ExecutionEvent event, final String property, final String def) { 12 | MavenSession mavenSession = event.getSession(); 13 | Properties systemProperties = mavenSession.getSystemProperties(); 14 | Properties userProperties = mavenSession.getUserProperties(); 15 | Properties projectProperties = mavenSession.getTopLevelProject() == null ? null : mavenSession.getTopLevelProject().getProperties(); 16 | String output = userProperties.getProperty(property); 17 | output = output == null ? projectProperties != null ? projectProperties.getProperty(property) : null : output; 18 | output = output == null ? systemProperties.getProperty(property) : output; 19 | return output == null ? def : output; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/MojoExecutionName.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import java.util.Locale; 4 | 5 | import org.apache.maven.plugin.MojoExecution; 6 | 7 | public class MojoExecutionName { 8 | 9 | private final String name; 10 | 11 | public MojoExecutionName(MojoExecution mojoExecution) { 12 | name = String.format(Locale.ENGLISH, 13 | "%s:%s (%s)", 14 | mojoExecution.getArtifactId(), 15 | mojoExecution.getGoal(), 16 | mojoExecution.getExecutionId()); 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/MojoTimer.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import java.lang.Comparable; 4 | 5 | public class MojoTimer implements Comparable { 6 | 7 | private final String projectName; 8 | 9 | private String name; 10 | private long startTime = 0; 11 | private long endTime = 0; 12 | private SystemClock systemClock; 13 | 14 | public MojoTimer(String projectName, String name, SystemClock systemClock) { 15 | this(projectName, name, 0,0, systemClock); 16 | } 17 | 18 | public MojoTimer(String projectName, String name, long startTime, long endTime){ 19 | this(projectName, name, startTime, endTime, new SystemClock()); 20 | } 21 | 22 | public MojoTimer(String projectName, String name, long startTime, long endTime, SystemClock systemClock) { 23 | this.projectName = projectName; 24 | this.name = name; 25 | this.startTime = startTime; 26 | this.endTime = endTime; 27 | this.systemClock = systemClock; 28 | } 29 | 30 | public Long getDuration() { 31 | return endTime - startTime; 32 | } 33 | 34 | public String getName() { 35 | return name; 36 | } 37 | 38 | public String getProjectName() { 39 | return projectName; 40 | } 41 | 42 | public void stop() { 43 | this.endTime = systemClock.currentTimeMillis(); 44 | } 45 | 46 | public void start() { 47 | this.startTime = systemClock.currentTimeMillis(); 48 | } 49 | 50 | public void accept(TimerVisitor visitor){ 51 | visitor.visit(this); 52 | } 53 | 54 | public int compareTo(MojoTimer that) { 55 | if (that == null) 56 | return 1; 57 | 58 | if (this == that) 59 | return 0; 60 | 61 | if (this.startTime > that.startTime) 62 | return 1; 63 | else if (this.startTime < that.startTime) 64 | return -1; 65 | 66 | return 0; 67 | } 68 | 69 | public long getStartTime() { 70 | return startTime; 71 | } 72 | 73 | public long getEndTime() { 74 | return endTime; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/ProjectTimer.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.ConcurrentMap; 8 | 9 | public class ProjectTimer implements Comparable { 10 | 11 | private final String projectName; 12 | 13 | private final ConcurrentMap dataStore; 14 | private final SystemClock systemClock; 15 | 16 | public ProjectTimer(String projectName, ConcurrentMap dataStore, SystemClock systemClock) { 17 | this.dataStore = dataStore; 18 | this.systemClock = systemClock; 19 | this.projectName = projectName; 20 | } 21 | 22 | public ProjectTimer(String projectName, SystemClock systemClock) { 23 | this(projectName, new ConcurrentHashMap(), systemClock); 24 | } 25 | 26 | public void stopTimerFor(MojoExecutionName me) { 27 | getMojoTimer(me).stop(); 28 | } 29 | 30 | public void startTimerFor(MojoExecutionName name) { 31 | getMojoTimer(name).start(); 32 | } 33 | 34 | public MojoTimer getMojoTimer(MojoExecutionName name) { 35 | if(!dataStore.containsKey(name.getName())) { 36 | dataStore.putIfAbsent(name.getName(), new MojoTimer(projectName, name.getName(), systemClock)); 37 | } 38 | return dataStore.get(name.getName()); 39 | } 40 | 41 | public Long getDuration() { 42 | return getProjectEndTime() - getProjectStartTime(); 43 | } 44 | 45 | public void accept(TimerVisitor visitor){ 46 | visitor.visit(this); 47 | 48 | final List mojoTimers = new ArrayList(dataStore.values()); 49 | Collections.sort(mojoTimers); 50 | 51 | for (MojoTimer mojoTimer : mojoTimers) { 52 | mojoTimer.accept(visitor); 53 | } 54 | } 55 | 56 | public int compareTo(ProjectTimer that) { 57 | if (that == null) 58 | return 1; 59 | 60 | if (this == that) 61 | return 0; 62 | 63 | long thisStartTime = this.getProjectStartTime(); 64 | long thatStartTime = that.getProjectStartTime(); 65 | 66 | if (thisStartTime > thatStartTime) 67 | return 1; 68 | else if (thisStartTime < thatStartTime) 69 | return -1; 70 | 71 | return 0; 72 | } 73 | 74 | public String getProjectName() { 75 | return projectName; 76 | } 77 | 78 | private long getProjectStartTime() { 79 | long startTime = Long.MAX_VALUE; 80 | 81 | for (MojoTimer mojoTimer : dataStore.values()) { 82 | startTime = Math.min(startTime, mojoTimer.getStartTime()); 83 | } 84 | 85 | return startTime; 86 | } 87 | 88 | private long getProjectEndTime() { 89 | long endTime = 0; 90 | 91 | for (MojoTimer mojoTimer : dataStore.values()) { 92 | endTime = Math.max(endTime, mojoTimer.getEndTime()); 93 | } 94 | 95 | return endTime; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/SessionTimer.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.ConcurrentMap; 8 | 9 | import org.apache.maven.plugin.MojoExecution; 10 | import org.apache.maven.project.MavenProject; 11 | 12 | public class SessionTimer { 13 | private ConcurrentMap projects; 14 | private SystemClock systemClock; 15 | 16 | public SessionTimer() { 17 | this(new ConcurrentHashMap(), new SystemClock()); 18 | } 19 | 20 | public SessionTimer(ConcurrentMap projects, SystemClock systemClock) { 21 | this.projects = projects; 22 | this.systemClock = systemClock; 23 | } 24 | 25 | public ProjectTimer getProject(MavenProject project) { 26 | return getProject(project.getArtifactId()); 27 | } 28 | 29 | public ProjectTimer getProject(String projectArtifactId) { 30 | if (!projects.containsKey(projectArtifactId)) 31 | projects.putIfAbsent(projectArtifactId, new ProjectTimer(projectArtifactId, systemClock)); 32 | 33 | return projects.get(projectArtifactId); 34 | } 35 | 36 | public void accept(TimerVisitor visitor) { 37 | visitor.visit(this); 38 | 39 | final List projectTimers = new ArrayList(projects.values()); 40 | Collections.sort(projectTimers); 41 | 42 | for (ProjectTimer projectTimer : projectTimers) { 43 | projectTimer.accept(visitor); 44 | } 45 | } 46 | 47 | public void mojoStarted(MavenProject project, MojoExecution mojoExecution) { 48 | getProject(project).startTimerFor(new MojoExecutionName(mojoExecution)); 49 | } 50 | 51 | public void mojoSucceeded(MavenProject project, MojoExecution mojoExecution) { 52 | getProject(project).stopTimerFor(new MojoExecutionName(mojoExecution)); 53 | } 54 | 55 | public void mojoFailed(MavenProject project, MojoExecution mojoExecution) { 56 | getProject(project).stopTimerFor(new MojoExecutionName(mojoExecution)); 57 | } 58 | 59 | public MojoTimer getMojoTimer(MavenProject project, MojoExecution mojoExecution) { 60 | return getProject(project).getMojoTimer(new MojoExecutionName(mojoExecution)); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/SystemClock.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | public class SystemClock { 4 | public long currentTimeMillis() { 5 | return System.currentTimeMillis(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/TimerVisitor.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | /** 4 | * Visitor Interface for Timer classes. 5 | * 6 | * It should not be implemented directly, use {@link AbstractTimerVisitor} instead. 7 | */ 8 | public interface TimerVisitor { 9 | 10 | void visit(SessionTimer sessionTimer); 11 | 12 | void visit(ProjectTimer projectTimer); 13 | 14 | void visit(MojoTimer mojoTimer); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/output/CsvReporter.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime.output; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.PrintWriter; 6 | import java.util.Locale; 7 | 8 | import org.apache.maven.execution.ExecutionEvent; 9 | import org.slf4j.Logger; 10 | 11 | import co.leantechniques.maven.buildtime.AbstractTimerVisitor; 12 | import co.leantechniques.maven.buildtime.Constants; 13 | import co.leantechniques.maven.buildtime.MavenHelper; 14 | import co.leantechniques.maven.buildtime.MojoTimer; 15 | import co.leantechniques.maven.buildtime.SessionTimer; 16 | 17 | public class CsvReporter implements Reporter { 18 | 19 | private File getOutputFile(final ExecutionEvent event) { 20 | String output = MavenHelper.getExecutionProperty(event, Constants.BUILDTIME_OUTPUT_CSV_FILE_PROPERTY, Constants.BUILDTIME_OUTPUT_CSV_FILE); 21 | if (output != null) { 22 | File file = new File(output); 23 | if (file.isAbsolute()) { 24 | file.getParentFile().mkdirs(); 25 | } else { 26 | File parent = new File("target"); 27 | parent.mkdirs(); 28 | file = new File(parent, output); 29 | } 30 | return file; 31 | } 32 | return null; 33 | } 34 | 35 | public void performReport(Logger logger, ExecutionEvent event, SessionTimer session) { 36 | if (Boolean.parseBoolean(MavenHelper.getExecutionProperty(event, Constants.BUILDTIME_OUTPUT_CSV_PROPERTY, "false"))) { 37 | File file = getOutputFile(event); 38 | if (file != null) { 39 | PrintWriter printWriter = null; 40 | try { 41 | printWriter = new PrintWriter(file); 42 | writeTo(session, printWriter); 43 | } catch (FileNotFoundException e) { 44 | logger.error("Could not write report", e); 45 | } finally { 46 | if (printWriter != null) { 47 | printWriter.close(); 48 | } 49 | } 50 | } 51 | } 52 | } 53 | 54 | public void writeTo(SessionTimer session, PrintWriter printWriter) { 55 | printWriter.println("\"Module\";\"Mojo\";\"Time\";\"Start\";\"End\""); 56 | session.accept(new CsvReportVisitor(printWriter)); 57 | } 58 | 59 | public static class CsvReportVisitor extends AbstractTimerVisitor { 60 | private PrintWriter printWriter; 61 | 62 | public CsvReportVisitor(PrintWriter printWriter) { 63 | this.printWriter = printWriter; 64 | } 65 | 66 | @Override 67 | public void visit(MojoTimer mojoTimer) { 68 | printWriter.format(Locale.ENGLISH, "\"%s\";\"%s\";\"%.3f\";\"%d\";\"%d\"%n", 69 | mojoTimer.getProjectName(), mojoTimer.getName(), mojoTimer.getDuration() / 1000d, mojoTimer.getStartTime(), mojoTimer.getEndTime()); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/output/LogReporter.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime.output; 2 | 3 | import java.util.Locale; 4 | 5 | import org.apache.maven.execution.ExecutionEvent; 6 | import org.codehaus.plexus.util.StringUtils; 7 | import org.slf4j.Logger; 8 | 9 | import co.leantechniques.maven.buildtime.AbstractTimerVisitor; 10 | import co.leantechniques.maven.buildtime.Constants; 11 | import co.leantechniques.maven.buildtime.LogOutput; 12 | import co.leantechniques.maven.buildtime.MavenHelper; 13 | import co.leantechniques.maven.buildtime.MojoTimer; 14 | import co.leantechniques.maven.buildtime.ProjectTimer; 15 | import co.leantechniques.maven.buildtime.SessionTimer; 16 | 17 | public class LogReporter implements Reporter { 18 | 19 | public static final int MAX_NAME_LENGTH = 58; 20 | 21 | public static final String DIVIDER = "------------------------------------------------------------------------"; 22 | 23 | public void performReport(Logger logger, ExecutionEvent event, SessionTimer session) { 24 | LogOutput logOutput = new LogOutput(logger, Boolean.parseBoolean( 25 | MavenHelper.getExecutionProperty(event, Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "false"))); 26 | 27 | session.accept(new LogReportVisitor(logOutput)); 28 | } 29 | 30 | public static class LogReportVisitor extends AbstractTimerVisitor { 31 | 32 | private LogOutput logOutput; 33 | 34 | public LogReportVisitor(LogOutput logOutput) { 35 | this.logOutput = logOutput; 36 | } 37 | 38 | @Override 39 | public void visit(SessionTimer sessionTimer) { 40 | logOutput.log(DIVIDER); 41 | logOutput.log("Build Time Summary:"); 42 | logOutput.log(DIVIDER); 43 | } 44 | 45 | @Override 46 | public void visit(ProjectTimer projectTimer) { 47 | logOutput.log(String.format(Locale.ENGLISH, "%s [%.3fs]", projectTimer.getProjectName(), projectTimer.getDuration() / 1000d)); 48 | } 49 | 50 | @Override 51 | public void visit(MojoTimer mojoTimer) { 52 | // 68 char width: coefficient-core .................................. SUCCESS [0.846s] 53 | logOutput.log(String.format(Locale.ENGLISH, " %s [%.3fs]", 54 | getDisplayName(mojoTimer.getName()), mojoTimer.getDuration() / 1000d)); 55 | } 56 | 57 | private String getDisplayName(String name) { 58 | String truncatedName = name.length() >= MAX_NAME_LENGTH ? 59 | StringUtils.substring(name, 0, MAX_NAME_LENGTH) : name + " "; 60 | return StringUtils.rightPad(truncatedName, MAX_NAME_LENGTH, "."); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/co/leantechniques/maven/buildtime/output/Reporter.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime.output; 2 | 3 | import org.apache.maven.execution.ExecutionEvent; 4 | import org.slf4j.Logger; 5 | 6 | import co.leantechniques.maven.buildtime.SessionTimer; 7 | 8 | public interface Reporter { 9 | void performReport(Logger logger, ExecutionEvent event, SessionTimer session); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/apache/maven/cli/BuildTimeEventSpy.java: -------------------------------------------------------------------------------- 1 | package org.apache.maven.cli; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import org.apache.maven.eventspy.AbstractEventSpy; 7 | import org.apache.maven.eventspy.EventSpy; 8 | import org.apache.maven.execution.ExecutionEvent; 9 | import org.codehaus.plexus.component.annotations.Component; 10 | import org.codehaus.plexus.component.annotations.Requirement; 11 | import org.slf4j.Logger; 12 | 13 | import co.leantechniques.maven.buildtime.SessionTimer; 14 | import co.leantechniques.maven.buildtime.output.CsvReporter; 15 | import co.leantechniques.maven.buildtime.output.LogReporter; 16 | import co.leantechniques.maven.buildtime.output.Reporter; 17 | 18 | @Component(role = EventSpy.class, hint = "timing") 19 | public class BuildTimeEventSpy extends AbstractEventSpy { 20 | 21 | @Requirement 22 | private Logger logger; 23 | 24 | private List reporters; 25 | 26 | public BuildTimeEventSpy(Logger logger, Reporter... reporters) { 27 | this.logger = logger; 28 | this.reporters = Arrays.asList(reporters); 29 | } 30 | 31 | public BuildTimeEventSpy() { 32 | reporters = Arrays.asList(new LogReporter(), new CsvReporter()); 33 | } 34 | 35 | private final SessionTimer session = new SessionTimer(); 36 | 37 | @Override 38 | public void init(Context context) throws Exception { 39 | super.init(context); 40 | logger.info("BuildTimeEventSpy is registered."); 41 | } 42 | 43 | @Override 44 | public void onEvent(Object event) throws Exception { 45 | if (event instanceof ExecutionEvent) { 46 | onEvent((ExecutionEvent) event); 47 | } 48 | } 49 | 50 | private void onEvent(ExecutionEvent event) throws Exception { 51 | switch (event.getType()) { 52 | case MojoStarted: 53 | session.mojoStarted(event.getProject(), event.getMojoExecution()); 54 | break; 55 | 56 | case MojoFailed: 57 | session.mojoFailed(event.getProject(), event.getMojoExecution()); 58 | break; 59 | 60 | case MojoSucceeded: 61 | session.mojoSucceeded(event.getProject(), event.getMojoExecution()); 62 | break; 63 | 64 | case SessionEnded: 65 | doReport(event); 66 | break; 67 | 68 | default: 69 | //Ignore other events 70 | } 71 | } 72 | 73 | @Override 74 | public void close() throws Exception { 75 | super.close(); 76 | } 77 | 78 | 79 | private void doReport(ExecutionEvent event) { 80 | for (Reporter reporter : reporters) { 81 | reporter.performReport(logger, event, session); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/co/leantechniques/maven/buildtime/MavenHelperTest.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.mockito.Mockito.when; 5 | 6 | import java.util.Properties; 7 | 8 | import org.apache.maven.execution.ExecutionEvent; 9 | import org.apache.maven.execution.MavenSession; 10 | import org.apache.maven.project.MavenProject; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.mockito.Mock; 15 | import org.mockito.junit.MockitoJUnitRunner; 16 | 17 | @RunWith(MockitoJUnitRunner.class) 18 | public class MavenHelperTest { 19 | 20 | @Mock 21 | private ExecutionEvent sessionEndEvent; 22 | 23 | @Mock 24 | private MavenSession session; 25 | 26 | @Before 27 | public void setUp() throws Exception { 28 | when( sessionEndEvent.getSession() ).thenReturn( session ); 29 | } 30 | 31 | @Test 32 | public void testPropertyPriorityUser() throws Exception { 33 | Properties systemProperties = new Properties(); 34 | systemProperties.setProperty( Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "systemProperty" ); 35 | MavenProject mavenProject = new MavenProject(); 36 | mavenProject.getProperties().setProperty( Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "projectProperty" ); 37 | Properties userProperties = new Properties(); 38 | userProperties.setProperty( Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "userProperty" ); 39 | 40 | when( session.getSystemProperties() ).thenReturn( systemProperties ); 41 | when( session.getUserProperties() ).thenReturn( userProperties ); 42 | when( session.getTopLevelProject() ).thenReturn( mavenProject ); 43 | 44 | assertEquals( "userProperty", MavenHelper.getExecutionProperty( sessionEndEvent, Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "default" ) ); 45 | } 46 | 47 | @Test 48 | public void testPropertyPriorityProject() throws Exception { 49 | Properties systemProperties = new Properties(); 50 | systemProperties.setProperty( Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "systemProperty" ); 51 | MavenProject mavenProject = new MavenProject(); 52 | mavenProject.getProperties().setProperty( Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "projectProperty" ); 53 | Properties userProperties = new Properties(); 54 | 55 | when( session.getSystemProperties() ).thenReturn( systemProperties ); 56 | when( session.getUserProperties() ).thenReturn( userProperties ); 57 | when( session.getTopLevelProject() ).thenReturn( mavenProject ); 58 | 59 | assertEquals( "projectProperty", MavenHelper.getExecutionProperty( sessionEndEvent, Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "default" ) ); 60 | } 61 | 62 | 63 | @Test 64 | public void testPropertyPrioritySystem() throws Exception { 65 | Properties systemProperties = new Properties(); 66 | systemProperties.setProperty( Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "systemProperty" ); 67 | MavenProject mavenProject = new MavenProject(); 68 | Properties userProperties = new Properties(); 69 | 70 | when( session.getSystemProperties() ).thenReturn( systemProperties ); 71 | when( session.getUserProperties() ).thenReturn( userProperties ); 72 | when( session.getTopLevelProject() ).thenReturn( mavenProject ); 73 | 74 | assertEquals( "systemProperty", MavenHelper.getExecutionProperty( sessionEndEvent, Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "default" ) ); 75 | } 76 | 77 | @Test 78 | public void testPropertyPriorityDefault() throws Exception { 79 | Properties systemProperties = new Properties(); 80 | MavenProject mavenProject = new MavenProject(); 81 | Properties userProperties = new Properties(); 82 | 83 | when( session.getSystemProperties() ).thenReturn( systemProperties ); 84 | when( session.getUserProperties() ).thenReturn( userProperties ); 85 | when( session.getTopLevelProject() ).thenReturn( mavenProject ); 86 | 87 | assertEquals( "default", MavenHelper.getExecutionProperty( sessionEndEvent, Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "default" ) ); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/co/leantechniques/maven/buildtime/MojoExecutionNameTest.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import org.apache.maven.model.Plugin; 4 | import org.apache.maven.plugin.MojoExecution; 5 | import org.junit.Test; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | 9 | public class MojoExecutionNameTest { 10 | 11 | @Test 12 | public void getName() throws Exception { 13 | Plugin plugin = new Plugin(); 14 | plugin.setArtifactId("artifact"); 15 | MojoExecution execution = new MojoExecution(plugin, "goal", "id"); 16 | 17 | MojoExecutionName executionName = new MojoExecutionName(execution); 18 | 19 | assertEquals("artifact:goal (id)", executionName.getName()); 20 | } 21 | } -------------------------------------------------------------------------------- /src/test/java/co/leantechniques/maven/buildtime/MojoTimerTest.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import static org.mockito.Mockito.verify; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.Mock; 9 | import org.mockito.junit.MockitoJUnitRunner; 10 | import org.slf4j.Logger; 11 | 12 | import co.leantechniques.maven.buildtime.output.LogReporter; 13 | 14 | @RunWith(MockitoJUnitRunner.class) 15 | public class MojoTimerTest { 16 | @Mock 17 | private Logger logger; 18 | 19 | private LogOutput logOutput; 20 | LogReporter.LogReportVisitor reportVisitor; 21 | 22 | @Before 23 | public void setUp() { 24 | logOutput = new LogOutput(logger, true); 25 | reportVisitor = new LogReporter.LogReportVisitor(logOutput); 26 | } 27 | 28 | @Test 29 | public void outputWithSubsecond() { 30 | new MojoTimer("proj", "1234567890", 100,200).accept(reportVisitor); 31 | 32 | //coefficient-core .................................. SUCCESS [0.846s] 33 | //coefficient-core .................................. SUCCESS [100.846s] 34 | verify(logger).info(" 1234567890 ............................................... [0.100s]"); 35 | } 36 | 37 | @Test 38 | public void outputWith100Seconds() { 39 | new MojoTimer("proj", "1234567890", 0,100100).accept(reportVisitor); 40 | verify(logger).info(" 1234567890 ............................................... [100.100s]"); 41 | } 42 | 43 | @Test 44 | public void outputWithLongPluginName() { 45 | new MojoTimer("proj", "Some really long project name", 0,100100).accept(reportVisitor); 46 | verify(logger).info(" Some really long project name ............................ [100.100s]"); 47 | } 48 | 49 | 50 | @Test 51 | public void outputToDebug() { 52 | logOutput = new LogOutput(logger, false); 53 | reportVisitor = new LogReporter.LogReportVisitor(logOutput); 54 | new MojoTimer("proj", "Some really long project name", 0,100100).accept(reportVisitor); 55 | verify(logger).debug(" Some really long project name ............................ [100.100s]"); 56 | } 57 | 58 | @Test 59 | public void outputWithNameAtTheMaxLength() { 60 | new MojoTimer("proj", "Some really, really, really, really, long project name", 0,100100).accept(reportVisitor); 61 | verify(logger).info(" Some really, really, really, really, long project name [100.100s]"); 62 | } 63 | 64 | @Test 65 | public void outputWithNameOverTheMaxLength() { 66 | new MojoTimer("proj", "Some really, really, really, really, really, long project name", 0,100100).accept(reportVisitor); 67 | verify(logger).info(" Some really, really, really, really, really, long pro [100.100s]"); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/co/leantechniques/maven/buildtime/SessionTimerTest.java: -------------------------------------------------------------------------------- 1 | package co.leantechniques.maven.buildtime; 2 | 3 | import static junit.framework.Assert.assertEquals; 4 | import static junit.framework.Assert.assertNotNull; 5 | import static junit.framework.Assert.assertSame; 6 | import static org.mockito.Mockito.inOrder; 7 | import static org.mockito.Mockito.mock; 8 | import static org.mockito.Mockito.when; 9 | 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.PrintWriter; 12 | import java.util.Properties; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | import java.util.concurrent.ConcurrentMap; 15 | 16 | import org.apache.maven.execution.ExecutionEvent; 17 | import org.apache.maven.execution.MavenSession; 18 | import org.apache.maven.model.Plugin; 19 | import org.apache.maven.plugin.MojoExecution; 20 | import org.apache.maven.project.MavenProject; 21 | import org.junit.Assert; 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | import org.mockito.InOrder; 26 | import org.mockito.Mock; 27 | import org.mockito.junit.MockitoJUnitRunner; 28 | import org.slf4j.Logger; 29 | 30 | import co.leantechniques.maven.buildtime.output.CsvReporter; 31 | import co.leantechniques.maven.buildtime.output.LogReporter; 32 | 33 | @RunWith(MockitoJUnitRunner.class) 34 | public class SessionTimerTest { 35 | 36 | private static final String CSV_HEADERS = "\"Module\";\"Mojo\";\"Time\";\"Start\";\"End\""; 37 | 38 | private ConcurrentMap existingProjects; 39 | private SessionTimer sessionTimer; 40 | private ProjectTimer oneProject; 41 | private ProjectTimer anotherProject; 42 | private ConcurrentMap mojoTiming; 43 | private ConcurrentMap anotherMojoTiming; 44 | 45 | @Mock 46 | private Logger logger; 47 | 48 | @Mock 49 | private ExecutionEvent sessionEndEvent; 50 | 51 | @Mock 52 | private MavenSession session; 53 | 54 | private CsvReporter csvReporter; 55 | private LogReporter logReporter; 56 | private MojoExecution mojoExecution; 57 | private MavenProject project; 58 | private PrintWriter printWriter; 59 | 60 | private ByteArrayOutputStream outputStream; 61 | 62 | private Properties userProperties = new Properties(); 63 | 64 | private Properties systemProperties = new Properties(); 65 | 66 | @Before 67 | public void setUp() throws Exception { 68 | logReporter = new LogReporter(); 69 | csvReporter = new CsvReporter(); 70 | existingProjects = new ConcurrentHashMap(); 71 | SystemClock mockClock = mock(SystemClock.class); 72 | when(mockClock.currentTimeMillis()) 73 | .thenReturn(100L) 74 | .thenReturn(200L); 75 | 76 | sessionTimer = new SessionTimer(existingProjects, mockClock); 77 | 78 | mojoTiming = new ConcurrentHashMap(); 79 | anotherMojoTiming = new ConcurrentHashMap(); 80 | oneProject = new ProjectTimer("one", mojoTiming, mockClock); 81 | anotherProject = new ProjectTimer("two", anotherMojoTiming, mockClock); 82 | mojoExecution = createMojoExecution(); 83 | project = createMavenProject(); 84 | outputStream = new ByteArrayOutputStream(); 85 | printWriter = new PrintWriter(outputStream); 86 | 87 | userProperties.setProperty(Constants.BUILDTIME_OUTPUT_LOG_PROPERTY, "true"); 88 | when(sessionEndEvent.getSession()).thenReturn(session); 89 | when(session.getSystemProperties()).thenReturn(systemProperties); 90 | when(session.getUserProperties()).thenReturn(userProperties); 91 | } 92 | 93 | @Test 94 | public void getProjectReturnsNewWhenNotExists(){ 95 | ProjectTimer actual = sessionTimer.getProject("not existing"); 96 | 97 | assertNotNull(actual); 98 | } 99 | 100 | @Test 101 | public void getProjectReturnsSameWhenExists() { 102 | existingProjects.put("one", oneProject); 103 | 104 | ProjectTimer actual = sessionTimer.getProject("one"); 105 | 106 | assertSame(oneProject, actual); 107 | } 108 | 109 | @Test 110 | public void writeOneProjectWithOnePlugin() { 111 | MojoTimer goal1Timer = new MojoTimer("one", "artifactId:goal1", 1, 2); 112 | MojoTimer goal2Timer = new MojoTimer("one", "artifactId:goal2", 2, 4); 113 | mojoTiming.put(goal1Timer.getName(), goal1Timer); 114 | mojoTiming.put(goal2Timer.getName(), goal2Timer); 115 | 116 | existingProjects.put("one", oneProject); 117 | 118 | logReporter.performReport(logger, sessionEndEvent, sessionTimer); 119 | 120 | String dividerLine = LogReporter.DIVIDER; 121 | 122 | InOrder inOrder = inOrder(logger); 123 | inOrder.verify(logger).info(dividerLine); 124 | inOrder.verify(logger).info("Build Time Summary:"); 125 | inOrder.verify(logger).info(dividerLine); 126 | inOrder.verify(logger).info("one [0.003s]"); 127 | inOrder.verify(logger).info(" artifactId:goal1 ......................................... [0.001s]"); 128 | inOrder.verify(logger).info(" artifactId:goal2 ......................................... [0.002s]"); 129 | } 130 | 131 | @Test 132 | public void testResultsOrderedByStartTime() { 133 | MojoTimer goal1Timer = new MojoTimer("one", "artifactId:goal1", 2, 5); 134 | MojoTimer goal2Timer = new MojoTimer("one", "artifactId:goal2", 1, 3); 135 | mojoTiming.put(goal1Timer.getName(), goal1Timer); 136 | mojoTiming.put(goal2Timer.getName(), goal2Timer); 137 | 138 | existingProjects.put("one", oneProject); 139 | 140 | logReporter.performReport(logger, sessionEndEvent, sessionTimer); 141 | 142 | String dividerLine = LogReporter.DIVIDER; 143 | 144 | InOrder inOrder = inOrder(logger); 145 | inOrder.verify(logger).info(dividerLine); 146 | inOrder.verify(logger).info("Build Time Summary:"); 147 | inOrder.verify(logger).info(dividerLine); 148 | inOrder.verify(logger).info("one [0.004s]"); 149 | inOrder.verify(logger).info(" artifactId:goal2 ......................................... [0.002s]"); 150 | inOrder.verify(logger).info(" artifactId:goal1 ......................................... [0.003s]"); 151 | } 152 | 153 | @Test 154 | public void writeToOneProjectWithOnePlugin() { 155 | MojoTimer goal1Timer = new MojoTimer("one", "artifactId:goal1", 1, 2); 156 | MojoTimer goal2Timer = new MojoTimer("one", "artifactId:goal2", 2, 4); 157 | mojoTiming.put(goal1Timer.getName(), goal1Timer); 158 | mojoTiming.put(goal2Timer.getName(), goal2Timer); 159 | 160 | existingProjects.put("one", oneProject); 161 | 162 | csvReporter.writeTo(sessionTimer, printWriter); 163 | 164 | printWriter.flush(); 165 | String output = outputStream.toString(); 166 | String[] split = output.split("\r?\n"); 167 | 168 | Assert.assertEquals(split[0], CSV_HEADERS); 169 | Assert.assertEquals(split[1], "\"one\";\"artifactId:goal1\";\"0.001\";\"1\";\"2\""); 170 | Assert.assertEquals(split[2], "\"one\";\"artifactId:goal2\";\"0.002\";\"2\";\"4\""); 171 | Assert.assertEquals(split.length, 3); 172 | } 173 | 174 | @Test 175 | public void testThatProjectsAreOrderedByStartTime() { 176 | MojoTimer goal1Timer = new MojoTimer("one", "artifactId:goal1", 6, 9); 177 | MojoTimer goal2Timer = new MojoTimer("one", "artifactId:goal2", 5, 7); 178 | mojoTiming.put(goal1Timer.getName(), goal1Timer); 179 | mojoTiming.put(goal2Timer.getName(), goal2Timer); 180 | 181 | existingProjects.put("one", oneProject); 182 | 183 | MojoTimer goal3Timer = new MojoTimer("two", "artifactId:goal3", 1, 2); 184 | MojoTimer goal4Timer = new MojoTimer("two", "artifactId:goal4", 2, 4); 185 | anotherMojoTiming.put(goal3Timer.getName(), goal3Timer); 186 | anotherMojoTiming.put(goal4Timer.getName(), goal4Timer); 187 | 188 | existingProjects.put("two", anotherProject); 189 | 190 | csvReporter.writeTo(sessionTimer, printWriter); 191 | 192 | printWriter.flush(); 193 | String output = outputStream.toString(); 194 | String[] split = output.split("\r?\n"); 195 | 196 | Assert.assertEquals(split[0], CSV_HEADERS); 197 | Assert.assertEquals(split[1], "\"two\";\"artifactId:goal3\";\"0.001\";\"1\";\"2\""); 198 | Assert.assertEquals(split[2], "\"two\";\"artifactId:goal4\";\"0.002\";\"2\";\"4\""); 199 | Assert.assertEquals(split[3], "\"one\";\"artifactId:goal2\";\"0.002\";\"5\";\"7\""); 200 | Assert.assertEquals(split[4], "\"one\";\"artifactId:goal1\";\"0.003\";\"6\";\"9\""); 201 | Assert.assertEquals(split.length, 5); 202 | } 203 | 204 | @Test 205 | public void successfulMojoShouldStopTimer(){ 206 | sessionTimer.mojoStarted(project, mojoExecution); 207 | sessionTimer.mojoSucceeded(project, mojoExecution); 208 | 209 | MojoTimer mojoTimer = sessionTimer.getMojoTimer(project, mojoExecution); 210 | 211 | assertEquals(new Long(100), mojoTimer.getDuration()); 212 | } 213 | 214 | @Test 215 | public void failureMojoShouldStopTimer(){ 216 | sessionTimer.mojoStarted(project, mojoExecution); 217 | sessionTimer.mojoFailed(project, mojoExecution); 218 | 219 | MojoTimer mojoTimer = sessionTimer.getMojoTimer(project, mojoExecution); 220 | 221 | assertEquals(new Long(100), mojoTimer.getDuration()); 222 | } 223 | 224 | private MojoExecution createMojoExecution() { 225 | Plugin plugin = new Plugin(); 226 | plugin.setArtifactId("plugin"); 227 | return new MojoExecution(plugin, "goal", "executionId"); 228 | } 229 | 230 | private MavenProject createMavenProject() { 231 | MavenProject project = new MavenProject(); 232 | project.setArtifactId("maven-project-artifact"); 233 | return project; 234 | } 235 | 236 | } 237 | -------------------------------------------------------------------------------- /src/test/java/org/apache/maven/cli/BuildTimeEventSpyTest.java: -------------------------------------------------------------------------------- 1 | package org.apache.maven.cli; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertTrue; 5 | import static org.mockito.Mockito.mock; 6 | import static org.mockito.Mockito.when; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.util.List; 11 | import java.util.Properties; 12 | import java.util.regex.Pattern; 13 | 14 | import org.apache.maven.execution.ExecutionEvent; 15 | import org.apache.maven.execution.MavenSession; 16 | import org.apache.maven.model.Plugin; 17 | import org.apache.maven.plugin.MojoExecution; 18 | import org.apache.maven.project.MavenProject; 19 | import org.codehaus.plexus.util.FileUtils; 20 | import org.junit.Before; 21 | import org.junit.Rule; 22 | import org.junit.Test; 23 | import org.junit.rules.TemporaryFolder; 24 | import org.junit.runner.RunWith; 25 | import org.mockito.Mock; 26 | import org.mockito.junit.MockitoJUnitRunner; 27 | import org.slf4j.Logger; 28 | 29 | import co.leantechniques.maven.buildtime.Constants; 30 | import co.leantechniques.maven.buildtime.output.CsvReporter; 31 | import co.leantechniques.maven.buildtime.output.LogReporter; 32 | 33 | @RunWith(MockitoJUnitRunner.class) 34 | public class BuildTimeEventSpyTest { 35 | 36 | private static final String CSV_HEADERS = "\"Module\";\"Mojo\";\"Time\";\"Start\";\"End\""; 37 | 38 | @Mock 39 | private Logger logger; 40 | 41 | @Mock 42 | private ExecutionEvent sessionEndEvent; 43 | 44 | @Mock 45 | private MavenSession session; 46 | 47 | private Properties userProperties = new Properties(); 48 | 49 | private Properties systemProperties = new Properties(); 50 | 51 | @Rule 52 | public TemporaryFolder temporaryFolder = new TemporaryFolder(); 53 | 54 | 55 | private BuildTimeEventSpy subject; 56 | 57 | private File testFile; 58 | 59 | @Before 60 | public void setUp() throws IOException { 61 | subject = new BuildTimeEventSpy(logger, new LogReporter(), new CsvReporter()); 62 | 63 | testFile = new File(temporaryFolder.getRoot(), "test.csv"); 64 | userProperties.setProperty(Constants.BUILDTIME_OUTPUT_CSV_FILE_PROPERTY, 65 | testFile.getAbsolutePath()); 66 | userProperties.setProperty(Constants.BUILDTIME_OUTPUT_CSV_PROPERTY, "true"); 67 | 68 | when(sessionEndEvent.getSession()).thenReturn(session); 69 | when(session.getSystemProperties()).thenReturn(systemProperties); 70 | when(session.getUserProperties()).thenReturn(userProperties); 71 | when(sessionEndEvent.getType()).thenReturn(ExecutionEvent.Type.SessionEnded); 72 | } 73 | 74 | @Test 75 | public void testCsvHeaderOutput() throws Exception { 76 | subject.onEvent(sessionEndEvent); 77 | 78 | assertTrue(testFile.exists()); 79 | List lines = FileUtils.loadFile(testFile); 80 | assertEquals(CSV_HEADERS, lines.get(0)); 81 | } 82 | 83 | 84 | @Test 85 | public void testCsvEntries() throws Exception { 86 | ExecutionEvent mojo = mock(ExecutionEvent.class); 87 | when(mojo.getProject()).thenReturn(createMavenProject()); 88 | when(mojo.getMojoExecution()).thenReturn(createMojoExecution()); 89 | when(mojo.getType()).thenReturn(ExecutionEvent.Type.MojoStarted); 90 | when(mojo.getType()).thenReturn(ExecutionEvent.Type.MojoSucceeded); 91 | 92 | subject.onEvent(mojo); 93 | subject.onEvent(mojo); 94 | subject.onEvent(sessionEndEvent); 95 | 96 | assertTrue(testFile.exists()); 97 | List lines = FileUtils.loadFile(testFile); 98 | assertEquals(CSV_HEADERS, lines.get(0)); 99 | 100 | String[] split = lines.get(1).split(";"); 101 | 102 | assertEquals(5, split.length); 103 | assertEquals("\"maven-project-artifact\"", split[0]); 104 | assertEquals("\"plugin:goal (executionId)\"", split[1]); 105 | assertTrue(Pattern.matches("\"\\d+\\.\\d+\"", split[2])); 106 | assertTrue(Pattern.matches("\"\\d+\"", split[3])); 107 | assertTrue(Pattern.matches("\"\\d+\"", split[4])); 108 | 109 | } 110 | 111 | private MojoExecution createMojoExecution() { 112 | Plugin plugin = new Plugin(); 113 | plugin.setArtifactId("plugin"); 114 | return new MojoExecution(plugin, "goal", "executionId"); 115 | } 116 | 117 | private MavenProject createMavenProject() { 118 | MavenProject project = new MavenProject(); 119 | project.setArtifactId("maven-project-artifact"); 120 | return project; 121 | } 122 | } 123 | --------------------------------------------------------------------------------