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:46 UTC

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

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>