GradleでDependencyをどのレポジトリからダウンロードしているか確認する方法

# 前置き: 確認方法を調べた理由

[A Confusing Dependency](https://blog.autsoft.hu/a-confusing-dependency/) に端を発して、JCenterに偽装ライブラリがアップロードされていることが広く知られることになり、Dependencyのダウンロード先のRepositoryに気をつける必要があることが再認識されました。

問題の回避方法として、[Gradle 5.1](https://docs.gradle.org/5.1/release-notes.html) で導入された [Matching repositories to dependencies](https://docs.gradle.org/current/userguide/declaring_repositories.html#sec::matching_repositories_to_dependencies) が有用そう (参考: [GradleのMatching repositories to dependenciesを使ってライブラリのダウンロード先を指定する - stsnブログ](https://satoshun.github.io/2018/12/gradle_deps_match/)) ですが、Androidアプリだと、Gradle 5.x が利用できるのは Android Gradle Plugin 3.4 (2019年1月4日時点でまだ alpha-10) からのようなので、多くの人にとって、まだ利用できる方法ではありません。現時点では、より信用できる Maven Central[^1] を JCenter よりも優先して使うようにすることが次善の策のようです (参考: [Jake Whartonのツイート)](https://twitter.com/JakeWharton/status/1073102730443526144)。

で、私もこのプラクティスに習ってレポジトリの優先度を整理してみたのですが、そもそもどのDependencyがどのレポジトリからダウンロードされているのかわからなかったので、確認する方法を調査しました。

# ダウンロード先のRepositoryを確認する方法

結論を先に言うと、[--refresh-dependencies](https://docs.gradle.org/current/userguide/troubleshooting_dependency_resolution.html#forcing_all_dependencies_to_be_re_resolved) と [-i](https://docs.gradle.org/current/userguide/logging.html#sec:choosing_a_log_level) オプション付きで gradle を実行して、Dependencyを再解決 & 解決先のURLをログに出力させ、ログから grep で抽出して確認しました。

Gradleのどこかに適当なハンドラがあって、Gradleスクリプトでそのハンドラを利用することでいい感じに解決先のレポジトリの情報が得られるかと思ったのですが、そういう方法を見つけられず... Gradle Forumsにも[まさにこの方法を聞いているForum](https://discuss.gradle.org/t/how-to-know-which-repository-a-dependency-is-from/6689)があったのですが、未解決で放置されていました。

以下が、確認のために実行するコマンドです。`assemble` 部分は、プロジェクトで利用しているFlavorに応じて、適当に変更してください。[-m](https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_execution_options) は dry run のオプションで、コンパイルの実行を回避して実行時間を抑えるためのものです。

```shell
./gradlew -m -i --refresh-dependencies assemble
```

なお、この後、このログを対象に grep で情報を抽出するのですが、一度、ログをファイルに出力して、それを `grep` するのがいいと思います。上記の gradlew コマンドの実行には時間がかかるため、パイプで grep すると、grep コマンドの記述をミスしたときにダメージが大きいです。

```shell
./gradlew -m -i --refresh-dependencies assemble > gradle.log # リダイレクトでファイル出力
./gradlew -m -i --refresh-dependencies assemble | tee gradle.log # teeでファイル出力
```

上記コマンドを実行すると、以下のようなログが出力されます。

```text:gradlewのログ出力例
> Configure project :buildSrc
Evaluating project ':buildSrc' using build file '/path/to/build.gradle'.
Found locally available resource with matching checksum: [https://plugins.gradle.org/m2/org/gradle/kotlin/kotlin-dsl/org.gradle.kotlin.kotlin-dsl.gradle.plugin/1.0-rc-5/org.gradle.kotlin.kotlin-dsl.gradle.plugin-1.0-rc-5.pom, /Users/tkanda/.gradle/caches/modules-2/files-2.1/org.gradle.kotlin.kotlin-dsl/org.gradle.kotlin.kotlin-dsl.gradle.plugin/1.0-rc-5/dd1f22adf523f8a6d76da784b0ce36d13761dc81/org.gradle.kotlin.kotlin-dsl.gradle.plugin-1.0-rc-5.pom]
Invalidating in-memory cache of /Users/tkanda/.gradle/caches/journal-1/file-access.bin
Resource missing. [HTTP HEAD: https://plugins.gradle.org/m2/org/gradle/kotlin/kotlin-dsl/org.gradle.kotlin.kotlin-dsl.gradle.plugin/1.0-rc-5/org.gradle.kotlin.kotlin-dsl.gradle.plugin-1.0-rc-5.jar]
Cached resource https://plugins.gradle.org/m2/gradle/plugin/org/gradle/kotlin/gradle-kotlin-dsl-plugins/1.0-rc-5/gradle-kotlin-dsl-plugins-1.0-rc-5.pom is up-to-date (lastModified: Thu Aug 23 00:07:07 IST 2018).
Cached resource https://plugins.gradle.org/m2/org/jetbrains/kotlin/kotlin-gradle-plugin/1.2.61/kotlin-gradle-plugin-1.2.61.pom is up-to-date (lastModified: Mon Aug 20 19:49:12 IST 2018).
...

> Configure project :app
Evaluating project ':app' using build file '/Users/tkanda/Work/acms/nml-nc-ice-android/app/build.gradle.kts'.
Resource missing. [HTTP HEAD: https://plugins.gradle.org/m2/com/android/tools/build/gradle/3.2.1/gradle-3.2.1.pom]
Resource missing. [HTTP HEAD: https://plugins.gradle.org/m2/com/android/tools/build/gradle/3.2.1/gradle-3.2.1.jar]
Cached resource https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.2.1/gradle-3.2.1.pom is up-to-date (lastModified: Fri Oct 12 01:30:00 IST 2018).
...

Selected primary task 'assemble' from project :
Cached resource https://maven-central.storage-download.googleapis.com/repos/central/data/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.3.0/kotlin-stdlib-jdk7-1.3.0.pom is up-to-date (lastModified: Mon Oct 29 20:17:01 IST 2018).
Cached resource https://maven-central.storage-download.googleapis.com/repos/central/data/com/squareup/leakcanary/leakcanary-android/1.6.2/leakcanary-android-1.6.2.pom is up-to-date (lastModified: Wed Oct 17 07:04:41 IST 2018).
...
```

このログからURLを抽出すれば、ダウンロード先のレポジトリがわかります。一点、注意として、以下のように「DependencyがこのURLには見つからなかった」という情報もログに出力されているので、この行は除く必要があります。

```
Resource missing. [HTTP HEAD: https://maven-central.storage-download.googleapis.com/repos/central/data/androidx/databinding/databinding-common/3.2.1/databinding-common-3.2.1.pom]
Resource missing. [HTTP HEAD: https://maven-central.storage-download.googleapis.com/repos/central/data/androidx/appcompat/appcompat/1.0.0/appcompat-1.0.0.pom]
```

以下が、grep コマンドと、その出力例です。

```shell:grapコマンド例
grep -v 'missing' gradle.log | grep -o 'https://[^ ]*.pom' | sort | uniq
```

```text:grepコマンドの出力例
https://dl.google.com/dl/android/maven2/androidx/annotation/annotation/1.0.0/annotation-1.0.0.pom
https://dl.google.com/dl/android/maven2/androidx/appcompat/appcompat/1.0.0/appcompat-1.0.0.pom
https://dl.google.com/dl/android/maven2/androidx/arch/core/core-common/2.0.0/core-common-2.0.0.pom
https://dl.google.com/dl/android/maven2/androidx/arch/core/core-runtime/2.0.0/core-runtime-2.0.0.pom
...
```

最初の `grep -v` で "Resource missing" の行を除いた後、次の `grep -o` でPOMファイルのURLを抽出し、それを sort & uniq しています。

ひとまず、私が開発しているアプリで確認したところ、JCenterから怪しげなライブラリはダウンロードしていないようなので安心しました。

[^1]: [Googleがミラーしている Maven Central レポジトリ](https://storage-download.googleapis.com/maven-central/index.html)を利用したほうがダウンロードが早いそうです (参考: [Jake Whartonのツイート](https://twitter.com/JakeWharton/status/1080927108782800903))