diff --git a/maven-wrapper/.gitignore b/maven-wrapper/.gitignore new file mode 100644 index 0000000000..114ff4f92a --- /dev/null +++ b/maven-wrapper/.gitignore @@ -0,0 +1,3 @@ +.classpath +.project +.settings \ No newline at end of file diff --git a/maven-wrapper/maven/wrapper/maven-wrapper.jar b/maven-wrapper/maven/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000..593b7af788 Binary files /dev/null and b/maven-wrapper/maven/wrapper/maven-wrapper.jar differ diff --git a/maven-wrapper/maven/wrapper/maven-wrapper.properties b/maven-wrapper/maven/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..10dcf5fd65 --- /dev/null +++ b/maven-wrapper/maven/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repository.apache.org/content/repositories/releases/org/apache/maven/apache-maven/3.0.5/apache-maven-3.0.5-bin.zip \ No newline at end of file diff --git a/maven-wrapper/mvnw b/maven-wrapper/mvnw new file mode 100755 index 0000000000..c03152e1bf --- /dev/null +++ b/maven-wrapper/mvnw @@ -0,0 +1,170 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + if [ -z "$JAVA_VERSION" ] ; then + JAVA_VERSION="CurrentJDK" + fi + if [ -z "$JAVA_HOME" ] ; then + JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" -a ! "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + javaExecutable="`readlink -f \"$javaExecutable\"`" + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." + echo " We cannot execute $JAVACMD" + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` +fi + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "./maven/wrapper/maven-wrapper.jar" \ + ${WRAPPER_LAUNCHER} "$@" diff --git a/maven-wrapper/mvnw.bat b/maven-wrapper/mvnw.bat new file mode 100644 index 0000000000..ab2822dd77 --- /dev/null +++ b/maven-wrapper/mvnw.bat @@ -0,0 +1,189 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +:skipRcPre + +set ERROR_CODE=0 + +@REM set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" @setlocal +if "%OS%"=="WINNT" @setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo ERROR: JAVA_HOME not found in your environment. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto chkMHome + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory. +echo JAVA_HOME = "%JAVA_HOME%" +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation +echo. +goto error + +:chkMHome +if not "%M2_HOME%"=="" goto valMHome + +if "%OS%"=="Windows_NT" SET "M2_HOME=%~dp0.." +if "%OS%"=="WINNT" SET "M2_HOME=%~dp0.." +if not "%M2_HOME%"=="" goto valMHome + +echo. +echo ERROR: M2_HOME not found in your environment. +echo Please set the M2_HOME variable in your environment to match the +echo location of the Maven installation +echo. +goto error + +:valMHome + +:stripMHome +if not "_%M2_HOME:~-1%"=="_\" goto checkMBat +set "M2_HOME=%M2_HOME:~0,-1%" +goto stripMHome + +:checkMBat +if exist "%M2_HOME%\bin\mvn.bat" goto init + +echo. +echo ERROR: M2_HOME is set to an invalid directory. +echo M2_HOME = "%M2_HOME%" +echo Please set the M2_HOME variable in your environment to match the +echo location of the Maven installation +echo. +goto error +@REM ==== END VALIDATION ==== + +:init +@REM Decide how to startup depending on the version of windows + +@REM -- Windows NT with Novell Login +if "%OS%"=="WINNT" goto WinNTNovell + +@REM -- Win98ME +if NOT "%OS%"=="Windows_NT" goto Win9xArg + +:WinNTNovell + +@REM -- 4NT shell +if "%@eval[2+2]" == "4" goto 4NTArgs + +@REM -- Regular WinNT shell +set MAVEN_CMD_LINE_ARGS=%* +goto endInit + +@REM The 4NT Shell from jp software +:4NTArgs +set MAVEN_CMD_LINE_ARGS=%$ +goto endInit + +:Win9xArg +@REM Slurp the command line arguments. This loop allows for an unlimited number +@REM of agruments (up to the command line limit, anyway). +set MAVEN_CMD_LINE_ARGS= +:Win9xApp +if %1a==a goto endInit +set MAVEN_CMD_LINE_ARGS=%MAVEN_CMD_LINE_ARGS% %1 +shift +goto Win9xApp + +@REM Reaching here means variables are defined and arguments have been captured +:endInit +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +@REM -- Regular WinNT shell +set WRAPPER_JAR="".\maven\wrapper\maven-wrapper.jar"" +goto runm2 + +@REM Start MAVEN2 +:runm2 +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +%MAVEN_JAVA_EXE% %MAVEN_OPTS% -classpath %WRAPPER_JAR% %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% +if ERRORLEVEL 1 goto error +goto end + +:error +if "%OS%"=="Windows_NT" @endlocal +if "%OS%"=="WINNT" @endlocal +set ERROR_CODE=1 + +:end +@REM set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" goto endNT +if "%OS%"=="WINNT" goto endNT + +@REM For old DOS remove the set variables from ENV - we assume they were not set +@REM before we started - at least we don't leave any baggage around +set MAVEN_JAVA_EXE= +set MAVEN_CMD_LINE_ARGS= +goto postExec + +:endNT +@endlocal & set ERROR_CODE=%ERROR_CODE% + +:postExec + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +:skipRcPost + +@REM pause the batch file if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% + + diff --git a/maven-wrapper/pom.xml b/maven-wrapper/pom.xml new file mode 100644 index 0000000000..4293959e9a --- /dev/null +++ b/maven-wrapper/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + + maven-parent + org.apache.maven + 23 + + maven-wapper + 0.0.1-SNAPSHOT + Maven Wrapper + + + + + junit + junit + 4.11 + test + + + org.hamcrest + hamcrest-all + 1.3 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + + commons-lang + commons-lang + 2.6 + test + + + commons-io + commons-io + 2.4 + test + + + + + ant + ant + 1.7.0 + test + + + + \ No newline at end of file diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/BootstrapMainStarter.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/BootstrapMainStarter.java new file mode 100644 index 0000000000..98efa97321 --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/BootstrapMainStarter.java @@ -0,0 +1,57 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper; + +import java.io.File; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * @author Hans Dockter + */ +public class BootstrapMainStarter +{ + public void start( String[] args, File mavenHome ) + throws Exception + { + File mavenJar = findLauncherJar( mavenHome ); + URLClassLoader contextClassLoader = + new URLClassLoader( new URL[] { mavenJar.toURI().toURL() }, ClassLoader.getSystemClassLoader().getParent() ); + Thread.currentThread().setContextClassLoader( contextClassLoader ); + Class mainClass = contextClassLoader.loadClass( "org.codehaus.plexus.classworlds.launcher.Launcher" ); + + System.setProperty( "maven.home", mavenHome.getAbsolutePath() ); + System.setProperty( "classworlds.conf", new File( mavenHome, "/bin/m2.conf" ).getAbsolutePath() ); + + Method mainMethod = mainClass.getMethod( "main", String[].class ); + mainMethod.invoke( null, new Object[] { args } ); + } + + private File findLauncherJar( File mavenHome ) + { + for ( File file : new File( mavenHome, "boot" ).listFiles() ) + { + if ( file.getName().matches( "plexus-classworlds-.*\\.jar" ) ) + { + return file; + } + } + throw new RuntimeException( + String.format( "Could not locate the Maven launcher JAR in Maven distribution '%s'.", + mavenHome ) ); + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/DefaultDownloader.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/DefaultDownloader.java new file mode 100644 index 0000000000..738911ce05 --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/DefaultDownloader.java @@ -0,0 +1,137 @@ +/* + * Copyright 2007-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.maven.wrapper; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Authenticator; +import java.net.PasswordAuthentication; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; + +/** + * @author Hans Dockter + */ +public class DefaultDownloader + implements Downloader +{ + private static final int PROGRESS_CHUNK = 20000; + + private static final int BUFFER_SIZE = 10000; + + private final String applicationName; + + private final String applicationVersion; + + public DefaultDownloader( String applicationName, String applicationVersion ) + { + this.applicationName = applicationName; + this.applicationVersion = applicationVersion; + configureProxyAuthentication(); + } + + private void configureProxyAuthentication() + { + if ( System.getProperty( "http.proxyUser" ) != null ) + { + Authenticator.setDefault( new SystemPropertiesProxyAuthenticator() ); + } + } + + public void download( URI address, File destination ) + throws Exception + { + if ( destination.exists() ) + { + return; + } + destination.getParentFile().mkdirs(); + + downloadInternal( address, destination ); + } + + private void downloadInternal( URI address, File destination ) + throws Exception + { + OutputStream out = null; + URLConnection conn; + InputStream in = null; + try + { + URL url = address.toURL(); + out = new BufferedOutputStream( new FileOutputStream( destination ) ); + conn = url.openConnection(); + final String userAgentValue = calculateUserAgent(); + conn.setRequestProperty( "User-Agent", userAgentValue ); + in = conn.getInputStream(); + byte[] buffer = new byte[BUFFER_SIZE]; + int numRead; + long progressCounter = 0; + while ( ( numRead = in.read( buffer ) ) != -1 ) + { + progressCounter += numRead; + if ( progressCounter / PROGRESS_CHUNK > 0 ) + { + System.out.print( "." ); + progressCounter = progressCounter - PROGRESS_CHUNK; + } + out.write( buffer, 0, numRead ); + } + } + finally + { + System.out.println( "" ); + if ( in != null ) + { + in.close(); + } + if ( out != null ) + { + out.close(); + } + } + } + + private String calculateUserAgent() + { + String appVersion = applicationVersion; + + String javaVendor = System.getProperty( "java.vendor" ); + String javaVersion = System.getProperty( "java.version" ); + String javaVendorVersion = System.getProperty( "java.vm.version" ); + String osName = System.getProperty( "os.name" ); + String osVersion = System.getProperty( "os.version" ); + String osArch = System.getProperty( "os.arch" ); + return String.format( "%s/%s (%s;%s;%s) (%s;%s;%s)", applicationName, appVersion, osName, osVersion, osArch, + javaVendor, javaVersion, javaVendorVersion ); + } + + private static class SystemPropertiesProxyAuthenticator + extends Authenticator + { + @Override + protected PasswordAuthentication getPasswordAuthentication() + { + return new PasswordAuthentication( System.getProperty( "http.proxyUser" ), + System.getProperty( "http.proxyPassword", "" ).toCharArray() ); + } + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/Downloader.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/Downloader.java new file mode 100644 index 0000000000..2b22cdb871 --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/Downloader.java @@ -0,0 +1,28 @@ +/* + * Copyright 2007-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper; + +import java.io.File; +import java.net.URI; + +/** + * @author Hans Dockter + */ +public interface Downloader +{ + void download( URI address, File destination ) + throws Exception; +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/Installer.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/Installer.java new file mode 100644 index 0000000000..6540545b33 --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/Installer.java @@ -0,0 +1,233 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.maven.wrapper; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.URI; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Formatter; +import java.util.List; +import java.util.Locale; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * @author Hans Dockter + */ +public class Installer +{ + public static final String DEFAULT_DISTRIBUTION_PATH = "wrapper/dists"; + + private final Downloader download; + + private final PathAssembler pathAssembler; + + public Installer( Downloader download, PathAssembler pathAssembler ) + { + this.download = download; + this.pathAssembler = pathAssembler; + } + + public File createDist( WrapperConfiguration configuration ) + throws Exception + { + URI distributionUrl = configuration.getDistribution(); + boolean alwaysDownload = configuration.isAlwaysDownload(); + boolean alwaysUnpack = configuration.isAlwaysUnpack(); + + PathAssembler.LocalDistribution localDistribution = pathAssembler.getDistribution( configuration ); + + File localZipFile = localDistribution.getZipFile(); + boolean downloaded = false; + if ( alwaysDownload || !localZipFile.exists() ) + { + File tmpZipFile = new File( localZipFile.getParentFile(), localZipFile.getName() + ".part" ); + tmpZipFile.delete(); + System.out.println( "Downloading " + distributionUrl ); + download.download( distributionUrl, tmpZipFile ); + tmpZipFile.renameTo( localZipFile ); + downloaded = true; + } + + File distDir = localDistribution.getDistributionDir(); + List dirs = listDirs( distDir ); + + if ( downloaded || alwaysUnpack || dirs.isEmpty() ) + { + for ( File dir : dirs ) + { + System.out.println( "Deleting directory " + dir.getAbsolutePath() ); + deleteDir( dir ); + } + System.out.println( "Unzipping " + localZipFile.getAbsolutePath() + " to " + distDir.getAbsolutePath() ); + unzip( localZipFile, distDir ); + dirs = listDirs( distDir ); + if ( dirs.isEmpty() ) + { + throw new RuntimeException( + String.format( "Maven distribution '%s' does not contain any directories. Expected to find exactly 1 directory.", + distributionUrl ) ); + } + setExecutablePermissions( dirs.get( 0 ) ); + } + if ( dirs.size() != 1 ) + { + throw new RuntimeException( + String.format( "Maven distribution '%s' contains too many directories. Expected to find exactly 1 directory.", + distributionUrl ) ); + } + return dirs.get( 0 ); + } + + private List listDirs( File distDir ) + { + List dirs = new ArrayList(); + if ( distDir.exists() ) + { + for ( File file : distDir.listFiles() ) + { + if ( file.isDirectory() ) + { + dirs.add( file ); + } + } + } + return dirs; + } + + private void setExecutablePermissions( File mavenHome ) + { + if ( isWindows() ) + { + return; + } + File mavenCommand = new File( mavenHome, "bin/mvn" ); + String errorMessage = null; + try + { + ProcessBuilder pb = new ProcessBuilder( "chmod", "755", mavenCommand.getCanonicalPath() ); + Process p = pb.start(); + if ( p.waitFor() == 0 ) + { + System.out.println( "Set executable permissions for: " + mavenCommand.getAbsolutePath() ); + } + else + { + BufferedReader is = new BufferedReader( new InputStreamReader( p.getInputStream() ) ); + Formatter stdout = new Formatter(); + String line; + while ( ( line = is.readLine() ) != null ) + { + stdout.format( "%s%n", line ); + } + errorMessage = stdout.toString(); + } + } + catch ( IOException e ) + { + errorMessage = e.getMessage(); + } + catch ( InterruptedException e ) + { + errorMessage = e.getMessage(); + } + if ( errorMessage != null ) + { + System.out.println( "Could not set executable permissions for: " + mavenCommand.getAbsolutePath() ); + System.out.println( "Please do this manually if you want to use maven." ); + } + } + + private boolean isWindows() + { + String osName = System.getProperty( "os.name" ).toLowerCase( Locale.US ); + if ( osName.indexOf( "windows" ) > -1 ) + { + return true; + } + return false; + } + + private boolean deleteDir( File dir ) + { + if ( dir.isDirectory() ) + { + String[] children = dir.list(); + for ( int i = 0; i < children.length; i++ ) + { + boolean success = deleteDir( new File( dir, children[i] ) ); + if ( !success ) + { + return false; + } + } + } + + // The directory is now empty so delete it + return dir.delete(); + } + + public void unzip( File zip, File dest ) + throws IOException + { + Enumeration entries; + ZipFile zipFile; + + zipFile = new ZipFile( zip ); + + entries = zipFile.entries(); + + while ( entries.hasMoreElements() ) + { + ZipEntry entry = (ZipEntry) entries.nextElement(); + + if ( entry.isDirectory() ) + { + ( new File( dest, entry.getName() ) ).mkdirs(); + continue; + } + + copyInputStream( zipFile.getInputStream( entry ), + new BufferedOutputStream( new FileOutputStream( new File( dest, entry.getName() ) ) ) ); + } + zipFile.close(); + } + + public void copyInputStream( InputStream in, OutputStream out ) + throws IOException + { + byte[] buffer = new byte[1024]; + int len; + + while ( ( len = in.read( buffer ) ) >= 0 ) + { + out.write( buffer, 0, len ); + } + + in.close(); + out.close(); + } + +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/MavenWrapperMain.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/MavenWrapperMain.java new file mode 100644 index 0000000000..86c1f06625 --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/MavenWrapperMain.java @@ -0,0 +1,152 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.maven.wrapper; + +import java.io.File; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Map; +import java.util.Properties; + +import org.apache.maven.wrapper.cli.CommandLineParser; +import org.apache.maven.wrapper.cli.SystemPropertiesCommandLineConverter; + +/** + * @author Hans Dockter + */ +public class MavenWrapperMain +{ + public static final String DEFAULT_MAVEN_USER_HOME = System.getProperty( "user.home" ) + "/.m2"; + + public static final String MAVEN_USER_HOME_PROPERTY_KEY = "maven.user.home"; + + public static final String MAVEN_USER_HOME_ENV_KEY = "MAVEN_USER_HOME"; + + public static void main( String[] args ) + throws Exception + { + File wrapperJar = wrapperJar(); + File propertiesFile = wrapperProperties( wrapperJar ); + File rootDir = rootDir( wrapperJar ); + + Properties systemProperties = System.getProperties(); + systemProperties.putAll( parseSystemPropertiesFromArgs( args ) ); + + addSystemProperties( rootDir ); + + WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile( propertiesFile, System.out ); + wrapperExecutor.execute( args, new Installer( new DefaultDownloader( "mvnw", wrapperVersion() ), + new PathAssembler( mavenUserHome() ) ), new BootstrapMainStarter() ); + } + + private static Map parseSystemPropertiesFromArgs( String[] args ) + { + SystemPropertiesCommandLineConverter converter = new SystemPropertiesCommandLineConverter(); + CommandLineParser commandLineParser = new CommandLineParser(); + converter.configure( commandLineParser ); + commandLineParser.allowUnknownOptions(); + return converter.convert( commandLineParser.parse( args ) ); + } + + private static void addSystemProperties( File rootDir ) + { + System.getProperties().putAll( SystemPropertiesHandler.getSystemProperties( new File( mavenUserHome(), + "maven.properties" ) ) ); + System.getProperties().putAll( SystemPropertiesHandler.getSystemProperties( new File( rootDir, + "maven.properties" ) ) ); + } + + private static File rootDir( File wrapperJar ) + { + return wrapperJar.getParentFile().getParentFile().getParentFile(); + } + + private static File wrapperProperties( File wrapperJar ) + { + return new File( wrapperJar.getParent(), wrapperJar.getName().replaceFirst( "\\.jar$", ".properties" ) ); + } + + private static File wrapperJar() + { + URI location; + try + { + location = MavenWrapperMain.class.getProtectionDomain().getCodeSource().getLocation().toURI(); + } + catch ( URISyntaxException e ) + { + throw new RuntimeException( e ); + } + if ( !location.getScheme().equals( "file" ) ) + { + throw new RuntimeException( + String.format( "Cannot determine classpath for wrapper Jar from codebase '%s'.", + location ) ); + } + return new File( location.getPath() ); + } + + static String wrapperVersion() + { + try + { + InputStream resourceAsStream = + MavenWrapperMain.class.getResourceAsStream( "/META-INF/maven/org.apache.maven/maven-wapper/pom.properties" ); + if ( resourceAsStream == null ) + { + throw new RuntimeException( "No maven properties found." ); + } + Properties mavenProperties = new Properties(); + try + { + mavenProperties.load( resourceAsStream ); + String version = mavenProperties.getProperty( "version" ); + if ( version == null ) + { + throw new RuntimeException( "No version number specified in build receipt resource." ); + } + return version; + } + finally + { + resourceAsStream.close(); + } + } + catch ( Exception e ) + { + throw new RuntimeException( "Could not determine wrapper version.", e ); + } + } + + private static File mavenUserHome() + { + String mavenUserHome = System.getProperty( MAVEN_USER_HOME_PROPERTY_KEY ); + if ( mavenUserHome != null ) + { + return new File( mavenUserHome ); + } + else if ( ( mavenUserHome = System.getenv( MAVEN_USER_HOME_ENV_KEY ) ) != null ) + { + return new File( mavenUserHome ); + } + else + { + return new File( DEFAULT_MAVEN_USER_HOME ); + } + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/PathAssembler.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/PathAssembler.java new file mode 100644 index 0000000000..03dd0c0c12 --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/PathAssembler.java @@ -0,0 +1,146 @@ +/* + * Copyright 2007-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper; + +import java.io.File; +import java.math.BigInteger; +import java.net.URI; +import java.security.MessageDigest; + +/** + * @author Hans Dockter + */ +public class PathAssembler +{ + public static final String MAVEN_USER_HOME_STRING = "MAVEN_USER_HOME"; + + public static final String PROJECT_STRING = "PROJECT"; + + private File mavenUserHome; + + public PathAssembler() + { + } + + public PathAssembler( File mavenUserHome ) + { + this.mavenUserHome = mavenUserHome; + } + + /** + * Determines the local locations for the distribution to use given the supplied configuration. + */ + public LocalDistribution getDistribution( WrapperConfiguration configuration ) + { + String baseName = getDistName( configuration.getDistribution() ); + String distName = removeExtension( baseName ); + String rootDirName = rootDirName( distName, configuration ); + File distDir = + new File( getBaseDir( configuration.getDistributionBase() ), configuration.getDistributionPath() + "/" + + rootDirName ); + File distZip = + new File( getBaseDir( configuration.getZipBase() ), configuration.getZipPath() + "/" + rootDirName + "/" + + baseName ); + return new LocalDistribution( distDir, distZip ); + } + + private String rootDirName( String distName, WrapperConfiguration configuration ) + { + String urlHash = getMd5Hash( configuration.getDistribution().toString() ); + return String.format( "%s/%s", distName, urlHash ); + } + + private String getMd5Hash( String string ) + { + try + { + MessageDigest messageDigest = MessageDigest.getInstance( "MD5" ); + byte[] bytes = string.getBytes(); + messageDigest.update( bytes ); + return new BigInteger( 1, messageDigest.digest() ).toString( 32 ); + } + catch ( Exception e ) + { + throw new RuntimeException( "Could not hash input string.", e ); + } + } + + private String removeExtension( String name ) + { + int p = name.lastIndexOf( "." ); + if ( p < 0 ) + { + return name; + } + return name.substring( 0, p ); + } + + private String getDistName( URI distUrl ) + { + String path = distUrl.getPath(); + int p = path.lastIndexOf( "/" ); + if ( p < 0 ) + { + return path; + } + return path.substring( p + 1 ); + } + + private File getBaseDir( String base ) + { + if ( base.equals( MAVEN_USER_HOME_STRING ) ) + { + return mavenUserHome; + } + else if ( base.equals( PROJECT_STRING ) ) + { + return new File( System.getProperty( "user.dir" ) ); + } + else + { + throw new RuntimeException( "Base: " + base + " is unknown" ); + } + } + + public class LocalDistribution + { + private final File distZip; + + private final File distDir; + + public LocalDistribution( File distDir, File distZip ) + { + this.distDir = distDir; + this.distZip = distZip; + } + + /** + * Returns the location to install the distribution into. + */ + public File getDistributionDir() + { + return distDir; + } + + /** + * Returns the location to install the distribution ZIP file to. + */ + public File getZipFile() + { + return distZip; + } + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/SystemPropertiesHandler.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/SystemPropertiesHandler.java new file mode 100644 index 0000000000..69fefff22e --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/SystemPropertiesHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Hans Dockter + */ +public class SystemPropertiesHandler +{ + + public static Map getSystemProperties( File propertiesFile ) + { + Map propertyMap = new HashMap(); + if ( !propertiesFile.isFile() ) + { + return propertyMap; + } + Properties properties = new Properties(); + try + { + FileInputStream inStream = new FileInputStream( propertiesFile ); + try + { + properties.load( inStream ); + } + finally + { + inStream.close(); + } + } + catch ( IOException e ) + { + throw new RuntimeException( "Error when loading properties file=" + propertiesFile, e ); + } + + Pattern pattern = Pattern.compile( "systemProp\\.(.*)" ); + for ( Object argument : properties.keySet() ) + { + Matcher matcher = pattern.matcher( argument.toString() ); + if ( matcher.find() ) + { + String key = matcher.group( 1 ); + if ( key.length() > 0 ) + { + propertyMap.put( key, properties.get( argument ).toString() ); + } + } + } + return propertyMap; + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/WrapperConfiguration.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/WrapperConfiguration.java new file mode 100644 index 0000000000..22ee7be6fc --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/WrapperConfiguration.java @@ -0,0 +1,109 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper; + +import java.net.URI; + +public class WrapperConfiguration +{ + public static final String ALWAYS_UNPACK_ENV = "MAVEN_WRAPPER_ALWAYS_UNPACK"; + + public static final String ALWAYS_DOWNLOAD_ENV = "MAVEN_WRAPPER_ALWAYS_DOWNLOAD"; + + private boolean alwaysUnpack = Boolean.parseBoolean( System.getenv( ALWAYS_UNPACK_ENV ) ); + + private boolean alwaysDownload = Boolean.parseBoolean( System.getenv( ALWAYS_DOWNLOAD_ENV ) ); + + private URI distribution; + + private String distributionBase = PathAssembler.MAVEN_USER_HOME_STRING; + + private String distributionPath = Installer.DEFAULT_DISTRIBUTION_PATH; + + private String zipBase = PathAssembler.MAVEN_USER_HOME_STRING; + + private String zipPath = Installer.DEFAULT_DISTRIBUTION_PATH; + + public boolean isAlwaysDownload() + { + return alwaysDownload; + } + + public void setAlwaysDownload( boolean alwaysDownload ) + { + this.alwaysDownload = alwaysDownload; + } + + public boolean isAlwaysUnpack() + { + return alwaysUnpack; + } + + public void setAlwaysUnpack( boolean alwaysUnpack ) + { + this.alwaysUnpack = alwaysUnpack; + } + + public URI getDistribution() + { + return distribution; + } + + public void setDistribution( URI distribution ) + { + this.distribution = distribution; + } + + public String getDistributionBase() + { + return distributionBase; + } + + public void setDistributionBase( String distributionBase ) + { + this.distributionBase = distributionBase; + } + + public String getDistributionPath() + { + return distributionPath; + } + + public void setDistributionPath( String distributionPath ) + { + this.distributionPath = distributionPath; + } + + public String getZipBase() + { + return zipBase; + } + + public void setZipBase( String zipBase ) + { + this.zipBase = zipBase; + } + + public String getZipPath() + { + return zipPath; + } + + public void setZipPath( String zipPath ) + { + this.zipPath = zipPath; + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/WrapperExecutor.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/WrapperExecutor.java new file mode 100644 index 0000000000..ef95020507 --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/WrapperExecutor.java @@ -0,0 +1,177 @@ +/* + * Copyright 2007-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Properties; + +/** + * @author Hans Dockter + */ +public class WrapperExecutor +{ + public static final String DISTRIBUTION_URL_PROPERTY = "distributionUrl"; + + public static final String DISTRIBUTION_BASE_PROPERTY = "distributionBase"; + + public static final String ZIP_STORE_BASE_PROPERTY = "zipStoreBase"; + + public static final String DISTRIBUTION_PATH_PROPERTY = "distributionPath"; + + public static final String ZIP_STORE_PATH_PROPERTY = "zipStorePath"; + + private final Properties properties; + + private final File propertiesFile; + + private final Appendable warningOutput; + + private final WrapperConfiguration config = new WrapperConfiguration(); + + public static WrapperExecutor forProjectDirectory( File projectDir, Appendable warningOutput ) + { + return new WrapperExecutor( new File( projectDir, "maven/wrapper/maven-wrapper.properties" ), new Properties(), + warningOutput ); + } + + public static WrapperExecutor forWrapperPropertiesFile( File propertiesFile, Appendable warningOutput ) + { + if ( !propertiesFile.exists() ) + { + throw new RuntimeException( String.format( "Wrapper properties file '%s' does not exist.", propertiesFile ) ); + } + return new WrapperExecutor( propertiesFile, new Properties(), warningOutput ); + } + + WrapperExecutor( File propertiesFile, Properties properties, Appendable warningOutput ) + { + this.properties = properties; + this.propertiesFile = propertiesFile; + this.warningOutput = warningOutput; + if ( propertiesFile.exists() ) + { + try + { + loadProperties( propertiesFile, properties ); + config.setDistribution( prepareDistributionUri() ); + config.setDistributionBase( getProperty( DISTRIBUTION_BASE_PROPERTY, config.getDistributionBase() ) ); + config.setDistributionPath( getProperty( DISTRIBUTION_PATH_PROPERTY, config.getDistributionPath() ) ); + config.setZipBase( getProperty( ZIP_STORE_BASE_PROPERTY, config.getZipBase() ) ); + config.setZipPath( getProperty( ZIP_STORE_PATH_PROPERTY, config.getZipPath() ) ); + } + catch ( Exception e ) + { + throw new RuntimeException( String.format( "Could not load wrapper properties from '%s'.", + propertiesFile ), e ); + } + } + } + + private URI prepareDistributionUri() + throws URISyntaxException + { + URI source = readDistroUrl(); + if ( source.getScheme() == null ) + { + // no scheme means someone passed a relative url. In our context only file relative urls make sense. + return new File( propertiesFile.getParentFile(), source.getSchemeSpecificPart() ).toURI(); + } + else + { + return source; + } + } + + private URI readDistroUrl() + throws URISyntaxException + { + if ( properties.getProperty( DISTRIBUTION_URL_PROPERTY ) != null ) + { + return new URI( getProperty( DISTRIBUTION_URL_PROPERTY ) ); + } + + reportMissingProperty( DISTRIBUTION_URL_PROPERTY ); + return null; // previous line will fail + } + + private static void loadProperties( File propertiesFile, Properties properties ) + throws IOException + { + InputStream inStream = new FileInputStream( propertiesFile ); + try + { + properties.load( inStream ); + } + finally + { + inStream.close(); + } + } + + /** + * Returns the distribution which this wrapper will use. Returns null if no wrapper meta-data was found in the + * specified project directory. + */ + public URI getDistribution() + { + return config.getDistribution(); + } + + /** + * Returns the configuration for this wrapper. + */ + public WrapperConfiguration getConfiguration() + { + return config; + } + + public void execute( String[] args, Installer install, BootstrapMainStarter bootstrapMainStarter ) + throws Exception + { + File mavenHome = install.createDist( config ); + bootstrapMainStarter.start( args, mavenHome ); + } + + private String getProperty( String propertyName ) + { + return getProperty( propertyName, null ); + } + + private String getProperty( String propertyName, String defaultValue ) + { + String value = properties.getProperty( propertyName ); + if ( value != null ) + { + return value; + } + if ( defaultValue != null ) + { + return defaultValue; + } + return reportMissingProperty( propertyName ); + } + + private String reportMissingProperty( String propertyName ) + { + throw new RuntimeException( String.format( "No value with key '%s' specified in wrapper properties file '%s'.", + propertyName, propertiesFile ) ); + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/AbstractCommandLineConverter.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/AbstractCommandLineConverter.java new file mode 100644 index 0000000000..31c46fd57c --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/AbstractCommandLineConverter.java @@ -0,0 +1,44 @@ +/* + * Copyright 2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper.cli; + +public abstract class AbstractCommandLineConverter + implements CommandLineConverter +{ + public T convert( Iterable args ) + throws CommandLineArgumentException + { + CommandLineParser parser = new CommandLineParser(); + configure( parser ); + return convert( parser.parse( args ) ); + } + + public T convert( ParsedCommandLine args ) + throws CommandLineArgumentException + { + return convert( args, newInstance() ); + } + + public T convert( Iterable args, T target ) + throws CommandLineArgumentException + { + CommandLineParser parser = new CommandLineParser(); + configure( parser ); + return convert( parser.parse( args ), target ); + } + + protected abstract T newInstance(); +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/AbstractPropertiesCommandLineConverter.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/AbstractPropertiesCommandLineConverter.java new file mode 100644 index 0000000000..e8937c3efe --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/AbstractPropertiesCommandLineConverter.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.maven.wrapper.cli; + +import java.util.HashMap; +import java.util.Map; + +public abstract class AbstractPropertiesCommandLineConverter + extends AbstractCommandLineConverter> +{ + protected abstract String getPropertyOption(); + + protected abstract String getPropertyOptionDetailed(); + + protected abstract String getPropertyOptionDescription(); + + public void configure( CommandLineParser parser ) + { + CommandLineOption option = parser.option( getPropertyOption(), getPropertyOptionDetailed() ); + option = option.hasArguments(); + option.hasDescription( getPropertyOptionDescription() ); + } + + protected Map newInstance() + { + return new HashMap(); + } + + public Map convert( ParsedCommandLine options, Map properties ) + throws CommandLineArgumentException + { + for ( String keyValueExpression : options.option( getPropertyOption() ).getValues() ) + { + int pos = keyValueExpression.indexOf( "=" ); + if ( pos < 0 ) + { + properties.put( keyValueExpression, "" ); + } + else + { + properties.put( keyValueExpression.substring( 0, pos ), keyValueExpression.substring( pos + 1 ) ); + } + } + return properties; + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineArgumentException.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineArgumentException.java new file mode 100644 index 0000000000..0fed0394bd --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineArgumentException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper.cli; + +/** + * A {@code CommandLineArgumentException} is thrown when command-line arguments cannot be parsed. + * + * @author Hans Dockter + */ +public class CommandLineArgumentException + extends RuntimeException +{ + public CommandLineArgumentException( String message ) + { + super( message ); + } + + public CommandLineArgumentException( String message, Throwable cause ) + { + super( message, cause ); + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineConverter.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineConverter.java new file mode 100644 index 0000000000..1d27dc293d --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineConverter.java @@ -0,0 +1,36 @@ +/* + * Copyright 2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper.cli; + +/** + * @author Hans Dockter + */ +public interface CommandLineConverter +{ + T convert( Iterable args ) + throws CommandLineArgumentException; + + T convert( Iterable args, T target ) + throws CommandLineArgumentException; + + T convert( ParsedCommandLine args ) + throws CommandLineArgumentException; + + T convert( ParsedCommandLine args, T target ) + throws CommandLineArgumentException; + + void configure( CommandLineParser parser ); +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineOption.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineOption.java new file mode 100644 index 0000000000..e3fde8bdfa --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineOption.java @@ -0,0 +1,132 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper.cli; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class CommandLineOption +{ + private final Set options = new HashSet(); + + private Class argumentType = Void.TYPE; + + private String description; + + private String subcommand; + + private String deprecationWarning; + + private boolean incubating; + + public CommandLineOption( Iterable options ) + { + for ( String option : options ) + { + this.options.add( option ); + } + } + + public Set getOptions() + { + return options; + } + + public CommandLineOption hasArgument() + { + argumentType = String.class; + return this; + } + + public CommandLineOption hasArguments() + { + argumentType = List.class; + return this; + } + + public String getSubcommand() + { + return subcommand; + } + + public CommandLineOption mapsToSubcommand( String command ) + { + this.subcommand = command; + return this; + } + + public String getDescription() + { + StringBuilder result = new StringBuilder(); + if ( description != null ) + { + result.append( description ); + } + if ( deprecationWarning != null ) + { + if ( result.length() > 0 ) + { + result.append( ' ' ); + } + result.append( "[deprecated - " ); + result.append( deprecationWarning ); + result.append( "]" ); + } + if ( incubating ) + { + if ( result.length() > 0 ) + { + result.append( ' ' ); + } + result.append( "[incubating]" ); + } + return result.toString(); + } + + public CommandLineOption hasDescription( String description ) + { + this.description = description; + return this; + } + + public boolean getAllowsArguments() + { + return argumentType != Void.TYPE; + } + + public boolean getAllowsMultipleArguments() + { + return argumentType == List.class; + } + + public CommandLineOption deprecated( String deprecationWarning ) + { + this.deprecationWarning = deprecationWarning; + return this; + } + + public CommandLineOption incubating() + { + incubating = true; + return this; + } + + public String getDeprecationWarning() + { + return deprecationWarning; + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineParser.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineParser.java new file mode 100644 index 0000000000..77460130fb --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/CommandLineParser.java @@ -0,0 +1,675 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper.cli; + +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Formatter; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +/** + *

