You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by hb...@apache.org on 2021/10/25 17:09:45 UTC

[maven-wrapper-plugin] branch MWRAPPER-14 created (now cd1ca3a)

This is an automated email from the ASF dual-hosted git repository.

hboutemy pushed a change to branch MWRAPPER-14
in repository https://gitbox.apache.org/repos/asf/maven-wrapper-plugin.git.


      at cd1ca3a  [MWRAPPER-14] first step at putting all wrapper pieces in one build

This branch includes the following new commits:

     new cd1ca3a  [MWRAPPER-14] first step at putting all wrapper pieces in one build

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[maven-wrapper-plugin] 01/01: [MWRAPPER-14] first step at putting all wrapper pieces in one build

Posted by hb...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

hboutemy pushed a commit to branch MWRAPPER-14
in repository https://gitbox.apache.org/repos/asf/maven-wrapper-plugin.git

commit cd1ca3abd0e332e54be0ef4f04c6f9c8b05d262f
Author: Hervé Boutemy <hb...@apache.org>
AuthorDate: Mon Oct 25 19:07:39 2021 +0200

    [MWRAPPER-14] first step at putting all wrapper pieces in one build
    
    - wrapper (maven-wrapper.jar)
    - wrapper distribution (mvnw scripts)
    - wrapper plugin
---
 maven-wrapper-distribution/pom.xml                 | 132 ++++++++++++
 maven-wrapper-distribution/src/assembly/bin.xml    |  85 ++++++++
 maven-wrapper-distribution/src/assembly/maven/init |  86 ++++++++
 .../src/assembly/maven/init.cmd                    |  94 +++++++++
 maven-wrapper-distribution/src/assembly/maven/run  |  19 ++
 .../src/assembly/maven/run.cmd                     |  31 +++
 .../src/assembly/maven/validate                    |  53 +++++
 .../src/assembly/maven/validate.cmd                |  70 +++++++
 maven-wrapper-distribution/src/assembly/script.xml |  77 +++++++
 .../src/assembly/script/download                   |  51 +++++
 .../src/assembly/script/download.cmd               |  32 +++
 .../shared/mvn/wrapper/maven-wrapper.properties    |   7 +-
 .../src/assembly/shared/mvnwDebug                  |  35 ++++
 .../src/assembly/shared/mvnwDebug.cmd              |  44 ++++
 .../src/assembly/shared/mvnwlauncher               |   3 +
 .../src/assembly/shared/mvnwlauncher.cmd           |   3 +
 maven-wrapper-distribution/src/assembly/source.xml |  82 ++++++++
 .../src/assembly/source/download                   |  34 +++
 .../src/assembly/source/download.cmd               |  21 ++
 .../source/mvn/wrapper/MavenWrapperDownloader.java | 131 ++++++++++++
 .../src/site/apt/index.apt.vm                      |  58 ++++++
 .../src/site/site.xml                              |  16 +-
 pom.xml => maven-wrapper-plugin/pom.xml            |  58 +-----
 .../src/it/projects/default}/invoker.properties    |   0
 .../src/it/projects/default}/pom.xml               |   0
 .../src}/it/projects/default/verify.groovy         |   0
 .../it/projects/excludeDebug}/invoker.properties   |   0
 .../src/it/projects/excludeDebug}/pom.xml          |   0
 .../src}/it/projects/excludeDebug/test.properties  |   0
 .../src}/it/projects/excludeDebug/verify.groovy    |   0
 .../src}/it/projects/extension/invoker.properties  |   0
 .../src}/it/projects/extension/pom.xml             |   0
 .../src}/it/projects/extension/verify.groovy       |   0
 .../src}/it/projects/maven3/invoker.properties     |   0
 .../src}/it/projects/maven3/pom.xml                |   0
 .../src}/it/projects/maven3/verify.groovy          |   0
 .../it/projects/mavenversion/invoker.properties    |   0
 .../src/it/projects/mavenversion}/pom.xml          |   0
 .../src}/it/projects/mavenversion/test.properties  |   0
 .../src/it/projects/mavenversion}/verify.groovy    |   0
 .../src/it/projects/type_bin}/invoker.properties   |   0
 .../src/it/projects/type_bin}/pom.xml              |   0
 .../src}/it/projects/type_bin/test.properties      |   0
 .../src}/it/projects/type_bin/verify.groovy        |   0
 .../it/projects/type_source}/invoker.properties    |   0
 .../src/it/projects/type_source}/pom.xml           |   0
 .../src}/it/projects/type_source/test.properties   |   0
 .../src}/it/projects/type_source/verify.groovy     |   0
 .../it/projects/wrapperversion/invoker.properties  |   0
 .../src/it/projects/wrapperversion}/pom.xml        |   0
 .../it/projects/wrapperversion/test.properties     |   0
 .../src/it/projects/wrapperversion}/verify.groovy  |   0
 {src => maven-wrapper-plugin/src}/it/settings.xml  |   0
 .../apache/maven/plugins/wrapper/WrapperMojo.java  |   2 +-
 .../main/resources/META-INF/plexus/components.xml  |   0
 .../src}/site/markdown/index.md.vm                 |   0
 .../src}/site/markdown/usage.md                    |   0
 .../src}/site/resources/download.cgi               |   0
 {src => maven-wrapper-plugin/src}/site/site.xml    |   0
 .../src}/site/xdoc/download.xml.vm                 |   0
 maven-wrapper/pom.xml                              |  67 ++++++
 .../apache/maven/wrapper/BootstrapMainStarter.java |  64 ++++++
 .../apache/maven/wrapper/DefaultDownloader.java    | 190 +++++++++++++++++
 .../java/org/apache/maven/wrapper/Downloader.java  |  54 +++++
 .../java/org/apache/maven/wrapper/Installer.java   | 231 +++++++++++++++++++++
 .../main/java/org/apache/maven/wrapper/Logger.java |  29 ++-
 .../org/apache/maven/wrapper/MavenWrapperMain.java | 107 ++++++++++
 .../org/apache/maven/wrapper/PathAssembler.java    | 131 ++++++++++++
 .../apache/maven/wrapper/WrapperConfiguration.java | 116 +++++++++++
 .../org/apache/maven/wrapper/WrapperExecutor.java  | 178 ++++++++++++++++
 maven-wrapper/src/site/apt/index.apt               |  30 +++
 {src => maven-wrapper/src}/site/site.xml           |  24 +--
 .../org/apache/maven/wrapper/DownloaderTest.java   |  71 +++++++
 .../org/apache/maven/wrapper/InstallerTest.java    | 214 +++++++++++++++++++
 .../apache/maven/wrapper/PathAssemblerTest.java    | 115 ++++++++++
 .../apache/maven/wrapper/WrapperExecutorTest.java  | 202 ++++++++++++++++++
 .../org/apache/maven/wrapper/wrapper.properties    |  11 +-
 pom.xml                                            |  75 ++-----
 78 files changed, 2981 insertions(+), 152 deletions(-)

