参考メモ/Maven Wrapper(mvnw)の練習

Spring FrameworkやSpring Bootの入門編を勉強してたら、mvnw というコマンドがありました。Maven Wrapperというラッパースクリプトで、Gradle Wrapper に触発されて開発されたそうです。

Gradleは頻繁にバージョンアップされているため、1-2年前のgradleスクリプトと最新のGradleとで大きくバージョンが異なってしまい、互換性問題に注意が必要です。そこで作られたのがGradle Wrapper(gradlew)で、設定ファイルで指定したバージョンのGradleをその場でダウンロードしてきて使う仕組みです。どのバージョンのGradleを使うのかを設定しておけば、いつ実行してもその時のバージョンをDLして使ってくれます。

Maven Wrapper (mvnw) はそのMaven版です。Maven自体は2016年現在、相当枯れたプロダクトですのでバージョンアップもそこまで頻繁ではありません。とはいえ、やっぱり安定したビルド環境という面から、使用するMavenバージョンを明示的に設定でき、自動で環境を整えてくれるのは良さげです。

----

- [Apache Maven Wrapper – Maven Wrapper](https://maven.apache.org/wrapper/)
  - https://maven.apache.org/wrapper/
  - 2022-03追記: 久しぶりに見てみたら、2021年末ごろに Maven 本家のプラグインに仲間入りして、今はこちらが公式サイトになってました。
- [takari/maven-wrapper: The easiest way to integrate Maven into your project!](https://github.com/takari/maven-wrapper)
  - https://github.com/takari/maven-wrapper
- [takari/takari-maven-plugin](https://github.com/takari/takari-maven-plugin)
  - https://github.com/takari/takari-maven-plugin

----

## とりあえず今すぐ使いたい人向けのメモ

- まず「Maven Wrapperの組み込み作業をする環境」に普通のMavenをインストールしておく。(= Maven が入ってない環境からいきなり Maven Wrapper を組み込むことはできない)
- 既存のMavenプロジェクトへの組み込み:
  ```
  mvn wrapper:wrapper
  ```
  - ~~`0.7.6` の部分は 2019-05-19 時点でのバージョン番号。使用する際に確認してください。~~ [^1]
  - 2022-03追記: Apache Maven 本家プラグインの仲間入りの影響か、2022-03-02時点の公式サイト上では上記のようにバージョン番号の指定が不要となりました。
- `.mvn/wrapper/maven-wrapper.jar` については mvnw の実行に必要なので、無視せずにリポジトリに登録する。
  - もしGitで .gitignore に `.jar` を含めている場合は、以下のようにmaven-wrapper.jarだけ無視しないよう設定追加。
    ```
    !.mvn/wrapper/maven-wrapper.jar
    ```
- 既に組み込んだ Maven Wrapper をバージョンアップしたい:
  -  → mvnコマンド実行環境の Maven を希望のバージョンにアップしておき、その状態で `mvn wrapper:wrapper` をする。
  - 実行時点の `mvn` のバージョンに基づく wrapper にアップデートされます。

## mvnw スクリプトファイルへの chmod

- Windows環境で組み込んだ場合、unix 向けの `mvnw` スクリプトファイルに実行権限を手動で付与する必要がある。(Windows環境のgitでそのまま追加すると、実行権限がつかないため、unix系でcloneしたときに `./mvnw` でビルドできない。)

```
git update-index --add --chmod=+x mvnw
```

## 練習メモ

自分の Maven3 プロジェクト https://github.com/msakamoto-sf/maven3-junit-spock-testng-mixin にmvnwを追加してみた練習メモです。

実験環境：

```
CentOS7(x64)
$ mvn -version
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T01:41:47+09:00)
Maven home: /home/msakamoto/devtools/apache-maven-3.3.9
Java version: 1.8.0_77, vendor: Oracle Corporation
Java home: /opt/jdk1.8.0_77/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-327.28.2.el7.x86_64", arch: "amd64", family: "unix"
```

Mavenプロジェクトへの組み込み：

```
$ mvn -N io.takari:maven:wrapper
(...)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 17.934 s
[INFO] Finished at: 2016-09-03T14:23:53+09:00
[INFO] Final Memory: 10M/135M
[INFO] ------------------------------------------------------------------------
```

ポイント：

* pom.xmlには何も追記する必要が無い。(その場で Maven Wrapper のmaven pluginをDLして実行してくれる)
* 組み込むときはMavenが必要。
* 後述のバージョン指定をしなければ、組み込んだ時に実行したMavenのバージョンが設定ファイルに保存される。

どんなファイルが作られる？

```
.mvn/
.mvn/wrapper/maven-wrapper.jar
.mvn/wrapper/maven-wrapper.properties ... この中にバージョン番号含めたMavenのDL用URLが保存される。
mvnw      ... unix用のラッパーシェルスクリプト
mvnw.cmd  ... windows用のラッパーバッチファイル
```

mvnwから初めて実行すると、`.mvn/wrapper/maven-wrapper.properties` の `distributionUrl` で設定されたURLからMavenの実行バイナリをDLして `~/.m2/wrapper/dist/` 以下に展開し、それを使ってmvnコマンドを起動している。

```
$ ./mvnw clean
Downloading https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip
(...)
Unzipping /home/msakamoto/.m2/wrapper/dists/apache-maven-3.3.9-bin/2609u9g41na2l7ogackmif6fj2/apache-maven-3.3.9-bin.zip to /home/msakamoto/.m2/wrapper/dists/apache-maven-3.3.9-bin/2609u9g41na2l7ogackmif6fj2
Set executable permissions for: /home/msakamoto/.m2/wrapper/dists/apache-maven-3.3.9-bin/2609u9g41na2l7ogackmif6fj2/apache-maven-3.3.9/bin/mvn
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building spock, TestNG, Maven3 Integration Demo 1.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven3-junit-spock-testng-mixin ---
[INFO] Deleting /home/msakamoto/github/msakamoto-sf/maven3-junit-spock-testng-mixin/target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.759 s
[INFO] Finished at: 2016-09-03T14:47:41+09:00
[INFO] Final Memory: 8M/57M
[INFO] ------------------------------------------------------------------------
```

2回目以降の mvnw 実行では、Mavenのダウンロードは発生しない。(初回でダウンロードされたものが使われる)

```
$ ./mvnw package
[INFO] Scanning for projects...
[INFO]
(...)
```

Mavenのバージョンを指定してmvnwを組み込む：

```
$ mvn -N io.takari:maven:wrapper -Dmaven=3.3.3

->
$ cat .mvn/wrapper/maven-wrapper.properties
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip

->
$ ./mvnw clean
Downloading https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip
(...)
Unzipping /home/msakamoto/.m2/wrapper/dists/apache-maven-3.3.3-bin/3opbjp6rgl6qp7k2a6tljcpvgp/apache-maven-3.3.3-bin.zip to /home/msakamoto/.m2/wrapper/dists/apache-maven-3.3.3-bin/3opbjp6rgl6qp7k2a6tljcpvgp
Set executable permissions for: /home/msakamoto/.m2/wrapper/dists/apache-maven-3.3.3-bin/3opbjp6rgl6qp7k2a6tljcpvgp/apache-maven-3.3.3/bin/mvn
[INFO] Scanning for projects...
(...)
```

こんな感じで、簡単に使いはじめることができます。`mvnw` スクリプトの中身を見ればどんなことをしてるのかも分かりますので、トラブルが発生してもある程度は自力で解析・対処できると思います。

他参考：

- [Spring-boot - What is the purpose of mvnw and mvnw.cmd files? - Stack Overflow](http://stackoverflow.com/questions/38723833/spring-boot-what-is-the-purpose-of-mvnw-and-mvnw-cmd-files)
  - http://stackoverflow.com/questions/38723833/spring-boot-what-is-the-purpose-of-mvnw-and-mvnw-cmd-files
- [Maven Wrapperを使ってプロジェクトで使うMavenのバージョンを指定する - zephiransasのチラシの裏](http://zephiransas.github.io/blog/2016/05/23/maven-wrapper/)
  - http://zephiransas.github.io/blog/2016/05/23/maven-wrapper/
- [bdemers/maven-wrapper: maven-wrapper](https://github.com/bdemers/maven-wrapper)
  - https://github.com/bdemers/maven-wrapper
  - https://github.com/takari/maven-wrapper のfork元。
- [http://mvnvm.org/](http://mvnvm.org/)
  - http://mvnvm.org/
  - Maven環境を複数インストールして切り替えられるようにする仕組み。

[^1]: 以前は [takari/maven-wrapper の README.md](https://github.com/takari/maven-wrapper/blob/master/README.md) にはバージョン番号指定が無かったのですが、2019-05-19 に改めて確認したところ指定されていました。バージョン表記が無いと以前にインストールされた maven-wrapper が使われ、最新の mvnw/.mvn が生成されない現象が手元で確認できたこともあり、明示的に最新を使いたい場合はバージョン番号指定を含めるほうが良いと思われます。