+ * A command-line parser which supports a command/sub-command style command-line interface. Supports the following + * syntax: + *

+ * + *
+ * <option>* (<sub-command> <sub-command-option>*)*
+ * 
+ *
    + *
  • Short options are a '-' followed by a single character. For example: {@code -a}.
  • + *
  • Long options are '--' followed by multiple characters. For example: {@code --long-option}.
  • + *
  • Options can take arguments. The argument follows the option. For example: {@code -a arg} or {@code --long arg}.
  • + *
  • Arguments can be attached to the option using '='. For example: {@code -a=arg} or {@code --long=arg}.
  • + *
  • Arguments can be attached to short options. For example: {@code -aarg}.
  • + *
  • Short options can be combined. For example {@code -ab} is equivalent to {@code -a -b}.
  • + *
  • Anything else is treated as an extra argument. This includes a single {@code -} character.
  • + *
  • '--' indicates the end of the options. Anything following is not parsed and is treated as extra arguments.
  • + *
  • The parser is forgiving, and allows '--' to be used with short options and '-' to be used with long options.
  • + *
  • The set of options must be known at parse time. Sub-commands and their options do not need to be known at parse + * time. Use {@link ParsedCommandLine#getExtraArguments()} to obtain the non-option command-line arguments.
  • + *
+ */ +public class CommandLineParser +{ + private Map optionsByString = new HashMap(); + + private boolean allowMixedOptions; + + private boolean allowUnknownOptions; + + private final PrintWriter deprecationPrinter; + + public CommandLineParser() + { + this( new OutputStreamWriter( System.out ) ); + } + + public CommandLineParser( Writer deprecationPrinter ) + { + this.deprecationPrinter = new PrintWriter( deprecationPrinter ); + } + + /** + * Parses the given command-line. + * + * @param commandLine The command-line. + * @return The parsed command line. + * @throws org.apache.maven.wrapper.cli.CommandLineArgumentException On parse failure. + */ + public ParsedCommandLine parse( String... commandLine ) + throws CommandLineArgumentException + { + return parse( Arrays.asList( commandLine ) ); + } + + /** + * Parses the given command-line. + * + * @param commandLine The command-line. + * @return The parsed command line. + * @throws org.apache.maven.wrapper.cli.CommandLineArgumentException On parse failure. + */ + public ParsedCommandLine parse( Iterable commandLine ) + throws CommandLineArgumentException + { + ParsedCommandLine parsedCommandLine = + new ParsedCommandLine( new HashSet( optionsByString.values() ) ); + ParserState parseState = new BeforeFirstSubCommand( parsedCommandLine ); + for ( String arg : commandLine ) + { + if ( parseState.maybeStartOption( arg ) ) + { + if ( arg.equals( "--" ) ) + { + parseState = new AfterOptions( parsedCommandLine ); + } + else if ( arg.matches( "--[^=]+" ) ) + { + OptionParserState parsedOption = parseState.onStartOption( arg, arg.substring( 2 ) ); + parseState = parsedOption.onStartNextArg(); + } + else if ( arg.matches( "--[^=]+=.*" ) ) + { + int endArg = arg.indexOf( '=' ); + OptionParserState parsedOption = parseState.onStartOption( arg, arg.substring( 2, endArg ) ); + parseState = parsedOption.onArgument( arg.substring( endArg + 1 ) ); + } + else if ( arg.matches( "-[^=]=.*" ) ) + { + OptionParserState parsedOption = parseState.onStartOption( arg, arg.substring( 1, 2 ) ); + parseState = parsedOption.onArgument( arg.substring( 3 ) ); + } + else + { + assert arg.matches( "-[^-].*" ); + String option = arg.substring( 1 ); + if ( optionsByString.containsKey( option ) ) + { + OptionParserState parsedOption = parseState.onStartOption( arg, option ); + parseState = parsedOption.onStartNextArg(); + } + else + { + String option1 = arg.substring( 1, 2 ); + OptionParserState parsedOption; + if ( optionsByString.containsKey( option1 ) ) + { + parsedOption = parseState.onStartOption( "-" + option1, option1 ); + if ( parsedOption.getHasArgument() ) + { + parseState = parsedOption.onArgument( arg.substring( 2 ) ); + } + else + { + parseState = parsedOption.onComplete(); + for ( int i = 2; i < arg.length(); i++ ) + { + String optionStr = arg.substring( i, i + 1 ); + parsedOption = parseState.onStartOption( "-" + optionStr, optionStr ); + parseState = parsedOption.onComplete(); + } + } + } + else + { + if ( allowUnknownOptions ) + { + // if we are allowing unknowns, just pass through the whole arg + parsedOption = parseState.onStartOption( arg, option ); + parseState = parsedOption.onComplete(); + } + else + { + // We are going to throw a CommandLineArgumentException below, but want the message + // to reflect that we didn't recognise the first char (i.e. the option specifier) + parsedOption = parseState.onStartOption( "-" + option1, option1 ); + parseState = parsedOption.onComplete(); + } + } + } + } + } + else + { + parseState = parseState.onNonOption( arg ); + } + } + + parseState.onCommandLineEnd(); + return parsedCommandLine; + } + + public CommandLineParser allowMixedSubcommandsAndOptions() + { + allowMixedOptions = true; + return this; + } + + public CommandLineParser allowUnknownOptions() + { + allowUnknownOptions = true; + return this; + } + + /** + * Prints a usage message to the given stream. + * + * @param out The output stream to write to. + */ + public void printUsage( Appendable out ) + { + Formatter formatter = new Formatter( out ); + Set orderedOptions = new TreeSet( new OptionComparator() ); + orderedOptions.addAll( optionsByString.values() ); + Map lines = new LinkedHashMap(); + for ( CommandLineOption option : orderedOptions ) + { + Set orderedOptionStrings = new TreeSet( new OptionStringComparator() ); + orderedOptionStrings.addAll( option.getOptions() ); + List prefixedStrings = new ArrayList(); + for ( String optionString : orderedOptionStrings ) + { + if ( optionString.length() == 1 ) + { + prefixedStrings.add( "-" + optionString ); + } + else + { + prefixedStrings.add( "--" + optionString ); + } + } + + String key = join( prefixedStrings, ", " ); + String value = option.getDescription(); + if ( value == null || value.length() == 0 ) + { + value = ""; + } + + lines.put( key, value ); + } + int max = 0; + for ( String optionStr : lines.keySet() ) + { + max = Math.max( max, optionStr.length() ); + } + for ( Map.Entry entry : lines.entrySet() ) + { + if ( entry.getValue().length() == 0 ) + { + formatter.format( "%s%n", entry.getKey() ); + } + else + { + formatter.format( "%-" + max + "s %s%n", entry.getKey(), entry.getValue() ); + } + } + formatter.flush(); + } + + private static String join( Collection things, String separator ) + { + StringBuffer buffer = new StringBuffer(); + boolean first = true; + + if ( separator == null ) + { + separator = ""; + } + + for ( Object thing : things ) + { + if ( !first ) + { + buffer.append( separator ); + } + buffer.append( thing.toString() ); + first = false; + } + return buffer.toString(); + } + + /** + * Defines a new option. By default, the option takes no arguments and has no description. + * + * @param options The options values. + * @return The option, which can be further configured. + */ + public CommandLineOption option( String... options ) + { + for ( String option : options ) + { + if ( optionsByString.containsKey( option ) ) + { + throw new IllegalArgumentException( String.format( "Option '%s' is already defined.", option ) ); + } + if ( option.startsWith( "-" ) ) + { + throw new IllegalArgumentException( + String.format( "Cannot add option '%s' as an option cannot start with '-'.", + option ) ); + } + } + CommandLineOption option = new CommandLineOption( Arrays.asList( options ) ); + for ( String optionStr : option.getOptions() ) + { + this.optionsByString.put( optionStr, option ); + } + return option; + } + + private static class OptionString + { + private final String arg; + + private final String option; + + private OptionString( String arg, String option ) + { + this.arg = arg; + this.option = option; + } + + public String getDisplayName() + { + return arg.startsWith( "--" ) ? "--" + option : "-" + option; + } + + @Override + public String toString() + { + return getDisplayName(); + } + } + + private static abstract class ParserState + { + public abstract boolean maybeStartOption( String arg ); + + boolean isOption( String arg ) + { + return arg.matches( "-.+" ); + } + + public abstract OptionParserState onStartOption( String arg, String option ); + + public abstract ParserState onNonOption( String arg ); + + public void onCommandLineEnd() + { + } + } + + private abstract class OptionAwareParserState + extends ParserState + { + protected final ParsedCommandLine commandLine; + + protected OptionAwareParserState( ParsedCommandLine commandLine ) + { + this.commandLine = commandLine; + } + + @Override + public boolean maybeStartOption( String arg ) + { + return isOption( arg ); + } + + @Override + public ParserState onNonOption( String arg ) + { + commandLine.addExtraValue( arg ); + return allowMixedOptions ? new AfterFirstSubCommand( commandLine ) : new AfterOptions( commandLine ); + } + } + + private class BeforeFirstSubCommand + extends OptionAwareParserState + { + private BeforeFirstSubCommand( ParsedCommandLine commandLine ) + { + super( commandLine ); + } + + @Override + public OptionParserState onStartOption( String arg, String option ) + { + OptionString optionString = new OptionString( arg, option ); + CommandLineOption commandLineOption = optionsByString.get( option ); + if ( commandLineOption == null ) + { + if ( allowUnknownOptions ) + { + return new UnknownOptionParserState( arg, commandLine, this ); + } + else + { + throw new CommandLineArgumentException( String.format( "Unknown command-line option '%s'.", + optionString ) ); + } + } + return new KnownOptionParserState( optionString, commandLineOption, commandLine, this ); + } + } + + private class AfterFirstSubCommand + extends OptionAwareParserState + { + private AfterFirstSubCommand( ParsedCommandLine commandLine ) + { + super( commandLine ); + } + + @Override + public OptionParserState onStartOption( String arg, String option ) + { + CommandLineOption commandLineOption = optionsByString.get( option ); + if ( commandLineOption == null ) + { + return new UnknownOptionParserState( arg, commandLine, this ); + } + return new KnownOptionParserState( new OptionString( arg, option ), commandLineOption, commandLine, this ); + } + } + + private static class AfterOptions + extends ParserState + { + private final ParsedCommandLine commandLine; + + private AfterOptions( ParsedCommandLine commandLine ) + { + this.commandLine = commandLine; + } + + @Override + public boolean maybeStartOption( String arg ) + { + return false; + } + + @Override + public OptionParserState onStartOption( String arg, String option ) + { + return new UnknownOptionParserState( arg, commandLine, this ); + } + + @Override + public ParserState onNonOption( String arg ) + { + commandLine.addExtraValue( arg ); + return this; + } + } + + private static class MissingOptionArgState + extends ParserState + { + private final OptionParserState option; + + private MissingOptionArgState( OptionParserState option ) + { + this.option = option; + } + + @Override + public boolean maybeStartOption( String arg ) + { + return isOption( arg ); + } + + @Override + public OptionParserState onStartOption( String arg, String option ) + { + return this.option.onComplete().onStartOption( arg, option ); + } + + @Override + public ParserState onNonOption( String arg ) + { + return option.onArgument( arg ); + } + + @Override + public void onCommandLineEnd() + { + option.onComplete(); + } + } + + private static abstract class OptionParserState + { + public abstract ParserState onStartNextArg(); + + public abstract ParserState onArgument( String argument ); + + public abstract boolean getHasArgument(); + + public abstract ParserState onComplete(); + } + + private class KnownOptionParserState + extends OptionParserState + { + private final OptionString optionString; + + private final CommandLineOption option; + + private final ParsedCommandLine commandLine; + + private final ParserState state; + + private final List values = new ArrayList(); + + private KnownOptionParserState( OptionString optionString, CommandLineOption option, + ParsedCommandLine commandLine, ParserState state ) + { + this.optionString = optionString; + this.option = option; + this.commandLine = commandLine; + this.state = state; + } + + @Override + public ParserState onArgument( String argument ) + { + if ( !getHasArgument() ) + { + throw new CommandLineArgumentException( + String.format( "Command-line option '%s' does not take an argument.", + optionString ) ); + } + if ( argument.length() == 0 ) + { + throw new CommandLineArgumentException( + String.format( "An empty argument was provided for command-line option '%s'.", + optionString ) ); + } + values.add( argument ); + return onComplete(); + } + + @Override + public ParserState onStartNextArg() + { + if ( option.getAllowsArguments() && values.isEmpty() ) + { + return new MissingOptionArgState( this ); + } + return onComplete(); + } + + @Override + public boolean getHasArgument() + { + return option.getAllowsArguments(); + } + + @Override + public ParserState onComplete() + { + if ( getHasArgument() && values.isEmpty() ) + { + throw new CommandLineArgumentException( + String.format( "No argument was provided for command-line option '%s'.", + optionString ) ); + } + + ParsedCommandLineOption parsedOption = commandLine.addOption( optionString.option, option ); + if ( values.size() + parsedOption.getValues().size() > 1 && !option.getAllowsMultipleArguments() ) + { + throw new CommandLineArgumentException( + String.format( "Multiple arguments were provided for command-line option '%s'.", + optionString ) ); + } + for ( String value : values ) + { + parsedOption.addArgument( value ); + } + if ( option.getDeprecationWarning() != null ) + { + deprecationPrinter.println( "The " + optionString + " option is deprecated - " + + option.getDeprecationWarning() ); + } + if ( option.getSubcommand() != null ) + { + return state.onNonOption( option.getSubcommand() ); + } + + return state; + } + } + + private static class UnknownOptionParserState + extends OptionParserState + { + private final ParserState state; + + private final String arg; + + private final ParsedCommandLine commandLine; + + private UnknownOptionParserState( String arg, ParsedCommandLine commandLine, ParserState state ) + { + this.arg = arg; + this.commandLine = commandLine; + this.state = state; + } + + @Override + public boolean getHasArgument() + { + return true; + } + + @Override + public ParserState onStartNextArg() + { + return onComplete(); + } + + @Override + public ParserState onArgument( String argument ) + { + return onComplete(); + } + + @Override + public ParserState onComplete() + { + commandLine.addExtraValue( arg ); + return state; + } + } + + private static final class OptionComparator + implements Comparator + { + public int compare( CommandLineOption option1, CommandLineOption option2 ) + { + String min1 = Collections.min( option1.getOptions(), new OptionStringComparator() ); + String min2 = Collections.min( option2.getOptions(), new OptionStringComparator() ); + return new CaseInsensitiveStringComparator().compare( min1, min2 ); + } + } + + private static final class CaseInsensitiveStringComparator + implements Comparator + { + public int compare( String option1, String option2 ) + { + int diff = option1.compareToIgnoreCase( option2 ); + if ( diff != 0 ) + { + return diff; + } + return option1.compareTo( option2 ); + } + } + + private static final class OptionStringComparator + implements Comparator + { + public int compare( String option1, String option2 ) + { + boolean short1 = option1.length() == 1; + boolean short2 = option2.length() == 1; + if ( short1 && !short2 ) + { + return -1; + } + if ( !short1 && short2 ) + { + return 1; + } + return new CaseInsensitiveStringComparator().compare( option1, option2 ); + } + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/ParsedCommandLine.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/ParsedCommandLine.java new file mode 100644 index 0000000000..e7e34451cc --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/ParsedCommandLine.java @@ -0,0 +1,133 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper.cli; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class ParsedCommandLine +{ + private final Map optionsByString = new HashMap(); + + private final Set presentOptions = new HashSet(); + + private final List extraArguments = new ArrayList(); + + ParsedCommandLine( Iterable options ) + { + for ( CommandLineOption option : options ) + { + ParsedCommandLineOption parsedOption = new ParsedCommandLineOption(); + for ( String optionStr : option.getOptions() ) + { + optionsByString.put( optionStr, parsedOption ); + } + } + } + + @Override + public String toString() + { + return String.format( "options: %s, extraArguments: %s", quoteAndJoin( presentOptions ), + quoteAndJoin( extraArguments ) ); + } + + private String quoteAndJoin( Iterable strings ) + { + StringBuilder output = new StringBuilder(); + boolean isFirst = true; + for ( String string : strings ) + { + if ( !isFirst ) + { + output.append( ", " ); + } + output.append( "'" ); + output.append( string ); + output.append( "'" ); + isFirst = false; + } + return output.toString(); + } + + /** + * Returns true if the given option is present in this command-line. + * + * @param option The option, without the '-' or '--' prefix. + * @return true if the option is present. + */ + public boolean hasOption( String option ) + { + option( option ); + return presentOptions.contains( option ); + } + + /** + * See also {@link #hasOption}. + * + * @param logLevelOptions the options to check + * @return true if any of the passed options is present + */ + public boolean hasAnyOption( Collection logLevelOptions ) + { + for ( String option : logLevelOptions ) + { + if ( hasOption( option ) ) + { + return true; + } + } + return false; + } + + /** + * Returns the value of the given option. + * + * @param option The option, without the '-' or '--' prefix. + * @return The option. never returns null. + */ + public ParsedCommandLineOption option( String option ) + { + ParsedCommandLineOption parsedOption = optionsByString.get( option ); + if ( parsedOption == null ) + { + throw new IllegalArgumentException( String.format( "Option '%s' not defined.", option ) ); + } + return parsedOption; + } + + public List getExtraArguments() + { + return extraArguments; + } + + void addExtraValue( String value ) + { + extraArguments.add( value ); + } + + ParsedCommandLineOption addOption( String optionStr, CommandLineOption option ) + { + ParsedCommandLineOption parsedOption = optionsByString.get( optionStr ); + presentOptions.addAll( option.getOptions() ); + return parsedOption; + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/ParsedCommandLineOption.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/ParsedCommandLineOption.java new file mode 100644 index 0000000000..7d75a8fec1 --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/ParsedCommandLineOption.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper.cli; + +import java.util.ArrayList; +import java.util.List; + +public class ParsedCommandLineOption +{ + private final List values = new ArrayList(); + + public String getValue() + { + if ( !hasValue() ) + { + throw new IllegalStateException( "Option does not have any value." ); + } + if ( values.size() > 1 ) + { + throw new IllegalStateException( "Option has multiple values." ); + } + return values.get( 0 ); + } + + public List getValues() + { + return values; + } + + public void addArgument( String argument ) + { + values.add( argument ); + } + + public boolean hasValue() + { + return !values.isEmpty(); + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/ProjectPropertiesCommandLineConverter.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/ProjectPropertiesCommandLineConverter.java new file mode 100644 index 0000000000..8b1a110f87 --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/ProjectPropertiesCommandLineConverter.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.maven.wrapper.cli; + +public class ProjectPropertiesCommandLineConverter + extends AbstractPropertiesCommandLineConverter +{ + + @Override + protected String getPropertyOption() + { + return "P"; + } + + @Override + protected String getPropertyOptionDetailed() + { + return "project-prop"; + } + + @Override + protected String getPropertyOptionDescription() + { + return "Set project property for the build script (e.g. -Pmyprop=myvalue)."; + } +} diff --git a/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/SystemPropertiesCommandLineConverter.java b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/SystemPropertiesCommandLineConverter.java new file mode 100644 index 0000000000..fb7bc9ac5d --- /dev/null +++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/cli/SystemPropertiesCommandLineConverter.java @@ -0,0 +1,39 @@ +/* + * Copyright 2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper.cli; + +public class SystemPropertiesCommandLineConverter + extends AbstractPropertiesCommandLineConverter +{ + + @Override + protected String getPropertyOption() + { + return "D"; + } + + @Override + protected String getPropertyOptionDetailed() + { + return "system-prop"; + } + + @Override + protected String getPropertyOptionDescription() + { + return "Set system property of the JVM (e.g. -Dmyprop=myvalue)."; + } +} \ No newline at end of file diff --git a/maven-wrapper/src/test/java/org/apache/maven/wrapper/DownloaderTest.java b/maven-wrapper/src/test/java/org/apache/maven/wrapper/DownloaderTest.java new file mode 100644 index 0000000000..c84096a867 --- /dev/null +++ b/maven-wrapper/src/test/java/org/apache/maven/wrapper/DownloaderTest.java @@ -0,0 +1,49 @@ +package org.apache.maven.wrapper; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.net.URI; + +import org.apache.commons.io.FileUtils; +import org.junit.Before; +import org.junit.Test; + +public class DownloaderTest +{ + + private DefaultDownloader download; + + private File testDir; + + private File downloadFile; + + private File rootDir; + + private URI sourceRoot; + + private File remoteFile; + + @Before + public void setUp() + throws Exception + { + download = new DefaultDownloader( "mvnw", "aVersion" ); + testDir = new File( "target/test-files/DownloadTest" ); + rootDir = new File( testDir, "root" ); + downloadFile = new File( rootDir, "file" ); + remoteFile = new File( testDir, "remoteFile" ); + FileUtils.write( remoteFile, "sometext" ); + sourceRoot = remoteFile.toURI(); + } + + @Test + public void testDownload() + throws Exception + { + assert !downloadFile.exists(); + download.download( sourceRoot, downloadFile ); + assert downloadFile.exists(); + assertEquals( "sometext", FileUtils.readFileToString( downloadFile ) ); + } +} diff --git a/maven-wrapper/src/test/java/org/apache/maven/wrapper/InstallerTest.java b/maven-wrapper/src/test/java/org/apache/maven/wrapper/InstallerTest.java new file mode 100644 index 0000000000..fc02d60940 --- /dev/null +++ b/maven-wrapper/src/test/java/org/apache/maven/wrapper/InstallerTest.java @@ -0,0 +1,196 @@ +package org.apache.maven.wrapper; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.net.URI; + +import org.apache.commons.io.FileUtils; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Zip; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Hans Dockter + */ +public class InstallerTest +{ + private File testDir = new File( "target/test-files/SystemPropertiesHandlerTest-" + System.currentTimeMillis() ); + + private Installer install; + + private Downloader downloadMock; + + private PathAssembler pathAssemblerMock; + + private boolean downloadCalled; + + private File zip; + + private File distributionDir; + + private File zipStore; + + private File mavenHomeDir; + + private File zipDestination; + + private WrapperConfiguration configuration = new WrapperConfiguration(); + + private Downloader download; + + private PathAssembler pathAssembler; + + private PathAssembler.LocalDistribution localDistribution; + + @Before + public void setup() + throws Exception + { + + testDir.mkdirs(); + + downloadCalled = false; + configuration.setZipBase( PathAssembler.PROJECT_STRING ); + configuration.setZipPath( "someZipPath" ); + configuration.setDistributionBase( PathAssembler.MAVEN_USER_HOME_STRING ); + configuration.setDistributionPath( "someDistPath" ); + configuration.setDistribution( new URI( "http://server/maven-0.9.zip" ) ); + configuration.setAlwaysDownload( false ); + configuration.setAlwaysUnpack( false ); + distributionDir = new File( testDir, "someDistPath" ); + mavenHomeDir = new File( distributionDir, "maven-0.9" ); + zipStore = new File( testDir, "zips" ); + zipDestination = new File( zipStore, "maven-0.9.zip" ); + + download = mock( Downloader.class ); + pathAssembler = mock( PathAssembler.class ); + localDistribution = mock( PathAssembler.LocalDistribution.class ); + + when( localDistribution.getZipFile() ).thenReturn( zipDestination ); + when( localDistribution.getDistributionDir() ).thenReturn( distributionDir ); + when( pathAssembler.getDistribution( configuration ) ).thenReturn( localDistribution ); + + install = new Installer( download, pathAssembler ); + + } + + private void createTestZip( File zipDestination ) + throws Exception + { + File explodedZipDir = new File( testDir, "explodedZip" ); + explodedZipDir.mkdirs(); + zipDestination.getParentFile().mkdirs(); + File mavenScript = new File( explodedZipDir, "maven-0.9/bin/mvn" ); + mavenScript.getParentFile().mkdirs(); + FileUtils.write( mavenScript, "something" ); + + zipTo( explodedZipDir, zipDestination ); + } + + public void testCreateDist() + throws Exception + { + File homeDir = install.createDist( configuration ); + + Assert.assertEquals( mavenHomeDir, homeDir ); + Assert.assertTrue( homeDir.isDirectory() ); + Assert.assertTrue( new File( homeDir, "bin/mvn" ).exists() ); + Assert.assertTrue( zipDestination.exists() ); + + Assert.assertEquals( localDistribution, pathAssembler.getDistribution( configuration ) ); + Assert.assertEquals( distributionDir, localDistribution.getDistributionDir() ); + Assert.assertEquals( zipDestination, localDistribution.getZipFile() ); + + // download.download(new URI("http://some/test"), distributionDir); + // verify(download).download(new URI("http://some/test"), distributionDir); + } + + @Test + public void testCreateDistWithExistingDistribution() + throws Exception + { + + FileUtils.touch( zipDestination ); + mavenHomeDir.mkdirs(); + File someFile = new File( mavenHomeDir, "some-file" ); + FileUtils.touch( someFile ); + + File homeDir = install.createDist( configuration ); + + Assert.assertEquals( mavenHomeDir, homeDir ); + Assert.assertTrue( mavenHomeDir.isDirectory() ); + Assert.assertTrue( new File( homeDir, "some-file" ).exists() ); + Assert.assertTrue( zipDestination.exists() ); + + Assert.assertEquals( localDistribution, pathAssembler.getDistribution( configuration ) ); + Assert.assertEquals( distributionDir, localDistribution.getDistributionDir() ); + Assert.assertEquals( zipDestination, localDistribution.getZipFile() ); + } + + @Test + public void testCreateDistWithExistingDistAndZipAndAlwaysUnpackTrue() + throws Exception + { + + createTestZip( zipDestination ); + mavenHomeDir.mkdirs(); + File garbage = new File( mavenHomeDir, "garbage" ); + FileUtils.touch( garbage ); + configuration.setAlwaysUnpack( true ); + + File homeDir = install.createDist( configuration ); + + Assert.assertEquals( mavenHomeDir, homeDir ); + Assert.assertTrue( mavenHomeDir.isDirectory() ); + Assert.assertFalse( new File( homeDir, "garbage" ).exists() ); + Assert.assertTrue( zipDestination.exists() ); + + Assert.assertEquals( localDistribution, pathAssembler.getDistribution( configuration ) ); + Assert.assertEquals( distributionDir, localDistribution.getDistributionDir() ); + Assert.assertEquals( zipDestination, localDistribution.getZipFile() ); + } + + @Test + public void testCreateDistWithExistingZipAndDistAndAlwaysDownloadTrue() + throws Exception + { + + createTestZip( zipDestination ); + File garbage = new File( mavenHomeDir, "garbage" ); + FileUtils.touch( garbage ); + configuration.setAlwaysUnpack( true ); + + File homeDir = install.createDist( configuration ); + + Assert.assertEquals( mavenHomeDir, homeDir ); + Assert.assertTrue( mavenHomeDir.isDirectory() ); + Assert.assertTrue( new File( homeDir, "bin/mvn" ).exists() ); + Assert.assertFalse( new File( homeDir, "garbage" ).exists() ); + Assert.assertTrue( zipDestination.exists() ); + + Assert.assertEquals( localDistribution, pathAssembler.getDistribution( configuration ) ); + Assert.assertEquals( distributionDir, localDistribution.getDistributionDir() ); + Assert.assertEquals( zipDestination, localDistribution.getZipFile() ); + + // download.download(new URI("http://some/test"), distributionDir); + // verify(download).download(new URI("http://some/test"), distributionDir); + } + + public void zipTo( File directoryToZip, File zipFile ) + { + Zip zip = new Zip(); + zip.setBasedir( directoryToZip ); + zip.setDestFile( zipFile ); + zip.setProject( new Project() ); + + Zip.WhenEmpty whenEmpty = new Zip.WhenEmpty(); + whenEmpty.setValue( "create" ); + zip.setWhenempty( whenEmpty ); + zip.execute(); + } + +} diff --git a/maven-wrapper/src/test/java/org/apache/maven/wrapper/PathAssemblerTest.java b/maven-wrapper/src/test/java/org/apache/maven/wrapper/PathAssemblerTest.java new file mode 100644 index 0000000000..fbd0d648de --- /dev/null +++ b/maven-wrapper/src/test/java/org/apache/maven/wrapper/PathAssemblerTest.java @@ -0,0 +1,145 @@ +/* + * Copyright 2007-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.maven.wrapper; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import java.io.File; +import java.net.URI; +import java.util.regex.Pattern; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Hans Dockter + */ +public class PathAssemblerTest +{ + public static final String TEST_MAVEN_USER_HOME = "someUserHome"; + + private PathAssembler pathAssembler = new PathAssembler( new File( TEST_MAVEN_USER_HOME ) ); + + final WrapperConfiguration configuration = new WrapperConfiguration(); + + @Before + public void setup() + { + configuration.setDistributionBase( PathAssembler.MAVEN_USER_HOME_STRING ); + configuration.setDistributionPath( "somePath" ); + configuration.setZipBase( PathAssembler.MAVEN_USER_HOME_STRING ); + configuration.setZipPath( "somePath" ); + } + + @Test + public void distributionDirWithMavenUserHomeBase() + throws Exception + { + configuration.setDistribution( new URI( "http://server/dist/maven-0.9-bin.zip" ) ); + + File distributionDir = pathAssembler.getDistribution( configuration ).getDistributionDir(); + assertThat( distributionDir.getName(), matchesRegexp( "[a-z0-9]+" ) ); + assertThat( distributionDir.getParentFile(), equalTo( file( TEST_MAVEN_USER_HOME + "/somePath/maven-0.9-bin" ) ) ); + } + + @Test + public void distributionDirWithProjectBase() + throws Exception + { + configuration.setDistributionBase( PathAssembler.PROJECT_STRING ); + configuration.setDistribution( new URI( "http://server/dist/maven-0.9-bin.zip" ) ); + + File distributionDir = pathAssembler.getDistribution( configuration ).getDistributionDir(); + assertThat( distributionDir.getName(), matchesRegexp( "[a-z0-9]+" ) ); + assertThat( distributionDir.getParentFile(), equalTo( file( currentDirPath() + "/somePath/maven-0.9-bin" ) ) ); + } + + @Test + public void distributionDirWithUnknownBase() + throws Exception + { + configuration.setDistribution( new URI( "http://server/dist/maven-1.0.zip" ) ); + configuration.setDistributionBase( "unknownBase" ); + + try + { + pathAssembler.getDistribution( configuration ); + fail(); + } + catch ( RuntimeException e ) + { + assertEquals( "Base: unknownBase is unknown", e.getMessage() ); + } + } + + @Test + public void distZipWithMavenUserHomeBase() + throws Exception + { + configuration.setDistribution( new URI( "http://server/dist/maven-1.0.zip" ) ); + + File dist = pathAssembler.getDistribution( configuration ).getZipFile(); + assertThat( dist.getName(), equalTo( "maven-1.0.zip" ) ); + assertThat( dist.getParentFile().getName(), matchesRegexp( "[a-z0-9]+" ) ); + assertThat( dist.getParentFile().getParentFile(), + equalTo( file( TEST_MAVEN_USER_HOME + "/somePath/maven-1.0" ) ) ); + } + + @Test + public void distZipWithProjectBase() + throws Exception + { + configuration.setZipBase( PathAssembler.PROJECT_STRING ); + configuration.setDistribution( new URI( "http://server/dist/maven-1.0.zip" ) ); + + File dist = pathAssembler.getDistribution( configuration ).getZipFile(); + assertThat( dist.getName(), equalTo( "maven-1.0.zip" ) ); + assertThat( dist.getParentFile().getName(), matchesRegexp( "[a-z0-9]+" ) ); + assertThat( dist.getParentFile().getParentFile(), equalTo( file( currentDirPath() + "/somePath/maven-1.0" ) ) ); + } + + private File file( String path ) + { + return new File( path ); + } + + private String currentDirPath() + { + return System.getProperty( "user.dir" ); + } + + public static Matcher matchesRegexp( final String pattern ) + { + return new BaseMatcher() + { + public boolean matches( Object o ) + { + return Pattern.compile( pattern ).matcher( (CharSequence) o ).matches(); + } + + public void describeTo( Description description ) + { + description.appendText( "a CharSequence that matches regexp " ).appendValue( pattern ); + } + }; + } +} diff --git a/maven-wrapper/src/test/java/org/apache/maven/wrapper/SystemPropertiesHandlerTest.java b/maven-wrapper/src/test/java/org/apache/maven/wrapper/SystemPropertiesHandlerTest.java new file mode 100644 index 0000000000..54b5d3c596 --- /dev/null +++ b/maven-wrapper/src/test/java/org/apache/maven/wrapper/SystemPropertiesHandlerTest.java @@ -0,0 +1,60 @@ +package org.apache.maven.wrapper; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.Test; + +public class SystemPropertiesHandlerTest +{ + + private File tmpDir = new File( "target/test-files/SystemPropertiesHandlerTest" ); + + @Before + public void setupTempDir() + { + tmpDir.mkdirs(); + } + + @Test + public void testParsePropertiesFile() + throws Exception + { + File propFile = new File( tmpDir, "props" ); + Properties props = new Properties(); + props.put( "a", "b" ); + props.put( "systemProp.c", "d" ); + props.put( "systemProp.", "e" ); + + FileOutputStream fos = null; + try + { + fos = new FileOutputStream( propFile ); + props.store( fos, "" ); + } + finally + { + IOUtils.closeQuietly( fos ); + } + + Map expected = new HashMap(); + expected.put( "c", "d" ); + + assertThat( SystemPropertiesHandler.getSystemProperties( propFile ), equalTo( expected ) ); + } + + @Test + public void ifNoPropertyFileExistShouldReturnEmptyMap() + { + Map expected = new HashMap(); + assertThat( SystemPropertiesHandler.getSystemProperties( new File( tmpDir, "unknown" ) ), equalTo( expected ) ); + } +} diff --git a/maven-wrapper/src/test/java/org/apache/maven/wrapper/WrapperExecutorTest.java b/maven-wrapper/src/test/java/org/apache/maven/wrapper/WrapperExecutorTest.java new file mode 100644 index 0000000000..b258f83c0e --- /dev/null +++ b/maven-wrapper/src/test/java/org/apache/maven/wrapper/WrapperExecutorTest.java @@ -0,0 +1,192 @@ +package org.apache.maven.wrapper; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.net.URI; +import java.util.Properties; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +public class WrapperExecutorTest +{ + private final Installer install; + + private final BootstrapMainStarter start; + + private File propertiesFile; + + private Properties properties = new Properties(); + + private File testDir = new File( "target/test-files/SystemPropertiesHandlerTest-" + System.currentTimeMillis() ); + + private File mockInstallDir = new File( testDir, "mock-dir" ); + + public WrapperExecutorTest() + throws Exception + { + install = mock( Installer.class ); + when( install.createDist( Mockito.any( WrapperConfiguration.class ) ) ).thenReturn( mockInstallDir ); + start = mock( BootstrapMainStarter.class ); + + testDir.mkdirs(); + propertiesFile = new File( testDir, "maven/wrapper/maven-wrapper.properties" ); + + properties.put( "distributionUrl", "http://server/test/maven.zip" ); + properties.put( "distributionBase", "testDistBase" ); + properties.put( "distributionPath", "testDistPath" ); + properties.put( "zipStoreBase", "testZipBase" ); + properties.put( "zipStorePath", "testZipPath" ); + + writePropertiesFile( properties, propertiesFile, "header" ); + + } + + @Test + public void loadWrapperMetadataFromFile() + throws Exception + { + WrapperExecutor wrapper = WrapperExecutor.forWrapperPropertiesFile( propertiesFile, System.out ); + + Assert.assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getDistribution() ); + Assert.assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getConfiguration().getDistribution() ); + Assert.assertEquals( "testDistBase", wrapper.getConfiguration().getDistributionBase() ); + Assert.assertEquals( "testDistPath", wrapper.getConfiguration().getDistributionPath() ); + Assert.assertEquals( "testZipBase", wrapper.getConfiguration().getZipBase() ); + Assert.assertEquals( "testZipPath", wrapper.getConfiguration().getZipPath() ); + } + + @Test + public void loadWrapperMetadataFromDirectory() + throws Exception + { + WrapperExecutor wrapper = WrapperExecutor.forProjectDirectory( testDir, System.out ); + + Assert.assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getDistribution() ); + Assert.assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getConfiguration().getDistribution() ); + Assert.assertEquals( "testDistBase", wrapper.getConfiguration().getDistributionBase() ); + Assert.assertEquals( "testDistPath", wrapper.getConfiguration().getDistributionPath() ); + Assert.assertEquals( "testZipBase", wrapper.getConfiguration().getZipBase() ); + Assert.assertEquals( "testZipPath", wrapper.getConfiguration().getZipPath() ); + } + + @Test + public void useDefaultMetadataNoProeprtiesFile() + throws Exception + { + WrapperExecutor wrapper = WrapperExecutor.forProjectDirectory( new File( testDir, "unknown" ), System.out ); + + Assert.assertNull( wrapper.getDistribution() ); + Assert.assertNull( wrapper.getConfiguration().getDistribution() ); + Assert.assertEquals( PathAssembler.MAVEN_USER_HOME_STRING, wrapper.getConfiguration().getDistributionBase() ); + Assert.assertEquals( Installer.DEFAULT_DISTRIBUTION_PATH, wrapper.getConfiguration().getDistributionPath() ); + Assert.assertEquals( PathAssembler.MAVEN_USER_HOME_STRING, wrapper.getConfiguration().getZipBase() ); + Assert.assertEquals( Installer.DEFAULT_DISTRIBUTION_PATH, wrapper.getConfiguration().getZipPath() ); + } + + @Test + public void propertiesFileOnlyContainsDistURL() + throws Exception + { + + properties = new Properties(); + properties.put( "distributionUrl", "http://server/test/maven.zip" ); + writePropertiesFile( properties, propertiesFile, "header" ); + + WrapperExecutor wrapper = WrapperExecutor.forWrapperPropertiesFile( propertiesFile, System.out ); + + Assert.assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getDistribution() ); + Assert.assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getConfiguration().getDistribution() ); + Assert.assertEquals( PathAssembler.MAVEN_USER_HOME_STRING, wrapper.getConfiguration().getDistributionBase() ); + Assert.assertEquals( Installer.DEFAULT_DISTRIBUTION_PATH, wrapper.getConfiguration().getDistributionPath() ); + Assert.assertEquals( PathAssembler.MAVEN_USER_HOME_STRING, wrapper.getConfiguration().getZipBase() ); + Assert.assertEquals( Installer.DEFAULT_DISTRIBUTION_PATH, wrapper.getConfiguration().getZipPath() ); + } + + @Test + public void executeInstallAndLaunch() + throws Exception + { + WrapperExecutor wrapper = WrapperExecutor.forProjectDirectory( propertiesFile, System.out ); + + wrapper.execute( new String[] { "arg" }, install, start ); + verify( install ).createDist( Mockito.any( WrapperConfiguration.class ) ); + verify( start ).start( new String[] { "arg" }, mockInstallDir ); + } + + @Test( ) + public void failWhenDistNotSetInProperties() + throws Exception + { + properties = new Properties(); + writePropertiesFile( properties, propertiesFile, "header" ); + + try + { + WrapperExecutor.forWrapperPropertiesFile( propertiesFile, System.out ); + Assert.fail( "Expected RuntimeException" ); + } + catch ( RuntimeException e ) + { + Assert.assertEquals( "Could not load wrapper properties from '" + propertiesFile + "'.", e.getMessage() ); + Assert.assertEquals( "No value with key 'distributionUrl' specified in wrapper properties file '" + + propertiesFile + "'.", e.getCause().getMessage() ); + } + + } + + @Test + public void failWhenPropertiesFileDoesNotExist() + { + propertiesFile = new File( testDir, "unknown.properties" ); + + try + { + WrapperExecutor.forWrapperPropertiesFile( propertiesFile, System.out ); + Assert.fail( "Expected RuntimeException" ); + } + catch ( RuntimeException e ) + { + Assert.assertEquals( "Wrapper properties file '" + propertiesFile + "' does not exist.", e.getMessage() ); + } + } + + @Test + public void testRelativeDistUrl() + throws Exception + { + + properties = new Properties(); + properties.put( "distributionUrl", "some/relative/url/to/bin.zip" ); + writePropertiesFile( properties, propertiesFile, "header" ); + + WrapperExecutor wrapper = WrapperExecutor.forWrapperPropertiesFile( propertiesFile, System.out ); + Assert.assertNotEquals( "some/relative/url/to/bin.zip", wrapper.getDistribution().getSchemeSpecificPart() ); + Assert.assertTrue( wrapper.getDistribution().getSchemeSpecificPart().endsWith( "some/relative/url/to/bin.zip" ) ); + } + + private void writePropertiesFile( Properties properties, File propertiesFile, String message ) + throws Exception + { + + propertiesFile.getParentFile().mkdirs(); + + OutputStream outStream = null; + try + { + outStream = new FileOutputStream( propertiesFile ); + properties.store( outStream, message ); + } + finally + { + IOUtils.closeQuietly( outStream ); + } + } +} diff --git a/maven-wrapper/src/test/resources/org/apache/maven/wrapper/wrapper.properties b/maven-wrapper/src/test/resources/org/apache/maven/wrapper/wrapper.properties new file mode 100644 index 0000000000..6ff45e7805 --- /dev/null +++ b/maven-wrapper/src/test/resources/org/apache/maven/wrapper/wrapper.properties @@ -0,0 +1,5 @@ +distributionUrl=http://server/test/maven.zip +distributionBase=testDistBase +zipStoreBase=testZipBase +distributionPath=testDistPath +zipStorePath=testZipPath