diff --git a/maven-wrapper-distribution/pom.xml b/maven-wrapper-distribution/pom.xml
new file mode 100644
index 0000000..f9c49d7
--- /dev/null
+++ b/maven-wrapper-distribution/pom.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.maven</groupId>
+    <artifactId>maven-wrapper-parent</artifactId>
+    <version>3.0.3-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-wrapper-distribution</artifactId>
+  <packaging>pom</packaging>
+
+  <name>Maven Wrapper Distribution</name>
+  <description>The Maven Wrapper distribution zips in 3 types: script, bin and source.</description>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.rat</groupId>
+          <artifactId>apache-rat-plugin</artifactId>
+          <configuration>
+            <excludes combine.children="append">
+              <exclude>src/assembly/maven/bin/m2.conf</exclude>
+              <!-- these are partial scripts, resulting in mwnw scripts -->
+              <exclude>src/assembly/maven/init</exclude>
+              <exclude>src/assembly/maven/init.cmd</exclude>
+              <exclude>src/assembly/maven/run</exclude>
+              <exclude>src/assembly/maven/run.cmd</exclude>
+              <exclude>src/assembly/shared/mvnwlauncher</exclude>
+              <exclude>src/assembly/shared/mvnwlauncher.cmd</exclude>
+              <exclude>src/assembly/*/download</exclude>
+              <exclude>src/assembly/*/download.cmd</exclude>
+            </excludes>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-clean-plugin</artifactId>
+          <configuration>
+            <skip>true</skip> <!-- sharing outputDirectory with maven-dist -->
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <descriptors>
+            <descriptor>src/assembly/script.xml</descriptor>
+            <descriptor>src/assembly/bin.xml</descriptor>
+            <descriptor>src/assembly/source.xml</descriptor>
+          </descriptors>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-wrapper</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>apache-release</id>
+      <build>
+        <plugins>
+          <!-- calculate sha512 checksums -->
+          <plugin>
+            <groupId>net.nicoulaj.maven.plugins</groupId>
+            <artifactId>checksum-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>source-release-checksum</id>
+                <goals>
+                  <goal>files</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <fileSets>
+                <fileSet>
+                  <directory>${project.build.directory}</directory>
+                  <includes>
+                    <include>${project.artifactId}-${project.version}-bin.zip</include>
+                    <include>${project.artifactId}-${project.version}-script.zip</include>
+                    <include>${project.artifactId}-${project.version}-source.zip</include>
+                  </includes>
+                </fileSet>
+              </fileSets>
+              <failIfNoFiles>true</failIfNoFiles>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
diff --git a/maven-wrapper-distribution/src/assembly/bin.xml b/maven-wrapper-distribution/src/assembly/bin.xml
new file mode 100644
index 0000000..131d518
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/bin.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
+  <id>bin</id>
+  <formats>
+    <format>zip</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  <dependencySets>
+    <dependencySet>
+      <useProjectArtifact>false</useProjectArtifact>
+      <includes>
+        <include>org.apache.maven:maven-wrapper:jar:*</include>
+      </includes>
+      <outputDirectory>.mvn/wrapper</outputDirectory>
+      <outputFileNameMapping>maven-wrapper.jar</outputFileNameMapping>
+    </dependencySet>
+  </dependencySets>
+  <files>
+    <file>
+      <source>src/assembly/shared/mvnwDebug.cmd</source>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>dos</lineEnding>
+    </file>
+    <file>
+      <source>src/assembly/shared/mvnwDebug</source>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>unix</lineEnding>
+      <fileMode>0755</fileMode>
+    </file>
+    <file>
+      <sources>
+        <source>src/assembly/maven/validate.cmd</source>
+        <source>src/assembly/maven/init.cmd</source>
+        <source>src/assembly/shared/mvnwlauncher.cmd</source>
+        <source>src/assembly/maven/run.cmd</source>
+      </sources>
+      <destName>mvnw.cmd</destName>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>dos</lineEnding>
+      <filtered>true</filtered>
+    </file>
+    <file>
+      <sources>
+        <source>src/assembly/maven/validate</source>
+        <source>src/assembly/maven/init</source>
+        <source>src/assembly/shared/mvnwlauncher</source>
+        <source>src/assembly/maven/run</source>
+      </sources>
+      <destName>mvnw</destName>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>unix</lineEnding>
+      <fileMode>0755</fileMode>
+      <filtered>true</filtered>
+    </file>
+  </files>
+  <fileSets>
+    <fileSet>
+      <directory>src/assembly/shared/mvn</directory>
+      <outputDirectory>.mvn</outputDirectory>
+      <filtered>true</filtered>
+    </fileSet>
+  </fileSets>
+</assembly>
diff --git a/maven-wrapper-distribution/src/assembly/maven/init b/maven-wrapper-distribution/src/assembly/maven/init
new file mode 100755
index 0000000..619bc4d
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/maven/init
@@ -0,0 +1,86 @@
+CLASSWORLDS_CONF="$MAVEN_HOME/bin/m2.conf"
+
+# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
+if $cygwin || $mingw ; then
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+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"
+
+    if [ ! -x "$JAVACMD" ] ; then
+      echo "The JAVA_HOME environment variable is not defined correctly, so Apache Maven cannot be started." >&2
+      echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" does not exist." >&2
+      exit 1
+    fi
+  fi
+else
+  JAVACMD="`\\unset -f command; \\command -v java`"
+
+  if [ ! -x "$JAVACMD" ] ; then
+    echo "The java(1) command does not exist in PATH nor is JAVA_HOME set, so Apache Maven cannot be started." >&2
+    exit 1
+  fi
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+(
+  basedir=`find_file_argument_basedir "$@"`
+  wdir="$basedir"
+  while [ "$wdir" != '/' ] ; do
+    if [ -d "$wdir"/.mvn ] ; then
+      basedir=$wdir
+      break
+    fi
+    wdir=`cd "$wdir/.."; pwd`
+  done
+  echo "$basedir"
+)
+}
+
+find_file_argument_basedir() {
+(
+  basedir=`pwd`
+
+  found_file_switch=0
+  for arg in "$@"; do
+    if [ ${found_file_switch} -eq 1 ]; then
+      if [ -d "${arg}" ]; then
+        basedir=`cd "${arg}" && pwd -P`
+      elif [ -f "${arg}" ]; then
+        basedir=`dirname "${arg}"`
+        basedir=`cd "$basedir" && pwd -P`
+        if [ ! -d "$basedir" ]; then
+          echo "Directory $basedir extracted from the -f/--file command-line argument ${arg} does not exist" >&2
+          exit 1
+        fi
+      else
+        echo "POM file ${arg} specified with the -f/--file command line argument does not exist" >&2
+        exit 1
+      fi
+      break
+    fi
+    if [ "$arg" = "-f" -o "$arg" = "--file" ]; then
+      found_file_switch=1
+    fi
+  done
+  echo "$basedir"
+)
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    echo "`tr -s '\r\n' '  ' < "$1"`"
+  fi
+}
+
+MAVEN_PROJECTBASEDIR="`find_maven_basedir "$@"`"
+MAVEN_OPTS="`concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config"` $MAVEN_OPTS"
diff --git a/maven-wrapper-distribution/src/assembly/maven/init.cmd b/maven-wrapper-distribution/src/assembly/maven/init.cmd
new file mode 100755
index 0000000..8b1eb67
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/maven/init.cmd
@@ -0,0 +1,94 @@
+@REM ==== END VALIDATION ====
+
+:init
+
+set "CLASSWORLDS_CONF=%MAVEN_HOME%\bin\m2.conf"
+
+@REM Find the project basedir, i.e., the directory that contains the directory ".mvn".
+@REM Fallback to current working directory if not found.
+
+set "EXEC_DIR=%CD%"
+set "WDIR=%EXEC_DIR%"
+
+@REM Look for the --file switch and start the search for the .mvn directory from the specified
+@REM POM location, if supplied.
+
+set FILE_ARG=
+:arg_loop
+if "%~1" == "-f" (
+  set "FILE_ARG=%~2"
+  shift
+  goto process_file_arg
+)
+if "%~1" == "--file" (
+  set "FILE_ARG=%~2"
+  shift
+  goto process_file_arg
+)
+@REM If none of the above, skip the argument
+shift
+if not "%~1" == "" (
+  goto arg_loop
+) else (
+  goto findBaseDir
+)
+
+:process_file_arg
+if "%FILE_ARG%" == "" (
+  goto findBaseDir
+)
+if not exist "%FILE_ARG%" (
+  echo POM file "%FILE_ARG%" specified the -f/--file command-line argument does not exist >&2
+  goto error
+)
+if exist "%FILE_ARG%\*" (
+  set "POM_DIR=%FILE_ARG%"
+) else (
+  call :get_directory_from_file "%FILE_ARG%"
+)
+if not exist "%POM_DIR%" (
+  echo Directory "%POM_DIR%" extracted from the -f/--file command-line argument "%FILE_ARG%" does not exist >&2
+  goto error
+)
+set "WDIR=%POM_DIR%"
+goto findBaseDir
+
+:get_directory_from_file
+set "POM_DIR=%~dp1"
+:stripPomDir
+if not "_%POM_DIR:~-1%"=="_\" goto pomDirStripped
+set "POM_DIR=%POM_DIR:~0,-1%"
+goto stripPomDir
+:pomDirStripped
+exit /b
+
+:findBaseDir
+cd /d "%WDIR%"
+:findBaseDirLoop
+if exist "%WDIR%\.mvn" goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set "WDIR=%CD%"
+goto findBaseDirLoop
+
+:baseDirFound
+set "MAVEN_PROJECTBASEDIR=%WDIR%"
+cd /d "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+if "_%EXEC_DIR:~-1%"=="_\" set "EXEC_DIR=%EXEC_DIR:~0,-1%"
+set "MAVEN_PROJECTBASEDIR=%EXEC_DIR%"
+cd /d "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+set "jvmConfig=\.mvn\jvm.config"
+if not exist "%MAVEN_PROJECTBASEDIR%%jvmConfig%" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
diff --git a/maven-wrapper-distribution/src/assembly/maven/run b/maven-wrapper-distribution/src/assembly/maven/run
new file mode 100755
index 0000000..69535d6
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/maven/run
@@ -0,0 +1,19 @@
+# For Cygwin and MinGW, switch paths to Windows format before running java(1) command
+if $cygwin || $mingw ; then
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --windows "$JAVA_HOME"`
+  LAUNCHER_JAR=`cygpath --windows "$LAUNCHER_JAR"`
+  CLASSWORLDS_CONF=`cygpath --windows "$CLASSWORLDS_CONF"`
+  MAVEN_HOME=`cygpath --windows "$MAVEN_HOME"`
+  MAVEN_PROJECTBASEDIR=`cygpath --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  $MAVEN_DEBUG_OPTS \
+  -classpath "$LAUNCHER_JAR" \
+  "-Dclassworlds.conf=$CLASSWORLDS_CONF" \
+  "-Dmaven.home=$MAVEN_HOME" \
+  "-Dlibrary.jansi.path=${MAVEN_HOME}/lib/jansi-native" \
+  "-Dmaven.multiModuleProjectDirectory=$MAVEN_PROJECTBASEDIR" \
+  $LAUNCHER_CLASS "$@"
diff --git a/maven-wrapper-distribution/src/assembly/maven/run.cmd b/maven-wrapper-distribution/src/assembly/maven/run.cmd
new file mode 100755
index 0000000..ac526f8
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/maven/run.cmd
@@ -0,0 +1,31 @@
+"%JAVACMD%" ^
+  %JVM_CONFIG_MAVEN_PROPS% ^
+  %MAVEN_OPTS% ^
+  %MAVEN_DEBUG_OPTS% ^
+  -classpath %LAUNCHER_JAR% ^
+  "-Dclassworlds.conf=%CLASSWORLDS_CONF%" ^
+  "-Dmaven.home=%MAVEN_HOME%" ^
+  "-Dlibrary.jansi.path=%MAVEN_HOME%\lib\jansi-native" ^
+  "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+  %LAUNCHER_CLASS% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" echo Warning: The mavenrc_post.bat script is deprecated and will be removed in a future version. >&2
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" echo Warning: The mavenrc_post.cmd script is deprecated and will be removed in a future version. >&2
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+exit /b %ERROR_CODE%
diff --git a/maven-wrapper-distribution/src/assembly/maven/validate b/maven-wrapper-distribution/src/assembly/maven/validate
new file mode 100644
index 0000000..0d22a8b
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/maven/validate
@@ -0,0 +1,53 @@
+#!/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.
+
+# -----------------------------------------------------------------------------
+# Apache Maven Startup Script
+#
+# Environment Variable Prerequisites
+#
+#   JAVA_HOME       (Optional) Points to a Java installation.
+#   MAVEN_OPTS      (Optional) Java runtime options used when Maven is executed.
+#   MAVEN_SKIP_RC   (Optional) Flag to disable loading of mavenrc files.
+# -----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+  if [ -f /usr/local/etc/mavenrc ] ; then
+    . /usr/local/etc/mavenrc
+  fi
+
+  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;
+mingw=false;
+case "`uname`" in
+  CYGWIN*) cygwin=true;;
+  MINGW*) mingw=true;;
+esac
+
diff --git a/maven-wrapper-distribution/src/assembly/maven/validate.cmd b/maven-wrapper-distribution/src/assembly/maven/validate.cmd
new file mode 100644
index 0000000..dc68027
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/maven/validate.cmd
@@ -0,0 +1,70 @@
+@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 Apache Maven Startup Script
+@REM
+@REM Environment Variable Prerequisites
+@REM
+@REM   JAVA_HOME         (Optional) Points to a Java installation.
+@REM   MAVEN_BATCH_ECHO  (Optional) Set to 'on' to enable the echoing of the batch commands.
+@REM   MAVEN_BATCH_PAUSE (Optional) set to 'on' to wait for a key stroke before ending.
+@REM   MAVEN_OPTS        (Optional) Java runtime options used when Maven is executed.
+@REM   MAVEN_SKIP_RC     (Optional) Flag to disable loading of mavenrc files.
+@REM -----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%"=="on" echo %MAVEN_BATCH_ECHO%
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%"=="" goto skipRc
+if exist "%PROGRAMDATA%\mavenrc.cmd" call "%PROGRAMDATA%\mavenrc.cmd" %*
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" echo Warning: The mavenrc_pre.bat script is deprecated and will be removed in a future version. >&2
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" echo Warning: The mavenrc_pre.cmd script is deprecated and will be removed in a future version. >&2
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+if exist "%USERPROFILE%\mavenrc.cmd" call "%USERPROFILE%\mavenrc.cmd" %*
+:skipRc
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%"=="" goto javaHomeSet
+for %%i in (java.exe) do set "JAVACMD=%%~$PATH:i"
+goto checkJavaCmd
+
+:javaHomeSet
+set "JAVACMD=%JAVA_HOME%\bin\java.exe"
+
+if not exist "%JAVACMD%" (
+  echo The JAVA_HOME environment variable is not defined correctly, so Apache Maven cannot be started. >&2
+  echo JAVA_HOME is set to "%JAVA_HOME%", but "%%JAVA_HOME%%\bin\java.exe" does not exist. >&2
+  goto error
+)
+
+:checkJavaCmd
+if not exist "%JAVACMD%" (
+  echo The java.exe command does not exist in PATH nor is JAVA_HOME set, so Apache Maven cannot be started. >&2
+  goto error
+)
diff --git a/maven-wrapper-distribution/src/assembly/script.xml b/maven-wrapper-distribution/src/assembly/script.xml
new file mode 100644
index 0000000..3873bfb
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/script.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
+  <id>script</id>
+  <formats>
+    <format>zip</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  <files>
+    <file>
+      <source>src/assembly/shared/mvnwDebug.cmd</source>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>dos</lineEnding>
+    </file>
+    <file>
+      <source>src/assembly/shared/mvnwDebug</source>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>unix</lineEnding>
+      <fileMode>0755</fileMode>
+    </file>
+    <file>
+      <sources>
+        <source>src/assembly/maven/validate.cmd</source>
+        <source>src/assembly/maven/init.cmd</source>
+        <source>src/assembly/shared/mvnwlauncher.cmd</source>
+        <source>src/assembly/script/download.cmd</source>
+        <source>src/assembly/maven/run.cmd</source>
+      </sources>
+      <destName>mvnw.cmd</destName>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>dos</lineEnding>
+      <filtered>true</filtered>
+    </file>
+    <file>
+      <sources>
+        <source>src/assembly/maven/validate</source>
+        <source>src/assembly/maven/init</source>
+        <source>src/assembly/shared/mvnwlauncher</source>
+        <source>src/assembly/script/download</source>
+        <source>src/assembly/maven/run</source>
+      </sources>
+      <destName>mvnw</destName>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>unix</lineEnding>
+      <fileMode>0755</fileMode>
+      <filtered>true</filtered>
+    </file>
+  </files>
+  <fileSets>
+    <fileSet>
+      <directory>src/assembly/shared/mvn</directory>
+      <outputDirectory>.mvn</outputDirectory>
+      <filtered>true</filtered>
+    </fileSet>
+  </fileSets>
+</assembly>
diff --git a/maven-wrapper-distribution/src/assembly/script/download b/maven-wrapper-distribution/src/assembly/script/download
new file mode 100755
index 0000000..ed8243e
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/script/download
@@ -0,0 +1,51 @@
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
+    fi
+else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+    fi
+
+    jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/maven-wrapper/${project.version}/maven-wrapper-${project.version}.jar"
+
+    if [ -n "$MVNW_REPOURL" ]; then
+      jarUrl="$MVNW_REPOURL/org/apache/maven/maven-wrapper/${project.version}/maven-wrapper-${project.version}.jar"
+    fi
+
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Downloading from: $jarUrl"
+    fi
+    wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+    if $cygwin; then
+      wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+    fi
+
+    if [ `echo "${jarUrl}" | cut -c 1-4` != 'file' ] && command -v wget > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found wget ... using wget"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        else
+            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        fi
+    elif command -v curl > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found curl ... using curl"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            curl --location -o "$wrapperJarPath" "$jarUrl" -f
+        else
+            curl --location --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
diff --git a/maven-wrapper-distribution/src/assembly/script/download.cmd b/maven-wrapper-distribution/src/assembly/script/download.cmd
new file mode 100755
index 0000000..9166b9a
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/script/download.cmd
@@ -0,0 +1,32 @@
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+IF NOT EXIST %LAUNCHER_JAR% goto downloadWrapper
+
+if "%MVNW_VERBOSE%" == "true" ECHO Found %LAUNCHER_JAR%
+goto endWrapper
+
+:downloadWrapper
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/maven-wrapper/${project.version}/maven-wrapper-${project.version}.jar"
+
+if not "%MVNW_REPOURL%" == "" (
+    SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/maven-wrapper/${project.version}/maven-wrapper-${project.version}.jar"
+)
+if "%MVNW_VERBOSE%" == "true" (
+    echo Couldn't find %LAUNCHER_JAR%, downloading it ...
+    echo Downloading from: %DOWNLOAD_URL%
+)
+
+powershell -Command "&{"^
+    "$webclient = new-object System.Net.WebClient;"^
+    "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+    "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+    "}"^
+    "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%LAUNCHER_JAR%')"^
+    "}"
+if "%MVNW_VERBOSE%" == "true" (
+    echo Finished downloading %LAUNCHER_JAR%
+)
+
+:endWrapper
+@REM End of extension
+
diff --git a/src/it/projects/excludeDebug/invoker.properties b/maven-wrapper-distribution/src/assembly/shared/mvn/wrapper/maven-wrapper.properties
similarity index 84%
copy from src/it/projects/excludeDebug/invoker.properties
copy to maven-wrapper-distribution/src/assembly/shared/mvn/wrapper/maven-wrapper.properties
index 3125747..6fda8be 100644
--- a/src/it/projects/excludeDebug/invoker.properties
+++ b/maven-wrapper-distribution/src/assembly/shared/mvn/wrapper/maven-wrapper.properties
@@ -5,14 +5,13 @@
 # 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.
-invoker.maven.version = 4+
-invoker.goals = org.apache.maven.plugins:maven-wrapper-plugin:${project.version}:wrapper
\ No newline at end of file
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/${project.version}/apache-maven-${project.version}-bin.zip
diff --git a/maven-wrapper-distribution/src/assembly/shared/mvnwDebug b/maven-wrapper-distribution/src/assembly/shared/mvnwDebug
new file mode 100644
index 0000000..3e66a1a
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/shared/mvnwDebug
@@ -0,0 +1,35 @@
+#!/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.
+
+# -----------------------------------------------------------------------------
+# Apache Maven Debug Script
+#
+# Environment Variable Prerequisites
+#
+#   JAVA_HOME           (Optional) Points to a Java installation.
+#   MAVEN_OPTS          (Optional) Java runtime options used when Maven is executed.
+#   MAVEN_SKIP_RC       (Optional) Flag to disable loading of mavenrc files.
+#   MAVEN_DEBUG_ADDRESS (Optional) Set the debug address. Default value is localhost:8000
+# -----------------------------------------------------------------------------
+
+MAVEN_DEBUG_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${MAVEN_DEBUG_ADDRESS:-localhost:8000}"
+
+echo Preparing to execute Maven Wrapper in debug mode
+
+env MAVEN_OPTS="$MAVEN_OPTS" MAVEN_DEBUG_OPTS="$MAVEN_DEBUG_OPTS" "`dirname "$0"`/mvnw" "$@"
diff --git a/maven-wrapper-distribution/src/assembly/shared/mvnwDebug.cmd b/maven-wrapper-distribution/src/assembly/shared/mvnwDebug.cmd
new file mode 100644
index 0000000..52368be
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/shared/mvnwDebug.cmd
@@ -0,0 +1,44 @@
+@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 Apache Maven Debug Script
+@REM
+@REM Environment Variable Prerequisites
+@REM
+@REM   JAVA_HOME           (Optional) Points to a Java installation.
+@REM   MAVEN_BATCH_ECHO    (Optional) Set to 'on' to enable the echoing of the batch commands.
+@REM   MAVEN_BATCH_PAUSE   (Optional) set to 'on' to wait for a key stroke before ending.
+@REM   MAVEN_OPTS          (Optional) Java runtime options used when Maven is executed.
+@REM   MAVEN_SKIP_RC       (Optional) Flag to disable loading of mavenrc files.
+@REM   MAVEN_DEBUG_ADDRESS (Optional) Set the debug address. Default value is localhost:8000
+@REM -----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%"=="on" echo %MAVEN_BATCH_ECHO%
+
+@setlocal
+
+IF "%MAVEN_DEBUG_ADDRESS%"=="" @set MAVEN_DEBUG_ADDRESS=localhost:8000
+
+@set MAVEN_DEBUG_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=%MAVEN_DEBUG_ADDRESS%
+
+@call "%~dp0"mvnw.cmd %*
diff --git a/maven-wrapper-distribution/src/assembly/shared/mvnwlauncher b/maven-wrapper-distribution/src/assembly/shared/mvnwlauncher
new file mode 100755
index 0000000..3fbd254
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/shared/mvnwlauncher
@@ -0,0 +1,3 @@
+LAUNCHER_JAR="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+LAUNCHER_CLASS=org.apache.maven.wrapper.MavenWrapperMain
+
diff --git a/maven-wrapper-distribution/src/assembly/shared/mvnwlauncher.cmd b/maven-wrapper-distribution/src/assembly/shared/mvnwlauncher.cmd
new file mode 100755
index 0000000..193db12
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/shared/mvnwlauncher.cmd
@@ -0,0 +1,3 @@
+set LAUNCHER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set LAUNCHER_CLASS=org.apache.maven.wrapper.MavenWrapperMain
+
diff --git a/maven-wrapper-distribution/src/assembly/source.xml b/maven-wrapper-distribution/src/assembly/source.xml
new file mode 100644
index 0000000..8218cfb
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/source.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
+  <id>source</id>
+  <formats>
+    <format>zip</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  <files>
+    <file>
+      <source>src/assembly/shared/mvnwDebug.cmd</source>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>dos</lineEnding>
+    </file>
+    <file>
+      <source>src/assembly/shared/mvnwDebug</source>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>unix</lineEnding>
+      <fileMode>0755</fileMode>
+    </file>
+    <file>
+      <sources>
+        <source>src/assembly/maven/validate.cmd</source>
+        <source>src/assembly/maven/init.cmd</source>
+        <source>src/assembly/shared/mvnwlauncher.cmd</source>
+        <source>src/assembly/source/download.cmd</source>
+        <source>src/assembly/maven/run.cmd</source>
+      </sources>
+      <destName>mvnw.cmd</destName>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>dos</lineEnding>
+      <filtered>true</filtered>
+    </file>
+    <file>
+      <sources>
+        <source>src/assembly/maven/validate</source>
+        <source>src/assembly/maven/init</source>
+        <source>src/assembly/shared/mvnwlauncher</source>
+        <source>src/assembly/source/download</source>
+        <source>src/assembly/maven/run</source>
+      </sources>
+      <destName>mvnw</destName>
+      <outputDirectory>.</outputDirectory>
+      <lineEnding>unix</lineEnding>
+      <fileMode>0755</fileMode>
+      <filtered>true</filtered>
+    </file>
+  </files>
+  <fileSets>
+    <fileSet>
+      <directory>src/assembly/shared/mvn</directory>
+      <outputDirectory>.mvn</outputDirectory>
+      <filtered>true</filtered>
+    </fileSet>
+    <fileSet>
+      <directory>src/assembly/source/mvn</directory>
+      <outputDirectory>.mvn</outputDirectory>
+      <filtered>true</filtered>
+    </fileSet>
+  </fileSets>
+</assembly>
diff --git a/maven-wrapper-distribution/src/assembly/source/download b/maven-wrapper-distribution/src/assembly/source/download
new file mode 100644
index 0000000..30cf5e4
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/source/download
@@ -0,0 +1,34 @@
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
+    fi
+else
+    javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
+    # For Cygwin, switch paths to Windows format before running javac
+    if $cygwin; then
+      javaClass=`cygpath --path --windows "$javaClass"`
+    fi
+    if [ -e "$javaClass" ]; then
+        if [ ! -e "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+            if [ "$MVNW_VERBOSE" = true ]; then
+              echo " - Compiling MavenWrapperDownloader.java ..."
+            fi
+            # Compiling the Java class
+            ("$JAVA_HOME/bin/javac" "$javaClass")
+        fi
+        if [ -e "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+            # Running the downloader
+            if [ "$MVNW_VERBOSE" = true ]; then
+              echo " - Running MavenWrapperDownloader.java ..."
+            fi
+            ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
diff --git a/maven-wrapper-distribution/src/assembly/source/download.cmd b/maven-wrapper-distribution/src/assembly/source/download.cmd
new file mode 100644
index 0000000..40d8451
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/source/download.cmd
@@ -0,0 +1,21 @@
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+
+SET javaClass="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\MavenWrapperDownloader.java"
+IF EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\MavenDownloader.class" goto :runDownloader
+
+if "%MVNW_VERBOSE%" == "true" echo  - Compiling MavenWrapperDownloader.java ...
+
+@REM Compiling the Java class
+"%JAVA_HOME%\bin\javac" %javaClass%
+
+:runDownloader
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\MavenWrapperDownloader.class" goto endWrapper
+
+if "%MVNW_VERBOSE%" == "true" echo  - Running MavenWrapperDownloader.class ...
+@REM Running the downloader
+"%JAVA_HOME%\bin\java" -cp "%MAVEN_PROJECTBASEDIR%\.mvn\wrapper" MavenWrapperDownloader "%MAVEN_PROJECTBASEDIR%"
+
+:endWrapper
+@REM End of extension
+
diff --git a/maven-wrapper-distribution/src/assembly/source/mvn/wrapper/MavenWrapperDownloader.java b/maven-wrapper-distribution/src/assembly/source/mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..29c5656
--- /dev/null
+++ b/maven-wrapper-distribution/src/assembly/source/mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2007-present 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.
+ */
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.util.Objects;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+    private static final String WRAPPER_VERSION = "${project.version}";
+
+    /**
+     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+     */
+    private static final String DEFAULT_DOWNLOAD_PATH = "/org/apache/maven/maven-wrapper/"
+        + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+    /**
+     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+     * use instead of the default one.
+     */
+    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+            ".mvn/wrapper/maven-wrapper.properties";
+
+    /**
+     * Path where the maven-wrapper.jar will be saved to.
+     */
+    private static final String MAVEN_WRAPPER_JAR_PATH =
+            ".mvn/wrapper/maven-wrapper.jar";
+
+    /**
+     * Name of the property which should be used to override the default download url for the wrapper.
+     */
+    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+    public static void main( String args[] ) {
+        System.out.println("- Downloader started");
+        File baseDirectory = new File(args[0]);
+        System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+        // If the maven-wrapper.properties exists, read it and check if it contains a custom
+        // wrapperUrl parameter.
+        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+
+        String url = null;
+
+        String repoUrl = System.getenv( "MVNW_REPOURL" );
+        if ( repoUrl != null )
+        {
+            url = repoUrl + DEFAULT_DOWNLOAD_PATH;
+        }
+        else if ( mavenWrapperPropertyFile.exists() )
+        {
+            Properties mavenWrapperProperties = new Properties();
+            try ( InputStream mavenWrapperPropertyFileInputStream = new FileInputStream( mavenWrapperPropertyFile ) )
+            {
+                mavenWrapperProperties.load( mavenWrapperPropertyFileInputStream );
+                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+            }
+            catch ( IOException e )
+            {
+                System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+            }
+        }
+
+        if ( url == null )
+        {
+            url = "https://repo.maven.apache.org/maven2" + DEFAULT_DOWNLOAD_PATH;
+        }
+        System.out.println("- Downloading from: " + url);
+
+        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+        if(!outputFile.getParentFile().exists()) {
+            if(!outputFile.getParentFile().mkdirs()) {
+                System.out.println(
+                        "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+            }
+        }
+        System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+        try {
+            downloadFileFromURL(url, outputFile);
+            System.out.println("Done");
+            System.exit(0);
+        } catch (Throwable e) {
+            System.out.println("- Error downloading");
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+        if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+            String username = System.getenv("MVNW_USERNAME");
+            char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+            Authenticator.setDefault(new Authenticator() {
+                @Override
+                protected PasswordAuthentication getPasswordAuthentication() {
+                    return new PasswordAuthentication(username, password);
+                }
+            });
+        }
+        URL website = new URL(urlString);
+        try ( ReadableByteChannel rbc = Channels.newChannel( website.openStream() );
+                        FileOutputStream fos = new FileOutputStream(destination) )
+        {
+            fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+        }
+    }
+
+}
diff --git a/maven-wrapper-distribution/src/site/apt/index.apt.vm b/maven-wrapper-distribution/src/site/apt/index.apt.vm
new file mode 100644
index 0000000..a8ecdc9
--- /dev/null
+++ b/maven-wrapper-distribution/src/site/apt/index.apt.vm
@@ -0,0 +1,58 @@
+~~ 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.
+
+ -----
+ ${project.name}
+ -----
+ Hervé Boutemy
+ -----
+ 2021-10-10
+ -----
+
+${project.name}
+
+ ${project.description}
+
+ Distributions types share the same base structure:
+
+----
+mvnw
+mvnw.cmd
+mvnwDebug
+mvnwDebug.cmd
+.mvn/wrapper/maven-wrapper.properties
+----
+
+ but every distribution has specific <<<mvnw>>>/<<<mvnw.cmd>>> scripts to manage different strategies to get {{{../maven-wrapper/}<<<maven-wrapper.jar>>>}}:
+ 
+ - <<<script>>> (default): <<<mvnw>>>/<<<mvnw.cmd>>> scripts will download {{{../maven-wrapper/}<<<maven-wrapper.jar>>>}} with <<<wget>>> or <<<curl>>> on Unix or PowerShell on Windows
+ 
+ - <<<bin>>>: no need to download <<<maven-wrapper.jar>>> binary, it is directly provided and used from project source tree:
+
+----
+.mvn/wrapper/maven-wrapper.jar
+----
+
+ - <<<source>>>: <<<mvnw>>>/<<<mvnw.cmd>>> scripts will compile <<<MavenWrapperDownloader.java>>> source then run the class to download {{{../maven-wrapper/}<<<maven-wrapper.jar>>>}}:
+
+----
+.mvn/wrapper/MavenWrapperDownloader.java
+----
+
+ []
+
+ Distribution can be installed in a project either by unpacking zip archive by hand, or by using {{{/plugins/maven-wrapper-plugin/}<<<wrapper:wrapper>>>}}.
diff --git a/src/it/projects/maven3/pom.xml b/maven-wrapper-distribution/src/site/site.xml
similarity index 63%
copy from src/it/projects/maven3/pom.xml
copy to maven-wrapper-distribution/src/site/site.xml
index 3a33965..cd7807c 100644
--- a/src/it/projects/maven3/pom.xml
+++ b/maven-wrapper-distribution/src/site/site.xml
@@ -1,4 +1,4 @@
-<?xml version='1.0' encoding='UTF-8'?>
+<?xml version="1.0" encoding="UTF-8"?>
 
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
@@ -19,11 +19,13 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
 
-  <groupId>org.apache.maven.plugins.it.wrapper</groupId>
-  <artifactId>maven3</artifactId>
-  <version>1.0.0-SNAPSHOT</version>
-  <packaging>pom</packaging>
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
 </project>
\ No newline at end of file
diff --git a/pom.xml b/maven-wrapper-plugin/pom.xml
similarity index 62%
copy from pom.xml
copy to maven-wrapper-plugin/pom.xml
index d081112..2a36173 100644
--- a/pom.xml
+++ b/maven-wrapper-plugin/pom.xml
@@ -23,72 +23,24 @@ under the License.
   <modelVersion>4.0.0</modelVersion>
 
   <parent>
-    <groupId>org.apache.maven.plugins</groupId>
-    <artifactId>maven-plugins</artifactId>
-    <version>34</version>
-    <relativePath />
+    <groupId>org.apache.maven</groupId>
+    <artifactId>maven-wrapper-parent</artifactId>
+    <version>3.0.3-SNAPSHOT</version>
   </parent>
 
+  <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-wrapper-plugin</artifactId>
-  <version>3.0.3-SNAPSHOT</version>
   <packaging>maven-plugin</packaging>
 
   <name>Apache Maven Wrapper Plugin</name>
   <description>
-    The Maven Wrapper Plugin is a plugin that provides support for the Maven Wrapper.
+    The Maven Wrapper Plugin is a plugin that provides support for the Maven Wrapper by unpacking Maven Wrapper Distribution to current project.
   </description>
-  <inceptionYear>2020</inceptionYear>
 
   <prerequisites>
     <maven>${mavenVersion}</maven>
   </prerequisites>
 
-  <scm>
-    <connection>scm:git:https://gitbox.apache.org/repos/asf/maven-wrapper-plugin.git</connection>
-    <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/maven-wrapper-plugin.git</developerConnection>
-    <url>https://github.com/apache/maven-wrapper-plugin/tree/${project.scm.tag}</url>
-    <tag>HEAD</tag>
-  </scm>
-  <issueManagement>
-    <system>JIRA</system>
-    <url>https://issues.apache.org/jira/browse/MWRAPPER</url>
-  </issueManagement>
-  <ciManagement>
-    <system>Jenkins</system>
-    <url>https://ci-builds.apache.org/job/Maven/job/maven-box/job/maven-wrapper-plugin/</url>
-  </ciManagement>
-  <distributionManagement>
-    <site>
-      <id>apache.website</id>
-      <url>scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path}</url>
-    </site>
-  </distributionManagement>
-
-  <properties>
-    <mavenVersion>3.1.0</mavenVersion>
-    <javaVersion>8</javaVersion>
-    <project.build.outputTimestamp>2021-04-05T14:15:37Z</project.build.outputTimestamp>
-  </properties>
-
-  <build>
-    <pluginManagement>
-      <plugins>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-jxr-plugin</artifactId>
-          <version>3.0.0</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-project-info-reports-plugin</artifactId>
-          <version>3.1.0</version>
-          <configuration>
-          </configuration>
-        </plugin>
-      </plugins>
-    </pluginManagement>
-  </build>
-
   <dependencies>
     <dependency>
       <groupId>org.apache.maven</groupId>
diff --git a/src/it/projects/type_source/invoker.properties b/maven-wrapper-plugin/src/it/projects/default/invoker.properties
similarity index 100%
rename from src/it/projects/type_source/invoker.properties
rename to maven-wrapper-plugin/src/it/projects/default/invoker.properties
diff --git a/src/it/projects/wrapperversion/pom.xml b/maven-wrapper-plugin/src/it/projects/default/pom.xml
similarity index 100%
rename from src/it/projects/wrapperversion/pom.xml
rename to maven-wrapper-plugin/src/it/projects/default/pom.xml
diff --git a/src/it/projects/default/verify.groovy b/maven-wrapper-plugin/src/it/projects/default/verify.groovy
similarity index 100%
rename from src/it/projects/default/verify.groovy
rename to maven-wrapper-plugin/src/it/projects/default/verify.groovy
diff --git a/src/it/projects/type_bin/invoker.properties b/maven-wrapper-plugin/src/it/projects/excludeDebug/invoker.properties
similarity index 100%
rename from src/it/projects/type_bin/invoker.properties
rename to maven-wrapper-plugin/src/it/projects/excludeDebug/invoker.properties
diff --git a/src/it/projects/type_source/pom.xml b/maven-wrapper-plugin/src/it/projects/excludeDebug/pom.xml
similarity index 100%
rename from src/it/projects/type_source/pom.xml
rename to maven-wrapper-plugin/src/it/projects/excludeDebug/pom.xml
diff --git a/src/it/projects/excludeDebug/test.properties b/maven-wrapper-plugin/src/it/projects/excludeDebug/test.properties
similarity index 100%
rename from src/it/projects/excludeDebug/test.properties
rename to maven-wrapper-plugin/src/it/projects/excludeDebug/test.properties
diff --git a/src/it/projects/excludeDebug/verify.groovy b/maven-wrapper-plugin/src/it/projects/excludeDebug/verify.groovy
similarity index 100%
rename from src/it/projects/excludeDebug/verify.groovy
rename to maven-wrapper-plugin/src/it/projects/excludeDebug/verify.groovy
diff --git a/src/it/projects/extension/invoker.properties b/maven-wrapper-plugin/src/it/projects/extension/invoker.properties
similarity index 100%
rename from src/it/projects/extension/invoker.properties
rename to maven-wrapper-plugin/src/it/projects/extension/invoker.properties
diff --git a/src/it/projects/extension/pom.xml b/maven-wrapper-plugin/src/it/projects/extension/pom.xml
similarity index 100%
rename from src/it/projects/extension/pom.xml
rename to maven-wrapper-plugin/src/it/projects/extension/pom.xml
diff --git a/src/it/projects/extension/verify.groovy b/maven-wrapper-plugin/src/it/projects/extension/verify.groovy
similarity index 100%
rename from src/it/projects/extension/verify.groovy
rename to maven-wrapper-plugin/src/it/projects/extension/verify.groovy
diff --git a/src/it/projects/maven3/invoker.properties b/maven-wrapper-plugin/src/it/projects/maven3/invoker.properties
similarity index 100%
rename from src/it/projects/maven3/invoker.properties
rename to maven-wrapper-plugin/src/it/projects/maven3/invoker.properties
diff --git a/src/it/projects/maven3/pom.xml b/maven-wrapper-plugin/src/it/projects/maven3/pom.xml
similarity index 100%
rename from src/it/projects/maven3/pom.xml
rename to maven-wrapper-plugin/src/it/projects/maven3/pom.xml
diff --git a/src/it/projects/maven3/verify.groovy b/maven-wrapper-plugin/src/it/projects/maven3/verify.groovy
similarity index 100%
rename from src/it/projects/maven3/verify.groovy
rename to maven-wrapper-plugin/src/it/projects/maven3/verify.groovy
diff --git a/src/it/projects/mavenversion/invoker.properties b/maven-wrapper-plugin/src/it/projects/mavenversion/invoker.properties
similarity index 100%
rename from src/it/projects/mavenversion/invoker.properties
rename to maven-wrapper-plugin/src/it/projects/mavenversion/invoker.properties
diff --git a/src/it/projects/type_bin/pom.xml b/maven-wrapper-plugin/src/it/projects/mavenversion/pom.xml
similarity index 100%
rename from src/it/projects/type_bin/pom.xml
rename to maven-wrapper-plugin/src/it/projects/mavenversion/pom.xml
diff --git a/src/it/projects/mavenversion/test.properties b/maven-wrapper-plugin/src/it/projects/mavenversion/test.properties
similarity index 100%
rename from src/it/projects/mavenversion/test.properties
rename to maven-wrapper-plugin/src/it/projects/mavenversion/test.properties
diff --git a/src/it/projects/wrapperversion/verify.groovy b/maven-wrapper-plugin/src/it/projects/mavenversion/verify.groovy
similarity index 100%
rename from src/it/projects/wrapperversion/verify.groovy
rename to maven-wrapper-plugin/src/it/projects/mavenversion/verify.groovy
diff --git a/src/it/projects/excludeDebug/invoker.properties b/maven-wrapper-plugin/src/it/projects/type_bin/invoker.properties
similarity index 100%
copy from src/it/projects/excludeDebug/invoker.properties
copy to maven-wrapper-plugin/src/it/projects/type_bin/invoker.properties
diff --git a/src/it/projects/mavenversion/pom.xml b/maven-wrapper-plugin/src/it/projects/type_bin/pom.xml
similarity index 100%
rename from src/it/projects/mavenversion/pom.xml
rename to maven-wrapper-plugin/src/it/projects/type_bin/pom.xml
diff --git a/src/it/projects/type_bin/test.properties b/maven-wrapper-plugin/src/it/projects/type_bin/test.properties
similarity index 100%
rename from src/it/projects/type_bin/test.properties
rename to maven-wrapper-plugin/src/it/projects/type_bin/test.properties
diff --git a/src/it/projects/type_bin/verify.groovy b/maven-wrapper-plugin/src/it/projects/type_bin/verify.groovy
similarity index 100%
copy from src/it/projects/type_bin/verify.groovy
copy to maven-wrapper-plugin/src/it/projects/type_bin/verify.groovy
diff --git a/src/it/projects/default/invoker.properties b/maven-wrapper-plugin/src/it/projects/type_source/invoker.properties
similarity index 100%
rename from src/it/projects/default/invoker.properties
rename to maven-wrapper-plugin/src/it/projects/type_source/invoker.properties
diff --git a/src/it/projects/excludeDebug/pom.xml b/maven-wrapper-plugin/src/it/projects/type_source/pom.xml
similarity index 100%
rename from src/it/projects/excludeDebug/pom.xml
rename to maven-wrapper-plugin/src/it/projects/type_source/pom.xml
diff --git a/src/it/projects/type_source/test.properties b/maven-wrapper-plugin/src/it/projects/type_source/test.properties
similarity index 100%
rename from src/it/projects/type_source/test.properties
rename to maven-wrapper-plugin/src/it/projects/type_source/test.properties
diff --git a/src/it/projects/type_source/verify.groovy b/maven-wrapper-plugin/src/it/projects/type_source/verify.groovy
similarity index 100%
rename from src/it/projects/type_source/verify.groovy
rename to maven-wrapper-plugin/src/it/projects/type_source/verify.groovy
diff --git a/src/it/projects/wrapperversion/invoker.properties b/maven-wrapper-plugin/src/it/projects/wrapperversion/invoker.properties
similarity index 100%
rename from src/it/projects/wrapperversion/invoker.properties
rename to maven-wrapper-plugin/src/it/projects/wrapperversion/invoker.properties
diff --git a/src/it/projects/default/pom.xml b/maven-wrapper-plugin/src/it/projects/wrapperversion/pom.xml
similarity index 100%
rename from src/it/projects/default/pom.xml
rename to maven-wrapper-plugin/src/it/projects/wrapperversion/pom.xml
diff --git a/src/it/projects/wrapperversion/test.properties b/maven-wrapper-plugin/src/it/projects/wrapperversion/test.properties
similarity index 100%
rename from src/it/projects/wrapperversion/test.properties
rename to maven-wrapper-plugin/src/it/projects/wrapperversion/test.properties
diff --git a/src/it/projects/mavenversion/verify.groovy b/maven-wrapper-plugin/src/it/projects/wrapperversion/verify.groovy
similarity index 100%
rename from src/it/projects/mavenversion/verify.groovy
rename to maven-wrapper-plugin/src/it/projects/wrapperversion/verify.groovy
diff --git a/src/it/settings.xml b/maven-wrapper-plugin/src/it/settings.xml
similarity index 100%
rename from src/it/settings.xml
rename to maven-wrapper-plugin/src/it/settings.xml
diff --git a/src/main/java/org/apache/maven/plugins/wrapper/WrapperMojo.java b/maven-wrapper-plugin/src/main/java/org/apache/maven/plugins/wrapper/WrapperMojo.java
similarity index 99%
rename from src/main/java/org/apache/maven/plugins/wrapper/WrapperMojo.java
rename to maven-wrapper-plugin/src/main/java/org/apache/maven/plugins/wrapper/WrapperMojo.java
index 755b81d..2429cce 100644
--- a/src/main/java/org/apache/maven/plugins/wrapper/WrapperMojo.java
+++ b/maven-wrapper-plugin/src/main/java/org/apache/maven/plugins/wrapper/WrapperMojo.java
@@ -48,7 +48,7 @@ import org.codehaus.plexus.archiver.UnArchiver;
 import org.codehaus.plexus.components.io.fileselectors.FileSelector;
 
 /**
- * Adds the maven-wrapper files to this project 
+ * Unpacks the maven-wrapper-distribution files to the current project source tree. 
  * 
  * @author Robert Scholte
  * @since 3.0.0
diff --git a/src/main/resources/META-INF/plexus/components.xml b/maven-wrapper-plugin/src/main/resources/META-INF/plexus/components.xml
similarity index 100%
rename from src/main/resources/META-INF/plexus/components.xml
rename to maven-wrapper-plugin/src/main/resources/META-INF/plexus/components.xml
diff --git a/src/site/markdown/index.md.vm b/maven-wrapper-plugin/src/site/markdown/index.md.vm
similarity index 100%
rename from src/site/markdown/index.md.vm
rename to maven-wrapper-plugin/src/site/markdown/index.md.vm
diff --git a/src/site/markdown/usage.md b/maven-wrapper-plugin/src/site/markdown/usage.md
similarity index 100%
rename from src/site/markdown/usage.md
rename to maven-wrapper-plugin/src/site/markdown/usage.md
diff --git a/src/site/resources/download.cgi b/maven-wrapper-plugin/src/site/resources/download.cgi
similarity index 100%
rename from src/site/resources/download.cgi
rename to maven-wrapper-plugin/src/site/resources/download.cgi
diff --git a/src/site/site.xml b/maven-wrapper-plugin/src/site/site.xml
similarity index 100%
copy from src/site/site.xml
copy to maven-wrapper-plugin/src/site/site.xml
diff --git a/src/site/xdoc/download.xml.vm b/maven-wrapper-plugin/src/site/xdoc/download.xml.vm
similarity index 100%
rename from src/site/xdoc/download.xml.vm
rename to maven-wrapper-plugin/src/site/xdoc/download.xml.vm
diff --git a/maven-wrapper/pom.xml b/maven-wrapper/pom.xml
new file mode 100644
index 0000000..90ce533
--- /dev/null
+++ b/maven-wrapper/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.maven</groupId>
+    <artifactId>maven-wrapper-parent</artifactId>
+    <version>3.0.3-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-wrapper</artifactId>
+  <name>Maven Wrapper</name>
+  <description>Maven Wrapper ...</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.hamcrest</groupId>
+      <artifactId>hamcrest</artifactId>
+      <version>2.2</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>2.23.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-engine</artifactId>
+      <version>5.8.1</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- Using zip util class, should be replaced with a zip lib -->
+    <dependency>
+      <groupId>org.apache.ant</groupId>
+      <artifactId>ant</artifactId>
+      <version>1.10.9</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
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 0000000..720b450
--- /dev/null
+++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/BootstrapMainStarter.java
@@ -0,0 +1,64 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+
+/**
+ * Maven starter, from a provided Maven home directory.
+ *
+ * @author Hans Dockter
+ */
+public class BootstrapMainStarter
+{
+    public void start( String[] args, Path mavenHome )
+        throws Exception
+    {
+        Path 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.toAbsolutePath().toString() );
+        System.setProperty( "classworlds.conf", mavenHome.resolve( "bin/m2.conf" ).toAbsolutePath().toString() );
+
+        Method mainMethod = mainClass.getMethod( "main", String[].class );
+        mainMethod.invoke( null, new Object[] { args } );
+    }
+
+    private Path findLauncherJar( Path mavenHome ) throws RuntimeException, IOException
+    {
+        try ( Stream<Path> list = Files.list( mavenHome.resolve( "boot" ) ) ) 
+        {
+            return list.filter( p -> p.getFileName().toString().matches( "plexus-classworlds-.*\\.jar" )  )
+                        .findFirst()
+                        .orElseThrow( () -> new RuntimeException(
+                                  String.format( "Couldn't 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 0000000..f5dd89c
--- /dev/null
+++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/DefaultDownloader.java
@@ -0,0 +1,190 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import static org.apache.maven.wrapper.MavenWrapperMain.MVNW_PASSWORD;
+import static org.apache.maven.wrapper.MavenWrapperMain.MVNW_USERNAME;
+
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+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;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Base64;
+
+/**
+ * @author Hans Dockter
+ */
+public class DefaultDownloader
+    implements Downloader
+{
+    private static final int PROGRESS_CHUNK = 500000;
+
+    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();
+        configureAuthentication();
+    }
+
+    private void configureProxyAuthentication()
+    {
+        if ( System.getProperty( "http.proxyUser" ) != null )
+        {
+            Authenticator.setDefault( new SystemPropertiesProxyAuthenticator() );
+        }
+    }
+
+    private void configureAuthentication()
+    {
+        if ( System.getenv( MVNW_USERNAME ) != null && System.getenv( MVNW_PASSWORD ) != null
+            && System.getProperty( "http.proxyUser" ) == null )
+        {
+            Authenticator.setDefault( new Authenticator()
+            {
+                @Override
+                protected PasswordAuthentication getPasswordAuthentication()
+                {
+                    return new PasswordAuthentication( System.getenv( MVNW_USERNAME ),
+                                                       System.getenv( MVNW_PASSWORD ).toCharArray() );
+                }
+            } );
+        }
+    }
+
+    @Override
+    public void download( URI address, Path destination ) throws IOException
+    {
+        if ( Files.exists( destination ) )
+        {
+            return;
+        }
+        Files.createDirectories( destination.getParent() );
+
+        downloadInternal( address, destination );
+    }
+
+    private void downloadInternal( URI address, Path destination ) throws IOException
+    {
+        URL url = address.toURL();
+        URLConnection conn = url.openConnection();
+        addBasicAuthentication( address, conn );
+        final String userAgentValue = calculateUserAgent();
+        conn.setRequestProperty( "User-Agent", userAgentValue );
+
+        try ( OutputStream out = new BufferedOutputStream( Files.newOutputStream( destination ) );
+              InputStream 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 )
+                {
+                    Logger.info( "." );
+                    progressCounter = progressCounter - PROGRESS_CHUNK;
+                }
+                out.write( buffer, 0, numRead );
+            }
+        }
+        finally
+        {
+            Logger.info( "" );
+        }
+    }
+
+    private void addBasicAuthentication( URI address, URLConnection connection )
+        throws IOException
+    {
+        String userInfo = calculateUserInfo( address );
+        if ( userInfo == null )
+        {
+            return;
+        }
+        if ( !"https".equals( address.getScheme() ) )
+        {
+            Logger.warn( "WARNING Using HTTP Basic Authentication over an insecure connection"
+                + " to download the Maven distribution. Please consider using HTTPS." );
+        }
+        connection.setRequestProperty( "Authorization", "Basic " + base64Encode( userInfo ) );
+    }
+
+    /**
+     * Base64 encode user info for HTTP Basic Authentication.
+     *
+     * @param userInfo user info
+     * @return Base64 encoded user info
+     * @throws RuntimeException if no public Base64 encoder is available on this JVM
+     */
+    private String base64Encode( String userInfo )
+    {
+        return Base64.getEncoder().encodeToString( userInfo.getBytes( StandardCharsets.UTF_8 ) );
+    }
+
+    private String calculateUserInfo( URI uri )
+    {
+        String username = System.getenv( MVNW_USERNAME );
+        String password = System.getenv( MVNW_PASSWORD );
+        if ( username != null && password != null )
+        {
+            return username + ':' + password;
+        }
+        return uri.getUserInfo();
+    }
+
+    private String calculateUserAgent()
+    {
+        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, applicationVersion, 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 0000000..90dc089
--- /dev/null
+++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/Downloader.java
@@ -0,0 +1,54 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+
+/*
+ * 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.
+ */
+
+import java.net.URI;
+import java.nio.file.Path;
+
+/**
+ * Maven distribution downloader.
+ *
+ * @author Hans Dockter
+ */
+public interface Downloader
+{
+    void download( URI address, Path destination ) throws IOException;
+}
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 0000000..b5c287f
--- /dev/null
+++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/Installer.java
@@ -0,0 +1,231 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Enumeration;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+
+/**
+ * Maven distribution installer, eventually using a {@link Downloader} first.
+ *
+ * @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 Path createDist( WrapperConfiguration configuration )
+        throws IOException, URISyntaxException
+    {
+        URI distributionUrl;
+        String mvnwRepoUrl = System.getenv( MavenWrapperMain.MVNW_REPOURL );
+        if ( mvnwRepoUrl != null && !mvnwRepoUrl.isEmpty() )
+        {
+            distributionUrl = new URI( mvnwRepoUrl + "/" + MavenWrapperMain.MVN_PATH );
+            Logger.info( "Detected MVNW_REPOURL environment variable " + mvnwRepoUrl );
+        }
+        else
+        {
+            distributionUrl = configuration.getDistribution();
+        }
+        Logger.info( "Downloading Maven binary from " + distributionUrl );
+        boolean alwaysDownload = configuration.isAlwaysDownload();
+        boolean alwaysUnpack = configuration.isAlwaysUnpack();
+
+        PathAssembler.LocalDistribution localDistribution = pathAssembler.getDistribution( configuration );
+
+        Path localZipFile = localDistribution.getZipFile();
+        boolean downloaded = false;
+        if ( alwaysDownload || !Files.exists( localZipFile ) )
+        {
+            Path tmpZipFile = localZipFile.resolveSibling( localZipFile.getFileName() + ".part" );
+            Files.deleteIfExists( tmpZipFile );
+            Logger.info( "Downloading " + distributionUrl );
+            download.download( distributionUrl, tmpZipFile );
+            Files.move( tmpZipFile, localZipFile );
+            downloaded = true;
+        }
+
+        Path distDir = localDistribution.getDistributionDir();
+        List<Path> dirs = listDirs( distDir );
+
+        if ( downloaded || alwaysUnpack || dirs.isEmpty() )
+        {
+            Files.walkFileTree( distDir.toAbsolutePath(), new SimpleFileVisitor<Path>()
+            {
+                @Override
+                public FileVisitResult postVisitDirectory( Path dir, IOException exc )
+                    throws IOException
+                {
+                    if ( dir.getParent().equals( distDir ) )
+                    {
+                        Logger.info( "Deleting directory " + distDir.toAbsolutePath() );
+                        Files.delete( dir );
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+
+                public FileVisitResult visitFile( Path file, BasicFileAttributes attrs )
+                    throws IOException
+                {
+                    if ( !file.getParent().equals( distDir ) )
+                    {
+                        Files.delete( file );
+                    }
+                    return FileVisitResult.CONTINUE;
+                };
+            } );
+
+            Logger.info( "Unzipping " + localZipFile.toAbsolutePath() + " to " + distDir.toAbsolutePath() );
+            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 IllegalStateException( String.format(
+                   "Maven distribution '%s' contains too many directories. Expected to find exactly 1 directory.",
+                   distributionUrl ) );
+        }
+        return dirs.get( 0 );
+    }
+
+    private List<Path> listDirs( Path distDir ) throws IOException
+    {
+        try ( Stream<Path> stream = Files.walk( distDir, 1 ) ) 
+        {
+              return stream.filter( p -> !distDir.equals( p ) )
+                     .filter( Files::isDirectory )
+                     .collect( Collectors.toList() );
+        }
+    }
+
+    private void setExecutablePermissions( Path mavenHome )
+    {
+        if ( isWindows() )
+        {
+            return;
+        }
+        Path mavenCommand = mavenHome.resolve( "bin/mvn" );
+        String errorMessage = null;
+        try
+        {
+            ProcessBuilder pb = new ProcessBuilder( "chmod", "755", mavenCommand.toString() );
+            Process p = pb.start();
+            if ( p.waitFor() == 0 )
+            {
+                Logger.info( "Set executable permissions for: " + mavenCommand.toString() );
+            }
+            else
+            {
+
+                try ( 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 | InterruptedException e )
+        {
+            errorMessage = e.getMessage();
+        }
+        if ( errorMessage != null )
+        {
+            Logger.warn( "Could not set executable permissions for: " + mavenCommand );
+            Logger.warn( "Please do this manually if you want to use maven." );
+        }
+    }
+
+    private boolean isWindows()
+    {
+        String osName = System.getProperty( "os.name" ).toLowerCase( Locale.US );
+
+        return ( osName.indexOf( "windows" ) > -1 );
+    }
+
+    private void unzip( Path zip, Path dest )
+        throws IOException
+    {
+        try ( ZipFile zipFile = new ZipFile( zip.toFile() ) )
+        {
+            Enumeration<? extends ZipEntry> entries = zipFile.entries();
+
+            while ( entries.hasMoreElements() )
+            {
+                ZipEntry entry = entries.nextElement();
+
+                if ( entry.isDirectory() )
+                {
+                    continue;
+                }
+
+                Path targetFile = dest.resolve( entry.getName() ).normalize();
+
+                // prevent Zip Slip
+                if ( targetFile.startsWith( dest ) )
+                {
+                    Files.createDirectories( targetFile.getParent() );
+
+                    Files.copy( zipFile.getInputStream( entry ), targetFile );
+                }
+            }
+        }
+    }
+}
diff --git a/src/it/projects/type_bin/verify.groovy b/maven-wrapper/src/main/java/org/apache/maven/wrapper/Logger.java
similarity index 58%
rename from src/it/projects/type_bin/verify.groovy
rename to maven-wrapper/src/main/java/org/apache/maven/wrapper/Logger.java
index e079d58..4998520 100644
--- a/src/it/projects/type_bin/verify.groovy
+++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/Logger.java
@@ -1,3 +1,4 @@
+package org.apache.maven.wrapper;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -8,7 +9,7 @@
  * "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
+ *  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
@@ -18,9 +19,23 @@
  * under the License.
  */
 
-assert new File(basedir,'mvnw').exists()
-assert new File(basedir,'mvnw.cmd').exists()
-assert new File(basedir,'mvnwDebug').exists()
-assert new File(basedir,'mvnwDebug.cmd').exists()
-assert new File(basedir,'.mvn/wrapper/maven-wrapper.properties').exists()
-assert new File(basedir,'.mvn/wrapper/maven-wrapper.jar').exists()
\ No newline at end of file
+/**
+ * @author <a href="mailto:konstantin.sobolev@gmail.com">Konstantin Sobolev</a>
+ */
+public class Logger
+{
+    private static final boolean VERBOSE = "true".equalsIgnoreCase( System.getenv( MavenWrapperMain.MVNW_VERBOSE ) );
+
+    public static void info( String msg )
+    {
+        if ( VERBOSE )
+        {
+            System.out.println( msg );
+        }
+    }
+
+    public static void warn( String msg )
+    {
+        System.out.println( msg );
+    }
+}
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 0000000..16cf2f8
--- /dev/null
+++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/MavenWrapperMain.java
@@ -0,0 +1,107 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Properties;
+
+/**
+ * Main entry point for the Maven Wrapper, delegating wrapper execution to {@link WrapperExecutor}.
+ *
+ * @author Hans Dockter
+ */
+public class MavenWrapperMain
+{
+    private static final String POM_PROPERTIES = "/META-INF/maven/org.apache.maven/maven-wrapper/pom.properties";
+
+    public static final String DEFAULT_MAVEN_USER_HOME = System.getProperty( "user.home" ) + "/.m2";
+
+    public static final String MVNW_VERBOSE = "MVNW_VERBOSE";
+
+    public static final String MVNW_USERNAME = "MVNW_USERNAME";
+
+    public static final String MVNW_PASSWORD = "MVNW_PASSWORD";
+
+    public static final String MVNW_REPOURL = "MVNW_REPOURL";
+
+    public static final String MVN_PATH =
+        "org/apache/maven/apache-maven/" + wrapperVersion() + "/apache-maven-" + wrapperVersion() + "-bin.zip";
+
+    public static void main( String[] args )
+        throws Exception
+    {
+        Path wrapperJar = wrapperJar();
+        Path propertiesFile = wrapperProperties( wrapperJar );
+
+        String wrapperVersion = wrapperVersion();
+        Logger.info( "Apache Maven Wrapper " + wrapperVersion );
+
+        WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile( propertiesFile );
+        wrapperExecutor.execute( args, new Installer( new DefaultDownloader( "mvnw", wrapperVersion ),
+                                                      new PathAssembler( mavenUserHome() ) ),
+                                 new BootstrapMainStarter() );
+    }
+
+    private static Path wrapperProperties( Path wrapperJar ) throws URISyntaxException
+    {
+        return wrapperJar().resolveSibling( wrapperJar.getFileName().toString().replaceFirst( "\\.jar$",
+                                                                                              ".properties" ) );
+    }
+
+    private static Path wrapperJar() throws URISyntaxException
+    {
+        URI location = MavenWrapperMain.class.getProtectionDomain().getCodeSource().getLocation().toURI();
+
+        return Paths.get( location );
+    }
+
+    static String wrapperVersion()
+    {
+        try ( InputStream resourceAsStream = MavenWrapperMain.class.getResourceAsStream( POM_PROPERTIES ) )
+        {
+            if ( resourceAsStream == null )
+            {
+                throw new IllegalStateException( POM_PROPERTIES + " not found." );
+            }
+            Properties mavenProperties = new Properties();
+            mavenProperties.load( resourceAsStream );
+            String version = mavenProperties.getProperty( "version" );
+            if ( version == null )
+            {
+                throw new NullPointerException( "No version specified in " + POM_PROPERTIES );
+            }
+            return version;
+        }
+        catch ( IOException e )
+        {
+            throw new RuntimeException( "Could not determine wrapper version.", e );
+        }
+    }
+
+    private static Path mavenUserHome()
+    {
+        return Paths.get( 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 0000000..fd99986
--- /dev/null
+++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/PathAssembler.java
@@ -0,0 +1,131 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * @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 Path mavenUserHome;
+
+    public PathAssembler()
+    {
+    }
+
+    public PathAssembler( Path 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 rootDirName = removeExtension( baseName );
+        Path distDir = getBaseDir( configuration.getDistributionBase() )
+                        .resolve( configuration.getDistributionPath() )
+                        .resolve( rootDirName );
+        Path distZip = getBaseDir( configuration.getZipBase() )
+                        .resolve( configuration.getZipPath() )
+                        .resolve( rootDirName )
+                        .resolve( baseName );
+        return new LocalDistribution( distDir, distZip );
+    }
+
+    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 Path getBaseDir( String base )
+    {
+        if ( MAVEN_USER_HOME_STRING.equals( base ) )
+        {
+            return mavenUserHome;
+        }
+        else if ( PROJECT_STRING.equals( base ) )
+        {
+            return Paths.get( System.getProperty( "user.dir" ) );
+        }
+        else
+        {
+            throw new IllegalArgumentException( "Base: " + base + " is unknown" );
+        }
+    }
+
+    /**
+     * The Local Distribution
+     */
+    public class LocalDistribution
+    {
+        private final Path distZip;
+
+        private final Path distDir;
+
+        public LocalDistribution( Path distDir, Path distZip )
+        {
+            this.distDir = distDir;
+            this.distZip = distZip;
+        }
+
+        /**
+         * Returns the location to install the distribution into.
+         */
+        public Path getDistributionDir()
+        {
+            return distDir;
+        }
+
+        /**
+         * Returns the location to install the distribution ZIP file to.
+         */
+        public Path getZipFile()
+        {
+            return distZip;
+        }
+    }
+}
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 0000000..d7be04e
--- /dev/null
+++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/WrapperConfiguration.java
@@ -0,0 +1,116 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import java.net.URI;
+
+/**
+ * The Wrapper Configuration
+ */
+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 0000000..42d5677
--- /dev/null
+++ b/maven-wrapper/src/main/java/org/apache/maven/wrapper/WrapperExecutor.java
@@ -0,0 +1,178 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Properties;
+
+/**
+ * Wrapper executor, running {@link Installer} to get a Maven distribution ready, followed by {@BootstrapMainStarter}
+ * to launch the Maven bootstrap.
+ * 
+ * @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 Path propertiesFile;
+
+    private final WrapperConfiguration config = new WrapperConfiguration();
+
+    public static WrapperExecutor forProjectDirectory( Path projectDir )
+    {
+        return new WrapperExecutor( projectDir.resolve( "maven/wrapper/maven-wrapper.properties" ),
+                                    new Properties() );
+    }
+
+    public static WrapperExecutor forWrapperPropertiesFile( Path propertiesFile )
+    {
+        if ( !Files.exists( propertiesFile ) )
+        {
+            throw new RuntimeException( String.format( "Wrapper properties file '%s' does not exist.",
+                                                       propertiesFile ) );
+        }
+        return new WrapperExecutor( propertiesFile, new Properties() );
+    }
+
+    WrapperExecutor( Path propertiesFile, Properties properties )
+    {
+        this.properties = properties;
+        this.propertiesFile = propertiesFile;
+        if ( Files.exists( propertiesFile ) )
+        {
+            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 ( IOException | URISyntaxException 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 propertiesFile.getParent().resolve( 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( Path propertiesFile, Properties properties )
+                    throws IOException
+    {
+        try ( InputStream inStream = Files.newInputStream( propertiesFile ) )
+        {
+            properties.load( inStream );
+        }
+    }
+
+    /**
+     * 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
+    {
+        Path 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/site/apt/index.apt b/maven-wrapper/src/site/apt/index.apt
new file mode 100644
index 0000000..c579786
--- /dev/null
+++ b/maven-wrapper/src/site/apt/index.apt
@@ -0,0 +1,30 @@
+~~ 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.
+
+ -----
+ Introduction
+ -----
+ Hervé Boutemy
+ -----
+ 2021-04-05
+ -----
+
+Maven Wrapper
+
+ Maven Wrapper dowloads Maven distribution if not already in cache, installs it, then launches Maven: Maven distributions installed by Maven Wrapper are stored under <<<~/.m2/wrapper/dists>>> by default.
+
+ Maven Wrapper is called by {{{../apache-maven-wrapper/}<<<mvnw>>>/<<<mvnw.cmd>>> scripts}} that need to be installed in the project source tree and called instead of <<<mvn>>>/<<<mvn.cmd>>>.
diff --git a/src/site/site.xml b/maven-wrapper/src/site/site.xml
similarity index 55%
rename from src/site/site.xml
rename to maven-wrapper/src/site/site.xml
index 3b846b6..e475330 100644
--- a/src/site/site.xml
+++ b/maven-wrapper/src/site/site.xml
@@ -19,22 +19,20 @@ specific language governing permissions and limitations
 under the License.
 -->
 
-<project xmlns="http://maven.apache.org/DECORATION/1.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd">
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="Goals" href="plugin-info.html"/>
-      <item name="Usage" href="usage.html"/>
-      <!-- According to https://issues.apache.org/jira/browse/MNGSITE-152 -->
-      <item name="License" href="http://www.apache.org/licenses/"/>
-      <item name="Download" href="download.html"/>
+      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
     </menu>
 
-    <menu name="Reference">
-      <item name="Wrapper Distribution" href="/ref/4-LATEST/apache-maven-wrapper/"/>
-      <item name="Wrapper" href="/ref/4-LATEST/maven-wrapper/"/>
-    </menu>
+    <menu ref="parent"/>
+    <menu ref="reports"/>
   </body>
-</project>
+</project>
\ 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 0000000..c0e84c7
--- /dev/null
+++ b/maven-wrapper/src/test/java/org/apache/maven/wrapper/DownloaderTest.java
@@ -0,0 +1,71 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+public class DownloaderTest
+{
+    @TempDir
+    public Path testDir;
+
+    private DefaultDownloader download;
+
+    private Path downloadFile;
+
+    private Path rootDir;
+
+    private URI sourceRoot;
+
+    private Path remoteFile;
+
+    @BeforeEach
+    public void setUp()
+        throws Exception
+    {
+        download = new DefaultDownloader( "mvnw", "aVersion" );
+        rootDir = testDir.resolve( "root" );
+        downloadFile = rootDir.resolve( "file" );
+        remoteFile = testDir.resolve( "remoteFile" );
+        Files.write( remoteFile, Arrays.asList( "sometext" ) );
+        sourceRoot = remoteFile.toUri();
+    }
+
+    @Test
+    public void testDownload()
+        throws Exception
+    {
+        assert !Files.exists( downloadFile );
+        download.download( sourceRoot, downloadFile );
+        assert Files.exists( downloadFile );
+        assertEquals( "sometext",
+                      Files.readAllLines( downloadFile ).stream().collect( Collectors.joining() ) );
+    }
+}
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 0000000..bef2057
--- /dev/null
+++ b/maven-wrapper/src/test/java/org/apache/maven/wrapper/InstallerTest.java
@@ -0,0 +1,214 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Zip;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+/**
+ * @author Hans Dockter
+ */
+public class InstallerTest
+{
+    @TempDir
+    public Path temporaryFolder;
+
+    private Installer install;
+
+    private Path distributionDir;
+
+    private Path zipStore;
+
+    private Path mavenHomeDir;
+
+    private Path zipDestination;
+
+    private WrapperConfiguration configuration = new WrapperConfiguration();
+
+    private Downloader download;
+
+    private PathAssembler pathAssembler;
+
+    private PathAssembler.LocalDistribution localDistribution;
+
+    @BeforeEach
+    public void setup()
+        throws Exception
+    {
+        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 = temporaryFolder.resolve( "someDistPath" );
+        Files.createDirectories( distributionDir );
+        mavenHomeDir = distributionDir.resolve( "maven-0.9" );
+        zipStore = temporaryFolder.resolve( "zips" );
+        Files.createDirectories( zipStore );
+        zipDestination = zipStore.resolve( "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( Path zipDestination )
+        throws Exception
+    {
+        Files.createDirectories( zipDestination.getParent() );
+
+        Path explodedZipDir = temporaryFolder.resolve( "explodedZip" );
+
+        Path mavenScript = explodedZipDir.resolve( "maven-0.9/bin/mvn" );
+        Files.createDirectories( mavenScript.getParent() );
+        Files.write( mavenScript, Arrays.asList( "something" ) );
+
+        zipTo( explodedZipDir, zipDestination );
+    }
+
+    @Test
+    @Disabled("not working")
+    public void testCreateDist()
+        throws Exception
+    {
+        Path homeDir = install.createDist( configuration );
+
+        Assert.assertEquals( mavenHomeDir, homeDir );
+        Assert.assertTrue( Files.isDirectory( homeDir ) );
+        Assert.assertTrue( Files.exists( homeDir.resolve( "bin/mvn" ) ) );
+        Assert.assertTrue( Files.exists( zipDestination ) );
+
+        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
+    {
+        Files.createFile( zipDestination );
+
+        Files.createDirectories( mavenHomeDir );
+        Path someFile = mavenHomeDir.resolve( "some-file" );
+        Files.createFile( someFile );
+
+        Path homeDir = install.createDist( configuration );
+
+        Assert.assertEquals( mavenHomeDir, homeDir );
+        Assert.assertTrue( Files.isDirectory( mavenHomeDir ) );
+        Assert.assertTrue( Files.exists( homeDir.resolve( "some-file" ) ) );
+        Assert.assertTrue( Files.exists( zipDestination ) );
+
+        Assert.assertEquals( localDistribution, pathAssembler.getDistribution( configuration ) );
+        Assert.assertEquals( distributionDir, localDistribution.getDistributionDir() );
+        Assert.assertEquals( zipDestination, localDistribution.getZipFile() );
+    }
+
+    @Test
+    public void testCreateDistWithExistingDistAndZipAndAlwaysUnpackTrue()
+        throws Exception
+    {
+
+        createTestZip( zipDestination );
+        Files.createDirectories( mavenHomeDir );
+        File garbage = mavenHomeDir.resolve( "garbage" ).toFile();
+        Files.createFile( garbage.toPath() );
+
+        configuration.setAlwaysUnpack( true );
+
+        Path homeDir = install.createDist( configuration );
+
+        Assert.assertEquals( mavenHomeDir, homeDir );
+        Assert.assertTrue( Files.isDirectory( mavenHomeDir ) );
+        Assert.assertFalse( Files.exists( homeDir.resolve( "garbage" ) ) );
+        Assert.assertTrue( Files.exists( zipDestination ) );
+
+        Assert.assertEquals( localDistribution, pathAssembler.getDistribution( configuration ) );
+        Assert.assertEquals( distributionDir, localDistribution.getDistributionDir() );
+        Assert.assertEquals( zipDestination, localDistribution.getZipFile() );
+    }
+
+    @Test
+    public void testCreateDistWithExistingZipAndDistAndAlwaysDownloadTrue()
+        throws Exception
+    {
+
+        createTestZip( zipDestination );
+        Files.createDirectories( mavenHomeDir );
+        File garbage = mavenHomeDir.resolve( "garbage" ).toFile();
+        Files.createFile( garbage.toPath() );
+
+        configuration.setAlwaysUnpack( true );
+
+        Path homeDir = install.createDist( configuration );
+
+        Assert.assertEquals( mavenHomeDir, homeDir );
+        Assert.assertTrue( Files.isDirectory( mavenHomeDir ) );
+        Assert.assertTrue( Files.exists( homeDir.resolve( "bin/mvn" ) ) );
+        Assert.assertFalse( Files.exists( homeDir.resolve( "garbage" ) ) );
+        Assert.assertTrue( Files.exists( zipDestination ) );
+
+        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( Path directoryToZip, Path zipFile )
+    {
+        Zip zip = new Zip();
+        zip.setBasedir( directoryToZip.toFile() );
+        zip.setDestFile( zipFile.toFile() );
+        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 0000000..a2334c1
--- /dev/null
+++ b/maven-wrapper/src/test/java/org/apache/maven/wrapper/PathAssemblerTest.java
@@ -0,0 +1,115 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author Hans Dockter
+ */
+public class PathAssemblerTest
+{
+    public static final String TEST_MAVEN_USER_HOME = "someUserHome";
+
+    private PathAssembler pathAssembler = new PathAssembler( Paths.get( TEST_MAVEN_USER_HOME ) );
+
+    final WrapperConfiguration configuration = new WrapperConfiguration();
+
+    @BeforeEach
+    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" ) );
+
+        Path distributionDir = pathAssembler.getDistribution( configuration ).getDistributionDir();
+        assertThat( distributionDir, is( Paths.get( 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" ) );
+
+        Path distributionDir = pathAssembler.getDistribution( configuration ).getDistributionDir();
+        assertThat( distributionDir, equalTo( Paths.get( 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" );
+
+        RuntimeException e =
+            assertThrows( RuntimeException.class, () -> pathAssembler.getDistribution( configuration ) );
+        assertEquals( "Base: unknownBase is unknown", e.getMessage() );
+    }
+
+    @Test
+    public void distZipWithMavenUserHomeBase()
+        throws Exception
+    {
+        configuration.setDistribution( new URI( "http://server/dist/maven-1.0.zip" ) );
+
+        Path dist = pathAssembler.getDistribution( configuration ).getZipFile();
+        assertThat( dist.getFileName().toString(), equalTo( "maven-1.0.zip" ) );
+        assertThat( dist.getParent(), equalTo( Paths.get( 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" ) );
+
+        Path dist = pathAssembler.getDistribution( configuration ).getZipFile();
+        assertThat( dist.getFileName().toString(), equalTo( "maven-1.0.zip" ) );
+        assertThat( dist.getParent(), equalTo( Paths.get( currentDirPath(), "/somePath/maven-1.0" ) ) );
+    }
+
+    private String currentDirPath()
+    {
+        return System.getProperty( "user.dir" );
+    }
+}
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 0000000..23bcf21
--- /dev/null
+++ b/maven-wrapper/src/test/java/org/apache/maven/wrapper/WrapperExecutorTest.java
@@ -0,0 +1,202 @@
+package org.apache.maven.wrapper;
+
+/*
+ * 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.
+ */
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Properties;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.mockito.Mockito;
+
+public class WrapperExecutorTest
+{
+    @TempDir
+    public Path testDir;
+
+    private Installer install;
+
+    private BootstrapMainStarter start;
+
+    private Path propertiesFile;
+
+    private Properties properties = new Properties();
+
+    private Path mockInstallDir;
+
+    @BeforeEach
+    public void setUp()
+        throws Exception
+    {
+        mockInstallDir = testDir.resolve( "mock-dir" );
+
+        install = mock( Installer.class );
+        when( install.createDist( Mockito.any( WrapperConfiguration.class ) ) ).thenReturn( mockInstallDir );
+        start = mock( BootstrapMainStarter.class );
+
+        propertiesFile = testDir.resolve( "maven" ).resolve( "wrapper" ).resolve( "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 );
+
+        assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getDistribution() );
+        assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getConfiguration().getDistribution() );
+        assertEquals( "testDistBase", wrapper.getConfiguration().getDistributionBase() );
+        assertEquals( "testDistPath", wrapper.getConfiguration().getDistributionPath() );
+        assertEquals( "testZipBase", wrapper.getConfiguration().getZipBase() );
+        assertEquals( "testZipPath", wrapper.getConfiguration().getZipPath() );
+    }
+
+    @Test
+    public void loadWrapperMetadataFromDirectory()
+        throws Exception
+    {
+        WrapperExecutor wrapper = WrapperExecutor.forProjectDirectory( testDir );
+
+        assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getDistribution() );
+        assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getConfiguration().getDistribution() );
+        assertEquals( "testDistBase", wrapper.getConfiguration().getDistributionBase() );
+        assertEquals( "testDistPath", wrapper.getConfiguration().getDistributionPath() );
+        assertEquals( "testZipBase", wrapper.getConfiguration().getZipBase() );
+        assertEquals( "testZipPath", wrapper.getConfiguration().getZipPath() );
+    }
+
+    @Test
+    public void useDefaultMetadataNoProeprtiesFile()
+        throws Exception
+    {
+        WrapperExecutor wrapper = WrapperExecutor.forProjectDirectory( testDir.resolve( "unknown" ) );
+
+        assertNull( wrapper.getDistribution() );
+        assertNull( wrapper.getConfiguration().getDistribution() );
+        assertEquals( PathAssembler.MAVEN_USER_HOME_STRING, wrapper.getConfiguration().getDistributionBase() );
+        assertEquals( Installer.DEFAULT_DISTRIBUTION_PATH, wrapper.getConfiguration().getDistributionPath() );
+        assertEquals( PathAssembler.MAVEN_USER_HOME_STRING, wrapper.getConfiguration().getZipBase() );
+        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 );
+
+        assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getDistribution() );
+        assertEquals( new URI( "http://server/test/maven.zip" ), wrapper.getConfiguration().getDistribution() );
+        assertEquals( PathAssembler.MAVEN_USER_HOME_STRING, wrapper.getConfiguration().getDistributionBase() );
+        assertEquals( Installer.DEFAULT_DISTRIBUTION_PATH, wrapper.getConfiguration().getDistributionPath() );
+        assertEquals( PathAssembler.MAVEN_USER_HOME_STRING, wrapper.getConfiguration().getZipBase() );
+        assertEquals( Installer.DEFAULT_DISTRIBUTION_PATH, wrapper.getConfiguration().getZipPath() );
+    }
+
+    @Test
+    public void executeInstallAndLaunch()
+        throws Exception
+    {
+        WrapperExecutor wrapper = WrapperExecutor.forProjectDirectory( propertiesFile );
+
+        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" );
+
+        RuntimeException e = assertThrows(
+                RuntimeException.class,
+                () -> WrapperExecutor.forWrapperPropertiesFile( propertiesFile ),
+                "Expected RuntimeException" );
+        assertEquals( "No value with key 'distributionUrl' specified in wrapper properties file '"
+            + propertiesFile + "'.", e.getMessage() );
+    }
+
+    @Test
+    public void failWhenPropertiesFileDoesNotExist()
+    {
+        propertiesFile = testDir.resolve( "unknown.properties" );
+
+        RuntimeException e = assertThrows(
+                RuntimeException.class,
+                () -> WrapperExecutor.forWrapperPropertiesFile( propertiesFile ),
+                "Expected RuntimeException" );
+        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 );
+        assertNotEquals( "some/relative/url/to/bin.zip", wrapper.getDistribution().getSchemeSpecificPart() );
+        assertTrue( wrapper.getDistribution().getSchemeSpecificPart().endsWith( "some/relative/url/to/bin.zip" ) );
+    }
+
+    private void writePropertiesFile( Properties properties, Path propertiesFile, String message )
+        throws IOException
+    {
+        Files.createDirectories( propertiesFile.getParent() );
+
+        try ( OutputStream outStream = Files.newOutputStream( propertiesFile ) )
+        {
+            properties.store( outStream, message );
+        }
+    }
+}
diff --git a/src/it/projects/excludeDebug/invoker.properties b/maven-wrapper/src/test/resources/org/apache/maven/wrapper/wrapper.properties
similarity index 83%
rename from src/it/projects/excludeDebug/invoker.properties
rename to maven-wrapper/src/test/resources/org/apache/maven/wrapper/wrapper.properties
index 3125747..a471a8c 100644
--- a/src/it/projects/excludeDebug/invoker.properties
+++ b/maven-wrapper/src/test/resources/org/apache/maven/wrapper/wrapper.properties
@@ -5,14 +5,17 @@
 # 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.
-invoker.maven.version = 4+
-invoker.goals = org.apache.maven.plugins:maven-wrapper-plugin:${project.version}:wrapper
\ No newline at end of file
+distributionUrl=http://server/test/maven.zip
+distributionBase=testDistBase
+zipStoreBase=testZipBase
+distributionPath=testDistPath
+zipStorePath=testZipPath
diff --git a/pom.xml b/pom.xml
index d081112..1043740 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,19 +23,19 @@ under the License.
   <modelVersion>4.0.0</modelVersion>
 
   <parent>
-    <groupId>org.apache.maven.plugins</groupId>
-    <artifactId>maven-plugins</artifactId>
+    <groupId>org.apache.maven</groupId>
+    <artifactId>maven-parent</artifactId>
     <version>34</version>
     <relativePath />
   </parent>
 
-  <artifactId>maven-wrapper-plugin</artifactId>
+  <artifactId>maven-wrapper-parent</artifactId>
   <version>3.0.3-SNAPSHOT</version>
-  <packaging>maven-plugin</packaging>
+  <packaging>pom</packaging>
 
-  <name>Apache Maven Wrapper Plugin</name>
+  <name>Apache Maven Wrapper Parent</name>
   <description>
-    The Maven Wrapper Plugin is a plugin that provides support for the Maven Wrapper.
+    The Maven Wrapper is...
   </description>
   <inceptionYear>2020</inceptionYear>
 
@@ -70,6 +70,12 @@ under the License.
     <project.build.outputTimestamp>2021-04-05T14:15:37Z</project.build.outputTimestamp>
   </properties>
 
+  <modules>
+    <module>maven-wrapper</module>
+    <module>maven-wrapper-distribution</module>
+    <module>maven-wrapper-plugin</module>
+  </modules>
+
   <build>
     <pluginManagement>
       <plugins>
@@ -82,65 +88,8 @@ under the License.
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-project-info-reports-plugin</artifactId>
           <version>3.1.0</version>
-          <configuration>
-          </configuration>
         </plugin>
       </plugins>
     </pluginManagement>
   </build>
-
-  <dependencies>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-core</artifactId>
-      <version>${mavenVersion}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-plugin-api</artifactId>
-      <version>${mavenVersion}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven.shared</groupId>
-      <artifactId>maven-artifact-transfer</artifactId>
-      <version>0.12.0</version>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-archiver</artifactId>
-      <version>4.2.1</version>
-    </dependency>
-
-    <!-- dependencies to annotations -->
-    <dependency>
-      <groupId>org.apache.maven.plugin-tools</groupId>
-      <artifactId>maven-plugin-annotations</artifactId>
-      <optional>true</optional>
-    </dependency>
-  </dependencies>
-  
-  <profiles>
-    <profile>
-      <id>run-its</id>
-      <build>
-        <plugins>
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-invoker-plugin</artifactId>
-            <configuration>
-              <goals>
-                <goal>wrapper</goal>
-              </goals>
-              <projectsDirectory>src/it/projects</projectsDirectory>
-              <debug>false</debug>
-              <pomExcludes>
-                <!-- remove once Maven 4 is released -->
-                <pomExclude>wrapperversion/pom.xml</pomExclude>
-              </pomExcludes>
-            </configuration>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-  </profiles>
 </project>